ENH: rewrite ModelInstance::rotate with rotation matrix

1. Rotation operation should always work on rotation matrix. Euler angles are not reliable.
2. Remove the ambiguous set_rotation on single euler angle.
3. Fix the bug that the rotation of the mirrored object is not correct.
jira: STUDIO-8752

Change-Id: I25d661b732a872b8378af87c0ba52d75afd75c1f
This commit is contained in:
Arthur 2024-11-27 11:59:48 +08:00 committed by lane.wei
parent fff7873456
commit f9a1ed7b24
8 changed files with 43 additions and 56 deletions

View File

@ -459,6 +459,13 @@ const Vec3d &Transformation::get_rotation_by_quaternion() const
Transform3d Transformation::get_rotation_matrix() const { return extract_rotation_matrix(m_matrix); }
void Transformation::set_rotation_matrix(const Transform3d &rot_mat)
{
const Vec3d offset = get_offset();
m_matrix = rot_mat * extract_scale(m_matrix);
m_matrix.translation() = offset;
}
void Transformation::set_rotation(const Vec3d &rotation)
{
const Vec3d offset = get_offset();
@ -466,20 +473,6 @@ void Transformation::set_rotation(const Vec3d &rotation)
m_matrix.translation() = offset;
}
void Transformation::set_rotation(Axis axis, double rotation)
{
rotation = angle_to_0_2PI(rotation);
if (is_approx(std::abs(rotation), 2.0 * double(PI))) rotation = 0.0;
auto [curr_rotation, scale] = extract_rotation_scale(m_matrix);
Vec3d angles = extract_rotation(curr_rotation);
angles[axis] = rotation;
const Vec3d offset = get_offset();
m_matrix = rotation_transform(angles) * scale;
m_matrix.translation() = offset;
}
const Vec3d &Transformation::get_scaling_factor() const
{
const Transform3d scale = extract_scale(m_matrix);

View File

@ -399,9 +399,9 @@ public:
double get_rotation(Axis axis) const { return get_rotation()[axis]; }
Transform3d get_rotation_matrix() const;
void set_rotation_matrix(const Transform3d &rot_mat);
void set_rotation(const Vec3d &rotation);
void set_rotation(Axis axis, double rotation);
const Vec3d &get_scaling_factor() const;
double get_scaling_factor(Axis axis) const { return get_scaling_factor()[axis]; }

View File

@ -3145,11 +3145,9 @@ void ModelVolume::calculate_convex_hull_2d(const Geometry::Transformation &tran
return;
Points pts;
Vec3d rotation = transformation.get_rotation();
Vec3d mirror = transformation.get_mirror();
Vec3d scale = transformation.get_scaling_factor();
//rotation(2) = 0.f;
Transform3d new_matrix = Geometry::assemble_transform(Vec3d::Zero(), rotation, scale, mirror);
Geometry::Transformation new_trans(transformation);
new_trans.reset_offset();
Transform3d new_matrix = new_trans.get_matrix();
pts.reserve(its.vertices.size());
// Using the shared vertices should be a bit quicker than using the STL faces.
@ -3480,6 +3478,12 @@ void ModelInstance::transform_mesh(TriangleMesh* mesh, bool dont_translate) cons
mesh->transform(get_matrix(dont_translate));
}
void ModelInstance::rotate(Matrix3d rotation_matrix)
{
auto new_rotation_mat = Transform3d(rotation_matrix) * m_transformation.get_rotation_matrix();
m_transformation.set_rotation_matrix(new_rotation_mat);
}
BoundingBoxf3 ModelInstance::transform_mesh_bounding_box(const TriangleMesh& mesh, bool dont_translate) const
{
// Rotate around mesh origin.
@ -3947,12 +3951,10 @@ void ModelInstance::get_arrange_polygon(void *ap, const Slic3r::DynamicPrintConf
{
// static const double SIMPLIFY_TOLERANCE_MM = 0.1;
Vec3d rotation = get_rotation();
rotation.z() = 0.;
Transform3d trafo_instance =
Geometry::assemble_transform(get_offset().z() * Vec3d::UnitZ(), rotation, get_scaling_factor(), get_mirror());
Geometry::Transformation trafo_instance = get_transformation();
trafo_instance.set_offset(Vec3d(0, 0, get_offset(Z)));
Polygon p = get_object()->convex_hull_2d(trafo_instance);
Polygon p = get_object()->convex_hull_2d(trafo_instance.get_matrix());
// if (!p.points.empty()) {
// Polygons pp{p};
@ -3963,7 +3965,7 @@ void ModelInstance::get_arrange_polygon(void *ap, const Slic3r::DynamicPrintConf
arrangement::ArrangePolygon& ret = *(arrangement::ArrangePolygon*)ap;
ret.poly.contour = std::move(p);
ret.translation = Vec2crd{scaled(get_offset(X)), scaled(get_offset(Y))};
ret.rotation = get_rotation(Z);
ret.rotation = 0;
//BBS: add materials related information
ModelVolume *volume = NULL;
@ -3995,6 +3997,15 @@ void ModelInstance::get_arrange_polygon(void *ap, const Slic3r::DynamicPrintConf
ret.extrude_ids.push_back(1);
}
void ModelInstance::apply_arrange_result(const Vec2d &offs, double rotation)
{
// write the transformation data into the model instance
rotate(Eigen::AngleAxisd(rotation, Eigen::Vector3d::UnitZ()).toRotationMatrix());
set_offset(X, unscale<double>(offs(X)));
set_offset(Y, unscale<double>(offs(Y)));
this->object->invalidate_bounding_box();
}
indexed_triangle_set FacetsAnnotation::get_facets(const ModelVolume& mv, EnforcerBlockerType type) const
{
TriangleSelector selector(mv.mesh());

View File

@ -1031,7 +1031,6 @@ public:
double get_rotation(Axis axis) const { return m_transformation.get_rotation(axis); }
void set_rotation(const Vec3d& rotation) { m_transformation.set_rotation(rotation); }
void set_rotation(Axis axis, double rotation) { m_transformation.set_rotation(axis, rotation); }
const Vec3d &get_scaling_factor() const { return m_transformation.get_scaling_factor(); }
double get_scaling_factor(Axis axis) const { return m_transformation.get_scaling_factor(axis); }
@ -1335,19 +1334,9 @@ public:
double get_rotation(Axis axis) const { return m_transformation.get_rotation(axis); }
void set_rotation(const Vec3d& rotation) { m_transformation.set_rotation(rotation); }
void set_rotation(Axis axis, double rotation) { m_transformation.set_rotation(axis, rotation); }
// BBS
void rotate(Matrix3d rotation_matrix) {
auto R = m_transformation.get_rotation_matrix();
auto R_new = rotation_matrix * R;
auto euler_angles = Geometry::extract_euler_angles(R_new);
//BOOST_LOG_TRIVIAL(debug) << "old R:\n"
// << R.matrix() << "\nnew R:\n"
// << R_new.matrix() << "\nold euler angles: " << m_transformation.get_rotation().transpose() << "\n"
// << "new euler angles: " << euler_angles.transpose();
set_rotation(euler_angles);
}
void rotate(Matrix3d rotation_matrix);
const Vec3d& get_scaling_factor() const { return m_transformation.get_scaling_factor(); }
double get_scaling_factor(Axis axis) const { return m_transformation.get_scaling_factor(axis); }
@ -1390,14 +1379,7 @@ public:
void get_arrange_polygon(void *arrange_polygon, const Slic3r::DynamicPrintConfig &config = Slic3r::DynamicPrintConfig()) const;
// Apply the arrange result on the ModelInstance
void apply_arrange_result(const Vec2d& offs, double rotation)
{
// write the transformation data into the model instance
set_rotation(Z, rotation);
set_offset(X, unscale<double>(offs(X)));
set_offset(Y, unscale<double>(offs(Y)));
this->object->invalidate_bounding_box();
}
void apply_arrange_result(const Vec2d &offs, double rotation);
protected:
friend class Print;

View File

@ -577,9 +577,10 @@ StringObjectException Print::sequential_print_clearance_valid(const Print &print
// FIXME: Arrangement has different parameters for offsetting (jtMiter, limit 2)
// which causes that the warning will be showed after arrangement with the
// appropriate object distance. Even if I set this to jtMiter the warning still shows up.
Geometry::Transformation new_trans(model_instance0->get_transformation());
new_trans.set_offset({0.0, 0.0, model_instance0->get_offset().z()});
it_convex_hull = map_model_object_to_convex_hull.emplace_hint(it_convex_hull, model_object_id,
print_object->model_object()->convex_hull_2d(Geometry::assemble_transform(
{ 0.0, 0.0, model_instance0->get_offset().z() }, model_instance0->get_rotation(), model_instance0->get_scaling_factor(), model_instance0->get_mirror())));
print_object->model_object()->convex_hull_2d(new_trans.get_matrix()));
}
// Make a copy, so it may be rotated for instances.
Polygon convex_hull0 = it_convex_hull->second;

View File

@ -508,7 +508,6 @@ public:
double get_instance_rotation(Axis axis) const { return m_instance_transformation.get_rotation(axis); }
void set_instance_rotation(const Vec3d& rotation) { m_instance_transformation.set_rotation(rotation); set_bounding_boxes_as_dirty(); }
void set_instance_rotation(Axis axis, double rotation) { m_instance_transformation.set_rotation(axis, rotation); set_bounding_boxes_as_dirty(); }
Vec3d get_instance_scaling_factor() const { return m_instance_transformation.get_scaling_factor(); }
double get_instance_scaling_factor(Axis axis) const { return m_instance_transformation.get_scaling_factor(axis); }
@ -536,7 +535,6 @@ public:
double get_volume_rotation(Axis axis) const { return m_volume_transformation.get_rotation(axis); }
void set_volume_rotation(const Vec3d& rotation) { m_volume_transformation.set_rotation(rotation); set_bounding_boxes_as_dirty(); }
void set_volume_rotation(Axis axis, double rotation) { m_volume_transformation.set_rotation(axis, rotation); set_bounding_boxes_as_dirty(); }
const Vec3d& get_volume_scaling_factor() const { return m_volume_transformation.get_scaling_factor(); }
double get_volume_scaling_factor(Axis axis) const { return m_volume_transformation.get_scaling_factor(axis); }

View File

@ -5446,7 +5446,7 @@ std::vector<Vec2f> GLCanvas3D::get_empty_cells(const Vec2f start_point, const Ve
Geometry::Transformation transformation;
const Vec3d& offset = instance->get_offset();
transformation.set_offset({ scale_(offset.x()), scale_(offset.y()), 0.0 });
transformation.set_rotation(Z, instance->get_rotation().z() - rotation_z0);
transformation.set_rotation({0, 0, instance->get_rotation().z() - rotation_z0});
const Transform3d& trafo = transformation.get_matrix();
Polygon inst_hull_2d = hull_2d.transform(trafo);
@ -5626,7 +5626,7 @@ void GLCanvas3D::update_sequential_clearance()
Geometry::Transformation transformation;
const Vec3d& offset = instance->get_offset();
transformation.set_offset({ offset.x(), offset.y(), 0.0 });
transformation.set_rotation(Z, instance->get_rotation().z() - rotation_z0);
transformation.set_rotation({0, 0, instance->get_rotation().z() - rotation_z0});
const Transform3d& trafo = transformation.get_matrix();
const Pointf3s& hull_2d = m_sequential_print_clearance.m_hull_2d_cache[i];
Points inst_pts;

View File

@ -633,8 +633,9 @@ void ArrangeJob::process()
BOOST_LOG_TRIVIAL(warning)<< "Arrange full params: "<< params.to_json();
BOOST_LOG_TRIVIAL(info) << boost::format("arrange: items selected before arranging: %1%") % m_selected.size();
for (auto selected : m_selected) {
BOOST_LOG_TRIVIAL(debug) << selected.name << ", extruder: " << selected.extrude_ids.back() << ", bed: " << selected.bed_idx << ", filemant_type:" << selected.filament_temp_type
<< ", trans: " << selected.translation.transpose();
BOOST_LOG_TRIVIAL(debug) << selected.name << ", extruder: " << selected.extrude_ids.back() << ", bed: " << selected.bed_idx
<< ", filemant_type:" << selected.filament_temp_type << ", trans: " << selected.translation.transpose()
<< ", rotation: " << selected.rotation;
}
BOOST_LOG_TRIVIAL(debug) << "arrange: items unselected before arrange: " << m_unselected.size();
for (auto item : m_unselected)
@ -651,10 +652,11 @@ void ArrangeJob::process()
for (auto selected : m_selected)
BOOST_LOG_TRIVIAL(debug) << selected.name << ", extruder: " << selected.extrude_ids.back() << ", bed: " << selected.bed_idx
<< ", bed_temp: " << selected.first_bed_temp << ", print_temp: " << selected.print_temp
<< ", trans: " << unscale<double>(selected.translation(X)) << ","<< unscale<double>(selected.translation(Y));
<< ", trans: " << unscale<double>(selected.translation(X)) << "," << unscale<double>(selected.translation(Y))
<< ", rotation: " << selected.rotation;
BOOST_LOG_TRIVIAL(debug) << "arrange: items unselected after arrange: "<< m_unselected.size();
for (auto item : m_unselected)
BOOST_LOG_TRIVIAL(debug) << item.name << ", bed: " << item.bed_idx << ", trans: " << item.translation.transpose();
BOOST_LOG_TRIVIAL(debug) << item.name << ", bed: " << item.bed_idx << ", trans: " << item.translation.transpose() << ", rotation: " << item.rotation;
}
// put unpackable items to m_unprintable so they goes outside