From 9d736ee68f2ebb58109215f6a8015ceef2ba1cbc Mon Sep 17 00:00:00 2001 From: YuSanka Date: Mon, 22 May 2023 16:03:15 +0200 Subject: [PATCH] Fix for #10631 - Negative Volumes get messed up when cutting an object + After cut by contours: * Set merged volume name as same as a object name * Merge all SolidPart but not Connectors --- src/slic3r/GUI/Gizmos/GLGizmoCut.cpp | 69 ++++++++++++++++++++++++---- src/slic3r/GUI/Gizmos/GLGizmoCut.hpp | 1 + 2 files changed, 60 insertions(+), 10 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp index c6ede9ceb..9f919af72 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp @@ -22,6 +22,7 @@ namespace GUI { static const ColorRGBA GRABBER_COLOR = ColorRGBA::YELLOW(); static const ColorRGBA UPPER_PART_COLOR = ColorRGBA::CYAN(); static const ColorRGBA LOWER_PART_COLOR = ColorRGBA::MAGENTA(); +static const ColorRGBA MODIFIER_COLOR = ColorRGBA(0.75f, 0.75f, 0.75f, 0.5f); // connector colors static const ColorRGBA PLAG_COLOR = ColorRGBA::YELLOW(); @@ -1405,7 +1406,7 @@ GLGizmoCut3D::PartSelection::PartSelection(const ModelObject* mo, const Transfor m_parts.clear(); for (const ModelVolume* volume : volumes) { assert(volume != nullptr); - m_parts.emplace_back(Part{GLModel(), MeshRaycaster(volume->mesh()), true}); + m_parts.emplace_back(Part{GLModel(), MeshRaycaster(volume->mesh()), true, !volume->is_model_part()}); m_parts.back().glmodel.set_color({ 0.f, 0.f, 1.f, 1.f }); m_parts.back().glmodel.init_from(volume->mesh()); @@ -1484,13 +1485,19 @@ void GLGizmoCut3D::PartSelection::render(const Vec3d* normal, GLModel& sphere_mo 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)); - m_parts[id].glmodel.set_color(m_parts[id].selected ? UPPER_PART_COLOR : LOWER_PART_COLOR); + if (m_parts[id].is_modifier) { + glsafe(::glEnable(GL_BLEND)); + glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); + } + m_parts[id].glmodel.set_color(m_parts[id].is_modifier ? MODIFIER_COLOR : (m_parts[id].selected ? UPPER_PART_COLOR : LOWER_PART_COLOR)); m_parts[id].glmodel.render(); + if (m_parts[id].is_modifier) + glsafe(::glDisable(GL_BLEND)); } shader->stop_using(); @@ -1551,7 +1558,7 @@ bool GLGizmoCut3D::PartSelection::is_one_object() const if (m_parts.size() < 2) return true; return std::all_of(m_parts.begin(), m_parts.end(), [this](const Part& part) { - return part.selected == m_parts.front().selected; + return part.is_modifier || part.selected == m_parts.front().selected; }); } @@ -2535,29 +2542,66 @@ void GLGizmoCut3D::perform_cut(const Selection& selection) }; const size_t cut_parts_cnt = m_part_selection.parts().size(); + bool has_modifiers = false; + + // Distribute SolidParts to the Upper/Lower object for (size_t id = 0; id < cut_parts_cnt; ++id) { - if (ModelObject* obj = (m_part_selection.parts()[id].selected ? upper : lower)) + if (m_part_selection.parts()[id].is_modifier) + has_modifiers = true; // modifiers will be added later to the related parts + else if (ModelObject* obj = (m_part_selection.parts()[id].selected ? upper : lower)) obj->add_volume(*(cut_mo->volumes[id])); } + if (has_modifiers) { + // Distribute Modifiers to the Upper/Lower object + auto upper_bb = upper ? upper->instance_bounding_box(instance_idx) : BoundingBoxf3(); + auto lower_bb = lower ? lower->instance_bounding_box(instance_idx) : BoundingBoxf3(); + const Transform3d inst_matrix = cut_mo->instances[instance_idx]->get_transformation().get_matrix(); + + for (size_t id = 0; id < cut_parts_cnt; ++id) + if (m_part_selection.parts()[id].is_modifier) { + ModelVolume* vol = cut_mo->volumes[id]; + auto bb = vol->mesh().transformed_bounding_box(inst_matrix * vol->get_matrix()); + // Don't add modifiers which are not intersecting with solid parts + if (upper_bb.intersects(bb)) + upper->add_volume(*vol); + if (lower_bb.intersects(bb)) + lower->add_volume(*vol); + } + } + ModelVolumePtrs& volumes = cut_mo->volumes; - if (volumes.size() == cut_parts_cnt) + if (volumes.size() == cut_parts_cnt) { + // Means that object is cut without connectors + + // Just add Upper and Lower objects to cut_object_ptrs and invalidate any cut information add_cut_objects(cut_object_ptrs, upper, lower); + } else if (volumes.size() > cut_parts_cnt) { + // Means that object is cut with connectors + + // All volumes are distributed to Upper / Lower object, + // So we don’t need them anymore for (size_t id = 0; id < cut_parts_cnt; id++) delete *(volumes.begin() + id); volumes.erase(volumes.begin(), volumes.begin() + cut_parts_cnt); + // Perform cut just to get connectors const ModelObjectPtrs 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); + // Connectors from upper object for (const ModelVolume* volume : cut_connectors_obj[0]->volumes) upper->add_volume(*volume, volume->type()); + + // Connectors from lower object for (const ModelVolume* volume : cut_connectors_obj[1]->volumes) lower->add_volume(*volume, volume->type()); + // Add Upper and Lower objects to cut_object_ptrs with saved cut information add_cut_objects(cut_object_ptrs, upper, lower, false); + // Add Dowel-connectors as separate objects to cut_object_ptrs 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]); @@ -2567,8 +2611,9 @@ void GLGizmoCut3D::perform_cut(const Selection& selection) { for (ModelObject* mo : cut_object_ptrs) { TriangleMesh mesh; + // Merge all SolidPart but not Connectors for (const ModelVolume* mv : mo->volumes) { - if (mv->is_model_part()) { + if (mv->is_model_part() && !mv->is_cut_connector()) { TriangleMesh m = mv->mesh(); m.transform(mv->get_matrix()); mesh.merge(m); @@ -2576,9 +2621,13 @@ void GLGizmoCut3D::perform_cut(const Selection& selection) } if (! mesh.empty()) { ModelVolume* new_volume = mo->add_volume(mesh); - for (int i=int(mo->volumes.size())-2; i>=0; --i) - if (mo->volumes[i]->type() == ModelVolumeType::MODEL_PART) + new_volume->name = mo->name; + // Delete all merged SolidPart but not Connectors + for (int i=int(mo->volumes.size())-2; i>=0; --i) { + const ModelVolume* mv = mo->volumes[i]; + if (mv->is_model_part() && !mv->is_cut_connector()) mo->delete_volume(i); + } } } } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp index 75fc54597..6d1a8e4e5 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp @@ -149,6 +149,7 @@ class GLGizmoCut3D : public GLGizmoBase GLModel glmodel; MeshRaycaster raycaster; bool selected; + bool is_modifier; }; void render(const Vec3d* normal, GLModel& sphere_model);