mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-14 13:55:58 +08:00
Cut: Fixes and improvements for object's context menu
* Disable or delete some menu items, which are inappropriate for cut objects * For cut objects added menu item "Invalidate cut info" to disconnect related cut parts of initial object * If just one part is kept after cut performance, than don't apply a cut info for this object. + CutGizmo: Fixed selection of the mode An object has connectors -> Connectors mode An object doesn't has connectors -> CutPlane mode
This commit is contained in:
parent
74a32e3261
commit
85af9b93f1
@ -1261,7 +1261,9 @@ void ModelObject::invalidate_cut()
|
||||
{
|
||||
for (ModelObject* obj : m_model->objects)
|
||||
if (obj != this && obj->cut_id.is_equal(this->cut_id))
|
||||
obj->cut_id.ivalidate();
|
||||
obj->cut_id.invalidate();
|
||||
// invalidate own cut_id
|
||||
this->cut_id.invalidate();
|
||||
}
|
||||
|
||||
void ModelObject::synchronize_model_after_cut()
|
||||
@ -1276,6 +1278,10 @@ void ModelObject::synchronize_model_after_cut()
|
||||
|
||||
void ModelObject::apply_cut_attributes(ModelObjectCutAttributes attributes)
|
||||
{
|
||||
// we don't save cut information, if result will not contains all parts of initial object
|
||||
if (!attributes.has(ModelObjectCutAttribute::KeepUpper) || !attributes.has(ModelObjectCutAttribute::KeepLower))
|
||||
return;
|
||||
|
||||
if (cut_id.id().invalid())
|
||||
cut_id.init();
|
||||
{
|
||||
|
@ -161,7 +161,7 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
void ivalidate() {
|
||||
void invalidate() {
|
||||
set_invalid_id();
|
||||
m_check_sum = 1;
|
||||
m_connectors_cnt = 0;
|
||||
|
@ -685,6 +685,24 @@ wxMenuItem* MenuFactory::append_menu_item_printable(wxMenu* menu)
|
||||
return menu_item_printable;
|
||||
}
|
||||
|
||||
void MenuFactory::append_menu_item_invalidate_cut_info(wxMenu* menu)
|
||||
{
|
||||
const wxString menu_name = _L("Invalidate cut info");
|
||||
|
||||
bool is_cut = obj_list()->has_selected_cut_object();
|
||||
|
||||
auto menu_item_id = menu->FindItem(menu_name);
|
||||
if (menu_item_id != wxNOT_FOUND) {
|
||||
// Delete old menu item if selected object isn't cut
|
||||
if (!is_cut)
|
||||
menu->Destroy(menu_item_id);
|
||||
}
|
||||
else if (is_cut)
|
||||
append_menu_item(menu, wxID_ANY, menu_name, "",
|
||||
[](wxCommandEvent&) { obj_list()->invalidate_cut_info_for_selection(); }, "", menu,
|
||||
[]() { return true; }, m_parent);
|
||||
}
|
||||
|
||||
void MenuFactory::append_menu_items_osx(wxMenu* menu)
|
||||
{
|
||||
append_menu_item(menu, wxID_ANY, _L("Rename"), "",
|
||||
@ -821,6 +839,8 @@ void MenuFactory::append_menu_items_convert_unit(wxMenu* menu, int insert_pos/*
|
||||
ModelObjectPtrs objects;
|
||||
for (int obj_idx : obj_idxs) {
|
||||
ModelObject* object = obj_list()->object(obj_idx);
|
||||
if (object->is_cut())
|
||||
return false;
|
||||
if (vol_idxs.empty()) {
|
||||
for (ModelVolume* volume : object->volumes)
|
||||
if (volume_respects_conversion(volume, conver_type))
|
||||
@ -1021,6 +1041,7 @@ wxMenu* MenuFactory::object_menu()
|
||||
append_menu_item_settings(&m_object_menu);
|
||||
append_menu_item_change_extruder(&m_object_menu);
|
||||
update_menu_items_instance_manipulation(mtObjectFFF);
|
||||
append_menu_item_invalidate_cut_info(&m_object_menu);
|
||||
|
||||
return &m_object_menu;
|
||||
}
|
||||
@ -1030,6 +1051,7 @@ wxMenu* MenuFactory::sla_object_menu()
|
||||
append_menu_items_convert_unit(&m_sla_object_menu, 11);
|
||||
append_menu_item_settings(&m_sla_object_menu);
|
||||
update_menu_items_instance_manipulation(mtObjectSLA);
|
||||
append_menu_item_invalidate_cut_info(&m_sla_object_menu);
|
||||
|
||||
return &m_sla_object_menu;
|
||||
}
|
||||
|
@ -89,6 +89,7 @@ private:
|
||||
wxMenuItem* append_menu_item_change_type(wxMenu* menu);
|
||||
wxMenuItem* append_menu_item_instance_to_object(wxMenu* menu);
|
||||
wxMenuItem* append_menu_item_printable(wxMenu* menu);
|
||||
void append_menu_item_invalidate_cut_info(wxMenu *menu);
|
||||
void append_menu_items_osx(wxMenu* menu);
|
||||
wxMenuItem* append_menu_item_fix_through_netfabb(wxMenu* menu);
|
||||
wxMenuItem* append_menu_item_simplify(wxMenu* menu);
|
||||
|
@ -2443,9 +2443,41 @@ bool ObjectList::can_split_instances()
|
||||
return selection.is_multiple_full_instance() || selection.is_single_full_instance();
|
||||
}
|
||||
|
||||
bool ObjectList::has_selected_cut_object() const
|
||||
{
|
||||
wxDataViewItemArray sels;
|
||||
GetSelections(sels);
|
||||
if (sels.IsEmpty())
|
||||
return false;
|
||||
|
||||
for (wxDataViewItem item : sels) {
|
||||
const int obj_idx = m_objects_model->GetObjectIdByItem(item);
|
||||
if (obj_idx >= 0 && object(obj_idx)->is_cut())
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ObjectList::invalidate_cut_info_for_selection()
|
||||
{
|
||||
wxDataViewItemArray sels;
|
||||
GetSelections(sels);
|
||||
if (sels.IsEmpty())
|
||||
return;
|
||||
|
||||
for (wxDataViewItem item : sels) {
|
||||
const int obj_idx = m_objects_model->GetObjectIdByItem(item);
|
||||
if (obj_idx >= 0 && object(obj_idx)->is_cut())
|
||||
object(obj_idx)->invalidate_cut();
|
||||
}
|
||||
|
||||
update_lock_icons_for_model();
|
||||
}
|
||||
|
||||
bool ObjectList::can_merge_to_multipart_object() const
|
||||
{
|
||||
if (printer_technology() == ptSLA)
|
||||
if (printer_technology() == ptSLA || has_selected_cut_object())
|
||||
return false;
|
||||
|
||||
wxDataViewItemArray sels;
|
||||
|
@ -277,6 +277,8 @@ public:
|
||||
bool is_splittable(bool to_objects);
|
||||
bool selected_instances_of_same_object();
|
||||
bool can_split_instances();
|
||||
bool has_selected_cut_object() const;
|
||||
void invalidate_cut_info_for_selection();
|
||||
bool can_merge_to_multipart_object() const;
|
||||
bool can_merge_to_single_object() const;
|
||||
|
||||
|
@ -1226,6 +1226,7 @@ bool GLGizmoCut3D::update_bb()
|
||||
if (CommonGizmosDataObjects::SelectionInfo* selection = m_c->selection_info()) {
|
||||
clear_selection();
|
||||
m_selected.resize(selection->model_object()->cut_connectors.size(), false);
|
||||
m_connectors_editing = !m_selected.empty();
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -1333,12 +1334,12 @@ void GLGizmoCut3D::adjust_window_position(float x, float y, float bottom_limit)
|
||||
|
||||
ImGui::SetWindowPos(ImVec2(x, y), ImGuiCond_Always);
|
||||
|
||||
if (last_h != win_h || last_y != y) {
|
||||
if (!is_approx(last_h, win_h) || !is_approx(last_y, y)) {
|
||||
// ask canvas for another frame to render the window in the correct position
|
||||
m_imgui->set_requires_extra_frame();
|
||||
if (last_h != win_h)
|
||||
if (!is_approx(last_h, win_h))
|
||||
last_h = win_h;
|
||||
if (last_y != y)
|
||||
if (!is_approx(last_y, y))
|
||||
last_y = y;
|
||||
}
|
||||
}
|
||||
@ -1773,9 +1774,9 @@ bool GLGizmoCut3D::can_perform_cut() const
|
||||
return tbb.contains(m_plane_center);
|
||||
}
|
||||
|
||||
void GLGizmoCut3D::apply_connectors_in_model(ModelObject* mo, const bool has_connectors, bool &create_dowels_as_separate_object)
|
||||
void GLGizmoCut3D::apply_connectors_in_model(ModelObject* mo, bool &create_dowels_as_separate_object)
|
||||
{
|
||||
if (has_connectors && m_connector_mode == CutConnectorMode::Manual) {
|
||||
if (m_connector_mode == CutConnectorMode::Manual) {
|
||||
clear_selection();
|
||||
|
||||
for (CutConnector&connector : mo->cut_connectors) {
|
||||
@ -1824,7 +1825,7 @@ void GLGizmoCut3D::perform_cut(const Selection& selection)
|
||||
{
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Cut by Plane"));
|
||||
// update connectors pos as offset of its center before cut performing
|
||||
apply_connectors_in_model(mo, has_connectors, create_dowels_as_separate_object);
|
||||
apply_connectors_in_model(mo, create_dowels_as_separate_object);
|
||||
}
|
||||
|
||||
plater->cut(object_idx, instance_idx, assemble_transform(cut_center_offset) * m_rotation_m,
|
||||
|
@ -225,7 +225,7 @@ private:
|
||||
void render_connectors();
|
||||
|
||||
bool can_perform_cut() const;
|
||||
void apply_connectors_in_model(ModelObject* mo, const bool has_connectors, bool &create_dowels_as_separate_object);
|
||||
void apply_connectors_in_model(ModelObject* mo, bool &create_dowels_as_separate_object);
|
||||
bool cut_line_processing() const;
|
||||
void discard_cut_line_processing();
|
||||
|
||||
|
@ -1807,6 +1807,7 @@ void ObjectDataViewModel::UpdateLockIcon(const wxDataViewItem& item, bool has_lo
|
||||
for (const wxDataViewItem& child : children)
|
||||
UpdateLockIcon(child, has_lock);
|
||||
}
|
||||
ItemChanged(item);
|
||||
}
|
||||
|
||||
} // namespace GUI
|
||||
|
@ -4786,7 +4786,8 @@ bool Plater::priv::can_split(bool to_objects) const
|
||||
bool Plater::priv::can_scale_to_print_volume() const
|
||||
{
|
||||
const BuildVolume::Type type = this->bed.build_volume().type();
|
||||
return !view3D->get_canvas3d()->get_selection().is_empty() && (type == BuildVolume::Type::Rectangle || type == BuildVolume::Type::Circle);
|
||||
return !sidebar->obj_list()->has_selected_cut_object() &&
|
||||
!view3D->get_canvas3d()->get_selection().is_empty() && (type == BuildVolume::Type::Rectangle || type == BuildVolume::Type::Circle);
|
||||
}
|
||||
|
||||
bool Plater::priv::layers_height_allowed() const
|
||||
@ -4801,16 +4802,19 @@ bool Plater::priv::layers_height_allowed() const
|
||||
|
||||
bool Plater::priv::can_mirror() const
|
||||
{
|
||||
return get_selection().is_from_single_instance();
|
||||
return !sidebar->obj_list()->has_selected_cut_object() && get_selection().is_from_single_instance();
|
||||
}
|
||||
|
||||
bool Plater::priv::can_replace_with_stl() const
|
||||
{
|
||||
return get_selection().get_volume_idxs().size() == 1;
|
||||
return !sidebar->obj_list()->has_selected_cut_object() && get_selection().get_volume_idxs().size() == 1;
|
||||
}
|
||||
|
||||
bool Plater::priv::can_reload_from_disk() const
|
||||
{
|
||||
if (sidebar->obj_list()->has_selected_cut_object())
|
||||
return false;
|
||||
|
||||
#if ENABLE_RELOAD_FROM_DISK_REWORK
|
||||
// collect selected reloadable ModelVolumes
|
||||
std::vector<std::pair<int, int>> selected_volumes = reloadable_volumes(model, get_selection());
|
||||
@ -4939,9 +4943,7 @@ bool Plater::priv::can_increase_instances() const
|
||||
|| q->canvas3D()->get_gizmos_manager().is_in_editing_mode())
|
||||
return false;
|
||||
|
||||
int obj_idx = get_selected_object_idx();
|
||||
return (0 <= obj_idx) && (obj_idx < (int)model.objects.size())
|
||||
&& !model.objects[obj_idx]->is_cut();
|
||||
return !sidebar->obj_list()->has_selected_cut_object();
|
||||
}
|
||||
|
||||
bool Plater::priv::can_decrease_instances() const
|
||||
@ -4950,9 +4952,7 @@ bool Plater::priv::can_decrease_instances() const
|
||||
|| q->canvas3D()->get_gizmos_manager().is_in_editing_mode())
|
||||
return false;
|
||||
|
||||
int obj_idx = get_selected_object_idx();
|
||||
return (0 <= obj_idx) && (obj_idx < (int)model.objects.size()) && (model.objects[obj_idx]->instances.size() > 1)
|
||||
&& !model.objects[obj_idx]->is_cut();
|
||||
return !sidebar->obj_list()->has_selected_cut_object();
|
||||
}
|
||||
|
||||
bool Plater::priv::can_split_to_objects() const
|
||||
|
Loading…
x
Reference in New Issue
Block a user