diff --git a/src/slic3r/GUI/GUI_Factories.cpp b/src/slic3r/GUI/GUI_Factories.cpp index 0c87d2a1ef..8b73aac839 100644 --- a/src/slic3r/GUI/GUI_Factories.cpp +++ b/src/slic3r/GUI/GUI_Factories.cpp @@ -1013,6 +1013,7 @@ void MenuFactory::create_object_menu() void MenuFactory::create_bbl_object_menu() { + append_menu_item_fill_bed(&m_object_menu); // Object Clone append_menu_item_clone(&m_object_menu); // Object Repair @@ -1620,6 +1621,12 @@ void MenuFactory::append_menu_item_locked(wxMenu* menu) }, item->GetId()); } +void MenuFactory::append_menu_item_fill_bed(wxMenu *menu) +{ + append_menu_item( + menu, wxID_ANY, _L("Fill bed with copies") + dots, _L("Fill the remaining area of bed with copies of the selected object"), + [](wxCommandEvent &) { plater()->fill_bed_with_instances(); }, "", nullptr, []() { return plater()->can_increase_instances(); }, m_parent); +} void MenuFactory::update_object_menu() { diff --git a/src/slic3r/GUI/GUI_Factories.hpp b/src/slic3r/GUI/GUI_Factories.hpp index 3d99a072bd..9b815c1b7d 100644 --- a/src/slic3r/GUI/GUI_Factories.hpp +++ b/src/slic3r/GUI/GUI_Factories.hpp @@ -150,7 +150,7 @@ private: void append_menu_item_change_filament(wxMenu* menu); void append_menu_item_set_printable(wxMenu* menu); void append_menu_item_locked(wxMenu* menu); - + void append_menu_item_fill_bed(wxMenu *menu); }; }} diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 1b676ab67f..f55b3ccfce 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -3547,7 +3547,7 @@ void ObjectList::update_info_items(size_t obj_idx, wxDataViewItemArray* selectio -void ObjectList::add_object_to_list(size_t obj_idx, bool call_selection_changed, bool notify_partplate) +void ObjectList::add_object_to_list(size_t obj_idx, bool call_selection_changed, bool notify_partplate, bool do_info_update) { auto model_object = (*m_objects)[obj_idx]; //BBS start add obj_idx for debug @@ -3564,6 +3564,9 @@ void ObjectList::add_object_to_list(size_t obj_idx, bool call_selection_changed, const auto item = m_objects_model->AddObject(model_object, warning_bitmap, model_object->is_cut()); Expand(m_objects_model->GetParent(item)); + if (!do_info_update) + return; + update_info_items(obj_idx, nullptr, call_selection_changed); add_volumes_to_object_in_list(obj_idx); diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp index da1302ed5b..aef19b80e3 100644 --- a/src/slic3r/GUI/GUI_ObjectList.hpp +++ b/src/slic3r/GUI/GUI_ObjectList.hpp @@ -325,7 +325,8 @@ public: void part_selection_changed(); // Add object to the list - void add_object_to_list(size_t obj_idx, bool call_selection_changed = true, bool notify_partplate = true); + // @param do_info_update: [Arthur] this function becomes slow as more functions are added, but I only need a fast version in FillBedJob, and I don't care about any info updates, so I pass a do_info_update param to skip all the uneccessary steps. + void add_object_to_list(size_t obj_idx, bool call_selection_changed = true, bool notify_partplate = true, bool do_info_update = true); // Add object's volumes to the list // Return selected items, if add_to_selection is defined wxDataViewItemArray add_volumes_to_object_in_list(size_t obj_idx, std::function add_to_selection = nullptr); diff --git a/src/slic3r/GUI/Jobs/ArrangeJob.cpp b/src/slic3r/GUI/Jobs/ArrangeJob.cpp index 9e3edaa248..50eaf9d40e 100644 --- a/src/slic3r/GUI/Jobs/ArrangeJob.cpp +++ b/src/slic3r/GUI/Jobs/ArrangeJob.cpp @@ -765,8 +765,8 @@ void ArrangeJob::finalize() { std::optional get_wipe_tower_arrangepoly(const Plater &plater) { - // BBS FIXME: use actual plate_idx - if (auto wti = get_wipe_tower(plater, 0)) + int id = plater.canvas3D()->fff_print()->get_plate_index(); + if (auto wti = get_wipe_tower(plater, id)) return get_wipetower_arrange_poly(&wti); return {}; @@ -775,12 +775,12 @@ get_wipe_tower_arrangepoly(const Plater &plater) //BBS: add sudoku-style stride double bed_stride_x(const Plater* plater) { double bedwidth = plater->build_volume().bounding_box().size().x(); - return scaled((1. + LOGICAL_BED_GAP) * bedwidth); + return (1. + LOGICAL_BED_GAP) * bedwidth; } double bed_stride_y(const Plater* plater) { double beddepth = plater->build_volume().bounding_box().size().y(); - return scaled((1. + LOGICAL_BED_GAP) * beddepth); + return (1. + LOGICAL_BED_GAP) * beddepth; } diff --git a/src/slic3r/GUI/Jobs/FillBedJob.cpp b/src/slic3r/GUI/Jobs/FillBedJob.cpp index e30affafdb..e3613cacee 100644 --- a/src/slic3r/GUI/Jobs/FillBedJob.cpp +++ b/src/slic3r/GUI/Jobs/FillBedJob.cpp @@ -6,6 +6,7 @@ #include "slic3r/GUI/Plater.hpp" #include "slic3r/GUI/GLCanvas3D.hpp" #include "slic3r/GUI/GUI_ObjectList.hpp" +#include "libnest2d/common.hpp" #include @@ -134,14 +135,15 @@ void FillBedJob::prepare() ap.bed_idx = arrangement::UNARRANGED; m_unselected.emplace_back(ap); - } - + }*/ if (auto wt = get_wipe_tower_arrangepoly(*m_plater)) - m_unselected.emplace_back(std::move(*wt));*/ + m_unselected.emplace_back(std::move(*wt)); double sc = scaled(1.) * scaled(1.); - ExPolygon poly = m_selected.front().poly; + const GLCanvas3D::ArrangeSettings& settings = static_cast(m_plater->canvas3D())->get_arrange_settings(); + auto polys = offset_ex(m_selected.front().poly, scaled(settings.distance) / 2); + ExPolygon poly = polys.empty() ? m_selected.front().poly : polys.front(); double poly_area = poly.area() / sc; double unsel_area = std::accumulate(m_unselected.begin(), m_unselected.end(), 0., @@ -171,8 +173,10 @@ void FillBedJob::prepare() ap.itemid = -1; ap.setter = [this, mi](const ArrangePolygon &p) { ModelObject *mo = m_plater->model().objects[m_object_idx]; - ModelInstance *inst = mo->add_instance(*mi); - inst->apply_arrange_result(p.translation.cast(), p.rotation); + ModelObject* newObj = m_plater->model().add_object(*mo); + newObj->name = mo->name +" "+ std::to_string(p.itemid); + for (ModelInstance *newInst : newObj->instances) { newInst->apply_arrange_result(p.translation.cast(), p.rotation); } + //m_plater->sidebar().obj_list()->paste_objects_into_list({m_plater->model().objects.size()-1}); }; m_selected.emplace_back(ap); } @@ -199,6 +203,13 @@ void FillBedJob::process() arrangement::ArrangeParams params; params.allow_rotations = settings.enable_rotation; params.min_obj_distance = scaled(settings.distance); + params.avoid_extrusion_cali_region = settings.avoid_extrusion_cali_region; + auto &partplate_list = m_plater->get_partplate_list(); + auto &print = wxGetApp().plater()->get_partplate_list().get_current_fff_print(); + if (params.avoid_extrusion_cali_region && print.full_print_config().opt_bool("scan_first_layer")) + partplate_list.preprocess_nonprefered_areas(m_unselected, MAX_NUM_PLATES); + + for (auto &ap : m_selected) { ap.inflation = params.min_obj_distance / 2; } bool do_stop = false; params.stopcondition = [this, &do_stop]() { @@ -206,8 +217,8 @@ void FillBedJob::process() }; params.progressind = [this](unsigned st,std::string str="") { - // if (st > 0) - // update_status(int(m_status_range - st), _L("Filling bed " + str)); + if (st > 0) + update_status(st, _L("Filling bed " + str)); }; params.on_packed = [&do_stop] (const ArrangePolygon &ap) { @@ -217,9 +228,9 @@ void FillBedJob::process() arrangement::arrange(m_selected, m_unselected, m_bedpts, params); // finalize just here. - // update_status(m_status_range, was_canceled() ? - // _(L("Bed filling canceled.")) : - // _(L("Bed filling done."))); + update_status(m_status_range, was_canceled() ? + _(L("Bed filling canceled.")) : + _(L("Bed filling done."))); } void FillBedJob::finalize() @@ -243,11 +254,14 @@ void FillBedJob::finalize() return s + int(ap.priority == 0 && ap.bed_idx == 0); }); + int oldSize = m_plater->model().objects.size(); + if (added_cnt > 0) { //BBS: adjust the selected instances for (ArrangePolygon& ap : m_selected) { if (ap.bed_idx != 0) { - if (ap.itemid == -1) + BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(":skipped: bed_id %1%, trans {%2%,%3%}") % ap.bed_idx % unscale(ap.translation(X)) % unscale(ap.translation(Y)); + /*if (ap.itemid == -1)*/ continue; ap.bed_idx = plate_list.get_plate_count(); } @@ -263,33 +277,24 @@ void FillBedJob::finalize() BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(":selected: bed_id %1%, trans {%2%,%3%}") % ap.bed_idx % unscale(ap.translation(X)) % unscale(ap.translation(Y)); } - for (size_t inst_idx = 0; inst_idx < model_object->instances.size(); ++inst_idx) - { - plate_list.notify_instance_update(m_object_idx, inst_idx); + + int newSize = m_plater->model().objects.size(); + auto obj_list = m_plater->sidebar().obj_list(); + for (size_t i = oldSize; i < newSize; i++) { + obj_list->add_object_to_list(i, true, true, false); } + BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << ": paste_objects_into_list"; + /*for (ArrangePolygon& ap : m_selected) { if (ap.bed_idx != arrangement::UNARRANGED && (ap.priority != 0 || ap.bed_idx == 0)) ap.apply(); }*/ - model_object->ensure_on_bed(); + //model_object->ensure_on_bed(); + //BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << ": model_object->ensure_on_bed()"; m_plater->update(); - - //BBS: add partplate related logic - int added_cnt = std::accumulate(m_selected.begin(), m_selected.end(), 0, - [cur_plate](int s, auto& ap) { - return s + int(ap.priority == 0 && ap.bed_idx == cur_plate); - //return s + int(ap.priority == 0 && ap.bed_idx == 0); - }); - - // FIXME: somebody explain why this is needed for increase_object_instances - if (inst_cnt == 1) added_cnt++; - - if (added_cnt > 0) - m_plater->sidebar() - .obj_list()->increase_object_instances(m_object_idx, size_t(added_cnt)); } Job::finalize(); diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index d91db4725d..d2908035cf 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -1961,7 +1961,9 @@ void Selection::update_type() unsigned int sels_cntr = 0; for (ObjectIdxsToInstanceIdxsMap::iterator it = m_cache.content.begin(); it != m_cache.content.end(); ++it) { - const ModelObject* model_object = m_model->objects[it->first]; + bool is_wipe_tower = it->first >= 1000; + int actual_obj_id = is_wipe_tower ? it->first - 1000 : it->first; + const ModelObject *model_object = m_model->objects[actual_obj_id]; unsigned int volumes_count = (unsigned int)model_object->volumes.size(); unsigned int instances_count = (unsigned int)model_object->instances.size(); sels_cntr += volumes_count * instances_count;