Eigenized 3mf I/O

This commit is contained in:
Enrico Turri 2018-08-28 14:30:36 +02:00
parent 84fb7940b7
commit 98a6468c81

View File

@ -87,8 +87,6 @@ const char* INVALID_OBJECT_TYPES[] =
"other" "other"
}; };
typedef Eigen::Matrix<float, 4, 4, Eigen::RowMajor> Matrix4x4;
const char* get_attribute_value_charptr(const char** attributes, unsigned int attributes_size, const char* attribute_key) const char* get_attribute_value_charptr(const char** attributes, unsigned int attributes_size, const char* attribute_key)
{ {
if ((attributes == nullptr) || (attributes_size == 0) || (attributes_size % 2 != 0) || (attribute_key == nullptr)) if ((attributes == nullptr) || (attributes_size == 0) || (attributes_size % 2 != 0) || (attribute_key == nullptr))
@ -121,11 +119,11 @@ int get_attribute_value_int(const char** attributes, unsigned int attributes_siz
return (text != nullptr) ? ::atoi(text) : 0; return (text != nullptr) ? ::atoi(text) : 0;
} }
Matrix4x4 get_matrix_from_string(const std::string& mat_str) Slic3r::Transform3d get_transform_from_string(const std::string& mat_str)
{ {
if (mat_str.empty()) if (mat_str.empty())
// empty string means default identity matrix // empty string means default identity matrix
return Matrix4x4::Identity(); return Slic3r::Transform3d::Identity();
std::vector<std::string> mat_elements_str; std::vector<std::string> mat_elements_str;
boost::split(mat_elements_str, mat_str, boost::is_any_of(" "), boost::token_compress_on); boost::split(mat_elements_str, mat_str, boost::is_any_of(" "), boost::token_compress_on);
@ -133,9 +131,9 @@ Matrix4x4 get_matrix_from_string(const std::string& mat_str)
unsigned int size = (unsigned int)mat_elements_str.size(); unsigned int size = (unsigned int)mat_elements_str.size();
if (size != 12) if (size != 12)
// invalid data, return identity matrix // invalid data, return identity matrix
return Matrix4x4::Identity(); return Slic3r::Transform3d::Identity();
Matrix4x4 ret = Matrix4x4::Identity(); Slic3r::Transform3d ret = Slic3r::Transform3d::Identity();
unsigned int i = 0; unsigned int i = 0;
// matrices are stored into 3mf files as 4x3 // matrices are stored into 3mf files as 4x3
// we need to transpose them // we need to transpose them
@ -143,7 +141,7 @@ Matrix4x4 get_matrix_from_string(const std::string& mat_str)
{ {
for (unsigned int r = 0; r < 3; ++r) for (unsigned int r = 0; r < 3; ++r)
{ {
ret(r, c) = (float)::atof(mat_elements_str[i++].c_str()); ret(r, c) = ::atof(mat_elements_str[i++].c_str());
} }
} }
return ret; return ret;
@ -209,17 +207,17 @@ namespace Slic3r {
struct Component struct Component
{ {
int object_id; int object_id;
Matrix4x4 matrix; Transform3d transform;
explicit Component(int object_id) explicit Component(int object_id)
: object_id(object_id) : object_id(object_id)
, matrix(Matrix4x4::Identity()) , transform(Transform3d::Identity())
{ {
} }
Component(int object_id, const Matrix4x4& matrix) Component(int object_id, const Transform3d& transform)
: object_id(object_id) : object_id(object_id)
, matrix(matrix) , transform(transform)
{ {
} }
}; };
@ -273,11 +271,11 @@ namespace Slic3r {
struct Instance struct Instance
{ {
ModelInstance* instance; ModelInstance* instance;
Matrix4x4 matrix; Transform3d transform;
Instance(ModelInstance* instance, const Matrix4x4& matrix) Instance(ModelInstance* instance, const Transform3d& transform)
: instance(instance) : instance(instance)
, matrix(matrix) , transform(transform)
{ {
} }
}; };
@ -405,9 +403,9 @@ namespace Slic3r {
bool _handle_start_metadata(const char** attributes, unsigned int num_attributes); bool _handle_start_metadata(const char** attributes, unsigned int num_attributes);
bool _handle_end_metadata(); bool _handle_end_metadata();
bool _create_object_instance(int object_id, const Matrix4x4& matrix, unsigned int recur_counter); bool _create_object_instance(int object_id, const Transform3d& transform, unsigned int recur_counter);
void _apply_transform(ModelInstance& instance, const Matrix4x4& matrix); void _apply_transform(ModelInstance& instance, const Transform3d& transform);
bool _handle_start_config(const char** attributes, unsigned int num_attributes); bool _handle_start_config(const char** attributes, unsigned int num_attributes);
bool _handle_end_config(); bool _handle_end_config();
@ -934,8 +932,8 @@ namespace Slic3r {
ModelObject* object = instance.instance->get_object(); ModelObject* object = instance.instance->get_object();
if (object != nullptr) if (object != nullptr)
{ {
// apply the matrix to the instance // apply the transform to the instance
_apply_transform(*instance.instance, instance.matrix); _apply_transform(*instance.instance, instance.transform);
} }
} }
} }
@ -1119,7 +1117,7 @@ namespace Slic3r {
bool _3MF_Importer::_handle_start_component(const char** attributes, unsigned int num_attributes) bool _3MF_Importer::_handle_start_component(const char** attributes, unsigned int num_attributes)
{ {
int object_id = get_attribute_value_int(attributes, num_attributes, OBJECTID_ATTR); int object_id = get_attribute_value_int(attributes, num_attributes, OBJECTID_ATTR);
Matrix4x4 matrix = get_matrix_from_string(get_attribute_value_string(attributes, num_attributes, TRANSFORM_ATTR)); Transform3d transform = get_transform_from_string(get_attribute_value_string(attributes, num_attributes, TRANSFORM_ATTR));
IdToModelObjectMap::iterator object_item = m_objects.find(object_id); IdToModelObjectMap::iterator object_item = m_objects.find(object_id);
if (object_item == m_objects.end()) if (object_item == m_objects.end())
@ -1132,7 +1130,7 @@ namespace Slic3r {
} }
} }
m_curr_object.components.emplace_back(object_id, matrix); m_curr_object.components.emplace_back(object_id, transform);
return true; return true;
} }
@ -1165,9 +1163,9 @@ namespace Slic3r {
// see specifications // see specifications
int object_id = get_attribute_value_int(attributes, num_attributes, OBJECTID_ATTR); int object_id = get_attribute_value_int(attributes, num_attributes, OBJECTID_ATTR);
Matrix4x4 matrix = get_matrix_from_string(get_attribute_value_string(attributes, num_attributes, TRANSFORM_ATTR)); Transform3d transform = get_transform_from_string(get_attribute_value_string(attributes, num_attributes, TRANSFORM_ATTR));
return _create_object_instance(object_id, matrix, 1); return _create_object_instance(object_id, transform, 1);
} }
bool _3MF_Importer::_handle_end_item() bool _3MF_Importer::_handle_end_item()
@ -1195,7 +1193,7 @@ namespace Slic3r {
return true; return true;
} }
bool _3MF_Importer::_create_object_instance(int object_id, const Matrix4x4& matrix, unsigned int recur_counter) bool _3MF_Importer::_create_object_instance(int object_id, const Transform3d& transform, unsigned int recur_counter)
{ {
static const unsigned int MAX_RECURSIONS = 10; static const unsigned int MAX_RECURSIONS = 10;
@ -1232,7 +1230,7 @@ namespace Slic3r {
return false; return false;
} }
m_instances.emplace_back(instance, matrix); m_instances.emplace_back(instance, transform);
} }
} }
else else
@ -1240,7 +1238,7 @@ namespace Slic3r {
// recursively process nested components // recursively process nested components
for (const Component& component : it->second) for (const Component& component : it->second)
{ {
if (!_create_object_instance(component.object_id, matrix * component.matrix, recur_counter + 1)) if (!_create_object_instance(component.object_id, transform * component.transform, recur_counter + 1))
return false; return false;
} }
} }
@ -1248,20 +1246,20 @@ namespace Slic3r {
return true; return true;
} }
void _3MF_Importer::_apply_transform(ModelInstance& instance, const Matrix4x4& matrix) void _3MF_Importer::_apply_transform(ModelInstance& instance, const Transform3d& transform)
{ {
// slic3r ModelInstance cannot be transformed using a matrix // slic3r ModelInstance cannot be transformed using a matrix
// we extract from the given matrix only the values currently used // we extract from the given matrix only the values currently used
// translation // translation
double offset_x = (double)matrix(0, 3); double offset_x = transform(0, 3);
double offset_y = (double)matrix(1, 3); double offset_y = transform(1, 3);
double offset_z = (double)matrix(2, 3); double offset_z = transform(2, 3);
// scale // scale
double sx = ::sqrt(sqr((double)matrix(0, 0)) + sqr((double)matrix(1, 0)) + sqr((double)matrix(2, 0))); double sx = ::sqrt(sqr(transform(0, 0)) + sqr(transform(1, 0)) + sqr(transform(2, 0)));
double sy = ::sqrt(sqr((double)matrix(0, 1)) + sqr((double)matrix(1, 1)) + sqr((double)matrix(2, 1))); double sy = ::sqrt(sqr(transform(0, 1)) + sqr(transform(1, 1)) + sqr(transform(2, 1)));
double sz = ::sqrt(sqr((double)matrix(0, 2)) + sqr((double)matrix(1, 2)) + sqr((double)matrix(2, 2))); double sz = ::sqrt(sqr(transform(0, 2)) + sqr(transform(1, 2)) + sqr(transform(2, 2)));
// invalid scale value, return // invalid scale value, return
if ((sx == 0.0) || (sy == 0.0) || (sz == 0.0)) if ((sx == 0.0) || (sy == 0.0) || (sz == 0.0))
@ -1271,86 +1269,23 @@ namespace Slic3r {
if ((std::abs(sx - sy) > 0.00001) || (std::abs(sx - sz) > 0.00001)) if ((std::abs(sx - sy) > 0.00001) || (std::abs(sx - sz) > 0.00001))
return; return;
#if 0 // use quaternions
// rotations (extracted using quaternion)
double inv_sx = 1.0 / sx;
double inv_sy = 1.0 / sy;
double inv_sz = 1.0 / sz;
Eigen::Matrix<double, 3, 3, Eigen::RowMajor> m3x3;
m3x3 << (double)matrix(0, 0) * inv_sx, (double)matrix(0, 1) * inv_sy, (double)matrix(0, 2) * inv_sz,
(double)matrix(1, 0) * inv_sx, (double)matrix(1, 1) * inv_sy, (double)matrix(1, 2) * inv_sz,
(double)matrix(2, 0) * inv_sx, (double)matrix(2, 1) * inv_sy, (double)matrix(2, 2) * inv_sz;
double qw = 0.5 * ::sqrt(std::max(0.0, 1.0 + m3x3(0, 0) + m3x3(1, 1) + m3x3(2, 2)));
double qx = 0.5 * ::sqrt(std::max(0.0, 1.0 + m3x3(0, 0) - m3x3(1, 1) - m3x3(2, 2)));
double qy = 0.5 * ::sqrt(std::max(0.0, 1.0 - m3x3(0, 0) + m3x3(1, 1) - m3x3(2, 2)));
double qz = 0.5 * ::sqrt(std::max(0.0, 1.0 - m3x3(0, 0) - m3x3(1, 1) + m3x3(2, 2)));
double q_magnitude = ::sqrt(sqr(qw) + sqr(qx) + sqr(qy) + sqr(qz));
// invalid length, return
if (q_magnitude == 0.0)
return;
double inv_q_magnitude = 1.0 / q_magnitude;
qw *= inv_q_magnitude;
qx *= inv_q_magnitude;
qy *= inv_q_magnitude;
qz *= inv_q_magnitude;
double test = qx * qy + qz * qw;
double angle_x, angle_y, angle_z;
if (test > 0.499)
{
// singularity at north pole
angle_x = 0.0;
angle_y = 2.0 * ::atan2(qx, qw);
angle_z = 0.5 * PI;
}
else if (test < -0.499)
{
// singularity at south pole
angle_x = 0.0;
angle_y = -2.0 * ::atan2(qx, qw);
angle_z = -0.5 * PI;
}
else
{
angle_x = ::atan2(2.0 * qx * qw - 2.0 * qy * qz, 1.0 - 2.0 * sqr(qx) - 2.0 * sqr(qz));
angle_y = ::atan2(2.0 * qy * qw - 2.0 * qx * qz, 1.0 - 2.0 * sqr(qy) - 2.0 * sqr(qz));
angle_z = ::asin(2.0 * qx * qy + 2.0 * qz * qw);
if (angle_x < 0.0)
angle_x += 2.0 * PI;
if (angle_y < 0.0)
angle_y += 2.0 * PI;
if (angle_z < 0.0)
angle_z += 2.0 * PI;
}
#else // use eigen library
double inv_sx = 1.0 / sx; double inv_sx = 1.0 / sx;
double inv_sy = 1.0 / sy; double inv_sy = 1.0 / sy;
double inv_sz = 1.0 / sz; double inv_sz = 1.0 / sz;
Eigen::Matrix3d m3x3; Eigen::Matrix3d m3x3;
m3x3 << (double)matrix(0, 0) * inv_sx, (double)matrix(0, 1) * inv_sy, (double)matrix(0, 2) * inv_sz, m3x3 << transform(0, 0) * inv_sx, transform(0, 1) * inv_sy, transform(0, 2) * inv_sz,
(double)matrix(1, 0) * inv_sx, (double)matrix(1, 1) * inv_sy, (double)matrix(1, 2) * inv_sz, transform(1, 0) * inv_sx, transform(1, 1) * inv_sy, transform(1, 2) * inv_sz,
(double)matrix(2, 0) * inv_sx, (double)matrix(2, 1) * inv_sy, (double)matrix(2, 2) * inv_sz; transform(2, 0) * inv_sx, transform(2, 1) * inv_sy, transform(2, 2) * inv_sz;
Eigen::AngleAxisd rotation; Eigen::AngleAxisd rotation;
rotation.fromRotationMatrix(m3x3); rotation.fromRotationMatrix(m3x3);
// invalid rotation axis, we currently handle only rotations around Z axis // invalid rotation axis, we currently handle only rotations around Z axis
if ((rotation.angle() != 0.0) && (rotation.axis() != Eigen::Vector3d::UnitZ()) && (rotation.axis() != -Eigen::Vector3d::UnitZ())) if ((rotation.angle() != 0.0) && (rotation.axis() != Vec3d::UnitZ()) && (rotation.axis() != -Vec3d::UnitZ()))
return; return;
double angle_z = (rotation.axis() == Eigen::Vector3d::UnitZ()) ? rotation.angle() : -rotation.angle(); double angle_z = (rotation.axis() == Vec3d::UnitZ()) ? rotation.angle() : -rotation.angle();
#endif
instance.offset(0) = offset_x; instance.offset(0) = offset_x;
instance.offset(1) = offset_y; instance.offset(1) = offset_y;
@ -1548,11 +1483,11 @@ namespace Slic3r {
struct BuildItem struct BuildItem
{ {
unsigned int id; unsigned int id;
Matrix4x4 matrix; Transform3d transform;
BuildItem(unsigned int id, const Matrix4x4& matrix) BuildItem(unsigned int id, const Transform3d& transform)
: id(id) : id(id)
, matrix(matrix) , transform(transform)
{ {
} }
}; };
@ -1801,9 +1736,11 @@ namespace Slic3r {
stream << " </" << COMPONENTS_TAG << ">\n"; stream << " </" << COMPONENTS_TAG << ">\n";
} }
Eigen::Affine3f transform; Transform3d t = Transform3d::Identity();
transform = Eigen::Translation3f((float)instance->offset(0), (float)instance->offset(1), 0.0f) * Eigen::AngleAxisf((float)instance->rotation, Eigen::Vector3f::UnitZ()) * Eigen::Scaling((float)instance->scaling_factor); t.translate(Vec3d(instance->offset(0), instance->offset(1), 0.0));
build_items.emplace_back(instance_id, transform.matrix()); t.rotate(Eigen::AngleAxisd(instance->rotation, Vec3d::UnitZ()));
t.scale(instance->scaling_factor);
build_items.emplace_back(instance_id, t);
stream << " </" << OBJECT_TAG << ">\n"; stream << " </" << OBJECT_TAG << ">\n";
@ -1904,7 +1841,7 @@ namespace Slic3r {
{ {
for (unsigned r = 0; r < 3; ++r) for (unsigned r = 0; r < 3; ++r)
{ {
stream << item.matrix(r, c); stream << item.transform(r, c);
if ((r != 2) || (c != 3)) if ((r != 2) || (c != 3))
stream << " "; stream << " ";
} }