diff --git a/xs/src/libslic3r/IO/TMF.cpp b/xs/src/libslic3r/IO/TMF.cpp index 4f3319a3c..ab493307b 100644 --- a/xs/src/libslic3r/IO/TMF.cpp +++ b/xs/src/libslic3r/IO/TMF.cpp @@ -503,13 +503,13 @@ TMFParserContext::startElement(const char *name, const char **atts) // Apply transformation if supplied. const char* transformation_matrix = get_attribute(atts, "transform"); if(transformation_matrix){ - // Decompose the affine matrix. TransformationMatrix trafo; std::vector single_transformations; - if(!get_transformations(transformation_matrix, trafo, &single_transformations)) + if(!extract_trafo(transformation_matrix, trafo)) this->stop(); - apply_transformation(instance, trafo, single_transformations); + // Decompose the affine matrix. + instance->set_complete_trafo(trafo); } node_type_new = NODE_TYPE_ITEM; @@ -560,7 +560,7 @@ TMFParserContext::startElement(const char *name, const char **atts) if(transformation_matrix){ TransformationMatrix trafo; - if(!get_transformations(transformation_matrix, trafo)) + if(!extract_trafo(transformation_matrix, trafo)) this->stop(); volume->apply_transformation(trafo); @@ -708,7 +708,7 @@ TMFParserContext::stop() } bool -TMFParserContext::get_transformations(std::string matrix, TransformationMatrix &trafo, std::vector* transformations) +TMFParserContext::extract_trafo(std::string matrix, TransformationMatrix &trafo) { // Get the values. double m[12]; @@ -741,93 +741,9 @@ TMFParserContext::get_transformations(std::string matrix, TransformationMatrix & trafo.m13 = m[10]; trafo.m23 = m[11]; - if (transformations) - { - - transformations->push_back(m[9]); - transformations->push_back(m[10]); - - // Get the scale values. - double sx = sqrt( m[0] * m[0] + m[1] * m[1] + m[2] * m[2]), - sy = sqrt( m[3] * m[3] + m[4] * m[4] + m[5] * m[5]), - sz = sqrt( m[6] * m[6] + m[7] * m[7] + m[8] * m[8]); - - double uniform_scaling = (sx + sy + sz) / 3; - transformations->push_back(uniform_scaling); - - // Get the rotation values. - // Normalize scale from the rotation matrix. - m[0] /= sx; m[1] /= sy; m[2] /= sz; - m[3] /= sx; m[4] /= sy; m[5] /= sz; - m[6] /= sx; m[7] /= sy; m[8] /= sz; - - // Get quaternion values - double q_w = sqrt(std::max(0.0, 1.0 + m[0] + m[4] + m[8])) / 2, - q_x = sqrt(std::max(0.0, 1.0 + m[0] - m[4] - m[8])) / 2, - q_y = sqrt(std::max(0.0, 1.0 - m[0] + m[4] - m[8])) / 2, - q_z = sqrt(std::max(0.0, 1.0 - m[0] - m[4] + m[8])) / 2; - - q_x *= ((q_x * (m[5] - m[7])) <= 0 ? -1 : 1); - q_y *= ((q_y * (m[6] - m[2])) <= 0 ? -1 : 1); - q_z *= ((q_z * (m[1] - m[3])) <= 0 ? -1 : 1); - - // Normalize quaternion values. - double q_magnitude = sqrt(q_w * q_w + q_x * q_x + q_y * q_y + q_z * q_z); - q_w /= q_magnitude; - q_x /= q_magnitude; - q_y /= q_magnitude; - q_z /= q_magnitude; - - double test = q_x * q_y + q_z * q_w; - double result_z; - // singularity at north pole - if (test > 0.499) - { - result_z = PI / 2; - } - // singularity at south pole - else if (test < -0.499) - { - result_z = -PI / 2; - } - else - { - result_z = asin(2 * q_x * q_y + 2 * q_z * q_w); - - if (result_z < 0) result_z += 2 * PI; - } - transformations->push_back(result_z); - - } return true; } -void -TMFParserContext::apply_transformation(ModelInstance *instance, const TransformationMatrix& complete_trafo, const std::vector& single_transformations) -{ - // Reset internal trafo - instance->additional_trafo = TransformationMatrix::mat_eye(); - - // Apply scale. - instance->scaling_factor = single_transformations[2]; - - // Apply z rotation. - instance->rotation = single_transformations[3]; - - // Apply translation. - instance->offset.x = single_transformations[0]; - instance->offset.y = single_transformations[1]; - - // Complete = Instance * Additional - // -> Instance^-1 * Complete = (Instance^-1 * Instance) * Additional - // -> Instance^-1 * Complete = Additional - instance->additional_trafo = TransformationMatrix::multiply( - instance->get_trafo_matrix().inverse(), - complete_trafo); - - return; -} - ModelVolume* TMFParserContext::add_volume(int start_offset, int end_offset, bool modifier) { diff --git a/xs/src/libslic3r/IO/TMF.hpp b/xs/src/libslic3r/IO/TMF.hpp index e4b6d55d8..c15b4d8d1 100644 --- a/xs/src/libslic3r/IO/TMF.hpp +++ b/xs/src/libslic3r/IO/TMF.hpp @@ -144,11 +144,10 @@ struct TMFParserContext{ void characters(const XML_Char *s, int len); void stop(); - /// Get scale, rotation and scale transformation from affine matrix. + /// Get transformation from string encoded matrix. /// \param matrix string the 3D matrix where elements are separated by space. /// \return TransformationMatrix a matrix that contains the complete defined transformation. - /// \return optional vector a vector contains [translation x, y, uniform scale factor, zRotation]. - bool get_transformations(std::string matrix, TransformationMatrix& trafo, std::vector* transformations = nullptr); + bool extract_trafo(std::string matrix, TransformationMatrix& trafo); /// Add a new volume to the current object. /// \param start_offset size_t the start index in the m_volume_facets vector. @@ -157,10 +156,6 @@ struct TMFParserContext{ /// \return ModelVolume* a pointer to the newly added volume. ModelVolume* add_volume(int start_offset, int end_offset, bool modifier); - /// Apply scale, rotate & translate to the given instance. - /// \param instance ModelInstance* - /// \param transfornmations vector - void apply_transformation(ModelInstance* instance, const TransformationMatrix& complete_trafo, const std::vector& single_transformations); }; } } diff --git a/xs/src/libslic3r/Model.cpp b/xs/src/libslic3r/Model.cpp index ac3fd886a..172de747f 100644 --- a/xs/src/libslic3r/Model.cpp +++ b/xs/src/libslic3r/Model.cpp @@ -1170,8 +1170,15 @@ ModelInstance::ModelInstance(ModelObject *object) : rotation(0), scaling_factor(1), object(object) {} +ModelInstance::ModelInstance(ModelObject *object, const TransformationMatrix & trafo) +: object(object) +{ + this->set_complete_trafo(trafo); +} + + ModelInstance::ModelInstance(ModelObject *object, const ModelInstance &other) -: rotation(other.rotation), scaling_factor(other.scaling_factor), offset(other.offset), object(object) +: rotation(other.rotation), scaling_factor(other.scaling_factor), offset(other.offset), additional_trafo(other.additional_trafo), object(object) {} ModelInstance& ModelInstance::operator= (ModelInstance other) @@ -1183,9 +1190,80 @@ ModelInstance& ModelInstance::operator= (ModelInstance other) void ModelInstance::swap(ModelInstance &other) { - std::swap(this->rotation, other.rotation); - std::swap(this->scaling_factor, other.scaling_factor); - std::swap(this->offset, other.offset); + std::swap(this->rotation, other.rotation); + std::swap(this->scaling_factor, other.scaling_factor); + std::swap(this->offset, other.offset); + std::swap(this->additional_trafo, other.additional_trafo); +} + +void ModelInstance::set_complete_trafo(TransformationMatrix const & trafo) +{ + // Extraction code moved from TMF class + + this->offset.x = trafo.m03; + this->offset.y = trafo.m13; + + // Get the scale values. + double sx = sqrt( trafo.m00 * trafo.m00 + trafo.m10 * trafo.m10 + trafo.m20 * trafo.m20), + sy = sqrt( trafo.m01 * trafo.m01 + trafo.m11 * trafo.m11 + trafo.m21 * trafo.m21), + sz = sqrt( trafo.m02 * trafo.m02 + trafo.m12 * trafo.m12 + trafo.m22 * trafo.m22); + + this->scaling_factor = (sx + sy + sz) / 3; + + // Get the rotation values. + // Normalize scale from the matrix. + TransformationMatrix rotmat = trafo.multiplyLeft(TransformationMatrix::mat_scale(1/sx, 1/sy, 1/sz)); + rotmat.m00 /= sx; rotmat.m10 /= sy; rotmat.m20 /= sz; + rotmat.m01 /= sx; rotmat.m11 /= sy; rotmat.m21 /= sz; + rotmat.m02 /= sx; rotmat.m12 /= sy; rotmat.m22 /= sz; + + // Get quaternion values + double q_w = sqrt(std::max(0.0, 1.0 + rotmat.m00 + rotmat.m11 + rotmat.m22)) / 2, + q_x = sqrt(std::max(0.0, 1.0 + rotmat.m00 - rotmat.m11 - rotmat.m22)) / 2, + q_y = sqrt(std::max(0.0, 1.0 - rotmat.m00 + rotmat.m11 - rotmat.m22)) / 2, + q_z = sqrt(std::max(0.0, 1.0 - rotmat.m00 - rotmat.m11 + rotmat.m22)) / 2; + + q_x *= ((q_x * (rotmat.m21 - rotmat.m12)) <= 0 ? -1 : 1); + q_y *= ((q_y * (rotmat.m02 - rotmat.m20)) <= 0 ? -1 : 1); + q_z *= ((q_z * (rotmat.m10 - rotmat.m01)) <= 0 ? -1 : 1); + + // Normalize quaternion values. + double q_magnitude = sqrt(q_w * q_w + q_x * q_x + q_y * q_y + q_z * q_z); + q_w /= q_magnitude; + q_x /= q_magnitude; + q_y /= q_magnitude; + q_z /= q_magnitude; + + double test = q_x * q_y + q_z * q_w; + double result_z; + // singularity at north pole + if (test > 0.499) + { + result_z = PI / 2; + } + // singularity at south pole + else if (test < -0.499) + { + result_z = -PI / 2; + } + else + { + result_z = asin(2 * q_x * q_y + 2 * q_z * q_w); + + if (result_z < 0) result_z += 2 * PI; + } + + this->rotation = result_z; + + this->additional_trafo = TransformationMatrix::mat_eye(); + + // Complete = Instance * Additional + // -> Instance^-1 * Complete = (Instance^-1 * Instance) * Additional + // -> Instance^-1 * Complete = Additional + this->additional_trafo = TransformationMatrix::multiply( + this->get_trafo_matrix().inverse(), + trafo); + } void @@ -1209,9 +1287,7 @@ TransformationMatrix ModelInstance::get_trafo_matrix(bool dont_translate) const BoundingBoxf3 ModelInstance::transform_bounding_box(const BoundingBoxf3 &bbox, bool dont_translate) const { - // rotate around mesh origin - double c = cos(this->rotation); - double s = sin(this->rotation); + TransformationMatrix Pointf3 pts[4] = { bbox.min, bbox.max, diff --git a/xs/src/libslic3r/Model.hpp b/xs/src/libslic3r/Model.hpp index e548aa775..cdad0fc8a 100644 --- a/xs/src/libslic3r/Model.hpp +++ b/xs/src/libslic3r/Model.hpp @@ -605,6 +605,9 @@ class ModelInstance /// \return ModelObject* pointer to the owner ModelObject ModelObject* get_object() const { return this->object; }; + /// Set the internal instance parameters by extracting them from the given complete transformation + void set_complete_trafo(TransformationMatrix const & trafo); + //TRAFO:should be deprecated /// Transform an external TriangleMesh object /// \param mesh TriangleMesh* pointer to the the mesh @@ -632,6 +635,11 @@ class ModelInstance /// \param object ModelObject* pointer to the owner ModelObject ModelInstance(ModelObject *object); + /// Constructor + /// \param object ModelObject* pointer to the owner ModelObject + /// \param trafo transformation that the Model Instance should initially represent + ModelInstance(ModelObject *object, const TransformationMatrix & trafo); + /// Constructor /// \param object ModelObject* pointer to the owner ModelObject /// \param other ModelInstance an instance to be copied in the new ModelInstance object