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
This commit is contained in:
YuSanka 2023-05-22 16:03:15 +02:00
parent 80b59ef769
commit 9d736ee68f
2 changed files with 60 additions and 10 deletions

View File

@ -22,6 +22,7 @@ namespace GUI {
static const ColorRGBA GRABBER_COLOR = ColorRGBA::YELLOW(); static const ColorRGBA GRABBER_COLOR = ColorRGBA::YELLOW();
static const ColorRGBA UPPER_PART_COLOR = ColorRGBA::CYAN(); static const ColorRGBA UPPER_PART_COLOR = ColorRGBA::CYAN();
static const ColorRGBA LOWER_PART_COLOR = ColorRGBA::MAGENTA(); static const ColorRGBA LOWER_PART_COLOR = ColorRGBA::MAGENTA();
static const ColorRGBA MODIFIER_COLOR = ColorRGBA(0.75f, 0.75f, 0.75f, 0.5f);
// connector colors // connector colors
static const ColorRGBA PLAG_COLOR = ColorRGBA::YELLOW(); static const ColorRGBA PLAG_COLOR = ColorRGBA::YELLOW();
@ -1405,7 +1406,7 @@ GLGizmoCut3D::PartSelection::PartSelection(const ModelObject* mo, const Transfor
m_parts.clear(); m_parts.clear();
for (const ModelVolume* volume : volumes) { for (const ModelVolume* volume : volumes) {
assert(volume != nullptr); 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.set_color({ 0.f, 0.f, 1.f, 1.f });
m_parts.back().glmodel.init_from(volume->mesh()); 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; const bool is_looking_forward = normal && camera.get_dir_forward().dot(*normal) < 0.05;
for (size_t id=0; id<m_parts.size(); ++id) { for (size_t id=0; id<m_parts.size(); ++id) {
if (normal && (( is_looking_forward && m_parts[id].selected) || if (!m_parts[id].is_modifier && normal && ((is_looking_forward && m_parts[id].selected) ||
(!is_looking_forward && !m_parts[id].selected) ) ) (!is_looking_forward && !m_parts[id].selected) ) )
continue; continue;
const Vec3d volume_offset = model_object()->volumes[id]->get_offset(); const Vec3d volume_offset = model_object()->volumes[id]->get_offset();
shader->set_uniform("view_model_matrix", view_inst_matrix * translation_transform(volume_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(); m_parts[id].glmodel.render();
if (m_parts[id].is_modifier)
glsafe(::glDisable(GL_BLEND));
} }
shader->stop_using(); shader->stop_using();
@ -1551,7 +1558,7 @@ bool GLGizmoCut3D::PartSelection::is_one_object() const
if (m_parts.size() < 2) if (m_parts.size() < 2)
return true; return true;
return std::all_of(m_parts.begin(), m_parts.end(), [this](const Part& part) { 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(); 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) { 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])); 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; 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); add_cut_objects(cut_object_ptrs, upper, lower);
}
else if (volumes.size() > cut_parts_cnt) { else if (volumes.size() > cut_parts_cnt) {
// Means that object is cut with connectors
// All volumes are distributed to Upper / Lower object,
// So we dont need them anymore
for (size_t id = 0; id < cut_parts_cnt; id++) for (size_t id = 0; id < cut_parts_cnt; id++)
delete *(volumes.begin() + id); delete *(volumes.begin() + id);
volumes.erase(volumes.begin(), volumes.begin() + cut_parts_cnt); 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); 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); 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) for (const ModelVolume* volume : cut_connectors_obj[0]->volumes)
upper->add_volume(*volume, volume->type()); upper->add_volume(*volume, volume->type());
// Connectors from lower object
for (const ModelVolume* volume : cut_connectors_obj[1]->volumes) for (const ModelVolume* volume : cut_connectors_obj[1]->volumes)
lower->add_volume(*volume, volume->type()); 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_cut_objects(cut_object_ptrs, upper, lower, false);
// Add Dowel-connectors as separate objects to cut_object_ptrs
if (cut_connectors_obj.size() >= 3) if (cut_connectors_obj.size() >= 3)
for (size_t id = 2; id < cut_connectors_obj.size(); id++) for (size_t id = 2; id < cut_connectors_obj.size(); id++)
cut_object_ptrs.push_back(cut_connectors_obj[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) { for (ModelObject* mo : cut_object_ptrs) {
TriangleMesh mesh; TriangleMesh mesh;
// Merge all SolidPart but not Connectors
for (const ModelVolume* mv : mo->volumes) { for (const ModelVolume* mv : mo->volumes) {
if (mv->is_model_part()) { if (mv->is_model_part() && !mv->is_cut_connector()) {
TriangleMesh m = mv->mesh(); TriangleMesh m = mv->mesh();
m.transform(mv->get_matrix()); m.transform(mv->get_matrix());
mesh.merge(m); mesh.merge(m);
@ -2576,9 +2621,13 @@ void GLGizmoCut3D::perform_cut(const Selection& selection)
} }
if (! mesh.empty()) { if (! mesh.empty()) {
ModelVolume* new_volume = mo->add_volume(mesh); ModelVolume* new_volume = mo->add_volume(mesh);
for (int i=int(mo->volumes.size())-2; i>=0; --i) new_volume->name = mo->name;
if (mo->volumes[i]->type() == ModelVolumeType::MODEL_PART) // 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); mo->delete_volume(i);
}
} }
} }
} }

View File

@ -149,6 +149,7 @@ class GLGizmoCut3D : public GLGizmoBase
GLModel glmodel; GLModel glmodel;
MeshRaycaster raycaster; MeshRaycaster raycaster;
bool selected; bool selected;
bool is_modifier;
}; };
void render(const Vec3d* normal, GLModel& sphere_model); void render(const Vec3d* normal, GLModel& sphere_model);