mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-16 21:42:43 +00:00
Add instances (#6237)
* Add instances * - Added a new menu item for converting instances to objects, --------- Co-authored-by: SoftFever <softfeverever@gmail.com>
This commit is contained in:
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 7.5 KiB |
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 7.4 KiB |
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 7.1 KiB |
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 7.1 KiB |
@@ -3550,20 +3550,20 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
//case '+': {
|
case '+': {
|
||||||
// if (dynamic_cast<Preview*>(m_canvas->GetParent()) != nullptr)
|
if (dynamic_cast<Preview*>(m_canvas->GetParent()) != nullptr)
|
||||||
// post_event(wxKeyEvent(EVT_GLCANVAS_EDIT_COLOR_CHANGE, evt));
|
post_event(wxKeyEvent(EVT_GLCANVAS_EDIT_COLOR_CHANGE, evt));
|
||||||
// else
|
else
|
||||||
// post_event(Event<int>(EVT_GLCANVAS_INCREASE_INSTANCES, +1));
|
post_event(Event<int>(EVT_GLCANVAS_INCREASE_INSTANCES, +1));
|
||||||
// break;
|
break;
|
||||||
//}
|
}
|
||||||
//case '-': {
|
case '-': {
|
||||||
// if (dynamic_cast<Preview*>(m_canvas->GetParent()) != nullptr)
|
if (dynamic_cast<Preview*>(m_canvas->GetParent()) != nullptr)
|
||||||
// post_event(wxKeyEvent(EVT_GLCANVAS_EDIT_COLOR_CHANGE, evt));
|
post_event(wxKeyEvent(EVT_GLCANVAS_EDIT_COLOR_CHANGE, evt));
|
||||||
// else
|
else
|
||||||
// post_event(Event<int>(EVT_GLCANVAS_INCREASE_INSTANCES, -1));
|
post_event(Event<int>(EVT_GLCANVAS_INCREASE_INSTANCES, -1));
|
||||||
// break;
|
break;
|
||||||
//}
|
}
|
||||||
case '?': { post_event(SimpleEvent(EVT_GLCANVAS_QUESTION_MARK)); break; }
|
case '?': { post_event(SimpleEvent(EVT_GLCANVAS_QUESTION_MARK)); break; }
|
||||||
case 'A':
|
case 'A':
|
||||||
case 'a':
|
case 'a':
|
||||||
@@ -6656,6 +6656,12 @@ void GLCanvas3D::_switch_toolbars_icon_filename()
|
|||||||
item = m_main_toolbar.get_item("arrange");
|
item = m_main_toolbar.get_item("arrange");
|
||||||
item->set_icon_filename(m_is_dark ? "toolbar_arrange_dark.svg" : "toolbar_arrange.svg");
|
item->set_icon_filename(m_is_dark ? "toolbar_arrange_dark.svg" : "toolbar_arrange.svg");
|
||||||
|
|
||||||
|
item = m_main_toolbar.get_item("more");
|
||||||
|
item->set_icon_filename(m_is_dark ? "instance_add_dark.svg" : "instance_add.svg");
|
||||||
|
|
||||||
|
item = m_main_toolbar.get_item("fewer");
|
||||||
|
item->set_icon_filename(m_is_dark ? "instance_remove_dark.svg" : "instance_remove.svg");
|
||||||
|
|
||||||
item = m_main_toolbar.get_item("splitobjects");
|
item = m_main_toolbar.get_item("splitobjects");
|
||||||
item->set_icon_filename(m_is_dark ? "split_objects_dark.svg" : "split_objects.svg");
|
item->set_icon_filename(m_is_dark ? "split_objects_dark.svg" : "split_objects.svg");
|
||||||
|
|
||||||
@@ -6805,6 +6811,30 @@ bool GLCanvas3D::_init_main_toolbar()
|
|||||||
if (!m_main_toolbar.add_separator())
|
if (!m_main_toolbar.add_separator())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
item.name = "more";
|
||||||
|
item.icon_filename = m_is_dark ? "instance_add_dark.svg" : "instance_add.svg";
|
||||||
|
item.tooltip = _utf8(L("Add instance")) + " [+]";
|
||||||
|
item.sprite_id++;
|
||||||
|
item.left.render_callback = nullptr;
|
||||||
|
item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_MORE)); };
|
||||||
|
item.visibility_callback = GLToolbarItem::Default_Visibility_Callback;
|
||||||
|
item.left.toggable = false;
|
||||||
|
item.enabling_callback = []()->bool { return wxGetApp().plater()->can_increase_instances(); };
|
||||||
|
if (!m_main_toolbar.add_item(item))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
item.name = "fewer";
|
||||||
|
item.icon_filename = m_is_dark ? "instance_remove_dark.svg" : "instance_remove.svg";
|
||||||
|
item.tooltip = _utf8(L("Remove instance")) + " [-]";
|
||||||
|
item.sprite_id++;
|
||||||
|
item.left.render_callback = nullptr;
|
||||||
|
item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_FEWER)); };
|
||||||
|
item.visibility_callback = GLToolbarItem::Default_Visibility_Callback;
|
||||||
|
item.left.toggable = false;
|
||||||
|
item.enabling_callback = []()->bool { return wxGetApp().plater()->can_decrease_instances(); };
|
||||||
|
if (!m_main_toolbar.add_item(item))
|
||||||
|
return false;
|
||||||
|
|
||||||
item.name = "splitobjects";
|
item.name = "splitobjects";
|
||||||
item.icon_filename = m_is_dark ? "split_objects_dark.svg" : "split_objects.svg";
|
item.icon_filename = m_is_dark ? "split_objects_dark.svg" : "split_objects.svg";
|
||||||
item.tooltip = _utf8(L("Split to objects"));
|
item.tooltip = _utf8(L("Split to objects"));
|
||||||
|
|||||||
@@ -782,7 +782,7 @@ void MenuFactory::append_menu_item_fill_bed(wxMenu *menu)
|
|||||||
{
|
{
|
||||||
append_menu_item(
|
append_menu_item(
|
||||||
menu, wxID_ANY, _L("Fill bed with copies"), _L("Fill the remaining area of bed with copies of the selected object"),
|
menu, wxID_ANY, _L("Fill bed with copies"), _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);
|
[](wxCommandEvent &) { plater()->fill_bed_with_copies(); }, "", nullptr, []() { return plater()->can_increase_instances(); }, m_parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
wxMenuItem* MenuFactory::append_menu_item_printable(wxMenu* menu)
|
wxMenuItem* MenuFactory::append_menu_item_printable(wxMenu* menu)
|
||||||
@@ -1259,14 +1259,12 @@ void MenuFactory::create_default_menu()
|
|||||||
void MenuFactory::create_common_object_menu(wxMenu* menu)
|
void MenuFactory::create_common_object_menu(wxMenu* menu)
|
||||||
{
|
{
|
||||||
append_menu_item_rename(menu);
|
append_menu_item_rename(menu);
|
||||||
// BBS
|
append_menu_items_instance_manipulation(menu);
|
||||||
//append_menu_items_instance_manipulation(menu);
|
|
||||||
// Delete menu was moved to be after +/- instace to make it more difficult to be selected by mistake.
|
// Delete menu was moved to be after +/- instace to make it more difficult to be selected by mistake.
|
||||||
append_menu_item_delete(menu);
|
append_menu_item_delete(menu);
|
||||||
//append_menu_item_instance_to_object(menu);
|
|
||||||
menu->AppendSeparator();
|
menu->AppendSeparator();
|
||||||
|
|
||||||
// BBS
|
|
||||||
append_menu_item_reload_from_disk(menu);
|
append_menu_item_reload_from_disk(menu);
|
||||||
append_menu_item_export_stl(menu);
|
append_menu_item_export_stl(menu);
|
||||||
// "Scale to print volume" makes a sense just for whole object
|
// "Scale to print volume" makes a sense just for whole object
|
||||||
@@ -1302,6 +1300,11 @@ void MenuFactory::create_object_menu()
|
|||||||
|
|
||||||
void MenuFactory::create_extra_object_menu()
|
void MenuFactory::create_extra_object_menu()
|
||||||
{
|
{
|
||||||
|
// Object instances / conversions
|
||||||
|
append_menu_items_instance_manipulation(&m_object_menu);
|
||||||
|
m_object_menu.AppendSeparator();
|
||||||
|
append_menu_item_instance_to_object(&m_object_menu);
|
||||||
|
m_object_menu.AppendSeparator();
|
||||||
//append_menu_item_fill_bed(&m_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);
|
||||||
@@ -1796,6 +1799,26 @@ wxMenu* MenuFactory::assemble_multi_selection_menu()
|
|||||||
return menu;
|
return menu;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//PS
|
||||||
|
void MenuFactory::append_menu_items_instance_manipulation(wxMenu* menu)
|
||||||
|
{
|
||||||
|
MenuType type = menu == &m_object_menu ? mtObjectFFF : mtObjectSLA;
|
||||||
|
|
||||||
|
items_increase[type] = append_menu_item(menu, wxID_ANY, _L("Add instance") + "\t+", _L("Add one more instance of the selected object"),
|
||||||
|
[](wxCommandEvent&) { plater()->increase_instances(); }, "", nullptr,
|
||||||
|
[]() { return plater()->can_increase_instances(); }, m_parent);
|
||||||
|
items_decrease[type] = append_menu_item(menu, wxID_ANY, _L("Remove instance") + "\t-", _L("Remove one instance of the selected object"),
|
||||||
|
[](wxCommandEvent&) { plater()->decrease_instances(); }, "", nullptr,
|
||||||
|
[]() { return plater()->can_decrease_instances(); }, m_parent);
|
||||||
|
items_set_number_of_copies[type] = append_menu_item(menu, wxID_ANY, _L("Set number of instances") + dots, _L("Change the number of instances of the selected object"),
|
||||||
|
[](wxCommandEvent&) { plater()->set_number_of_copies(); }, "", nullptr,
|
||||||
|
[]() { return plater()->can_increase_instances(); }, m_parent);
|
||||||
|
append_menu_item(menu, wxID_ANY, _L("Fill bed with instances") + dots, _L("Fill the remaining area of bed with instances of the selected object"),
|
||||||
|
[](wxCommandEvent&) { plater()->fill_bed_with_instances(); }, "", nullptr,
|
||||||
|
[]() { return plater()->can_increase_instances(); }, m_parent);
|
||||||
|
}
|
||||||
|
|
||||||
wxMenu *MenuFactory::filament_action_menu(int active_filament_menu_id) {
|
wxMenu *MenuFactory::filament_action_menu(int active_filament_menu_id) {
|
||||||
create_filament_action_menu(false, active_filament_menu_id);
|
create_filament_action_menu(false, active_filament_menu_id);
|
||||||
return &m_filament_action_menu;
|
return &m_filament_action_menu;
|
||||||
|
|||||||
@@ -157,7 +157,7 @@ private:
|
|||||||
void append_menu_item_edit_text(wxMenu *menu);
|
void append_menu_item_edit_text(wxMenu *menu);
|
||||||
void append_menu_item_edit_svg(wxMenu *menu);
|
void append_menu_item_edit_svg(wxMenu *menu);
|
||||||
|
|
||||||
//void append_menu_items_instance_manipulation(wxMenu *menu);
|
void append_menu_items_instance_manipulation(wxMenu *menu);
|
||||||
//void update_menu_items_instance_manipulation(MenuType type);
|
//void update_menu_items_instance_manipulation(MenuType type);
|
||||||
//BBS add bbl menu item
|
//BBS add bbl menu item
|
||||||
void append_menu_item_clone(wxMenu* menu);
|
void append_menu_item_clone(wxMenu* menu);
|
||||||
|
|||||||
@@ -1735,12 +1735,12 @@ void ObjectList::key_event(wxKeyEvent& event)
|
|||||||
cut();
|
cut();
|
||||||
else if (wxGetKeyState(wxKeyCode('K')) && wxGetKeyState(WXK_CONTROL))
|
else if (wxGetKeyState(wxKeyCode('K')) && wxGetKeyState(WXK_CONTROL))
|
||||||
clone();
|
clone();
|
||||||
//else if (event.GetUnicodeKey() == '+')
|
else if (event.GetUnicodeKey() == '+')
|
||||||
// increase_instances();
|
increase_instances();
|
||||||
//else if (event.GetUnicodeKey() == '-')
|
else if (event.GetUnicodeKey() == '-')
|
||||||
// decrease_instances();
|
decrease_instances();
|
||||||
//else if (event.GetUnicodeKey() == 'p')
|
else if (event.GetUnicodeKey() == 'p')
|
||||||
// toggle_printable_state();
|
toggle_printable_state();
|
||||||
else if (filaments_count() > 1) {
|
else if (filaments_count() > 1) {
|
||||||
std::vector<wxChar> numbers = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
|
std::vector<wxChar> numbers = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
|
||||||
wxChar key_char = event.GetUnicodeKey();
|
wxChar key_char = event.GetUnicodeKey();
|
||||||
|
|||||||
@@ -169,16 +169,35 @@ void FillBedJob::prepare()
|
|||||||
ModelInstance *mi = model_object->instances[sel_id];
|
ModelInstance *mi = model_object->instances[sel_id];
|
||||||
ArrangePolygon template_ap = get_instance_arrange_poly(mi, global_config);
|
ArrangePolygon template_ap = get_instance_arrange_poly(mi, global_config);
|
||||||
|
|
||||||
for (int i = 0; i < needed_items; ++i) {
|
int obj_idx;
|
||||||
|
double offset_base, offset;
|
||||||
|
bool was_one_instance;
|
||||||
|
if (m_instances) {
|
||||||
|
obj_idx = m_plater->get_selected_object_idx();
|
||||||
|
offset_base = m_plater->canvas3D()->get_size_proportional_to_max_bed_size(0.05);
|
||||||
|
offset = offset_base;
|
||||||
|
was_one_instance = model_object->instances.size()==1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < needed_items; ++i, offset += offset_base) {
|
||||||
ArrangePolygon ap = template_ap;
|
ArrangePolygon ap = template_ap;
|
||||||
ap.poly = m_selected.front().poly;
|
ap.poly = m_selected.front().poly;
|
||||||
ap.bed_idx = PartPlateList::MAX_PLATES_COUNT;
|
ap.bed_idx = PartPlateList::MAX_PLATES_COUNT;
|
||||||
ap.itemid = -1;
|
ap.itemid = -1;
|
||||||
ap.setter = [this, mi](const ArrangePolygon &p) {
|
ap.setter = [this, mi, offset](const ArrangePolygon &p) {
|
||||||
ModelObject *mo = m_plater->model().objects[m_object_idx];
|
ModelObject *mo = m_plater->model().objects[m_object_idx];
|
||||||
ModelObject* newObj = m_plater->model().add_object(*mo);
|
ModelObject *obj;
|
||||||
newObj->name = mo->name +" "+ std::to_string(p.itemid);
|
if (m_instances) {
|
||||||
for (ModelInstance *newInst : newObj->instances) { newInst->apply_arrange_result(p.translation.cast<double>(), p.rotation); }
|
ModelInstance* model_instance = mo->instances.back();
|
||||||
|
Vec3d offset_vec = model_instance->get_offset() + Vec3d(offset, offset, 0.0);
|
||||||
|
mo->add_instance(offset_vec, model_instance->get_scaling_factor(), model_instance->get_rotation(), model_instance->get_mirror());
|
||||||
|
obj = mo;
|
||||||
|
} else {
|
||||||
|
ModelObject* newObj = m_plater->model().add_object(*mo);
|
||||||
|
newObj->name = mo->name +" "+ std::to_string(p.itemid);
|
||||||
|
obj = newObj;
|
||||||
|
}
|
||||||
|
for (ModelInstance *newInst : obj->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_plater->sidebar().obj_list()->paste_objects_into_list({m_plater->model().objects.size()-1});
|
||||||
};
|
};
|
||||||
m_selected.emplace_back(ap);
|
m_selected.emplace_back(ap);
|
||||||
@@ -256,7 +275,7 @@ void FillBedJob::process(Ctl &ctl)
|
|||||||
_u8L("Bed filling done."));
|
_u8L("Bed filling done."));
|
||||||
}
|
}
|
||||||
|
|
||||||
FillBedJob::FillBedJob() : m_plater{wxGetApp().plater()} {}
|
FillBedJob::FillBedJob(bool instances) : m_plater{wxGetApp().plater()}, m_instances{instances} {}
|
||||||
|
|
||||||
void FillBedJob::finalize(bool canceled, std::exception_ptr &eptr)
|
void FillBedJob::finalize(bool canceled, std::exception_ptr &eptr)
|
||||||
{
|
{
|
||||||
@@ -323,6 +342,10 @@ void FillBedJob::finalize(bool canceled, std::exception_ptr &eptr)
|
|||||||
//model_object->ensure_on_bed();
|
//model_object->ensure_on_bed();
|
||||||
//BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << ": model_object->ensure_on_bed()";
|
//BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << ": model_object->ensure_on_bed()";
|
||||||
|
|
||||||
|
if (m_instances && wxGetApp().app_config->get("auto_arrange") == "true") {
|
||||||
|
m_plater->set_prepare_state(Job::PREPARE_STATE_MENU);
|
||||||
|
m_plater->arrange();
|
||||||
|
}
|
||||||
m_plater->update();
|
m_plater->update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,12 +26,14 @@ class FillBedJob : public Job
|
|||||||
int m_status_range = 0;
|
int m_status_range = 0;
|
||||||
Plater *m_plater;
|
Plater *m_plater;
|
||||||
|
|
||||||
|
bool m_instances;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
void prepare();
|
void prepare();
|
||||||
void process(Ctl &ctl) override;
|
void process(Ctl &ctl) override;
|
||||||
|
|
||||||
FillBedJob();
|
FillBedJob(bool instances = false);
|
||||||
|
|
||||||
int status_range() const
|
int status_range() const
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -13604,8 +13604,6 @@ void Plater::remove_selected()
|
|||||||
|
|
||||||
void Plater::increase_instances(size_t num)
|
void Plater::increase_instances(size_t num)
|
||||||
{
|
{
|
||||||
// BBS
|
|
||||||
#if 0
|
|
||||||
if (! can_increase_instances()) { return; }
|
if (! can_increase_instances()) { return; }
|
||||||
|
|
||||||
Plater::TakeSnapshot snapshot(this, "Increase Instances");
|
Plater::TakeSnapshot snapshot(this, "Increase Instances");
|
||||||
@@ -13638,13 +13636,14 @@ void Plater::increase_instances(size_t num)
|
|||||||
|
|
||||||
p->selection_changed();
|
p->selection_changed();
|
||||||
this->p->schedule_background_process();
|
this->p->schedule_background_process();
|
||||||
#endif
|
if (wxGetApp().app_config->get("auto_arrange") == "true") {
|
||||||
|
this->set_prepare_state(Job::PREPARE_STATE_MENU);
|
||||||
|
this->arrange();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Plater::decrease_instances(size_t num)
|
void Plater::decrease_instances(size_t num)
|
||||||
{
|
{
|
||||||
// BBS
|
|
||||||
#if 0
|
|
||||||
if (! can_decrease_instances()) { return; }
|
if (! can_decrease_instances()) { return; }
|
||||||
|
|
||||||
Plater::TakeSnapshot snapshot(this, "Decrease Instances");
|
Plater::TakeSnapshot snapshot(this, "Decrease Instances");
|
||||||
@@ -13668,7 +13667,10 @@ void Plater::decrease_instances(size_t num)
|
|||||||
|
|
||||||
p->selection_changed();
|
p->selection_changed();
|
||||||
this->p->schedule_background_process();
|
this->p->schedule_background_process();
|
||||||
#endif
|
if (wxGetApp().app_config->get("auto_arrange") == "true") {
|
||||||
|
this->set_prepare_state(Job::PREPARE_STATE_MENU);
|
||||||
|
this->arrange();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static long GetNumberFromUser( const wxString& msg,
|
static long GetNumberFromUser( const wxString& msg,
|
||||||
@@ -13713,7 +13715,7 @@ void Plater::set_number_of_copies(/*size_t num*/)
|
|||||||
decrease_instances(-diff);
|
decrease_instances(-diff);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Plater::fill_bed_with_instances()
|
void Plater::fill_bed_with_copies()
|
||||||
{
|
{
|
||||||
auto &w = get_ui_job_worker();
|
auto &w = get_ui_job_worker();
|
||||||
if (w.is_idle()) {
|
if (w.is_idle()) {
|
||||||
@@ -13722,6 +13724,15 @@ void Plater::fill_bed_with_instances()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Plater::fill_bed_with_instances()
|
||||||
|
{
|
||||||
|
auto &w = get_ui_job_worker();
|
||||||
|
if (w.is_idle()) {
|
||||||
|
p->take_snapshot(_u8L("Arrange"));
|
||||||
|
replace_job(w, std::make_unique<FillBedJob>(true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool Plater::is_selection_empty() const
|
bool Plater::is_selection_empty() const
|
||||||
{
|
{
|
||||||
return p->get_selection().is_empty() || p->get_selection().is_wipe_tower();
|
return p->get_selection().is_empty() || p->get_selection().is_wipe_tower();
|
||||||
|
|||||||
@@ -460,6 +460,7 @@ public:
|
|||||||
void increase_instances(size_t num = 1);
|
void increase_instances(size_t num = 1);
|
||||||
void decrease_instances(size_t num = 1);
|
void decrease_instances(size_t num = 1);
|
||||||
void set_number_of_copies(/*size_t num*/);
|
void set_number_of_copies(/*size_t num*/);
|
||||||
|
void fill_bed_with_copies();
|
||||||
void fill_bed_with_instances();
|
void fill_bed_with_instances();
|
||||||
bool is_selection_empty() const;
|
bool is_selection_empty() const;
|
||||||
void scale_selection_to_fit_print_volume();
|
void scale_selection_to_fit_print_volume();
|
||||||
|
|||||||
Reference in New Issue
Block a user