From 708a14c22847789c222bdfac5aa245c211769257 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Fri, 25 Jan 2019 14:56:41 +0100 Subject: [PATCH 1/4] Fix of instance synchronization. It seems to be working, but one may want to review the center of rotation of the instances when rotating around a general axis (zero component of the rotation axis in the world Z). --- src/slic3r/GUI/GLCanvas3D.cpp | 111 +++++++++++++++++++++++++--------- 1 file changed, 81 insertions(+), 30 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index a97c98135..79b9ffa68 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1731,55 +1731,64 @@ void GLCanvas3D::Selection::translate(const Vec3d& displacement, bool local) void GLCanvas3D::Selection::rotate(const Vec3d& rotation, bool local) { - if (!m_valid) + int rot_axis_max; + if (!m_valid || rotation.cwiseAbs().maxCoeff(&rot_axis_max) < EPSILON) return; + // For generic rotation, we want to rotate the first volume in selection, and then to synchronize the other volumes with it. + std::vector object_instance_first(m_model->objects.size(), -1); + auto rotate_instance = [this, &rotation, &object_instance_first, rot_axis_max, local](GLVolume &volume, int i) { + int first_volume_idx = object_instance_first[volume.object_idx()]; + if (rot_axis_max != 2 && first_volume_idx != -1) { + // Generic rotation, but no rotation around the Z axis. + // Always do a local rotation (do not consider the selection to be a rigid body). + assert(rotation.z() == 0); + const GLVolume &first_volume = *(*m_volumes)[first_volume_idx]; + const Vec3d &rotation = first_volume.get_instance_rotation(); + double z_diff = m_cache.volumes_data[i].get_instance_rotation()(2) - m_cache.volumes_data[first_volume_idx].get_instance_rotation()(2); + volume.set_instance_rotation(Vec3d(rotation(0), rotation(1), rotation(2) + z_diff)); + } else { + // extracts rotations from the composed transformation + Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation); + Vec3d new_rotation = Geometry::extract_euler_angles(m * m_cache.volumes_data[i].get_instance_rotation_matrix()); + if (!local) + volume.set_instance_offset(m_cache.dragging_center + m * (m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center)); + volume.set_instance_rotation(new_rotation); + object_instance_first[volume.object_idx()] = i; + } + }; + for (unsigned int i : m_list) { + GLVolume &volume = *(*m_volumes)[i]; if (is_single_full_instance()) - { - if (local) - (*m_volumes)[i]->set_instance_rotation(rotation); - else - { - Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation); - Vec3d new_rotation = Geometry::extract_euler_angles(m * m_cache.volumes_data[i].get_instance_rotation_matrix()); - (*m_volumes)[i]->set_instance_rotation(new_rotation); - } - } + rotate_instance(volume, i); else if (is_single_volume() || is_single_modifier()) { if (local) - (*m_volumes)[i]->set_volume_rotation(rotation); + volume.set_volume_rotation(rotation); else { Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation); Vec3d new_rotation = Geometry::extract_euler_angles(m * m_cache.volumes_data[i].get_volume_rotation_matrix()); - (*m_volumes)[i]->set_volume_rotation(new_rotation); + volume.set_volume_rotation(new_rotation); } } else { - Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation); if (m_mode == Instance) - { - // extracts rotations from the composed transformation - Vec3d new_rotation = Geometry::extract_euler_angles(m * m_cache.volumes_data[i].get_instance_rotation_matrix()); - if (!local) - (*m_volumes)[i]->set_instance_offset(m_cache.dragging_center + m * (m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center)); - - (*m_volumes)[i]->set_instance_rotation(new_rotation); - } + rotate_instance(volume, i); else if (m_mode == Volume) { // extracts rotations from the composed transformation + Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation); Vec3d new_rotation = Geometry::extract_euler_angles(m * m_cache.volumes_data[i].get_volume_rotation_matrix()); if (!local) { Vec3d offset = m * (m_cache.volumes_data[i].get_volume_position() + m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center); - (*m_volumes)[i]->set_volume_offset(m_cache.dragging_center - m_cache.volumes_data[i].get_instance_position() + offset); + volume.set_volume_offset(m_cache.dragging_center - m_cache.volumes_data[i].get_instance_position() + offset); } - (*m_volumes)[i]->set_volume_rotation(new_rotation); + volume.set_volume_rotation(new_rotation); } } } @@ -2699,6 +2708,40 @@ void GLCanvas3D::Selection::_render_sidebar_size_hint(Axis axis, double length) { } +#ifdef _DEBUG +static bool is_rotation_xy_synchronized(const Vec3d &rotation1, const Vec3d &rotation2) +{ + // The XYZ Euler angles are not unique. Rather then comparing the XY components of the two rotations, + // transform the up vector to one instance and back, which should lead to the same up vector. + Transform3d m1 = Geometry::assemble_transform(Vec3d::Zero(), rotation1); + Transform3d m2 = Geometry::assemble_transform(Vec3d::Zero(), rotation2); + Vec3d up0(0., 0., 1.); + Vec3d up = m1.rotation() * m2.rotation().inverse() * up0; + return (up - up0).cwiseAbs().maxCoeff() < EPSILON; +} +static void verify_instances_rotation_synchronized(const Model &model, const GLVolumePtrs &volumes) +{ + for (size_t idx_object = 0; idx_object < model.objects.size(); ++ idx_object) { + int idx_volume_first = -1; + for (int i = 0; i < (int)volumes.size(); ++ i) { + if (volumes[i]->object_idx() == idx_object) { + idx_volume_first = i; + break; + } + } + assert(idx_volume_first != -1); // object without instances? + if (idx_volume_first == -1) + continue; + const Vec3d &rotation0 = volumes[idx_volume_first]->get_instance_rotation(); + for (int i = idx_volume_first + 1; i < (int)volumes.size(); ++ i) + if (volumes[i]->object_idx() == idx_object) { + const Vec3d &rotation = volumes[i]->get_instance_rotation(); + assert(is_rotation_xy_synchronized(rotation, rotation0)); + } + } +} +#endif /* _DEBUG */ + void GLCanvas3D::Selection::_synchronize_unselected_instances(bool including_z) { std::set done; // prevent processing volumes twice @@ -2738,12 +2781,16 @@ void GLCanvas3D::Selection::_synchronize_unselected_instances(bool including_z) if (including_z) // rotation comes from place on face -> force given z z = rotation(2); - else if (is_approx(rotation(0), m_cache.volumes_data[j].get_instance_rotation()(0)) && is_approx(rotation(1), m_cache.volumes_data[j].get_instance_rotation()(1))) - // z only rotation -> keep instance z - z = v->get_instance_rotation()(2); - else - // generic rotation -> update instance z - z = m_cache.volumes_data[j].get_instance_rotation()(2) + rotation(2); + else if (is_approx(rotation(0), m_cache.volumes_data[j].get_instance_rotation()(0)) && is_approx(rotation(1), m_cache.volumes_data[j].get_instance_rotation()(1))) { + // z only rotation -> keep instance z + z = v->get_instance_rotation()(2); + // The X,Y rotations should be synchronized from start to end of the rotation. + assert(is_rotation_xy_synchronized(m_cache.volumes_data[i].get_instance_rotation(), m_cache.volumes_data[j].get_instance_rotation())); + assert(is_rotation_xy_synchronized(rotation, v->get_instance_rotation())); + } else { + // generic rotation -> update instance z with the delta of the rotation. + z = rotation(2) + m_cache.volumes_data[j].get_instance_rotation()(2) - m_cache.volumes_data[i].get_instance_rotation()(2); + } v->set_instance_rotation(Vec3d(rotation(0), rotation(1), z)); v->set_instance_scaling_factor(scaling_factor); @@ -2752,6 +2799,10 @@ void GLCanvas3D::Selection::_synchronize_unselected_instances(bool including_z) done.insert(j); } } + +#ifdef _DEBUG + verify_instances_rotation_synchronized(*m_model, *m_volumes); +#endif /* _DEBUG */ } void GLCanvas3D::Selection::_synchronize_unselected_volumes() From bb0cf221bcfd68e5e729be787b3dc29dbd25fe81 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 28 Jan 2019 08:52:22 +0100 Subject: [PATCH 2/4] WIP synchronization of Z rotation of the instances --- src/libslic3r/Geometry.cpp | 12 ++--- src/libslic3r/Geometry.hpp | 2 +- src/libslic3r/Model.hpp | 2 +- src/slic3r/GUI/GLCanvas3D.cpp | 97 ++++++++++++++++++++++++----------- src/slic3r/GUI/GLCanvas3D.hpp | 10 +++- 5 files changed, 84 insertions(+), 39 deletions(-) diff --git a/src/libslic3r/Geometry.cpp b/src/libslic3r/Geometry.cpp index b84e2f13d..cbb38b9bb 100644 --- a/src/libslic3r/Geometry.cpp +++ b/src/libslic3r/Geometry.cpp @@ -1189,16 +1189,16 @@ Vec3d extract_euler_angles(const Eigen::Matrix& Vec3d angles2 = Vec3d::Zero(); if (is_approx(std::abs(rotation_matrix(2, 0)), 1.0)) { - angles1(0) = 0.0; - if (rotation_matrix(2, 0) > 0.0) // == +1.0 + angles1(2) = 0.0; + if (rotation_matrix(2, 0) < 0.0) // == -1.0 { angles1(1) = 0.5 * (double)PI; - angles1(2) = angles1(0) + ::atan2(rotation_matrix(0, 1), rotation_matrix(0, 2)); + angles1(0) = angles1(2) + ::atan2(rotation_matrix(0, 1), rotation_matrix(0, 2)); } - else // == -1.0 + else // == 1.0 { - angles1(1) = 0.5 * (double)PI; - angles1(2) = -angles1(0) - ::atan2(rotation_matrix(0, 1), rotation_matrix(0, 2)); + angles1(1) = - 0.5 * (double)PI; + angles1(0) = - angles1(2) + ::atan2(- rotation_matrix(0, 1), - rotation_matrix(0, 2)); } angles2 = angles1; } diff --git a/src/libslic3r/Geometry.hpp b/src/libslic3r/Geometry.hpp index deefaa789..b43d59143 100644 --- a/src/libslic3r/Geometry.hpp +++ b/src/libslic3r/Geometry.hpp @@ -237,7 +237,7 @@ public: void set_rotation(const Vec3d& rotation); void set_rotation(Axis axis, double rotation); - Vec3d get_scaling_factor() const { return m_scaling_factor; } + const Vec3d& get_scaling_factor() const { return m_scaling_factor; } double get_scaling_factor(Axis axis) const { return m_scaling_factor(axis); } void set_scaling_factor(const Vec3d& scaling_factor); diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index f13baee08..1448ee447 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -464,7 +464,7 @@ public: void set_rotation(const Vec3d& rotation) { m_transformation.set_rotation(rotation); } void set_rotation(Axis axis, double rotation) { m_transformation.set_rotation(axis, rotation); } - Vec3d get_scaling_factor() const { return m_transformation.get_scaling_factor(); } + 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); } void set_scaling_factor(const Vec3d& scaling_factor) { m_transformation.set_scaling_factor(scaling_factor); } diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 79b9ffa68..f193af9e0 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1,3 +1,13 @@ +#if 1 +#pragma optimize("", off) +// Enable debugging and assert in this file. +#define DEBUG +#define _DEBUG +#undef NDEBUG +#endif + +#include + #include "slic3r/GUI/GLGizmo.hpp" #include "GLCanvas3D.hpp" @@ -1721,7 +1731,7 @@ void GLCanvas3D::Selection::translate(const Vec3d& displacement, bool local) #if !DISABLE_INSTANCES_SYNCH if (m_mode == Instance) - _synchronize_unselected_instances(); + _synchronize_unselected_instances(SYNC_ROTATION_NONE); else if (m_mode == Volume) _synchronize_unselected_volumes(); #endif // !DISABLE_INSTANCES_SYNCH @@ -1729,6 +1739,30 @@ void GLCanvas3D::Selection::translate(const Vec3d& displacement, bool local) m_bounding_box_dirty = true; } +static Eigen::Quaterniond rotation_xyz_diff(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to) +{ + return + // From the current coordinate system to world. + Eigen::AngleAxisd(rot_xyz_to(2), Vec3d::UnitZ()) * Eigen::AngleAxisd(rot_xyz_to(1), Vec3d::UnitY()) * Eigen::AngleAxisd(rot_xyz_to(0), Vec3d::UnitX()) * + // From world to the initial coordinate system. + Eigen::AngleAxisd(-rot_xyz_from(0), Vec3d::UnitX()) * Eigen::AngleAxisd(-rot_xyz_from(1), Vec3d::UnitY()) * Eigen::AngleAxisd(-rot_xyz_from(2), Vec3d::UnitZ()); +} + +// This should only be called if it is known, that the two rotations only differ in rotation around the Z axis. +static double rotation_diff_z(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to) +{ + Eigen::AngleAxisd angle_axis(rotation_xyz_diff(rot_xyz_from, rot_xyz_to)); + Vec3d axis = angle_axis.axis(); + double angle = angle_axis.angle(); +#ifdef _DEBUG + if (std::abs(angle) > 1e-8) { + assert(std::abs(axis.x()) < 1e-8); + assert(std::abs(axis.y()) < 1e-8); + } +#endif /* _DEBUG */ + return (axis.z() < 0) ? -angle : angle; +} + void GLCanvas3D::Selection::rotate(const Vec3d& rotation, bool local) { int rot_axis_max; @@ -1745,13 +1779,14 @@ void GLCanvas3D::Selection::rotate(const Vec3d& rotation, bool local) assert(rotation.z() == 0); const GLVolume &first_volume = *(*m_volumes)[first_volume_idx]; const Vec3d &rotation = first_volume.get_instance_rotation(); - double z_diff = m_cache.volumes_data[i].get_instance_rotation()(2) - m_cache.volumes_data[first_volume_idx].get_instance_rotation()(2); + double z_diff = rotation_diff_z(m_cache.volumes_data[first_volume_idx].get_instance_rotation(), m_cache.volumes_data[i].get_instance_rotation()); volume.set_instance_rotation(Vec3d(rotation(0), rotation(1), rotation(2) + z_diff)); } else { // extracts rotations from the composed transformation Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation); Vec3d new_rotation = Geometry::extract_euler_angles(m * m_cache.volumes_data[i].get_instance_rotation_matrix()); - if (!local) + if (rot_axis_max == 2 && !local) + // Only allow rotation of multiple instances as a single rigid body when rotating around the Z axis. volume.set_instance_offset(m_cache.dragging_center + m * (m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center)); volume.set_instance_rotation(new_rotation); object_instance_first[volume.object_idx()] = i; @@ -1795,7 +1830,7 @@ void GLCanvas3D::Selection::rotate(const Vec3d& rotation, bool local) #if !DISABLE_INSTANCES_SYNCH if (m_mode == Instance) - _synchronize_unselected_instances(); + _synchronize_unselected_instances((rot_axis_max == 2) ? SYNC_ROTATION_NONE : SYNC_ROTATION_GENERAL); else if (m_mode == Volume) _synchronize_unselected_volumes(); #endif // !DISABLE_INSTANCES_SYNCH @@ -1838,7 +1873,7 @@ void GLCanvas3D::Selection::flattening_rotate(const Vec3d& normal) // we want to synchronize z-rotation as well, otherwise the flattening behaves funny // when applied on one of several identical instances if (m_mode == Instance) - _synchronize_unselected_instances(true); + _synchronize_unselected_instances(SYNC_ROTATION_FULL); #endif // !DISABLE_INSTANCES_SYNCH m_bounding_box_dirty = true; @@ -1885,7 +1920,7 @@ void GLCanvas3D::Selection::scale(const Vec3d& scale, bool local) #if !DISABLE_INSTANCES_SYNCH if (m_mode == Instance) - _synchronize_unselected_instances(); + _synchronize_unselected_instances(SYNC_ROTATION_NONE); else if (m_mode == Volume) _synchronize_unselected_volumes(); #endif // !DISABLE_INSTANCES_SYNCH @@ -1912,7 +1947,7 @@ void GLCanvas3D::Selection::mirror(Axis axis) #if !DISABLE_INSTANCES_SYNCH if (m_mode == Instance) - _synchronize_unselected_instances(); + _synchronize_unselected_instances(SYNC_ROTATION_NONE); else if (m_mode == Volume) _synchronize_unselected_volumes(); #endif // !DISABLE_INSTANCES_SYNCH @@ -2709,15 +2744,17 @@ void GLCanvas3D::Selection::_render_sidebar_size_hint(Axis axis, double length) } #ifdef _DEBUG -static bool is_rotation_xy_synchronized(const Vec3d &rotation1, const Vec3d &rotation2) +static bool is_rotation_xy_synchronized(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to) { - // The XYZ Euler angles are not unique. Rather then comparing the XY components of the two rotations, - // transform the up vector to one instance and back, which should lead to the same up vector. - Transform3d m1 = Geometry::assemble_transform(Vec3d::Zero(), rotation1); - Transform3d m2 = Geometry::assemble_transform(Vec3d::Zero(), rotation2); - Vec3d up0(0., 0., 1.); - Vec3d up = m1.rotation() * m2.rotation().inverse() * up0; - return (up - up0).cwiseAbs().maxCoeff() < EPSILON; + Eigen::AngleAxisd angle_axis(rotation_xyz_diff(rot_xyz_from, rot_xyz_to)); + Vec3d axis = angle_axis.axis(); + double angle = angle_axis.angle(); + if (std::abs(angle) < 1e-8) + return true; + assert(std::abs(axis.x()) < 1e-8); + assert(std::abs(axis.y()) < 1e-8); + assert(std::abs(std::abs(axis.z()) - 1.) < 1e-8); + return std::abs(axis.x()) < 1e-8 && std::abs(axis.y()) < 1e-8 && std::abs(std::abs(axis.z()) - 1.) < 1e-8; } static void verify_instances_rotation_synchronized(const Model &model, const GLVolumePtrs &volumes) { @@ -2742,7 +2779,7 @@ static void verify_instances_rotation_synchronized(const Model &model, const GLV } #endif /* _DEBUG */ -void GLCanvas3D::Selection::_synchronize_unselected_instances(bool including_z) +void GLCanvas3D::Selection::_synchronize_unselected_instances(SyncRotationType sync_rotation_type) { std::set done; // prevent processing volumes twice done.insert(m_list.begin(), m_list.end()); @@ -2758,7 +2795,7 @@ void GLCanvas3D::Selection::_synchronize_unselected_instances(bool including_z) continue; int instance_idx = volume->instance_idx(); - const Vec3d& rotation = volume->get_instance_rotation(); + const Vec3d& rotation = volume->get_instance_rotation(); const Vec3d& scaling_factor = volume->get_instance_scaling_factor(); const Vec3d& mirror = volume->get_instance_mirror(); @@ -2775,24 +2812,24 @@ void GLCanvas3D::Selection::_synchronize_unselected_instances(bool including_z) if ((v->object_idx() != object_idx) || (v->instance_idx() == instance_idx)) continue; - auto is_approx = [](double value, double test_value) -> bool { return std::abs(value - test_value) < EPSILON; }; - - double z; - if (including_z) - // rotation comes from place on face -> force given z - z = rotation(2); - else if (is_approx(rotation(0), m_cache.volumes_data[j].get_instance_rotation()(0)) && is_approx(rotation(1), m_cache.volumes_data[j].get_instance_rotation()(1))) { + assert(is_rotation_xy_synchronized(m_cache.volumes_data[i].get_instance_rotation(), m_cache.volumes_data[j].get_instance_rotation())); + switch (sync_rotation_type) { + case SYNC_ROTATION_NONE: // z only rotation -> keep instance z - z = v->get_instance_rotation()(2); // The X,Y rotations should be synchronized from start to end of the rotation. - assert(is_rotation_xy_synchronized(m_cache.volumes_data[i].get_instance_rotation(), m_cache.volumes_data[j].get_instance_rotation())); assert(is_rotation_xy_synchronized(rotation, v->get_instance_rotation())); - } else { + break; + case SYNC_ROTATION_FULL: + // rotation comes from place on face -> force given z + v->set_instance_rotation(Vec3d(rotation(0), rotation(1), rotation(2))); + break; + case SYNC_ROTATION_GENERAL: // generic rotation -> update instance z with the delta of the rotation. - z = rotation(2) + m_cache.volumes_data[j].get_instance_rotation()(2) - m_cache.volumes_data[i].get_instance_rotation()(2); + double z_diff = rotation_diff_z(m_cache.volumes_data[i].get_instance_rotation(), m_cache.volumes_data[j].get_instance_rotation()); + v->set_instance_rotation(Vec3d(rotation(0), rotation(1), rotation(2) + z_diff)); + break; } - v->set_instance_rotation(Vec3d(rotation(0), rotation(1), z)); v->set_instance_scaling_factor(scaling_factor); v->set_instance_mirror(mirror); @@ -4570,7 +4607,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re } if (printer_technology == ptSLA) { const SLAPrint *sla_print = this->sla_print(); - #ifdef _DEBUG + #if 0 // #ifdef _DEBUG // Verify that the SLAPrint object is synchronized with m_model. check_model_ids_equal(*m_model, sla_print->model()); #endif /* _DEBUG */ diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index fb4a465d2..53ab1ed09 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -647,7 +647,15 @@ public: void _render_sidebar_rotation_hint(Axis axis) const; void _render_sidebar_scale_hint(Axis axis) const; void _render_sidebar_size_hint(Axis axis, double length) const; - void _synchronize_unselected_instances(bool including_z = false); + enum SyncRotationType { + // Do not synchronize rotation. Either not rotating at all, or rotating by world Z axis. + SYNC_ROTATION_NONE = 0, + // Synchronize fully. Used from "place on bed" feature. + SYNC_ROTATION_FULL = 1, + // Synchronize after rotation by an axis not parallel with Z. + SYNC_ROTATION_GENERAL = 2, + }; + void _synchronize_unselected_instances(SyncRotationType sync_rotation_type); void _synchronize_unselected_volumes(); void _ensure_on_bed(); }; From 66ecdf61ec6831dc9c6f0a2c130428c1aa252466 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 28 Jan 2019 08:53:02 +0100 Subject: [PATCH 3/4] FIx of the previous commit --- src/slic3r/GUI/GLCanvas3D.cpp | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index f193af9e0..d96db8945 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1,13 +1,3 @@ -#if 1 -#pragma optimize("", off) -// Enable debugging and assert in this file. -#define DEBUG -#define _DEBUG -#undef NDEBUG -#endif - -#include - #include "slic3r/GUI/GLGizmo.hpp" #include "GLCanvas3D.hpp" @@ -4607,7 +4597,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re } if (printer_technology == ptSLA) { const SLAPrint *sla_print = this->sla_print(); - #if 0 // #ifdef _DEBUG + #ifdef _DEBUG // Verify that the SLAPrint object is synchronized with m_model. check_model_ids_equal(*m_model, sla_print->model()); #endif /* _DEBUG */ From 6f25a933b63a00a639c1aebcb425fed9ff5d678d Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 28 Jan 2019 09:59:22 +0100 Subject: [PATCH 4/4] Removed check of max rotation close to zero in GLCanvas3D::Selection::rotate() --- src/slic3r/GUI/GLCanvas3D.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index fb0768e75..a65478bdc 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1804,10 +1804,12 @@ static double rotation_diff_z(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to void GLCanvas3D::Selection::rotate(const Vec3d& rotation, bool local) { - int rot_axis_max; - if (!m_valid || rotation.cwiseAbs().maxCoeff(&rot_axis_max) < EPSILON) + if (!m_valid) return; + int rot_axis_max; + rotation.cwiseAbs().maxCoeff(&rot_axis_max); + // For generic rotation, we want to rotate the first volume in selection, and then to synchronize the other volumes with it. std::vector object_instance_first(m_model->objects.size(), -1); auto rotate_instance = [this, &rotation, &object_instance_first, rot_axis_max, local](GLVolume &volume, int i) {