diff --git a/src/libslic3r/BoundingBox.hpp b/src/libslic3r/BoundingBox.hpp index b3a1c2f5c..26302f702 100644 --- a/src/libslic3r/BoundingBox.hpp +++ b/src/libslic3r/BoundingBox.hpp @@ -32,6 +32,7 @@ public: } this->defined = (this->min(0) < this->max(0)) && (this->min(1) < this->max(1)); } + void reset() { this->defined = false; this->min = PointClass::Zero(); this->max = PointClass::Zero(); } void merge(const PointClass &point); void merge(const std::vector &points); void merge(const BoundingBoxBase &bb); diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index b13b00e57..593f716fa 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -573,6 +573,8 @@ ModelObject& ModelObject::assign_copy(const ModelObject &rhs) this->origin_translation = rhs.origin_translation; m_bounding_box = rhs.m_bounding_box; m_bounding_box_valid = rhs.m_bounding_box_valid; + m_raw_mesh_bounding_box = rhs.m_raw_mesh_bounding_box; + m_raw_mesh_bounding_box_valid = rhs.m_raw_mesh_bounding_box_valid; this->clear_volumes(); this->volumes.reserve(rhs.volumes.size()); @@ -604,6 +606,8 @@ ModelObject& ModelObject::assign_copy(ModelObject &&rhs) 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); + m_raw_mesh_bounding_box = rhs.m_raw_mesh_bounding_box; + m_raw_mesh_bounding_box_valid = rhs.m_raw_mesh_bounding_box_valid; this->clear_volumes(); this->volumes = std::move(rhs.volumes); @@ -783,19 +787,11 @@ void ModelObject::clear_instances() const BoundingBoxf3& ModelObject::bounding_box() const { if (! m_bounding_box_valid) { - BoundingBoxf3 raw_bbox; - for (const ModelVolume *v : this->volumes) - if (v->is_model_part()) - { - TriangleMesh m = v->mesh; - m.transform(v->get_matrix()); - raw_bbox.merge(m.bounding_box()); - } - BoundingBoxf3 bb; - for (const ModelInstance *i : this->instances) - bb.merge(i->transform_bounding_box(raw_bbox)); - m_bounding_box = bb; m_bounding_box_valid = true; + BoundingBoxf3 raw_bbox = this->raw_mesh_bounding_box(); + m_bounding_box.reset(); + for (const ModelInstance *i : this->instances) + m_bounding_box.merge(i->transform_bounding_box(raw_bbox)); } return m_bounding_box; } @@ -842,6 +838,26 @@ TriangleMesh ModelObject::full_raw_mesh() const return mesh; } +BoundingBoxf3 ModelObject::raw_mesh_bounding_box() const +{ + if (! m_raw_mesh_bounding_box_valid) { + m_raw_mesh_bounding_box_valid = true; + m_raw_mesh_bounding_box.reset(); + for (const ModelVolume *v : this->volumes) + if (v->is_model_part()) + m_raw_mesh_bounding_box.merge(v->mesh.transformed_bounding_box(v->get_matrix())); + } + return m_raw_mesh_bounding_box; +} + +BoundingBoxf3 ModelObject::full_raw_mesh_bounding_box() const +{ + BoundingBoxf3 bb; + for (const ModelVolume *v : this->volumes) + bb.merge(v->mesh.transformed_bounding_box(v->get_matrix())); + return bb; +} + // A transformed snug bounding box around the non-modifier object volumes, without the translation applied. // This bounding box is only used for the actual slicing. BoundingBoxf3 ModelObject::raw_bounding_box() const @@ -896,20 +912,6 @@ BoundingBoxf3 ModelObject::instance_bounding_box(size_t instance_idx, bool dont_ return bb; } -#if ENABLE_VOLUMES_CENTERING_FIXES -BoundingBoxf3 ModelObject::full_raw_mesh_bounding_box() const -{ - BoundingBoxf3 bb; - for (const ModelVolume *v : this->volumes) - { - TriangleMesh vol_mesh(v->mesh); - vol_mesh.transform(v->get_matrix()); - bb.merge(vol_mesh.bounding_box()); - } - return bb; -} -#endif // ENABLE_VOLUMES_CENTERING_FIXES - void ModelObject::center_around_origin() { // calculate the displacements needed to diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index f13baee08..0dd73f62f 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -205,7 +205,7 @@ public: // This bounding box is approximate and not snug. // This bounding box is being cached. const BoundingBoxf3& bounding_box() const; - void invalidate_bounding_box() { m_bounding_box_valid = false; } + void invalidate_bounding_box() { m_bounding_box_valid = false; m_raw_mesh_bounding_box_valid = false; } // A mesh containing all transformed instances of this object. TriangleMesh mesh() const; @@ -219,10 +219,10 @@ public: BoundingBoxf3 raw_bounding_box() const; // A snug bounding box around the transformed non-modifier object volumes. BoundingBoxf3 instance_bounding_box(size_t instance_idx, bool dont_translate = false) const; -#if ENABLE_VOLUMES_CENTERING_FIXES - // Bounding box of non-transformed (non-rotated, non-scaled, non-translated) sum of all object volumes. + // A snug bounding box of non-transformed (non-rotated, non-scaled, non-translated) sum of non-modifier object volumes. + BoundingBoxf3 raw_mesh_bounding_box() const; + // A snug bounding box of non-transformed (non-rotated, non-scaled, non-translated) sum of all object volumes. BoundingBoxf3 full_raw_mesh_bounding_box() const; -#endif // ENABLE_VOLUMES_CENTERING_FIXES void center_around_origin(); void ensure_on_bed(); void translate_instances(const Vec3d& vector); @@ -261,7 +261,8 @@ protected: void set_model(Model *model) { m_model = model; } private: - ModelObject(Model *model) : m_model(model), origin_translation(Vec3d::Zero()), m_bounding_box_valid(false) {} + ModelObject(Model *model) : m_model(model), origin_translation(Vec3d::Zero()), + m_bounding_box_valid(false), m_raw_mesh_bounding_box_valid(false) {} ~ModelObject(); /* To be able to return an object from own copy / clone methods. Hopefully the compiler will do the "Copy elision" */ @@ -280,6 +281,8 @@ private: // Bounding box, cached. mutable BoundingBoxf3 m_bounding_box; mutable bool m_bounding_box_valid; + mutable BoundingBoxf3 m_raw_mesh_bounding_box; + mutable bool m_raw_mesh_bounding_box_valid; }; // An object STL, or a modifier volume, over which a different set of parameters shall be applied. diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index 4648b95c0..8b69a9e5c 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -525,67 +525,22 @@ BoundingBoxf3 TriangleMesh::bounding_box() const return bb; } -BoundingBoxf3 TriangleMesh::transformed_bounding_box(const Transform3d& t) const +BoundingBoxf3 TriangleMesh::transformed_bounding_box(const Transform3d &trafo) const { - bool has_shared = (stl.v_shared != nullptr); - if (!has_shared) - stl_generate_shared_vertices(const_cast(&stl)); - - unsigned int vertices_count = (stl.stats.shared_vertices > 0) ? (unsigned int)stl.stats.shared_vertices : 3 * (unsigned int)stl.stats.number_of_facets; - - if (vertices_count == 0) - return BoundingBoxf3(); - - Eigen::MatrixXd src_vertices(3, vertices_count); - - if (stl.stats.shared_vertices > 0) - { - assert(stl.v_shared != nullptr); - stl_vertex* vertex_ptr = stl.v_shared; - for (int i = 0; i < stl.stats.shared_vertices; ++i) - { - src_vertices(0, i) = (double)(*vertex_ptr)(0); - src_vertices(1, i) = (double)(*vertex_ptr)(1); - src_vertices(2, i) = (double)(*vertex_ptr)(2); - vertex_ptr += 1; + BoundingBoxf3 bbox; + if (stl.v_shared == nullptr) { + // Using the STL faces. + for (int i = 0; i < this->facets_count(); ++ i) { + const stl_facet &facet = this->stl.facet_start[i]; + for (size_t j = 0; j < 3; ++ j) + bbox.merge(trafo * facet.vertex[j].cast()); } + } else { + // Using the shared vertices should be a bit quicker than using the STL faces. + for (int i = 0; i < stl.stats.shared_vertices; ++ i) + bbox.merge(trafo * this->stl.v_shared[i].cast()); } - else - { - stl_facet* facet_ptr = stl.facet_start; - unsigned int v_id = 0; - while (facet_ptr < stl.facet_start + stl.stats.number_of_facets) - { - for (int i = 0; i < 3; ++i) - { - src_vertices(0, v_id) = (double)facet_ptr->vertex[i](0); - src_vertices(1, v_id) = (double)facet_ptr->vertex[i](1); - src_vertices(2, v_id) = (double)facet_ptr->vertex[i](2); - ++v_id; - } - facet_ptr += 1; - } - } - - if (!has_shared && (stl.stats.shared_vertices > 0)) - stl_invalidate_shared_vertices(const_cast(&stl)); - - Eigen::MatrixXd dst_vertices(3, vertices_count); - dst_vertices = t * src_vertices.colwise().homogeneous(); - - Vec3d v_min(dst_vertices(0, 0), dst_vertices(1, 0), dst_vertices(2, 0)); - Vec3d v_max = v_min; - - for (int i = 1; i < vertices_count; ++i) - { - for (int j = 0; j < 3; ++j) - { - v_min(j) = std::min(v_min(j), dst_vertices(j, i)); - v_max(j) = std::max(v_max(j), dst_vertices(j, i)); - } - } - - return BoundingBoxf3(v_min, v_max); + return bbox; } TriangleMesh TriangleMesh::convex_hull_3d() const @@ -2010,4 +1965,5 @@ TriangleMesh make_sphere(double rho, double fa) { TriangleMesh mesh(vertices, facets); return mesh; } + } diff --git a/src/libslic3r/TriangleMesh.hpp b/src/libslic3r/TriangleMesh.hpp index fc2b40013..be70ee79d 100644 --- a/src/libslic3r/TriangleMesh.hpp +++ b/src/libslic3r/TriangleMesh.hpp @@ -60,7 +60,7 @@ public: Polygon convex_hull(); BoundingBoxf3 bounding_box() const; // Returns the bbox of this TriangleMesh transformed by the given transformation - BoundingBoxf3 transformed_bounding_box(const Transform3d& t) const; + BoundingBoxf3 transformed_bounding_box(const Transform3d &trafo) const; // Returns the convex hull of this TriangleMesh TriangleMesh convex_hull_3d() const; void reset_repair_stats(); diff --git a/src/slic3r/GUI/GLGizmo.cpp b/src/slic3r/GUI/GLGizmo.cpp index cb9a5abc9..1660976a1 100644 --- a/src/slic3r/GUI/GLGizmo.cpp +++ b/src/slic3r/GUI/GLGizmo.cpp @@ -1428,6 +1428,7 @@ void GLGizmoFlatten::on_start_dragging(const GLCanvas3D::Selection& selection) { if (m_hover_id != -1) { + assert(m_planes_valid); m_normal = m_planes[m_hover_id].normal; m_starting_center = selection.get_bounding_box().center(); } @@ -1446,6 +1447,8 @@ void GLGizmoFlatten::on_render(const GLCanvas3D::Selection& selection) const ::glPushMatrix(); ::glMultMatrixd(m.data()); ::glTranslatef(0.f, 0.f, selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z()); + if (this->is_plane_update_necessary()) + const_cast(this)->update_planes(); for (int i = 0; i < (int)m_planes.size(); ++i) { if (i == m_hover_id) @@ -1478,6 +1481,8 @@ void GLGizmoFlatten::on_render_for_picking(const GLCanvas3D::Selection& selectio ::glPushMatrix(); ::glMultMatrixd(m.data()); ::glTranslatef(0.f, 0.f, selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z()); + if (this->is_plane_update_necessary()) + const_cast(this)->update_planes(); for (int i = 0; i < (int)m_planes.size(); ++i) { ::glColor3f(1.0f, 1.0f, picking_color_component(i)); @@ -1497,11 +1502,11 @@ 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; + if (m_model_object != model_object) { + m_planes.clear(); + m_planes_valid = false; + } m_model_object = model_object; - - if (model_object && (object_changed || is_plane_update_necessary())) - update_planes(); } void GLGizmoFlatten::update_planes() @@ -1701,6 +1706,8 @@ void GLGizmoFlatten::update_planes() } m_first_instance_scale = m_model_object->instances.front()->get_scaling_factor(); m_first_instance_mirror = m_model_object->instances.front()->get_mirror(); + + m_planes_valid = true; } @@ -1709,7 +1716,7 @@ bool GLGizmoFlatten::is_plane_update_necessary() const if (m_state != On || !m_model_object || m_model_object->instances.empty()) return false; - if (m_model_object->volumes.size() != m_volumes_matrices.size()) + if (! m_planes_valid || m_model_object->volumes.size() != m_volumes_matrices.size()) return true; // We want to recalculate when the scale changes - some planes could (dis)appear. diff --git a/src/slic3r/GUI/GLGizmo.hpp b/src/slic3r/GUI/GLGizmo.hpp index 02b637a35..7a55a2392 100644 --- a/src/slic3r/GUI/GLGizmo.hpp +++ b/src/slic3r/GUI/GLGizmo.hpp @@ -408,6 +408,7 @@ private: Vec3d m_first_instance_mirror; std::vector m_planes; + bool m_planes_valid = false; mutable Vec3d m_starting_center; const ModelObject* m_model_object = nullptr; std::vector instances_matrices; diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 62c00d02d..d62548d48 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -621,7 +621,8 @@ const std::vector& get_options_for_bundle(const wxString& bundle_na if (bundle_name == _(it.first)) return it.second; } - return std::vector {}; + static std::vector empty; + return empty; } // category -> vector ( option ; label ) @@ -1276,15 +1277,12 @@ bool ObjectList::is_splittable() if (!get_volume_by_item(item, volume) || !volume) return false; - if (volume->is_splittable() != -1) // if is_splittable value is already known - return volume->is_splittable() == 0 ? false : true; - - TriangleMeshPtrs meshptrs = volume->mesh.split(); - bool splittable = meshptrs.size() > 1; - for (TriangleMesh* m : meshptrs) { delete m; } - - volume->set_splittable(splittable ? 1 : 0); - return splittable; + int splittable = volume->is_splittable(); + if (splittable == -1) { + splittable = (int)volume->mesh.has_multiple_patches(); + volume->set_splittable(splittable); + } + return splittable != 0; } bool ObjectList::selected_instances_of_same_object() diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index 363294ce8..5157dc9c5 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -267,7 +267,7 @@ void ObjectManipulation::update_settings_value(const GLCanvas3D::Selection& sele bool changed_box = false; if (!m_cache.instance.matches_object(obj_idx)) { - m_cache.instance.set(obj_idx, instance_idx, (*wxGetApp().model_objects())[obj_idx]->raw_mesh().bounding_box().size()); + m_cache.instance.set(obj_idx, instance_idx, (*wxGetApp().model_objects())[obj_idx]->raw_mesh_bounding_box().size()); changed_box = true; } if (changed_box || !m_cache.instance.matches_instance(instance_idx) || !m_cache.scale.isApprox(100.0 * m_new_scale)) @@ -278,7 +278,7 @@ void ObjectManipulation::update_settings_value(const GLCanvas3D::Selection& sele m_new_size = Vec3d::Zero(); #else if ((0 <= obj_idx) && (obj_idx < (int)wxGetApp().model_objects()->size())) - m_new_size = volume->get_instance_transformation().get_matrix(true, true) * (*wxGetApp().model_objects())[obj_idx]->raw_mesh().bounding_box().size(); + m_new_size = volume->get_instance_transformation().get_matrix(true, true) * (*wxGetApp().model_objects())[obj_idx]->raw_mesh_bounding_box().size(); else // this should never happen m_new_size = Vec3d::Zero(); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index cb08ea3f3..bc65d9784 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -2105,7 +2105,7 @@ void Plater::priv::fix_through_netfabb(const int obj_idx) o->clear_instances(); for (auto instance: model_object->instances) o->add_instance(*instance); - // o->invalidate_bounding_box(); + o->invalidate_bounding_box(); if (o->volumes.size() == model_object->volumes.size()) { for (int i = 0; i < o->volumes.size(); i++) {