Merge branch 'main' into belt/baseChanges

This commit is contained in:
SoftFever
2026-04-17 15:44:03 +08:00
committed by GitHub
10180 changed files with 1873143 additions and 1865132 deletions

View File

@@ -4507,7 +4507,7 @@ struct Plater::priv
// BBS: backup & restore
std::vector<size_t> load_files(const std::vector<fs::path>& input_files, LoadStrategy strategy, bool ask_multi = false);
std::vector<size_t> load_model_objects(const ModelObjectPtrs& model_objects, bool allow_negative_z = false, bool split_object = false);
std::vector<size_t> load_model_objects(const ModelObjectPtrs& model_objects, bool allow_negative_z = false, bool split_object = false, bool auto_drop = true);
fs::path get_export_file_path(GUI::FileType file_type);
wxString get_export_file(GUI::FileType file_type);
@@ -4538,7 +4538,8 @@ struct Plater::priv
void center_selection();
void drop_selection();
void mirror(Axis axis);
void split_object();
void split_object(bool auto_drop = true);
void split_object(int obj_idx, bool auto_drop = true);
void split_volume();
void scale_selection_to_fit_print_volume();
@@ -6715,14 +6716,37 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
if (new_model != nullptr && new_model->objects.size() > 1) {
//BBS do not popup this dialog
bool new_model_auto_drop = true;
int single_object_answer = false;
if (ask_multi) {
MessageDialog msg_dlg(q, _L("Load these files as a single object with multiple parts?\n"), _L("Object with multiple parts was detected"),
wxICON_WARNING | wxYES | wxNO);
if (msg_dlg.ShowModal() == wxID_YES) { new_model->convert_multipart_object(filaments_cnt); }
RichMessageDialog dlg(q, _L("Load these files as a single object with multiple parts?\n"),
_L("Object with multiple parts was detected"), wxICON_QUESTION | wxYES_NO);
dlg.ShowCheckBox(_L("Auto-Drop"), true);
single_object_answer = dlg.ShowModal();
if (dlg.IsCheckBoxChecked() == false)
new_model_auto_drop = false;
// convert to multipart and split after load_model_objects
// to keep relative positioning if auto_drop == false
if (single_object_answer == wxID_YES || new_model_auto_drop == false)
new_model->convert_multipart_object(filaments_cnt);
}
auto loaded_idxs = load_model_objects(new_model->objects);
// TODO
// DONE always convert to multipart, split afterwards to retain relative position
// DONE if !auto_drop move all objects over the z-position 0, so that none are clipped by the bed.
// DONE retain auto_drop (and printable) state when assembling or splitting objects.
// DONE when manually split to object ask users if looks_like_multipart and none have auto_drob disabled if they want to disable auto_drop for all resulting objects.
// - add icon in object list, similar to fuzzy painting, etc.
auto loaded_idxs = load_model_objects(new_model->objects, false, false, new_model_auto_drop);
obj_idxs.insert(obj_idxs.end(), loaded_idxs.begin(), loaded_idxs.end());
if (single_object_answer == wxID_NO && new_model_auto_drop == false) {
split_object(loaded_idxs[0], new_model_auto_drop);
}
}
if (load_config) {
@@ -6889,7 +6913,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
#define AUTOPLACEMENT_ON_LOAD
std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs& model_objects, bool allow_negative_z, bool split_object)
std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs& model_objects, bool allow_negative_z, bool split_object, bool auto_drop)
{
const Vec3d bed_size = Slic3r::to_3d(this->bed.build_volume().bounding_volume2d().size(), 1.0) - 2.0 * Vec3d::Ones();
@@ -6916,7 +6940,7 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs& mode
#else /* AUTOPLACEMENT_ON_LOAD */
// if object has no defined position(s) we need to rearrange everything after loading
// need_arrange = true;
// add a default instance and center object around origin
// add a default instance and center object around origin
object->center_around_origin(); // also aligns object to Z = 0
ModelInstance* instance = object->add_instance();
@@ -6925,7 +6949,7 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs& mode
instance->set_offset(Slic3r::to_3d(this->bed.build_volume().bed_center(), -object->origin_translation(2)));
#endif /* AUTOPLACEMENT_ON_LOAD */
}
//BBS: when the object is too large, let the user choose whether to scale it down
for (size_t i = 0; i < object->instances.size(); ++i) {
ModelInstance* instance = object->instances[i];
@@ -6955,7 +6979,20 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs& mode
}
}
object->ensure_on_bed(allow_negative_z);
if (!auto_drop) {
for (size_t i = 0; i < object->instances.size(); ++i) {
ModelInstance* instance = object->instances[i];
instance->auto_drop = auto_drop;
}
// if under the bed, move over the bed
double dist_to_bed = std::min(object->min_z(), double(0));
object->translate_instances(Vec3d(0, 0, -dist_to_bed));
}
else {
object->ensure_on_bed(allow_negative_z);
}
if (!split_object) {
//BBS initial assemble transformation
for (ModelObject* model_object : model.objects) {
@@ -6965,7 +7002,7 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs& mode
model_object->instances[i]->set_assemble_transformation(model_object->instances[i]->get_transformation());
}
}
}
}
}
}
@@ -7032,7 +7069,7 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs& mode
// which is updated after a view3D->reload_scene(false, flags & (unsigned int)UpdateParams::FORCE_FULL_SCREEN_REFRESH) call
for (const size_t idx : obj_idxs)
wxGetApp().obj_list()->update_info_items(idx);
object_list_changed();
this->schedule_background_process();
@@ -7484,9 +7521,16 @@ void Plater::find_new_position(const ModelInstancePtrs &instances)
m.apply();
}
void Plater::priv::split_object()
{
// split selected object into multiple objects by its volumes
void Plater::priv::split_object(bool auto_drop /* = true */)
{
int obj_idx = get_selected_object_idx();
priv::split_object(obj_idx, auto_drop);
}
// split provided object into multiple objects by its volumes
void Plater::priv::split_object(int obj_idx, bool auto_drop /* = true */)
{
if (obj_idx == -1)
return;
@@ -7512,12 +7556,30 @@ void Plater::priv::split_object()
Plater::TakeSnapshot snapshot(q, "Split to Objects");
auto is_atleast_one_floating = [new_objects]() {
for (ModelObject* new_object : new_objects) {
if (new_object->get_instance_min_z(0) >= SINKING_MIN_Z_THRESHOLD)
return true;
}
return false;
};
bool split_auto_drop = auto_drop;
if (current_model_object->instances[0]->auto_drop && is_atleast_one_floating()) {
MessageDialog dlg(q, _L("Disable Auto-Drop to preserve z positioning?\n"),
_L("Object with floating parts was detected"), wxICON_QUESTION | wxYES_NO);
if (dlg.ShowModal() == wxID_YES)
split_auto_drop = false;
}
remove(obj_idx);
// load all model objects at once, otherwise the plate would be rearranged after each one
// causing original positions not to be kept
//BBS: set split_object to true to avoid re-compute assemble matrix
std::vector<size_t> idxs = load_model_objects(new_objects, false, true);
std::vector<size_t> idxs = load_model_objects(new_objects, false, true, split_auto_drop);
wxGetApp().plater()->get_view3D_canvas3D()->update_instance_printable_state_for_objects(idxs);
// select newly added objects
for (size_t idx : idxs)
@@ -16750,7 +16812,7 @@ const GLCanvas3D* Plater::canvas3D() const
GLCanvas3D* Plater::get_view3D_canvas3D()
{
return p->view3D->get_canvas3d();
return p ? p->view3D->get_canvas3d() : nullptr;
}
GLCanvas3D* Plater::get_preview_canvas3D()
@@ -16941,11 +17003,11 @@ void Plater::suppress_background_process(const bool stop_background_process)
this->p->suppressed_backround_processing_update = true;
}
void Plater::center_selection() { p->center_selection(); }
void Plater::drop_selection() { p->drop_selection(); }
void Plater::mirror(Axis axis) { p->mirror(axis); }
void Plater::split_object() { p->split_object(); }
void Plater::split_volume() { p->split_volume(); }
void Plater::center_selection() { p->center_selection(); }
void Plater::drop_selection() { p->drop_selection(); }
void Plater::mirror(Axis axis) { p->mirror(axis); }
void Plater::split_object(bool auto_drop) { p->split_object(auto_drop); }
void Plater::split_volume() { p->split_volume(); }
void Plater::optimize_rotation()
{
auto &w = get_ui_job_worker();