FIX:upgrade cut code from PrusaSlicer
jira:none code is from PrusaSlicer,thanks for PrusaSlicer and YuSanka Author: YuSanka <yusanka@gmail.com> Date: Tue Mar 5 15:13:31 2024 +0100 Fix for #12206 - Dowel connector hole often disappears after one of the resultant objects is cut with a dovetail cut Change-Id: Ib21be385f6df3b4ed41c2eb91dc33dd43132f276
This commit is contained in:
parent
542aa02acd
commit
af7b21549f
|
@ -424,10 +424,20 @@ static void distribute_modifiers_from_object(ModelObject *from_obj, const int in
|
|||
|
||||
for (ModelVolume *vol : from_obj->volumes)
|
||||
if (!vol->is_model_part()) {
|
||||
// Don't add modifiers which are processed connectors
|
||||
if (vol->cut_info.is_connector && !vol->cut_info.is_processed)
|
||||
continue;
|
||||
|
||||
// Modifiers are not cut, but we still need to add the instance transformation
|
||||
// to the modifier volume transformation to preserve their shape properly.
|
||||
const auto modifier_trafo = Transformation(from_obj->instances[instance_idx]->get_transformation().get_matrix_no_offset() * vol->get_matrix());
|
||||
|
||||
auto bb = vol->mesh().transformed_bounding_box(inst_matrix * vol->get_matrix());
|
||||
// Don't add modifiers which are not intersecting with solid parts
|
||||
if (obj1_bb.intersects(bb)) to_obj1->add_volume(*vol);
|
||||
if (obj2_bb.intersects(bb)) to_obj2->add_volume(*vol);
|
||||
if (obj1_bb.intersects(bb))
|
||||
to_obj1->add_volume(*vol)->set_transformation(modifier_trafo);
|
||||
if (obj2_bb.intersects(bb))
|
||||
to_obj2->add_volume(*vol)->set_transformation(modifier_trafo);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -451,6 +461,8 @@ static void merge_solid_parts_inside_object(ModelObjectPtrs &objects)
|
|||
const ModelVolume *mv = mo->volumes[i];
|
||||
if (mv->is_model_part() && !mv->is_cut_connector()) mo->delete_volume(i);
|
||||
}
|
||||
// Ensuring that volumes start with solid parts for proper slicing
|
||||
mo->sort_volumes(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -651,14 +663,23 @@ const ModelObjectPtrs &Cut::perform_with_groove(const Groove &groove, const Tran
|
|||
|
||||
// add modifiers
|
||||
for (const ModelVolume *volume : cut_mo->volumes)
|
||||
if (!volume->is_model_part()) upper->add_volume(*volume);
|
||||
if (!volume->is_model_part()) {
|
||||
// Modifiers are not cut, but we still need to add the instance transformation
|
||||
// to the modifier volume transformation to preserve their shape properly.
|
||||
const auto modifier_trafo = Transformation(cut_mo->instances[m_instance]->get_transformation().get_matrix_no_offset() * volume->get_matrix());
|
||||
upper->add_volume(*volume)->set_transformation(modifier_trafo);
|
||||
}
|
||||
|
||||
cut_object_ptrs.push_back(upper);
|
||||
|
||||
// add lower object to the cut_object_ptrs just to correct delete it from the Model destructor and avoid memory leaks
|
||||
cut_object_ptrs.push_back(lower);
|
||||
} else {
|
||||
// add modifiers if object has any
|
||||
reset_instance_transformation(upper, m_instance, m_cut_matrix);
|
||||
reset_instance_transformation(lower, m_instance, m_cut_matrix);
|
||||
|
||||
// Add modifiers if object has any
|
||||
// Note: make it after all transformations are reset for upper/lower object
|
||||
for (const ModelVolume *volume : cut_mo->volumes)
|
||||
if (!volume->is_model_part()) {
|
||||
distribute_modifiers_from_object(cut_mo, m_instance, upper, lower);
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <algorithm>
|
||||
#include "GLGizmosCommon.hpp"
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
#include "slic3r/GUI/format.hpp"
|
||||
#include "slic3r/GUI/Plater.hpp"
|
||||
#include "libslic3r/AppConfig.hpp"
|
||||
#include "../GUI/MsgDialog.hpp"
|
||||
|
@ -850,7 +851,40 @@ void update_object_cut_id(CutObjectBase &cut_id, ModelObjectCutAttributes attrib
|
|||
}
|
||||
}
|
||||
|
||||
void synchronize_model_after_cut(Model &model, const CutObjectBase &cut_id)
|
||||
static void check_objects_after_cut(const ModelObjectPtrs &objects)
|
||||
{
|
||||
std::vector<std::string> err_objects_names;
|
||||
std::vector<int> err_objects_idxs;
|
||||
int obj_idx{0};
|
||||
for (const ModelObject *object : objects) {
|
||||
std::vector<std::string> connectors_names;
|
||||
connectors_names.reserve(object->volumes.size());
|
||||
for (const ModelVolume *vol : object->volumes)
|
||||
if (vol->cut_info.is_connector) connectors_names.push_back(vol->name);
|
||||
const size_t connectors_count = connectors_names.size();
|
||||
sort_remove_duplicates(connectors_names);
|
||||
if (connectors_count != connectors_names.size()) err_objects_names.push_back(object->name);
|
||||
|
||||
// check manifol/repairs
|
||||
auto stats = object->get_object_stl_stats();
|
||||
if (!stats.manifold() || stats.repaired()) err_objects_idxs.push_back(obj_idx);
|
||||
obj_idx++;
|
||||
}
|
||||
|
||||
auto plater = wxGetApp().plater();
|
||||
if (!err_objects_names.empty()) {
|
||||
wxString names = from_u8(err_objects_names[0]);
|
||||
for (size_t i = 1; i < err_objects_names.size(); i++) names += ", " + from_u8(err_objects_names[i]);
|
||||
WarningDialog(plater, format_wxstr("Objects(%1%) have duplicated connectors. "
|
||||
"Some connectors may be missing in slicing result.\n"
|
||||
"Please report to BambuSudio team in which scenario this issue happened.\n"
|
||||
"Thank you.",
|
||||
names))
|
||||
.ShowModal();
|
||||
}
|
||||
}
|
||||
|
||||
void synchronize_model_after_cut(Model &model, const CutObjectBase &cut_id)
|
||||
{
|
||||
for (ModelObject *obj : model.objects)
|
||||
if (obj->is_cut() && obj->cut_id.has_same_id(cut_id) && !obj->cut_id.is_equal(cut_id)) obj->cut_id.copy(cut_id);
|
||||
|
@ -915,6 +949,7 @@ void GLGizmoAdvancedCut::perform_cut(const Selection& selection)
|
|||
const ModelObjectPtrs &new_objects = cut_by_contour ? cut.perform_by_contour(m_part_selection->get_cut_parts(), dowels_count) :
|
||||
cut_with_groove ? cut.perform_with_groove(m_groove, m_rotate_matrix) :
|
||||
cut.perform_with_plane();
|
||||
check_objects_after_cut(new_objects);// Fix for #11487 - Cut Connectors Broken when assigning part to other side
|
||||
// fix_non_manifold_edges
|
||||
#ifdef HAS_WIN10SDK
|
||||
if (is_windows10()) {
|
||||
|
@ -2561,14 +2596,18 @@ PartSelection::PartSelection(
|
|||
const ModelVolumePtrs &volumes = model_object()->volumes;
|
||||
|
||||
// split to parts
|
||||
for (int id = int(volumes.size()) - 1; id >= 0; id--)
|
||||
if (volumes[id]->is_splittable()) volumes[id]->split(1);
|
||||
for (int id = int(volumes.size()) - 1; id >= 0; id--) {
|
||||
auto look = volumes[id]->is_model_part();
|
||||
if (volumes[id]->is_splittable() && volumes[id]->is_model_part()) // we have to split just solid volumes
|
||||
volumes[id]->split(1);
|
||||
}
|
||||
|
||||
const Vec3d inst_offset = model_object()->instances[m_instance_idx]->get_offset();
|
||||
int i = 0;
|
||||
m_cut_parts.resize(volumes.size());
|
||||
for (const ModelVolume *volume : volumes) {
|
||||
assert(volume != nullptr);
|
||||
m_cut_parts[i].is_modifier = !volume->is_model_part();
|
||||
m_cut_parts[i].is_up_part = false;
|
||||
if (m_cut_parts[i].raycaster) { delete m_cut_parts[i].raycaster; }
|
||||
m_cut_parts[i].raycaster = new MeshRaycaster(volume->mesh());
|
||||
|
@ -2645,11 +2684,13 @@ PartSelection::PartSelection(const ModelObject *object, int instance_idx_in) : m
|
|||
m_cut_parts.resize(volumes.size());
|
||||
for (const ModelVolume *volume : volumes) {
|
||||
assert(volume != nullptr);
|
||||
m_cut_parts[i].is_modifier = !volume->is_model_part();
|
||||
if (m_cut_parts[i].raycaster) { delete m_cut_parts[i].raycaster; }
|
||||
m_cut_parts[i].raycaster = new MeshRaycaster(volume->mesh());
|
||||
m_cut_parts[i].glmodel.reset();
|
||||
m_cut_parts[i].glmodel.init_from(volume->mesh_ptr()->its);
|
||||
m_cut_parts[i].trans = Geometry::translation_transform(inst_offset) * model_object()->volumes[i]->get_matrix();
|
||||
// Now check whether this part is below or above the plane.
|
||||
m_cut_parts[i].is_up_part = volume->is_from_upper();
|
||||
i++;
|
||||
}
|
||||
|
@ -2678,7 +2719,16 @@ void PartSelection::part_render(const Vec3d *cut_center, const Vec3d *normal)
|
|||
if (!is_looking_forward)
|
||||
continue;
|
||||
}
|
||||
GLGizmoBase::render_glmodel(m_cut_parts[id].glmodel, m_cut_parts[id].is_up_part ? UPPER_PART_COLOR.get_data() : LOWER_PART_COLOR.get_data(), m_cut_parts[id].trans);
|
||||
if (m_cut_parts[id].is_modifier) {
|
||||
glsafe(::glEnable(GL_BLEND));
|
||||
glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
|
||||
}
|
||||
GLGizmoBase::render_glmodel(m_cut_parts[id].glmodel,
|
||||
m_cut_parts[id].is_modifier ? MODIFIER_COLOR.get_data() :
|
||||
(m_cut_parts[id].is_up_part ? UPPER_PART_COLOR.get_data() : LOWER_PART_COLOR.get_data()),
|
||||
m_cut_parts[id].trans);
|
||||
if (m_cut_parts[id].is_modifier)
|
||||
glsafe(::glDisable(GL_BLEND));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2703,13 +2753,13 @@ bool PartSelection::is_one_object() const
|
|||
// flawlessly. Because it is currently not always so for self-intersecting
|
||||
// objects, let's better check the parts itself:
|
||||
if (m_cut_parts.size() < 2) return true;
|
||||
return std::all_of(m_cut_parts.begin(), m_cut_parts.end(), [this](const PartPara &part) { return part.is_up_part == m_cut_parts.front().is_up_part; });
|
||||
return std::all_of(m_cut_parts.begin(), m_cut_parts.end(), [this](const PartPara &part) { return part.is_modifier || part.is_up_part == m_cut_parts.front().is_up_part; });
|
||||
}
|
||||
|
||||
std::vector<Cut::Part> PartSelection::get_cut_parts()
|
||||
{
|
||||
std::vector<Cut::Part> parts;
|
||||
for (const auto &part : m_cut_parts) parts.push_back({part.is_up_part, false});
|
||||
for (const auto &part : m_cut_parts) parts.push_back({part.is_up_part, part.is_modifier});
|
||||
return parts;
|
||||
}
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ public:
|
|||
MeshRaycaster* raycaster;
|
||||
bool is_up_part;
|
||||
Transform3d trans;
|
||||
bool is_modifier;
|
||||
};
|
||||
void part_render(const Vec3d *cut_center, const Vec3d *normal);
|
||||
void toggle_selection(const Vec2d &mouse_pos);
|
||||
|
|
Loading…
Reference in New Issue