diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index d33f44c35..577d16c3c 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -624,8 +624,16 @@ const BoundingBoxf3& ModelObject::bounding_box() const BoundingBoxf3 raw_bbox; for (const ModelVolume *v : this->volumes) if (v->is_model_part()) +#if ENABLE_MODELVOLUME_TRANSFORM + { + TriangleMesh m = v->mesh; + m.transform(v->get_matrix().cast()); + raw_bbox.merge(m.bounding_box()); + } +#else // mesh.bounding_box() returns a cached value. raw_bbox.merge(v->mesh.bounding_box()); +#endif // ENABLE_MODELVOLUME_TRANSFORM BoundingBoxf3 bb; for (const ModelInstance *i : this->instances) bb.merge(i->transform_bounding_box(raw_bbox)); @@ -656,7 +664,15 @@ TriangleMesh ModelObject::raw_mesh() const TriangleMesh mesh; for (const ModelVolume *v : this->volumes) if (v->is_model_part()) - mesh.merge(v->mesh); +#if ENABLE_MODELVOLUME_TRANSFORM + { + TriangleMesh vol_mesh(v->mesh); + vol_mesh.transform(v->get_matrix().cast()); + mesh.merge(vol_mesh); + } +#else + mesh.merge(v->mesh); +#endif // ENABLE_MODELVOLUME_TRANSFORM return mesh; } @@ -699,12 +715,14 @@ void ModelObject::center_around_origin() this->translate(shift); this->origin_translation += shift; +#if !ENABLE_MODELVOLUME_TRANSFORM if (!this->instances.empty()) { for (ModelInstance *i : this->instances) { i->set_offset(i->get_offset() - shift); } this->invalidate_bounding_box(); } +#endif // !ENABLE_MODELVOLUME_TRANSFORM } void ModelObject::ensure_on_bed() @@ -731,8 +749,12 @@ void ModelObject::translate(double x, double y, double z) { for (ModelVolume *v : this->volumes) { +#if ENABLE_MODELVOLUME_TRANSFORM + v->translate(x, y, z); +#else v->mesh.translate(float(x), float(y), float(z)); v->m_convex_hull.translate(float(x), float(y), float(z)); +#endif // ENABLE_MODELVOLUME_TRANSFORM } if (m_bounding_box_valid) @@ -918,17 +940,29 @@ double ModelObject::get_instance_min_z(size_t instance_idx) const double min_z = DBL_MAX; ModelInstance* inst = instances[instance_idx]; - const Transform3d& m = inst->get_matrix(true); + const Transform3d& mi = inst->get_matrix(true); - for (ModelVolume *v : volumes) + for (const ModelVolume* v : volumes) { +#if ENABLE_MODELVOLUME_TRANSFORM + Transform3d mv = mi * v->get_matrix(); + const TriangleMesh& hull = v->get_convex_hull(); + for (uint32_t f = 0; f < hull.stl.stats.number_of_facets; ++f) + { + const stl_facet* facet = hull.stl.facet_start + f; + min_z = std::min(min_z, Vec3d::UnitZ().dot(mv * facet->vertex[0].cast())); + min_z = std::min(min_z, Vec3d::UnitZ().dot(mv * facet->vertex[1].cast())); + min_z = std::min(min_z, Vec3d::UnitZ().dot(mv * facet->vertex[2].cast())); + } +#else for (uint32_t f = 0; f < v->mesh.stl.stats.number_of_facets; ++f) { const stl_facet* facet = v->mesh.stl.facet_start + f; - min_z = std::min(min_z, Vec3d::UnitZ().dot(m * facet->vertex[0].cast())); - min_z = std::min(min_z, Vec3d::UnitZ().dot(m * facet->vertex[1].cast())); - min_z = std::min(min_z, Vec3d::UnitZ().dot(m * facet->vertex[2].cast())); + min_z = std::min(min_z, Vec3d::UnitZ().dot(mi * facet->vertex[0].cast())); + min_z = std::min(min_z, Vec3d::UnitZ().dot(mi * facet->vertex[1].cast())); + min_z = std::min(min_z, Vec3d::UnitZ().dot(mi * facet->vertex[2].cast())); } +#endif // ENABLE_MODELVOLUME_TRANSFORM } return min_z + inst->get_offset(Z); @@ -1115,8 +1149,12 @@ void ModelVolume::translate(double x, double y, double z) void ModelVolume::translate(const Vec3d& displacement) { +#if ENABLE_MODELVOLUME_TRANSFORM + m_transformation.set_offset(m_transformation.get_offset() + displacement); +#else mesh.translate((float)displacement(0), (float)displacement(1), (float)displacement(2)); m_convex_hull.translate((float)displacement(0), (float)displacement(1), (float)displacement(2)); +#endif // ENABLE_MODELVOLUME_TRANSFORM } #if !ENABLE_MODELVOLUME_TRANSFORM diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index b72f20501..92cef8e6d 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -306,8 +306,25 @@ private: if (mesh.stl.stats.number_of_facets > 1) calculate_convex_hull(); } - ModelVolume(ModelObject *object, TriangleMesh &&mesh, TriangleMesh &&convex_hull) : + ModelVolume(ModelObject *object, TriangleMesh &&mesh, TriangleMesh &&convex_hull) : mesh(std::move(mesh)), m_convex_hull(std::move(convex_hull)), m_type(MODEL_PART), object(object) {} + +#if ENABLE_MODELVOLUME_TRANSFORM + ModelVolume(ModelObject *object, const ModelVolume &other) : + ModelBase(other), // copy the ID + name(other.name), mesh(other.mesh), m_convex_hull(other.m_convex_hull), config(other.config), m_type(other.m_type), object(object), m_transformation(other.m_transformation) + { + this->set_material_id(other.material_id()); + } + ModelVolume(ModelObject *object, const ModelVolume &other, const TriangleMesh &&mesh) : + ModelBase(other), // copy the ID + name(other.name), mesh(std::move(mesh)), config(other.config), m_type(other.m_type), object(object), m_transformation(other.m_transformation) + { + this->set_material_id(other.material_id()); + if (mesh.stl.stats.number_of_facets > 1) + calculate_convex_hull(); + } +#else ModelVolume(ModelObject *object, const ModelVolume &other) : ModelBase(other), // copy the ID name(other.name), mesh(other.mesh), m_convex_hull(other.m_convex_hull), config(other.config), m_type(other.m_type), object(object) @@ -322,6 +339,7 @@ private: if (mesh.stl.stats.number_of_facets > 1) calculate_convex_hull(); } +#endif // ENABLE_MODELVOLUME_TRANSFORM explicit ModelVolume(ModelVolume &rhs) = delete; ModelVolume& operator=(ModelVolume &rhs) = delete; diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 16b3ff773..57745cae4 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -615,8 +615,12 @@ static inline bool model_volume_list_changed(const ModelObject &model_object_old if (mv_old.id() != mv_new.id()) return true; //FIXME test for the content of the mesh! - //FIXME test for the transformation matrices! - ++ i_old; + +#if ENABLE_MODELVOLUME_TRANSFORM + if (!mv_old.get_matrix().isApprox(mv_new.get_matrix())) + return true; +#endif // ENABLE_MODELVOLUME_TRANSFORM + ++i_old; ++ i_new; } for (; i_old < model_object_old.volumes.size(); ++ i_old) { diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 8f9146766..9ae654cbc 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -1601,7 +1601,15 @@ std::vector PrintObject::_slice_volumes(const std::vector &z, //FIXME better to perform slicing over each volume separately and then to use a Boolean operation to merge them. TriangleMesh mesh; for (const ModelVolume *v : volumes) - mesh.merge(v->mesh); +#if ENABLE_MODELVOLUME_TRANSFORM + { + TriangleMesh vol_mesh(v->mesh); + vol_mesh.transform(v->get_matrix().cast()); + mesh.merge(vol_mesh); + } +#else + mesh.merge(v->mesh); +#endif // ENABLE_MODELVOLUME_TRANSFORM if (mesh.stl.stats.number_of_facets > 0) { mesh.transform(m_trafo.cast()); // apply XY shift diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 6fb9e4bcb..11f0b570e 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -723,7 +723,11 @@ std::vector GLVolumeCollection::load_object( for (int instance_idx : instance_idxs) { const ModelInstance *instance = model_object->instances[instance_idx]; +#if ENABLE_MODELVOLUME_TRANSFORM + const TriangleMesh& mesh = model_volume->mesh; +#else TriangleMesh mesh = model_volume->mesh; +#endif // ENABLE_MODELVOLUME_TRANSFORM volumes_idx.push_back(int(this->volumes.size())); float color[4]; memcpy(color, colors[((color_by == "volume") ? volume_idx : obj_idx) % 4], sizeof(float) * 3); @@ -758,7 +762,8 @@ std::vector GLVolumeCollection::load_object( v.is_modifier = ! model_volume->is_model_part(); v.shader_outside_printer_detection_enabled = model_volume->is_model_part(); #if ENABLE_MODELVOLUME_TRANSFORM - v.set_transformation(instance->get_transformation()); + v.set_instance_transformation(instance->get_transformation()); + v.set_volume_transformation(model_volume->get_transformation()); #else v.set_offset(instance->get_offset()); v.set_rotation(instance->get_rotation()); @@ -833,7 +838,11 @@ int GLVolumeCollection::load_wipe_tower_preview( else v.indexed_vertex_array.load_mesh_flat_shading(mesh); +#if ENABLE_MODELVOLUME_TRANSFORM + v.set_volume_offset(Vec3d(pos_x, pos_y, 0.0)); +#else v.set_offset(Vec3d(pos_x, pos_y, 0.0)); +#endif // ENABLE_MODELVOLUME_TRANSFORM // finalize_geometry() clears the vertex arrays, therefore the bounding box has to be computed before finalize_geometry(). v.bounding_box = v.indexed_vertex_array.bounding_box(); diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index a69147a86..8384e11b8 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -255,7 +255,8 @@ public: private: #if ENABLE_MODELVOLUME_TRANSFORM - Geometry::Transformation m_transformation; + Geometry::Transformation m_instance_transformation; + Geometry::Transformation m_volume_transformation; #else // Offset of the volume to be rendered. Vec3d m_offset; @@ -329,32 +330,59 @@ public: void set_render_color(); #if ENABLE_MODELVOLUME_TRANSFORM - const Geometry::Transformation& get_transformation() const { return m_transformation; } - void set_transformation(const Geometry::Transformation& transformation) { m_transformation = transformation; set_bounding_boxes_as_dirty(); } + const Geometry::Transformation& get_instance_transformation() const { return m_instance_transformation; } + void set_instance_transformation(const Geometry::Transformation& transformation) { m_instance_transformation = transformation; set_bounding_boxes_as_dirty(); } - const Vec3d& get_offset() const { return m_transformation.get_offset(); } - double get_offset(Axis axis) const { return m_transformation.get_offset(axis); } + const Vec3d& get_instance_offset() const { return m_instance_transformation.get_offset(); } + double get_instance_offset(Axis axis) const { return m_instance_transformation.get_offset(axis); } - void set_offset(const Vec3d& offset) { m_transformation.set_offset(offset); set_bounding_boxes_as_dirty(); } - void set_offset(Axis axis, double offset) { m_transformation.set_offset(axis, offset); set_bounding_boxes_as_dirty(); } + void set_instance_offset(const Vec3d& offset) { m_instance_transformation.set_offset(offset); set_bounding_boxes_as_dirty(); } + void set_instance_offset(Axis axis, double offset) { m_instance_transformation.set_offset(axis, offset); set_bounding_boxes_as_dirty(); } - const Vec3d& get_rotation() const { return m_transformation.get_rotation(); } - double get_rotation(Axis axis) const { return m_transformation.get_rotation(axis); } + const Vec3d& get_instance_rotation() const { return m_instance_transformation.get_rotation(); } + double get_instance_rotation(Axis axis) const { return m_instance_transformation.get_rotation(axis); } - void set_rotation(const Vec3d& rotation) { m_transformation.set_rotation(rotation); set_bounding_boxes_as_dirty(); } - void set_rotation(Axis axis, double rotation) { m_transformation.set_rotation(axis, rotation); set_bounding_boxes_as_dirty(); } + 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_scaling_factor() const { return m_transformation.get_scaling_factor(); } - double get_scaling_factor(Axis axis) const { return m_transformation.get_scaling_factor(axis); } + 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); } - void set_scaling_factor(const Vec3d& scaling_factor) { m_transformation.set_scaling_factor(scaling_factor); set_bounding_boxes_as_dirty(); } - void set_scaling_factor(Axis axis, double scaling_factor) { m_transformation.set_scaling_factor(axis, scaling_factor); set_bounding_boxes_as_dirty(); } + void set_instance_scaling_factor(const Vec3d& scaling_factor) { m_instance_transformation.set_scaling_factor(scaling_factor); set_bounding_boxes_as_dirty(); } + void set_instance_scaling_factor(Axis axis, double scaling_factor) { m_instance_transformation.set_scaling_factor(axis, scaling_factor); set_bounding_boxes_as_dirty(); } - const Vec3d& get_mirror() const { return m_transformation.get_mirror(); } - double get_mirror(Axis axis) const { return m_transformation.get_mirror(axis); } + const Vec3d& get_instance_mirror() const { return m_instance_transformation.get_mirror(); } + double get_instance_mirror(Axis axis) const { return m_instance_transformation.get_mirror(axis); } - void set_mirror(const Vec3d& mirror) { m_transformation.set_mirror(mirror); set_bounding_boxes_as_dirty(); } - void set_mirror(Axis axis, double mirror) { m_transformation.set_mirror(axis, mirror); set_bounding_boxes_as_dirty(); } + void set_instance_mirror(const Vec3d& mirror) { m_instance_transformation.set_mirror(mirror); set_bounding_boxes_as_dirty(); } + void set_instance_mirror(Axis axis, double mirror) { m_instance_transformation.set_mirror(axis, mirror); set_bounding_boxes_as_dirty(); } + + const Geometry::Transformation& get_volume_transformation() const { return m_volume_transformation; } + void set_volume_transformation(const Geometry::Transformation& transformation) { m_volume_transformation = transformation; set_bounding_boxes_as_dirty(); } + + const Vec3d& get_volume_offset() const { return m_volume_transformation.get_offset(); } + double get_volume_offset(Axis axis) const { return m_volume_transformation.get_offset(axis); } + + void set_volume_offset(const Vec3d& offset) { m_volume_transformation.set_offset(offset); set_bounding_boxes_as_dirty(); } + void set_volume_offset(Axis axis, double offset) { m_volume_transformation.set_offset(axis, offset); set_bounding_boxes_as_dirty(); } + + const Vec3d& get_volume_rotation() const { return m_volume_transformation.get_rotation(); } + 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(); } + + 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); } + + void set_volume_scaling_factor(const Vec3d& scaling_factor) { m_volume_transformation.set_scaling_factor(scaling_factor); set_bounding_boxes_as_dirty(); } + void set_volume_scaling_factor(Axis axis, double scaling_factor) { m_volume_transformation.set_scaling_factor(axis, scaling_factor); set_bounding_boxes_as_dirty(); } + + const Vec3d& get_volume_mirror() const { return m_volume_transformation.get_mirror(); } + double get_volume_mirror(Axis axis) const { return m_volume_transformation.get_mirror(axis); } + + void set_volume_mirror(const Vec3d& mirror) { m_volume_transformation.set_mirror(mirror); set_bounding_boxes_as_dirty(); } + void set_volume_mirror(Axis axis, double mirror) { m_volume_transformation.set_mirror(axis, mirror); set_bounding_boxes_as_dirty(); } #else const Vec3d& get_rotation() const; void set_rotation(const Vec3d& rotation); @@ -378,7 +406,7 @@ public: int instance_idx() const { return this->composite_id % 1000; } #if ENABLE_MODELVOLUME_TRANSFORM - const Transform3d& world_matrix() const { return m_transformation.get_matrix(); } + Transform3d world_matrix() const { return m_instance_transformation.get_matrix() * m_volume_transformation.get_matrix(); } #else const Transform3f& world_matrix() const; #endif // ENABLE_MODELVOLUME_TRANSFORM diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index fe1376cf2..b9dd8fe11 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1126,6 +1126,31 @@ bool GLCanvas3D::Mouse::is_start_position_3D_defined() const return (drag.start_position_3D != Drag::Invalid_3D_Point); } +#if ENABLE_MODELVOLUME_TRANSFORM +GLCanvas3D::Selection::VolumeCache::TransformCache::TransformCache() + : position(Vec3d::Zero()) + , rotation(Vec3d::Zero()) + , scaling_factor(Vec3d::Ones()) + , rotation_matrix(Transform3d::Identity()) + , scale_matrix(Transform3d::Identity()) +{ +} + +GLCanvas3D::Selection::VolumeCache::TransformCache::TransformCache(const Geometry::Transformation& transform) + : position(transform.get_offset()) + , rotation(transform.get_rotation()) + , scaling_factor(transform.get_scaling_factor()) +{ + rotation_matrix = Geometry::assemble_transform(Vec3d::Zero(), rotation); + scale_matrix = Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), scaling_factor); +} + +GLCanvas3D::Selection::VolumeCache::VolumeCache(const Geometry::Transformation& volume_transform, const Geometry::Transformation& instance_transform) + : m_volume(volume_transform) + , m_instance(instance_transform) +{ +} +#else GLCanvas3D::Selection::VolumeCache::VolumeCache() : m_position(Vec3d::Zero()) , m_rotation(Vec3d::Zero()) @@ -1143,6 +1168,7 @@ GLCanvas3D::Selection::VolumeCache::VolumeCache(const Vec3d& position, const Vec m_rotation_matrix = Geometry::assemble_transform(Vec3d::Zero(), m_rotation); m_scale_matrix = Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), m_scaling_factor); } +#endif // ENABLE_MODELVOLUME_TRANSFORM GLCanvas3D::Selection::Selection() : m_volumes(nullptr) @@ -1188,11 +1214,13 @@ void GLCanvas3D::Selection::add(unsigned int volume_idx, bool as_single_selectio _add_instance(volume->object_idx(), volume->instance_idx()); break; } +#if !ENABLE_MODELVOLUME_TRANSFORM case Object: { _add_object(volume->object_idx()); break; } +#endif // !ENABLE_MODELVOLUME_TRANSFORM } _update_type(); @@ -1218,11 +1246,13 @@ void GLCanvas3D::Selection::remove(unsigned int volume_idx) _remove_instance(volume->object_idx(), volume->instance_idx()); break; } +#if !ENABLE_MODELVOLUME_TRANSFORM case Object: { _remove_object(volume->object_idx()); break; } +#endif // !ENABLE_MODELVOLUME_TRANSFORM } _update_type(); @@ -1392,7 +1422,14 @@ void GLCanvas3D::Selection::translate(const Vec3d& displacement) for (unsigned int i : m_list) { +#if ENABLE_MODELVOLUME_TRANSFORM + if (m_mode == Instance) + (*m_volumes)[i]->set_instance_offset(m_cache.volumes_data[i].get_instance_position() + displacement); + else if (m_mode == Volume) + (*m_volumes)[i]->set_volume_offset(m_cache.volumes_data[i].get_volume_position() + displacement); +#else (*m_volumes)[i]->set_offset(m_cache.volumes_data[i].get_position() + displacement); +#endif // ENABLE_MODELVOLUME_TRANSFORM } m_bounding_box_dirty = true; @@ -1406,15 +1443,35 @@ void GLCanvas3D::Selection::rotate(const Vec3d& rotation) for (unsigned int i : m_list) { if (is_single_full_instance()) +#if ENABLE_MODELVOLUME_TRANSFORM + (*m_volumes)[i]->set_instance_rotation(rotation); +#else (*m_volumes)[i]->set_rotation(rotation); +#endif // ENABLE_MODELVOLUME_TRANSFORM else { Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation); +#if ENABLE_MODELVOLUME_TRANSFORM + 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()); + (*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); + } + else if (m_mode == Volume) + { + // extracts rotations from the composed transformation + Vec3d new_rotation = Geometry::extract_euler_angles(m * m_cache.volumes_data[i].get_volume_rotation_matrix()); + (*m_volumes)[i]->set_volume_offset(m_cache.dragging_center + m * (m_cache.volumes_data[i].get_volume_position() - m_cache.dragging_center)); + (*m_volumes)[i]->set_volume_rotation(new_rotation); + } +#else // extracts rotations from the composed transformation Vec3d new_rotation = Geometry::extract_euler_angles(m * m_cache.volumes_data[i].get_rotation_matrix()); - (*m_volumes)[i]->set_offset(m_cache.dragging_center + m * (m_cache.volumes_data[i].get_position() - m_cache.dragging_center)); (*m_volumes)[i]->set_rotation(new_rotation); +#endif // ENABLE_MODELVOLUME_TRANSFORM } } @@ -1434,16 +1491,38 @@ void GLCanvas3D::Selection::scale(const Vec3d& scale) for (unsigned int i : m_list) { if (is_single_full_instance()) +#if ENABLE_MODELVOLUME_TRANSFORM + (*m_volumes)[i]->set_instance_scaling_factor(scale); +#else (*m_volumes)[i]->set_scaling_factor(scale); +#endif // ENABLE_MODELVOLUME_TRANSFORM else { Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), scale); +#if ENABLE_MODELVOLUME_TRANSFORM + if (m_mode == Instance) + { + Eigen::Matrix new_matrix = (m * m_cache.volumes_data[i].get_instance_scale_matrix()).matrix().block(0, 0, 3, 3); + // extracts scaling factors from the composed transformation + Vec3d new_scale(new_matrix.col(0).norm(), new_matrix.col(1).norm(), new_matrix.col(2).norm()); + (*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_scaling_factor(new_scale); + } + else if (m_mode == Volume) + { + Eigen::Matrix new_matrix = (m * m_cache.volumes_data[i].get_volume_scale_matrix()).matrix().block(0, 0, 3, 3); + // extracts scaling factors from the composed transformation + Vec3d new_scale(new_matrix.col(0).norm(), new_matrix.col(1).norm(), new_matrix.col(2).norm()); + (*m_volumes)[i]->set_volume_offset(m_cache.dragging_center + m * (m_cache.volumes_data[i].get_volume_position() - m_cache.dragging_center)); + (*m_volumes)[i]->set_volume_scaling_factor(new_scale); + } +#else Eigen::Matrix new_matrix = (m * m_cache.volumes_data[i].get_scale_matrix()).matrix().block(0, 0, 3, 3); // extracts scaling factors from the composed transformation Vec3d new_scale(new_matrix.col(0).norm(), new_matrix.col(1).norm(), new_matrix.col(2).norm()); - (*m_volumes)[i]->set_offset(m_cache.dragging_center + m * (m_cache.volumes_data[i].get_position() - m_cache.dragging_center)); (*m_volumes)[i]->set_scaling_factor(new_scale); +#endif // ENABLE_MODELVOLUME_TRANSFORM } } @@ -1463,7 +1542,11 @@ void GLCanvas3D::Selection::mirror(Axis axis) for (unsigned int i : m_list) { if (is_single_full_instance()) +#if ENABLE_MODELVOLUME_TRANSFORM + (*m_volumes)[i]->set_instance_mirror(axis, -(*m_volumes)[i]->get_instance_mirror(axis)); +#else (*m_volumes)[i]->set_mirror(axis, -(*m_volumes)[i]->get_mirror(axis)); +#endif // ENABLE_MODELVOLUME_TRANSFORM } #if !DISABLE_INSTANCES_SYNCH @@ -1483,7 +1566,11 @@ void GLCanvas3D::Selection::translate(unsigned int object_idx, const Vec3d& disp { GLVolume* v = (*m_volumes)[i]; if (v->object_idx() == object_idx) +#if ENABLE_MODELVOLUME_TRANSFORM + v->set_instance_offset(v->get_instance_offset() + displacement); +#else v->set_offset(v->get_offset() + displacement); +#endif // ENABLE_MODELVOLUME_TRANSFORM } std::set done; // prevent processing volumes twice @@ -1511,7 +1598,11 @@ void GLCanvas3D::Selection::translate(unsigned int object_idx, const Vec3d& disp if (v->object_idx() != object_idx) continue; +#if ENABLE_MODELVOLUME_TRANSFORM + v->set_instance_offset(v->get_instance_offset() + displacement); +#else v->set_offset(v->get_offset() + displacement); +#endif // ENABLE_MODELVOLUME_TRANSFORM done.insert(j); } } @@ -1528,7 +1619,11 @@ void GLCanvas3D::Selection::translate(unsigned int object_idx, unsigned int inst { GLVolume* v = (*m_volumes)[i]; if ((v->object_idx() == object_idx) && (v->instance_idx() == instance_idx)) +#if ENABLE_MODELVOLUME_TRANSFORM + v->set_instance_offset(v->get_instance_offset() + displacement); +#else v->set_offset(v->get_offset() + displacement); +#endif // ENABLE_MODELVOLUME_TRANSFORM } std::set done; // prevent processing volumes twice @@ -1556,7 +1651,11 @@ void GLCanvas3D::Selection::translate(unsigned int object_idx, unsigned int inst if ((v->object_idx() != object_idx) || (v->instance_idx() != instance_idx)) continue; +#if ENABLE_MODELVOLUME_TRANSFORM + v->set_instance_offset(v->get_instance_offset() + displacement); +#else v->set_offset(v->get_offset() + displacement); +#endif // ENABLE_MODELVOLUME_TRANSFORM done.insert(j); } } @@ -1684,7 +1783,11 @@ void GLCanvas3D::Selection::_set_caches() for (unsigned int i : m_list) { const GLVolume* v = (*m_volumes)[i]; +#if ENABLE_MODELVOLUME_TRANSFORM + m_cache.volumes_data.emplace(i, VolumeCache(v->get_volume_transformation(), v->get_instance_transformation())); +#else m_cache.volumes_data.emplace(i, VolumeCache(v->get_offset(), v->get_rotation(), v->get_scaling_factor())); +#endif // ENABLE_MODELVOLUME_TRANSFORM } m_cache.dragging_center = get_bounding_box().center(); } @@ -1885,9 +1988,15 @@ void GLCanvas3D::Selection::_synchronize_unselected_instances() continue; int instance_idx = volume->instance_idx(); +#if ENABLE_MODELVOLUME_TRANSFORM + const Vec3d& rotation = volume->get_instance_rotation(); + const Vec3d& scaling_factor = volume->get_instance_scaling_factor(); + const Vec3d& mirror = volume->get_instance_mirror(); +#else const Vec3d& rotation = volume->get_rotation(); const Vec3d& scaling_factor = volume->get_scaling_factor(); const Vec3d& mirror = volume->get_mirror(); +#endif // ENABLE_MODELVOLUME_TRANSFORM // Process unselected instances. for (unsigned int j = 0; j < (unsigned int)m_volumes->size(); ++j) @@ -1902,9 +2011,15 @@ void GLCanvas3D::Selection::_synchronize_unselected_instances() if ((v->object_idx() != object_idx) || (v->instance_idx() == instance_idx)) continue; +#if ENABLE_MODELVOLUME_TRANSFORM + v->set_instance_rotation(rotation); + v->set_instance_scaling_factor(scaling_factor); + v->set_instance_mirror(mirror); +#else v->set_rotation(rotation); v->set_scaling_factor(scaling_factor); v->set_mirror(mirror); +#endif // ENABLE_MODELVOLUME_TRANSFORM done.insert(j); } @@ -4841,18 +4956,29 @@ void GLCanvas3D::_update_gizmos_data() if (m_selection.is_single_full_instance()) { +#if ENABLE_MODELVOLUME_TRANSFORM + // all volumes in the selection belongs to the same instance, any of them contains the needed data, so we take the first + const GLVolume* volume = m_volumes.volumes[*m_selection.get_volume_idxs().begin()]; + m_gizmos.set_scale(volume->get_instance_scaling_factor()); + m_gizmos.set_rotation(volume->get_instance_rotation()); + ModelObject* model_object = m_model->objects[m_selection.get_object_idx()]; + m_gizmos.set_flattening_data(model_object); + m_gizmos.set_model_object_ptr(model_object); +#else ModelObject* model_object = m_model->objects[m_selection.get_object_idx()]; ModelInstance* model_instance = model_object->instances[m_selection.get_instance_idx()]; m_gizmos.set_scale(model_instance->get_scaling_factor()); m_gizmos.set_rotation(model_instance->get_rotation()); m_gizmos.set_flattening_data(model_object); m_gizmos.set_model_object_ptr(model_object); +#endif // ENABLE_MODELVOLUME_TRANSFORM } else { m_gizmos.set_scale(Vec3d::Ones()); m_gizmos.set_rotation(Vec3d::Zero()); m_gizmos.set_flattening_data(nullptr); + m_gizmos.set_model_object_ptr(nullptr); } } @@ -5991,14 +6117,22 @@ void GLCanvas3D::_on_move() ModelObject* model_object = m_model->objects[object_idx]; if (model_object != nullptr) { +#if ENABLE_MODELVOLUME_TRANSFORM + model_object->instances[instance_idx]->set_offset(v->get_instance_offset()); +#else model_object->instances[instance_idx]->set_offset(v->get_offset()); +#endif // ENABLE_MODELVOLUME_TRANSFORM model_object->invalidate_bounding_box(); object_moved = true; } } else if (object_idx == 1000) // Move a wipe tower proxy. +#if ENABLE_MODELVOLUME_TRANSFORM + wipe_tower_origin = v->get_volume_offset(); +#else wipe_tower_origin = v->get_offset(); +#endif // ENABLE_MODELVOLUME_TRANSFORM } for (const std::pair& i : done) @@ -6042,8 +6176,13 @@ void GLCanvas3D::_on_rotate() ModelObject* model_object = m_model->objects[object_idx]; if (model_object != nullptr) { +#if ENABLE_MODELVOLUME_TRANSFORM + model_object->instances[instance_idx]->set_rotation(v->get_instance_rotation()); + model_object->instances[instance_idx]->set_offset(v->get_instance_offset()); +#else model_object->instances[instance_idx]->set_rotation(v->get_rotation()); model_object->instances[instance_idx]->set_offset(v->get_offset()); +#endif // ENABLE_MODELVOLUME_TRANSFORM model_object->invalidate_bounding_box(); } } @@ -6085,8 +6224,13 @@ void GLCanvas3D::_on_scale() ModelObject* model_object = m_model->objects[object_idx]; if (model_object != nullptr) { +#if ENABLE_MODELVOLUME_TRANSFORM + model_object->instances[instance_idx]->set_scaling_factor(v->get_instance_scaling_factor()); + model_object->instances[instance_idx]->set_offset(v->get_instance_offset()); +#else model_object->instances[instance_idx]->set_scaling_factor(v->get_scaling_factor()); model_object->instances[instance_idx]->set_offset(v->get_offset()); +#endif // ENABLE_MODELVOLUME_TRANSFORM model_object->invalidate_bounding_box(); } } @@ -6133,7 +6277,11 @@ void GLCanvas3D::_on_mirror() ModelObject* model_object = m_model->objects[object_idx]; if (model_object != nullptr) { +#if ENABLE_MODELVOLUME_TRANSFORM + model_object->instances[instance_idx]->set_mirror(v->get_instance_mirror()); +#else model_object->instances[instance_idx]->set_mirror(v->get_mirror()); +#endif // ENABLE_MODELVOLUME_TRANSFORM model_object->invalidate_bounding_box(); } } diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index bf2fb4fd5..5d0f5f218 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -358,9 +358,14 @@ public: enum EMode : unsigned char { +#if ENABLE_MODELVOLUME_TRANSFORM + Volume, + Instance +#else Volume, Instance, Object +#endif // ENABLE_MODELVOLUME_TRANSFORM }; enum EType : unsigned char @@ -378,21 +383,57 @@ public: struct VolumeCache { private: +#if ENABLE_MODELVOLUME_TRANSFORM + struct TransformCache + { + Vec3d position; + Vec3d rotation; + Vec3d scaling_factor; + Transform3d rotation_matrix; + Transform3d scale_matrix; + + TransformCache(); + explicit TransformCache(const Geometry::Transformation& transform); + }; + + TransformCache m_volume; + TransformCache m_instance; +#else Vec3d m_position; Vec3d m_rotation; Vec3d m_scaling_factor; Transform3d m_rotation_matrix; Transform3d m_scale_matrix; +#endif // ENABLE_MODELVOLUME_TRANSFORM public: +#if ENABLE_MODELVOLUME_TRANSFORM + VolumeCache() {} + VolumeCache(const Geometry::Transformation& volume_transform, const Geometry::Transformation& instance_transform); +#else VolumeCache(); VolumeCache(const Vec3d& position, const Vec3d& rotation, const Vec3d& scaling_factor); +#endif // ENABLE_MODELVOLUME_TRANSFORM +#if ENABLE_MODELVOLUME_TRANSFORM + const Vec3d& get_volume_position() const { return m_volume.position; } + const Vec3d& get_volume_rotation() const { return m_volume.rotation; } + const Vec3d& get_volume_scaling_factor() const { return m_volume.scaling_factor; } + const Transform3d& get_volume_rotation_matrix() const { return m_volume.rotation_matrix; } + const Transform3d& get_volume_scale_matrix() const { return m_volume.scale_matrix; } + + const Vec3d& get_instance_position() const { return m_instance.position; } + const Vec3d& get_instance_rotation() const { return m_instance.rotation; } + const Vec3d& get_instance_scaling_factor() const { return m_instance.scaling_factor; } + const Transform3d& get_instance_rotation_matrix() const { return m_instance.rotation_matrix; } + const Transform3d& get_instance_scale_matrix() const { return m_instance.scale_matrix; } +#else const Vec3d& get_position() const { return m_position; } const Vec3d& get_rotation() const { return m_rotation; } const Vec3d& get_scaling_factor() const { return m_scaling_factor; } const Transform3d& get_rotation_matrix() const { return m_rotation_matrix; } const Transform3d& get_scale_matrix() const { return m_scale_matrix; } +#endif // ENABLE_MODELVOLUME_TRANSFORM }; typedef std::map VolumesCache; diff --git a/src/slic3r/GUI/GLGizmo.cpp b/src/slic3r/GUI/GLGizmo.cpp index 0420d9bf5..d632f0d91 100644 --- a/src/slic3r/GUI/GLGizmo.cpp +++ b/src/slic3r/GUI/GLGizmo.cpp @@ -718,7 +718,11 @@ void GLGizmoScale3D::on_process_double_click() void GLGizmoScale3D::on_render(const GLCanvas3D::Selection& selection) const { bool single_instance = selection.is_single_full_instance(); +#if ENABLE_MODELVOLUME_TRANSFORM + Vec3f scale = single_instance ? 100.0f * selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_scaling_factor().cast() : 100.0f * m_scale.cast(); +#else Vec3f scale = single_instance ? 100.0f * selection.get_volume(*selection.get_volume_idxs().begin())->get_scaling_factor().cast() : 100.0f * m_scale.cast(); +#endif // ENABLE_MODELVOLUME_TRANSFORM if ((single_instance && ((m_hover_id == 0) || (m_hover_id == 1))) || m_grabbers[0].dragging || m_grabbers[1].dragging) set_tooltip("X: " + format(scale(0), 4) + "%"); @@ -760,10 +764,18 @@ void GLGizmoScale3D::on_render(const GLCanvas3D::Selection& selection) const #endif // ENABLE_MODELVOLUME_TRANSFORM // gets angles from first selected volume +#if ENABLE_MODELVOLUME_TRANSFORM + angles = v->get_instance_rotation(); +#else angles = v->get_rotation(); +#endif // ENABLE_MODELVOLUME_TRANSFORM // consider rotation+mirror only components of the transform for offsets +#if ENABLE_MODELVOLUME_TRANSFORM + offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), angles, Vec3d::Ones(), v->get_instance_mirror()); +#else offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), angles, Vec3d::Ones(), v->get_mirror()); +#endif // ENABLE_MODELVOLUME_TRANSFORM } else box = selection.get_bounding_box(); @@ -1241,7 +1253,15 @@ void GLGizmoFlatten::update_planes() { TriangleMesh ch; for (const ModelVolume* vol : m_model_object->volumes) +#if ENABLE_MODELVOLUME_TRANSFORM + { + TriangleMesh vol_ch = vol->get_convex_hull(); + vol_ch.transform(vol->get_matrix().cast()); + ch.merge(vol_ch); + } +#else ch.merge(vol->get_convex_hull()); +#endif // ENABLE_MODELVOLUME_TRANSFORM ch = ch.convex_hull_3d(); @@ -1476,11 +1496,14 @@ bool GLGizmoSlaSupports::on_init() void GLGizmoSlaSupports::set_model_object_ptr(ModelObject* model_object) { - m_starting_center = Vec3d::Zero(); - m_model_object = model_object; - m_model_object_matrix = model_object->instances.front()->get_matrix(); - if (is_mesh_update_necessary()) - update_mesh(); + if (model_object != nullptr) + { + m_starting_center = Vec3d::Zero(); + m_model_object = model_object; + m_model_object_matrix = model_object->instances.front()->get_matrix(); + if (is_mesh_update_necessary()) + update_mesh(); + } } void GLGizmoSlaSupports::on_render(const GLCanvas3D::Selection& selection) const diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index fc34c0d09..806ea5699 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -268,6 +268,9 @@ void ObjectManipulation::update_settings_list() void ObjectManipulation::update_settings_value(const GLCanvas3D::Selection& selection) { +#if ENABLE_MODELVOLUME_TRANSFORM + if (selection.is_single_full_instance()) +#else if (selection.is_single_full_object()) { auto obj_idx = selection.get_object_idx(); @@ -284,30 +287,49 @@ void ObjectManipulation::update_settings_value(const GLCanvas3D::Selection& sele reset_settings_value(); } else if (selection.is_single_full_instance()) +#endif // ENABLE_MODELVOLUME_TRANSFORM { // all volumes in the selection belongs to the same instance, any of them contains the needed data, so we take the first const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); +#if ENABLE_MODELVOLUME_TRANSFORM + update_position_value(volume->get_instance_offset()); + update_rotation_value(volume->get_instance_rotation()); + update_scale_value(volume->get_instance_scaling_factor()); +#else update_position_value(volume->get_offset()); update_rotation_value(volume->get_rotation()); update_scale_value(volume->get_scaling_factor()); +#endif // ENABLE_MODELVOLUME_TRANSFORM m_og->enable(); } else if (selection.is_wipe_tower()) { // the selection contains a single volume const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); +#if ENABLE_MODELVOLUME_TRANSFORM + update_position_value(volume->get_volume_offset()); + update_rotation_value(volume->get_volume_rotation()); + update_scale_value(volume->get_volume_scaling_factor()); +#else update_position_value(volume->get_offset()); update_rotation_value(volume->get_rotation()); update_scale_value(volume->get_scaling_factor()); +#endif // ENABLE_MODELVOLUME_TRANSFORM m_og->enable(); } else if (selection.is_modifier()) { // the selection contains a single volume const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); +#if ENABLE_MODELVOLUME_TRANSFORM + update_position_value(volume->get_volume_offset()); + update_rotation_value(volume->get_volume_rotation()); + update_scale_value(volume->get_volume_scaling_factor()); +#else update_position_value(volume->get_offset()); update_rotation_value(volume->get_rotation()); update_scale_value(volume->get_scaling_factor()); +#endif // ENABLE_MODELVOLUME_TRANSFORM m_og->enable(); } else diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index df1a42a19..fe6be5607 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1227,7 +1227,9 @@ std::vector Plater::priv::load_files(const std::vector &input_ std::vector Plater::priv::load_model_objects(const ModelObjectPtrs &model_objects) { const BoundingBoxf bed_shape = bed_shape_bb(); +#if !ENABLE_MODELVOLUME_TRANSFORM const Vec3d bed_center = Slic3r::to_3d(bed_shape.center().cast(), 0.0); +#endif // !ENABLE_MODELVOLUME_TRANSFORM const Vec3d bed_size = Slic3r::to_3d(bed_shape.size().cast(), 1.0); bool need_arrange = false; @@ -1246,8 +1248,12 @@ std::vector Plater::priv::load_model_objects(const ModelObjectPtrs &mode // add a default instance and center object around origin object->center_around_origin(); // also aligns object to Z = 0 - auto *instance = object->add_instance(); + ModelInstance* instance = object->add_instance(); +#if ENABLE_MODELVOLUME_TRANSFORM + instance->set_offset(Slic3r::to_3d(bed_shape.center().cast(), -object->origin_translation(2))); +#else instance->set_offset(bed_center); +#endif // ENABLE_MODELVOLUME_TRANSFORM } const Vec3d size = object->bounding_box().size();