From f9a1ed7b248c01b68c42715b21eedd59dcfd7db2 Mon Sep 17 00:00:00 2001 From: Arthur Date: Wed, 27 Nov 2024 11:59:48 +0800 Subject: [PATCH] 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 --- src/libslic3r/Geometry.cpp | 21 +++++++------------ src/libslic3r/Geometry.hpp | 2 +- src/libslic3r/Model.cpp | 33 ++++++++++++++++++++---------- src/libslic3r/Model.hpp | 22 ++------------------ src/libslic3r/Print.cpp | 5 +++-- src/slic3r/GUI/3DScene.hpp | 2 -- src/slic3r/GUI/GLCanvas3D.cpp | 4 ++-- src/slic3r/GUI/Jobs/ArrangeJob.cpp | 10 +++++---- 8 files changed, 43 insertions(+), 56 deletions(-) diff --git a/src/libslic3r/Geometry.cpp b/src/libslic3r/Geometry.cpp index 93fa586ed..249cc69eb 100644 --- a/src/libslic3r/Geometry.cpp +++ b/src/libslic3r/Geometry.cpp @@ -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); diff --git a/src/libslic3r/Geometry.hpp b/src/libslic3r/Geometry.hpp index 02afe33a0..46d0d4c23 100644 --- a/src/libslic3r/Geometry.hpp +++ b/src/libslic3r/Geometry.hpp @@ -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]; } diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 9af7e9548..84b376629 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -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(offs(X))); + set_offset(Y, unscale(offs(Y))); + this->object->invalidate_bounding_box(); +} + indexed_triangle_set FacetsAnnotation::get_facets(const ModelVolume& mv, EnforcerBlockerType type) const { TriangleSelector selector(mv.mesh()); diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 0835b4273..7d36e97f5 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -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(offs(X))); - set_offset(Y, unscale(offs(Y))); - this->object->invalidate_bounding_box(); - } + void apply_arrange_result(const Vec2d &offs, double rotation); protected: friend class Print; diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index fd094356d..f53ea7c4a 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -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; diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index d4fa7ef22..5047c180c 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -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); } diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 4499ae716..f0340d30d 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -5446,7 +5446,7 @@ std::vector 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; diff --git a/src/slic3r/GUI/Jobs/ArrangeJob.cpp b/src/slic3r/GUI/Jobs/ArrangeJob.cpp index cd1e78ea7..a85331612 100644 --- a/src/slic3r/GUI/Jobs/ArrangeJob.cpp +++ b/src/slic3r/GUI/Jobs/ArrangeJob.cpp @@ -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(selected.translation(X)) << ","<< unscale(selected.translation(Y)); + << ", trans: " << unscale(selected.translation(X)) << "," << unscale(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