diff --git a/src/libslic3r/Geometry.cpp b/src/libslic3r/Geometry.cpp index c45f087919..a100f520a9 100644 --- a/src/libslic3r/Geometry.cpp +++ b/src/libslic3r/Geometry.cpp @@ -1166,7 +1166,11 @@ MedialAxis::retrieve_endpoint(const VD::cell_type* cell) const } } +#if ENABLE_MIRROR +void assemble_transform(Transform3d& transform, const Vec3d& translation, const Vec3d& rotation, const Vec3d& scale, const Vec3d& mirror) +#else void assemble_transform(Transform3d& transform, const Vec3d& translation, const Vec3d& rotation, const Vec3d& scale) +#endif // ENABLE_MIRROR { transform = Transform3d::Identity(); transform.translate(translation); @@ -1174,12 +1178,23 @@ void assemble_transform(Transform3d& transform, const Vec3d& translation, const transform.rotate(Eigen::AngleAxisd(rotation(1), Vec3d::UnitY())); transform.rotate(Eigen::AngleAxisd(rotation(0), Vec3d::UnitX())); transform.scale(scale); +#if ENABLE_MIRROR + transform.scale(mirror); +#endif // ENABLE_MIRROR } +#if ENABLE_MIRROR +Transform3d assemble_transform(const Vec3d& translation, const Vec3d& rotation, const Vec3d& scale, const Vec3d& mirror) +#else Transform3d assemble_transform(const Vec3d& translation, const Vec3d& rotation, const Vec3d& scale) +#endif // ENABLE_MIRROR { Transform3d transform; +#if ENABLE_MIRROR + assemble_transform(transform, translation, rotation, scale, mirror); +#else assemble_transform(transform, translation, rotation, scale); +#endif // ENABLE_MIRROR return transform; } diff --git a/src/libslic3r/Geometry.hpp b/src/libslic3r/Geometry.hpp index 35f59bdfd7..9046add258 100644 --- a/src/libslic3r/Geometry.hpp +++ b/src/libslic3r/Geometry.hpp @@ -158,20 +158,40 @@ class MedialAxis { }; // Sets the given transform by assembling the given transformations in the following order: +#if ENABLE_MIRROR +// 1) mirror +// 2) scale +// 3) rotate X +// 4) rotate Y +// 5) rotate Z +// 6) translate +void assemble_transform(Transform3d& transform, const Vec3d& translation = Vec3d::Zero(), const Vec3d& rotation = Vec3d::Zero(), const Vec3d& scale = Vec3d::Ones(), const Vec3d& mirror = Vec3d::Ones()); +#else // 1) scale // 2) rotate X // 3) rotate Y // 4) rotate Z // 5) translate void assemble_transform(Transform3d& transform, const Vec3d& translation = Vec3d::Zero(), const Vec3d& rotation = Vec3d::Zero(), const Vec3d& scale = Vec3d::Ones()); +#endif // ENABLE_MIRROR // Returns the transform obtained by assembling the given transformations in the following order: +#if ENABLE_MIRROR +// 1) mirror +// 2) scale +// 3) rotate X +// 4) rotate Y +// 5) rotate Z +// 6) translate +Transform3d assemble_transform(const Vec3d& translation = Vec3d::Zero(), const Vec3d& rotation = Vec3d::Zero(), const Vec3d& scale = Vec3d::Ones(), const Vec3d& mirror = Vec3d::Ones()); +#else // 1) scale // 2) rotate X // 3) rotate Y // 4) rotate Z // 5) translate Transform3d assemble_transform(const Vec3d& translation = Vec3d::Zero(), const Vec3d& rotation = Vec3d::Zero(), const Vec3d& scale = Vec3d::Ones()); +#endif // ENABLE_MIRROR // Returns the euler angles extracted from the given rotation matrix // Warning -> The matrix should not contain any scale or shear !!! diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index dc2c37c7fd..8e2d1f391c 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -1080,6 +1080,38 @@ void ModelInstance::set_rotation(Axis axis, double rotation) m_rotation(axis) = rotation; } +#if ENABLE_MIRROR +void ModelInstance::set_scaling_factor(const Vec3d& scaling_factor) +{ + set_scaling_factor(X, scaling_factor(0)); + set_scaling_factor(Y, scaling_factor(1)); + set_scaling_factor(Z, scaling_factor(2)); +} + +void ModelInstance::set_scaling_factor(Axis axis, double scaling_factor) +{ + m_scaling_factor(axis) = std::abs(scaling_factor); +} + +void ModelInstance::set_mirror(const Vec3d& mirror) +{ + set_mirror(X, mirror(0)); + set_mirror(Y, mirror(1)); + set_mirror(Z, mirror(2)); +} + +void ModelInstance::set_mirror(Axis axis, double mirror) +{ + double abs_mirror = std::abs(mirror); + if (abs_mirror == 0.0) + mirror = 1.0; + else if (abs_mirror != 1.0) + mirror /= abs_mirror; + + m_mirror(axis) = mirror; +} +#endif // ENABLE_MIRROR + void ModelInstance::transform_mesh(TriangleMesh* mesh, bool dont_translate) const { mesh->transform(world_matrix(dont_translate).cast()); @@ -1130,12 +1162,21 @@ void ModelInstance::transform_polygon(Polygon* polygon) const polygon->scale(this->m_scaling_factor(0), this->m_scaling_factor(1)); // scale around polygon origin } +#if ENABLE_MIRROR +Transform3d ModelInstance::world_matrix(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror) const +#else Transform3d ModelInstance::world_matrix(bool dont_translate, bool dont_rotate, bool dont_scale) const +#endif // ENABLE_MIRROR { Vec3d translation = dont_translate ? Vec3d::Zero() : m_offset; Vec3d rotation = dont_rotate ? Vec3d::Zero() : m_rotation; Vec3d scale = dont_scale ? Vec3d::Ones() : m_scaling_factor; +#if ENABLE_MIRROR + Vec3d mirror = dont_mirror ? Vec3d::Ones() : m_mirror; + return Geometry::assemble_transform(translation, rotation, scale, mirror); +#else return Geometry::assemble_transform(translation, rotation, scale); +#endif // ENABLE_MIRROR } } diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 7fd889ffb8..6c34292d31 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -251,6 +251,9 @@ private: Vec3d m_offset; // in unscaled coordinates Vec3d m_rotation; // Rotation around the three axes, in radians around mesh center point Vec3d m_scaling_factor; // Scaling factors along the three axes +#if ENABLE_MIRROR + Vec3d m_mirror; // Mirroring along the three axes +#endif // ENABLE_MIRROR public: // flag showing the position of this instance with respect to the print volume (set by Print::validate() using ModelObject::check_instances_print_volume_state()) @@ -273,8 +276,21 @@ public: Vec3d get_scaling_factor() const { return m_scaling_factor; } double get_scaling_factor(Axis axis) const { return m_scaling_factor(axis); } +#if ENABLE_MIRROR + void set_scaling_factor(const Vec3d& scaling_factor); + void set_scaling_factor(Axis axis, double scaling_factor); +#else void set_scaling_factor(const Vec3d& scaling_factor) { m_scaling_factor = scaling_factor; } void set_scaling_factor(Axis axis, double scaling_factor) { m_scaling_factor(axis) = scaling_factor; } +#endif // ENABLE_MIRROR + +#if ENABLE_MIRROR + const Vec3d& get_mirror() const { return m_mirror; } + double get_mirror(Axis axis) const { return m_mirror(axis); } + + void set_mirror(const Vec3d& mirror); + void set_mirror(Axis axis, double mirror); +#endif // ENABLE_MIRROR // To be called on an external mesh void transform_mesh(TriangleMesh* mesh, bool dont_translate = false) const; @@ -287,7 +303,11 @@ public: // To be called on an external polygon. It does not translate the polygon, only rotates and scales. void transform_polygon(Polygon* polygon) const; +#if ENABLE_MIRROR + Transform3d world_matrix(bool dont_translate = false, bool dont_rotate = false, bool dont_scale = false, bool dont_mirror = false) const; +#else Transform3d world_matrix(bool dont_translate = false, bool dont_rotate = false, bool dont_scale = false) const; +#endif // ENABLE_MIRROR bool is_printable() const { return print_volume_state == PVS_Inside; } @@ -295,9 +315,15 @@ private: // Parent object, owning this instance. ModelObject* object; +#if ENABLE_MIRROR + ModelInstance(ModelObject *object) : m_offset(Vec3d::Zero()), m_rotation(Vec3d::Zero()), m_scaling_factor(Vec3d::Ones()), m_mirror(Vec3d::Ones()), object(object), print_volume_state(PVS_Inside) {} + ModelInstance(ModelObject *object, const ModelInstance &other) : + m_offset(other.m_offset), m_rotation(other.m_rotation), m_scaling_factor(other.m_scaling_factor), m_mirror(other.m_mirror), object(object), print_volume_state(PVS_Inside) {} +#else ModelInstance(ModelObject *object) : m_rotation(Vec3d::Zero()), m_scaling_factor(Vec3d::Ones()), m_offset(Vec3d::Zero()), object(object), print_volume_state(PVS_Inside) {} ModelInstance(ModelObject *object, const ModelInstance &other) : m_rotation(other.m_rotation), m_scaling_factor(other.m_scaling_factor), m_offset(other.m_offset), object(object), print_volume_state(PVS_Inside) {} +#endif // ENABLE_MIRROR }; diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 4c653e543e..3f8fd80f0b 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -10,6 +10,8 @@ #define ENABLE_USE_UNIQUE_GLCONTEXT (1 && ENABLE_1_42_0) // New selections #define ENABLE_EXTENDED_SELECTION (1 && ENABLE_1_42_0) +// Add mirror components along the three axes in ModelInstance and GLVolume +#define ENABLE_MIRROR (0 && ENABLE_1_42_0) #endif // _technologies_h_ diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 402d7b8ee9..91f60947c5 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -198,6 +198,9 @@ GLVolume::GLVolume(float r, float g, float b, float a) : m_offset(Vec3d::Zero()) , m_rotation(Vec3d::Zero()) , m_scaling_factor(Vec3d::Ones()) +#if ENABLE_MIRROR + , m_mirror(Vec3d::Ones()) +#endif // ENABLE_MIRROR , m_world_matrix(Transform3f::Identity()) , m_world_matrix_dirty(true) , m_transformed_bounding_box_dirty(true) @@ -324,6 +327,40 @@ void GLVolume::set_scaling_factor(const Vec3d& scaling_factor) } } +#if ENABLE_MIRROR +const Vec3d& GLVolume::get_mirror() const +{ + return m_mirror; +} + +double GLVolume::get_mirror(Axis axis) const +{ + return m_mirror(axis); +} + +void GLVolume::set_mirror(const Vec3d& mirror) +{ + if (m_mirror != mirror) + { + m_mirror = mirror; + m_world_matrix_dirty = true; + m_transformed_bounding_box_dirty = true; + m_transformed_convex_hull_bounding_box_dirty = true; + } +} + +void GLVolume::set_mirror(Axis axis, double mirror) +{ + if (m_mirror(axis) != mirror) + { + m_mirror(axis) = mirror; + m_world_matrix_dirty = true; + m_transformed_bounding_box_dirty = true; + m_transformed_convex_hull_bounding_box_dirty = true; + } +} +#endif // ENABLE_MIRROR + void GLVolume::set_convex_hull(const TriangleMesh& convex_hull) { m_convex_hull = &convex_hull; @@ -353,7 +390,11 @@ const Transform3f& GLVolume::world_matrix() const { if (m_world_matrix_dirty) { +#if ENABLE_MIRROR + m_world_matrix = Geometry::assemble_transform(m_offset, m_rotation, m_scaling_factor, m_mirror).cast(); +#else m_world_matrix = Geometry::assemble_transform(m_offset, m_rotation, m_scaling_factor).cast(); +#endif // ENABLE_MIRROR m_world_matrix_dirty = false; } return m_world_matrix; @@ -729,6 +770,9 @@ std::vector GLVolumeCollection::load_object( v.set_offset(instance->get_offset()); v.set_rotation(instance->get_rotation()); v.set_scaling_factor(instance->get_scaling_factor()); +#if ENABLE_MIRROR + v.set_mirror(instance->get_mirror()); +#endif // ENABLE_MIRROR } } @@ -2076,6 +2120,15 @@ int _3DScene::get_in_object_volume_id(wxGLCanvas* canvas, int scene_vol_idx) return s_canvas_mgr.get_in_object_volume_id(canvas, scene_vol_idx); } +#if ENABLE_MIRROR +#if ENABLE_EXTENDED_SELECTION +void _3DScene::mirror_selection(wxGLCanvas* canvas, Axis axis) +{ + s_canvas_mgr.mirror_selection(canvas, axis); +} +#endif // ENABLE_EXTENDED_SELECTION +#endif // ENABLE_MIRROR + void _3DScene::reload_scene(wxGLCanvas* canvas, bool force) { s_canvas_mgr.reload_scene(canvas, force); diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index e3f7ea0d36..7e74ff92f2 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -260,6 +260,10 @@ private: Vec3d m_rotation; // Scale factor along the three axes of the volume to be rendered. Vec3d m_scaling_factor; +#if ENABLE_MIRROR + // Mirroring along the three axes of the volume to be rendered. + Vec3d m_mirror; +#endif // ENABLE_MIRROR // World matrix of the volume to be rendered. mutable Transform3f m_world_matrix; // Whether or not is needed to recalculate the world matrix. @@ -337,6 +341,13 @@ public: #endif // ENABLE_EXTENDED_SELECTION void set_scaling_factor(const Vec3d& scaling_factor); +#if ENABLE_MIRROR + const Vec3d& get_mirror() const; + double get_mirror(Axis axis) const; + void set_mirror(const Vec3d& mirror); + void set_mirror(Axis axis, double mirror); +#endif // ENABLE_MIRROR + const Vec3d& get_offset() const; void set_offset(const Vec3d& offset); @@ -581,6 +592,12 @@ public: static int get_first_volume_id(wxGLCanvas* canvas, int obj_idx); static int get_in_object_volume_id(wxGLCanvas* canvas, int scene_vol_idx); +#if ENABLE_MIRROR +#if ENABLE_EXTENDED_SELECTION + static void mirror_selection(wxGLCanvas* canvas, Axis axis); +#endif // ENABLE_EXTENDED_SELECTION +#endif // ENABLE_MIRROR + static void reload_scene(wxGLCanvas* canvas, bool force); static void load_gcode_preview(wxGLCanvas* canvas, const GCodePreviewData* preview_data, const std::vector& str_tool_colors); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 12cd32d560..6dce5cd16c 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1457,6 +1457,25 @@ void GLCanvas3D::Selection::scale(const Vec3d& scale) m_bounding_box_dirty = true; } +#if ENABLE_MIRROR +void GLCanvas3D::Selection::mirror(Axis axis) +{ + if (!m_valid) + return; + + for (unsigned int i : m_list) + { + if (is_single_full_instance()) + (*m_volumes)[i]->set_mirror(axis, -(*m_volumes)[i]->get_mirror(axis)); + } + + if (m_mode == Instance) + _synchronize_unselected_instances(); + + m_bounding_box_dirty = true; +} +#endif // ENABLE_MIRROR + void GLCanvas3D::Selection::render(bool show_indirect_selection) const { if (is_empty()) @@ -1780,6 +1799,9 @@ void GLCanvas3D::Selection::_synchronize_unselected_instances() int instance_idx = volume->instance_idx(); const Vec3d& rotation = volume->get_rotation(); const Vec3d& scaling_factor = volume->get_scaling_factor(); +#if ENABLE_MIRROR + const Vec3d& mirror = volume->get_mirror(); +#endif // ENABLE_MIRROR // Process unselected instances. for (unsigned int j = 0; j < (unsigned int)m_volumes->size(); ++j) @@ -1796,6 +1818,9 @@ void GLCanvas3D::Selection::_synchronize_unselected_instances() v->set_rotation(rotation); v->set_scaling_factor(scaling_factor); +#if ENABLE_MIRROR + v->set_mirror(mirror); +#endif // ENABLE_MIRROR done.insert(j); } @@ -3403,6 +3428,18 @@ int GLCanvas3D::get_in_object_volume_id(int scene_vol_idx) const return ((0 <= scene_vol_idx) && (scene_vol_idx < (int)m_volumes.volumes.size())) ? m_volumes.volumes[scene_vol_idx]->volume_idx() : -1; } +#if ENABLE_MIRROR +#if ENABLE_EXTENDED_SELECTION +void GLCanvas3D::mirror_selection(Axis axis) +{ + m_regenerate_volumes = false; + m_selection.mirror(axis); + _on_mirror(); + wxGetApp().obj_manipul()->update_settings_value(m_selection); +} +#endif // ENABLE_EXTENDED_SELECTION +#endif // ENABLE_MIRROR + void GLCanvas3D::reload_scene(bool force) { if ((m_canvas == nullptr) || (m_config == nullptr) || (m_model == nullptr)) @@ -6525,6 +6562,41 @@ void GLCanvas3D::_on_flatten() _on_rotate(); } +#if ENABLE_MIRROR +void GLCanvas3D::_on_mirror() +{ + if (m_model == nullptr) + return; + + std::set> done; // prevent mirroring instances twice + + for (const GLVolume* v : m_volumes.volumes) + { + int object_idx = v->object_idx(); + if (object_idx >= 1000) + continue; + + int instance_idx = v->instance_idx(); + + // prevent mirroring instances twice + std::pair done_id(object_idx, instance_idx); + if (done.find(done_id) != done.end()) + continue; + + done.insert(done_id); + + // Mirror instances. + ModelObject* model_object = m_model->objects[object_idx]; + if (model_object != nullptr) + { + model_object->instances[instance_idx]->set_mirror(v->get_mirror()); + model_object->invalidate_bounding_box(); + } + } + + // schedule_background_process +} +#endif // ENABLE_MIRROR #else void GLCanvas3D::_on_move(const std::vector& volume_idxs) { diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index c4e53cfe2f..58b414c8d9 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -501,6 +501,9 @@ public: void translate(const Vec3d& displacement); void rotate(const Vec3d& rotation); void scale(const Vec3d& scale); +#if ENABLE_MIRROR + void mirror(Axis axis); +#endif // ENABLE_MIRROR void render(bool show_indirect_selection) const; @@ -833,6 +836,12 @@ public: int get_first_volume_id(int obj_idx) const; int get_in_object_volume_id(int scene_vol_idx) const; +#if ENABLE_MIRROR +#if ENABLE_EXTENDED_SELECTION + void mirror_selection(Axis axis); +#endif // ENABLE_EXTENDED_SELECTION +#endif // ENABLE_MIRROR + void reload_scene(bool force); void load_gcode_preview(const GCodePreviewData& preview_data, const std::vector& str_tool_colors); @@ -955,6 +964,9 @@ private: void _on_rotate(); void _on_scale(); void _on_flatten(); +#if ENABLE_MIRROR + void _on_mirror(); +#endif // ENABLE_MIRROR #else void _on_move(const std::vector& volume_idxs); #endif // ENABLE_EXTENDED_SELECTION diff --git a/src/slic3r/GUI/GLCanvas3DManager.cpp b/src/slic3r/GUI/GLCanvas3DManager.cpp index 182298a690..1d963e3b7b 100644 --- a/src/slic3r/GUI/GLCanvas3DManager.cpp +++ b/src/slic3r/GUI/GLCanvas3DManager.cpp @@ -596,6 +596,17 @@ int GLCanvas3DManager::get_in_object_volume_id(wxGLCanvas* canvas, int scene_vol return (it != m_canvases.end()) ? it->second->get_in_object_volume_id(scene_vol_idx) : -1; } +#if ENABLE_MIRROR +#if ENABLE_EXTENDED_SELECTION +void GLCanvas3DManager::mirror_selection(wxGLCanvas* canvas, Axis axis) +{ + CanvasesMap::iterator it = _get_canvas(canvas); + if (it != m_canvases.end()) + it->second->mirror_selection(axis); +} +#endif // ENABLE_EXTENDED_SELECTION +#endif // ENABLE_MIRROR + void GLCanvas3DManager::reload_scene(wxGLCanvas* canvas, bool force) { CanvasesMap::iterator it = _get_canvas(canvas); diff --git a/src/slic3r/GUI/GLCanvas3DManager.hpp b/src/slic3r/GUI/GLCanvas3DManager.hpp index 2261a57b2b..89cb09e7f0 100644 --- a/src/slic3r/GUI/GLCanvas3DManager.hpp +++ b/src/slic3r/GUI/GLCanvas3DManager.hpp @@ -163,6 +163,12 @@ public: int get_first_volume_id(wxGLCanvas* canvas, int obj_idx) const; int get_in_object_volume_id(wxGLCanvas* canvas, int scene_vol_idx) const; +#if ENABLE_MIRROR +#if ENABLE_EXTENDED_SELECTION + void mirror_selection(wxGLCanvas* canvas, Axis axis); +#endif // ENABLE_EXTENDED_SELECTION +#endif // ENABLE_MIRROR + void reload_scene(wxGLCanvas* canvas, bool force); void load_gcode_preview(wxGLCanvas* canvas, const GCodePreviewData* preview_data, const std::vector& str_tool_colors); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 7981d66634..40fffc85ba 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1519,6 +1519,11 @@ void Plater::priv::rotate() void Plater::priv::mirror(Axis axis) { +#if ENABLE_MIRROR +#if ENABLE_EXTENDED_SELECTION + _3DScene::mirror_selection(canvas3D, axis); +#endif // ENABLE_EXTENDED_SELECTION +#else #if ENABLE_EXTENDED_SELECTION int obj_idx = get_selected_object_idx(); if (obj_idx == -1) @@ -1551,6 +1556,7 @@ void Plater::priv::mirror(Axis axis) #endif // ENABLE_EXTENDED_SELECTION selection_changed(); update(); +#endif // ENABLE_MIRROR } #if !ENABLE_EXTENDED_SELECTION