diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 74dabb8e1c..6c316e889a 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -1353,6 +1353,7 @@ void ModelObject::synchronize_model_after_cut() if (obj->is_cut() && obj->cut_id.has_same_id(this->cut_id)) obj->cut_id.copy(this->cut_id); } + this->invalidate_cut(); } void ModelObject::apply_cut_attributes(ModelObjectCutAttributes attributes) @@ -1378,7 +1379,7 @@ void ModelObject::apply_cut_attributes(ModelObjectCutAttributes attributes) void ModelObject::clone_for_cut(ModelObject** obj) { (*obj) = ModelObject::new_clone(*this); - (*obj)->set_model(nullptr); + (*obj)->set_model(this->get_model()); (*obj)->sla_support_points.clear(); (*obj)->sla_drain_holes.clear(); (*obj)->sla_points_status = sla::PointsStatus::NoPoints; @@ -1461,7 +1462,7 @@ static void add_cut_volume(TriangleMesh& mesh, ModelObject* object, const ModelV void ModelObject::process_connector_cut(ModelVolume* volume, const Transform3d& instance_matrix, const Transform3d& cut_matrix, ModelObjectCutAttributes attributes, ModelObject* upper, ModelObject* lower, - std::vector& dowels, Vec3d& local_dowels_displace) + std::vector& dowels) { assert(volume->cut_info.is_connector); volume->cut_info.set_processed(); @@ -1497,9 +1498,6 @@ void ModelObject::process_connector_cut(ModelVolume* volume, const Transform3d& vol->set_rotation(Vec3d::Zero()); vol->set_offset(Z, 0.0); - // Compute the displacement (in instance coordinates) to be applied to place the dowels - local_dowels_displace = lower->full_raw_mesh_bounding_box().size().cwiseProduct(Vec3d(1.0, 1.0, 0.0)); - dowels.push_back(dowel); } @@ -1566,7 +1564,7 @@ void ModelObject::process_volume_cut(ModelVolume* volume, const Transform3d& ins lower_mesh = TriangleMesh(lower_its); } void ModelObject::process_solid_part_cut(ModelVolume* volume, const Transform3d& instance_matrix, const Transform3d& cut_matrix, - ModelObjectCutAttributes attributes, ModelObject* upper, ModelObject* lower, Vec3d& local_displace) + ModelObjectCutAttributes attributes, ModelObject* upper, ModelObject* lower) { // Perform cut TriangleMesh upper_mesh, lower_mesh; @@ -1583,31 +1581,12 @@ void ModelObject::process_solid_part_cut(ModelVolume* volume, const Transform3d& if (attributes.has(ModelObjectCutAttribute::KeepUpper)) add_cut_volume(upper_mesh, upper, volume, cut_matrix); - if (attributes.has(ModelObjectCutAttribute::KeepLower) && !lower_mesh.empty()) { + if (attributes.has(ModelObjectCutAttribute::KeepLower) && !lower_mesh.empty()) add_cut_volume(lower_mesh, lower, volume, cut_matrix); - - // Compute the displacement (in instance coordinates) to be applied to place the upper parts - // The upper part displacement is set to half of the lower part bounding box - // this is done in hope at least a part of the upper part will always be visible and draggable - local_displace = lower->full_raw_mesh_bounding_box().size().cwiseProduct(Vec3d(-0.5, -0.5, 0.0)); - } } -static void invalidate_translations(ModelObject* object, const ModelInstance* src_instance) -{ - if (!object->origin_translation.isApprox(Vec3d::Zero()) && src_instance->get_offset().isApprox(Vec3d::Zero())) { - object->center_around_origin(); - object->translate_instances(-object->origin_translation); - object->origin_translation = Vec3d::Zero(); - } - else { - object->invalidate_bounding_box(); - object->center_around_origin(); - } -} - -static void reset_instance_transformation(ModelObject* object, size_t src_instance_idx, const Transform3d& cut_matrix, - bool place_on_cut = false, bool flip = false, Vec3d local_displace = Vec3d::Zero()) +void ModelObject::reset_instance_transformation(ModelObject* object, size_t src_instance_idx, const Transform3d& cut_matrix, + bool place_on_cut/* = false*/, bool flip/* = false*/) { using namespace Geometry; @@ -1615,15 +1594,8 @@ static void reset_instance_transformation(ModelObject* object, size_t src_instan for (size_t i = 0; i < object->instances.size(); ++i) { auto& obj_instance = object->instances[i]; - const Vec3d offset = obj_instance->get_offset(); const double rot_z = obj_instance->get_rotation().z(); - obj_instance->set_transformation(Transformation()); - - const Vec3d displace = local_displace.isApprox(Vec3d::Zero()) ? Vec3d::Zero() : - rotation_transform(obj_instance->get_rotation()) * local_displace; - obj_instance->set_offset(offset + displace); - Vec3d rotation = Vec3d::Zero(); if (!flip && !place_on_cut) { if ( i != src_instance_idx) @@ -1680,10 +1652,6 @@ ModelObjectPtrs ModelObject::cut(size_t instance, const Transform3d& cut_matrix, const Transformation cut_transformation = Transformation(cut_matrix); const Transform3d inverse_cut_matrix = cut_transformation.get_rotation_matrix().inverse() * translation_transform(-1. * cut_transformation.get_offset()); - // Displacement (in instance coordinates) to be applied to place the upper parts - Vec3d local_displace = Vec3d::Zero(); - Vec3d local_dowels_displace = Vec3d::Zero(); - for (ModelVolume* volume : volumes) { volume->reset_extra_facets(); @@ -1691,10 +1659,10 @@ ModelObjectPtrs ModelObject::cut(size_t instance, const Transform3d& cut_matrix, if (volume->cut_info.is_processed) process_modifier_cut(volume, instance_matrix, inverse_cut_matrix, attributes, upper, lower); else - process_connector_cut(volume, instance_matrix, cut_matrix, attributes, upper, lower, dowels, local_dowels_displace); + process_connector_cut(volume, instance_matrix, cut_matrix, attributes, upper, lower, dowels); } else if (!volume->mesh().empty()) - process_solid_part_cut(volume, instance_matrix, cut_matrix, attributes, upper, lower, local_displace); + process_solid_part_cut(volume, instance_matrix, cut_matrix, attributes, upper, lower); } // Post-process cut parts @@ -1707,31 +1675,22 @@ ModelObjectPtrs ModelObject::cut(size_t instance, const Transform3d& cut_matrix, } else { if (attributes.has(ModelObjectCutAttribute::KeepUpper) && !upper->volumes.empty()) { - invalidate_translations(upper, instances[instance]); - reset_instance_transformation(upper, instance, cut_matrix, attributes.has(ModelObjectCutAttribute::PlaceOnCutUpper), - attributes.has(ModelObjectCutAttribute::FlipUpper), - local_displace); + attributes.has(ModelObjectCutAttribute::FlipUpper)); res.push_back(upper); } if (attributes.has(ModelObjectCutAttribute::KeepLower) && !lower->volumes.empty()) { - invalidate_translations(lower, instances[instance]); - reset_instance_transformation(lower, instance, cut_matrix, attributes.has(ModelObjectCutAttribute::PlaceOnCutLower), - attributes.has(ModelObjectCutAttribute::PlaceOnCutLower) ? true : attributes.has(ModelObjectCutAttribute::FlipLower)); + attributes.has(ModelObjectCutAttribute::PlaceOnCutLower) || attributes.has(ModelObjectCutAttribute::FlipLower)); res.push_back(lower); } if (attributes.has(ModelObjectCutAttribute::CreateDowels) && !dowels.empty()) { for (auto dowel : dowels) { - invalidate_translations(dowel, instances[instance]); - - reset_instance_transformation(dowel, instance, Transform3d::Identity(), false, false, local_dowels_displace); - - local_dowels_displace += dowel->full_raw_mesh_bounding_box().size().cwiseProduct(Vec3d(-1.5, -1.5, 0.0)); + reset_instance_transformation(dowel, instance, Transform3d::Identity()); dowel->name += "-Dowel-" + dowel->volumes[0]->name; res.push_back(dowel); } diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 359e1fbbdf..ccbe0bf640 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -472,13 +472,17 @@ public: void clone_for_cut(ModelObject **obj); void process_connector_cut(ModelVolume* volume, const Transform3d& instance_matrix, const Transform3d& cut_matrix, ModelObjectCutAttributes attributes, ModelObject* upper, ModelObject* lower, - std::vector& dowels, Vec3d& local_dowels_displace); + std::vector& dowels); void process_modifier_cut(ModelVolume* volume, const Transform3d& instance_matrix, const Transform3d& inverse_cut_matrix, ModelObjectCutAttributes attributes, ModelObject* upper, ModelObject* lower); void process_volume_cut(ModelVolume* volume, const Transform3d& instance_matrix, const Transform3d& cut_matrix, ModelObjectCutAttributes attributes, TriangleMesh& upper_mesh, TriangleMesh& lower_mesh); void process_solid_part_cut(ModelVolume* volume, const Transform3d& instance_matrix, const Transform3d& cut_matrix, - ModelObjectCutAttributes attributes, ModelObject* upper, ModelObject* lower, Vec3d& local_displace); + ModelObjectCutAttributes attributes, ModelObject* upper, ModelObject* lower); + + static void reset_instance_transformation(ModelObject* object, size_t src_instance_idx, const Transform3d& cut_matrix, + bool place_on_cut = false, bool flip = false); + ModelObjectPtrs cut(size_t instance, const Transform3d&cut_matrix, ModelObjectCutAttributes attributes); void split(ModelObjectPtrs*new_objects); void merge(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp index edf91aba86..92a38f9ecc 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp @@ -892,6 +892,7 @@ void GLGizmoCut3D::on_set_state() // initiate archived values m_ar_plane_center = m_plane_center; m_start_dragging_m = m_rotation_m; + reset_cut_by_contours(); m_parent.request_extra_frame(); } @@ -1116,6 +1117,8 @@ void GLGizmoCut3D::dragging_grabber_z(const GLGizmoBase::UpdateData &data) projection = m_snap_step * std::round(projection / m_snap_step); const Vec3d shift = starting_vec * projection; + if (shift != Vec3d::Zero()) + reset_cut_by_contours(); // move cut plane center set_center(m_plane_center + shift, true); @@ -1153,6 +1156,9 @@ void GLGizmoCut3D::dragging_grabber_xy(const GLGizmoBase::UpdateData &data) if (m_hover_id == X) theta += 0.5 * PI; + if (!is_approx(theta, 0.0)) + reset_cut_by_contours(); + Vec3d rotation = Vec3d::Zero(); rotation[m_hover_id] = theta; @@ -1187,14 +1193,10 @@ void GLGizmoCut3D::on_dragging(const UpdateData& data) { if (m_hover_id < 0) return; - if (m_hover_id == Z || m_hover_id == CutPlane) { + if (m_hover_id == Z || m_hover_id == CutPlane) dragging_grabber_z(data); - reset_cut_by_contours(); - } - else if (m_hover_id == X || m_hover_id == Y) { + else if (m_hover_id == X || m_hover_id == Y) dragging_grabber_xy(data); - reset_cut_by_contours(); - } else if (m_hover_id >= m_connectors_group_id && m_connector_mode == CutConnectorMode::Manual) dragging_connector(data); } @@ -1301,6 +1303,7 @@ void GLGizmoCut3D::update_bb() m_bounding_box = box; invalidate_cut_plane(); + reset_cut_by_contours(); m_max_pos = box.max; m_min_pos = box.min; @@ -1402,11 +1405,14 @@ void GLGizmoCut3D::PartSelection::render(const Vec3d* normal) // FIXME: Cache the transforms. - const Vec3d inst_offset = model_object->instances[0]->get_offset(); + const Vec3d inst_offset = model_object->instances[instance_idx]->get_offset(); const Transform3d view_inst_matrix= camera.get_view_matrix() * translation_transform(inst_offset); + const bool is_looking_forward = normal && camera.get_dir_forward().dot(*normal) < 0.05; + for (size_t id=0; idvolumes[id]->get_offset(); shader->set_uniform("view_model_matrix", view_inst_matrix * translation_transform(volume_offset)); @@ -1419,7 +1425,6 @@ void GLGizmoCut3D::PartSelection::render(const Vec3d* normal) } } - void GLGizmoCut3D::PartSelection::toggle_selection(const Vec2d& mouse_pos) { // FIXME: Cache the transforms. @@ -1430,7 +1435,7 @@ void GLGizmoCut3D::PartSelection::toggle_selection(const Vec2d& mouse_pos) for (size_t id=0; idvolumes[id]->get_offset(); - Transform3d tr = model_object->instances.front()->get_matrix() * model_object->volumes[id]->get_matrix(); + Transform3d tr = model_object->instances[instance_idx]->get_matrix() * model_object->volumes[id]->get_matrix(); if (parts[id].raycaster.unproject_on_mesh(mouse_pos, tr, camera, pos, normal)) { parts[id].selected = ! parts[id].selected; return; @@ -1438,6 +1443,12 @@ void GLGizmoCut3D::PartSelection::toggle_selection(const Vec2d& mouse_pos) } } +void GLGizmoCut3D::PartSelection::turn_over_selection() +{ + for (Part& part : parts) + part.selected = !part.selected; +} + void GLGizmoCut3D::on_render() { if (m_state == On) { @@ -1708,12 +1719,14 @@ void GLGizmoCut3D::flip_cut_plane() m_start_dragging_m = m_rotation_m; update_clipper(); + m_part_selection.turn_over_selection(); } -GLGizmoCut3D::PartSelection::PartSelection(ModelObject* mo, const Vec3d& center, const Vec3d& normal) +GLGizmoCut3D::PartSelection::PartSelection(ModelObject* mo, int instance_idx_in, const Vec3d& center, const Vec3d& normal) { model_object = mo; // FIXME: Ownership. + instance_idx = instance_idx_in; const ModelVolumePtrs& volumes = mo->volumes; @@ -1730,7 +1743,7 @@ GLGizmoCut3D::PartSelection::PartSelection(ModelObject* mo, const Vec3d& center, parts.back().glmodel.init_from(volume->mesh()); // Now check whether this part is below or above the plane. - Transform3d tr = (model_object->instances.front()->get_matrix() * volume->get_matrix()).inverse(); + Transform3d tr = (model_object->instances[instance_idx]->get_matrix() * volume->get_matrix()).inverse(); Vec3f pos = (tr * center).cast(); Vec3f norm = (tr.linear().inverse().transpose() * normal).cast(); for (const Vec3f& v : volume->mesh().its.vertices) { @@ -1749,7 +1762,10 @@ GLGizmoCut3D::PartSelection::PartSelection(ModelObject* mo, const Vec3d& center, void GLGizmoCut3D::reset_cut_by_contours() { m_part_selection = PartSelection(); - m_parent.toggle_model_objects_visibility(true); + + const Selection& selection = m_parent.get_selection(); + const ModelObjectPtrs& model_objects = selection.get_model()->objects; + m_parent.toggle_model_objects_visibility(true, model_objects[selection.get_object_idx()], selection.get_instance_idx()); } void GLGizmoCut3D::process_contours() @@ -1763,14 +1779,14 @@ void GLGizmoCut3D::process_contours() const int instance_idx = selection.get_instance_idx(); const int object_idx = selection.get_object_idx(); - ModelObjectPtrs moptrs = model_objects[object_idx]->cut(instance_idx, get_cut_matrix(selection), + m_cut_part_ptrs.clear(); + m_cut_part_ptrs = model_objects[object_idx]->cut(instance_idx, get_cut_matrix(selection), ModelObjectCutAttribute::KeepUpper | ModelObjectCutAttribute::KeepLower | - ModelObjectCutAttribute::KeepAsParts | - ModelObjectCutAttribute::InvalidateCutInfo); + ModelObjectCutAttribute::KeepAsParts); + assert(m_cut_part_ptrs.size() == 1); - assert(moptrs.size() == 1); - m_part_selection = PartSelection(moptrs.front(), m_plane_center, m_cut_normal); + m_part_selection = PartSelection(m_cut_part_ptrs.front(), instance_idx, m_plane_center, m_cut_normal); m_parent.toggle_model_objects_visibility(false); } @@ -1919,7 +1935,7 @@ void GLGizmoCut3D::render_cut_plane_input_window(CutConnectors &connectors) ImGuiWrapper::text(_L("Cut result") + ": "); add_vertical_scaled_interval(0.5f); - m_imgui->disabled_begin(has_connectors || m_keep_as_parts); + m_imgui->disabled_begin(has_connectors || m_keep_as_parts || m_part_selection.valid); render_part_name("A", m_keep_upper, m_imgui->to_ImU32(UPPER_PART_COLOR)); ImGui::SameLine(h_shift + ImGui::GetCurrentWindow()->WindowPadding.x); render_part_name("B", m_keep_lower, m_imgui->to_ImU32(LOWER_PART_COLOR)); @@ -1938,6 +1954,9 @@ void GLGizmoCut3D::render_cut_plane_input_window(CutConnectors &connectors) m_imgui->disabled_begin(has_connectors); ImGuiWrapper::text(_L("Cut into") + ":"); + if (m_part_selection.valid) + m_keep_as_parts = false; + add_horizontal_scaled_interval(1.2f); // TRN CutGizmo: RadioButton Cut into ... if (m_imgui->radio_button(_L("Objects"), !m_keep_as_parts)) @@ -2322,21 +2341,88 @@ void GLGizmoCut3D::perform_cut(const Selection& selection) { Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Cut by Plane")); + const bool cut_by_contour = m_part_selection.valid && !m_cut_part_ptrs.empty(); + ModelObject* cut_mo = cut_by_contour ? m_cut_part_ptrs.front() : nullptr; + if (cut_mo) + cut_mo->cut_connectors = mo->cut_connectors; + bool create_dowels_as_separate_object = false; const bool has_connectors = !mo->cut_connectors.empty(); // update connectors pos as offset of its center before cut performing - apply_connectors_in_model(mo, create_dowels_as_separate_object); + apply_connectors_in_model(cut_mo ? cut_mo : mo , create_dowels_as_separate_object); - plater->cut(object_idx, instance_idx, get_cut_matrix(selection), - only_if(has_connectors ? true : m_keep_upper, ModelObjectCutAttribute::KeepUpper) | - only_if(has_connectors ? true : m_keep_lower, ModelObjectCutAttribute::KeepLower) | - only_if(has_connectors ? false: m_keep_as_parts, ModelObjectCutAttribute::KeepAsParts) | - only_if(m_place_on_cut_upper, ModelObjectCutAttribute::PlaceOnCutUpper) | - only_if(m_place_on_cut_lower, ModelObjectCutAttribute::PlaceOnCutLower) | - only_if(m_rotate_upper, ModelObjectCutAttribute::FlipUpper) | - only_if(m_rotate_lower, ModelObjectCutAttribute::FlipLower) | - only_if(create_dowels_as_separate_object, ModelObjectCutAttribute::CreateDowels) | - only_if(!has_connectors, ModelObjectCutAttribute::InvalidateCutInfo)); + wxBusyCursor wait; + + const Transform3d cut_matrix = get_cut_matrix(selection); + + ModelObjectCutAttributes attributes = only_if(has_connectors ? true : m_keep_upper, ModelObjectCutAttribute::KeepUpper) | + only_if(has_connectors ? true : m_keep_lower, ModelObjectCutAttribute::KeepLower) | + only_if(has_connectors ? false : m_keep_as_parts, ModelObjectCutAttribute::KeepAsParts) | + only_if(m_place_on_cut_upper, ModelObjectCutAttribute::PlaceOnCutUpper) | + only_if(m_place_on_cut_lower, ModelObjectCutAttribute::PlaceOnCutLower) | + only_if(m_rotate_upper, ModelObjectCutAttribute::FlipUpper) | + only_if(m_rotate_lower, ModelObjectCutAttribute::FlipLower) | + only_if(create_dowels_as_separate_object, ModelObjectCutAttribute::CreateDowels) | + only_if(!has_connectors, ModelObjectCutAttribute::InvalidateCutInfo); + + ModelObjectPtrs cut_object_ptrs; + if (cut_by_contour) { + // apply cut attributes for object + cut_mo->apply_cut_attributes(ModelObjectCutAttribute::KeepLower | ModelObjectCutAttribute::KeepUpper | + only_if(create_dowels_as_separate_object, ModelObjectCutAttribute::CreateDowels)); + + // Clone the object to duplicate instances, materials etc. + ModelObject* upper{ nullptr }; + cut_mo->clone_for_cut(&upper); + ModelObject* lower{ nullptr }; + cut_mo->clone_for_cut(&lower); + + auto add_cut_objects = [this, &instance_idx, &cut_matrix](ModelObjectPtrs& cut_objects, ModelObject* upper, ModelObject* lower, bool invalidate_cut = true) { + if (!upper->volumes.empty()) { + ModelObject::reset_instance_transformation(upper, instance_idx, cut_matrix, m_place_on_cut_upper, m_rotate_upper); + if (invalidate_cut) + upper->invalidate_cut(); + cut_objects.push_back(upper); + } + if (!lower->volumes.empty()) { + ModelObject::reset_instance_transformation(lower, instance_idx, cut_matrix, m_place_on_cut_lower, m_place_on_cut_lower || m_rotate_lower); + if (invalidate_cut) + lower->invalidate_cut(); + cut_objects.push_back(lower); + } + }; + + const size_t cut_parts_cnt = m_part_selection.parts.size(); + for (size_t id = 0; id < cut_parts_cnt; ++id) + (m_part_selection.parts[id].selected ? upper : lower)->add_volume(*(cut_mo->volumes[id])); + + ModelVolumePtrs& volumes = cut_mo->volumes; + if (volumes.size() == cut_parts_cnt) + add_cut_objects(cut_object_ptrs, upper, lower); + else if (volumes.size() > cut_parts_cnt) { + for (size_t id = 0; id < cut_parts_cnt; id++) + delete *(volumes.begin() + id); + volumes.erase(volumes.begin(), volumes.begin() + cut_parts_cnt); + + const auto cut_connectors_obj = cut_mo->cut(instance_idx, get_cut_matrix(selection), attributes); + assert(create_dowels_as_separate_object ? cut_connectors_obj.size() >= 3 : cut_connectors_obj.size() == 2); + + for (const ModelVolume* volume : cut_connectors_obj[0]->volumes) + upper->add_volume(*volume, volume->type()); + for (const ModelVolume* volume : cut_connectors_obj[1]->volumes) + lower->add_volume(*volume, volume->type()); + + add_cut_objects(cut_object_ptrs, upper, lower, false); + + if (cut_connectors_obj.size() >= 3) + for (size_t id = 2; id < cut_connectors_obj.size(); id++) + cut_object_ptrs.push_back(cut_connectors_obj[id]); + } + } + else + cut_object_ptrs = mo->cut(instance_idx, cut_matrix, attributes); + + plater->cut(object_idx, cut_object_ptrs); } } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp index 9bf805188b..598bc1d5a8 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp @@ -139,10 +139,11 @@ class GLGizmoCut3D : public GLGizmoBase struct PartSelection { PartSelection() = default; - PartSelection(ModelObject* mo, const Vec3d& center, const Vec3d& normal); + PartSelection(ModelObject* mo, int instance_idx, const Vec3d& center, const Vec3d& normal); void render(const Vec3d* normal = nullptr); void toggle_selection(const Vec2d& mouse_pos); + void turn_over_selection(); struct Part { GLModel glmodel; @@ -151,11 +152,13 @@ class GLGizmoCut3D : public GLGizmoBase bool upper; }; ModelObject* model_object; // FIXME: Ownership ! + int instance_idx; std::vector parts; bool valid = false; }; PartSelection m_part_selection; + ModelObjectPtrs m_cut_part_ptrs; bool m_show_shortcuts{ false }; std::vector> m_shortcuts; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 061f39622c..35308c0581 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -6266,7 +6266,11 @@ void Plater::cut(size_t obj_idx, size_t instance_idx, const Transform3d& cut_mat wxBusyCursor wait; const auto new_objects = object->cut(instance_idx, cut_matrix, attributes); + cut(obj_idx, new_objects); +} +void Plater::cut(size_t obj_idx, const ModelObjectPtrs& new_objects) +{ model().delete_object(obj_idx); sidebar().obj_list()->delete_object_from_list(obj_idx); @@ -6284,6 +6288,8 @@ void Plater::cut(size_t obj_idx, size_t instance_idx, const Transform3d& cut_mat size_t last_id = p->model.objects.size() - 1; for (size_t i = 0; i < new_objects.size(); ++i) selection.add_object((unsigned int)(last_id - i), i == 0); + + arrange(); } void Plater::export_gcode(bool prefer_removable) diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 58a840a4b5..0359328699 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -260,6 +260,7 @@ public: void toggle_layers_editing(bool enable); void cut(size_t obj_idx, size_t instance_idx, const Transform3d& cut_matrix, ModelObjectCutAttributes attributes); + void cut(size_t init_obj_idx, const ModelObjectPtrs& cut_objects); void export_gcode(bool prefer_removable); void export_stl_obj(bool extended = false, bool selection_only = false);