adapt 3mf to matrices

This commit is contained in:
Michael Kirsch 2019-07-06 21:46:25 +02:00 committed by Joseph Lenox
parent 1bd679dcba
commit 2a476e1742
2 changed files with 103 additions and 130 deletions

View File

@ -504,14 +504,12 @@ TMFParserContext::startElement(const char *name, const char **atts)
const char* transformation_matrix = get_attribute(atts, "transform");
if(transformation_matrix){
// Decompose the affine matrix.
std::vector<double> transformations;
if(!get_transformations(transformation_matrix, transformations))
TransformationMatrix trafo;
std::vector<double> single_transformations;
if(!get_transformations(transformation_matrix, trafo, &single_transformations))
this->stop();
if(transformations.size() != 9)
this->stop();
apply_transformation(instance, transformations);
apply_transformation(instance, trafo, single_transformations);
}
node_type_new = NODE_TYPE_ITEM;
@ -554,36 +552,19 @@ TMFParserContext::startElement(const char *name, const char **atts)
if(!object_id)
this->stop();
ModelObject* component_object = m_model.objects[m_objects_indices[object_id]];
// Append it to the parent (current m_object) as a mesh since Slic3r doesn't support an object inside another.
// after applying 3d matrix transformation if found.
TriangleMesh component_mesh;
const char* transformation_matrix = get_attribute(atts, "transform");
if(transformation_matrix){
// Decompose the affine matrix.
std::vector<double> transformations;
if(!get_transformations(transformation_matrix, transformations))
this->stop();
if( transformations.size() != 9)
this->stop();
// Create a copy of the current object.
ModelObject* object_copy = m_model.add_object(*component_object, true);
apply_transformation(object_copy, transformations);
// Get the mesh of this instance object.
component_mesh = object_copy->raw_mesh();
// Delete the copy of the object.
m_model.delete_object(m_model.objects.size() - 1);
} else {
component_mesh = component_object->raw_mesh();
}
ModelVolume* volume = m_object->add_volume(component_mesh);
ModelVolume* volume = m_object->add_volume(component_object->raw_mesh());
if(!volume)
this->stop();
const char* transformation_matrix = get_attribute(atts, "transform");
if(transformation_matrix){
TransformationMatrix trafo;
if(!get_transformations(transformation_matrix, trafo))
this->stop();
volume->apply_transformation(trafo);
}
node_type_new =NODE_TYPE_COMPONENT;
} else if (strcmp(name, "slic3r:volumes") == 0) {
node_type_new = NODE_TYPE_SLIC3R_VOLUMES;
@ -727,7 +708,7 @@ TMFParserContext::stop()
}
bool
TMFParserContext::get_transformations(std::string matrix, std::vector<double> &transformations)
TMFParserContext::get_transformations(std::string matrix, TransformationMatrix &trafo, std::vector<double>* transformations)
{
// Get the values.
double m[12];
@ -745,107 +726,102 @@ TMFParserContext::get_transformations(std::string matrix, std::vector<double> &t
if(k != 12)
return false;
// Get the translation (x,y,z) value. Remember the matrix in 3mf is a row major not a column major.
transformations.push_back(m[9]);
transformations.push_back(m[10]);
transformations.push_back(m[11]);
// matrices in 3mf is row-major for row-vectors multiplied from the left,
// so we have to transpose the matrix
trafo.m11 = m[0];
trafo.m21 = m[1];
trafo.m31 = m[2];
trafo.m12 = m[3];
trafo.m22 = m[4];
trafo.m32 = m[5];
trafo.m13 = m[6];
trafo.m23 = m[7];
trafo.m33 = m[8];
trafo.m14 = m[9];
trafo.m24 = m[10];
trafo.m34 = m[11];
// 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]);
transformations.push_back(sx);
transformations.push_back(sy);
transformations.push_back(sz);
// 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_x, result_y, result_z;
// singularity at north pole
if (test > 0.499)
if (transformations)
{
result_x = 0;
result_y = 2 * atan2(q_x, q_w);
result_z = PI / 2;
}
// singularity at south pole
else if (test < -0.499)
{
result_x = 0;
result_y = -2 * atan2(q_x, q_w);
result_z = -PI / 2;
}
else
{
result_x = atan2(2 * q_x * q_w - 2 * q_y * q_z, 1 - 2 * q_x * q_x - 2 * q_z * q_z);
result_y = atan2(2 * q_y * q_w - 2 * q_x * q_z, 1 - 2 * q_y * q_y - 2 * q_z * q_z);
result_z = asin(2 * q_x * q_y + 2 * q_z * q_w);
if (result_x < 0) result_x += 2 * PI;
if (result_y < 0) result_y += 2 * PI;
if (result_z < 0) result_z += 2 * PI;
}
transformations.push_back(result_x);
transformations.push_back(result_y);
transformations.push_back(result_z);
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(ModelObject *object, std::vector<double> &transformations)
TMFParserContext::apply_transformation(ModelInstance *instance, const TransformationMatrix& complete_trafo, const std::vector<double>& single_transformations)
{
// Apply scale.
Pointf3 vec(transformations[3], transformations[4], transformations[5]);
object->scale(vec);
// Reset internal trafo
instance->additional_trafo = TransformationMatrix::mat_eye();
// Apply x, y & z rotation.
object->rotate(transformations[6], X);
object->rotate(transformations[7], Y);
object->rotate(transformations[8], Z);
// Apply scale.
instance->scaling_factor = single_transformations[2];
// Apply z rotation.
instance->rotation = single_transformations[3];
// Apply translation.
object->translate(transformations[0], transformations[1], transformations[2]);
return;
}
instance->offset.x = single_transformations[0];
instance->offset.y = single_transformations[1];
void
TMFParserContext::apply_transformation(ModelInstance *instance, std::vector<double> &transformations)
{
// Apply scale.
// instance->scaling_vector = Pointf3(transformations[3], transformations[4], transformations[5]);;
instance->additional_trafo = TransformationMatrix::multiply(
instance->get_trafo_matrix().inverse(),
complete_trafo);
// Apply x, y & z rotation.
instance->rotation = transformations[8];
// instance->x_rotation = transformations[6];
// instance->y_rotation = transformations[7];
// Apply translation.
instance->offset.x = transformations[0];
instance->offset.y = transformations[1];
// instance->z_translation = transformations[2];
return;
}

View File

@ -3,6 +3,7 @@
#include "../IO.hpp"
#include "../Zip/ZipArchive.hpp"
#include "../TransformationMatrix.hpp"
#include <cstdio>
#include <string>
#include <cstring>
@ -145,8 +146,9 @@ struct TMFParserContext{
/// Get scale, rotation and scale transformation from affine matrix.
/// \param matrix string the 3D matrix where elements are separated by space.
/// \return vector<double> a vector contains [translation, scale factor, xRotation, yRotation, zRotation].
bool get_transformations(std::string matrix, std::vector<double>& transformations);
/// \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);
/// Add a new volume to the current object.
/// \param start_offset size_t the start index in the m_volume_facets vector.
@ -155,15 +157,10 @@ 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 object.
/// \param object ModelObject*
/// \param transfornmations vector<int>
void apply_transformation(ModelObject* object, std::vector<double>& transformations);
/// Apply scale, rotate & translate to the given instance.
/// \param instance ModelInstance*
/// \param transfornmations vector<int>
void apply_transformation(ModelInstance* instance, std::vector<double>& transformations);
void apply_transformation(ModelInstance* instance, const TransformationMatrix& complete_trafo, const std::vector<double>& single_transformations);
};
} }