From 3aad8b5fd29acd5cc218cee3da25785c0966fc95 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 2 Nov 2018 12:11:28 +0100 Subject: [PATCH 01/43] Translation of ModelVolume as transformation component (without modifying the mesh) --- src/libslic3r/Model.cpp | 50 ++++++- src/libslic3r/Model.hpp | 20 ++- src/libslic3r/Print.cpp | 8 +- src/libslic3r/PrintObject.cpp | 10 +- src/slic3r/GUI/3DScene.cpp | 11 +- src/slic3r/GUI/3DScene.hpp | 68 +++++++--- src/slic3r/GUI/GLCanvas3D.cpp | 152 +++++++++++++++++++++- src/slic3r/GUI/GLCanvas3D.hpp | 41 ++++++ src/slic3r/GUI/GLGizmo.cpp | 33 ++++- src/slic3r/GUI/GUI_ObjectManipulation.cpp | 22 ++++ src/slic3r/GUI/Plater.cpp | 8 +- 11 files changed, 384 insertions(+), 39 deletions(-) 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(); From 7114b8088213e45a87400cb7b63fdb18f8ac5de0 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 2 Nov 2018 13:47:47 +0100 Subject: [PATCH 02/43] Use Transform3d in place of Transform3f as parameter of mesh transform functions --- src/admesh/stl.h | 2 +- src/admesh/util.cpp | 4 ++-- src/libslic3r/Model.cpp | 8 ++++---- src/libslic3r/PrintObject.cpp | 4 ++-- src/libslic3r/TriangleMesh.cpp | 8 ++++---- src/libslic3r/TriangleMesh.hpp | 2 +- src/slic3r/GUI/GLGizmo.cpp | 2 +- 7 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/admesh/stl.h b/src/admesh/stl.h index 9898f3e64..45889bcd3 100644 --- a/src/admesh/stl.h +++ b/src/admesh/stl.h @@ -173,7 +173,7 @@ extern void stl_mirror_xy(stl_file *stl); extern void stl_mirror_yz(stl_file *stl); extern void stl_mirror_xz(stl_file *stl); extern void stl_transform(stl_file *stl, float *trafo3x4); -extern void stl_transform(stl_file *stl, const Eigen::Transform& t); +extern void stl_transform(stl_file *stl, const Eigen::Transform& t); extern void stl_open_merge(stl_file *stl, char *file); extern void stl_invalidate_shared_vertices(stl_file *stl); extern void stl_generate_shared_vertices(stl_file *stl); diff --git a/src/admesh/util.cpp b/src/admesh/util.cpp index cc104fdd1..7cb69bccd 100644 --- a/src/admesh/util.cpp +++ b/src/admesh/util.cpp @@ -155,7 +155,7 @@ void stl_transform(stl_file *stl, float *trafo3x4) { calculate_normals(stl); } -void stl_transform(stl_file *stl, const Eigen::Transform& t) +void stl_transform(stl_file *stl, const Eigen::Transform& t) { if (stl->error) return; @@ -178,7 +178,7 @@ void stl_transform(stl_file *stl, const Eigen::Transform() * src_vertices.colwise().homogeneous(); facet_ptr = stl->facet_start; v_id = 0; diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 577d16c3c..fabc2992d 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -627,7 +627,7 @@ const BoundingBoxf3& ModelObject::bounding_box() const #if ENABLE_MODELVOLUME_TRANSFORM { TriangleMesh m = v->mesh; - m.transform(v->get_matrix().cast()); + m.transform(v->get_matrix()); raw_bbox.merge(m.bounding_box()); } #else @@ -667,7 +667,7 @@ TriangleMesh ModelObject::raw_mesh() const #if ENABLE_MODELVOLUME_TRANSFORM { TriangleMesh vol_mesh(v->mesh); - vol_mesh.transform(v->get_matrix().cast()); + vol_mesh.transform(v->get_matrix()); mesh.merge(vol_mesh); } #else @@ -1212,14 +1212,14 @@ void ModelInstance::set_mirror(Axis axis, double mirror) void ModelInstance::transform_mesh(TriangleMesh* mesh, bool dont_translate) const { - mesh->transform(get_matrix(dont_translate).cast()); + mesh->transform(get_matrix(dont_translate)); } BoundingBoxf3 ModelInstance::transform_mesh_bounding_box(const TriangleMesh* mesh, bool dont_translate) const { // Rotate around mesh origin. TriangleMesh copy(*mesh); - copy.transform(get_matrix(true, false, true, true).cast()); + copy.transform(get_matrix(true, false, true, true)); BoundingBoxf3 bbox = copy.bounding_box(); if (!empty(bbox)) { diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 9ae654cbc..447ba076a 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -1604,14 +1604,14 @@ std::vector PrintObject::_slice_volumes(const std::vector &z, #if ENABLE_MODELVOLUME_TRANSFORM { TriangleMesh vol_mesh(v->mesh); - vol_mesh.transform(v->get_matrix().cast()); + vol_mesh.transform(v->get_matrix()); 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()); + mesh.transform(m_trafo); // apply XY shift mesh.translate(- unscale(m_copies_shift(0)), - unscale(m_copies_shift(1)), 0); // perform actual slicing diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index c8a6e2130..425967f9f 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -272,9 +272,9 @@ void TriangleMesh::rotate(float angle, const Vec3d& axis) if (angle == 0.f) return; - Vec3f axis_norm = axis.cast().normalized(); - Transform3f m = Transform3f::Identity(); - m.rotate(Eigen::AngleAxisf(angle, axis_norm)); + Vec3d axis_norm = axis.normalized(); + Transform3d m = Transform3d::Identity(); + m.rotate(Eigen::AngleAxisd(angle, axis_norm)); stl_transform(&stl, m); } @@ -290,7 +290,7 @@ void TriangleMesh::mirror(const Axis &axis) stl_invalidate_shared_vertices(&this->stl); } -void TriangleMesh::transform(const Transform3f& t) +void TriangleMesh::transform(const Transform3d& t) { stl_transform(&stl, t); } diff --git a/src/libslic3r/TriangleMesh.hpp b/src/libslic3r/TriangleMesh.hpp index f6e0baea9..fd312d0e0 100644 --- a/src/libslic3r/TriangleMesh.hpp +++ b/src/libslic3r/TriangleMesh.hpp @@ -49,7 +49,7 @@ public: void mirror_x() { this->mirror(X); } void mirror_y() { this->mirror(Y); } void mirror_z() { this->mirror(Z); } - void transform(const Transform3f& t); + void transform(const Transform3d& t); void align_to_origin(); void rotate(double angle, Point* center); TriangleMeshPtrs split() const; diff --git a/src/slic3r/GUI/GLGizmo.cpp b/src/slic3r/GUI/GLGizmo.cpp index d632f0d91..974f855e2 100644 --- a/src/slic3r/GUI/GLGizmo.cpp +++ b/src/slic3r/GUI/GLGizmo.cpp @@ -1256,7 +1256,7 @@ void GLGizmoFlatten::update_planes() #if ENABLE_MODELVOLUME_TRANSFORM { TriangleMesh vol_ch = vol->get_convex_hull(); - vol_ch.transform(vol->get_matrix().cast()); + vol_ch.transform(vol->get_matrix()); ch.merge(vol_ch); } #else From 385b0f261d3c1f2851b3ebe2b884e39582703180 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 2 Nov 2018 14:41:08 +0100 Subject: [PATCH 03/43] Scale of ModelVolume as transformation component (without modifying the mesh) --- src/libslic3r/Model.cpp | 25 +++++++++++++------------ src/libslic3r/Model.hpp | 6 +++++- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index fabc2992d..443b96bc8 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -749,12 +749,7 @@ 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) @@ -765,11 +760,12 @@ void ModelObject::scale(const Vec3d &versor) { for (ModelVolume *v : this->volumes) { - v->mesh.scale(versor); - v->m_convex_hull.scale(versor); + v->scale(versor); } +#if !ENABLE_MODELVOLUME_TRANSFORM // reset origin translation since it doesn't make sense anymore this->origin_translation = Vec3d::Zero(); +#endif // !ENABLE_MODELVOLUME_TRANSFORM this->invalidate_bounding_box(); } @@ -1142,11 +1138,6 @@ size_t ModelVolume::split(unsigned int max_extruders) return idx; } -void ModelVolume::translate(double x, double y, double z) -{ - translate(Vec3d(x, y, z)); -} - void ModelVolume::translate(const Vec3d& displacement) { #if ENABLE_MODELVOLUME_TRANSFORM @@ -1157,6 +1148,16 @@ void ModelVolume::translate(const Vec3d& displacement) #endif // ENABLE_MODELVOLUME_TRANSFORM } +void ModelVolume::scale(const Vec3d& scaling_factors) +{ +#if ENABLE_MODELVOLUME_TRANSFORM + m_transformation.set_scaling_factor(m_transformation.get_scaling_factor().cwiseProduct(scaling_factors)); +#else + mesh.scale(scaling_factors); + m_convex_hull.scale(scaling_factors); +#endif // ENABLE_MODELVOLUME_TRANSFORM +} + #if !ENABLE_MODELVOLUME_TRANSFORM void ModelInstance::set_rotation(const Vec3d& rotation) { diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 92cef8e6d..69bae3454 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -163,6 +163,7 @@ public: void translate(double x, double y, double z); void scale(const Vec3d &versor); void scale(const double s) { this->scale(Vec3d(s, s, s)); } + void scale(double x, double y, double z) { this->scale(Vec3d(x, y, z)); } void rotate(float angle, const Axis &axis); void rotate(float angle, const Vec3d& axis); void mirror(const Axis &axis); @@ -246,8 +247,11 @@ public: // Return the number of volumes created from this one. // This is useful to assign different materials to different volumes of an object. size_t split(unsigned int max_extruders); - void translate(double x, double y, double z); + void translate(double x, double y, double z) { translate(Vec3d(x, y, z)); } void translate(const Vec3d& displacement); + void scale(const Vec3d& scaling_factors); + void scale(double x, double y, double z) { scale(Vec3d(x, y, z)); } + void scale(double s) { scale(Vec3d(s, s, s)); } ModelMaterial* assign_unique_material(); From ca32338ceae57164c4cf1f9ebb076c2779088e47 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Fri, 2 Nov 2018 14:47:13 +0100 Subject: [PATCH 04/43] ModelBase ID refactoring, WIP --- src/libslic3r/Model.cpp | 155 +++++++++++++++++++++++++++------------- src/libslic3r/Model.hpp | 134 ++++++++++++++++++++++++++-------- 2 files changed, 207 insertions(+), 82 deletions(-) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index d33f44c35..01886e870 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -21,26 +21,40 @@ namespace Slic3r { unsigned int Model::s_auto_extruder_id = 1; -ModelID ModelBase::s_last_id = 0; +size_t ModelBase::s_last_id = 0; -Model::Model(const Model &rhs) +Model& Model::assign_copy(const Model &rhs) { - *this = rhs; -} - -Model& Model::operator=(const Model &rhs) -{ - m_id = rhs.m_id; + this->copy_id(rhs); // copy materials - for (const auto &m : rhs.materials) + for (const std::pair &m : rhs.materials) this->add_material(m.first, *m.second); // copy objects this->objects.reserve(rhs.objects.size()); for (const ModelObject *o : rhs.objects) - this->add_object(*o, true); + this->add_object(*o); return *this; } +Model& Model::assign_copy(Model &&rhs) +{ + this->copy_id(rhs); + this->materials = std::move(rhs.materials); + rhs.materials.clear(); + this->objects = std::move(rhs.objects); + rhs.objects.clear(); + return *this; +} + +void Model::assign_new_unique_ids_recursive() +{ + this->set_new_unique_id(); + for (std::pair &m : this->materials) + m.second->assign_new_unique_ids_recursive(); + for (ModelObject *model_object : this->objects) + model_object->assign_new_unique_ids_recursive(); +} + Model Model::read_from_file(const std::string &input_file, DynamicPrintConfig *config, bool add_default_instances) { Model model; @@ -150,9 +164,9 @@ ModelObject* Model::add_object(const char *name, const char *path, TriangleMesh return new_object; } -ModelObject* Model::add_object(const ModelObject &other, bool copy_volumes) +ModelObject* Model::add_object(const ModelObject &other) { - ModelObject* new_object = new ModelObject(this, other, copy_volumes); + ModelObject* new_object = new ModelObject(this, other); this->objects.push_back(new_object); return new_object; } @@ -483,10 +497,10 @@ void Model::reset_auto_extruder_id() s_auto_extruder_id = 1; } -ModelObject::ModelObject(Model *model, const ModelObject &rhs, bool copy_volumes) : +ModelObject::ModelObject(Model *model, const ModelObject &rhs) : m_model(model) { - this->assign(&rhs, copy_volumes); + this->assign_copy(rhs); } ModelObject::~ModelObject() @@ -495,41 +509,74 @@ ModelObject::~ModelObject() this->clear_instances(); } -// Clone this ModelObject including its volumes and instances, keep the IDs of the copies equal to the original. -// Called by Print::apply() to clone the Model / ModelObject hierarchy to the back end for background processing. -ModelObject* ModelObject::clone(Model *parent) +// maintains the m_model pointer +ModelObject& ModelObject::assign_copy(const ModelObject &rhs) { - return new ModelObject(parent, *this, true); -} + this->copy_id(rhs); -ModelObject& ModelObject::assign(const ModelObject *rhs, bool copy_volumes) -{ - m_id = rhs->m_id; - name = rhs->name; - input_file = rhs->input_file; - config = rhs->config; - sla_support_points = rhs->sla_support_points; - layer_height_ranges = rhs->layer_height_ranges; - layer_height_profile = rhs->layer_height_profile; - layer_height_profile_valid = rhs->layer_height_profile_valid; - origin_translation = rhs->origin_translation; - m_bounding_box = rhs->m_bounding_box; - m_bounding_box_valid = rhs->m_bounding_box_valid; + this->name = rhs.name; + this->input_file = rhs.input_file; + this->config = rhs.config; + this->sla_support_points = rhs.sla_support_points; + this->layer_height_ranges = rhs.layer_height_ranges; + this->layer_height_profile = rhs.layer_height_profile; + this->layer_height_profile_valid = rhs.layer_height_profile_valid; + this->origin_translation = rhs.origin_translation; + m_bounding_box = rhs.m_bounding_box; + m_bounding_box_valid = rhs.m_bounding_box_valid; - volumes.clear(); - instances.clear(); - if (copy_volumes) { - this->volumes.reserve(rhs->volumes.size()); - for (ModelVolume *model_volume : rhs->volumes) - this->add_volume(*model_volume); - this->instances.reserve(rhs->instances.size()); - for (const ModelInstance *model_instance : rhs->instances) - this->add_instance(*model_instance); - } + this->volumes.clear(); + this->volumes.reserve(rhs.volumes.size()); + for (ModelVolume *model_volume : rhs.volumes) + this->add_volume(*model_volume); + this->instances.clear(); + this->instances.reserve(rhs.instances.size()); + for (const ModelInstance *model_instance : rhs.instances) + this->add_instance(*model_instance); return *this; } +// maintains the m_model pointer +ModelObject& ModelObject::assign_copy(ModelObject &&rhs) +{ + this->copy_id(rhs); + + this->name = std::move(rhs.name); + this->input_file = std::move(rhs.input_file); + this->config = std::move(rhs.config); + this->sla_support_points = std::move(rhs.sla_support_points); + this->layer_height_ranges = std::move(rhs.layer_height_ranges); + this->layer_height_profile = std::move(rhs.layer_height_profile); + this->layer_height_profile_valid = std::move(rhs.layer_height_profile_valid); + this->origin_translation = std::move(rhs.origin_translation); + m_bounding_box = std::move(rhs.m_bounding_box); + m_bounding_box_valid = std::move(rhs.m_bounding_box_valid); + + this->volumes = std::move(rhs.volumes); + rhs.volumes.clear(); + this->instances = std::move(rhs.instances); + rhs.instances.clear(); + + return *this; +} + +void ModelObject::assign_new_unique_ids_recursive() +{ + this->set_new_unique_id(); + for (ModelVolume *model_volume : this->volumes) + model_volume->assign_new_unique_ids_recursive(); + for (ModelInstance *model_instance : this->instances) + model_instance->assign_new_unique_ids_recursive(); +} + +// Clone this ModelObject including its volumes and instances, keep the IDs of the copies equal to the original. +// Called by Print::apply() to clone the Model / ModelObject hierarchy to the back end for background processing. +//ModelObject* ModelObject::clone(Model *parent) +//{ +// return new ModelObject(parent, *this, true); +//} + ModelVolume* ModelObject::add_volume(const TriangleMesh &mesh) { ModelVolume* v = new ModelVolume(this, mesh); @@ -554,6 +601,14 @@ ModelVolume* ModelObject::add_volume(const ModelVolume &other) return v; } +ModelVolume* ModelObject::add_volume(const ModelVolume &other, TriangleMesh &&mesh) +{ + ModelVolume* v = new ModelVolume(this, other, std::move(mesh)); + this->volumes.push_back(v); + this->invalidate_bounding_box(); + return v; +} + void ModelObject::delete_volume(size_t idx) { ModelVolumePtrs::iterator i = this->volumes.begin() + idx; @@ -876,15 +931,13 @@ void ModelObject::split(ModelObjectPtrs* new_objects) mesh->repair(); - ModelObject* new_object = m_model->add_object(*this, false); - new_object->sla_support_points.clear(); - new_object->input_file = ""; - ModelVolume* new_volume = new_object->add_volume(*mesh); - new_volume->name = volume->name; - new_volume->config = volume->config; - new_volume->set_type(volume->type()); - new_volume->set_material_id(volume->material_id()); - + ModelObject* new_object = m_model->add_object(); + new_object->name = this->name; + new_object->config = this->config; + new_object->instances.reserve(this->instances.size()); + for (const ModelInstance *model_instance : this->instances) + new_object->add_instance(*model_instance); + new_object->add_volume(*volume, std::move(*mesh)); new_objects->push_back(new_object); delete mesh; } diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index b72f20501..90ee456ec 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -27,16 +27,31 @@ class Print; typedef std::string t_model_material_id; typedef std::string t_model_material_attribute; -typedef std::map t_model_material_attributes; +typedef std::map t_model_material_attributes; -typedef std::map ModelMaterialMap; +typedef std::map ModelMaterialMap; typedef std::vector ModelObjectPtrs; typedef std::vector ModelVolumePtrs; typedef std::vector ModelInstancePtrs; // Unique identifier of a Model, ModelObject, ModelVolume, ModelInstance or ModelMaterial. // Used to synchronize the front end (UI) with the back end (BackgroundSlicingProcess / Print / PrintObject) -typedef size_t ModelID; +// Valid IDs are strictly positive (non zero). +// It is declared as an object, as some compilers (notably msvcc) consider a typedef size_t equivalent to size_t +// for parameter overload. +struct ModelID +{ + ModelID(size_t id) : id(id) {} + + bool operator==(const ModelID &rhs) const { return this->id == rhs.id; } + bool operator!=(const ModelID &rhs) const { return this->id != rhs.id; } + bool operator< (const ModelID &rhs) const { return this->id < rhs.id; } + bool operator> (const ModelID &rhs) const { return this->id > rhs.id; } + bool operator<=(const ModelID &rhs) const { return this->id <= rhs.id; } + bool operator>=(const ModelID &rhs) const { return this->id >= rhs.id; } + + size_t id; +}; // Base for Model, ModelObject, ModelVolume, ModelInstance or ModelMaterial to provide a unique ID // to synchronize the front end (UI) with the back end (BackgroundSlicingProcess / Print / PrintObject). @@ -45,18 +60,71 @@ typedef size_t ModelID; class ModelBase { public: - ModelID id() const { return m_id; } + ModelID id() const { return m_id; } + // Use with caution! + void set_new_unique_id() { m_id = generate_new_id(); } + void set_invalid_id() { m_id = 0; } + // Use with caution! + void copy_id(const ModelBase &rhs) { m_id = rhs.id(); } protected: - // Constructor to be only called by derived classes. - ModelBase() {} - ModelID m_id = generate_new_id(); + // Constructors to be only called by derived classes. + // Default constructor to assign a unique ID. + ModelBase() : m_id(generate_new_id()) {} + // Constructor with ignored int parameter to assign an invalid ID, to be replaced + // by an existing ID copied from elsewhere. + ModelBase(int) : m_id(ModelID(0)) {} + + // Override this method if a ModelBase derived class owns other ModelBase derived instances. + void assign_new_unique_ids_recursive() { this->set_new_unique_id(); } private: - static inline ModelID generate_new_id() { return s_last_id ++; } - static ModelID s_last_id; + ModelID m_id; + + static inline ModelID generate_new_id() { return ModelID(++ s_last_id); } + static size_t s_last_id; }; +#define MODELBASE_DERIVED_COPY_MOVE_CLONE(TYPE) \ + /* To be able to return an object from own copy / clone methods. Hopefully the compiler will do the "Copy elision" */ \ + /* (Omits copy and move(since C++11) constructors, resulting in zero - copy pass - by - value semantics). */ \ + TYPE(const TYPE &rhs) : ModelBase(-1) { this->assign_copy(rhs); } \ + explicit TYPE(TYPE &&rhs) : ModelBase(-1) { this->assign_clone(std::move(rhs)); } \ + TYPE& operator=(const TYPE &rhs) { this->assign_copy(rhs); return *this; } \ + TYPE& operator=(TYPE &&rhs) { this->assign_copy(std::move(rhs)); return *this; } \ + /* Copy a model, copy the IDs. The Print::apply() will call the TYPE::copy() method */ \ + /* to make a private copy for background processing. */ \ + static TYPE* new_copy(const TYPE &rhs) { return new TYPE(rhs); } \ + static TYPE* new_copy(TYPE &&rhs) { return new TYPE(std::move(rhs)); } \ + static TYPE make_copy(const TYPE &rhs) { return TYPE(rhs); } \ + static TYPE make_copy(TYPE &&rhs) { return TYPE(std::move(rhs)); } \ + TYPE& assign_copy(const TYPE &rhs); \ + TYPE& assign_copy(TYPE &&rhs); \ + /* Copy a TYPE, generate new IDs. The front end will use this call. */ \ + TYPE* new_clone(const TYPE &rhs) { \ + /* Default constructor assigning an invalid ID. */ \ + auto obj = new TYPE(-1); \ + obj->assign_clone(rhs); \ + return obj; \ + } \ + TYPE make_clone(const TYPE &rhs) { \ + /* Default constructor assigning an invalid ID. */ \ + TYPE obj(-1); \ + obj.assign_clone(rhs); \ + return obj; \ + } \ + TYPE& assign_clone(const TYPE &rhs) { \ + this->assign_copy(rhs); \ + this->assign_new_unique_ids_recursive(); \ + return *this; \ + } + +#define MODELBASE_DERIVED_PRIVATE_COPY_MOVE(TYPE) \ +private: \ + /* Private constructor with an unused int parameter will create a TYPE instance with an invalid ID. */ \ + explicit TYPE(int) : ModelBase(-1) {}; \ + void assign_new_unique_ids_recursive(); + // Material, which may be shared across multiple ModelObjects of a single Model. class ModelMaterial : public ModelBase { @@ -119,15 +187,12 @@ public: when user expects that. */ Vec3d origin_translation; - // Assign a ModelObject to this object while keeping the original pointer to the parent Model. - // Make a deep copy. - ModelObject& assign(const ModelObject *rhs, bool copy_volumes = true); - Model* get_model() const { return m_model; }; ModelVolume* add_volume(const TriangleMesh &mesh); ModelVolume* add_volume(TriangleMesh &&mesh); ModelVolume* add_volume(const ModelVolume &volume); + ModelVolume* add_volume(const ModelVolume &volume, TriangleMesh &&mesh); void delete_volume(size_t idx); void clear_volumes(); bool is_multiparts() const { return volumes.size() > 1; } @@ -184,17 +249,16 @@ public: protected: friend class Print; - // Clone this ModelObject including its volumes and instances, keep the IDs of the copies equal to the original. - // Called by Print::apply() to clone the Model / ModelObject hierarchy to the back end for background processing. - ModelObject* clone(Model *parent); - void set_model(Model *model) { m_model = model; } + // Called by Print::apply() to set the model pointer after making a copy. + void set_model(Model *model) { m_model = model; } private: ModelObject(Model *model) : layer_height_profile_valid(false), m_model(model), origin_translation(Vec3d::Zero()), m_bounding_box_valid(false) {} - ModelObject(Model *model, const ModelObject &rhs, bool copy_volumes = true); - explicit ModelObject(ModelObject &rhs) = delete; + ModelObject(Model *model, const ModelObject &rhs); ~ModelObject(); - ModelObject& operator=(ModelObject &rhs) = default; + + MODELBASE_DERIVED_COPY_MOVE_CLONE(ModelObject) + MODELBASE_DERIVED_PRIVATE_COPY_MOVE(ModelObject) // Parent object, owning this ModelObject. Model *m_model; @@ -314,7 +378,7 @@ private: { this->set_material_id(other.material_id()); } - ModelVolume(ModelObject *object, const ModelVolume &other, const TriangleMesh &&mesh) : + ModelVolume(ModelObject *object, const ModelVolume &other, TriangleMesh &&mesh) : ModelBase(other), // copy the ID name(other.name), mesh(std::move(mesh)), config(other.config), m_type(other.m_type), object(object) { @@ -460,30 +524,32 @@ class Model : public ModelBase public: // Materials are owned by a model and referenced by objects through t_model_material_id. // Single material may be shared by multiple models. - ModelMaterialMap materials; + ModelMaterialMap materials; // Objects are owned by a model. Each model may have multiple instances, each instance having its own transformation (shift, scale, rotation). - ModelObjectPtrs objects; + ModelObjectPtrs objects; + // Default constructor assigns a new ID to the model. Model() {} - Model(const Model &rhs); - Model& operator=(const Model &rhs); ~Model() { this->clear_objects(); this->clear_materials(); } - // XXX: use fs::path ? + MODELBASE_DERIVED_COPY_MOVE_CLONE(Model) + static Model read_from_file(const std::string &input_file, DynamicPrintConfig *config = nullptr, bool add_default_instances = true); static Model read_from_archive(const std::string &input_file, DynamicPrintConfig *config, bool add_default_instances = true); /// Repair the ModelObjects of the current Model. /// This function calls repair function on each TriangleMesh of each model object volume - void repair(); + void repair(); + // Add a new ModelObject to this Model, generate a new ID for this ModelObject. ModelObject* add_object(); ModelObject* add_object(const char *name, const char *path, const TriangleMesh &mesh); ModelObject* add_object(const char *name, const char *path, TriangleMesh &&mesh); - ModelObject* add_object(const ModelObject &other, bool copy_volumes = true); - void delete_object(size_t idx); - void delete_object(ModelObject* object); - void clear_objects(); + ModelObject* add_object(const ModelObject &other); + void delete_object(size_t idx); + void delete_object(ModelID id); + void delete_object(ModelObject* object); + void clear_objects(); ModelMaterial* add_material(t_model_material_id material_id); ModelMaterial* add_material(t_model_material_id material_id, const ModelMaterial &other); @@ -520,8 +586,14 @@ public: static unsigned int get_auto_extruder_id(unsigned int max_extruders); static std::string get_auto_extruder_id_as_string(unsigned int max_extruders); static void reset_auto_extruder_id(); + +private: + MODELBASE_DERIVED_PRIVATE_COPY_MOVE(Model) }; +#undef MODELBASE_DERIVED_COPY_MOVE_CLONE +#undef MODELBASE_DERIVED_PRIVATE_COPY_MOVE + } #endif From d26d90ac85e948a1d54d8026d356290655871c6b Mon Sep 17 00:00:00 2001 From: bubnikv Date: Fri, 2 Nov 2018 15:08:08 +0100 Subject: [PATCH 05/43] ModelBase ID refactoring, WIP --- src/libslic3r/Print.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 16b3ff773..402edaeac 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -774,7 +774,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co for (PrintRegion *region : m_regions) delete region; m_regions.clear(); - m_model = model; + m_model.assign_copy(model); for (const ModelObject *model_object : m_model.objects) model_object_status.emplace(model_object->id(), ModelObjectStatus::New); } else { @@ -789,7 +789,8 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co model_object_status.emplace(model_object->id(), ModelObjectStatus::Old); for (size_t i = m_model.objects.size(); i < model.objects.size(); ++ i) { model_object_status.emplace(model.objects[i]->id(), ModelObjectStatus::New); - m_model.objects.emplace_back(model.objects[i]->clone(&m_model)); + m_model.objects.emplace_back(ModelObject::new_copy(*model.objects[i])); + m_model.objects.back()->set_model(&m_model); } } else { // Reorder the objects, add new objects. @@ -806,7 +807,8 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co auto it = std::lower_bound(model_objects_old.begin(), model_objects_old.end(), mobj, by_id_lower); if (it == model_objects_old.end() || (*it)->id() != mobj->id()) { // New ModelObject added. - m_model.objects.emplace_back((*it)->clone(&m_model)); + m_model.objects.emplace_back(ModelObject::new_copy(**it)); + m_model.objects.back()->set_model(&m_model); model_object_status.emplace(mobj->id(), ModelObjectStatus::New); } else { // Existing ModelObject re-added (possibly moved in the list). @@ -899,8 +901,8 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co update_apply_status(it->print_object->invalidate_all_steps()); const_cast(*it).status = PrintObjectStatus::Deleted; } - // Copy content of the ModelObject including its ID, reset the parent. - model_object.assign(&model_object_new); + // Copy content of the ModelObject including its ID, do not change the parent. + model_object.assign_copy(model_object_new); } else if (support_blockers_differ || support_enforcers_differ) { // First stop background processing before shuffling or deleting the ModelVolumes in the ModelObject's list. m_cancel_callback(); From 622f4ee4f62474acfa0ee2f3f071bb4839e0532d Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 2 Nov 2018 15:20:26 +0100 Subject: [PATCH 06/43] Flatten gizmo should now work with multiple selection --- src/slic3r/GUI/GLCanvas3D.cpp | 54 ++++++++++++++++++---- src/slic3r/GUI/GLCanvas3D.hpp | 5 +- src/slic3r/GUI/GLGizmo.cpp | 87 +++++++++++++++++------------------ src/slic3r/GUI/GLGizmo.hpp | 5 +- 4 files changed, 95 insertions(+), 56 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index b9dd8fe11..a09e33b68 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1394,6 +1394,14 @@ int GLCanvas3D::Selection::get_instance_idx() const return -1; } +const GLCanvas3D::Selection::InstanceIdxsList& GLCanvas3D::Selection::get_instance_idxs() const +{ + if (m_cache.content.size() != 1) + throw std::runtime_error("get_instance_idxs() called for multiple object selection."); + + return m_cache.content.begin()->second; +} + const GLVolume* GLCanvas3D::Selection::get_volume(unsigned int volume_idx) const { return (m_valid && (volume_idx < (unsigned int)m_volumes->size())) ? (*m_volumes)[volume_idx] : nullptr; @@ -1483,6 +1491,36 @@ void GLCanvas3D::Selection::rotate(const Vec3d& rotation) m_bounding_box_dirty = true; } +void GLCanvas3D::Selection::flattening_rotate(const Vec3d& normal) +{ + // We get the normal in untransformed coordinates. We must transform it using the instance matrix, find out + // how to rotate the instance so it faces downwards and do the rotation. All that for all selected instances. + // The function assumes that is_from_single_object() holds. + + if (!m_valid) + return; + + for (unsigned int i : m_list) + { + Vec3d scaling_factor = m_cache.volumes_data[i].get_scaling_factor(); + scaling_factor = Vec3d(1./scaling_factor(0), 1./scaling_factor(1), 1./scaling_factor(2)); + + Vec3d transformed_normal = Geometry::assemble_transform(Vec3d::Zero(), m_cache.volumes_data[i].get_rotation(), scaling_factor) * normal; + transformed_normal.normalize(); + + Vec3d axis = transformed_normal(2) > 0.999f ? Vec3d(1., 0., 0.) : Vec3d(transformed_normal.cross(Vec3d(0., 0., -1.))); + axis.normalize(); + + Transform3d extra_rotation = Transform3d::Identity(); + extra_rotation.rotate(Eigen::AngleAxisd(acos(-transformed_normal(2)), axis)); + + Vec3d new_rotation = Geometry::extract_euler_angles(extra_rotation * m_cache.volumes_data[i].get_rotation_matrix() ); + (*m_volumes)[i]->set_rotation(new_rotation); + } + m_bounding_box_dirty = true; +} + + void GLCanvas3D::Selection::scale(const Vec3d& scale) { if (!m_valid) @@ -2389,13 +2427,13 @@ void GLCanvas3D::Gizmos::set_rotation(const Vec3d& rotation) reinterpret_cast(it->second)->set_rotation(rotation); } -Vec3d GLCanvas3D::Gizmos::get_flattening_rotation() const +Vec3d GLCanvas3D::Gizmos::get_flattening_normal() const { if (!m_enabled) return Vec3d::Zero(); GizmosMap::const_iterator it = m_gizmos.find(Flatten); - return (it != m_gizmos.end()) ? reinterpret_cast(it->second)->get_flattening_rotation() : Vec3d::Zero(); + return (it != m_gizmos.end()) ? reinterpret_cast(it->second)->get_flattening_normal() : Vec3d::Zero(); } void GLCanvas3D::Gizmos::set_flattening_data(const ModelObject* model_object) @@ -2520,12 +2558,12 @@ float GLCanvas3D::Gizmos::_get_total_overlay_height() const for (GizmosMap::const_iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it) { - height += (float)it->second->get_textures_size(); - if (std::distance(it, m_gizmos.end()) > 1) - height += OverlayGapY; + if (it->first == SlaSupports && wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA) + continue; + height += (float)it->second->get_textures_size() + OverlayGapY; } - return height; + return height - OverlayGapY; } GLGizmoBase* GLCanvas3D::Gizmos::_get_current() const @@ -3898,7 +3936,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) if (m_gizmos.get_current_type() == Gizmos::Flatten) { // Rotate the object so the normal points downward: - m_selection.rotate(m_gizmos.get_flattening_rotation()); + m_selection.flattening_rotate(m_gizmos.get_flattening_normal()); _on_flatten(); wxGetApp().obj_manipul()->update_settings_value(m_selection); } @@ -4977,7 +5015,7 @@ void GLCanvas3D::_update_gizmos_data() { m_gizmos.set_scale(Vec3d::Ones()); m_gizmos.set_rotation(Vec3d::Zero()); - m_gizmos.set_flattening_data(nullptr); + m_gizmos.set_flattening_data(m_selection.is_from_single_object() ? m_model->objects[m_selection.get_object_idx()] : nullptr); m_gizmos.set_model_object_ptr(nullptr); } } diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 5d0f5f218..fdbb67011 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -496,6 +496,8 @@ public: int get_object_idx() const; // Returns the instance id if the selection is from a single object and from a single instance, otherwise is -1 int get_instance_idx() const; + // Returns the indices of selected instances if the selection is from a single object, throws otherwise! + const InstanceIdxsList& get_instance_idxs() const; const IndicesList& get_volume_idxs() const { return m_list; } const GLVolume* get_volume(unsigned int volume_idx) const; @@ -507,6 +509,7 @@ public: void translate(const Vec3d& displacement); void rotate(const Vec3d& rotation); + void flattening_rotate(const Vec3d& normal); void scale(const Vec3d& scale); void mirror(Axis axis); @@ -597,7 +600,7 @@ private: Vec3d get_rotation() const; void set_rotation(const Vec3d& rotation); - Vec3d get_flattening_rotation() const; + Vec3d get_flattening_normal() const; void set_flattening_data(const ModelObject* model_object); diff --git a/src/slic3r/GUI/GLGizmo.cpp b/src/slic3r/GUI/GLGizmo.cpp index 974f855e2..7ff0cdfd8 100644 --- a/src/slic3r/GUI/GLGizmo.cpp +++ b/src/slic3r/GUI/GLGizmo.cpp @@ -1175,38 +1175,41 @@ void GLGizmoFlatten::on_start_dragging(const GLCanvas3D::Selection& selection) void GLGizmoFlatten::on_render(const GLCanvas3D::Selection& selection) const { - // the dragged_offset is a vector measuring where was the object moved - // with the gizmo being on. This is reset in set_flattening_data and - // does not work correctly when there are multiple copies. + // The planes are rendered incorrectly when the object is being moved. We better won't render anything in that case. + // This indeed has a better solution (to be implemented when there is more time) Vec3d dragged_offset(Vec3d::Zero()); if (m_starting_center == Vec3d::Zero()) m_starting_center = selection.get_bounding_box().center(); dragged_offset = selection.get_bounding_box().center() - m_starting_center; + if (dragged_offset.norm() > 0.001) + return; ::glEnable(GL_BLEND); ::glEnable(GL_DEPTH_TEST); ::glDisable(GL_CULL_FACE); - for (int i=0; i<(int)m_planes.size(); ++i) { - if (i == m_hover_id) - ::glColor4f(0.9f, 0.9f, 0.9f, 0.75f); - else - ::glColor4f(0.9f, 0.9f, 0.9f, 0.5f); + if (selection.is_from_single_object()) { + const std::set& instances_list = selection.get_instance_idxs(); - int instance_idx = selection.get_instance_idx(); - if ((instance_idx != -1) && (m_model_object != nullptr)) - { + if (!instances_list.empty() && m_model_object) { + for (const int instance_idx : instances_list) { Transform3d m = m_model_object->instances[instance_idx]->get_matrix(); - m.pretranslate(dragged_offset); - ::glPushMatrix(); - ::glMultMatrixd(m.data()); - ::glBegin(GL_POLYGON); - for (const Vec3d& vertex : m_planes[i].vertices) - { - ::glVertex3dv(vertex.data()); + for (int i=0; i<(int)m_planes.size(); ++i) { + if (i == m_hover_id) + ::glColor4f(0.9f, 0.9f, 0.9f, 0.75f); + else + ::glColor4f(0.9f, 0.9f, 0.9f, 0.5f); + + m.pretranslate(dragged_offset); + ::glPushMatrix(); + ::glMultMatrixd(m.data()); + ::glBegin(GL_POLYGON); + for (const Vec3d& vertex : m_planes[i].vertices) + ::glVertex3dv(vertex.data()); + ::glEnd(); + ::glPopMatrix(); + } } - ::glEnd(); - ::glPopMatrix(); } } @@ -1218,22 +1221,21 @@ void GLGizmoFlatten::on_render_for_picking(const GLCanvas3D::Selection& selectio { ::glEnable(GL_DEPTH_TEST); ::glDisable(GL_CULL_FACE); - - for (unsigned int i = 0; i < m_planes.size(); ++i) - { - ::glColor3f(1.0f, 1.0f, picking_color_component(i)); - int instance_idx = selection.get_instance_idx(); - if ((instance_idx != -1) && (m_model_object != nullptr)) - { - ::glPushMatrix(); - ::glMultMatrixd(m_model_object->instances[instance_idx]->get_matrix().data()); - ::glBegin(GL_POLYGON); - for (const Vec3d& vertex : m_planes[i].vertices) - { - ::glVertex3dv(vertex.data()); + if (selection.is_from_single_object()) { + const std::set& instances_list = selection.get_instance_idxs(); + if (!instances_list.empty() && m_model_object) { + for (const int instance_idx : instances_list) { + for (int i=0; i<(int)m_planes.size(); ++i) { + ::glColor3f(1.0f, 1.0f, picking_color_component(i)); + ::glPushMatrix(); + ::glMultMatrixd(m_model_object->instances[instance_idx]->get_matrix().data()); + ::glBegin(GL_POLYGON); + for (const Vec3d& vertex : m_planes[i].vertices) + ::glVertex3dv(vertex.data()); + ::glEnd(); + ::glPopMatrix(); + } } - ::glEnd(); - ::glPopMatrix(); } } @@ -1243,9 +1245,10 @@ void GLGizmoFlatten::on_render_for_picking(const GLCanvas3D::Selection& selectio void GLGizmoFlatten::set_flattening_data(const ModelObject* model_object) { m_starting_center = Vec3d::Zero(); + bool object_changed = m_model_object != model_object; m_model_object = model_object; - if (is_plane_update_necessary()) + if (object_changed && is_plane_update_necessary()) update_planes(); } @@ -1456,20 +1459,14 @@ bool GLGizmoFlatten::is_plane_update_necessary() const return false; } -Vec3d GLGizmoFlatten::get_flattening_rotation() const +Vec3d GLGizmoFlatten::get_flattening_normal() const { - // calculates the rotations in model space, taking in account the scaling factors - Eigen::Matrix m = m_model_object->instances.front()->get_matrix(true, true).matrix().block(0, 0, 3, 3).inverse().transpose(); - Eigen::Quaterniond q; - Vec3d angles = Geometry::extract_euler_angles(q.setFromTwoVectors(m * m_normal, -Vec3d::UnitZ()).toRotationMatrix()); + Vec3d out = m_normal; m_normal = Vec3d::Zero(); m_starting_center = Vec3d::Zero(); - return angles; + return out; } - - - GLGizmoSlaSupports::GLGizmoSlaSupports(GLCanvas3D& parent) : GLGizmoBase(parent), m_starting_center(Vec3d::Zero()) { diff --git a/src/slic3r/GUI/GLGizmo.hpp b/src/slic3r/GUI/GLGizmo.hpp index ea6e3ae6b..2b1749654 100644 --- a/src/slic3r/GUI/GLGizmo.hpp +++ b/src/slic3r/GUI/GLGizmo.hpp @@ -348,6 +348,7 @@ private: std::vector m_planes; mutable Vec3d m_starting_center; const ModelObject* m_model_object = nullptr; + std::vector instances_matrices; void update_planes(); bool is_plane_update_necessary() const; @@ -356,12 +357,12 @@ public: explicit GLGizmoFlatten(GLCanvas3D& parent); void set_flattening_data(const ModelObject* model_object); - Vec3d get_flattening_rotation() const; + Vec3d get_flattening_normal() const; protected: virtual bool on_init(); virtual std::string on_get_name() const; - virtual bool on_is_activable(const GLCanvas3D::Selection& selection) const { return selection.is_single_full_instance(); } + virtual bool on_is_activable(const GLCanvas3D::Selection& selection) const { return (selection.is_from_single_object() && !selection.is_wipe_tower() && !selection.is_modifier()); } virtual void on_start_dragging(const GLCanvas3D::Selection& selection); virtual void on_update(const Linef3& mouse_ray, const Point* mouse_pos) {} virtual void on_render(const GLCanvas3D::Selection& selection) const; From cf5dcfa9ed091d9a1b982ddb489ef72bb5528463 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Fri, 2 Nov 2018 19:49:40 +0100 Subject: [PATCH 07/43] ModelBase ID refactoring, starting to work. Now it remains to clean up some of the no more used Model interfaces. --- src/libslic3r/Model.cpp | 112 +++++++++++++++++++++++++------------- src/libslic3r/Model.hpp | 100 ++++++++++++++++++++++------------ src/libslic3r/Print.cpp | 66 +++++++++++++++++++++- src/slic3r/GUI/Plater.cpp | 2 + xs/xsp/Model.xsp | 2 +- 5 files changed, 205 insertions(+), 77 deletions(-) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 01886e870..79fd7292f 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -27,21 +27,39 @@ Model& Model::assign_copy(const Model &rhs) { this->copy_id(rhs); // copy materials - for (const std::pair &m : rhs.materials) - this->add_material(m.first, *m.second); + this->clear_materials(); + this->materials = rhs.materials; + for (std::pair &m : this->materials) { + // Copy including the ID and m_model. + m.second = new ModelMaterial(*m.second); + m.second->set_model(this); + } // copy objects + this->clear_objects(); this->objects.reserve(rhs.objects.size()); - for (const ModelObject *o : rhs.objects) - this->add_object(*o); + for (const ModelObject *model_object : rhs.objects) { + // Copy including the ID, leave ID set to invalid (zero). + auto mo = ModelObject::new_copy(*model_object); + mo->set_model(this); + this->objects.emplace_back(mo); + } return *this; } Model& Model::assign_copy(Model &&rhs) { this->copy_id(rhs); - this->materials = std::move(rhs.materials); + // Move materials, adjust the parent pointer. + this->clear_materials(); + this->materials = std::move(rhs.materials); + for (std::pair &m : this->materials) + m.second->set_model(this); rhs.materials.clear(); + // Move objects, adjust the parent pointer. + this->clear_objects(); this->objects = std::move(rhs.objects); + for (ModelObject *model_object : this->objects) + model_object->set_model(this); rhs.objects.clear(); return *this; } @@ -166,7 +184,8 @@ ModelObject* Model::add_object(const char *name, const char *path, TriangleMesh ModelObject* Model::add_object(const ModelObject &other) { - ModelObject* new_object = new ModelObject(this, other); + ModelObject* new_object = ModelObject::new_clone(other); + new_object->set_model(this); this->objects.push_back(new_object); return new_object; } @@ -178,21 +197,36 @@ void Model::delete_object(size_t idx) this->objects.erase(i); } -void Model::delete_object(ModelObject* object) +bool Model::delete_object(ModelObject* object) { - if (object == nullptr) - return; - - for (ModelObjectPtrs::iterator it = objects.begin(); it != objects.end(); ++it) - { - ModelObject* obj = *it; - if (obj == object) - { - delete obj; - objects.erase(it); - return; + if (object != nullptr) { + size_t idx = 0; + for (ModelObject *model_object : objects) { + if (model_object == object) { + delete model_object; + objects.erase(objects.begin() + idx); + return true; + } + ++ idx; } } + return false; +} + +bool Model::delete_object(ModelID id) +{ + if (id.id != 0) { + size_t idx = 0; + for (ModelObject *model_object : objects) { + if (model_object->id() == id) { + delete model_object; + objects.erase(objects.begin() + idx); + return true; + } + ++ idx; + } + } + return false; } void Model::clear_objects() @@ -232,7 +266,8 @@ ModelMaterial* Model::add_material(t_model_material_id material_id, const ModelM ModelMaterial* material = this->get_material(material_id); delete material; // set new material - material = new ModelMaterial(this, other); + material = new ModelMaterial(other); + material->set_model(this); this->materials[material_id] = material; return material; } @@ -435,6 +470,7 @@ void Model::convert_multipart_object(unsigned int max_extruders) ModelObject* object = new ModelObject(this); object->input_file = this->objects.front()->input_file; object->name = this->objects.front()->name; + //FIXME copy the config etc? reset_auto_extruder_id(); @@ -497,12 +533,6 @@ void Model::reset_auto_extruder_id() s_auto_extruder_id = 1; } -ModelObject::ModelObject(Model *model, const ModelObject &rhs) : - m_model(model) -{ - this->assign_copy(rhs); -} - ModelObject::~ModelObject() { this->clear_volumes(); @@ -525,14 +555,18 @@ ModelObject& ModelObject::assign_copy(const ModelObject &rhs) m_bounding_box = rhs.m_bounding_box; m_bounding_box_valid = rhs.m_bounding_box_valid; - this->volumes.clear(); + this->clear_volumes(); this->volumes.reserve(rhs.volumes.size()); - for (ModelVolume *model_volume : rhs.volumes) - this->add_volume(*model_volume); - this->instances.clear(); + for (ModelVolume *model_volume : rhs.volumes) { + this->volumes.emplace_back(new ModelVolume(*model_volume)); + this->volumes.back()->set_model_object(this); + } + this->clear_instances(); this->instances.reserve(rhs.instances.size()); - for (const ModelInstance *model_instance : rhs.instances) - this->add_instance(*model_instance); + for (const ModelInstance *model_instance : rhs.instances) { + this->instances.emplace_back(new ModelInstance(*model_instance)); + this->instances.back()->set_model_object(this); + } return *this; } @@ -553,10 +587,16 @@ ModelObject& ModelObject::assign_copy(ModelObject &&rhs) m_bounding_box = std::move(rhs.m_bounding_box); m_bounding_box_valid = std::move(rhs.m_bounding_box_valid); + this->clear_volumes(); this->volumes = std::move(rhs.volumes); rhs.volumes.clear(); + for (ModelVolume *model_volume : this->volumes) + model_volume->set_model_object(this); + this->clear_instances(); this->instances = std::move(rhs.instances); rhs.instances.clear(); + for (ModelInstance *model_instance : this->instances) + model_instance->set_model_object(this); return *this; } @@ -919,7 +959,7 @@ void ModelObject::split(ModelObjectPtrs* new_objects) if (this->volumes.size() > 1) { // We can't split meshes if there's more than one volume, because // we can't group the resulting meshes by object afterwards - new_objects->push_back(this); + new_objects->emplace_back(this); return; } @@ -938,7 +978,7 @@ void ModelObject::split(ModelObjectPtrs* new_objects) for (const ModelInstance *model_instance : this->instances) new_object->add_instance(*model_instance); new_object->add_volume(*volume, std::move(*mesh)); - new_objects->push_back(new_object); + new_objects->emplace_back(new_object); delete mesh; } @@ -1060,9 +1100,8 @@ void ModelObject::print_info() const void ModelVolume::set_material_id(t_model_material_id material_id) { m_material_id = material_id; - // ensure m_material_id references an existing material - (void)this->object->get_model()->add_material(material_id); + this->object->get_model()->add_material(material_id); } ModelMaterial* ModelVolume::material() const @@ -1073,13 +1112,12 @@ ModelMaterial* ModelVolume::material() const void ModelVolume::set_material(t_model_material_id material_id, const ModelMaterial &material) { m_material_id = material_id; - (void)this->object->get_model()->add_material(material_id, material); + this->object->get_model()->add_material(material_id, material); } ModelMaterial* ModelVolume::assign_unique_material() { Model* model = this->get_object()->get_model(); - // as material-id "0" is reserved by the AMF spec we start from 1 m_material_id = 1 + model->materials.size(); // watchout for implicit cast return model->add_material(m_material_id); diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 90ee456ec..adc1f3406 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -61,11 +61,6 @@ class ModelBase { public: ModelID id() const { return m_id; } - // Use with caution! - void set_new_unique_id() { m_id = generate_new_id(); } - void set_invalid_id() { m_id = 0; } - // Use with caution! - void copy_id(const ModelBase &rhs) { m_id = rhs.id(); } protected: // Constructors to be only called by derived classes. @@ -75,6 +70,12 @@ protected: // by an existing ID copied from elsewhere. ModelBase(int) : m_id(ModelID(0)) {} + // Use with caution! + void set_new_unique_id() { m_id = generate_new_id(); } + void set_invalid_id() { m_id = 0; } + // Use with caution! + void copy_id(const ModelBase &rhs) { m_id = rhs.id(); } + // Override this method if a ModelBase derived class owns other ModelBase derived instances. void assign_new_unique_ids_recursive() { this->set_new_unique_id(); } @@ -86,12 +87,6 @@ private: }; #define MODELBASE_DERIVED_COPY_MOVE_CLONE(TYPE) \ - /* To be able to return an object from own copy / clone methods. Hopefully the compiler will do the "Copy elision" */ \ - /* (Omits copy and move(since C++11) constructors, resulting in zero - copy pass - by - value semantics). */ \ - TYPE(const TYPE &rhs) : ModelBase(-1) { this->assign_copy(rhs); } \ - explicit TYPE(TYPE &&rhs) : ModelBase(-1) { this->assign_clone(std::move(rhs)); } \ - TYPE& operator=(const TYPE &rhs) { this->assign_copy(rhs); return *this; } \ - TYPE& operator=(TYPE &&rhs) { this->assign_copy(std::move(rhs)); return *this; } \ /* Copy a model, copy the IDs. The Print::apply() will call the TYPE::copy() method */ \ /* to make a private copy for background processing. */ \ static TYPE* new_copy(const TYPE &rhs) { return new TYPE(rhs); } \ @@ -101,7 +96,7 @@ private: TYPE& assign_copy(const TYPE &rhs); \ TYPE& assign_copy(TYPE &&rhs); \ /* Copy a TYPE, generate new IDs. The front end will use this call. */ \ - TYPE* new_clone(const TYPE &rhs) { \ + static TYPE* new_clone(const TYPE &rhs) { \ /* Default constructor assigning an invalid ID. */ \ auto obj = new TYPE(-1); \ obj->assign_clone(rhs); \ @@ -128,7 +123,6 @@ private: \ // Material, which may be shared across multiple ModelObjects of a single Model. class ModelMaterial : public ModelBase { - friend class Model; public: // Attributes are defined by the AMF file format, but they don't seem to be used by Slic3r for any purpose. t_model_material_attributes attributes; @@ -139,14 +133,22 @@ public: void apply(const t_model_material_attributes &attributes) { this->attributes.insert(attributes.begin(), attributes.end()); } +protected: + friend class Model; + // Constructor, which assigns a new unique ID. + ModelMaterial(Model *model) : m_model(model) {} + // Copy constructor copies the ID and m_model! + ModelMaterial(const ModelMaterial &rhs) = default; + void set_model(Model *model) { m_model = model; } + private: // Parent, owning this material. Model *m_model; - ModelMaterial(Model *model) : m_model(model) {} - ModelMaterial(Model *model, const ModelMaterial &other) : attributes(other.attributes), config(other.config), m_model(model) {} - explicit ModelMaterial(ModelMaterial &rhs) = delete; - ModelMaterial& operator=(ModelMaterial &rhs) = delete; + ModelMaterial() = delete; + ModelMaterial(ModelMaterial &&rhs) = delete; + ModelMaterial& operator=(const ModelMaterial &rhs) = delete; + ModelMaterial& operator=(ModelMaterial &&rhs) = delete; }; // A printable object, possibly having multiple print volumes (each with its own set of parameters and materials), @@ -254,16 +256,23 @@ protected: private: ModelObject(Model *model) : layer_height_profile_valid(false), m_model(model), origin_translation(Vec3d::Zero()), m_bounding_box_valid(false) {} - ModelObject(Model *model, const ModelObject &rhs); + ModelObject(Model *model, const ModelObject &rhs) { this->assign_copy(rhs); m_model = model; } ~ModelObject(); - MODELBASE_DERIVED_COPY_MOVE_CLONE(ModelObject) + /* To be able to return an object from own copy / clone methods. Hopefully the compiler will do the "Copy elision" */ + /* (Omits copy and move(since C++11) constructors, resulting in zero - copy pass - by - value semantics). */ + ModelObject(const ModelObject &rhs) : ModelBase(-1), m_model(rhs.m_model) { this->assign_copy(rhs); } + explicit ModelObject(ModelObject &&rhs) : ModelBase(-1) { this->assign_copy(std::move(rhs)); } + ModelObject& operator=(const ModelObject &rhs) { this->assign_copy(rhs); m_model = rhs.m_model; return *this; } + ModelObject& operator=(ModelObject &&rhs) { this->assign_copy(std::move(rhs)); m_model = rhs.m_model; return *this; } + + MODELBASE_DERIVED_COPY_MOVE_CLONE(ModelObject) MODELBASE_DERIVED_PRIVATE_COPY_MOVE(ModelObject) - // Parent object, owning this ModelObject. - Model *m_model; - // Bounding box, cached. + // Parent object, owning this ModelObject. Set to nullptr here, so the macros above will have it initialized. + Model *m_model = nullptr; + // Bounding box, cached. mutable BoundingBoxf3 m_bounding_box; mutable bool m_bounding_box_valid; }; @@ -353,6 +362,10 @@ public: const Transform3d& get_matrix(bool dont_translate = false, bool dont_rotate = false, bool dont_scale = false, bool dont_mirror = false) const { return m_transformation.get_matrix(dont_translate, dont_rotate, dont_scale, dont_mirror); } #endif // ENABLE_MODELVOLUME_TRANSFORM +protected: + explicit ModelVolume(ModelVolume &rhs) = default; + void set_model_object(ModelObject *model_object) { object = model_object; } + private: // Parent object owning this ModelVolume. ModelObject* object; @@ -373,21 +386,20 @@ private: 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) {} 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) { - this->set_material_id(other.material_id()); + if (! other.material_id().empty()) + this->set_material_id(other.material_id()); } ModelVolume(ModelObject *object, const ModelVolume &other, TriangleMesh &&mesh) : - ModelBase(other), // copy the ID name(other.name), mesh(std::move(mesh)), config(other.config), m_type(other.m_type), object(object) { - this->set_material_id(other.material_id()); + if (! other.material_id().empty()) + this->set_material_id(other.material_id()); if (mesh.stl.stats.number_of_facets > 1) calculate_convex_hull(); } - explicit ModelVolume(ModelVolume &rhs) = delete; ModelVolume& operator=(ModelVolume &rhs) = delete; }; @@ -404,8 +416,6 @@ public: Num_BedStates }; - friend class ModelObject; - private: #if ENABLE_MODELVOLUME_TRANSFORM Geometry::Transformation m_transformation; @@ -494,12 +504,21 @@ public: bool is_printable() const { return print_volume_state == PVS_Inside; } +protected: + friend class Print; + friend class ModelObject; + + explicit ModelInstance(const ModelInstance &rhs) = default; + void set_model_object(ModelObject *model_object) { object = model_object; } + private: // Parent object, owning this instance. ModelObject* object; #if ENABLE_MODELVOLUME_TRANSFORM + // Constructor, which assigns a new unique ID. ModelInstance(ModelObject *object) : object(object), print_volume_state(PVS_Inside) {} + // Constructor, which assigns a new unique ID. ModelInstance(ModelObject *object, const ModelInstance &other) : m_transformation(other.m_transformation), object(object), print_volume_state(PVS_Inside) {} #else @@ -508,8 +527,10 @@ private: 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) {} #endif // ENABLE_MODELVOLUME_TRANSFORM - explicit ModelInstance(ModelInstance &rhs) = delete; - ModelInstance& operator=(ModelInstance &rhs) = delete; + ModelInstance() = delete; + explicit ModelInstance(ModelInstance &&rhs) = delete; + ModelInstance& operator=(const ModelInstance &rhs) = delete; + ModelInstance& operator=(ModelInstance &&rhs) = delete; }; // The print bed content. @@ -532,6 +553,13 @@ public: Model() {} ~Model() { this->clear_objects(); this->clear_materials(); } + /* To be able to return an object from own copy / clone methods. Hopefully the compiler will do the "Copy elision" */ + /* (Omits copy and move(since C++11) constructors, resulting in zero - copy pass - by - value semantics). */ + Model(const Model &rhs) : ModelBase(-1) { this->assign_copy(rhs); } + explicit Model(Model &&rhs) : ModelBase(-1) { this->assign_copy(std::move(rhs)); } + Model& operator=(const Model &rhs) { this->assign_copy(rhs); return *this; } + Model& operator=(Model &&rhs) { this->assign_copy(std::move(rhs)); return *this; } + MODELBASE_DERIVED_COPY_MOVE_CLONE(Model) static Model read_from_file(const std::string &input_file, DynamicPrintConfig *config = nullptr, bool add_default_instances = true); @@ -547,8 +575,8 @@ public: ModelObject* add_object(const char *name, const char *path, TriangleMesh &&mesh); ModelObject* add_object(const ModelObject &other); void delete_object(size_t idx); - void delete_object(ModelID id); - void delete_object(ModelObject* object); + bool delete_object(ModelID id); + bool delete_object(ModelObject* object); void clear_objects(); ModelMaterial* add_material(t_model_material_id material_id); @@ -558,9 +586,9 @@ public: return (i == this->materials.end()) ? nullptr : i->second; } - void delete_material(t_model_material_id material_id); - void clear_materials(); - bool add_default_instances(); + void delete_material(t_model_material_id material_id); + void clear_materials(); + bool add_default_instances(); // Returns approximate axis aligned bounding box of this model BoundingBoxf3 bounding_box() const; // Set the print_volume_state of PrintObject::instances, diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 402edaeac..4052c79ac 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -709,8 +709,60 @@ static std::vector print_objects_from_model_object(const ModelOb return std::vector(trafos.begin(), trafos.end()); } +#ifdef _DEBUG +// Verify whether the IDs of Model / ModelObject / ModelVolume / ModelInstance / ModelMaterial are valid and unique. +static inline void check_model_ids_validity(const Model &model) +{ + std::set ids; + auto check = [&ids](ModelID id) { + assert(id.id > 0); + assert(ids.find(id) == ids.end()); + ids.insert(id); + }; + for (const ModelObject *model_object : model.objects) { + check(model_object->id()); + for (const ModelVolume *model_volume : model_object->volumes) + check(model_volume->id()); + for (const ModelInstance *model_instance : model_object->instances) + check(model_instance->id()); + } + for (const auto mm : model.materials) + check(mm.second->id()); +} + +static inline void check_model_ids_equal(const Model &model1, const Model &model2) +{ + // Verify whether the IDs of model1 and model match. + assert(model1.objects.size() == model2.objects.size()); + for (size_t idx_model = 0; idx_model < model2.objects.size(); ++ idx_model) { + const ModelObject &model_object1 = *model1.objects[idx_model]; + const ModelObject &model_object2 = * model2.objects[idx_model]; + assert(model_object1.id() == model_object2.id()); + assert(model_object1.volumes.size() == model_object2.volumes.size()); + assert(model_object1.instances.size() == model_object2.instances.size()); + for (size_t i = 0; i < model_object1.volumes.size(); ++ i) + assert(model_object1.volumes[i]->id() == model_object2.volumes[i]->id()); + for (size_t i = 0; i < model_object1.instances.size(); ++ i) + assert(model_object1.instances[i]->id() == model_object2.instances[i]->id()); + } + assert(model1.materials.size() == model2.materials.size()); + { + auto it1 = model1.materials.begin(); + auto it2 = model2.materials.begin(); + for (; it1 != model1.materials.end(); ++ it1, ++ it2) { + assert(it1->first == it2->first); // compare keys + assert(it1->second->id() == it2->second->id()); + } + } +} +#endif /* _DEBUG */ + Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &config_in) { +#ifdef _DEBUG + check_model_ids_validity(model); +#endif /* _DEBUG */ + // Make a copy of the config, normalize it. DynamicPrintConfig config(config_in); config.normalize(); @@ -807,7 +859,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co auto it = std::lower_bound(model_objects_old.begin(), model_objects_old.end(), mobj, by_id_lower); if (it == model_objects_old.end() || (*it)->id() != mobj->id()) { // New ModelObject added. - m_model.objects.emplace_back(ModelObject::new_copy(**it)); + m_model.objects.emplace_back(ModelObject::new_copy(*mobj)); m_model.objects.back()->set_model(&m_model); model_object_status.emplace(mobj->id(), ModelObjectStatus::New); } else { @@ -935,8 +987,11 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co model_object.name = model_object_new.name; model_object.input_file = model_object_new.input_file; model_object.clear_instances(); - for (const ModelInstance *model_instance : model_object_new.instances) - model_object.add_instance(*model_instance); + model_object.instances.reserve(model_object_new.instances.size()); + for (const ModelInstance *model_instance : model_object_new.instances) { + model_object.instances.emplace_back(new ModelInstance(*model_instance)); + model_object.instances.back()->set_model_object(&model_object); + } } } @@ -1138,6 +1193,11 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co object->update_layer_height_profile(); this->update_object_placeholders(); + +#ifdef _DEBUG + check_model_ids_equal(m_model, model); +#endif /* _DEBUG */ + return static_cast(apply_status); } diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 4cb274a50..a78b656d2 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1435,7 +1435,9 @@ void Plater::priv::mirror(Axis axis) void Plater::priv::arrange() { + this->background_process.stop(); main_frame->app_controller()->arrange_model(); + this->schedule_background_process(); // ignore arrange failures on purpose: user has visual feedback and we don't need to warn him // when parts don't fit in print bed diff --git a/xs/xsp/Model.xsp b/xs/xsp/Model.xsp index 180e052ff..a198b1b9f 100644 --- a/xs/xsp/Model.xsp +++ b/xs/xsp/Model.xsp @@ -32,7 +32,7 @@ %name{_add_object} Ref add_object(); Ref _add_object_clone(ModelObject* other, bool copy_volumes = true) - %code%{ RETVAL = THIS->add_object(*other, copy_volumes); %}; + %code%{ auto ptr = THIS->add_object(*other); if (! copy_volumes) ptr->clear_volumes(); RETVAL = ptr; %}; void delete_object(size_t idx); void clear_objects(); size_t objects_count() From 5da83742a37141467a9887067592e72f8657e379 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Fri, 2 Nov 2018 20:41:49 +0100 Subject: [PATCH 08/43] Some refactoring. --- src/libslic3r/Layer.cpp | 14 ++++++-------- src/libslic3r/Model.hpp | 19 ++++++++----------- src/libslic3r/Print.cpp | 8 +++++--- src/libslic3r/Print.hpp | 9 +++------ src/libslic3r/PrintObject.cpp | 17 +++++++++-------- 5 files changed, 31 insertions(+), 36 deletions(-) diff --git a/src/libslic3r/Layer.cpp b/src/libslic3r/Layer.cpp index afdde1852..5003c67d7 100644 --- a/src/libslic3r/Layer.cpp +++ b/src/libslic3r/Layer.cpp @@ -32,9 +32,8 @@ void Layer::make_slices() slices = m_regions.front()->slices; } else { Polygons slices_p; - FOREACH_LAYERREGION(this, layerm) { - polygons_append(slices_p, to_polygons((*layerm)->slices)); - } + for (LayerRegion *layerm : m_regions) + polygons_append(slices_p, to_polygons(layerm->slices)); slices = union_ex(slices_p); } @@ -53,7 +52,7 @@ void Layer::make_slices() // populate slices vector for (size_t i : order) - this->slices.expolygons.push_back(STDMOVE(slices[i])); + this->slices.expolygons.push_back(std::move(slices[i])); } void Layer::merge_slices() @@ -63,10 +62,9 @@ void Layer::merge_slices() // but use the non-split islands of a layer. For a single region print, these shall be equal. m_regions.front()->slices.set(this->slices.expolygons, stInternal); } else { - FOREACH_LAYERREGION(this, layerm) { + for (LayerRegion *layerm : m_regions) // without safety offset, artifacts are generated (GH #2494) - (*layerm)->slices.set(union_ex(to_polygons(STDMOVE((*layerm)->slices.surfaces)), true), stInternal); - } + layerm->slices.set(union_ex(to_polygons(std::move(layerm->slices.surfaces)), true), stInternal); } } @@ -80,7 +78,7 @@ void Layer::make_perimeters() // keep track of regions whose perimeters we have already generated std::set done; - FOREACH_LAYERREGION(this, layerm) { + for (LayerRegionPtrs::iterator layerm = m_regions.begin(); layerm != m_regions.end(); ++ layerm) { size_t region_id = layerm - m_regions.begin(); if (done.find(region_id) != done.end()) continue; BOOST_LOG_TRIVIAL(trace) << "Generating perimeters for layer " << this->id() << ", region " << region_id; diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index adc1f3406..cfa6ed25b 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -256,7 +256,6 @@ protected: private: ModelObject(Model *model) : layer_height_profile_valid(false), m_model(model), origin_translation(Vec3d::Zero()), m_bounding_box_valid(false) {} - ModelObject(Model *model, const ModelObject &rhs) { this->assign_copy(rhs); m_model = model; } ~ModelObject(); /* To be able to return an object from own copy / clone methods. Hopefully the compiler will do the "Copy elision" */ @@ -281,8 +280,6 @@ private: // ModelVolume instances are owned by a ModelObject. class ModelVolume : public ModelBase { - friend class ModelObject; - public: std::string name; // The triangular model. @@ -299,9 +296,6 @@ public: SUPPORT_BLOCKER, }; - // Clone this ModelVolume, keep the ID identical, set the parent to the cloned volume. - ModelVolume* clone(ModelObject *parent) { return new ModelVolume(parent, *this); } - // A parent object owning this modifier volume. ModelObject* get_object() const { return this->object; }; Type type() const { return m_type; } @@ -363,7 +357,10 @@ public: #endif // ENABLE_MODELVOLUME_TRANSFORM protected: - explicit ModelVolume(ModelVolume &rhs) = default; + friend class Print; + friend class ModelObject; + + explicit ModelVolume(ModelVolume &rhs) = default; void set_model_object(ModelObject *model_object) { object = model_object; } private: @@ -517,13 +514,13 @@ private: #if ENABLE_MODELVOLUME_TRANSFORM // Constructor, which assigns a new unique ID. - ModelInstance(ModelObject *object) : object(object), print_volume_state(PVS_Inside) {} + explicit ModelInstance(ModelObject *object) : object(object), print_volume_state(PVS_Inside) {} // Constructor, which assigns a new unique ID. - ModelInstance(ModelObject *object, const ModelInstance &other) : + explicit ModelInstance(ModelObject *object, const ModelInstance &other) : m_transformation(other.m_transformation), object(object), print_volume_state(PVS_Inside) {} #else - 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) : + explicit 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) {} + explicit 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) {} #endif // ENABLE_MODELVOLUME_TRANSFORM diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 4052c79ac..1eacb50b1 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -634,7 +634,7 @@ static inline bool model_volume_list_changed(const ModelObject &model_object_old return false; } -static inline void model_volume_list_update_supports(ModelObject &model_object_dst, const ModelObject &model_object_src) +void Print::model_volume_list_update_supports(ModelObject &model_object_dst, const ModelObject &model_object_src) { // 1) Delete the support volumes from model_object_dst. { @@ -650,8 +650,10 @@ static inline void model_volume_list_update_supports(ModelObject &model_object_d } // 2) Copy the support volumes from model_object_src to the end of model_object_dst. for (ModelVolume *vol : model_object_src.volumes) { - if (vol->is_support_modifier()) - model_object_dst.volumes.emplace_back(vol->clone(&model_object_dst)); + if (vol->is_support_modifier()) { + model_object_dst.volumes.emplace_back(new ModelVolume(*vol)); + model_object_dst.volumes.back()->set_model_object(&model_object_dst); + } } } diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index 3c2a87c74..705c41458 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -564,6 +564,9 @@ private: void _make_wipe_tower(); void _simplify_slices(double distance); + // Declared here to have access to Model / ModelObject / ModelInstance + static void model_volume_list_update_supports(ModelObject &model_object_dst, const ModelObject &model_object_src); + PrintState m_state; // Mutex used for synchronization of the worker thread with the UI thread: // The mutex will be used to guard the worker thread against entering a stage @@ -601,12 +604,6 @@ private: friend class PrintObject; }; - -#define FOREACH_BASE(type, container, iterator) for (type::const_iterator iterator = (container).begin(); iterator != (container).end(); ++iterator) -#define FOREACH_OBJECT(print, object) FOREACH_BASE(PrintObjectPtrs, (print)->m_objects, object) -#define FOREACH_LAYER(object, layer) FOREACH_BASE(LayerPtrs, (object)->m_layers, layer) -#define FOREACH_LAYERREGION(layer, layerm) FOREACH_BASE(LayerRegionPtrs, (layer)->m_regions, layerm) - } #endif diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 8f9146766..8ca9c37ae 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -170,8 +170,8 @@ void PrintObject::make_perimeters() // merge slices if they were split into types if (this->typed_slices) { - FOREACH_LAYER(this, layer_it) { - (*layer_it)->merge_slices(); + for (Layer *layer : m_layers) { + layer->merge_slices(); m_print->throw_if_canceled(); } this->typed_slices = false; @@ -1243,9 +1243,10 @@ void PrintObject::bridge_over_infill() *this ); - FOREACH_LAYER(this, layer_it) { + for (LayerPtrs::iterator layer_it = m_layers.begin(); layer_it != m_layers.end(); ++ layer_it) { // skip first layer - if (layer_it == m_layers.begin()) continue; + if (layer_it == m_layers.begin()) + continue; Layer* layer = *layer_it; LayerRegion* layerm = layer->m_regions[region_id]; @@ -1271,8 +1272,8 @@ void PrintObject::bridge_over_infill() // iterate through regions and collect internal surfaces Polygons lower_internal; - FOREACH_LAYERREGION(lower_layer, lower_layerm_it) - (*lower_layerm_it)->fill_surfaces.filter_by_type(stInternal, &lower_internal); + for (LayerRegion *lower_layerm : lower_layer->m_regions) + lower_layerm->fill_surfaces.filter_by_type(stInternal, &lower_internal); // intersect such lower internal surfaces with the candidate solid surfaces to_bridge_pp = intersection(to_bridge_pp, lower_internal); @@ -1734,8 +1735,8 @@ void PrintObject::_make_perimeters() // merge slices if they were split into types if (this->typed_slices) { - FOREACH_LAYER(this, layer_it) - (*layer_it)->merge_slices(); + for (Layer *layer : m_layers) + layer->merge_slices(); this->typed_slices = false; this->invalidate_step(posPrepareInfill); } From 3b72748489b544d95e741f67f971d2fd7c2b8e4d Mon Sep 17 00:00:00 2001 From: bubnikv Date: Fri, 2 Nov 2018 20:45:23 +0100 Subject: [PATCH 09/43] Removed the STDMOVE macro. --- src/libslic3r/Fill/Fill.cpp | 2 +- src/libslic3r/Layer.cpp | 2 +- src/libslic3r/LayerRegion.cpp | 28 ++++++++++++++-------------- src/libslic3r/SupportMaterial.cpp | 10 +++++----- src/libslic3r/libslic3r.h | 13 ------------- src/slic3r/GUI/OptionsGroup.cpp | 20 ++++++++++---------- 6 files changed, 31 insertions(+), 44 deletions(-) diff --git a/src/libslic3r/Fill/Fill.cpp b/src/libslic3r/Fill/Fill.cpp index f1436c931..016d162d8 100644 --- a/src/libslic3r/Fill/Fill.cpp +++ b/src/libslic3r/Fill/Fill.cpp @@ -247,7 +247,7 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out) // Only concentric fills are not sorted. eec->no_sort = f->no_sort(); extrusion_entities_append_paths( - eec->entities, STDMOVE(polylines), + eec->entities, std::move(polylines), is_bridge ? erBridgeInfill : (surface.is_solid() ? diff --git a/src/libslic3r/Layer.cpp b/src/libslic3r/Layer.cpp index 5003c67d7..7878bffab 100644 --- a/src/libslic3r/Layer.cpp +++ b/src/libslic3r/Layer.cpp @@ -135,7 +135,7 @@ void Layer::make_perimeters() // Separate the fill surfaces. ExPolygons expp = intersection_ex(to_polygons(fill_surfaces), (*l)->slices); (*l)->fill_expolygons = expp; - (*l)->fill_surfaces.set(STDMOVE(expp), fill_surfaces.surfaces.front()); + (*l)->fill_surfaces.set(std::move(expp), fill_surfaces.surfaces.front()); } } } diff --git a/src/libslic3r/LayerRegion.cpp b/src/libslic3r/LayerRegion.cpp index e0f97703c..6f70fba65 100644 --- a/src/libslic3r/LayerRegion.cpp +++ b/src/libslic3r/LayerRegion.cpp @@ -34,7 +34,7 @@ void LayerRegion::slices_to_fill_surfaces_clipped() // in place. However we're now only using its boundaries (which are invariant) // so we're safe. This guarantees idempotence of prepare_infill() also in case // that combine_infill() turns some fill_surface into VOID surfaces. -// Polygons fill_boundaries = to_polygons(STDMOVE(this->fill_surfaces)); +// Polygons fill_boundaries = to_polygons(std::move(this->fill_surfaces)); Polygons fill_boundaries = to_polygons(this->fill_expolygons); // Collect polygons per surface type. std::vector polygons_by_surface; @@ -133,9 +133,9 @@ void LayerRegion::process_external_surfaces(const Layer* lower_layer) if (internal_surface) // Make a copy as the following line uses the move semantics. internal.push_back(surface); - polygons_append(fill_boundaries, STDMOVE(surface.expolygon)); + polygons_append(fill_boundaries, std::move(surface.expolygon)); } else if (internal_surface) - internal.push_back(STDMOVE(surface)); + internal.push_back(std::move(surface)); } } @@ -192,7 +192,7 @@ void LayerRegion::process_external_surfaces(const Layer* lower_layer) polys = intersection(polys, to_polygons(fill_boundaries_ex[idx_island])); } bridge_bboxes.push_back(get_extents(polys)); - bridges_grown.push_back(STDMOVE(polys)); + bridges_grown.push_back(std::move(polys)); } } @@ -243,7 +243,7 @@ void LayerRegion::process_external_surfaces(const Layer* lower_layer) for (size_t i = 0; i < bridges.size(); ++ i) { if (bridge_group[i] != group_id) continue; - initial.push_back(STDMOVE(bridges[i].expolygon)); + initial.push_back(std::move(bridges[i].expolygon)); polygons_append(grown, bridges_grown[i]); } // detect bridge direction before merging grown surfaces otherwise adjacent bridges @@ -269,7 +269,7 @@ void LayerRegion::process_external_surfaces(const Layer* lower_layer) surfaces_append(bottom, union_ex(grown, true), bridges[idx_last]); } - fill_boundaries = STDMOVE(to_polygons(fill_boundaries_ex)); + fill_boundaries = std::move(to_polygons(fill_boundaries_ex)); BOOST_LOG_TRIVIAL(trace) << "Processing external surface, detecting bridges - done"; } @@ -284,7 +284,7 @@ void LayerRegion::process_external_surfaces(const Layer* lower_layer) Surfaces new_surfaces; { // Merge top and bottom in a single collection. - surfaces_append(top, STDMOVE(bottom)); + surfaces_append(top, std::move(bottom)); // Intersect the grown surfaces with the actual fill boundaries. Polygons bottom_polygons = to_polygons(bottom); for (size_t i = 0; i < top.size(); ++ i) { @@ -292,11 +292,11 @@ void LayerRegion::process_external_surfaces(const Layer* lower_layer) if (s1.empty()) continue; Polygons polys; - polygons_append(polys, STDMOVE(s1)); + polygons_append(polys, std::move(s1)); for (size_t j = i + 1; j < top.size(); ++ j) { Surface &s2 = top[j]; if (! s2.empty() && surfaces_could_merge(s1, s2)) { - polygons_append(polys, STDMOVE(s2)); + polygons_append(polys, std::move(s2)); s2.clear(); } } @@ -306,7 +306,7 @@ void LayerRegion::process_external_surfaces(const Layer* lower_layer) surfaces_append( new_surfaces, // Don't use a safety offset as fill_boundaries were already united using the safety offset. - STDMOVE(intersection_ex(polys, fill_boundaries, false)), + std::move(intersection_ex(polys, fill_boundaries, false)), s1); } } @@ -318,20 +318,20 @@ void LayerRegion::process_external_surfaces(const Layer* lower_layer) if (s1.empty()) continue; Polygons polys; - polygons_append(polys, STDMOVE(s1)); + polygons_append(polys, std::move(s1)); for (size_t j = i + 1; j < internal.size(); ++ j) { Surface &s2 = internal[j]; if (! s2.empty() && surfaces_could_merge(s1, s2)) { - polygons_append(polys, STDMOVE(s2)); + polygons_append(polys, std::move(s2)); s2.clear(); } } ExPolygons new_expolys = diff_ex(polys, new_polygons); polygons_append(new_polygons, to_polygons(new_expolys)); - surfaces_append(new_surfaces, STDMOVE(new_expolys), s1); + surfaces_append(new_surfaces, std::move(new_expolys), s1); } - this->fill_surfaces.surfaces = STDMOVE(new_surfaces); + this->fill_surfaces.surfaces = std::move(new_surfaces); #ifdef SLIC3R_DEBUG_SLICE_PROCESSING export_region_fill_surfaces_to_svg_debug("3_process_external_surfaces-final"); diff --git a/src/libslic3r/SupportMaterial.cpp b/src/libslic3r/SupportMaterial.cpp index bd1a9f3fb..31305f332 100644 --- a/src/libslic3r/SupportMaterial.cpp +++ b/src/libslic3r/SupportMaterial.cpp @@ -2450,7 +2450,7 @@ void LoopInterfaceProcessor::generate(MyLayerExtruded &top_contact_layer, const // Transform loops into ExtrusionPath objects. extrusion_entities_append_paths( top_contact_layer.extrusions, - STDMOVE(loop_lines), + std::move(loop_lines), erSupportMaterialInterface, flow.mm3_per_mm(), flow.width, flow.height); } @@ -2827,7 +2827,7 @@ void PrintObjectSupportMaterial::generate_toolpaths( to_infill = offset_ex(to_infill, float(- 0.4 * flow.scaled_spacing())); extrusion_entities_append_paths( support_layer.support_fills.entities, - to_polylines(STDMOVE(to_infill_polygons)), + to_polylines(std::move(to_infill_polygons)), erSupportMaterial, flow.mm3_per_mm(), flow.width, flow.height); } if (! to_infill.empty()) { @@ -2841,7 +2841,7 @@ void PrintObjectSupportMaterial::generate_toolpaths( // Destination support_layer.support_fills.entities, // Regions to fill - STDMOVE(to_infill), + std::move(to_infill), // Filler and its parameters filler, float(support_density), // Extrusion parameters @@ -3037,14 +3037,14 @@ void PrintObjectSupportMaterial::generate_toolpaths( to_infill = offset_ex(to_infill, - 0.4 * float(flow.scaled_spacing())); extrusion_entities_append_paths( base_layer.extrusions, - to_polylines(STDMOVE(to_infill_polygons)), + to_polylines(std::move(to_infill_polygons)), erSupportMaterial, flow.mm3_per_mm(), flow.width, flow.height); } fill_expolygons_generate_paths( // Destination base_layer.extrusions, // Regions to fill - STDMOVE(to_infill), + std::move(to_infill), // Filler and its parameters filler, density, // Extrusion parameters diff --git a/src/libslic3r/libslic3r.h b/src/libslic3r/libslic3r.h index a2ee3fc9f..f8088faea 100644 --- a/src/libslic3r/libslic3r.h +++ b/src/libslic3r/libslic3r.h @@ -47,19 +47,6 @@ typedef double coordf_t; #define scale_(val) ((val) / SCALING_FACTOR) #define SCALED_EPSILON scale_(EPSILON) -// Which C++ version is supported? -// For example, could optimized functions with move semantics be used? -#if __cplusplus==201402L - #define SLIC3R_CPPVER 14 - #define STDMOVE(WHAT) std::move(WHAT) -#elif __cplusplus==201103L - #define SLIC3R_CPPVER 11 - #define STDMOVE(WHAT) std::move(WHAT) -#else - #define SLIC3R_CPPVER 0 - #define STDMOVE(WHAT) (WHAT) -#endif - #define SLIC3R_DEBUG_OUT_PATH_PREFIX "out/" inline std::string debug_out_path(const char *name, ...) diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp index 8e810fcda..a61713aac 100644 --- a/src/slic3r/GUI/OptionsGroup.cpp +++ b/src/slic3r/GUI/OptionsGroup.cpp @@ -22,18 +22,18 @@ const t_field& OptionsGroup::build_field(const t_config_option_key& id, const Co // is the normal type. if (opt.gui_type.compare("select") == 0) { } else if (opt.gui_type.compare("select_open") == 0) { - m_fields.emplace(id, STDMOVE(Choice::Create(parent(), opt, id))); + m_fields.emplace(id, std::move(Choice::Create(parent(), opt, id))); } else if (opt.gui_type.compare("color") == 0) { - m_fields.emplace(id, STDMOVE(ColourPicker::Create(parent(), opt, id))); + m_fields.emplace(id, std::move(ColourPicker::Create(parent(), opt, id))); } else if (opt.gui_type.compare("f_enum_open") == 0 || opt.gui_type.compare("i_enum_open") == 0 || opt.gui_type.compare("i_enum_closed") == 0) { - m_fields.emplace(id, STDMOVE(Choice::Create(parent(), opt, id))); + m_fields.emplace(id, std::move(Choice::Create(parent(), opt, id))); } else if (opt.gui_type.compare("slider") == 0) { - m_fields.emplace(id, STDMOVE(SliderCtrl::Create(parent(), opt, id))); + m_fields.emplace(id, std::move(SliderCtrl::Create(parent(), opt, id))); } else if (opt.gui_type.compare("i_spin") == 0) { // Spinctrl } else if (opt.gui_type.compare("legend") == 0) { // StaticText - m_fields.emplace(id, STDMOVE(StaticText::Create(parent(), opt, id))); + m_fields.emplace(id, std::move(StaticText::Create(parent(), opt, id))); } else { switch (opt.type) { case coFloatOrPercent: @@ -43,21 +43,21 @@ const t_field& OptionsGroup::build_field(const t_config_option_key& id, const Co case coPercents: case coString: case coStrings: - m_fields.emplace(id, STDMOVE(TextCtrl::Create(parent(), opt, id))); + m_fields.emplace(id, std::move(TextCtrl::Create(parent(), opt, id))); break; case coBool: case coBools: - m_fields.emplace(id, STDMOVE(CheckBox::Create(parent(), opt, id))); + m_fields.emplace(id, std::move(CheckBox::Create(parent(), opt, id))); break; case coInt: case coInts: - m_fields.emplace(id, STDMOVE(SpinCtrl::Create(parent(), opt, id))); + m_fields.emplace(id, std::move(SpinCtrl::Create(parent(), opt, id))); break; case coEnum: - m_fields.emplace(id, STDMOVE(Choice::Create(parent(), opt, id))); + m_fields.emplace(id, std::move(Choice::Create(parent(), opt, id))); break; case coPoints: - m_fields.emplace(id, STDMOVE(PointCtrl::Create(parent(), opt, id))); + m_fields.emplace(id, std::move(PointCtrl::Create(parent(), opt, id))); break; case coNone: break; default: From edceb80b1805487c7d8e0fd59687ded7ad4f42c0 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Sat, 3 Nov 2018 08:46:51 +0100 Subject: [PATCH 10/43] Updated function names in GLCanvas3D.cpp (mismatch caused by two conflicting commits yesterday) --- src/slic3r/GUI/GLCanvas3D.cpp | 12 +++++------- src/slic3r/GUI/GLCanvas3D.hpp | 3 ++- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index a09e33b68..0009f9e7a 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1396,9 +1396,7 @@ int GLCanvas3D::Selection::get_instance_idx() const const GLCanvas3D::Selection::InstanceIdxsList& GLCanvas3D::Selection::get_instance_idxs() const { - if (m_cache.content.size() != 1) - throw std::runtime_error("get_instance_idxs() called for multiple object selection."); - + assert(m_cache.content.size() == 1); return m_cache.content.begin()->second; } @@ -1502,10 +1500,10 @@ void GLCanvas3D::Selection::flattening_rotate(const Vec3d& normal) for (unsigned int i : m_list) { - Vec3d scaling_factor = m_cache.volumes_data[i].get_scaling_factor(); + Vec3d scaling_factor = m_cache.volumes_data[i].get_volume_scaling_factor(); scaling_factor = Vec3d(1./scaling_factor(0), 1./scaling_factor(1), 1./scaling_factor(2)); - Vec3d transformed_normal = Geometry::assemble_transform(Vec3d::Zero(), m_cache.volumes_data[i].get_rotation(), scaling_factor) * normal; + Vec3d transformed_normal = Geometry::assemble_transform(Vec3d::Zero(), m_cache.volumes_data[i].get_volume_rotation(), scaling_factor) * normal; transformed_normal.normalize(); Vec3d axis = transformed_normal(2) > 0.999f ? Vec3d(1., 0., 0.) : Vec3d(transformed_normal.cross(Vec3d(0., 0., -1.))); @@ -1514,8 +1512,8 @@ void GLCanvas3D::Selection::flattening_rotate(const Vec3d& normal) Transform3d extra_rotation = Transform3d::Identity(); extra_rotation.rotate(Eigen::AngleAxisd(acos(-transformed_normal(2)), axis)); - Vec3d new_rotation = Geometry::extract_euler_angles(extra_rotation * m_cache.volumes_data[i].get_rotation_matrix() ); - (*m_volumes)[i]->set_rotation(new_rotation); + Vec3d new_rotation = Geometry::extract_euler_angles(extra_rotation * m_cache.volumes_data[i].get_volume_rotation_matrix() ); + (*m_volumes)[i]->set_volume_rotation(new_rotation); } m_bounding_box_dirty = true; } diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index fdbb67011..7318d00c9 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -496,7 +496,8 @@ public: int get_object_idx() const; // Returns the instance id if the selection is from a single object and from a single instance, otherwise is -1 int get_instance_idx() const; - // Returns the indices of selected instances if the selection is from a single object, throws otherwise! + // Returns the indices of selected instances. + // Can only be called if selection is from a single object. const InstanceIdxsList& get_instance_idxs() const; const IndicesList& get_volume_idxs() const { return m_list; } From fb6a08cfb0cf8a2599279efeaecc2f73bb6f4158 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 5 Nov 2018 08:31:54 +0100 Subject: [PATCH 11/43] Rotate of ModelVolume as transformation component (without modifying the mesh) --- src/libslic3r/Model.cpp | 39 +++++++++++++++++++++++++++++++++------ src/libslic3r/Model.hpp | 6 ++++-- 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 36403b8de..e86e09463 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -864,31 +864,33 @@ void ModelObject::scale(const Vec3d &versor) this->invalidate_bounding_box(); } -void ModelObject::rotate(float angle, const Axis& axis) +void ModelObject::rotate(double angle, Axis axis) { for (ModelVolume *v : this->volumes) { - v->mesh.rotate(angle, axis); - v->m_convex_hull.rotate(angle, axis); + v->rotate(angle, axis); } center_around_origin(); +#if !ENABLE_MODELVOLUME_TRANSFORM this->origin_translation = Vec3d::Zero(); +#endif // !ENABLE_MODELVOLUME_TRANSFORM this->invalidate_bounding_box(); } -void ModelObject::rotate(float angle, const Vec3d& axis) +void ModelObject::rotate(double angle, const Vec3d& axis) { for (ModelVolume *v : this->volumes) { - v->mesh.rotate(angle, axis); - v->m_convex_hull.rotate(angle, axis); + v->rotate(angle, axis); } center_around_origin(); +#if !ENABLE_MODELVOLUME_TRANSFORM this->origin_translation = Vec3d::Zero(); +#endif // !ENABLE_MODELVOLUME_TRANSFORM this->invalidate_bounding_box(); } @@ -1249,6 +1251,31 @@ void ModelVolume::scale(const Vec3d& scaling_factors) #endif // ENABLE_MODELVOLUME_TRANSFORM } +void ModelVolume::rotate(double angle, Axis axis) +{ +#if ENABLE_MODELVOLUME_TRANSFORM + switch (axis) + { + case X: { rotate(angle, Vec3d::UnitX()); break; } + case Y: { rotate(angle, Vec3d::UnitY()); break; } + case Z: { rotate(angle, Vec3d::UnitZ()); break; } + } +#else + mesh.rotate(angle, axis); + m_convex_hull.rotate(angle, axis); +#endif // ENABLE_MODELVOLUME_TRANSFORM +} + +void ModelVolume::rotate(double angle, const Vec3d& axis) +{ +#if ENABLE_MODELVOLUME_TRANSFORM + m_transformation.set_rotation(m_transformation.get_rotation() + Geometry::extract_euler_angles(Eigen::Quaterniond(Eigen::AngleAxisd(angle, axis)).toRotationMatrix())); +#else + mesh.rotate(angle, axis); + m_convex_hull.rotate(angle, axis); +#endif // ENABLE_MODELVOLUME_TRANSFORM +} + #if !ENABLE_MODELVOLUME_TRANSFORM void ModelInstance::set_rotation(const Vec3d& rotation) { diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 828dfc817..c420c5ead 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -231,8 +231,8 @@ public: void scale(const Vec3d &versor); void scale(const double s) { this->scale(Vec3d(s, s, s)); } void scale(double x, double y, double z) { this->scale(Vec3d(x, y, z)); } - void rotate(float angle, const Axis &axis); - void rotate(float angle, const Vec3d& axis); + void rotate(double angle, Axis axis); + void rotate(double angle, const Vec3d& axis); void mirror(const Axis &axis); size_t materials_count() const; size_t facets_count() const; @@ -319,6 +319,8 @@ public: void scale(const Vec3d& scaling_factors); void scale(double x, double y, double z) { scale(Vec3d(x, y, z)); } void scale(double s) { scale(Vec3d(s, s, s)); } + void rotate(double angle, Axis axis); + void rotate(double angle, const Vec3d& axis); ModelMaterial* assign_unique_material(); From 864bc6ad485481a4dd45ca98d528fe5538c17e9b Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 5 Nov 2018 08:51:00 +0100 Subject: [PATCH 12/43] Mirror of ModelVolume as transformation component (without modifying the mesh) --- src/libslic3r/Model.cpp | 24 +++++++++++++++++++++--- src/libslic3r/Model.hpp | 3 ++- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index e86e09463..c42691395 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -894,15 +894,16 @@ void ModelObject::rotate(double angle, const Vec3d& axis) this->invalidate_bounding_box(); } -void ModelObject::mirror(const Axis &axis) +void ModelObject::mirror(Axis axis) { for (ModelVolume *v : this->volumes) { - v->mesh.mirror(axis); - v->m_convex_hull.mirror(axis); + v->mirror(axis); } +#if !ENABLE_MODELVOLUME_TRANSFORM this->origin_translation = Vec3d::Zero(); +#endif // !ENABLE_MODELVOLUME_TRANSFORM this->invalidate_bounding_box(); } @@ -1276,6 +1277,23 @@ void ModelVolume::rotate(double angle, const Vec3d& axis) #endif // ENABLE_MODELVOLUME_TRANSFORM } +void ModelVolume::mirror(Axis axis) +{ +#if ENABLE_MODELVOLUME_TRANSFORM + Vec3d mirror = m_transformation.get_mirror(); + switch (axis) + { + case X: { mirror(0) *= -1.0; break; } + case Y: { mirror(1) *= -1.0; break; } + case Z: { mirror(2) *= -1.0; break; } + } + m_transformation.set_mirror(mirror); +#else + mesh.mirror(axis); + m_convex_hull.mirror(axis); +#endif // ENABLE_MODELVOLUME_TRANSFORM +} + #if !ENABLE_MODELVOLUME_TRANSFORM void ModelInstance::set_rotation(const Vec3d& rotation) { diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index c420c5ead..a3aeab739 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -233,7 +233,7 @@ public: void scale(double x, double y, double z) { this->scale(Vec3d(x, y, z)); } void rotate(double angle, Axis axis); void rotate(double angle, const Vec3d& axis); - void mirror(const Axis &axis); + void mirror(Axis axis); size_t materials_count() const; size_t facets_count() const; bool needed_repair() const; @@ -321,6 +321,7 @@ public: void scale(double s) { scale(Vec3d(s, s, s)); } void rotate(double angle, Axis axis); void rotate(double angle, const Vec3d& axis); + void mirror(Axis axis); ModelMaterial* assign_unique_material(); From a9e7b5c645ced9974477aa976a792f6b010d93a1 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Fri, 2 Nov 2018 12:35:26 +0100 Subject: [PATCH 13/43] Implemented adding of support enforcer/blocker to the object list --- resources/icons/support_blocker_.png | Bin 0 -> 1955 bytes resources/icons/support_enforcer_.png | Bin 0 -> 1744 bytes src/slic3r/GUI/GUI_ObjectList.cpp | 142 ++++++++++---------------- src/slic3r/GUI/GUI_ObjectList.hpp | 9 +- 4 files changed, 58 insertions(+), 93 deletions(-) create mode 100644 resources/icons/support_blocker_.png create mode 100644 resources/icons/support_enforcer_.png diff --git a/resources/icons/support_blocker_.png b/resources/icons/support_blocker_.png new file mode 100644 index 0000000000000000000000000000000000000000..0873c5e6edbf7cb9232723e54f43202eacfa208f GIT binary patch literal 1955 zcmV;U2VD4xP) zaB^>EX>4U6ba`-PAZ2)IW&i+q+O1b>vg{}b{_iSg2_ho89G_LQgIWHdF(#cypL3@s zsg48@kPk4e>OX%s^_N@*tX7uTyWpIb%LW@v6vFH6+D6cJJm-tvi4VS76Gm7lBW|y* zPWdQ&Iu@{<{Pf9JoTnZ?744d*LhP1}5L3=iMQAoY%y$*$x@b?^nZHnm^BShm_1&@r zqmbxBqfA9WEl=02pm=~DqdY;L!ZCW%R%XZZId*E1m*6ex5<49yA3sB(w3`C%5~Iln zdXC+Q&;_;K^2dZF&H8+uV%J*nt<`OJ(K?BgQ*%@MRt6=4NmSuj=HzDikv{vyJ6VN;KgzQku)I6Kvvvt^~C%y_fphaPh9}*SFFS@)3Zk0=*ab_NC_a&W=v_s zciiffH~IuD3W7Ak>}7*dr%gp7IC2XI&M0!Et=f`a1DB~lLL|0HoRN&SpdBEA1I@-T zfW*-YK2bb3XiX9XfXEb3O|U_90**J`wya?ovWCpYmewLb5ISUmCSVk>tR=}Gwq9~5 z5|UL!m9N(OXa6dG_81AA<=fEsTN-tbz|A#3)9i zsE)EaibRabBuq9@a*2~qA;m1|lWnH#GH0Jdj>Qx#QvSsiR>hZ4VudQHRBff|Dpy}a zjZJc`VY7{zYutPbEiTk1s-LLA1-b92!9=YiW``Ufs0o{SR{_19P{&LVGZqAK?g&Ui zn~s_GV6ExMb z+TqIv5Al%SO$}vgr!6mb^0!5HH)Zy8gfijhkUF6{3N`cO!Y@ZIxM!_=@@?=Bc5D6n zV@`Np;vB9T&a<>9B|}lmL0Ac6_w1EM-j?XqXEY3qZA(u*oEAra?dI~RI9%*f zu99)(dQIWJ31O=15}#M8(Y;{SrkgoJL7l5UCC}4-agpCjw#3y&X8C>Wxb7sGpEGnO znVLD6-*ZrAVUe!Bs8$cze>eYHL&s`$vHjh%lj?T!sOY#FLtHH=?98}Ax25r0o~p;{ z`E`-F1&fM@xAXvsKb&;e##hT~a?Y!JKr!>vSr_yoAK=VYa6f%JVE(( zw5f-5J<1jy%QqbXq$Q}Xkqmq7;&L0qsi(eWm-?{)4zB#!nYwwEecats(v{vSa-EHM zKSH7UegDpvy=OO~C(&iit+Tr_-vczd)z%?(yPgeu(9m6gwjUoe!pLr&YkA>bR}|#4 z;RskeqO>nB*CR{mtA*neq!sypul@xy?dD(!K=$4M000JJOGiWi{{a60|De66lK=n! z32;bRa{vGmbN~PnbOGLGA9w%&00(qQO+^Rd3jzu%EE=WEt^fc6SxH1eR5;6Rl1)og zVHC%I=gtkYL?WX^+_acg>Lz!&((#2$+q;nw6fZbiKZ2jY?Nw$razX49$cSJ;RCr;c zA)$oqg|cj6G+NCtcm6G!8-w+Shv)py^PKl%k}8sJ05vn~0utc6q+Z8yvOr7H6EnL9 zAn8QX5%9sxPF zRBm4|eh6gD?7o?etgNg6U}oJw4LCv4fu#5Od|rS6RjbuUshl23?<5@nnwy(TdF%q$ z&Foe?V%5xshlYk4i;Ig~z*pc3z{bYLiInVuI=EX*|yx1_**+;-YmB z1a|>9<;`Xj+6ot7YisLqrBb;!Ffc%|SR@QX;y4CiY;27A`FVmMNE_UpI&y(Jfa|)~ zq9_6&iXsYy0#Ou^&*uSHTU!I5UE0r12S3~Ow^HTa-X3RXXA}wr0G5}Rsnu$o6{Q)} zos^ha()lAb23TEPz1Whj_TA@n%=|o+$H&J3*xcMC3_}1$M@RV&&K#h(O`P@h^;ZD1 zv$O2)@3XtROB~09VfZ(rQmNGH^xy)Q9LJ%jr^l()YATgV|AdL-m>>w~d~=*X$(y7q z(B*kvHc1l7X*W_PBhrpRP6_`c7=!onvcZAv<-*Xz$EeFl`v<>dRm zB)taY`@V9yoB)-}<$9yhI82h{siX%kaMEhEp17_%oFvJ|BuTy;A0Kz`?CfNhmX@*r pp64++IZ1zi|C{#STm|}o!QZ~gDUfRO66XK_002ovPDHLkV1fx3v84b2 literal 0 HcmV?d00001 diff --git a/resources/icons/support_enforcer_.png b/resources/icons/support_enforcer_.png new file mode 100644 index 0000000000000000000000000000000000000000..265cebcb953919dcd947496a4cd36d4683012ee8 GIT binary patch literal 1744 zcmV;>1~2)EP) zaB^>EX>4U6ba`-PAZ2)IW&i+q+O1b>7V{_w{m&|92?52&a!k~7W(TwUxmxpV()OD( z@iY=ZAY84#-AYd8H=Jn{x z&`;p&zQEhTpU-^q%diuMq1Ey*XqsmMG4#SPWaP!?@l0{7OZM%ee&V5YeYPIS z$O?N#NQz-I;qICjg9uD833tXF9BG^hv>M;}?ml<4k(cCc)FpRQ8hmq31x;=!xJ!-( zpY=X>Jwq4NR?jDa^5m!Eb;w<78glIpEdauGYVeg^{C{Hw_d&T-UlCj3MSZ~!37^eh#^IZ1}#jZi=JYLF{T8k z38oWPCupQJ%WP&l>+EJfhdIt^LHR6p(Zwx(2}@j3mTWS%e|FhZ4msvjxS*7ZEm~ah zC6riFMXgm+ZPn_kuc5}8Hq-{HXVmzD+-KBypw~`cn;znx!2se2`jv93T2XfS) z8_2!mc7s|@{X{VxptcKJPA5~**r1doq;?+lDYdidHR}*emw8jHXnZe{wncTWWfxyf z9;EhawVR@Yvde6>9eA-#I7MYJS^?^iJssHXA9+An94X)?du8dh}~NC&LH%*$}UQ<7>$e zl2=x)7l01cwHF-S*WrOH&sBPy>9XvtC=W3rwt5M73wxpCE7W~4KQBH>%Sw{xyeS0! z#rM4v`bF)R2x$#*&54E`V)Ln{E~P+^iahTg^?Q_`UahQfY1+NZU6iQ9VaWVeOK#ua zoX^{z&fA{f+tXQ^R?-~`wcHit+865mwt7q?oimA!e4ERS|Cr1d{2K2uzxv&F?RzTe z$6S6*C7s1uLr_Cx4?xA510gmjLzPI2ZAI!UT@*DN-DKUBg(_|TLjFW|{(?e5w_;Wn+O1g#uG>Y> zKafS}LM%iSnnfsvLWG9*-f`i3;Tb9(80OxYd(S<0=F0Y4+nc~p5+#PVn<0cYfbEW? zHjvux+8zQ|lKQg!swfI@mm()HuIOqUK8UqvHF1FvgTdf0{|}eXY`)f#45 z)~S@_dENoO0eS6Bc7WvojH^IN`=!~Glx11=0U(3`unYtiFh7_~CY@fdSGnU5!krl7 z5B`HWL6Rit*4EZhsb~fWn3mTmFer-R!9NLXQ=0?wJnz-wn!v>N=MA6* zTvmex+?RA!Dok%x09@4x7f~xPM^gKR8%eWT@EWjIx)*t#KLftr*1{&h($dm+I-S0# zB*qw3BOk>W`$>}QFXXQ#z`5_4Vu8)IJO$T>b`QSLC<~(D)qy0000 menu_items = { L("Add part"), L("Add modifier"), L("Add generic") }; + std::vector menu_object_types_items = {L("Add part"), + L("Add modifier"), + L("Add support enforcer"), + L("Add support bloker"), + L("Add generic") }; + const int obj_types_count = menu_object_types_items.size(); + const int generics_count = 4; - wxWindowID config_id_base = wxWindow::NewControlId(menu_items.size() + 4 + 2); + wxWindowID config_id_base = wxWindow::NewControlId(menu_object_types_items.size() + 4 + 2); + // Add first 4 menu items int i = 0; - for (auto& item : menu_items) { + for (i = 0; i < obj_types_count - 1; i++) { + auto& item = menu_object_types_items[i]; auto menu_item = new wxMenuItem(menu, config_id_base + i, _(item)); - menu_item->SetBitmap(i == 0 ? m_bmp_solidmesh : m_bmp_modifiermesh); - if (item == "Add generic") - menu_item_add_generic(menu_item, config_id_base + i); + menu_item->SetBitmap(*m_bmp_vector[i]); menu->Append(menu_item); - i++; } + // Add generic modifier + auto& item = menu_object_types_items[i]; + auto menu_item = new wxMenuItem(menu, config_id_base + i, _(item)); + menu_item->SetBitmap(*m_bmp_vector[1]); // set modifier's icon + menu_item_add_generic(menu_item, config_id_base + i); + menu->Append(menu_item); + // Split object to parts menu->AppendSeparator(); - auto menu_item = menu_item_split(menu, config_id_base + i + 4); + menu_item = menu_item_split(menu, config_id_base + obj_types_count + generics_count); menu->Append(menu_item); menu_item->Enable(is_splittable_object(false)); + // Settings menu->AppendSeparator(); // Append settings popupmenu - menu->Append(menu_item_settings(menu, config_id_base + i + 5, false)); + menu->Append(menu_item_settings(menu, config_id_base + obj_types_count + generics_count+1, false)); menu->Bind(wxEVT_MENU, [config_id_base, menu, this](wxEvent &event) { switch (event.GetId() - config_id_base) { - case 0: - load_subobject(); + case 0: // ~ModelVolume::MODEL_PART + case 1: // ~ModelVolume::PARAMETER_MODIFIER + case 2: // ~ModelVolume::SUPPORT_ENFORCER + case 3: // ~ModelVolume::SUPPORT_BLOCKER + load_subobject(event.GetId() - config_id_base); break; - case 1: - load_subobject(true); - break; - case 2: - case 3: case 4: case 5: case 6: + case 7: + case 8: #ifdef __WXMSW__ load_lambda(menu->GetLabel(event.GetId()).ToStdString()); #endif // __WXMSW__ break; - case 7: //3: + case 9: split(false); break; default: @@ -655,31 +677,21 @@ wxMenu* ObjectList::create_add_settings_popupmenu(bool is_part) return menu; } - -// Load SubObjects (parts and modifiers) -void ObjectList::load_subobject(bool is_modifier /*= false*/, bool is_lambda/* = false*/) +void ObjectList::load_subobject(int type) { auto item = GetSelection(); - if (!item) - return; - int obj_idx = -1; - if (m_objects_model->GetParent(item) == wxDataViewItem(0)) - obj_idx = m_objects_model->GetIdByItem(item); - else + if (!item || m_objects_model->GetParent(item) != wxDataViewItem(0)) return; + int obj_idx = m_objects_model->GetIdByItem(item); if (obj_idx < 0) return; wxArrayString part_names; - if (is_lambda) - load_lambda((*m_objects)[obj_idx], part_names, is_modifier); - else - load_part((*m_objects)[obj_idx], part_names, is_modifier); + load_part((*m_objects)[obj_idx], part_names, type); parts_changed(obj_idx); for (int i = 0; i < part_names.size(); ++i) { - const wxDataViewItem sel_item = m_objects_model->AddVolumeChild(item, part_names.Item(i), - is_modifier ? m_bmp_modifiermesh : m_bmp_solidmesh); + const wxDataViewItem sel_item = m_objects_model->AddVolumeChild(item, part_names.Item(i), *m_bmp_vector[type]); if (i == part_names.size() - 1) select_item(sel_item); @@ -688,11 +700,12 @@ void ObjectList::load_subobject(bool is_modifier /*= false*/, bool is_lambda/* = #ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME // selection_changed(); #endif //no __WXOSX__//__WXMSW__ + } void ObjectList::load_part( ModelObject* model_object, wxArrayString& part_names, - const bool is_modifier) + int type) { wxWindow* parent = wxGetApp().tab_panel()->GetPage(0); @@ -722,7 +735,7 @@ void ObjectList::load_part( ModelObject* model_object, } for (auto volume : object->volumes) { auto new_volume = model_object->add_volume(*volume); - new_volume->set_type(is_modifier ? ModelVolume::PARAMETER_MODIFIER : ModelVolume::MODEL_PART); + new_volume->set_type(static_cast(type)); boost::filesystem::path(input_file).filename().string(); new_volume->name = boost::filesystem::path(input_file).filename().string(); @@ -738,58 +751,7 @@ void ObjectList::load_part( ModelObject* model_object, } } } -} -void ObjectList::load_lambda( ModelObject* model_object, - wxArrayString& part_names, - const bool is_modifier) -{ - auto dlg = new LambdaObjectDialog(GetMainWindow()); - if (dlg->ShowModal() == wxID_CANCEL) { - m_parts_changed = false; - return; - } - - std::string name = "lambda-"; - TriangleMesh mesh; - - auto params = dlg->ObjectParameters(); - switch (params.type) - { - case LambdaTypeBox:{ - mesh = make_cube(params.dim[0], params.dim[1], params.dim[2]); - name += "Box"; - break; } - case LambdaTypeCylinder:{ - mesh = make_cylinder(params.cyl_r, params.cyl_h); - name += "Cylinder"; - break; } - case LambdaTypeSphere:{ - mesh = make_sphere(params.sph_rho); - name += "Sphere"; - break; } - case LambdaTypeSlab:{ - const auto& size = model_object->bounding_box().size(); - mesh = make_cube(size(0)*1.5, size(1)*1.5, params.slab_h); - // box sets the base coordinate at 0, 0, move to center of plate and move it up to initial_z - mesh.translate(-size(0)*1.5 / 2.0, -size(1)*1.5 / 2.0, params.slab_z); - name += "Slab"; - break; } - default: - break; - } - mesh.repair(); - - auto new_volume = model_object->add_volume(mesh); - new_volume->set_type(is_modifier ? ModelVolume::PARAMETER_MODIFIER : ModelVolume::MODEL_PART); - - new_volume->name = name; - // set a default extruder value, since user can't add it manually - new_volume->config.set_key_value("extruder", new ConfigOptionInt(0)); - - part_names.Add(name); - - m_parts_changed = true; } void ObjectList::load_lambda(const std::string& type_name) diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp index 3a7de9e3b..63bf3efd0 100644 --- a/src/slic3r/GUI/GUI_ObjectList.hpp +++ b/src/slic3r/GUI/GUI_ObjectList.hpp @@ -28,10 +28,14 @@ class ObjectList : public wxDataViewCtrl wxBitmap m_bmp_modifiermesh; wxBitmap m_bmp_solidmesh; + wxBitmap m_bmp_support_enforcer; + wxBitmap m_bmp_support_blocker; wxBitmap m_bmp_manifold_warning; wxBitmap m_bmp_cog; wxBitmap m_bmp_split; + std::vector m_bmp_vector; + int m_selected_object_id = -1; bool m_prevent_list_events = false; // We use this flag to avoid circular event handling Select() // happens to fire a wxEVT_LIST_ITEM_SELECTED on OSX, whose event handler @@ -85,9 +89,8 @@ public: wxMenu* create_part_settings_popupmenu(); wxMenu* create_add_settings_popupmenu(bool is_part); - void load_subobject(bool is_modifier = false, bool is_lambda = false); - void load_part(ModelObject* model_object, wxArrayString& part_names, const bool is_modifier); - void load_lambda(ModelObject* model_object, wxArrayString& part_names, const bool is_modifier); + void load_subobject(int type); + void load_part(ModelObject* model_object, wxArrayString& part_names, int type); void load_lambda(const std::string& type_name); void del_subobject_item(wxDataViewItem& item); void del_settings_from_config(); From 4eae6c0189c71e67a8bbeb1b2f6e4e6192a3fa2b Mon Sep 17 00:00:00 2001 From: YuSanka Date: Fri, 2 Nov 2018 23:27:31 +0100 Subject: [PATCH 14/43] Changing of a type of a volume in the object list --- src/slic3r/GUI/GUI_ObjectList.cpp | 76 ++++++++++++++++++++++++------- src/slic3r/GUI/GUI_ObjectList.hpp | 3 ++ src/slic3r/GUI/wxExtensions.cpp | 33 +++++++++++--- src/slic3r/GUI/wxExtensions.hpp | 9 +++- 4 files changed, 96 insertions(+), 25 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 082a9f66d..6bb7d2785 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -36,11 +36,11 @@ ObjectList::ObjectList(wxWindow* parent) : CATEGORY_ICON[L("Advanced")] = wxBitmap(from_u8(var("wand.png")), wxBITMAP_TYPE_PNG); } - init_icons(); - // create control create_objects_ctrl(); + init_icons(); + // describe control behavior Bind(wxEVT_DATAVIEW_SELECTION_CHANGED, [this](wxEvent& event) { selection_changed(); @@ -224,6 +224,7 @@ void ObjectList::init_icons() m_bmp_vector.push_back(&m_bmp_modifiermesh); // Add modifier m_bmp_vector.push_back(&m_bmp_support_enforcer); // Add support enforcer m_bmp_vector.push_back(&m_bmp_support_blocker); // Add support blocker + m_objects_model->SetVolumeBitmaps(m_bmp_vector); // init icon for manifold warning m_bmp_manifold_warning = wxBitmap(from_u8(var("exclamation_mark_.png")), wxBITMAP_TYPE_PNG);//(Slic3r::var("error.png")), wxBITMAP_TYPE_PNG); @@ -569,10 +570,10 @@ wxMenu* ObjectList::create_add_part_popupmenu() const int obj_types_count = menu_object_types_items.size(); const int generics_count = 4; - wxWindowID config_id_base = wxWindow::NewControlId(menu_object_types_items.size() + 4 + 2); + wxWindowID config_id_base = NewControlId(menu_object_types_items.size() + 4 + 2); // Add first 4 menu items - int i = 0; + int i; for (i = 0; i < obj_types_count - 1; i++) { auto& item = menu_object_types_items[i]; auto menu_item = new wxMenuItem(menu, config_id_base + i, _(item)); @@ -631,24 +632,33 @@ wxMenu* ObjectList::create_add_part_popupmenu() wxMenu* ObjectList::create_part_settings_popupmenu() { wxMenu *menu = new wxMenu; - wxWindowID config_id_base = wxWindow::NewControlId(2); + wxWindowID config_id_base = NewControlId(3); auto menu_item = menu_item_split(menu, config_id_base); menu->Append(menu_item); menu_item->Enable(is_splittable_object(true)); + // Append change part type menu->AppendSeparator(); + menu->Append(new wxMenuItem(menu, config_id_base + 1, _(L("Change type")))); + // Append settings popupmenu - menu->Append(menu_item_settings(menu, config_id_base + 1, true)); + menu->AppendSeparator(); + menu_item = menu_item_settings(menu, config_id_base + 2, true); + menu->Append(menu_item); + menu_item->Enable(get_selected_model_volume()->type() <= ModelVolume::PARAMETER_MODIFIER); menu->Bind(wxEVT_MENU, [config_id_base, menu, this](wxEvent &event) { switch (event.GetId() - config_id_base) { case 0: split(true); break; - default:{ + case 1: + change_part_type(); + break; + default: get_settings_choice(menu, event.GetId(), true); - break; } + break; } }); @@ -691,7 +701,7 @@ void ObjectList::load_subobject(int type) parts_changed(obj_idx); for (int i = 0; i < part_names.size(); ++i) { - const wxDataViewItem sel_item = m_objects_model->AddVolumeChild(item, part_names.Item(i), *m_bmp_vector[type]); + const wxDataViewItem sel_item = m_objects_model->AddVolumeChild(item, part_names.Item(i), /**m_bmp_vector[*/type/*]*/); if (i == part_names.size() - 1) select_item(sel_item); @@ -790,8 +800,7 @@ void ObjectList::load_lambda(const std::string& type_name) m_parts_changed = true; parts_changed(m_selected_object_id); - select_item(m_objects_model->AddVolumeChild(GetSelection(), - name, m_bmp_modifiermesh)); + select_item(m_objects_model->AddVolumeChild(GetSelection(), name, ModelVolume::PARAMETER_MODIFIER/*m_bmp_modifiermesh*/)); #ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME selection_changed(); #endif //no __WXOSX__ //__WXMSW__ @@ -908,7 +917,7 @@ void ObjectList::split(const bool split_part) for (auto id = 0; id < model_object->volumes.size(); id++) m_objects_model->AddVolumeChild(parent, model_object->volumes[id]->name, - model_object->volumes[id]->is_modifier() ? m_bmp_modifiermesh : m_bmp_solidmesh, + model_object->volumes[id]->is_modifier() ? ModelVolume::PARAMETER_MODIFIER : ModelVolume::MODEL_PART, model_object->volumes[id]->config.has("extruder") ? model_object->volumes[id]->config.option("extruder")->value : 0, false); @@ -918,7 +927,7 @@ void ObjectList::split(const bool split_part) else { for (auto id = 0; id < model_object->volumes.size(); id++) m_objects_model->AddVolumeChild(item, model_object->volumes[id]->name, - m_bmp_solidmesh, + ModelVolume::MODEL_PART, model_object->volumes[id]->config.has("extruder") ? model_object->volumes[id]->config.option("extruder")->value : 0, false); @@ -929,7 +938,7 @@ void ObjectList::split(const bool split_part) parts_changed(m_selected_object_id); // restores selection - _3DScene::get_canvas(wxGetApp().canvas3D())->get_selection().add_object(m_selected_object_id); +// _3DScene::get_canvas(wxGetApp().canvas3D())->get_selection().add_object(m_selected_object_id); } bool ObjectList::get_volume_by_item(const bool split_part, const wxDataViewItem& item, ModelVolume*& volume) @@ -979,7 +988,7 @@ void ObjectList::part_settings_changed() void ObjectList::parts_changed(int obj_idx) { - wxGetApp().plater()->changed_object(get_selected_obj_idx()); + wxGetApp().plater()->changed_object(obj_idx); m_parts_changed = false; } @@ -1071,7 +1080,7 @@ void ObjectList::add_object_to_list(size_t obj_idx) for (auto id = 0; id < model_object->volumes.size(); id++) m_objects_model->AddVolumeChild(item, model_object->volumes[id]->name, - m_bmp_solidmesh, + ModelVolume::MODEL_PART, model_object->volumes[id]->config.option("extruder")->value, false); Expand(item); @@ -1296,5 +1305,40 @@ void ObjectList::fix_multiselection_conflicts() m_prevent_list_events = false; } +ModelVolume* ObjectList::get_selected_model_volume() +{ + auto item = GetSelection(); + if (!item || m_objects_model->GetItemType(item) != itVolume) + return nullptr; + + const auto vol_idx = m_objects_model->GetVolumeIdByItem(item); + const auto obj_idx = get_selected_obj_idx(); + if (vol_idx < 0 || obj_idx < 0) + return nullptr; + + return (*m_objects)[obj_idx]->volumes[vol_idx]; +} + +void ObjectList::change_part_type() +{ + ModelVolume* volume = get_selected_model_volume(); + if (!volume) + return; + const auto type = volume->type(); + + const wxString names[] = { "Part", "Modifier", "Support Enforcer", "Support Blocker" }; + + auto new_type = wxGetSingleChoiceIndex("Type: ", _(L("Select type of part")), wxArrayString(4, names), type); + + if (new_type == type || new_type < 0) + return; + + volume->set_type(static_cast(new_type)); + m_objects_model->SetVolumeType(GetSelection(), new_type); + + m_parts_changed = true; + parts_changed(get_selected_obj_idx()); +} + } //namespace GUI } //namespace Slic3r \ No newline at end of file diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp index 63bf3efd0..ca9de5f76 100644 --- a/src/slic3r/GUI/GUI_ObjectList.hpp +++ b/src/slic3r/GUI/GUI_ObjectList.hpp @@ -145,6 +145,9 @@ public: void select_all(); // correct current selections to avoid of the possible conflicts void fix_multiselection_conflicts(); + + ModelVolume* get_selected_model_volume(); + void change_part_type(); }; diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 8d7498170..8d6a0408e 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -9,6 +9,7 @@ #include #include "GUI_App.hpp" #include "GUI_ObjectList.hpp" +#include "Model.hpp" wxMenuItem* append_menu_item(wxMenu* menu, int id, const wxString& string, const wxString& description, std::function cb, const std::string& icon, wxEvtHandler* event_handler) @@ -400,10 +401,9 @@ bool PrusaObjectDataViewModelNode::update_settings_digest(const std::vector& categories_icon = Slic3r::GUI::wxGetApp().obj_list()->CATEGORY_ICON;//Slic3r::GUI::get_category_icon(); + std::map& categories_icon = Slic3r::GUI::wxGetApp().obj_list()->CATEGORY_ICON; for (auto& cat : m_opt_categories) m_name += cat + "; "; @@ -453,19 +453,18 @@ wxDataViewItem PrusaObjectDataViewModel::Add(const wxString &name) wxDataViewItem PrusaObjectDataViewModel::AddVolumeChild(const wxDataViewItem &parent_item, const wxString &name, - const wxBitmap& icon, + const int volume_type, const int extruder/* = 0*/, const bool create_frst_child/* = true*/) { PrusaObjectDataViewModelNode *root = (PrusaObjectDataViewModelNode*)parent_item.GetID(); if (!root) return wxDataViewItem(0); - const wxString extruder_str = extruder == 0 ? "default" : wxString::Format("%d", extruder); + wxString extruder_str = extruder == 0 ? "default" : wxString::Format("%d", extruder); if (create_frst_child && root->m_volumes_cnt == 0) { - const auto bmp_solid_mesh = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("object.png")), wxBITMAP_TYPE_PNG); - const auto node = new PrusaObjectDataViewModelNode(root, root->m_name, bmp_solid_mesh, extruder_str, 0); + const auto node = new PrusaObjectDataViewModelNode(root, root->m_name, *m_volume_bmps[0], extruder_str, 0); root->Append(node); // notify control const wxDataViewItem child((void*)node); @@ -474,7 +473,10 @@ wxDataViewItem PrusaObjectDataViewModel::AddVolumeChild(const wxDataViewItem &pa root->m_volumes_cnt++; } - const auto node = new PrusaObjectDataViewModelNode(root, name, icon, extruder_str, root->m_volumes_cnt); +// if (volume_type >= Slic3r::ModelVolume::SUPPORT_ENFORCER) +// extruder_str = ""; + + const auto node = new PrusaObjectDataViewModelNode(root, name, *m_volume_bmps[volume_type], extruder_str, root->m_volumes_cnt); root->Append(node); // notify control const wxDataViewItem child((void*)node); @@ -563,6 +565,10 @@ wxDataViewItem PrusaObjectDataViewModel::Delete(const wxDataViewItem &item) auto id = node_parent->GetChildren().Index(node); auto idx = node->GetIdx(); node_parent->GetChildren().Remove(node); + + if (node->m_type == itVolume) + node_parent->m_volumes_cnt--; + if (id > 0) { if(id == node_parent->GetChildCount()) id--; ret_item = wxDataViewItem(node_parent->GetChildren().Item(id)); @@ -692,6 +698,9 @@ void PrusaObjectDataViewModel::DeleteChildren(wxDataViewItem& parent) auto item = wxDataViewItem(node); children.RemoveAt(id); + if (node->m_type == itVolume) + root->m_volumes_cnt--; + // free the node delete node; @@ -1050,6 +1059,16 @@ void PrusaObjectDataViewModel::UpdateSettingsDigest(const wxDataViewItem &item, ItemChanged(item); } +void PrusaObjectDataViewModel::SetVolumeType(const wxDataViewItem &item, const int type) +{ + if (!item.IsOk() || GetItemType(item) != itVolume) + return; + + PrusaObjectDataViewModelNode *node = (PrusaObjectDataViewModelNode*)item.GetID(); + node->SetBitmap(*m_volume_bmps[type]); + ItemChanged(item); +} + //----------------------------------------------------------------------------- // PrusaDataViewBitmapText //----------------------------------------------------------------------------- diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp index 60bc083fe..3c9159233 100644 --- a/src/slic3r/GUI/wxExtensions.hpp +++ b/src/slic3r/GUI/wxExtensions.hpp @@ -424,7 +424,9 @@ private: class PrusaObjectDataViewModel :public wxDataViewModel { - std::vector m_objects; + std::vector m_objects; + std::vector m_volume_bmps; + public: PrusaObjectDataViewModel(); ~PrusaObjectDataViewModel(); @@ -432,7 +434,7 @@ public: wxDataViewItem Add(const wxString &name); wxDataViewItem AddVolumeChild(const wxDataViewItem &parent_item, const wxString &name, - const wxBitmap& icon, + const int volume_type, const int extruder = 0, const bool create_frst_child = true); wxDataViewItem AddSettingsChild(const wxDataViewItem &parent_item); @@ -491,6 +493,9 @@ public: wxDataViewItem GetSettingsItem(const wxDataViewItem &item) const; bool IsSettingsItem(const wxDataViewItem &item) const; void UpdateSettingsDigest(const wxDataViewItem &item, const std::vector& categories); + + void SetVolumeBitmaps(const std::vector& volume_bmps) { m_volume_bmps = volume_bmps; } + void SetVolumeType(const wxDataViewItem &item, const int type); }; // ---------------------------------------------------------------------------- From be57bb5c0ebabd9bdd136230aa5a92eb8d7ab703 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Mon, 5 Nov 2018 08:55:44 +0100 Subject: [PATCH 15/43] Update showing of the settings after part type changing --- src/slic3r/GUI/GUI_ObjectList.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 6bb7d2785..da5095bb6 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -1333,11 +1333,24 @@ void ObjectList::change_part_type() if (new_type == type || new_type < 0) return; + const auto item = GetSelection(); volume->set_type(static_cast(new_type)); - m_objects_model->SetVolumeType(GetSelection(), new_type); + m_objects_model->SetVolumeType(item, new_type); m_parts_changed = true; parts_changed(get_selected_obj_idx()); + + // Update settings showing, if we have it + //(we show additional settings for Part and Modifier and hide it for Support Blocker/Enforcer) + const auto settings_item = m_objects_model->GetSettingsItem(item); + if (settings_item && + new_type == ModelVolume::SUPPORT_ENFORCER || new_type == ModelVolume::SUPPORT_BLOCKER) { + m_objects_model->Delete(settings_item); + } + else if (!settings_item && + new_type == ModelVolume::MODEL_PART || new_type == ModelVolume::PARAMETER_MODIFIER) { + select_item(m_objects_model->AddSettingsChild(item)); + } } } //namespace GUI From 9442cb99f4ffc0570e9f851738ae8c9bccf32759 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Mon, 5 Nov 2018 09:34:04 +0100 Subject: [PATCH 16/43] Flatten gizmo now correctly processes both instance and volume transformations --- src/slic3r/GUI/GLCanvas3D.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 0009f9e7a..7e1024813 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1500,10 +1500,11 @@ void GLCanvas3D::Selection::flattening_rotate(const Vec3d& normal) for (unsigned int i : m_list) { - Vec3d scaling_factor = m_cache.volumes_data[i].get_volume_scaling_factor(); - scaling_factor = Vec3d(1./scaling_factor(0), 1./scaling_factor(1), 1./scaling_factor(2)); + Transform3d wst = m_cache.volumes_data[i].get_instance_scale_matrix() * m_cache.volumes_data[i].get_volume_scale_matrix(); + Vec3d scaling_factor = Vec3d(1./wst(0,0), 1./wst(1,1), 1./wst(2,2)); - Vec3d transformed_normal = Geometry::assemble_transform(Vec3d::Zero(), m_cache.volumes_data[i].get_volume_rotation(), scaling_factor) * normal; + Vec3d rotation = Geometry::extract_euler_angles(m_cache.volumes_data[i].get_instance_rotation_matrix() * m_cache.volumes_data[i].get_volume_rotation_matrix()); + Vec3d transformed_normal = Geometry::assemble_transform(Vec3d::Zero(), rotation, scaling_factor) * normal; transformed_normal.normalize(); Vec3d axis = transformed_normal(2) > 0.999f ? Vec3d(1., 0., 0.) : Vec3d(transformed_normal.cross(Vec3d(0., 0., -1.))); @@ -1512,8 +1513,8 @@ void GLCanvas3D::Selection::flattening_rotate(const Vec3d& normal) Transform3d extra_rotation = Transform3d::Identity(); extra_rotation.rotate(Eigen::AngleAxisd(acos(-transformed_normal(2)), axis)); - Vec3d new_rotation = Geometry::extract_euler_angles(extra_rotation * m_cache.volumes_data[i].get_volume_rotation_matrix() ); - (*m_volumes)[i]->set_volume_rotation(new_rotation); + Vec3d new_rotation = Geometry::extract_euler_angles(extra_rotation * m_cache.volumes_data[i].get_instance_rotation_matrix() ); + (*m_volumes)[i]->set_instance_rotation(new_rotation); } m_bounding_box_dirty = true; } From 4b5657b16b6fe74b4a42c6ee6df03eec20eec0e8 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 5 Nov 2018 10:54:05 +0100 Subject: [PATCH 17/43] Fixed assert in GLCanvas3D::Selection::is_single_full_instance() --- src/slic3r/GUI/GLCanvas3D.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 7e1024813..1b6e06160 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1368,11 +1368,8 @@ bool GLCanvas3D::Selection::is_single_full_instance() const return true; int object_idx = m_valid ? get_object_idx() : -1; - if (object_idx != -1) - { - if ((object_idx != -1) && (object_idx < 1000)) - return m_model->objects[object_idx]->volumes.size() == m_list.size(); - } + if ((0 <= object_idx) && (object_idx < (int)m_model->objects.size())) + return m_model->objects[object_idx]->volumes.size() == m_list.size(); return false; } From e0b488fd119b50610a239bb7f8b60ebe9df36a40 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 5 Nov 2018 11:52:14 +0100 Subject: [PATCH 18/43] Fixed instances count after split to objects --- src/slic3r/GUI/Plater.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index e81a0caa7..25d5f26f5 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1478,10 +1478,6 @@ void Plater::priv::split_object() for (ModelObject* m : new_objects) { m->name = current_model_object->name + "_" + std::to_string(counter++); - for (ModelInstance* i : current_model_object->instances) - { - m->add_instance(*i); - } } remove(obj_idx); From 706da612b620fb6363b61c82be24d6af1903f597 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 5 Nov 2018 12:52:51 +0100 Subject: [PATCH 19/43] Fixed duplicate instances after "split object to objects" --- src/slic3r/GUI/Plater.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index e81a0caa7..dadeec4ec 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1476,13 +1476,7 @@ void Plater::priv::split_object() { unsigned int counter = 1; for (ModelObject* m : new_objects) - { m->name = current_model_object->name + "_" + std::to_string(counter++); - for (ModelInstance* i : current_model_object->instances) - { - m->add_instance(*i); - } - } remove(obj_idx); From 7ffa22191dfaf29e4489b2e602085697f18a9642 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 5 Nov 2018 17:52:55 +0100 Subject: [PATCH 20/43] Fixed some issues with front end / back end synchronization. --- src/libslic3r/Model.cpp | 16 ++++++---------- src/libslic3r/Model.hpp | 9 +++++---- src/libslic3r/PrintObject.cpp | 2 +- xs/xsp/Model.xsp | 2 -- 4 files changed, 12 insertions(+), 17 deletions(-) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index c42691395..9cd7846f3 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -254,6 +254,7 @@ void Model::clear_materials() ModelMaterial* Model::add_material(t_model_material_id material_id) { + assert(! material_id.empty()); ModelMaterial* material = this->get_material(material_id); if (material == nullptr) material = this->materials[material_id] = new ModelMaterial(this); @@ -262,6 +263,7 @@ ModelMaterial* Model::add_material(t_model_material_id material_id) ModelMaterial* Model::add_material(t_model_material_id material_id, const ModelMaterial &other) { + assert(! material_id.empty()); // delete existing material if any ModelMaterial* material = this->get_material(material_id); delete material; @@ -1134,7 +1136,8 @@ void ModelVolume::set_material_id(t_model_material_id material_id) { m_material_id = material_id; // ensure m_material_id references an existing material - this->object->get_model()->add_material(material_id); + if (! material_id.empty()) + this->object->get_model()->add_material(material_id); } ModelMaterial* ModelVolume::material() const @@ -1145,15 +1148,8 @@ ModelMaterial* ModelVolume::material() const void ModelVolume::set_material(t_model_material_id material_id, const ModelMaterial &material) { m_material_id = material_id; - this->object->get_model()->add_material(material_id, material); -} - -ModelMaterial* ModelVolume::assign_unique_material() -{ - Model* model = this->get_object()->get_model(); - // as material-id "0" is reserved by the AMF spec we start from 1 - m_material_id = 1 + model->materials.size(); // watchout for implicit cast - return model->add_material(m_material_id); + if (! material_id.empty()) + this->object->get_model()->add_material(material_id, material); } void ModelVolume::calculate_convex_hull() diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index a3aeab739..1850cce1f 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -22,7 +22,6 @@ class ModelInstance; class ModelMaterial; class ModelObject; class ModelVolume; -class PresetBundle; class Print; typedef std::string t_model_material_id; @@ -323,8 +322,6 @@ public: void rotate(double angle, const Vec3d& axis); void mirror(Axis axis); - ModelMaterial* assign_unique_material(); - void calculate_convex_hull(); const TriangleMesh& get_convex_hull() const; @@ -391,14 +388,15 @@ private: mesh(std::move(mesh)), m_convex_hull(std::move(convex_hull)), m_type(MODEL_PART), object(object) {} #if ENABLE_MODELVOLUME_TRANSFORM + // Copying an existing volume, therefore this volume will get a copy of the ID assigned. 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()); } + // Providing a new mesh, therefore this volume will get a new unique ID assigned. 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()); @@ -406,12 +404,15 @@ private: calculate_convex_hull(); } #else + // Copying an existing volume, therefore this volume will get a copy of the ID assigned. 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) { if (! other.material_id().empty()) this->set_material_id(other.material_id()); } + // Providing a new mesh, therefore this volume will get a new unique ID assigned. ModelVolume(ModelObject *object, const ModelVolume &other, TriangleMesh &&mesh) : name(other.name), mesh(std::move(mesh)), config(other.config), m_type(other.m_type), object(object) { diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index bc4a3020c..a7e368a11 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -633,7 +633,7 @@ void PrintObject::detect_surfaces_type() // should be visible. bool interface_shells = m_config.interface_shells.value; - for (int idx_region = 0; idx_region < m_print->m_regions.size(); ++ idx_region) { + for (int idx_region = 0; idx_region < this->region_volumes.size(); ++ idx_region) { BOOST_LOG_TRIVIAL(debug) << "Detecting solid surfaces for region " << idx_region << " in parallel - start"; #ifdef SLIC3R_DEBUG_SLICE_PROCESSING for (Layer *layer : m_layers) diff --git a/xs/xsp/Model.xsp b/xs/xsp/Model.xsp index a198b1b9f..11fa7e920 100644 --- a/xs/xsp/Model.xsp +++ b/xs/xsp/Model.xsp @@ -286,8 +286,6 @@ ModelMaterial::attributes() %code%{ THIS->set_type(ModelVolume::SUPPORT_BLOCKER); %}; size_t split(unsigned int max_extruders); - - ModelMaterial* assign_unique_material(); }; From 0810beae770578001fdfd84ecb5c276b2ba49048 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 6 Nov 2018 08:47:21 +0100 Subject: [PATCH 21/43] Reintroduced instances synchronization --- src/libslic3r/Technologies.hpp | 2 +- src/slic3r/GUI/GLCanvas3D.cpp | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 819366146..31825d346 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -18,7 +18,7 @@ // Uses a unique opengl context #define ENABLE_USE_UNIQUE_GLCONTEXT (1 && ENABLE_1_42_0) // Disable synchronization of unselected instances -#define DISABLE_INSTANCES_SYNCH (1 && ENABLE_1_42_0) +#define DISABLE_INSTANCES_SYNCH (0 && ENABLE_1_42_0) // Modified camera target behavior #define ENABLE_MODIFIED_CAMERA_TARGET (1 && ENABLE_1_42_0) // Add Geometry::Transformation class and use it into ModelInstance, ModelVolume and GLVolume diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 1b6e06160..71f07c6da 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1513,6 +1513,12 @@ void GLCanvas3D::Selection::flattening_rotate(const Vec3d& normal) Vec3d new_rotation = Geometry::extract_euler_angles(extra_rotation * m_cache.volumes_data[i].get_instance_rotation_matrix() ); (*m_volumes)[i]->set_instance_rotation(new_rotation); } + +#if !DISABLE_INSTANCES_SYNCH + if (m_mode == Instance) + _synchronize_unselected_instances(); +#endif // !DISABLE_INSTANCES_SYNCH + m_bounding_box_dirty = true; } @@ -2046,11 +2052,11 @@ void GLCanvas3D::Selection::_synchronize_unselected_instances() continue; #if ENABLE_MODELVOLUME_TRANSFORM - v->set_instance_rotation(rotation); + v->set_instance_rotation(Vec3d(rotation(0), rotation(1), v->get_instance_rotation()(2))); v->set_instance_scaling_factor(scaling_factor); v->set_instance_mirror(mirror); #else - v->set_rotation(rotation); + v->set_rotation(Vec3d(rotation(0), rotation(1), v->get_rotation()(2))); v->set_scaling_factor(scaling_factor); v->set_mirror(mirror); #endif // ENABLE_MODELVOLUME_TRANSFORM From 95af5c7cc6570536cabcdd6de4824de9526bf1f1 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Mon, 5 Nov 2018 13:53:30 +0100 Subject: [PATCH 22/43] Instance selection in object list according to the canvas selection --- src/slic3r/GUI/GUI_ObjectList.cpp | 15 ++++++++--- src/slic3r/GUI/wxExtensions.cpp | 43 ++++++++++++++++++++++++++----- src/slic3r/GUI/wxExtensions.hpp | 3 +++ 3 files changed, 51 insertions(+), 10 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index da5095bb6..6a319446e 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -1198,11 +1198,18 @@ void ObjectList::update_selections() auto& selection = _3DScene::get_canvas(wxGetApp().canvas3D())->get_selection(); wxDataViewItemArray sels; - for (auto idx: selection.get_volume_idxs()) - { - const auto gl_vol = selection.get_volume(idx); - sels.Add(m_objects_model->GetItemByVolumeId(gl_vol->object_idx(), gl_vol->volume_idx())); + if (selection.is_single_full_object()) { + for (auto idx : selection.get_volume_idxs()) { + const auto gl_vol = selection.get_volume(idx); + sels.Add(m_objects_model->GetItemByVolumeId(gl_vol->object_idx(), gl_vol->volume_idx())); + } } + else if (selection.is_single_full_instance()) { + for (auto idx : selection.get_instance_idxs()) { + sels.Add(m_objects_model->GetItemByInstanceId(selection.get_object_idx(), idx)); + } + } + select_items(sels); } diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 8d6a0408e..b561a11ce 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -727,7 +727,7 @@ wxDataViewItem PrusaObjectDataViewModel::GetItemById(int obj_idx) wxDataViewItem PrusaObjectDataViewModel::GetItemByVolumeId(int obj_idx, int volume_idx) { - if (obj_idx >= m_objects.size()) { + if (obj_idx >= m_objects.size() || obj_idx < 0) { printf("Error! Out of objects range.\n"); return wxDataViewItem(0); } @@ -749,6 +749,25 @@ wxDataViewItem PrusaObjectDataViewModel::GetItemByVolumeId(int obj_idx, int volu return wxDataViewItem(0); } +wxDataViewItem PrusaObjectDataViewModel::GetItemByInstanceId(int obj_idx, int inst_idx) +{ + if (obj_idx >= m_objects.size() || obj_idx < 0) { + printf("Error! Out of objects range.\n"); + return wxDataViewItem(0); + } + + auto instances_item = GetInstanceRootItem(wxDataViewItem(m_objects[obj_idx])); + if (!instances_item) + return wxDataViewItem(0); + + auto parent = (PrusaObjectDataViewModelNode*)instances_item.GetID();; + for (size_t i = 0; i < parent->GetChildCount(); i++) + if (parent->GetNthChild(i)->m_idx == inst_idx) + return wxDataViewItem(parent->GetNthChild(i)); + + return wxDataViewItem(0); +} + int PrusaObjectDataViewModel::GetIdByItem(const wxDataViewItem& item) { wxASSERT(item.IsOk()); @@ -1024,21 +1043,33 @@ ItemType PrusaObjectDataViewModel::GetItemType(const wxDataViewItem &item) const return node->m_type; } -wxDataViewItem PrusaObjectDataViewModel::GetSettingsItem(const wxDataViewItem &item) const +wxDataViewItem PrusaObjectDataViewModel::GetItemByType(const wxDataViewItem &parent_item, ItemType type) const { - if (!item.IsOk()) + if (!parent_item.IsOk()) return wxDataViewItem(0); - PrusaObjectDataViewModelNode *node = (PrusaObjectDataViewModelNode*)item.GetID(); + PrusaObjectDataViewModelNode *node = (PrusaObjectDataViewModelNode*)parent_item.GetID(); if (node->GetChildCount() == 0) return wxDataViewItem(0); - if (node->GetNthChild(0)->m_type == itSettings) - return wxDataViewItem((void*)node->GetNthChild(0)); + for (int i = 0; i < node->GetChildCount(); i++) { + if (node->GetNthChild(i)->m_type == type) + return wxDataViewItem((void*)node->GetNthChild(i)); + } return wxDataViewItem(0); } +wxDataViewItem PrusaObjectDataViewModel::GetSettingsItem(const wxDataViewItem &item) const +{ + return GetItemByType(item, itSettings); +} + +wxDataViewItem PrusaObjectDataViewModel::GetInstanceRootItem(const wxDataViewItem &item) const +{ + return GetItemByType(item, itInstanceRoot); +} + bool PrusaObjectDataViewModel::IsSettingsItem(const wxDataViewItem &item) const { if (!item.IsOk()) diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp index 3c9159233..4fae7452b 100644 --- a/src/slic3r/GUI/wxExtensions.hpp +++ b/src/slic3r/GUI/wxExtensions.hpp @@ -445,6 +445,7 @@ public: void DeleteChildren(wxDataViewItem& parent); wxDataViewItem GetItemById(int obj_idx); wxDataViewItem GetItemByVolumeId(int obj_idx, int volume_idx); + wxDataViewItem GetItemByInstanceId(int obj_idx, int inst_idx); int GetIdByItem(const wxDataViewItem& item); int GetIdByItemAndType(const wxDataViewItem& item, const ItemType type) const; int GetVolumeIdByItem(const wxDataViewItem& item) const; @@ -490,7 +491,9 @@ public: virtual bool HasContainerColumns(const wxDataViewItem& WXUNUSED(item)) const override { return true; } ItemType GetItemType(const wxDataViewItem &item) const ; + wxDataViewItem GetItemByType(const wxDataViewItem &parent_item, ItemType type) const; wxDataViewItem GetSettingsItem(const wxDataViewItem &item) const; + wxDataViewItem GetInstanceRootItem(const wxDataViewItem &item) const; bool IsSettingsItem(const wxDataViewItem &item) const; void UpdateSettingsDigest(const wxDataViewItem &item, const std::vector& categories); From 4a8b738a6ba525ba06cff41da516206aff050858 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Tue, 6 Nov 2018 09:06:26 +0100 Subject: [PATCH 23/43] Fixed object/part splitting If object has additional settings and we split it, add this settings for each of the new objects(parts) --- src/slic3r/GUI/GUI_ObjectList.cpp | 86 ++++++++++++++++--------------- src/slic3r/GUI/wxExtensions.cpp | 33 ++++++++++++ src/slic3r/GUI/wxExtensions.hpp | 1 + 3 files changed, 79 insertions(+), 41 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 6a319446e..8721b4249 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -898,8 +898,10 @@ bool ObjectList::del_subobject_from_object(const int obj_idx, const int idx, con void ObjectList::split(const bool split_part) { const auto item = GetSelection(); - if (!item || m_selected_object_id < 0) + const int obj_idx = get_selected_obj_idx(); + if (!item || obj_idx < 0) return; + ModelVolume* volume; if (!get_volume_by_item(split_part, item, volume)) return; DynamicPrintConfig& config = wxGetApp().preset_bundle->printers.get_edited_preset().config; @@ -909,52 +911,51 @@ void ObjectList::split(const bool split_part) return; } - auto model_object = (*m_objects)[m_selected_object_id]; + auto model_object = (*m_objects)[obj_idx]; - if (split_part) { - auto parent = m_objects_model->GetParent(item); - m_objects_model->DeleteChildren(parent); + auto parent = m_objects_model->GetTopParent(item); + if (parent) + m_objects_model->DeleteVolumeChildren(parent); + else + parent = item; - for (auto id = 0; id < model_object->volumes.size(); id++) - m_objects_model->AddVolumeChild(parent, model_object->volumes[id]->name, - model_object->volumes[id]->is_modifier() ? ModelVolume::PARAMETER_MODIFIER : ModelVolume::MODEL_PART, - model_object->volumes[id]->config.has("extruder") ? - model_object->volumes[id]->config.option("extruder")->value : 0, - false); - - Expand(parent); - } - else { - for (auto id = 0; id < model_object->volumes.size(); id++) - m_objects_model->AddVolumeChild(item, model_object->volumes[id]->name, - ModelVolume::MODEL_PART, - model_object->volumes[id]->config.has("extruder") ? - model_object->volumes[id]->config.option("extruder")->value : 0, - false); - Expand(item); + for (auto id = 0; id < model_object->volumes.size(); id++) { + const auto vol_item = m_objects_model->AddVolumeChild(parent, model_object->volumes[id]->name, + model_object->volumes[id]->is_modifier() ? + ModelVolume::PARAMETER_MODIFIER : ModelVolume::MODEL_PART, + model_object->volumes[id]->config.has("extruder") ? + model_object->volumes[id]->config.option("extruder")->value : 0, + false); + // add settings to the part, if it has those + auto opt_keys = model_object->volumes[id]->config.keys(); + if ( !(opt_keys.size() == 1 && opt_keys[0] == "extruder") ) { + select_item(m_objects_model->AddSettingsChild(vol_item)); + Collapse(vol_item); + } } m_parts_changed = true; - parts_changed(m_selected_object_id); - - // restores selection -// _3DScene::get_canvas(wxGetApp().canvas3D())->get_selection().add_object(m_selected_object_id); + parts_changed(obj_idx); } bool ObjectList::get_volume_by_item(const bool split_part, const wxDataViewItem& item, ModelVolume*& volume) { - if (!item || m_selected_object_id < 0) + auto obj_idx = get_selected_obj_idx(); + if (!item || obj_idx < 0) return false; const auto volume_id = m_objects_model->GetVolumeIdByItem(item); + + // object is selected if (volume_id < 0) { - if (split_part) return false; - volume = (*m_objects)[m_selected_object_id]->volumes[0]; + if ( split_part || (*m_objects)[obj_idx]->volumes.size() > 1 ) + return false; + volume = (*m_objects)[obj_idx]->volumes[0]; } + // volume is selected else - volume = (*m_objects)[m_selected_object_id]->volumes[volume_id]; - if (volume) - return true; - return false; + volume = (*m_objects)[obj_idx]->volumes[volume_id]; + + return true; } bool ObjectList::is_splittable_object(const bool split_part) @@ -962,20 +963,14 @@ bool ObjectList::is_splittable_object(const bool split_part) const wxDataViewItem item = GetSelection(); if (!item) return false; - wxDataViewItemArray children; - if (!split_part && m_objects_model->GetChildren(item, children) > 0) - return false; - ModelVolume* volume; if (!get_volume_by_item(split_part, item, volume) || !volume) return false; TriangleMeshPtrs meshptrs = volume->mesh.split(); bool splittable = meshptrs.size() > 1; - for (TriangleMesh* m : meshptrs) - { - delete m; - } + for (TriangleMesh* m : meshptrs) { delete m; } + return splittable; } @@ -1076,6 +1071,7 @@ void ObjectList::add_object_to_list(size_t obj_idx) m_objects_model->SetValue(variant, item, 0); } + // add volumes to the object if (model_object->volumes.size() > 1) { for (auto id = 0; id < model_object->volumes.size(); id++) m_objects_model->AddVolumeChild(item, @@ -1086,9 +1082,17 @@ void ObjectList::add_object_to_list(size_t obj_idx) Expand(item); } + // add instances to the object, if it has those if (model_object->instances.size()>1) increase_object_instances(obj_idx, model_object->instances.size()); + // add settings to the object, if it has those + auto opt_keys = model_object->config.keys(); + if ( !(opt_keys.size() == 1 && opt_keys[0] == "extruder") ) { + select_item(m_objects_model->AddSettingsChild(item)); + Collapse(item); + } + #ifndef __WXOSX__ selection_changed(); #endif //__WXMSW__ diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index b561a11ce..c5743c3ce 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -714,6 +714,39 @@ void PrusaObjectDataViewModel::DeleteChildren(wxDataViewItem& parent) #endif //__WXGTK__ } +void PrusaObjectDataViewModel::DeleteVolumeChildren(wxDataViewItem& parent) +{ + PrusaObjectDataViewModelNode *root = (PrusaObjectDataViewModelNode*)parent.GetID(); + if (!root) // happens if item.IsOk()==false + return; + + // first remove the node from the parent's array of children; + // NOTE: MyObjectTreeModelNodePtrArray is only an array of _pointers_ + // thus removing the node from it doesn't result in freeing it + auto& children = root->GetChildren(); + for (int id = root->GetChildCount() - 1; id >= 0; --id) + { + auto node = children[id]; + if (node->m_type != itVolume) + continue; + + auto item = wxDataViewItem(node); + children.RemoveAt(id); + root->m_volumes_cnt--; + + // free the node + delete node; + + // notify control + ItemDeleted(parent, item); + } + + // set m_containet to FALSE if parent has no child +#ifndef __WXGTK__ + root->m_container = false; +#endif //__WXGTK__ +} + wxDataViewItem PrusaObjectDataViewModel::GetItemById(int obj_idx) { if (obj_idx >= m_objects.size()) diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp index 4fae7452b..6293fb962 100644 --- a/src/slic3r/GUI/wxExtensions.hpp +++ b/src/slic3r/GUI/wxExtensions.hpp @@ -443,6 +443,7 @@ public: wxDataViewItem DeleteLastInstance(const wxDataViewItem &parent_item, size_t num); void DeleteAll(); void DeleteChildren(wxDataViewItem& parent); + void DeleteVolumeChildren(wxDataViewItem& parent); wxDataViewItem GetItemById(int obj_idx); wxDataViewItem GetItemByVolumeId(int obj_idx, int volume_idx); wxDataViewItem GetItemByInstanceId(int obj_idx, int inst_idx); From 4f0869730a39f4f891d2cedaf995d6410b62046b Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 6 Nov 2018 10:31:19 +0100 Subject: [PATCH 24/43] Do not render selection's bounding box when any gizmo is active --- src/slic3r/GUI/GLCanvas3D.cpp | 61 ++--------------------------------- src/slic3r/GUI/GLCanvas3D.hpp | 3 +- 2 files changed, 4 insertions(+), 60 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 71f07c6da..f69d798bd 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1703,17 +1703,13 @@ void GLCanvas3D::Selection::translate(unsigned int object_idx, unsigned int inst m_bounding_box_dirty = true; } -void GLCanvas3D::Selection::render(bool show_indirect_selection) const +void GLCanvas3D::Selection::render() const { if (is_empty()) return; // render cumulative bounding box of selected volumes _render_selected_volumes(); - - // render bounding boxes of indirectly selected instances - if (show_indirect_selection && (m_mode == Instance)) - _render_unselected_instances(); } void GLCanvas3D::Selection::_update_valid() @@ -1912,56 +1908,6 @@ void GLCanvas3D::Selection::_render_selected_volumes() const _render_bounding_box(get_bounding_box(), color); } -void GLCanvas3D::Selection::_render_unselected_instances() const -{ - std::set done; // prevent processing volumes twice - done.insert(m_list.begin(), m_list.end()); - - typedef std::map, BoundingBoxf3> InstanceToBoxMap; - InstanceToBoxMap boxes; - for (unsigned int i : m_list) - { - if (done.size() == m_volumes->size()) - break; - - const GLVolume* volume = (*m_volumes)[i]; - int object_idx = volume->object_idx(); - if (object_idx >= 1000) - continue; - - int instance_idx = volume->instance_idx(); - - for (unsigned int j = 0; j < (unsigned int)m_volumes->size(); ++j) - { - if (done.size() == m_volumes->size()) - break; - - if (done.find(j) != done.end()) - continue; - - GLVolume* v = (*m_volumes)[j]; - int i_idx = v->instance_idx(); - if ((v->object_idx() != object_idx) || (i_idx == instance_idx)) - continue; - - std::pair box_id(object_idx, i_idx); - InstanceToBoxMap::iterator it = boxes.find(box_id); - if (it == boxes.end()) - it = boxes.insert(InstanceToBoxMap::value_type(box_id, BoundingBoxf3())).first; - - it->second.merge(v->transformed_convex_hull_bounding_box()); - - done.insert(j); - } - } - - float color[3] = { 1.0f, 1.0f, 0.0f }; - for (const InstanceToBoxMap::value_type& box : boxes) - { - _render_bounding_box(box.second, color); - } -} - void GLCanvas3D::Selection::_render_bounding_box(const BoundingBoxf3& box, float* color) const { if (color == nullptr) @@ -4798,9 +4744,8 @@ void GLCanvas3D::_render_objects() const void GLCanvas3D::_render_selection() const { - Gizmos::EType type = m_gizmos.get_current_type(); - bool show_indirect_selection = m_gizmos.is_running() && ((type == Gizmos::Rotate) || (type == Gizmos::Scale) || (type == Gizmos::Flatten)); - m_selection.render(show_indirect_selection); + if (!m_gizmos.is_running()) + m_selection.render(); } void GLCanvas3D::_render_cutting_plane() const diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 7318d00c9..07bca269b 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -517,7 +517,7 @@ public: void translate(unsigned int object_idx, const Vec3d& displacement); void translate(unsigned int object_idx, unsigned int instance_idx, const Vec3d& displacement); - void render(bool show_indirect_selection) const; + void render() const; private: void _update_valid(); @@ -531,7 +531,6 @@ public: void _remove_object(unsigned int object_idx); void _calc_bounding_box() const; void _render_selected_volumes() const; - void _render_unselected_instances() const; void _render_bounding_box(const BoundingBoxf3& box, float* color) const; void _synchronize_unselected_instances(); }; From 0ac17b551341c7f8334627f04498de56c8621c42 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Tue, 6 Nov 2018 11:39:38 +0100 Subject: [PATCH 25/43] Changed sequence of the items in the objects list (inside object): Additional Settings, Subvolumes(parts), Instances --- src/slic3r/GUI/GUI_ObjectList.cpp | 3 ++- src/slic3r/GUI/wxExtensions.cpp | 32 +++++++++++++++---------------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 8721b4249..f6a103516 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -387,7 +387,8 @@ void ObjectList::on_drop(wxDataViewEvent &event) wxDataViewItem item(event.GetItem()); // only allow drops for item, not containers - if (item.IsOk() && m_objects_model->GetParent(item) == wxDataViewItem(0) || + if (m_selected_object_id < 0 || + item.IsOk() && m_objects_model->GetParent(item) == wxDataViewItem(0) || event.GetDataFormat() != wxDF_UNICODETEXT || m_objects_model->GetItemType(item) != itVolume) { event.Veto(); return; diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index c5743c3ce..cd6cf171f 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -462,22 +462,25 @@ wxDataViewItem PrusaObjectDataViewModel::AddVolumeChild(const wxDataViewItem &pa wxString extruder_str = extruder == 0 ? "default" : wxString::Format("%d", extruder); + // because of istance_root is a last item of the object + int insert_position = root->GetChildCount() - 1; + if (insert_position < 0 || root->GetNthChild(insert_position)->m_type != itInstanceRoot) + insert_position = -1; + if (create_frst_child && root->m_volumes_cnt == 0) { const auto node = new PrusaObjectDataViewModelNode(root, root->m_name, *m_volume_bmps[0], extruder_str, 0); - root->Append(node); + insert_position < 0 ? root->Append(node) : root->Insert(node, insert_position); // notify control const wxDataViewItem child((void*)node); ItemAdded(parent_item, child); root->m_volumes_cnt++; + if (insert_position > 0) insert_position++; } -// if (volume_type >= Slic3r::ModelVolume::SUPPORT_ENFORCER) -// extruder_str = ""; - const auto node = new PrusaObjectDataViewModelNode(root, name, *m_volume_bmps[volume_type], extruder_str, root->m_volumes_cnt); - root->Append(node); + insert_position < 0 ? root->Append(node) : root->Insert(node, insert_position); // notify control const wxDataViewItem child((void*)node); ItemAdded(parent_item, child); @@ -501,15 +504,13 @@ wxDataViewItem PrusaObjectDataViewModel::AddSettingsChild(const wxDataViewItem & int get_istances_root_idx(PrusaObjectDataViewModelNode *parent_node) { - int inst_root_id = -1; - int stop_search_i = parent_node->GetChildCount(); - if (stop_search_i > 2) stop_search_i = 2; - for (int i = 0; i < stop_search_i; ++i) - if (parent_node->GetNthChild(i)->m_type & itInstanceRoot) { - inst_root_id = i; - break; - } - return inst_root_id; + // because of istance_root is a last item of the object + const int inst_root_idx = parent_node->GetChildCount()-1; + + if (inst_root_idx < 0 || parent_node->GetNthChild(inst_root_idx)->m_type == itInstanceRoot) + return inst_root_idx; + + return -1; } wxDataViewItem PrusaObjectDataViewModel::AddInstanceChild(const wxDataViewItem &parent_item, size_t num) @@ -526,8 +527,7 @@ wxDataViewItem PrusaObjectDataViewModel::AddInstanceChild(const wxDataViewItem & const wxDataViewItem inst_root_item((void*)inst_root_node); if (inst_root_id < 0) { - const unsigned insert_pos = parent_node->GetChildCount() == 0 || parent_node->GetNthChild(0)->m_type != itSettings ? 0 : 1; - parent_node->Insert(inst_root_node, insert_pos); + parent_node->Append(inst_root_node); // notify control ItemAdded(parent_item, inst_root_item); if (num == 1) num++; From 7c934ef9516bad03111867405fb8ca5d542e0d6d Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 6 Nov 2018 11:54:36 +0100 Subject: [PATCH 26/43] Catch unhandled exceptions in background processing, call wxApp::OnUnhandledException() --- src/slic3r/GUI/BackgroundSlicingProcess.cpp | 12 +++++++++++- src/slic3r/GUI/BackgroundSlicingProcess.hpp | 1 + 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp index f2b07c51e..cd438ebe5 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp @@ -1,6 +1,7 @@ #include "BackgroundSlicingProcess.hpp" #include "GUI_App.hpp" +#include #include #include #include @@ -103,6 +104,15 @@ void BackgroundSlicingProcess::thread_proc() // End of the background processing thread. The UI thread should join m_thread now. } +void BackgroundSlicingProcess::thread_proc_safe() +{ + try { + this->thread_proc(); + } catch (...) { + wxTheApp->OnUnhandledException(); + } +} + void BackgroundSlicingProcess::join_background_thread() { std::unique_lock lck(m_mutex); @@ -127,7 +137,7 @@ bool BackgroundSlicingProcess::start() if (m_state == STATE_INITIAL) { // The worker thread is not running yet. Start it. assert(! m_thread.joinable()); - m_thread = std::thread([this]{this->thread_proc();}); + m_thread = std::thread([this]{this->thread_proc_safe();}); // Wait until the worker thread is ready to execute the background processing task. m_condition.wait(lck, [this](){ return m_state == STATE_IDLE; }); } diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.hpp b/src/slic3r/GUI/BackgroundSlicingProcess.hpp index f00668299..6b92e8516 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.hpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.hpp @@ -80,6 +80,7 @@ public: private: void thread_proc(); + void thread_proc_safe(); void join_background_thread(); // To be called by Print::apply() through the Print::m_cancel_callback to stop the background // processing before changing any data of running or finalized milestones. From 3eea327ef0bb476adb1d43e4eca0135fef94eb8c Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 6 Nov 2018 15:31:26 +0100 Subject: [PATCH 27/43] WIP: When iterating over PrintObject's regions, use the region count by PrintObject::region_volumes. This is due to the way Print::apply() works, it does not invalidate an existing PrintObject if a new region is added to the print. --- src/libslic3r/GCode.cpp | 6 ++-- src/libslic3r/GCode/ToolOrdering.cpp | 2 +- src/libslic3r/PrintObject.cpp | 44 ++++++++++++++-------------- xs/xsp/Print.xsp | 2 -- 4 files changed, 26 insertions(+), 28 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 52bdf1d1b..765c8b8c1 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -445,7 +445,7 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_ boost::nowide::remove(path_tmp.c_str()); throw std::runtime_error(std::string("G-code export to ") + path + " failed\nIs the disk full?\n"); } - } catch (std::exception &ex) { + } catch (std::exception & /* ex */) { // Rethrow on any exception. std::runtime_exception and CanceledException are expected to be thrown. // Close and remove the file. fclose(file); @@ -606,7 +606,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) // get the minimum cross-section used in the print std::vector mm3_per_mm; for (auto object : printable_objects) { - for (size_t region_id = 0; region_id < print.regions().size(); ++region_id) { + for (size_t region_id = 0; region_id < object->region_volumes.size(); ++ region_id) { auto region = print.regions()[region_id]; for (auto layer : object->layers()) { auto layerm = layer->regions()[region_id]; @@ -1442,7 +1442,7 @@ void GCode::process_layer( }; for (size_t region_id = 0; region_id < print.regions().size(); ++ region_id) { - const LayerRegion *layerm = layer.regions()[region_id]; + const LayerRegion *layerm = (region_id < layer.regions().size()) ? layer.regions()[region_id] : nullptr; if (layerm == nullptr) continue; const PrintRegion ®ion = *print.regions()[region_id]; diff --git a/src/libslic3r/GCode/ToolOrdering.cpp b/src/libslic3r/GCode/ToolOrdering.cpp index 175b69447..b20386730 100644 --- a/src/libslic3r/GCode/ToolOrdering.cpp +++ b/src/libslic3r/GCode/ToolOrdering.cpp @@ -151,7 +151,7 @@ void ToolOrdering::collect_extruders(const PrintObject &object) for (auto layer : object.layers()) { LayerTools &layer_tools = this->tools_for_layer(layer->print_z); // What extruders are required to print this object layer? - for (size_t region_id = 0; region_id < object.print()->regions().size(); ++ region_id) { + for (size_t region_id = 0; region_id < object.region_volumes.size(); ++ region_id) { const LayerRegion *layerm = (region_id < layer->regions().size()) ? layer->regions()[region_id] : nullptr; if (layerm == nullptr) continue; diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index a7e368a11..45b2689bb 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -184,8 +184,8 @@ void PrintObject::make_perimeters() // but we don't generate any extra perimeter if fill density is zero, as they would be floating // inside the object - infill_only_where_needed should be the method of choice for printing // hollow objects - for (size_t region_id = 0; region_id < m_print->regions().size(); ++ region_id) { - const PrintRegion ®ion = *m_print->regions()[region_id]; + for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) { + const PrintRegion ®ion = *m_print->regions()[region_id]; if (! region.config().extra_perimeters || region.config().perimeters == 0 || region.config().fill_density == 0 || this->layer_count() < 2) continue; @@ -313,7 +313,7 @@ void PrintObject::prepare_infill() // Debugging output. #ifdef SLIC3R_DEBUG_SLICE_PROCESSING - for (size_t region_id = 0; region_id < this->print()->regions().size(); ++ region_id) { + for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) { for (const Layer *layer : m_layers) { LayerRegion *layerm = layer->m_regions[region_id]; layerm->export_region_slices_to_svg_debug("6_discover_vertical_shells-final"); @@ -332,7 +332,7 @@ void PrintObject::prepare_infill() m_print->throw_if_canceled(); #ifdef SLIC3R_DEBUG_SLICE_PROCESSING - for (size_t region_id = 0; region_id < this->print()->regions().size(); ++ region_id) { + for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) { for (const Layer *layer : m_layers) { LayerRegion *layerm = layer->m_regions[region_id]; layerm->export_region_slices_to_svg_debug("7_discover_horizontal_shells-final"); @@ -351,7 +351,7 @@ void PrintObject::prepare_infill() m_print->throw_if_canceled(); #ifdef SLIC3R_DEBUG_SLICE_PROCESSING - for (size_t region_id = 0; region_id < this->print()->regions().size(); ++ region_id) { + for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) { for (const Layer *layer : m_layers) { LayerRegion *layerm = layer->m_regions[region_id]; layerm->export_region_slices_to_svg_debug("8_clip_surfaces-final"); @@ -370,7 +370,7 @@ void PrintObject::prepare_infill() m_print->throw_if_canceled(); #ifdef SLIC3R_DEBUG_SLICE_PROCESSING - for (size_t region_id = 0; region_id < this->print()->regions().size(); ++ region_id) { + for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) { for (const Layer *layer : m_layers) { LayerRegion *layerm = layer->m_regions[region_id]; layerm->export_region_slices_to_svg_debug("9_prepare_infill-final"); @@ -818,7 +818,7 @@ void PrintObject::process_external_surfaces() { BOOST_LOG_TRIVIAL(info) << "Processing external surfaces..."; - for (size_t region_id = 0; region_id < m_print->regions().size(); ++ region_id) { + for (size_t region_id = 0; region_id < this->region_volumes.size(); ++region_id) { const PrintRegion ®ion = *m_print->regions()[region_id]; BOOST_LOG_TRIVIAL(debug) << "Processing external surfaces for region " << region_id << " in parallel - start"; @@ -851,13 +851,13 @@ void PrintObject::discover_vertical_shells() Polygons holes; }; std::vector cache_top_botom_regions(m_layers.size(), DiscoverVerticalShellsCacheEntry()); - bool top_bottom_surfaces_all_regions = m_print->regions().size() > 1 && ! m_config.interface_shells.value; + bool top_bottom_surfaces_all_regions = this->region_volumes.size() > 1 && ! m_config.interface_shells.value; if (top_bottom_surfaces_all_regions) { // This is a multi-material print and interface_shells are disabled, meaning that the vertical shell thickness // is calculated over all materials. // Is the "ensure vertical wall thickness" applicable to any region? bool has_extra_layers = false; - for (size_t idx_region = 0; idx_region < m_print->regions().size(); ++ idx_region) { + for (size_t idx_region = 0; idx_region < this->region_volumes.size(); ++ idx_region) { const PrintRegion ®ion = *m_print->get_region(idx_region); if (region.config().ensure_vertical_shell_thickness.value && (region.config().top_solid_layers.value > 1 || region.config().bottom_solid_layers.value > 1)) { @@ -874,7 +874,7 @@ void PrintObject::discover_vertical_shells() tbb::blocked_range(0, m_layers.size(), grain_size), [this, &cache_top_botom_regions](const tbb::blocked_range& range) { const SurfaceType surfaces_bottom[2] = { stBottom, stBottomBridge }; - const size_t num_regions = m_print->regions().size(); + const size_t num_regions = this->region_volumes.size(); for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++ idx_layer) { m_print->throw_if_canceled(); const Layer &layer = *m_layers[idx_layer]; @@ -935,7 +935,7 @@ void PrintObject::discover_vertical_shells() BOOST_LOG_TRIVIAL(debug) << "Discovering vertical shells in parallel - end : cache top / bottom"; } - for (size_t idx_region = 0; idx_region < m_print->regions().size(); ++ idx_region) { + for (size_t idx_region = 0; idx_region < this->region_volumes.size(); ++ idx_region) { PROFILE_BLOCK(discover_vertical_shells_region); const PrintRegion ®ion = *m_print->get_region(idx_region); @@ -1227,7 +1227,7 @@ void PrintObject::bridge_over_infill() { BOOST_LOG_TRIVIAL(info) << "Bridge over infill..."; - for (size_t region_id = 0; region_id < m_print->regions().size(); ++ region_id) { + for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) { const PrintRegion ®ion = *m_print->regions()[region_id]; // skip bridging in case there are no voids @@ -1444,14 +1444,14 @@ void PrintObject::_slice() layer->lower_layer = prev; } // Make sure all layers contain layer region objects for all regions. - for (size_t region_id = 0; region_id < this->print()->regions().size(); ++ region_id) + for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) layer->add_region(this->print()->regions()[region_id]); prev = layer; } } // Slice all non-modifier volumes. - for (size_t region_id = 0; region_id < this->print()->regions().size(); ++ region_id) { + for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) { BOOST_LOG_TRIVIAL(debug) << "Slicing objects - region " << region_id; std::vector expolygons_by_layer = this->_slice_region(region_id, slice_zs, false); m_print->throw_if_canceled(); @@ -1463,14 +1463,14 @@ void PrintObject::_slice() } // Slice all modifier volumes. - if (this->print()->regions().size() > 1) { - for (size_t region_id = 0; region_id < this->print()->regions().size(); ++ region_id) { + if (this->region_volumes.size() > 1) { + for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) { BOOST_LOG_TRIVIAL(debug) << "Slicing modifier volumes - region " << region_id; std::vector expolygons_by_layer = this->_slice_region(region_id, slice_zs, true); m_print->throw_if_canceled(); // loop through the other regions and 'steal' the slices belonging to this one BOOST_LOG_TRIVIAL(debug) << "Slicing modifier volumes - stealing " << region_id << " start"; - for (size_t other_region_id = 0; other_region_id < this->print()->regions().size(); ++ other_region_id) { + for (size_t other_region_id = 0; other_region_id < this->region_volumes.size(); ++ other_region_id) { if (region_id == other_region_id) continue; for (size_t layer_id = 0; layer_id < expolygons_by_layer.size(); ++ layer_id) { @@ -1497,7 +1497,7 @@ void PrintObject::_slice() BOOST_LOG_TRIVIAL(debug) << "Slicing objects - removing top empty layers"; while (! m_layers.empty()) { const Layer *layer = m_layers.back(); - for (size_t region_id = 0; region_id < this->print()->regions().size(); ++ region_id) + for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) if (layer->m_regions[region_id] != nullptr && ! layer->m_regions[region_id]->slices.empty()) // Non empty layer. goto end; @@ -1756,7 +1756,7 @@ void PrintObject::_make_perimeters() // but we don't generate any extra perimeter if fill density is zero, as they would be floating // inside the object - infill_only_where_needed should be the method of choice for printing // hollow objects - for (size_t region_id = 0; region_id < m_print->regions().size(); ++ region_id) { + for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) { const PrintRegion ®ion = *m_print->regions()[region_id]; if (! region.config().extra_perimeters || region.config().perimeters == 0 || region.config().fill_density == 0 || this->layer_count() < 2) continue; @@ -1928,7 +1928,7 @@ void PrintObject::discover_horizontal_shells() { BOOST_LOG_TRIVIAL(trace) << "discover_horizontal_shells()"; - for (size_t region_id = 0; region_id < this->print()->regions().size(); ++ region_id) { + for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) { for (int i = 0; i < int(m_layers.size()); ++ i) { m_print->throw_if_canceled(); LayerRegion *layerm = m_layers[i]->regions()[region_id]; @@ -2102,7 +2102,7 @@ void PrintObject::discover_horizontal_shells() } // for each region #ifdef SLIC3R_DEBUG_SLICE_PROCESSING - for (size_t region_id = 0; region_id < this->print()->regions().size(); ++ region_id) { + for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) { for (const Layer *layer : m_layers) { const LayerRegion *layerm = layer->m_regions[region_id]; layerm->export_region_slices_to_svg_debug("5_discover_horizontal_shells"); @@ -2118,7 +2118,7 @@ void PrintObject::discover_horizontal_shells() void PrintObject::combine_infill() { // Work on each region separately. - for (size_t region_id = 0; region_id < this->print()->regions().size(); ++ region_id) { + for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) { const PrintRegion *region = this->print()->regions()[region_id]; const int every = region->config().infill_every_layers.value; if (every < 2 || region->config().fill_density == 0.) diff --git a/xs/xsp/Print.xsp b/xs/xsp/Print.xsp index b34444b23..cf3b67931 100644 --- a/xs/xsp/Print.xsp +++ b/xs/xsp/Print.xsp @@ -44,8 +44,6 @@ _constant() int region_count() %code%{ RETVAL = THIS->print()->regions().size(); %}; - int region_volumes_count() - %code%{ RETVAL = THIS->region_volumes.size(); %}; Ref print(); Ref model_object(); Ref config() From de981ce8be4329fa2ac93c58e84939a2795abc9f Mon Sep 17 00:00:00 2001 From: YuSanka Date: Tue, 6 Nov 2018 15:34:44 +0100 Subject: [PATCH 28/43] Changed object context menu : Add part/modifier/support enforcer/support blocker -> Load model / generic box/sphere/cylinder/slab --- src/slic3r/GUI/GUI_App.hpp | 2 +- src/slic3r/GUI/GUI_ObjectList.cpp | 94 +++++++++++++-------------- src/slic3r/GUI/GUI_ObjectList.hpp | 4 +- src/slic3r/GUI/LambdaObjectDialog.cpp | 8 +-- 4 files changed, 52 insertions(+), 56 deletions(-) diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index ccc7026ee..6716d73ad 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -60,7 +60,7 @@ enum ConfigMenuIDs { class Tab; -static wxString dots("…", wxConvUTF8); +static wxString dots("…"/*, wxConvUTF8*/); class GUI_App : public wxApp { diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index f6a103516..4aed6d701 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -529,16 +529,24 @@ void ObjectList::get_settings_choice(wxMenu *menu, int id, bool is_part) wxGetApp().obj_manipul()->update_settings_list(); } -void ObjectList::menu_item_add_generic(wxMenuItem* &menu, int id) { +void ObjectList::menu_item_add_generic(wxMenuItem* &menu, int id, const int type) { auto sub_menu = new wxMenu; + const wxString menu_load = _(L("Load")) +" "+ dots; + sub_menu->Append(new wxMenuItem(sub_menu, id++, menu_load)); + sub_menu->AppendSeparator(); + std::vector menu_items = { L("Box"), L("Cylinder"), L("Sphere"), L("Slab") }; for (auto& item : menu_items) - sub_menu->Append(new wxMenuItem(sub_menu, ++id, _(item))); + sub_menu->Append(new wxMenuItem(sub_menu, id++, _(item))); #ifndef __WXMSW__ - sub_menu->Bind(wxEVT_MENU, [this, sub_menu](wxEvent &event) { - load_lambda(sub_menu->GetLabel(event.GetId()).ToStdString()); + sub_menu->Bind(wxEVT_MENU, [sub_menu, type, menu_load, this](wxEvent &event) { + auto selection = sub_menu->GetLabel(event.GetId()); + if (selection == menu_load) + load_subobject(type); + else + load_generic_subobject(selection.ToStdString(), type); }); #endif //no __WXMSW__ @@ -563,68 +571,53 @@ wxMenuItem* ObjectList::menu_item_settings(wxMenu* menu, int id, const bool is_p wxMenu* ObjectList::create_add_part_popupmenu() { wxMenu *menu = new wxMenu; - std::vector menu_object_types_items = {L("Add part"), - L("Add modifier"), - L("Add support enforcer"), - L("Add support bloker"), - L("Add generic") }; + // Note: id accords to type of the sub-object, so sequence of the menu items is important + std::vector menu_object_types_items = {L("Add part"), // ~ModelVolume::MODEL_PART + L("Add modifier"), // ~ModelVolume::PARAMETER_MODIFIER + L("Add support enforcer"), // ~ModelVolume::SUPPORT_ENFORCER + L("Add support bloker") }; // ~ModelVolume::SUPPORT_BLOCKER + const int obj_types_count = menu_object_types_items.size(); - const int generics_count = 4; + const int generics_count = 5; // "Load ...", "Box", "Cylinder", "Sphere", "Slab" - wxWindowID config_id_base = NewControlId(menu_object_types_items.size() + 4 + 2); + wxWindowID config_id_base = NewControlId(generics_count*obj_types_count + 2); // Add first 4 menu items - int i; - for (i = 0; i < obj_types_count - 1; i++) { - auto& item = menu_object_types_items[i]; - auto menu_item = new wxMenuItem(menu, config_id_base + i, _(item)); - menu_item->SetBitmap(*m_bmp_vector[i]); + for (int type = 0; type < obj_types_count; type++) { + auto& item = menu_object_types_items[type]; + auto menu_item = new wxMenuItem(menu, config_id_base + type, _(item)); + menu_item->SetBitmap(*m_bmp_vector[type]); + menu_item_add_generic(menu_item, config_id_base + type*generics_count, type); menu->Append(menu_item); } - // Add generic modifier - auto& item = menu_object_types_items[i]; - auto menu_item = new wxMenuItem(menu, config_id_base + i, _(item)); - menu_item->SetBitmap(*m_bmp_vector[1]); // set modifier's icon - menu_item_add_generic(menu_item, config_id_base + i); - menu->Append(menu_item); // Split object to parts menu->AppendSeparator(); - menu_item = menu_item_split(menu, config_id_base + obj_types_count + generics_count); + auto menu_item = menu_item_split(menu, config_id_base + obj_types_count * generics_count); menu->Append(menu_item); menu_item->Enable(is_splittable_object(false)); // Settings menu->AppendSeparator(); // Append settings popupmenu - menu->Append(menu_item_settings(menu, config_id_base + obj_types_count + generics_count+1, false)); + menu->Append(menu_item_settings(menu, config_id_base + obj_types_count * generics_count+1, false)); - menu->Bind(wxEVT_MENU, [config_id_base, menu, this](wxEvent &event) { - switch (event.GetId() - config_id_base) { - case 0: // ~ModelVolume::MODEL_PART - case 1: // ~ModelVolume::PARAMETER_MODIFIER - case 2: // ~ModelVolume::SUPPORT_ENFORCER - case 3: // ~ModelVolume::SUPPORT_BLOCKER - load_subobject(event.GetId() - config_id_base); - break; - case 4: - case 5: - case 6: - case 7: - case 8: -#ifdef __WXMSW__ - load_lambda(menu->GetLabel(event.GetId()).ToStdString()); -#endif // __WXMSW__ - break; - case 9: + menu->Bind(wxEVT_MENU, [config_id_base, menu, obj_types_count, generics_count, this](wxEvent &event) { + auto selection = event.GetId() - config_id_base; + + if ( selection == 0 * generics_count || // ~ModelVolume::MODEL_PART + selection == 1 * generics_count || // ~ModelVolume::PARAMETER_MODIFIER + selection == 2 * generics_count || // ~ModelVolume::SUPPORT_ENFORCER + selection == 3 * generics_count ) // ~ModelVolume::SUPPORT_BLOCKER + load_subobject(int(selection / generics_count)); + else if ( selection == obj_types_count * generics_count) split(false); - break; - default: #ifdef __WXMSW__ + else if ( selection > obj_types_count * generics_count) // "Add Settings" is selected get_settings_choice(menu, event.GetId(), false); + else // Some generic model is selected + load_generic_subobject(menu->GetLabel(event.GetId()).ToStdString(), int(selection / generics_count)); #endif // __WXMSW__ - break; - } }); return menu; @@ -765,7 +758,7 @@ void ObjectList::load_part( ModelObject* model_object, } -void ObjectList::load_lambda(const std::string& type_name) +void ObjectList::load_generic_subobject(const std::string& type_name, const int type) { if (m_selected_object_id < 0) return; @@ -792,7 +785,7 @@ void ObjectList::load_lambda(const std::string& type_name) mesh.repair(); auto new_volume = (*m_objects)[m_selected_object_id]->add_volume(mesh); - new_volume->set_type(ModelVolume::PARAMETER_MODIFIER); + new_volume->set_type(static_cast(type)); new_volume->name = name; // set a default extruder value, since user can't add it manually @@ -801,7 +794,7 @@ void ObjectList::load_lambda(const std::string& type_name) m_parts_changed = true; parts_changed(m_selected_object_id); - select_item(m_objects_model->AddVolumeChild(GetSelection(), name, ModelVolume::PARAMETER_MODIFIER/*m_bmp_modifiermesh*/)); + select_item(m_objects_model->AddVolumeChild(GetSelection(), name, type)); #ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME selection_changed(); #endif //no __WXOSX__ //__WXMSW__ @@ -935,6 +928,9 @@ void ObjectList::split(const bool split_part) } } + if (parent == item) + Expand(parent); + m_parts_changed = true; parts_changed(obj_idx); } diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp index ca9de5f76..33b2a7608 100644 --- a/src/slic3r/GUI/GUI_ObjectList.hpp +++ b/src/slic3r/GUI/GUI_ObjectList.hpp @@ -82,7 +82,7 @@ public: void on_drop(wxDataViewEvent &event); void get_settings_choice(wxMenu *menu, int id, bool is_part); - void menu_item_add_generic(wxMenuItem* &menu, int id); + void menu_item_add_generic(wxMenuItem* &menu, int id, const int type); wxMenuItem* menu_item_split(wxMenu* menu, int id); wxMenuItem* menu_item_settings(wxMenu* menu, int id, const bool is_part); wxMenu* create_add_part_popupmenu(); @@ -91,7 +91,7 @@ public: void load_subobject(int type); void load_part(ModelObject* model_object, wxArrayString& part_names, int type); - void load_lambda(const std::string& type_name); + void load_generic_subobject(const std::string& type_name, const int type); void del_subobject_item(wxDataViewItem& item); void del_settings_from_config(); void del_instances_from_object(const int obj_idx); diff --git a/src/slic3r/GUI/LambdaObjectDialog.cpp b/src/slic3r/GUI/LambdaObjectDialog.cpp index a55a5bc9b..9c89a8c04 100644 --- a/src/slic3r/GUI/LambdaObjectDialog.cpp +++ b/src/slic3r/GUI/LambdaObjectDialog.cpp @@ -49,15 +49,15 @@ LambdaObjectDialog::LambdaObjectDialog(wxWindow* parent, def.type = coFloat; def.default_value = new ConfigOptionFloat{ 1.0 }; - def.label = L("L"); + def.label = L("Length"); Option option(def, "l"); optgroup->append_single_option_line(option); - def.label = L("W"); + def.label = L("Width"); option = Option(def, "w"); optgroup->append_single_option_line(option); - def.label = L("H"); + def.label = L("Height"); option = Option(def, "h"); optgroup->append_single_option_line(option); } @@ -112,7 +112,7 @@ LambdaObjectDialog::LambdaObjectDialog(wxWindow* parent, def.type = coFloat; def.default_value = new ConfigOptionFloat{ 1.0 }; - def.label = L("H"); + def.label = L("Height"); auto option = Option(def, "slab_h"); optgroup->append_single_option_line(option); From 57c769b63b036b99cf50edb4646590b62007539e Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 6 Nov 2018 15:51:33 +0100 Subject: [PATCH 29/43] Selection of modifiers in 3D scene --- src/libslic3r/Model.cpp | 11 +++ src/libslic3r/Model.hpp | 4 ++ src/slic3r/GUI/GLCanvas3D.cpp | 111 +++++++++++++++++++++++++++--- src/slic3r/GUI/GLCanvas3D.hpp | 6 +- src/slic3r/GUI/GUI_ObjectList.cpp | 10 ++- src/slic3r/GUI/Plater.cpp | 2 + 6 files changed, 133 insertions(+), 11 deletions(-) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 9cd7846f3..15eaa89c1 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -1038,6 +1038,9 @@ double ModelObject::get_instance_min_z(size_t instance_idx) const for (const ModelVolume* v : volumes) { + if (!v->is_model_part()) + continue; + #if ENABLE_MODELVOLUME_TRANSFORM Transform3d mv = mi * v->get_matrix(); const TriangleMesh& hull = v->get_convex_hull(); @@ -1152,6 +1155,14 @@ void ModelVolume::set_material(t_model_material_id material_id, const ModelMater this->object->get_model()->add_material(material_id, material); } +#if ENABLE_MODELVOLUME_TRANSFORM +void ModelVolume::translate_geometry(const Vec3d& displacement) +{ + 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 + void ModelVolume::calculate_convex_hull() { m_convex_hull = mesh.convex_hull_3d(); diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 1850cce1f..b965f09ba 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -322,6 +322,10 @@ public: void rotate(double angle, const Vec3d& axis); void mirror(Axis axis); +#if ENABLE_MODELVOLUME_TRANSFORM + void translate_geometry(const Vec3d& displacement); +#endif // ENABLE_MODELVOLUME_TRANSFORM + void calculate_convex_hull(); const TriangleMesh& get_convex_hull() const; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index f69d798bd..958037d4c 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1197,16 +1197,30 @@ void GLCanvas3D::Selection::add(unsigned int volume_idx, bool as_single_selectio if (!m_valid || ((unsigned int)m_volumes->size() <= volume_idx)) return; - // resets the current list if needed const GLVolume* volume = (*m_volumes)[volume_idx]; - if (as_single_selection || volume->is_wipe_tower || is_wipe_tower() || volume->is_modifier || is_modifier()) + // wipe tower is already selected + if (is_wipe_tower() && volume->is_wipe_tower) + return; + + // resets the current list if needed + bool needs_reset = as_single_selection; + needs_reset |= volume->is_wipe_tower; + needs_reset |= is_wipe_tower() && !volume->is_wipe_tower; + needs_reset |= !is_modifier() && volume->is_modifier; + needs_reset |= is_modifier() && !volume->is_modifier; + + if (needs_reset) clear(); + m_mode = volume->is_modifier ? Volume : Instance; + switch (m_mode) { case Volume: { - _add_volume(volume_idx); + if (is_empty() || ((is_modifier() && volume->is_modifier) && (volume->instance_idx() == get_instance_idx()))) + _add_volume(volume_idx); + break; } case Instance: @@ -1435,6 +1449,11 @@ void GLCanvas3D::Selection::translate(const Vec3d& displacement) #endif // ENABLE_MODELVOLUME_TRANSFORM } +#if !DISABLE_INSTANCES_SYNCH + if (m_mode == Volume) + _synchronize_unselected_volumes(); +#endif // !DISABLE_INSTANCES_SYNCH + m_bounding_box_dirty = true; } @@ -1466,7 +1485,6 @@ void GLCanvas3D::Selection::rotate(const Vec3d& rotation) { // 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 @@ -1481,6 +1499,8 @@ void GLCanvas3D::Selection::rotate(const Vec3d& rotation) #if !DISABLE_INSTANCES_SYNCH if (m_mode == Instance) _synchronize_unselected_instances(); + else if (m_mode == Volume) + _synchronize_unselected_volumes(); #endif // !DISABLE_INSTANCES_SYNCH m_bounding_box_dirty = true; @@ -1497,6 +1517,7 @@ void GLCanvas3D::Selection::flattening_rotate(const Vec3d& normal) for (unsigned int i : m_list) { +#if ENABLE_MODELVOLUME_TRANSFORM Transform3d wst = m_cache.volumes_data[i].get_instance_scale_matrix() * m_cache.volumes_data[i].get_volume_scale_matrix(); Vec3d scaling_factor = Vec3d(1./wst(0,0), 1./wst(1,1), 1./wst(2,2)); @@ -1512,6 +1533,23 @@ void GLCanvas3D::Selection::flattening_rotate(const Vec3d& normal) Vec3d new_rotation = Geometry::extract_euler_angles(extra_rotation * m_cache.volumes_data[i].get_instance_rotation_matrix() ); (*m_volumes)[i]->set_instance_rotation(new_rotation); +#else + Transform3d wst = m_cache.volumes_data[i].get_scale_matrix() * m_cache.volumes_data[i].get_scale_matrix(); + Vec3d scaling_factor = Vec3d(1. / wst(0, 0), 1. / wst(1, 1), 1. / wst(2, 2)); + + Vec3d rotation = Geometry::extract_euler_angles(m_cache.volumes_data[i].get_rotation_matrix() * m_cache.volumes_data[i].get_rotation_matrix()); + Vec3d transformed_normal = Geometry::assemble_transform(Vec3d::Zero(), rotation, scaling_factor) * normal; + transformed_normal.normalize(); + + Vec3d axis = transformed_normal(2) > 0.999f ? Vec3d(1., 0., 0.) : Vec3d(transformed_normal.cross(Vec3d(0., 0., -1.))); + axis.normalize(); + + Transform3d extra_rotation = Transform3d::Identity(); + extra_rotation.rotate(Eigen::AngleAxisd(acos(-transformed_normal(2)), axis)); + + Vec3d new_rotation = Geometry::extract_euler_angles(extra_rotation * m_cache.volumes_data[i].get_rotation_matrix()); + (*m_volumes)[i]->set_rotation(new_rotation); +#endif // ENABLE_MODELVOLUME_TRANSFORM } #if !DISABLE_INSTANCES_SYNCH @@ -1553,7 +1591,6 @@ void GLCanvas3D::Selection::scale(const Vec3d& scale) 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 @@ -1569,6 +1606,8 @@ void GLCanvas3D::Selection::scale(const Vec3d& scale) #if !DISABLE_INSTANCES_SYNCH if (m_mode == Instance) _synchronize_unselected_instances(); + else if (m_mode == Volume) + _synchronize_unselected_volumes(); #endif // !DISABLE_INSTANCES_SYNCH m_bounding_box_dirty = true; @@ -1592,6 +1631,8 @@ void GLCanvas3D::Selection::mirror(Axis axis) #if !DISABLE_INSTANCES_SYNCH if (m_mode == Instance) _synchronize_unselected_instances(); + else if (m_mode == Volume) + _synchronize_unselected_volumes(); #endif // !DISABLE_INSTANCES_SYNCH m_bounding_box_dirty = true; @@ -1746,7 +1787,7 @@ void GLCanvas3D::Selection::_update_type() if (first->is_wipe_tower) m_type = WipeTower; else if (first->is_modifier) - m_type = Modifier; + m_type = SingleModifier; else { const ModelObject* model_object = m_model->objects[first->object_idx()]; @@ -1769,6 +1810,8 @@ void GLCanvas3D::Selection::_update_type() m_type = SingleFullObject; else if ((m_cache.content.begin()->second.size() == 1) && (volumes_count == (unsigned int)m_list.size())) m_type = SingleFullInstance; + else if ((*m_volumes)[*m_list.begin()]->is_modifier) + m_type = MultipleModifier; } } } @@ -1790,9 +1833,14 @@ void GLCanvas3D::Selection::_update_type() std::cout << "selection type: WipeTower" << std::endl; break; } - case Modifier: + case SingleModifier: { - std::cout << "selection type: Modifier" << std::endl; + std::cout << "selection type: SingleModifier" << std::endl; + break; + } + case MultipleModifier: + { + std::cout << "selection type: MultipleModifier" << std::endl; break; } case SingleFullObject: @@ -2012,6 +2060,53 @@ void GLCanvas3D::Selection::_synchronize_unselected_instances() } } +void GLCanvas3D::Selection::_synchronize_unselected_volumes() +{ + for (unsigned int i : m_list) + { + const GLVolume* volume = (*m_volumes)[i]; + int object_idx = volume->object_idx(); + if (object_idx >= 1000) + continue; + + int volume_idx = volume->volume_idx(); +#if ENABLE_MODELVOLUME_TRANSFORM + const Vec3d& offset = volume->get_volume_offset(); + const Vec3d& rotation = volume->get_volume_rotation(); + const Vec3d& scaling_factor = volume->get_volume_scaling_factor(); + const Vec3d& mirror = volume->get_volume_mirror(); +#else + const Vec3d& offset = volume->get_offset(); + 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 volumes. + for (unsigned int j = 0; j < (unsigned int)m_volumes->size(); ++j) + { + if (j == i) + continue; + + GLVolume* v = (*m_volumes)[j]; + if ((v->object_idx() != object_idx) || (v->volume_idx() != volume_idx)) + continue; + +#if ENABLE_MODELVOLUME_TRANSFORM + v->set_volume_offset(offset); + v->set_volume_rotation(rotation); + v->set_volume_scaling_factor(scaling_factor); + v->set_volume_mirror(mirror); +#else + v->set_offset(offset); + v->set_rotation(Vec3d(rotation)); + v->set_scaling_factor(scaling_factor); + v->set_mirror(mirror); +#endif // ENABLE_MODELVOLUME_TRANSFORM + } + } +} + const float GLCanvas3D::Gizmos::OverlayTexturesScale = 0.75f; const float GLCanvas3D::Gizmos::OverlayOffsetX = 10.0f * OverlayTexturesScale; const float GLCanvas3D::Gizmos::OverlayGapY = 5.0f * OverlayTexturesScale; diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 07bca269b..2db3cfc65 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -373,7 +373,8 @@ public: Invalid, Empty, WipeTower, - Modifier, + SingleModifier, + MultipleModifier, SingleFullObject, SingleFullInstance, Mixed @@ -483,7 +484,7 @@ public: bool is_empty() const { return m_type == Empty; } bool is_wipe_tower() const { return m_type == WipeTower; } - bool is_modifier() const { return m_type == Modifier; } + bool is_modifier() const { return (m_type == SingleModifier) || (m_type == MultipleModifier); } bool is_single_full_instance() const; bool is_single_full_object() const { return m_type == SingleFullObject; } bool is_mixed() const { return m_type == Mixed; } @@ -533,6 +534,7 @@ public: void _render_selected_volumes() const; void _render_bounding_box(const BoundingBoxf3& box, float* color) const; void _synchronize_unselected_instances(); + void _synchronize_unselected_volumes(); }; private: diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 4aed6d701..c5eb84c58 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -734,19 +734,27 @@ void ObjectList::load_part( ModelObject* model_object, if (model_object->origin_translation != Vec3d::Zero()) { object->center_around_origin(); +#if !ENABLE_MODELVOLUME_TRANSFORM object->ensure_on_bed(); +#endif // !ENABLE_MODELVOLUME_TRANSFORM delta = model_object->origin_translation - object->origin_translation; } for (auto volume : object->volumes) { +#if ENABLE_MODELVOLUME_TRANSFORM + Vec3d shift = volume->mesh.bounding_box().center(); + volume->translate_geometry(-shift); + volume->translate(delta + shift); +#endif // ENABLE_MODELVOLUME_TRANSFORM auto new_volume = model_object->add_volume(*volume); new_volume->set_type(static_cast(type)); - boost::filesystem::path(input_file).filename().string(); new_volume->name = boost::filesystem::path(input_file).filename().string(); part_names.Add(new_volume->name); +#if !ENABLE_MODELVOLUME_TRANSFORM if (delta != Vec3d::Zero()) new_volume->translate(delta); +#endif // !ENABLE_MODELVOLUME_TRANSFORM // set a default extruder value, since user can't add it manually new_volume->config.set_key_value("extruder", new ConfigOptionInt(0)); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index dadeec4ec..911c930ef 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -2255,7 +2255,9 @@ void Plater::changed_object(int obj_idx) if (list->is_parts_changed()) { // recenter and re - align to Z = 0 auto model_object = p->model.objects[obj_idx]; +#if !ENABLE_MODELVOLUME_TRANSFORM model_object->center_around_origin(); +#endif // !ENABLE_MODELVOLUME_TRANSFORM model_object->ensure_on_bed(); _3DScene::reload_scene(p->canvas3D, false); } From f9caa6f7f1bf5ecffcdb2a135a5e7dd476dc1e20 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 6 Nov 2018 16:04:30 +0100 Subject: [PATCH 30/43] Fixed backend detection of out of print volume --- src/libslic3r/Model.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 15eaa89c1..dac6f7713 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -1076,7 +1076,11 @@ unsigned int ModelObject::check_instances_print_volume_state(const BoundingBoxf3 unsigned int inside_outside = 0; for (const ModelVolume *vol : this->volumes) if (vol->is_model_part()) { +#if ENABLE_MODELVOLUME_TRANSFORM + BoundingBoxf3 bb = vol->get_convex_hull().transformed_bounding_box(model_instance->get_matrix() * vol->get_matrix()); +#else BoundingBoxf3 bb = vol->get_convex_hull().transformed_bounding_box(model_instance->get_matrix()); +#endif // ENABLE_MODELVOLUME_TRANSFORM if (print_volume.contains(bb)) inside_outside |= INSIDE; else if (print_volume.intersects(bb)) From 879a7bb9e4df9c5212b12b643da6ed3cc1dc2d17 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 6 Nov 2018 17:27:08 +0100 Subject: [PATCH 31/43] Fixed a typo --- src/libslic3r/Print.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index e4daa02b7..d1a942f3f 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -603,7 +603,7 @@ static inline bool model_volume_list_changed(const ModelObject &model_object_old size_t i_old, i_new; for (i_old = 0, i_new = 0; i_old < model_object_old.volumes.size() && i_new < model_object_new.volumes.size();) { const ModelVolume &mv_old = *model_object_old.volumes[i_old]; - const ModelVolume &mv_new = *model_object_new.volumes[i_old]; + const ModelVolume &mv_new = *model_object_new.volumes[i_new]; if (mv_old.type() != type) { ++ i_old; continue; From 00b833fbbe41e4ef8589bca8881586a25b990e92 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Tue, 6 Nov 2018 17:26:33 +0100 Subject: [PATCH 32/43] Lambda dialog is changed to default object adding (with default values), which can be modified from modifier matrix (in the future) --- src/slic3r/GUI/GUI_ObjectList.cpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index c5eb84c58..f3b1e0f47 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -768,31 +768,31 @@ void ObjectList::load_part( ModelObject* model_object, void ObjectList::load_generic_subobject(const std::string& type_name, const int type) { - if (m_selected_object_id < 0) return; - - auto dlg = new LambdaObjectDialog(GetMainWindow(), type_name); - if (dlg->ShowModal() == wxID_CANCEL) - return; + const auto obj_idx = get_selected_obj_idx(); + if (obj_idx < 0) return; const std::string name = "lambda-" + type_name; TriangleMesh mesh; - const auto params = dlg->ObjectParameters(); + auto& bed_shape = wxGetApp().preset_bundle->printers.get_edited_preset().config.option("bed_shape")->values; + const auto& sz = BoundingBoxf(bed_shape).size(); + const auto side = 0.1 * std::max(sz(0), sz(1)); + if (type_name == _("Box")) - mesh = make_cube(params.dim[0], params.dim[1], params.dim[2]); + mesh = make_cube(side, side, side); else if (type_name == _("Cylinder")) - mesh = make_cylinder(params.cyl_r, params.cyl_h); + mesh = make_cylinder(0.5*side, side); else if (type_name == _("Sphere")) - mesh = make_sphere(params.sph_rho); + mesh = make_sphere(side, PI/18); else if (type_name == _("Slab")) { - const auto& size = (*m_objects)[m_selected_object_id]->bounding_box().size(); - mesh = make_cube(size(0)*1.5, size(1)*1.5, params.slab_h); + const auto& size = (*m_objects)[obj_idx]->bounding_box().size(); + mesh = make_cube(size(0)*1.5, size(1)*1.5, size(2)*0.5); // box sets the base coordinate at 0, 0, move to center of plate and move it up to initial_z - mesh.translate(-size(0)*1.5 / 2.0, -size(1)*1.5 / 2.0, params.slab_z); + mesh.translate(-size(0)*1.5 / 2.0, -size(1)*1.5 / 2.0, 0); } mesh.repair(); - auto new_volume = (*m_objects)[m_selected_object_id]->add_volume(mesh); + auto new_volume = (*m_objects)[obj_idx]->add_volume(mesh); new_volume->set_type(static_cast(type)); new_volume->name = name; @@ -800,7 +800,7 @@ void ObjectList::load_generic_subobject(const std::string& type_name, const int new_volume->config.set_key_value("extruder", new ConfigOptionInt(0)); m_parts_changed = true; - parts_changed(m_selected_object_id); + parts_changed(obj_idx); select_item(m_objects_model->AddVolumeChild(GetSelection(), name, type)); #ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME From 6e5ce6eb613fd1e7687c243a57a2ebe341c324f7 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Tue, 6 Nov 2018 17:38:40 +0100 Subject: [PATCH 33/43] GUI_App.hpp changed to UTF-8 --- src/slic3r/GUI/GUI_App.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index 6716d73ad..3c52d29f6 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -60,7 +60,7 @@ enum ConfigMenuIDs { class Tab; -static wxString dots("…"/*, wxConvUTF8*/); +static wxString dots("…", wxConvUTF8); class GUI_App : public wxApp { From e4eec90046cafe92461d0e5ab944f12e63588aaa Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 6 Nov 2018 19:09:54 +0100 Subject: [PATCH 34/43] Fixed loading of old 3mf files. --- src/libslic3r/Config.hpp | 1 + src/slic3r/GUI/Plater.cpp | 28 +++++++++++++++++++--------- src/slic3r/GUI/Preset.cpp | 12 +++++++----- 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/src/libslic3r/Config.hpp b/src/libslic3r/Config.hpp index fb42a85ae..64548bf8d 100644 --- a/src/libslic3r/Config.hpp +++ b/src/libslic3r/Config.hpp @@ -1237,6 +1237,7 @@ public: ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) override; // Overrides ConfigBase::keys(). Collect names of all configuration values maintained by this configuration store. t_config_option_keys keys() const override; + bool empty() const { return options.empty(); } // Set a value for an opt_key. Returns true if the value did not exist yet. // This DynamicConfig will take ownership of opt. diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 911c930ef..f5561a5ec 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1151,16 +1151,26 @@ std::vector Plater::priv::load_files(const std::vector &input_ try { if (type_3mf || type_zip_amf) { DynamicPrintConfig config; - config.apply(FullPrintConfig::defaults()); - model = Slic3r::Model::read_from_archive(path.string(), &config, false); - Preset::normalize(config); - wxGetApp().preset_bundle->load_config_model(filename.string(), std::move(config)); - for (const auto &kv : main_frame->options_tabs()) { kv.second->load_current_preset(); } + { + DynamicPrintConfig config_loaded; + model = Slic3r::Model::read_from_archive(path.string(), &config_loaded, false); + // Based on the printer technology field found in the loaded config, select the base for the config, + PrinterTechnology printer_technology = Preset::printer_technology(config_loaded); + if (! config_loaded.empty()) { + config.apply(printer_technology == ptFFF ? + static_cast(FullPrintConfig::defaults()) : + static_cast(SLAFullPrintConfig::defaults())); + // and place the loaded config over the base. + config += std::move(config_loaded); + } + } + if (! config.empty()) { + Preset::normalize(config); + wxGetApp().preset_bundle->load_config_model(filename.string(), std::move(config)); + for (const auto &kv : main_frame->options_tabs()) + kv.second->load_current_preset(); + } wxGetApp().app_config->update_config_dir(path.parent_path().string()); - // forces the update of the config here, or it will invalidate the imported layer heights profile if done using the timer - // and if the config contains a "layer_height" different from the current defined one - // TODO: - // $self->async_apply_config; } else { model = Slic3r::Model::read_from_file(path.string(), nullptr, false); for (auto obj : model.objects) diff --git a/src/slic3r/GUI/Preset.cpp b/src/slic3r/GUI/Preset.cpp index bd43d01ca..892b391c2 100644 --- a/src/slic3r/GUI/Preset.cpp +++ b/src/slic3r/GUI/Preset.cpp @@ -170,10 +170,12 @@ void Preset::set_num_extruders(DynamicPrintConfig &config, unsigned int num_extr { const auto &defaults = FullPrintConfig::defaults(); for (const std::string &key : Preset::nozzle_options()) { + if (key == "default_filament_profile") + continue; auto *opt = config.option(key, false); assert(opt != nullptr); assert(opt->is_vector()); - if (opt != nullptr && opt->is_vector() && key != "default_filament_profile") + if (opt != nullptr && opt->is_vector()) static_cast(opt)->resize(num_extruders, defaults.option(key)); } } @@ -202,8 +204,7 @@ void Preset::normalize(DynamicPrintConfig &config) // The following keys are mandatory for the UI, but they are not part of FullPrintConfig, therefore they are handled separately. for (const std::string &key : { "filament_settings_id" }) { auto *opt = config.option(key, false); - assert(opt != nullptr); - assert(opt->type() == coStrings); + assert(opt == nullptr || opt->type() == coStrings); if (opt != nullptr && opt->type() == coStrings) static_cast(opt)->values.resize(n, std::string()); } @@ -534,7 +535,8 @@ Preset& PresetCollection::load_external_preset( cfg.apply_only(config, cfg.keys(), true); // Is there a preset already loaded with the name stored inside the config? std::deque::iterator it = this->find_preset_internal(original_name); - if (it != m_presets.end() && it->name == original_name && profile_print_params_same(it->config, cfg)) { + bool found = it != m_presets.end() && it->name == original_name; + if (found && profile_print_params_same(it->config, cfg)) { // The preset exists and it matches the values stored inside config. if (select) this->select_preset(it - m_presets.begin()); @@ -542,7 +544,7 @@ Preset& PresetCollection::load_external_preset( } // Update the "inherits" field. std::string &inherits = Preset::inherits(cfg); - if (it != m_presets.end() && inherits.empty()) { + if (found && inherits.empty()) { // There is a profile with the same name already loaded. Should we update the "inherits" field? if (it->vendor == nullptr) inherits = it->inherits(); From f4b16bb242139cb0dc0ee00a8625aae9a6807d9a Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Wed, 7 Nov 2018 10:34:44 +0100 Subject: [PATCH 35/43] Added new selection states - Select parts/modifiers from first instance only from right panel --- src/slic3r/GUI/GLCanvas3D.cpp | 51 +++++++++++++++++++++++++++---- src/slic3r/GUI/GLCanvas3D.hpp | 5 ++- src/slic3r/GUI/GUI_ObjectList.cpp | 2 +- 3 files changed, 50 insertions(+), 8 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 958037d4c..f9a265829 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1325,7 +1325,7 @@ void GLCanvas3D::Selection::remove_instance(unsigned int object_idx, unsigned in m_bounding_box_dirty = true; } -void GLCanvas3D::Selection::add_volume(unsigned int object_idx, unsigned int volume_idx, bool as_single_selection) +void GLCanvas3D::Selection::add_volume(unsigned int object_idx, unsigned int volume_idx, int instance_idx, bool as_single_selection) { if (!m_valid) return; @@ -1338,7 +1338,10 @@ void GLCanvas3D::Selection::add_volume(unsigned int object_idx, unsigned int vol { GLVolume* v = (*m_volumes)[i]; if ((v->object_idx() == object_idx) && (v->volume_idx() == volume_idx)) + { + if ((instance_idx != -1) && (v->instance_idx() == instance_idx)) _add_volume(i); + } } _update_type(); @@ -1797,6 +1800,8 @@ void GLCanvas3D::Selection::_update_type() m_type = SingleFullObject; else if (volumes_count == 1) // instances_count > 1 m_type = SingleFullInstance; + else + m_type = SingleVolume; } } else @@ -1806,12 +1811,30 @@ void GLCanvas3D::Selection::_update_type() const ModelObject* model_object = m_model->objects[m_cache.content.begin()->first]; unsigned int volumes_count = (unsigned int)model_object->volumes.size(); unsigned int instances_count = (unsigned int)model_object->instances.size(); + unsigned int selected_instances_count = (unsigned int)m_cache.content.begin()->second.size(); if (volumes_count * instances_count == (unsigned int)m_list.size()) m_type = SingleFullObject; - else if ((m_cache.content.begin()->second.size() == 1) && (volumes_count == (unsigned int)m_list.size())) - m_type = SingleFullInstance; - else if ((*m_volumes)[*m_list.begin()]->is_modifier) - m_type = MultipleModifier; + else if (selected_instances_count == 1) + { + if (volumes_count == (unsigned int)m_list.size()) + m_type = SingleFullInstance; + else + { + unsigned int modifiers_count = 0; + for (unsigned int i : m_list) + { + if ((*m_volumes)[i]->is_modifier) + ++modifiers_count; + } + + if (modifiers_count == 0) + m_type = MultipleVolume; + else if (modifiers_count == (unsigned int)m_list.size()) + m_type = MultipleModifier; + } + } + else if ((selected_instances_count > 1) && (selected_instances_count * volumes_count == (unsigned int)m_list.size())) + m_type = MultipleFullInstance; } } } @@ -1843,6 +1866,16 @@ void GLCanvas3D::Selection::_update_type() std::cout << "selection type: MultipleModifier" << std::endl; break; } + case SingleVolume: + { + std::cout << "selection type: SingleVolume" << std::endl; + break; + } + case MultipleVolume: + { + std::cout << "selection type: MultipleVolume" << std::endl; + break; + } case SingleFullObject: { std::cout << "selection type: SingleFullObject" << std::endl; @@ -1853,6 +1886,11 @@ void GLCanvas3D::Selection::_update_type() std::cout << "selection type: SingleFullInstance" << std::endl; break; } + case MultipleFullInstance: + { + std::cout << "selection type: MultipleFullInstance" << std::endl; + break; + } case Mixed: { std::cout << "selection type: Mixed" << std::endl; @@ -1963,11 +2001,12 @@ void GLCanvas3D::Selection::_render_bounding_box(const BoundingBoxf3& box, float Vec3f b_min = box.min.cast(); Vec3f b_max = box.max.cast(); - Vec3f size = 0.25f * box.size().cast(); + Vec3f size = 0.2f * box.size().cast(); ::glEnable(GL_DEPTH_TEST); ::glColor3fv(color); + ::glLineWidth(2.0f); ::glBegin(GL_LINES); diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 2db3cfc65..f68c2a702 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -375,8 +375,11 @@ public: WipeTower, SingleModifier, MultipleModifier, + SingleVolume, + MultipleVolume, SingleFullObject, SingleFullInstance, + MultipleFullInstance, Mixed }; @@ -477,7 +480,7 @@ public: void add_instance(unsigned int object_idx, unsigned int instance_idx, bool as_single_selection = true); void remove_instance(unsigned int object_idx, unsigned int instance_idx); - void add_volume(unsigned int object_idx, unsigned int volume_idx, bool as_single_selection = true); + void add_volume(unsigned int object_idx, unsigned int volume_idx, int instance_idx, bool as_single_selection = true); void remove_volume(unsigned int object_idx, unsigned int volume_idx); void clear(); diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index f3b1e0f47..63d9740ca 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -1243,7 +1243,7 @@ void ObjectList::update_selections_on_canvas() if (m_objects_model->GetItemType(item) == itVolume) { const int obj_idx = m_objects_model->GetIdByItem(m_objects_model->GetParent(item)); const int vol_idx = m_objects_model->GetVolumeIdByItem(item); - selection.add_volume(obj_idx, vol_idx, as_single_selection); + selection.add_volume(obj_idx, vol_idx, 0, as_single_selection); } else if (m_objects_model->GetItemType(item) == itInstance) { const int obj_idx = m_objects_model->GetIdByItem(m_objects_model->GetTopParent(item)); From 102bc99958b8f904c7c36fa3d2fb138954c4b082 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Wed, 7 Nov 2018 12:11:34 +0100 Subject: [PATCH 36/43] Only one instance enabled when selecting sub parts --- src/slic3r/GUI/3DScene.cpp | 4 +++ src/slic3r/GUI/3DScene.hpp | 3 ++ src/slic3r/GUI/GLCanvas3D.cpp | 68 ++++++++++++++++++++++++++++++++--- src/slic3r/GUI/GLCanvas3D.hpp | 1 + 4 files changed, 72 insertions(+), 4 deletions(-) diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 11f0b570e..565ef94fb 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -193,6 +193,7 @@ const float GLVolume::SELECTED_COLOR[4] = { 0.0f, 1.0f, 0.0f, 1.0f }; const float GLVolume::HOVER_COLOR[4] = { 0.4f, 0.9f, 0.1f, 1.0f }; const float GLVolume::OUTSIDE_COLOR[4] = { 0.0f, 0.38f, 0.8f, 1.0f }; const float GLVolume::SELECTED_OUTSIDE_COLOR[4] = { 0.19f, 0.58f, 1.0f, 1.0f }; +const float GLVolume::DISABLED_COLOR[4] = { 0.25f, 0.25f, 0.25f, 1.0f }; GLVolume::GLVolume(float r, float g, float b, float a) #if ENABLE_MODELVOLUME_TRANSFORM @@ -211,6 +212,7 @@ GLVolume::GLVolume(float r, float g, float b, float a) , composite_id(-1) , extruder_id(0) , selected(false) + , disabled(false) , is_active(true) , zoom_to_volumes(true) , shader_outside_printer_detection_enabled(false) @@ -252,6 +254,8 @@ void GLVolume::set_render_color() set_render_color(is_outside ? SELECTED_OUTSIDE_COLOR : SELECTED_COLOR, 4); else if (hover) set_render_color(HOVER_COLOR, 4); + else if (disabled) + set_render_color(DISABLED_COLOR, 4); else if (is_outside && shader_outside_printer_detection_enabled) set_render_color(OUTSIDE_COLOR, 4); else diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index 8384e11b8..87c9df385 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -249,6 +249,7 @@ public: static const float HOVER_COLOR[4]; static const float OUTSIDE_COLOR[4]; static const float SELECTED_OUTSIDE_COLOR[4]; + static const float DISABLED_COLOR[4]; GLVolume(float r = 1.f, float g = 1.f, float b = 1.f, float a = 1.f); GLVolume(const float *rgba) : GLVolume(rgba[0], rgba[1], rgba[2], rgba[3]) {} @@ -295,6 +296,8 @@ public: int extruder_id; // Is this object selected? bool selected; + // Is this object disabled from selection? + bool disabled; // Whether or not this volume is active for rendering bool is_active; // Whether or not to use this volume when applying zoom_to_volumes() diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index f9a265829..1cd5fe6fc 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1212,13 +1212,14 @@ void GLCanvas3D::Selection::add(unsigned int volume_idx, bool as_single_selectio if (needs_reset) clear(); - m_mode = volume->is_modifier ? Volume : Instance; + if (volume->is_modifier) + m_mode = Volume; switch (m_mode) { case Volume: { - if (is_empty() || ((is_modifier() && volume->is_modifier) && (volume->instance_idx() == get_instance_idx()))) + if (is_empty() || (volume->instance_idx() == get_instance_idx())) _add_volume(volume_idx); break; @@ -1282,6 +1283,8 @@ void GLCanvas3D::Selection::add_object(unsigned int object_idx, bool as_single_s if (as_single_selection) clear(); + m_mode = Instance; + _add_object(object_idx); _update_type(); @@ -1308,6 +1311,8 @@ void GLCanvas3D::Selection::add_instance(unsigned int object_idx, unsigned int i if (as_single_selection) clear(); + m_mode = Instance; + _add_instance(object_idx, instance_idx); _update_type(); @@ -1334,13 +1339,15 @@ void GLCanvas3D::Selection::add_volume(unsigned int object_idx, unsigned int vol if (as_single_selection) clear(); + m_mode = Volume; + for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i) { GLVolume* v = (*m_volumes)[i]; if ((v->object_idx() == object_idx) && (v->volume_idx() == volume_idx)) { if ((instance_idx != -1) && (v->instance_idx() == instance_idx)) - _add_volume(i); + _add_volume(i); } } @@ -1375,6 +1382,7 @@ void GLCanvas3D::Selection::clear() } m_list.clear(); + _update_type(); m_bounding_box_dirty = true; } @@ -1754,6 +1762,7 @@ void GLCanvas3D::Selection::render() const // render cumulative bounding box of selected volumes _render_selected_volumes(); + _render_synchronized_volumes(); } void GLCanvas3D::Selection::_update_valid() @@ -1778,6 +1787,8 @@ void GLCanvas3D::Selection::_update_type() obj_it->second.insert(inst_idx); } + bool requires_disable = false; + if (!m_valid) m_type = Invalid; else @@ -1790,7 +1801,10 @@ void GLCanvas3D::Selection::_update_type() if (first->is_wipe_tower) m_type = WipeTower; else if (first->is_modifier) + { m_type = SingleModifier; + requires_disable = true; + } else { const ModelObject* model_object = m_model->objects[first->object_idx()]; @@ -1801,7 +1815,10 @@ void GLCanvas3D::Selection::_update_type() else if (volumes_count == 1) // instances_count > 1 m_type = SingleFullInstance; else + { m_type = SingleVolume; + requires_disable = true; + } } } else @@ -1828,9 +1845,15 @@ void GLCanvas3D::Selection::_update_type() } if (modifiers_count == 0) + { m_type = MultipleVolume; + requires_disable = true; + } else if (modifiers_count == (unsigned int)m_list.size()) + { m_type = MultipleModifier; + requires_disable = true; + } } } else if ((selected_instances_count > 1) && (selected_instances_count * volumes_count == (unsigned int)m_list.size())) @@ -1839,6 +1862,13 @@ void GLCanvas3D::Selection::_update_type() } } + int object_idx = get_object_idx(); + int instance_idx = get_instance_idx(); + for (GLVolume* v : *m_volumes) + { + v->disabled = requires_disable ? (v->object_idx() != object_idx) || (v->instance_idx() != instance_idx) : false; + } + switch (m_type) { case Invalid: @@ -1994,6 +2024,33 @@ void GLCanvas3D::Selection::_render_selected_volumes() const _render_bounding_box(get_bounding_box(), color); } +void GLCanvas3D::Selection::_render_synchronized_volumes() const +{ + if (m_mode == Instance) + return; + + float color[3] = { 1.0f, 1.0f, 0.0f }; + + for (unsigned int i : m_list) + { + const GLVolume* volume = (*m_volumes)[i]; + int object_idx = volume->object_idx(); + int instance_idx = volume->instance_idx(); + int volume_idx = volume->volume_idx(); + for (unsigned int j = 0; j < (unsigned int)m_volumes->size(); ++j) + { + if (i == j) + continue; + + const GLVolume* v = (*m_volumes)[j]; + if ((v->object_idx() != object_idx) || (v->volume_idx() != volume_idx)) + continue; + + _render_bounding_box(v->transformed_convex_hull_bounding_box(), color); + } + } +} + void GLCanvas3D::Selection::_render_bounding_box(const BoundingBoxf3& box, float* color) const { if (color == nullptr) @@ -4253,6 +4310,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) #endif // ENABLE_GIZMOS_RESET { m_selection.clear(); + m_selection.set_mode(Selection::Instance); wxGetApp().obj_manipul()->update_settings_value(m_selection); post_event(SimpleEvent(EVT_GLCANVAS_OBJECT_SELECT)); _update_gizmos_data(); @@ -4968,7 +5026,9 @@ void GLCanvas3D::_render_volumes(bool fake_colors) const ::glColor4fv(vol->render_color); } - vol->render(); + if (!fake_colors || !vol->disabled) + vol->render(); + ++volume_id; } diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index f68c2a702..b1b78d3b4 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -535,6 +535,7 @@ public: void _remove_object(unsigned int object_idx); void _calc_bounding_box() const; void _render_selected_volumes() const; + void _render_synchronized_volumes() const; void _render_bounding_box(const BoundingBoxf3& box, float* color) const; void _synchronize_unselected_instances(); void _synchronize_unselected_volumes(); From b05aa00089ed6097b1467caaf594456936af0919 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Wed, 7 Nov 2018 14:01:03 +0100 Subject: [PATCH 37/43] Fixed update of ModelVolume offset after GLVolume manipulation --- src/libslic3r/Model.cpp | 24 ++++++++++++------------ src/slic3r/GUI/GLCanvas3D.cpp | 27 +++++++++++++++++++-------- 2 files changed, 31 insertions(+), 20 deletions(-) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index dac6f7713..20bf9e367 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -1246,7 +1246,7 @@ size_t ModelVolume::split(unsigned int max_extruders) void ModelVolume::translate(const Vec3d& displacement) { #if ENABLE_MODELVOLUME_TRANSFORM - m_transformation.set_offset(m_transformation.get_offset() + displacement); + set_offset(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)); @@ -1256,7 +1256,7 @@ void ModelVolume::translate(const Vec3d& displacement) void ModelVolume::scale(const Vec3d& scaling_factors) { #if ENABLE_MODELVOLUME_TRANSFORM - m_transformation.set_scaling_factor(m_transformation.get_scaling_factor().cwiseProduct(scaling_factors)); + set_scaling_factor(get_scaling_factor().cwiseProduct(scaling_factors)); #else mesh.scale(scaling_factors); m_convex_hull.scale(scaling_factors); @@ -1281,7 +1281,7 @@ void ModelVolume::rotate(double angle, Axis axis) void ModelVolume::rotate(double angle, const Vec3d& axis) { #if ENABLE_MODELVOLUME_TRANSFORM - m_transformation.set_rotation(m_transformation.get_rotation() + Geometry::extract_euler_angles(Eigen::Quaterniond(Eigen::AngleAxisd(angle, axis)).toRotationMatrix())); + set_rotation(get_rotation() + Geometry::extract_euler_angles(Eigen::Quaterniond(Eigen::AngleAxisd(angle, axis)).toRotationMatrix())); #else mesh.rotate(angle, axis); m_convex_hull.rotate(angle, axis); @@ -1291,14 +1291,14 @@ void ModelVolume::rotate(double angle, const Vec3d& axis) void ModelVolume::mirror(Axis axis) { #if ENABLE_MODELVOLUME_TRANSFORM - Vec3d mirror = m_transformation.get_mirror(); + Vec3d mirror = get_mirror(); switch (axis) { case X: { mirror(0) *= -1.0; break; } case Y: { mirror(1) *= -1.0; break; } case Z: { mirror(2) *= -1.0; break; } } - m_transformation.set_mirror(mirror); + set_mirror(mirror); #else mesh.mirror(axis); m_convex_hull.mirror(axis); @@ -1375,10 +1375,10 @@ BoundingBoxf3 ModelInstance::transform_mesh_bounding_box(const TriangleMesh* mes for (unsigned int i = 0; i < 3; ++i) { #if ENABLE_MODELVOLUME_TRANSFORM - if (std::abs(m_transformation.get_scaling_factor((Axis)i)-1.0) > EPSILON) + if (std::abs(get_scaling_factor((Axis)i)-1.0) > EPSILON) { - bbox.min(i) *= m_transformation.get_scaling_factor((Axis)i); - bbox.max(i) *= m_transformation.get_scaling_factor((Axis)i); + bbox.min(i) *= get_scaling_factor((Axis)i); + bbox.max(i) *= get_scaling_factor((Axis)i); #else if (std::abs(this->m_scaling_factor(i) - 1.0) > EPSILON) { @@ -1391,8 +1391,8 @@ BoundingBoxf3 ModelInstance::transform_mesh_bounding_box(const TriangleMesh* mes // Translate the bounding box. if (! dont_translate) { #if ENABLE_MODELVOLUME_TRANSFORM - bbox.min += m_transformation.get_offset(); - bbox.max += m_transformation.get_offset(); + bbox.min += get_offset(); + bbox.max += get_offset(); #else bbox.min += this->m_offset; bbox.max += this->m_offset; @@ -1416,9 +1416,9 @@ void ModelInstance::transform_polygon(Polygon* polygon) const { #if ENABLE_MODELVOLUME_TRANSFORM // CHECK_ME -> Is the following correct or it should take in account all three rotations ? - polygon->rotate(m_transformation.get_rotation(Z)); // rotate around polygon origin + polygon->rotate(get_rotation(Z)); // rotate around polygon origin // CHECK_ME -> Is the following correct ? - polygon->scale(m_transformation.get_scaling_factor(X), m_transformation.get_scaling_factor(Y)); // scale around polygon origin + polygon->scale(get_scaling_factor(X), get_scaling_factor(Y)); // scale around polygon origin #else // CHECK_ME -> Is the following correct or it should take in account all three rotations ? polygon->rotate(this->m_rotation(2)); // rotate around polygon origin diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 1cd5fe6fc..bcfff43db 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -6274,35 +6274,45 @@ void GLCanvas3D::_on_move() if (m_model == nullptr) return; - std::set> done; // prevent moving instances twice + std::set> done; // keeps track of moved instances bool object_moved = false; Vec3d wipe_tower_origin = Vec3d::Zero(); + Selection::EMode selection_mode = m_selection.get_mode(); + for (const GLVolume* v : m_volumes.volumes) { int object_idx = v->object_idx(); int instance_idx = v->instance_idx(); + int volume_idx = v->volume_idx(); - // prevent moving instances twice std::pair done_id(object_idx, instance_idx); - if (done.find(done_id) != done.end()) - continue; - if (object_idx < 1000) + if ((0 <= object_idx) && (object_idx < (int)m_model->objects.size())) { done.insert(done_id); - // Move instances. + // Move instances/volumes 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()); + if (selection_mode == Selection::Instance) + { + model_object->instances[instance_idx]->set_offset(v->get_instance_offset()); + object_moved = true; + } + else if (selection_mode == Selection::Volume) + { + model_object->volumes[volume_idx]->set_offset(v->get_volume_offset()); + object_moved = true; + } + if (object_moved) #else model_object->instances[instance_idx]->set_offset(v->get_offset()); + object_moved = true; #endif // ENABLE_MODELVOLUME_TRANSFORM model_object->invalidate_bounding_box(); - object_moved = true; } } else if (object_idx == 1000) @@ -6314,6 +6324,7 @@ void GLCanvas3D::_on_move() #endif // ENABLE_MODELVOLUME_TRANSFORM } + // Fixes sinking/flying instances for (const std::pair& i : done) { ModelObject* m = m_model->objects[i.first]; From 92528ebcb38e1bc26d32fd57dea289a0ea2b3e0b Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Wed, 7 Nov 2018 14:15:04 +0100 Subject: [PATCH 38/43] Fixed update of ModelVolume rotation after GLVolume manipulation --- src/slic3r/GUI/GLCanvas3D.cpp | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index bcfff43db..8b70d9949 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -6345,30 +6345,36 @@ void GLCanvas3D::_on_rotate() if (m_model == nullptr) return; - std::set> done; // prevent rotating instances twice + std::set> done; // keeps track of moved instances + Selection::EMode selection_mode = m_selection.get_mode(); + for (const GLVolume* v : m_volumes.volumes) { int object_idx = v->object_idx(); - if (object_idx >= 1000) + if ((object_idx < 0) || ((int)m_model->objects.size() <= object_idx)) continue; int instance_idx = v->instance_idx(); + int volume_idx = v->volume_idx(); - // prevent rotating instances twice - std::pair done_id(object_idx, instance_idx); - if (done.find(done_id) != done.end()) - continue; + done.insert(std::pair(object_idx, instance_idx)); - done.insert(done_id); - - // Rotate instances. + // Rotate instances/volumes. 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()); + if (selection_mode == Selection::Instance) + { + model_object->instances[instance_idx]->set_rotation(v->get_instance_rotation()); + model_object->instances[instance_idx]->set_offset(v->get_instance_offset()); + } + else if (selection_mode == Selection::Volume) + { + model_object->volumes[volume_idx]->set_rotation(v->get_volume_rotation()); + model_object->volumes[volume_idx]->set_offset(v->get_volume_offset()); + } #else model_object->instances[instance_idx]->set_rotation(v->get_rotation()); model_object->instances[instance_idx]->set_offset(v->get_offset()); @@ -6377,6 +6383,7 @@ void GLCanvas3D::_on_rotate() } } + // Fixes sinking/flying instances for (const std::pair& i : done) { ModelObject* m = m_model->objects[i.first]; From 69208c4f436ca119e14386081eabce0e987a1387 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Wed, 7 Nov 2018 14:24:10 +0100 Subject: [PATCH 39/43] Fixed update of ModelVolume scale after GLVolume manipulation --- src/slic3r/GUI/GLCanvas3D.cpp | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 8b70d9949..68798dd9d 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -6274,7 +6274,7 @@ void GLCanvas3D::_on_move() if (m_model == nullptr) return; - std::set> done; // keeps track of moved instances + std::set> done; // keeps track of modified instances bool object_moved = false; Vec3d wipe_tower_origin = Vec3d::Zero(); @@ -6345,7 +6345,7 @@ void GLCanvas3D::_on_rotate() if (m_model == nullptr) return; - std::set> done; // keeps track of moved instances + std::set> done; // keeps track of modified instances Selection::EMode selection_mode = m_selection.get_mode(); @@ -6400,30 +6400,36 @@ void GLCanvas3D::_on_scale() if (m_model == nullptr) return; - std::set> done; // prevent scaling instances twice + std::set> done; // keeps track of modified instances + + Selection::EMode selection_mode = m_selection.get_mode(); for (const GLVolume* v : m_volumes.volumes) { int object_idx = v->object_idx(); - if (object_idx >= 1000) + if ((object_idx < 0) || ((int)m_model->objects.size() <= object_idx)) continue; int instance_idx = v->instance_idx(); + int volume_idx = v->volume_idx(); - // prevent scaling instances twice - std::pair done_id(object_idx, instance_idx); - if (done.find(done_id) != done.end()) - continue; - - done.insert(done_id); + done.insert(std::pair(object_idx, instance_idx)); // Rotate instances. 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()); + if (selection_mode == Selection::Instance) + { + 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 if (selection_mode == Selection::Volume) + { + model_object->volumes[volume_idx]->set_scaling_factor(v->get_volume_scaling_factor()); + model_object->volumes[volume_idx]->set_offset(v->get_volume_offset()); + } #else model_object->instances[instance_idx]->set_scaling_factor(v->get_scaling_factor()); model_object->instances[instance_idx]->set_offset(v->get_offset()); @@ -6432,6 +6438,7 @@ void GLCanvas3D::_on_scale() } } + // Fixes sinking/flying instances for (const std::pair& i : done) { ModelObject* m = m_model->objects[i.first]; From 9ca9e2a5454ac96758182a2fb7447d36cf7ee67c Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 7 Nov 2018 14:44:47 +0100 Subject: [PATCH 40/43] Merge branch lm_colorprint_integration into dev_native + deleting ticks outside slider range --- src/libslic3r/GCode.cpp | 15 ++++++++++++++ src/libslic3r/GCode.hpp | 3 +++ src/libslic3r/Print.cpp | 1 + src/libslic3r/PrintConfig.cpp | 6 ++++++ src/libslic3r/PrintConfig.hpp | 2 ++ src/slic3r/GUI/GUI_Preview.cpp | 21 +++++++++++++++++++ src/slic3r/GUI/PresetBundle.cpp | 1 + src/slic3r/GUI/wxExtensions.cpp | 36 +++++++++++++++++++++++++++++++-- src/slic3r/GUI/wxExtensions.hpp | 6 ++++++ 9 files changed, 89 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 765c8b8c1..dcd4d2ab1 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -601,6 +601,9 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) this->apply_print_config(print.config()); this->set_extruders(print.extruders()); + // Initialize colorprint. + m_colorprint_heights = cast(print.config().colorprint_heights.values); + // Initialize autospeed. { // get the minimum cross-section used in the print @@ -1319,6 +1322,18 @@ void GCode::process_layer( m_second_layer_things_done = true; } + // Let's issue a filament change command if requested at this layer. + // In case there are more toolchange requests that weren't done yet and should happen simultaneously, erase them all. + // (Layers can be close to each other, model could have been resliced with bigger layer height, ...). + bool colorprint_change = false; + while (!m_colorprint_heights.empty() && m_colorprint_heights.front()-EPSILON < layer.print_z) { + m_colorprint_heights.erase(m_colorprint_heights.begin()); + colorprint_change = true; + } + if (colorprint_change) + gcode += "M600\n"; + + // Extrude skirt at the print_z of the raft layers and normal object layers // not at the print_z of the interlaced support material layers. bool extrude_skirt = diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index 45f17a68a..bf65311db 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -317,6 +317,9 @@ protected: bool m_second_layer_things_done; // Index of a last object copy extruded. std::pair m_last_obj_copy; + // Layer heights for colorprint - updated before the export and erased during the process + // so no toolchange occurs twice. + std::vector m_colorprint_heights; // Time estimators GCodeTimeEstimator m_normal_time_estimator; diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index d1a942f3f..41e5f067d 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -124,6 +124,7 @@ bool Print::invalidate_state_by_config_options(const std::vectormode = comExpert; def->default_value = new ConfigOptionBool(false); + def = this->add("colorprint_heights", coFloats); + def->label = L("Colorprint height"); + def->tooltip = L("Heights at which a filament change is to occur. "); + def->cli = "colorprint-heights=f@"; + def->default_value = new ConfigOptionFloats { }; + def = this->add("compatible_printers", coStrings); def->label = L("Compatible printers"); def->mode = comAdvanced; diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index d92b3758d..87a882c64 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -704,6 +704,7 @@ public: ConfigOptionInts bridge_fan_speed; ConfigOptionFloat brim_width; ConfigOptionBool complete_objects; + ConfigOptionFloats colorprint_heights; ConfigOptionBools cooling; ConfigOptionFloat default_acceleration; ConfigOptionInts disable_fan_first_layers; @@ -781,6 +782,7 @@ protected: OPT_PTR(bridge_fan_speed); OPT_PTR(brim_width); OPT_PTR(complete_objects); + OPT_PTR(colorprint_heights); OPT_PTR(cooling); OPT_PTR(default_acceleration); OPT_PTR(disable_fan_first_layers); diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index 5618eab04..78f8b7462 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -1,5 +1,6 @@ #include "../../libslic3r/libslic3r.h" #include "GUI_Preview.hpp" +#include "GUI_App.hpp" #include "GUI.hpp" #include "AppConfig.hpp" #include "3DScene.hpp" @@ -22,6 +23,7 @@ namespace Slic3r { namespace GUI { + Preview::Preview(wxNotebook* notebook, DynamicPrintConfig* config, Print* print, GCodePreviewData* gcode_preview_data) : m_canvas(nullptr) , m_double_slider_sizer(nullptr) @@ -482,6 +484,11 @@ void Preview::create_double_slider() if (IsShown()) m_canvas->Refresh(); }); + + Bind(wxCUSTOMEVT_TICKSCHANGED, [this](wxEvent&) { + auto& config = wxGetApp().preset_bundle->project_config; + ((config.option("colorprint_heights"))->values) = (m_slider->GetTicksValues()); + }); } void Preview::update_double_slider(bool force_sliders_full_range) @@ -495,6 +502,11 @@ void Preview::update_double_slider(bool force_sliders_full_range) m_slider->SetMaxValue(layers_z.size() - 1); m_slider->SetSliderValues(values); + const auto& config = wxGetApp().preset_bundle->project_config; + const std::vector &ticks_from_config = (config.option("colorprint_heights"))->values; + + m_slider->SetTicksValues(ticks_from_config); + set_double_slider_thumbs(force_sliders_full_range, layers_z, z_low, z_high); } @@ -515,6 +527,15 @@ void Preview::fill_slider_values(std::vector> &values, break; } } + + // All ticks that would end up outside the slider range should be erased. + // TODO: this should probably be placed into more appropriate part of code, + // this way it relies on the Preview tab being active. + auto& config = wxGetApp().preset_bundle->project_config; + std::vector &ticks_from_config = (config.option("colorprint_heights"))->values; + ticks_from_config.erase(std::remove_if(ticks_from_config.begin(), ticks_from_config.end(), + [values](double val) { return values.back().second < val; }), + ticks_from_config.end()); } void Preview::set_double_slider_thumbs(const bool force_sliders_full_range, diff --git a/src/slic3r/GUI/PresetBundle.cpp b/src/slic3r/GUI/PresetBundle.cpp index f22299b7c..5e42501b6 100644 --- a/src/slic3r/GUI/PresetBundle.cpp +++ b/src/slic3r/GUI/PresetBundle.cpp @@ -36,6 +36,7 @@ namespace Slic3r { static std::vector s_project_options { + "colorprint_heights", "wiping_volumes_extruders", "wiping_volumes_matrix" }; diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index cd6cf171f..52b6a01e9 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -11,6 +11,8 @@ #include "GUI_ObjectList.hpp" #include "Model.hpp" +wxDEFINE_EVENT(wxCUSTOMEVT_TICKSCHANGED, wxEvent); + wxMenuItem* append_menu_item(wxMenu* menu, int id, const wxString& string, const wxString& description, std::function cb, const std::string& icon, wxEvtHandler* event_handler) { @@ -1189,7 +1191,6 @@ wxSize PrusaBitmapTextRenderer::GetSize() const // ---------------------------------------------------------------------------- // PrusaDoubleSlider // ---------------------------------------------------------------------------- - PrusaDoubleSlider::PrusaDoubleSlider(wxWindow *parent, wxWindowID id, int lowerValue, @@ -1371,6 +1372,34 @@ double PrusaDoubleSlider::get_double_value(const SelectedSlider& selection) cons return m_values[selection == ssLower ? m_lower_value : m_higher_value].second; } +std::vector PrusaDoubleSlider::GetTicksValues() const +{ + std::vector values; + + if (!m_values.empty()) + for (auto tick : m_ticks) + values.push_back(m_values[tick].second); + + return values; +} + +void PrusaDoubleSlider::SetTicksValues(const std::vector& heights) +{ + if (m_values.empty()) + return; + + m_ticks.clear(); + unsigned int i = 0; + for (auto h : heights) { + while (i < m_values.size() && m_values[i].second - 1e-6 < h) + ++i; + if (i == m_values.size()) + return; + m_ticks.insert(i); + } + +} + void PrusaDoubleSlider::get_lower_and_higher_position(int& lower_pos, int& higher_pos) { const double step = get_scroll_step(); @@ -1795,10 +1824,13 @@ void PrusaDoubleSlider::action_tick(const TicksAction action) m_ticks.insert(tick); else if (it != m_ticks.end() && action == taDel) m_ticks.erase(tick); - else + else { + wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED)); return; + } } + wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED)); Refresh(); Update(); } diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp index 6293fb962..e5e4600da 100644 --- a/src/slic3r/GUI/wxExtensions.hpp +++ b/src/slic3r/GUI/wxExtensions.hpp @@ -622,6 +622,9 @@ private: // PrusaDoubleSlider // ---------------------------------------------------------------------------- +// custom message the slider sends to its parent to notify a tick-change: +wxDECLARE_EVENT(wxCUSTOMEVT_TICKSCHANGED, wxEvent); + enum SelectedSlider { ssUndef, ssLower, @@ -632,6 +635,7 @@ enum TicksAction{ taAdd, taDel }; + class PrusaDoubleSlider : public wxControl { public: @@ -669,6 +673,8 @@ public: m_values = values; } void ChangeOneLayerLock(); + std::vector GetTicksValues() const; + void SetTicksValues(const std::vector& heights); void OnPaint(wxPaintEvent& ) { render();} void OnLeftDown(wxMouseEvent& event); From e529315ef9ff9464fe2258cca1fdf4afb719178f Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Wed, 7 Nov 2018 14:51:11 +0100 Subject: [PATCH 41/43] Fixed update of ModelVolume mirror after GLVolume manipulation --- src/slic3r/GUI/GLCanvas3D.cpp | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 68798dd9d..e153161d4 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1629,11 +1629,15 @@ void GLCanvas3D::Selection::mirror(Axis axis) if (!m_valid) return; + bool single_full_instance = is_single_full_instance(); + for (unsigned int i : m_list) { - if (is_single_full_instance()) + if (single_full_instance) #if ENABLE_MODELVOLUME_TRANSFORM (*m_volumes)[i]->set_instance_mirror(axis, -(*m_volumes)[i]->get_instance_mirror(axis)); + else if (m_mode == Volume) + (*m_volumes)[i]->set_volume_mirror(axis, -(*m_volumes)[i]->get_volume_mirror(axis)); #else (*m_volumes)[i]->set_mirror(axis, -(*m_volumes)[i]->get_mirror(axis)); #endif // ENABLE_MODELVOLUME_TRANSFORM @@ -6415,7 +6419,7 @@ void GLCanvas3D::_on_scale() done.insert(std::pair(object_idx, instance_idx)); - // Rotate instances. + // Rotate instances/volumes ModelObject* model_object = m_model->objects[object_idx]; if (model_object != nullptr) { @@ -6460,29 +6464,30 @@ void GLCanvas3D::_on_mirror() if (m_model == nullptr) return; - std::set> done; // prevent mirroring instances twice + std::set> done; // keeps track of modified instances + + Selection::EMode selection_mode = m_selection.get_mode(); for (const GLVolume* v : m_volumes.volumes) { int object_idx = v->object_idx(); - if (object_idx >= 1000) + if ((object_idx < 0) || ((int)m_model->objects.size() <= object_idx)) continue; int instance_idx = v->instance_idx(); + int volume_idx = v->volume_idx(); - // prevent mirroring instances twice - std::pair done_id(object_idx, instance_idx); - if (done.find(done_id) != done.end()) - continue; + done.insert(std::pair(object_idx, instance_idx)); - done.insert(done_id); - - // Mirror instances. + // Mirror instances/volumes 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()); + if (selection_mode == Selection::Instance) + model_object->instances[instance_idx]->set_mirror(v->get_instance_mirror()); + else if (selection_mode == Selection::Volume) + model_object->volumes[volume_idx]->set_mirror(v->get_volume_mirror()); #else model_object->instances[instance_idx]->set_mirror(v->get_mirror()); #endif // ENABLE_MODELVOLUME_TRANSFORM From 041de161a9cec3face1bfa042ba2d3c8186f84a1 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Wed, 7 Nov 2018 14:57:50 +0100 Subject: [PATCH 42/43] Fixes to storing and loading configs from AMF/3MF. --- src/admesh/stl.h | 2 +- src/libslic3r/Config.cpp | 15 +++++++-------- src/libslic3r/Config.hpp | 3 ++- src/libslic3r/Format/3mf.cpp | 30 ++++++++++++++++-------------- src/libslic3r/Format/3mf.hpp | 4 ++-- src/libslic3r/Format/AMF.cpp | 14 ++++++++------ src/libslic3r/Format/AMF.hpp | 6 +++--- src/libslic3r/Point.hpp | 2 +- src/slic3r.cpp | 2 +- src/slic3r/GUI/MainFrame.cpp | 6 ++---- src/slic3r/GUI/Plater.cpp | 15 ++++++++------- src/slic3r/GUI/PresetBundle.cpp | 14 +------------- src/slic3r/GUI/PresetBundle.hpp | 5 ----- src/slic3r/GUI/WipeTowerDialog.cpp | 2 +- 14 files changed, 53 insertions(+), 67 deletions(-) diff --git a/src/admesh/stl.h b/src/admesh/stl.h index 45889bcd3..9c71f00f6 100644 --- a/src/admesh/stl.h +++ b/src/admesh/stl.h @@ -189,7 +189,7 @@ inline void stl_normalize_vector(stl_normal &normal) { if (length < 0.000000000001) normal = stl_normal::Zero(); else - normal *= (1.0 / length); + normal *= float(1.0 / length); } inline bool stl_vertex_lower(const stl_vertex &a, const stl_vertex &b) { return (a(0) != b(0)) ? (a(0) < b(0)) : diff --git a/src/libslic3r/Config.cpp b/src/libslic3r/Config.cpp index bf8be7feb..bfa0991a7 100644 --- a/src/libslic3r/Config.cpp +++ b/src/libslic3r/Config.cpp @@ -439,14 +439,16 @@ void ConfigBase::load_from_gcode_file(const std::string &file) ifs.read(data.data(), data_length); ifs.close(); - load_from_gcode_string(data.data()); + size_t key_value_pairs = load_from_gcode_string(data.data()); + if (key_value_pairs < 80) + throw std::runtime_error((boost::format("Suspiciously low number of configuration values extracted from %1: %2") % file % key_value_pairs).str()); } // Load the config keys from the given string. -void ConfigBase::load_from_gcode_string(const char* str) +size_t ConfigBase::load_from_gcode_string(const char* str) { if (str == nullptr) - return; + return 0; // Walk line by line in reverse until a non-configuration key appears. char *data_start = const_cast(str); @@ -497,11 +499,8 @@ void ConfigBase::load_from_gcode_string(const char* str) } end = start; } - if (num_key_value_pairs < 90) { - char msg[80]; - sprintf(msg, "Suspiciously low number of configuration values extracted: %d", num_key_value_pairs); - throw std::runtime_error(msg); - } + + return num_key_value_pairs; } void ConfigBase::save(const std::string &file) const diff --git a/src/libslic3r/Config.hpp b/src/libslic3r/Config.hpp index 64548bf8d..2d8d049ba 100644 --- a/src/libslic3r/Config.hpp +++ b/src/libslic3r/Config.hpp @@ -1119,7 +1119,8 @@ public: void load(const std::string &file); void load_from_ini(const std::string &file); void load_from_gcode_file(const std::string &file); - void load_from_gcode_string(const char* str); + // Returns number of key/value pairs extracted. + size_t load_from_gcode_string(const char* str); void load(const boost::property_tree::ptree &tree); void save(const std::string &file) const; diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index d3b28be26..fc2cf7b89 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -813,7 +813,7 @@ namespace Slic3r { std::vector sla_support_points; for (unsigned int i=0; i()); if (!sla_support_points.empty()) m_sla_support_points.insert(IdToSlaSupportPointsMap::value_type(object_id, sla_support_points)); @@ -1608,10 +1608,10 @@ namespace Slic3r { IdToObjectDataMap m_objects_data; public: - bool save_model_to_file(const std::string& filename, Model& model, const Print& print, bool export_print_config); + bool save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config); private: - bool _save_model_to_file(const std::string& filename, Model& model, const Print& print, bool export_print_config); + bool _save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config); bool _add_content_types_file_to_archive(mz_zip_archive& archive); bool _add_relationships_file_to_archive(mz_zip_archive& archive); bool _add_model_file_to_archive(mz_zip_archive& archive, Model& model); @@ -1620,17 +1620,17 @@ namespace Slic3r { bool _add_build_to_model_stream(std::stringstream& stream, const BuildItemsList& build_items); bool _add_layer_height_profile_file_to_archive(mz_zip_archive& archive, Model& model); bool _add_sla_support_points_file_to_archive(mz_zip_archive& archive, Model& model); - bool _add_print_config_file_to_archive(mz_zip_archive& archive, const Print& print); + bool _add_print_config_file_to_archive(mz_zip_archive& archive, const DynamicPrintConfig &config); bool _add_model_config_file_to_archive(mz_zip_archive& archive, const Model& model); }; - bool _3MF_Exporter::save_model_to_file(const std::string& filename, Model& model, const Print& print, bool export_print_config) + bool _3MF_Exporter::save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config) { clear_errors(); - return _save_model_to_file(filename, model, print, export_print_config); + return _save_model_to_file(filename, model, config); } - bool _3MF_Exporter::_save_model_to_file(const std::string& filename, Model& model, const Print& print, bool export_print_config) + bool _3MF_Exporter::_save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config) { mz_zip_archive archive; mz_zip_zero_struct(&archive); @@ -1685,9 +1685,9 @@ namespace Slic3r { } // adds slic3r print config file - if (export_print_config) + if (config != nullptr) { - if (!_add_print_config_file_to_archive(archive, print)) + if (!_add_print_config_file_to_archive(archive, *config)) { mz_zip_writer_end(&archive); boost::filesystem::remove(filename); @@ -2017,13 +2017,15 @@ namespace Slic3r { return true; } - bool _3MF_Exporter::_add_print_config_file_to_archive(mz_zip_archive& archive, const Print& print) + bool _3MF_Exporter::_add_print_config_file_to_archive(mz_zip_archive& archive, const DynamicPrintConfig &config) { char buffer[1024]; sprintf(buffer, "; %s\n\n", header_slic3r_generated().c_str()); std::string out = buffer; - GCode::append_full_config(print, out); + for (const std::string &key : config.keys()) + if (key != "compatible_printers") + out += "; " + key + " = " + config.serialize(key) + "\n"; if (!out.empty()) { @@ -2123,13 +2125,13 @@ namespace Slic3r { return res; } - bool store_3mf(const char* path, Model* model, Print* print, bool export_print_config) + bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config) { - if ((path == nullptr) || (model == nullptr) || (print == nullptr)) + if ((path == nullptr) || (model == nullptr)) return false; _3MF_Exporter exporter; - bool res = exporter.save_model_to_file(path, *model, *print, export_print_config); + bool res = exporter.save_model_to_file(path, *model, config); if (!res) exporter.log_errors(); diff --git a/src/libslic3r/Format/3mf.hpp b/src/libslic3r/Format/3mf.hpp index cfab1c600..44b37c1ae 100644 --- a/src/libslic3r/Format/3mf.hpp +++ b/src/libslic3r/Format/3mf.hpp @@ -4,14 +4,14 @@ namespace Slic3r { class Model; - class Print; + class DynamicPrintConfig; // Load the content of a 3mf file into the given model and preset bundle. extern bool load_3mf(const char* path, DynamicPrintConfig* config, Model* model); // Save the given model and the config data contained in the given Print into a 3mf file. // The model could be modified during the export process if meshes are not repaired or have no shared vertices - extern bool store_3mf(const char* path, Model* model, Print* print, bool export_print_config); + extern bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config); }; // namespace Slic3r diff --git a/src/libslic3r/Format/AMF.cpp b/src/libslic3r/Format/AMF.cpp index 36964d869..089368865 100644 --- a/src/libslic3r/Format/AMF.cpp +++ b/src/libslic3r/Format/AMF.cpp @@ -834,9 +834,9 @@ bool load_amf(const char *path, DynamicPrintConfig *config, Model *model) return false; } -bool store_amf(const char *path, Model *model, Print* print, bool export_print_config) +bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config) { - if ((path == nullptr) || (model == nullptr) || (print == nullptr)) + if ((path == nullptr) || (model == nullptr)) return false; // forces ".zip.amf" extension @@ -857,11 +857,13 @@ bool store_amf(const char *path, Model *model, Print* print, bool export_print_c stream << "Slic3r " << SLIC3R_VERSION << "\n"; stream << "" << VERSION_AMF << "\n"; - if (export_print_config) + if (config != nullptr) { - std::string config = "\n"; - GCode::append_full_config(*print, config); - stream << "" << xml_escape(config) << "\n"; + std::string str_config = "\n"; + for (const std::string &key : config->keys()) + if (key != "compatible_printers") + str_config += "; " + key + " = " + config->serialize(key) + "\n"; + stream << "" << xml_escape(str_config) << "\n"; } for (const auto &material : model->materials) { diff --git a/src/libslic3r/Format/AMF.hpp b/src/libslic3r/Format/AMF.hpp index ae8863e02..e085ad22e 100644 --- a/src/libslic3r/Format/AMF.hpp +++ b/src/libslic3r/Format/AMF.hpp @@ -4,14 +4,14 @@ namespace Slic3r { class Model; -class Print; +class DynamicPrintConfig; // Load the content of an amf file into the given model and configuration. extern bool load_amf(const char *path, DynamicPrintConfig *config, Model *model); -// Save the given model and the config data contained in the given Print into an amf file. +// Save the given model and the config data into an amf file. // The model could be modified during the export process if meshes are not repaired or have no shared vertices -extern bool store_amf(const char *path, Model *model, Print* print, bool export_print_config); +extern bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config); }; // namespace Slic3r diff --git a/src/libslic3r/Point.hpp b/src/libslic3r/Point.hpp index 100178108..277fc5877 100644 --- a/src/libslic3r/Point.hpp +++ b/src/libslic3r/Point.hpp @@ -58,7 +58,7 @@ inline Vec2d to_2d(const Vec3d &pt3) { return Vec2d (pt3(0), pt3(1)); } inline Vec3d to_3d(const Vec2d &v, double z) { return Vec3d(v(0), v(1), z); } inline Vec3f to_3d(const Vec2f &v, float z) { return Vec3f(v(0), v(1), z); } -inline Vec3i64 to_3d(const Vec2i64 &v, float z) { return Vec3i64(v(0), v(1), z); } +inline Vec3i64 to_3d(const Vec2i64 &v, float z) { return Vec3i64(int64_t(v(0)), int64_t(v(1)), int64_t(z)); } inline Vec3crd to_3d(const Vec3crd &p, coord_t z) { return Vec3crd(p(0), p(1), z); } inline Vec2d unscale(coord_t x, coord_t y) { return Vec2d(unscale(x), unscale(y)); } diff --git a/src/slic3r.cpp b/src/slic3r.cpp index cf86c40ed..441a6ab80 100644 --- a/src/slic3r.cpp +++ b/src/slic3r.cpp @@ -186,7 +186,7 @@ int main(int argc, char **argv) else // Remove the previous extension and add .3mf extention. outfile = outfile.substr(0, outfile.find_last_of('.')) + ".3mf"; - store_3mf(outfile.c_str(), &model, nullptr, false); + store_3mf(outfile.c_str(), &model, nullptr); boost::nowide::cout << "File file exported to " << outfile << std::endl; } else if (cli_config.cut > 0) { model.repair(); diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 1515b1386..a378a067e 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -596,8 +596,7 @@ void MainFrame::load_config_file(wxString file/* = wxEmptyString*/) // if (Slic3r::GUI::catch_error(this)) // return; } - for (auto tab : m_options_tabs ) - tab.second->load_current_preset(); + wxGetApp().load_current_presets(); wxGetApp().app_config->update_config_dir(get_dir_name(file)); m_last_config = file; } @@ -659,8 +658,7 @@ void MainFrame::load_configbundle(wxString file/* = wxEmptyString, const bool re } // Load the currently selected preset into the GUI, update the preset selection box. - for (auto tab : m_options_tabs) - tab.second->load_current_preset(); + wxGetApp().load_current_presets(); const auto message = wxString::Format(_(L("%d presets successfully imported.")), presets_imported); Slic3r::GUI::show_info(this, message, "Info"); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index f5561a5ec..0381744da 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1154,10 +1154,10 @@ std::vector Plater::priv::load_files(const std::vector &input_ { DynamicPrintConfig config_loaded; model = Slic3r::Model::read_from_archive(path.string(), &config_loaded, false); - // Based on the printer technology field found in the loaded config, select the base for the config, - PrinterTechnology printer_technology = Preset::printer_technology(config_loaded); if (! config_loaded.empty()) { - config.apply(printer_technology == ptFFF ? + // Based on the printer technology field found in the loaded config, select the base for the config, + PrinterTechnology printer_technology = Preset::printer_technology(config_loaded); + config.apply(printer_technology == ptFFF ? static_cast(FullPrintConfig::defaults()) : static_cast(SLAFullPrintConfig::defaults())); // and place the loaded config over the base. @@ -1167,8 +1167,7 @@ std::vector Plater::priv::load_files(const std::vector &input_ if (! config.empty()) { Preset::normalize(config); wxGetApp().preset_bundle->load_config_model(filename.string(), std::move(config)); - for (const auto &kv : main_frame->options_tabs()) - kv.second->load_current_preset(); + wxGetApp().load_current_presets(); } wxGetApp().app_config->update_config_dir(path.parent_path().string()); } else { @@ -2117,7 +2116,8 @@ void Plater::export_amf() wxString path = dialog->GetPath(); auto path_cstr = path.c_str(); - if (Slic3r::store_amf(path_cstr, &p->model, &p->print, dialog->get_checkbox_value())) { + DynamicPrintConfig cfg = wxGetApp().preset_bundle->full_config(); + if (Slic3r::store_amf(path_cstr, &p->model, dialog->get_checkbox_value() ? &cfg : nullptr)) { // Success p->statusbar()->set_status_text(wxString::Format(_(L("AMF file exported to %s")), path)); } else { @@ -2136,7 +2136,8 @@ void Plater::export_3mf() wxString path = dialog->GetPath(); auto path_cstr = path.c_str(); - if (Slic3r::store_3mf(path_cstr, &p->model, &p->print, dialog->get_checkbox_value())) { + DynamicPrintConfig cfg = wxGetApp().preset_bundle->full_config(); + if (Slic3r::store_3mf(path_cstr, &p->model, dialog->get_checkbox_value() ? &cfg : nullptr)) { // Success p->statusbar()->set_status_text(wxString::Format(_(L("3MF file exported to %s")), path)); } else { diff --git a/src/slic3r/GUI/PresetBundle.cpp b/src/slic3r/GUI/PresetBundle.cpp index 5e42501b6..f51e9f647 100644 --- a/src/slic3r/GUI/PresetBundle.cpp +++ b/src/slic3r/GUI/PresetBundle.cpp @@ -618,18 +618,6 @@ void PresetBundle::load_config_file(const std::string &path) } } -void PresetBundle::load_config_string(const char* str, const char* source_filename) -{ - if (str != nullptr) - { - DynamicPrintConfig config; - config.apply(FullPrintConfig::defaults()); - config.load_from_gcode_string(str); - Preset::normalize(config); - load_config_file_config((source_filename == nullptr) ? "" : source_filename, true, std::move(config)); - } -} - // Load a config file from a boost property_tree. This is a private method called from load_config_file. void PresetBundle::load_config_file_config(const std::string &name_or_path, bool is_external, DynamicPrintConfig &&config) { @@ -677,7 +665,7 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool compatible_printers_condition = compatible_printers_condition_values[idx]; if (is_external) presets.load_external_preset(name_or_path, name, - config.opt_string((i_group == 0) ? ((printer_technology == ptFFF) ? "print_settings_id" : "sla_material_id") : "printer_settings_id", true), + config.opt_string((i_group == 0) ? ((printer_technology == ptFFF) ? "print_settings_id" : "sla_material_settings_id") : "printer_settings_id", true), config); else presets.load_preset(presets.path_from_name(name), name, config).save(); diff --git a/src/slic3r/GUI/PresetBundle.hpp b/src/slic3r/GUI/PresetBundle.hpp index a7d9ab7d2..07f89bc70 100644 --- a/src/slic3r/GUI/PresetBundle.hpp +++ b/src/slic3r/GUI/PresetBundle.hpp @@ -84,11 +84,6 @@ public: // If the file is loaded successfully, its print / filament / printer profiles will be activated. void load_config_file(const std::string &path); - // Load an external config source containing the print, filament and printer presets. - // The given string must contain the full set of parameters (same as those exported to gcode). - // If the string is parsed successfully, its print / filament / printer profiles will be activated. - void load_config_string(const char* str, const char* source_filename = nullptr); - // Load a config bundle file, into presets and store the loaded presets into separate files // of the local configuration directory. // Load settings into the provided settings instance. diff --git a/src/slic3r/GUI/WipeTowerDialog.cpp b/src/slic3r/GUI/WipeTowerDialog.cpp index eef4017c1..b31e59cc0 100644 --- a/src/slic3r/GUI/WipeTowerDialog.cpp +++ b/src/slic3r/GUI/WipeTowerDialog.cpp @@ -108,7 +108,7 @@ RammingPanel::RammingPanel(wxWindow* parent, const std::string& parameters) m_widget_time->Bind(wxEVT_CHAR,[](wxKeyEvent&){}); // do nothing - prevents the user to change the value m_widget_volume->Bind(wxEVT_CHAR,[](wxKeyEvent&){}); // do nothing - prevents the user to change the value Bind(EVT_WIPE_TOWER_CHART_CHANGED,[this](wxCommandEvent&) {m_widget_volume->SetValue(m_chart->get_volume()); m_widget_time->SetValue(m_chart->get_time());} ); - Refresh(this); + Refresh(true); // erase background } void RammingPanel::line_parameters_changed() { From 377350db33a7bb8f5bc8b8fa37044a1ae9745120 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 7 Nov 2018 15:17:29 +0100 Subject: [PATCH 43/43] When iterating over PrintObject regions, use PrintObject::region_volumes (see also yesterday's commit 3eea327) --- src/libslic3r/GCode.cpp | 7 +++---- src/libslic3r/GCode/ToolOrdering.cpp | 4 ++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index dcd4d2ab1..b6752147b 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -610,9 +610,9 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) std::vector mm3_per_mm; for (auto object : printable_objects) { for (size_t region_id = 0; region_id < object->region_volumes.size(); ++ region_id) { - auto region = print.regions()[region_id]; + const PrintRegion* region = print.regions()[region_id]; for (auto layer : object->layers()) { - auto layerm = layer->regions()[region_id]; + const LayerRegion* layerm = layer->regions()[region_id]; if (region->config().get_abs_value("perimeter_speed" ) == 0 || region->config().get_abs_value("small_perimeter_speed" ) == 0 || region->config().get_abs_value("external_perimeter_speed" ) == 0 || @@ -676,8 +676,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) const PrintObject *first_object = printable_objects.front(); const double layer_height = first_object->config().layer_height.value; const double first_layer_height = first_object->config().first_layer_height.get_abs_value(layer_height); - for (size_t region_id = 0; region_id < print.regions().size(); ++ region_id) { - auto region = print.regions()[region_id]; + for (const PrintRegion* region : print.regions()) { _write_format(file, "; external perimeters extrusion width = %.2fmm\n", region->flow(frExternalPerimeter, layer_height, false, false, -1., *first_object).width); _write_format(file, "; perimeters extrusion width = %.2fmm\n", region->flow(frPerimeter, layer_height, false, false, -1., *first_object).width); _write_format(file, "; infill extrusion width = %.2fmm\n", region->flow(frInfill, layer_height, false, false, -1., *first_object).width); diff --git a/src/libslic3r/GCode/ToolOrdering.cpp b/src/libslic3r/GCode/ToolOrdering.cpp index b20386730..3793051f4 100644 --- a/src/libslic3r/GCode/ToolOrdering.cpp +++ b/src/libslic3r/GCode/ToolOrdering.cpp @@ -479,7 +479,7 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int for (unsigned int copy = 0; copy < num_of_copies; ++copy) { // iterate through copies first, so that we mark neighbouring infills to minimize travel moves - for (size_t region_id = 0; region_id < object->print()->regions().size(); ++ region_id) { + for (size_t region_id = 0; region_id < object->region_volumes.size(); ++ region_id) { const auto& region = *object->print()->regions()[region_id]; if (!region.config().wipe_into_infill && !object->config().wipe_into_objects) @@ -557,7 +557,7 @@ void WipingExtrusions::ensure_perimeters_infills_order(const Print& print) unsigned int num_of_copies = object->copies().size(); for (unsigned int copy = 0; copy < num_of_copies; ++copy) { // iterate through copies first, so that we mark neighbouring infills to minimize travel moves - for (size_t region_id = 0; region_id < object->print()->regions().size(); ++ region_id) { + for (size_t region_id = 0; region_id < object->region_volumes.size(); ++ region_id) { const auto& region = *object->print()->regions()[region_id]; if (!region.config().wipe_into_infill && !object->config().wipe_into_objects)