mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-07 23:17:35 -06:00
ENH: add fill in bed arrangement
Also add an option to add_object_to_list to speedup. Change-Id: I9860a950fb98b144d831ded11d5911d3aba77ba5 (cherry picked from commit aa9dd9a02ef4ac4cd6987b02b0c9be6d9ce9097f)
This commit is contained in:
parent
a73ff69860
commit
f19c83ce38
7 changed files with 56 additions and 38 deletions
|
@ -1013,6 +1013,7 @@ void MenuFactory::create_object_menu()
|
||||||
|
|
||||||
void MenuFactory::create_bbl_object_menu()
|
void MenuFactory::create_bbl_object_menu()
|
||||||
{
|
{
|
||||||
|
append_menu_item_fill_bed(&m_object_menu);
|
||||||
// Object Clone
|
// Object Clone
|
||||||
append_menu_item_clone(&m_object_menu);
|
append_menu_item_clone(&m_object_menu);
|
||||||
// Object Repair
|
// Object Repair
|
||||||
|
@ -1620,6 +1621,12 @@ void MenuFactory::append_menu_item_locked(wxMenu* menu)
|
||||||
}, item->GetId());
|
}, 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()
|
void MenuFactory::update_object_menu()
|
||||||
{
|
{
|
||||||
|
|
|
@ -150,7 +150,7 @@ private:
|
||||||
void append_menu_item_change_filament(wxMenu* menu);
|
void append_menu_item_change_filament(wxMenu* menu);
|
||||||
void append_menu_item_set_printable(wxMenu* menu);
|
void append_menu_item_set_printable(wxMenu* menu);
|
||||||
void append_menu_item_locked(wxMenu* menu);
|
void append_menu_item_locked(wxMenu* menu);
|
||||||
|
void append_menu_item_fill_bed(wxMenu *menu);
|
||||||
};
|
};
|
||||||
|
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -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];
|
auto model_object = (*m_objects)[obj_idx];
|
||||||
//BBS start add obj_idx for debug
|
//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());
|
const auto item = m_objects_model->AddObject(model_object, warning_bitmap, model_object->is_cut());
|
||||||
Expand(m_objects_model->GetParent(item));
|
Expand(m_objects_model->GetParent(item));
|
||||||
|
|
||||||
|
if (!do_info_update)
|
||||||
|
return;
|
||||||
|
|
||||||
update_info_items(obj_idx, nullptr, call_selection_changed);
|
update_info_items(obj_idx, nullptr, call_selection_changed);
|
||||||
|
|
||||||
add_volumes_to_object_in_list(obj_idx);
|
add_volumes_to_object_in_list(obj_idx);
|
||||||
|
|
|
@ -325,7 +325,8 @@ public:
|
||||||
void part_selection_changed();
|
void part_selection_changed();
|
||||||
|
|
||||||
// Add object to the list
|
// 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
|
// Add object's volumes to the list
|
||||||
// Return selected items, if add_to_selection is defined
|
// Return selected items, if add_to_selection is defined
|
||||||
wxDataViewItemArray add_volumes_to_object_in_list(size_t obj_idx, std::function<bool(const ModelVolume *)> add_to_selection = nullptr);
|
wxDataViewItemArray add_volumes_to_object_in_list(size_t obj_idx, std::function<bool(const ModelVolume *)> add_to_selection = nullptr);
|
||||||
|
|
|
@ -765,8 +765,8 @@ void ArrangeJob::finalize() {
|
||||||
std::optional<arrangement::ArrangePolygon>
|
std::optional<arrangement::ArrangePolygon>
|
||||||
get_wipe_tower_arrangepoly(const Plater &plater)
|
get_wipe_tower_arrangepoly(const Plater &plater)
|
||||||
{
|
{
|
||||||
// BBS FIXME: use actual plate_idx
|
int id = plater.canvas3D()->fff_print()->get_plate_index();
|
||||||
if (auto wti = get_wipe_tower(plater, 0))
|
if (auto wti = get_wipe_tower(plater, id))
|
||||||
return get_wipetower_arrange_poly(&wti);
|
return get_wipetower_arrange_poly(&wti);
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
|
@ -775,12 +775,12 @@ get_wipe_tower_arrangepoly(const Plater &plater)
|
||||||
//BBS: add sudoku-style stride
|
//BBS: add sudoku-style stride
|
||||||
double bed_stride_x(const Plater* plater) {
|
double bed_stride_x(const Plater* plater) {
|
||||||
double bedwidth = plater->build_volume().bounding_box().size().x();
|
double bedwidth = plater->build_volume().bounding_box().size().x();
|
||||||
return scaled<double>((1. + LOGICAL_BED_GAP) * bedwidth);
|
return (1. + LOGICAL_BED_GAP) * bedwidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
double bed_stride_y(const Plater* plater) {
|
double bed_stride_y(const Plater* plater) {
|
||||||
double beddepth = plater->build_volume().bounding_box().size().y();
|
double beddepth = plater->build_volume().bounding_box().size().y();
|
||||||
return scaled<double>((1. + LOGICAL_BED_GAP) * beddepth);
|
return (1. + LOGICAL_BED_GAP) * beddepth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "slic3r/GUI/Plater.hpp"
|
#include "slic3r/GUI/Plater.hpp"
|
||||||
#include "slic3r/GUI/GLCanvas3D.hpp"
|
#include "slic3r/GUI/GLCanvas3D.hpp"
|
||||||
#include "slic3r/GUI/GUI_ObjectList.hpp"
|
#include "slic3r/GUI/GUI_ObjectList.hpp"
|
||||||
|
#include "libnest2d/common.hpp"
|
||||||
|
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
|
|
||||||
|
@ -134,14 +135,15 @@ void FillBedJob::prepare()
|
||||||
ap.bed_idx = arrangement::UNARRANGED;
|
ap.bed_idx = arrangement::UNARRANGED;
|
||||||
|
|
||||||
m_unselected.emplace_back(ap);
|
m_unselected.emplace_back(ap);
|
||||||
}
|
}*/
|
||||||
|
|
||||||
if (auto wt = get_wipe_tower_arrangepoly(*m_plater))
|
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<double>(1.) * scaled(1.);
|
double sc = scaled<double>(1.) * scaled(1.);
|
||||||
|
|
||||||
ExPolygon poly = m_selected.front().poly;
|
const GLCanvas3D::ArrangeSettings& settings = static_cast<const GLCanvas3D*>(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 poly_area = poly.area() / sc;
|
||||||
double unsel_area = std::accumulate(m_unselected.begin(),
|
double unsel_area = std::accumulate(m_unselected.begin(),
|
||||||
m_unselected.end(), 0.,
|
m_unselected.end(), 0.,
|
||||||
|
@ -171,8 +173,10 @@ void FillBedJob::prepare()
|
||||||
ap.itemid = -1;
|
ap.itemid = -1;
|
||||||
ap.setter = [this, mi](const ArrangePolygon &p) {
|
ap.setter = [this, mi](const ArrangePolygon &p) {
|
||||||
ModelObject *mo = m_plater->model().objects[m_object_idx];
|
ModelObject *mo = m_plater->model().objects[m_object_idx];
|
||||||
ModelInstance *inst = mo->add_instance(*mi);
|
ModelObject* newObj = m_plater->model().add_object(*mo);
|
||||||
inst->apply_arrange_result(p.translation.cast<double>(), p.rotation);
|
newObj->name = mo->name +" "+ std::to_string(p.itemid);
|
||||||
|
for (ModelInstance *newInst : newObj->instances) { newInst->apply_arrange_result(p.translation.cast<double>(), p.rotation); }
|
||||||
|
//m_plater->sidebar().obj_list()->paste_objects_into_list({m_plater->model().objects.size()-1});
|
||||||
};
|
};
|
||||||
m_selected.emplace_back(ap);
|
m_selected.emplace_back(ap);
|
||||||
}
|
}
|
||||||
|
@ -199,6 +203,13 @@ void FillBedJob::process()
|
||||||
arrangement::ArrangeParams params;
|
arrangement::ArrangeParams params;
|
||||||
params.allow_rotations = settings.enable_rotation;
|
params.allow_rotations = settings.enable_rotation;
|
||||||
params.min_obj_distance = scaled(settings.distance);
|
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;
|
bool do_stop = false;
|
||||||
params.stopcondition = [this, &do_stop]() {
|
params.stopcondition = [this, &do_stop]() {
|
||||||
|
@ -206,8 +217,8 @@ void FillBedJob::process()
|
||||||
};
|
};
|
||||||
|
|
||||||
params.progressind = [this](unsigned st,std::string str="") {
|
params.progressind = [this](unsigned st,std::string str="") {
|
||||||
// if (st > 0)
|
if (st > 0)
|
||||||
// update_status(int(m_status_range - st), _L("Filling bed " + str));
|
update_status(st, _L("Filling bed " + str));
|
||||||
};
|
};
|
||||||
|
|
||||||
params.on_packed = [&do_stop] (const ArrangePolygon &ap) {
|
params.on_packed = [&do_stop] (const ArrangePolygon &ap) {
|
||||||
|
@ -217,9 +228,9 @@ void FillBedJob::process()
|
||||||
arrangement::arrange(m_selected, m_unselected, m_bedpts, params);
|
arrangement::arrange(m_selected, m_unselected, m_bedpts, params);
|
||||||
|
|
||||||
// finalize just here.
|
// finalize just here.
|
||||||
// update_status(m_status_range, was_canceled() ?
|
update_status(m_status_range, was_canceled() ?
|
||||||
// _(L("Bed filling canceled.")) :
|
_(L("Bed filling canceled.")) :
|
||||||
// _(L("Bed filling done.")));
|
_(L("Bed filling done.")));
|
||||||
}
|
}
|
||||||
|
|
||||||
void FillBedJob::finalize()
|
void FillBedJob::finalize()
|
||||||
|
@ -243,11 +254,14 @@ void FillBedJob::finalize()
|
||||||
return s + int(ap.priority == 0 && ap.bed_idx == 0);
|
return s + int(ap.priority == 0 && ap.bed_idx == 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
int oldSize = m_plater->model().objects.size();
|
||||||
|
|
||||||
if (added_cnt > 0) {
|
if (added_cnt > 0) {
|
||||||
//BBS: adjust the selected instances
|
//BBS: adjust the selected instances
|
||||||
for (ArrangePolygon& ap : m_selected) {
|
for (ArrangePolygon& ap : m_selected) {
|
||||||
if (ap.bed_idx != 0) {
|
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<double>(ap.translation(X)) % unscale<double>(ap.translation(Y));
|
||||||
|
/*if (ap.itemid == -1)*/
|
||||||
continue;
|
continue;
|
||||||
ap.bed_idx = plate_list.get_plate_count();
|
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<double>(ap.translation(X)) % unscale<double>(ap.translation(Y));
|
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(":selected: bed_id %1%, trans {%2%,%3%}") % ap.bed_idx % unscale<double>(ap.translation(X)) % unscale<double>(ap.translation(Y));
|
||||||
}
|
}
|
||||||
for (size_t inst_idx = 0; inst_idx < model_object->instances.size(); ++inst_idx)
|
|
||||||
{
|
int newSize = m_plater->model().objects.size();
|
||||||
plate_list.notify_instance_update(m_object_idx, inst_idx);
|
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) {
|
/*for (ArrangePolygon& ap : m_selected) {
|
||||||
if (ap.bed_idx != arrangement::UNARRANGED && (ap.priority != 0 || ap.bed_idx == 0))
|
if (ap.bed_idx != arrangement::UNARRANGED && (ap.priority != 0 || ap.bed_idx == 0))
|
||||||
ap.apply();
|
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();
|
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();
|
Job::finalize();
|
||||||
|
|
|
@ -1961,7 +1961,9 @@ void Selection::update_type()
|
||||||
unsigned int sels_cntr = 0;
|
unsigned int sels_cntr = 0;
|
||||||
for (ObjectIdxsToInstanceIdxsMap::iterator it = m_cache.content.begin(); it != m_cache.content.end(); ++it)
|
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 volumes_count = (unsigned int)model_object->volumes.size();
|
||||||
unsigned int instances_count = (unsigned int)model_object->instances.size();
|
unsigned int instances_count = (unsigned int)model_object->instances.size();
|
||||||
sels_cntr += volumes_count * instances_count;
|
sels_cntr += volumes_count * instances_count;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue