move matrix decomposition to instance class

This commit is contained in:
Michael Kirsch 2019-07-18 21:56:10 +02:00 committed by Joseph Lenox
parent 5aa8d8e748
commit 794b3a1419
4 changed files with 98 additions and 103 deletions

View File

@ -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<double> 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<double>* 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<double>& 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)
{

View File

@ -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<double> a vector contains [translation x, y, uniform scale factor, zRotation].
bool get_transformations(std::string matrix, TransformationMatrix& trafo, std::vector<double>* 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<int>
void apply_transformation(ModelInstance* instance, const TransformationMatrix& complete_trafo, const std::vector<double>& single_transformations);
};
} }

View File

@ -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,

View File

@ -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