diff --git a/resources/icons/collapse_btn.svg b/resources/icons/collapse_btn.svg index 4ee221a44a..32d7f99595 100644 --- a/resources/icons/collapse_btn.svg +++ b/resources/icons/collapse_btn.svg @@ -3,11 +3,10 @@ - - - - - - + + + + + - \ No newline at end of file + diff --git a/resources/icons/expand_btn.svg b/resources/icons/expand_btn.svg index 32d7f99595..4ee221a44a 100644 --- a/resources/icons/expand_btn.svg +++ b/resources/icons/expand_btn.svg @@ -3,10 +3,11 @@ - - - - - + + + + + + - + \ No newline at end of file diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index f4e27982b2..cf0d29eb8f 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -1154,7 +1154,7 @@ indexed_triangle_set its_make_frustum_dowel(double radius, double h, int sectorC else for (int j = 0; j < sectorCount; ++j) { // from 0 to 2pi - double sectorAngle = sectorStep * j; + double sectorAngle = sectorStep * j + 0.25 * M_PI; vertices.emplace_back(Vec3d(xy * std::cos(sectorAngle), xy * std::sin(sectorAngle), z).cast()); } } diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index aeb0b7d4a6..de912a1344 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1755,7 +1755,20 @@ std::vector GLCanvas3D::load_object(const Model& model, int obj_idx) void GLCanvas3D::mirror_selection(Axis axis) { +#if ENABLE_WORLD_COORDINATE + TransformationType transformation_type; + if (wxGetApp().obj_manipul()->is_local_coordinates()) + transformation_type.set_local(); + else if (wxGetApp().obj_manipul()->is_instance_coordinates()) + transformation_type.set_instance(); + + transformation_type.set_relative(); + + m_selection.setup_cache(); + m_selection.mirror(axis, transformation_type); +#else m_selection.mirror(axis); +#endif // ENABLE_WORLD_COORDINATE do_mirror(L("Mirror Object")); wxGetApp().obj_manipul()->set_dirty(); } @@ -3646,7 +3659,13 @@ void GLCanvas3D::do_rotate(const std::string& snapshot_type) for (const GLVolume* v : m_volumes.volumes) { if (v->is_wipe_tower) { const Vec3d offset = v->get_volume_offset(); +#if ENABLE_WORLD_COORDINATE + Vec3d rot_unit_x = v->get_volume_transformation().get_matrix().linear() * Vec3d::UnitX(); + double z_rot = std::atan2(rot_unit_x.y(), rot_unit_x.x()); + post_event(Vec3dEvent(EVT_GLCANVAS_WIPETOWER_ROTATED, Vec3d(offset.x(), offset.y(), z_rot))); +#else post_event(Vec3dEvent(EVT_GLCANVAS_WIPETOWER_ROTATED, Vec3d(offset.x(), offset.y(), v->get_volume_rotation().z()))); +#endif // ENABLE_WORLD_COORDINATE } const int object_idx = v->object_idx(); if (object_idx < 0 || (int)m_model->objects.size() <= object_idx) @@ -5096,9 +5115,17 @@ void GLCanvas3D::_refresh_if_shown_on_screen() const Size& cnv_size = get_canvas_size(); _resize((unsigned int)cnv_size.get_width(), (unsigned int)cnv_size.get_height()); + // When the application starts the following call to render() triggers the opengl initialization. + // We need to ask for an extra call to reload_scene() to force the generation of the model for wipe tower + // for printers using it, which is skipped by all the previous calls to reload_scene() because m_initialized == false + const bool requires_reload_scene = !m_initialized; + // Because of performance problems on macOS, where PaintEvents are not delivered // frequently enough, we call render() here directly when we can. render(); + assert(m_initialized); + if (requires_reload_scene) + reload_scene(true); } } diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 161784d959..7a42e1eec2 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -2216,6 +2216,17 @@ bool GUI_App::load_language(wxString language, bool initial) // Override language at the active wxTranslations class (which is stored in the active m_wxLocale) // to load possibly different dictionary, for example, load Czech dictionary for Slovak language. wxTranslations::Get()->SetLanguage(language_dict); + { + // UKR Localization specific workaround till the wxWidgets doesn't fixed: + // From wxWidgets 3.1.6 calls setlocation(0, wxInfoLanguage->LocaleTag), see (https://github.com/prusa3d/wxWidgets/commit/deef116a09748796711d1e3509965ee208dcdf0b#diff-7de25e9a71c4dce61bbf76492c589623d5b93fd1bb105ceaf0662075d15f4472), + // where LocaleTag is a Tag of locale in BCP 47 - like notation. + // For Ukrainian Language LocaleTag == "uk". + // But setlocale(0, "uk") returns "English_United Kingdom.1252" instead of "uk", + // and, as a result, locales are set to English_United Kingdom + + if (language_info->CanonicalName == "uk") + setlocale(0, language_info->GetCanonicalWithRegion().data()); + } m_wxLocale->AddCatalog(SLIC3R_APP_KEY); m_imgui->set_language(into_u8(language_info->CanonicalName)); //FIXME This is a temporary workaround, the correct solution is to switch to "C" locale during file import / export only. diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 8c15464100..3d55e21741 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -2825,8 +2825,12 @@ void ObjectList::part_selection_changed() panel.Freeze(); #if ENABLE_WORLD_COORDINATE - const ManipulationEditor* const editor = wxGetApp().obj_manipul()->get_focused_editor(); - const std::string opt_key = (editor != nullptr) ? editor->get_full_opt_name() : ""; + std::string opt_key; + if (m_selected_object_id >= 0) { + const ManipulationEditor* const editor = wxGetApp().obj_manipul()->get_focused_editor(); + if (editor != nullptr) + opt_key = editor->get_full_opt_name(); + } wxGetApp().plater()->canvas3D()->handle_sidebar_focus_event(opt_key, !opt_key.empty()); #else wxGetApp().plater()->canvas3D()->handle_sidebar_focus_event("", false); diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index bbcad29195..edf4d5b07e 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -125,8 +125,10 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : // Load bitmaps to be used for the mirroring buttons: m_mirror_bitmap_on = ScalableBitmap(parent, "mirroring_on"); +#if !ENABLE_WORLD_COORDINATE m_mirror_bitmap_off = ScalableBitmap(parent, "mirroring_off"); m_mirror_bitmap_hidden = ScalableBitmap(parent, "mirroring_transparent"); +#endif // !ENABLE_WORLD_COORDINATE const int border = wxOSX ? 0 : 4; const int em = wxGetApp().em_unit(); @@ -265,28 +267,44 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : // We will add a button to toggle mirroring to each axis: auto btn = new ScalableButton(parent, wxID_ANY, "mirroring_off", wxEmptyString, wxDefaultSize, wxDefaultPosition, wxBU_EXACTFIT | wxNO_BORDER | wxTRANSPARENT_WINDOW); +#if ENABLE_WORLD_COORDINATE + btn->SetToolTip(_L("Mirror along") + wxString::Format(_L(" %c "), (int)label) + _L("axis")); + + m_mirror_buttons[axis_idx] = btn; +#else btn->SetToolTip(wxString::Format(_L("Toggle %c axis mirroring"), (int)label)); btn->SetBitmapDisabled_(m_mirror_bitmap_hidden); m_mirror_buttons[axis_idx].first = btn; m_mirror_buttons[axis_idx].second = mbShown; +#endif // ENABLE_WORLD_COORDINATE sizer->AddStretchSpacer(2); sizer->Add(btn, 0, wxALIGN_CENTER_VERTICAL); btn->Bind(wxEVT_BUTTON, [this, axis_idx](wxCommandEvent&) { +#if !ENABLE_WORLD_COORDINATE Axis axis = (Axis)(axis_idx + X); if (m_mirror_buttons[axis_idx].second == mbHidden) - return; + return; +#endif // !ENABLE_WORLD_COORDINATE GLCanvas3D* canvas = wxGetApp().plater()->canvas3D(); Selection& selection = canvas->get_selection(); #if ENABLE_WORLD_COORDINATE - if (selection.is_single_volume_or_modifier()) { + TransformationType transformation_type; + if (is_local_coordinates()) + transformation_type.set_local(); + else if (is_instance_coordinates()) + transformation_type.set_instance(); + + transformation_type.set_relative(); + + selection.setup_cache(); + selection.mirror((Axis)axis_idx, transformation_type); #else if (selection.is_single_volume() || selection.is_single_modifier()) { -#endif // ENABLE_WORLD_COORDINATE GLVolume* volume = const_cast(selection.get_first_volume()); volume->set_volume_mirror(axis, -volume->get_volume_mirror(axis)); } @@ -302,6 +320,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : // Update mirroring at the GLVolumes. selection.synchronize_unselected_instances(Selection::SyncRotationType::GENERAL); selection.synchronize_unselected_volumes(); +#endif // ENABLE_WORLD_COORDINATE // Copy mirroring values from GLVolumes into Model (ModelInstance / ModelVolume), trigger background processing. canvas->do_mirror(L("Set Mirror")); UpdateAndShow(true); @@ -310,7 +329,12 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : editors_grid_sizer->Add(sizer, 0, wxALIGN_CENTER_HORIZONTAL); } +#if ENABLE_WORLD_COORDINATE + m_mirror_warning_bitmap = new wxStaticBitmap(parent, wxID_ANY, wxNullBitmap); + editors_grid_sizer->Add(m_mirror_warning_bitmap, 0, wxALIGN_CENTER_VERTICAL); +#else editors_grid_sizer->AddStretchSpacer(1); +#endif // ENABLE_WORLD_COORDINATE editors_grid_sizer->AddStretchSpacer(1); // add EditBoxes @@ -541,15 +565,15 @@ void ObjectManipulation::Show(const bool show) bool show_world_local_combo = wxGetApp().get_mode() != comSimple && (selection.is_single_full_instance() || selection.is_single_volume_or_modifier()); if (selection.is_single_volume_or_modifier() && m_word_local_combo->GetCount() < 3) { #ifdef __linux__ - m_word_local_combo->Insert(coordinate_type_str(ECoordinatesType::Instance), 1); + m_word_local_combo->Insert(coordinate_type_str(ECoordinatesType::Local), 2); #else - m_word_local_combo->Insert(coordinate_type_str(ECoordinatesType::Instance), wxNullBitmap, 1); + m_word_local_combo->Insert(coordinate_type_str(ECoordinatesType::Local), wxNullBitmap, 2); #endif // __linux__ m_word_local_combo->Select((int)ECoordinatesType::World); this->set_coordinates_type(m_word_local_combo->GetString(m_word_local_combo->GetSelection())); } else if (selection.is_single_full_instance() && m_word_local_combo->GetCount() > 2) { - m_word_local_combo->Delete(1); + m_word_local_combo->Delete(2); m_word_local_combo->Select((int)ECoordinatesType::World); this->set_coordinates_type(m_word_local_combo->GetString(m_word_local_combo->GetSelection())); } @@ -660,7 +684,7 @@ void ObjectManipulation::update_ui_from_settings() void ObjectManipulation::update_settings_value(const Selection& selection) { - m_new_move_label_string = L("Position"); + m_new_move_label_string = L("Position"); m_new_rotate_label_string = L("Rotation"); m_new_scale_label_string = L("Scale factors"); @@ -688,13 +712,15 @@ void ObjectManipulation::update_settings_value(const Selection& selection) #if ENABLE_WORLD_COORDINATE if (is_world_coordinates()) { m_new_position = volume->get_instance_offset(); + m_new_scale_label_string = L("Scale"); + m_new_scale = Vec3d(100.0, 100.0, 100.0); #else if (m_world_coordinates) { + m_new_scale = m_new_size.cwiseQuotient(selection.get_unscaled_instance_bounding_box().size()) * 100.0; #endif // ENABLE_WORLD_COORDINATE m_new_rotate_label_string = L("Rotate"); m_new_rotation = Vec3d::Zero(); m_new_size = selection.get_scaled_instance_bounding_box().size(); - m_new_scale = m_new_size.cwiseQuotient(selection.get_unscaled_instance_bounding_box().size()) * 100.0; } else { #if ENABLE_WORLD_COORDINATE @@ -702,12 +728,13 @@ void ObjectManipulation::update_settings_value(const Selection& selection) m_new_rotate_label_string = L("Rotate"); m_new_position = Vec3d::Zero(); m_new_rotation = Vec3d::Zero(); + m_new_scale = Vec3d(100.0, 100.0, 100.0); #else m_new_rotation = volume->get_instance_rotation() * (180.0 / M_PI); #endif // ENABLE_WORLD_COORDINATE + m_new_scale = volume->get_instance_scaling_factor() * 100.0; m_new_size = volume->get_instance_scaling_factor().cwiseProduct(wxGetApp().model().objects[volume->object_idx()]->raw_mesh_bounding_box().size()); - m_new_scale = volume->get_instance_scaling_factor() * 100.0; - } + } m_new_enabled = true; } @@ -718,7 +745,7 @@ void ObjectManipulation::update_settings_value(const Selection& selection) m_new_scale = Vec3d(100.0, 100.0, 100.0); m_new_size = box.size(); m_new_rotate_label_string = L("Rotate"); - m_new_scale_label_string = L("Scale"); + m_new_scale_label_string = L("Scale"); m_new_enabled = true; } #if ENABLE_WORLD_COORDINATE @@ -736,9 +763,10 @@ void ObjectManipulation::update_settings_value(const Selection& selection) m_new_position = offset; m_new_rotate_label_string = L("Rotate"); + m_new_scale_label_string = L("Scale"); + m_new_scale = Vec3d(100.0, 100.0, 100.0); m_new_rotation = Vec3d::Zero(); m_new_size = volume->transformed_convex_hull_bounding_box(trafo.get_matrix()).size(); - m_new_scale = m_new_size.cwiseQuotient(volume->transformed_convex_hull_bounding_box(volume->get_instance_transformation().get_matrix() * volume->get_volume_transformation().get_matrix_no_scaling_factor()).size()) * 100.0; } else if (is_local_coordinates()) { m_new_move_label_string = L("Translate"); @@ -750,12 +778,13 @@ void ObjectManipulation::update_settings_value(const Selection& selection) } else { #endif // ENABLE_WORLD_COORDINATE - m_new_position = volume->get_volume_offset(); - m_new_rotate_label_string = L("Rotate"); - m_new_rotation = Vec3d::Zero(); + m_new_position = volume->get_volume_offset(); + m_new_rotate_label_string = L("Rotate"); + m_new_rotation = Vec3d::Zero(); #if ENABLE_WORLD_COORDINATE + m_new_scale_label_string = L("Scale"); m_new_size = volume->transformed_convex_hull_bounding_box(volume->get_volume_transformation().get_matrix()).size(); - m_new_scale = m_new_size.cwiseQuotient(volume->transformed_convex_hull_bounding_box(volume->get_volume_transformation().get_matrix_no_scaling_factor()).size()) * 100.0; + m_new_scale = Vec3d(100.0, 100.0, 100.0); } #else m_new_scale = volume->get_volume_scaling_factor() * 100.0; @@ -765,17 +794,17 @@ void ObjectManipulation::update_settings_value(const Selection& selection) } else if (obj_list->is_connectors_item_selected() || obj_list->multiple_selection() || obj_list->is_selected(itInstanceRoot)) { reset_settings_value(); - m_new_move_label_string = L("Translate"); - m_new_rotate_label_string = L("Rotate"); - m_new_scale_label_string = L("Scale"); + m_new_move_label_string = L("Translate"); + m_new_rotate_label_string = L("Rotate"); + m_new_scale_label_string = L("Scale"); m_new_size = selection.get_bounding_box().size(); m_new_enabled = true; } - else { + else { // No selection, reset the cache. // assert(selection.is_empty()); - reset_settings_value(); - } + reset_settings_value(); + } } void ObjectManipulation::update_if_dirty() @@ -882,6 +911,7 @@ void ObjectManipulation::update_reset_buttons_visibility() bool show_drop_to_bed = false; #if ENABLE_WORLD_COORDINATE bool show_skew = false; + bool show_mirror_warning = false; if (selection.is_single_full_instance() || selection.is_single_volume_or_modifier()) { const double min_z = selection.is_single_full_instance() ? selection.get_scaled_instance_bounding_box().min.z() : @@ -891,7 +921,6 @@ void ObjectManipulation::update_reset_buttons_visibility() const GLVolume* volume = selection.get_first_volume(); Transform3d rotation = Transform3d::Identity(); Transform3d scale = Transform3d::Identity(); - Geometry::Transformation skew; #else if (selection.is_single_full_instance() || selection.is_single_modifier() || selection.is_single_volume()) { const GLVolume* volume = selection.get_first_volume(); @@ -907,11 +936,9 @@ void ObjectManipulation::update_reset_buttons_visibility() scale = trafo.get_scaling_factor_matrix(); const Selection::IndicesList& idxs = selection.get_volume_idxs(); for (unsigned int id : idxs) { - const Geometry::Transformation world_trafo(selection.get_volume(id)->world_matrix()); - if (world_trafo.has_skew()) { - skew = world_trafo; - break; - } + const Geometry::Transformation world_trafo(selection.get_volume(id)->world_matrix()); + show_skew |= world_trafo.has_skew(); + show_mirror_warning |= world_trafo.get_matrix().matrix().determinant() < 0.0; } #else rotation = volume->get_instance_rotation(); @@ -925,8 +952,8 @@ void ObjectManipulation::update_reset_buttons_visibility() rotation = trafo.get_rotation_matrix(); scale = trafo.get_scaling_factor_matrix(); const Geometry::Transformation world_trafo(volume->world_matrix()); - if (world_trafo.has_skew()) - skew = world_trafo; + show_skew |= world_trafo.has_skew(); + show_mirror_warning |= world_trafo.get_matrix().matrix().determinant() < 0.0; #else rotation = volume->get_volume_rotation(); scale = volume->get_volume_scaling_factor(); @@ -936,7 +963,6 @@ void ObjectManipulation::update_reset_buttons_visibility() #if ENABLE_WORLD_COORDINATE show_rotation = !rotation.isApprox(Transform3d::Identity()); show_scale = !scale.isApprox(Transform3d::Identity()); - show_skew = skew.has_skew(); #else show_rotation = !rotation.isApprox(Vec3d::Zero()); show_scale = !scale.isApprox(Vec3d::Ones()); @@ -945,7 +971,7 @@ void ObjectManipulation::update_reset_buttons_visibility() } #if ENABLE_WORLD_COORDINATE - wxGetApp().CallAfter([this, show_rotation, show_scale, show_drop_to_bed, show_skew] { + wxGetApp().CallAfter([this, show_rotation, show_scale, show_drop_to_bed, show_skew, show_mirror_warning] { #else wxGetApp().CallAfter([this, show_rotation, show_scale, show_drop_to_bed] { #endif // ENABLE_WORLD_COORDINATE @@ -959,6 +985,9 @@ void ObjectManipulation::update_reset_buttons_visibility() #if ENABLE_WORLD_COORDINATE m_reset_skew_button->Show(show_skew); m_skew_label->Show(show_skew); + m_mirror_warning_bitmap->SetBitmap(show_mirror_warning ? m_manifold_warning_bmp.bmp() : wxNullBitmap); + m_mirror_warning_bitmap->SetMinSize(show_mirror_warning ? m_manifold_warning_bmp.GetSize() : wxSize(0, 0)); + m_mirror_warning_bitmap->SetToolTip(show_mirror_warning ? _L("Left handed") : ""); #endif // ENABLE_WORLD_COORDINATE // Because of CallAfter we need to layout sidebar after Show/hide of reset buttons one more time @@ -977,16 +1006,14 @@ void ObjectManipulation::update_mirror_buttons_visibility() { GLCanvas3D* canvas = wxGetApp().plater()->canvas3D(); Selection& selection = canvas->get_selection(); - std::array new_states = {mbHidden, mbHidden, mbHidden}; #if ENABLE_WORLD_COORDINATE if (is_local_coordinates()) { -#else - if (!m_world_coordinates) { -#endif // ENABLE_WORLD_COORDINATE -#if ENABLE_WORLD_COORDINATE if (selection.is_single_full_instance() || selection.is_single_volume_or_modifier()) { #else + std::array new_states = { mbHidden, mbHidden, mbHidden }; + + if (!m_world_coordinates) { if (selection.is_single_full_instance() || selection.is_single_modifier() || selection.is_single_volume()) { #endif // ENABLE_WORLD_COORDINATE const GLVolume* volume = selection.get_first_volume(); @@ -997,10 +1024,13 @@ void ObjectManipulation::update_mirror_buttons_visibility() else mirror = volume->get_volume_mirror(); +#if !ENABLE_WORLD_COORDINATE for (unsigned char i=0; i<3; ++i) new_states[i] = (mirror[i] < 0. ? mbActive : mbShown); +#endif // !ENABLE_WORLD_COORDINATE } } +#if !ENABLE_WORLD_COORDINATE else { // the mirroring buttons should be hidden in world coordinates, // unless we make it actually mirror in world coords. @@ -1022,6 +1052,7 @@ void ObjectManipulation::update_mirror_buttons_visibility() } } }); +#endif // !ENABLE_WORLD_COORDINATE } @@ -1059,8 +1090,8 @@ wxString ObjectManipulation::coordinate_type_str(ECoordinatesType type) switch (type) { case ECoordinatesType::World: { return _L("World coordinates"); } - case ECoordinatesType::Instance: { return _L("Instance coordinates"); } - case ECoordinatesType::Local: { return _L("Local coordinates"); } + case ECoordinatesType::Instance: { return _L("Object coordinates"); } + case ECoordinatesType::Local: { return _L("Part coordinates"); } default: { assert(false); return _L("Unknown"); } } } @@ -1162,13 +1193,24 @@ void ObjectManipulation::change_scale_value(int axis, double value) return; Vec3d scale = m_cache.scale; - scale(axis) = value; + scale(axis) = value; +#if ENABLE_WORLD_COORDINATE + const Selection& selection = wxGetApp().plater()->canvas3D()->get_selection(); + Vec3d ref_scale = m_cache.scale; + if (selection.is_single_full_instance()) { + scale = scale.cwiseQuotient(ref_scale); + ref_scale = Vec3d::Ones(); + } + + this->do_scale(axis, scale.cwiseQuotient(ref_scale)); +#else this->do_scale(axis, 0.01 * scale); +#endif // ENABLE_WORLD_COORDINATE m_cache.scale = scale; - m_cache.scale_rounded(axis) = DBL_MAX; - this->UpdateAndShow(true); + m_cache.scale_rounded(axis) = DBL_MAX; + this->UpdateAndShow(true); } @@ -1195,9 +1237,12 @@ void ObjectManipulation::change_size_value(int axis, double value) Vec3d ref_size = m_cache.size; #if ENABLE_WORLD_COORDINATE if (selection.is_single_volume_or_modifier()) { + if (is_local_coordinates()) + ref_size = selection.get_first_volume()->bounding_box().size(); + size = size.cwiseQuotient(ref_size); + ref_size = Vec3d::Ones(); #else if (selection.is_single_volume() || selection.is_single_modifier()) { -#endif // ENABLE_WORLD_COORDINATE const GLVolume* v = selection.get_first_volume(); const Vec3d local_size = size.cwiseQuotient(v->get_instance_scaling_factor()); const Vec3d local_ref_size = v->bounding_box().size().cwiseProduct(v->get_volume_scaling_factor()); @@ -1205,15 +1250,20 @@ void ObjectManipulation::change_size_value(int axis, double value) size = local_change.cwiseProduct(v->get_volume_scaling_factor()); ref_size = Vec3d::Ones(); +#endif // ENABLE_WORLD_COORDINATE } - else if (selection.is_single_full_instance()) + else if (selection.is_single_full_instance()) { #if ENABLE_WORLD_COORDINATE - ref_size = is_world_coordinates() ? + if (is_world_coordinates()) + ref_size = selection.get_unscaled_instance_bounding_box().size(); + size = size.cwiseQuotient(ref_size); + ref_size = Vec3d::Ones(); #else ref_size = m_world_coordinates ? -#endif // ENABLE_WORLD_COORDINATE selection.get_unscaled_instance_bounding_box().size() : wxGetApp().model().objects[selection.get_first_volume()->object_idx()]->raw_mesh_bounding_box().size(); +#endif // ENABLE_WORLD_COORDINATE + } #if ENABLE_WORLD_COORDINATE this->do_size(axis, size.cwiseQuotient(ref_size)); @@ -1222,8 +1272,8 @@ void ObjectManipulation::change_size_value(int axis, double value) #endif // ENABLE_WORLD_COORDINATE m_cache.size = size; - m_cache.size_rounded(axis) = DBL_MAX; - this->UpdateAndShow(true); + m_cache.size_rounded(axis) = DBL_MAX; + this->UpdateAndShow(true); } void ObjectManipulation::do_scale(int axis, const Vec3d &scale) const @@ -1240,7 +1290,8 @@ void ObjectManipulation::do_scale(int axis, const Vec3d &scale) const else if (is_instance_coordinates()) transformation_type.set_instance(); - if (!selection.is_single_full_instance() && !selection.is_single_volume_or_modifier()) + if (!(selection.is_single_volume_or_modifier() && is_local_coordinates()) && + !(selection.is_single_full_instance() && is_instance_coordinates())) transformation_type.set_relative(); const Vec3d scaling_factor = m_uniform_scale ? scale(axis) * Vec3d::Ones() : scale; @@ -1425,15 +1476,23 @@ void ObjectManipulation::sys_color_changed() editor->sys_color_changed(this); m_mirror_bitmap_on.sys_color_changed(); +#if !ENABLE_WORLD_COORDINATE m_mirror_bitmap_off.sys_color_changed(); m_mirror_bitmap_hidden.sys_color_changed(); +#endif // !ENABLE_WORLD_COORDINATE m_reset_scale_button->sys_color_changed(); m_reset_rotation_button->sys_color_changed(); m_drop_to_bed_button->sys_color_changed(); m_lock_bnt->sys_color_changed(); +#if ENABLE_WORLD_COORDINATE + for (int id = 0; id < 3; ++id) { + m_mirror_buttons[id]->sys_color_changed(); + } +#else for (int id = 0; id < 3; ++id) m_mirror_buttons[id].first->sys_color_changed(); +#endif // ENABLE_WORLD_COORDINATE } #if ENABLE_WORLD_COORDINATE diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.hpp b/src/slic3r/GUI/GUI_ObjectManipulation.hpp index 9995b3e6fa..69022dde7f 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.hpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.hpp @@ -132,6 +132,9 @@ private: wxCheckBox* m_check_inch {nullptr}; +#if ENABLE_WORLD_COORDINATE + std::array m_mirror_buttons; +#else // Mirroring buttons and their current state enum MirrorButtonState { mbHidden, @@ -139,18 +142,21 @@ private: mbActive }; std::array, 3> m_mirror_buttons; +#endif // ENABLE_WORLD_COORDINATE // Bitmaps for the mirroring buttons. ScalableBitmap m_mirror_bitmap_on; +#if !ENABLE_WORLD_COORDINATE ScalableBitmap m_mirror_bitmap_off; ScalableBitmap m_mirror_bitmap_hidden; +#endif // !ENABLE_WORLD_COORDINATE // Needs to be updated from OnIdle? bool m_dirty = false; // Cached labels for the delayed update, not localized! std::string m_new_move_label_string; - std::string m_new_rotate_label_string; - std::string m_new_scale_label_string; + std::string m_new_rotate_label_string; + std::string m_new_scale_label_string; Vec3d m_new_position; Vec3d m_new_rotation; Vec3d m_new_scale; @@ -167,7 +173,10 @@ private: choice_ctrl* m_word_local_combo { nullptr }; ScalableBitmap m_manifold_warning_bmp; - wxStaticBitmap* m_fix_throught_netfab_bitmap; + wxStaticBitmap* m_fix_throught_netfab_bitmap{ nullptr }; +#if ENABLE_WORLD_COORDINATE + wxStaticBitmap* m_mirror_warning_bitmap{ nullptr }; +#endif // ENABLE_WORLD_COORDINATE #if ENABLE_WORLD_COORDINATE // Currently focused editor (nullptr if none) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp index 95eddd9a0f..0202f8ada5 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp @@ -15,6 +15,7 @@ #include "libslic3r/TriangleMeshSlicer.hpp" #include "imgui/imgui_internal.h" +#include "slic3r/GUI/MsgDialog.hpp" namespace Slic3r { namespace GUI { @@ -913,7 +914,7 @@ void GLGizmoCut3D::on_register_raycasters_for_picking() m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, i + m_connectors_group_id, *(m_shapes[connectors[i].attribs]).mesh_raycaster, Transform3d::Identity())); } } - else { + else if (!cut_line_processing()) { m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, X, *m_cone.mesh_raycaster, Transform3d::Identity())); m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, X, *m_cone.mesh_raycaster, Transform3d::Identity())); @@ -991,7 +992,7 @@ void GLGizmoCut3D::update_raycasters_for_picking_transform() m_raycasters[i]->set_transform(translation_transform(pos) * m_rotation_m * scale_trafo); } } - else { + else if (!cut_line_processing()){ const Transform3d trafo = translation_transform(m_plane_center) * m_rotation_m; const BoundingBoxf3 box = bounding_box(); @@ -1376,10 +1377,14 @@ void GLGizmoCut3D::init_rendering_items() init_from_angle_arc(m_angle_arc, m_angle, m_grabber_connection_len); if (!m_plane.is_initialized() && !m_hide_cut_plane && !m_connectors_editing) { +#if 1 + m_plane.init_from(its_make_frustum_dowel((double)m_cut_plane_radius_koef * m_radius, 0.3, m_cut_plane_as_circle ? 180 : 4)); +#else if (m_cut_plane_as_circle) m_plane.init_from(its_make_frustum_dowel(2. * m_radius, 0.3, 180)); else m_plane.init_from(its_make_square_plane(float(m_radius))); +#endif } } @@ -1419,9 +1424,13 @@ void GLGizmoCut3D::on_render() m_selection_rectangle.render(m_parent); } -void GLGizmoCut3D::render_debug_input_window() +void GLGizmoCut3D::render_debug_input_window(float x) { m_imgui->begin(wxString("DEBUG")); + + ImVec2 pos = ImGui::GetWindowPos(); + pos.x = x; + ImGui::SetWindowPos(pos, ImGuiCond_Always); /* static bool hide_clipped = false; static bool fill_cut = false; @@ -1434,12 +1443,20 @@ void GLGizmoCut3D::render_debug_input_window() m_imgui->slider_float("contour_width", &contour_width, 0.f, 3.f); if (auto oc = m_c->object_clipper()) oc->set_behavior(hide_clipped || m_connectors_editing, fill_cut || m_connectors_editing, double(contour_width)); +*/ + ImGui::PushItemWidth(0.5f * m_label_width); + if (auto oc = m_c->object_clipper(); oc && m_imgui->slider_float("contour_width", &m_contour_width, 0.f, 3.f)) + oc->set_behavior(m_connectors_editing, m_connectors_editing, double(m_contour_width)); ImGui::Separator(); -*/ + if (m_imgui->checkbox(_L("Render cut plane as circle"), m_cut_plane_as_circle)) m_plane.reset(); + ImGui::PushItemWidth(0.5f * m_label_width); + if (m_imgui->slider_float("cut_plane_radius_koef", &m_cut_plane_radius_koef, 1.f, 2.f)) + m_plane.reset(); + m_imgui->end(); } @@ -1481,10 +1498,19 @@ void GLGizmoCut3D::render_shortcuts() if (m_imgui->button("? " + (m_show_shortcuts ? wxString(ImGui::CollapseBtn) : wxString(ImGui::ExpandBtn)))) m_show_shortcuts = !m_show_shortcuts; + if (m_shortcut_label_width < 0.f) { + for (const auto& shortcut : m_shortcuts) { + const float width = m_imgui->calc_text_size(shortcut.first).x; + if (m_shortcut_label_width < width) + m_shortcut_label_width = width; + } + m_shortcut_label_width += +m_imgui->scaled(1.f); + } + if (m_show_shortcuts) for (const auto&shortcut : m_shortcuts ){ m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, shortcut.first); - ImGui::SameLine(m_label_width); + ImGui::SameLine(m_shortcut_label_width); m_imgui->text(shortcut.second); } } @@ -1624,8 +1650,8 @@ void GLGizmoCut3D::render_cut_plane_input_window(CutConnectors &connectors) ImGui::AlignTextToFramePadding(); m_imgui->text(wxString(ImGui::InfoMarkerSmall)); ImGui::SameLine(); - m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, _L("Hold SHIFT key and connect some two points of an object to cut by line")); - + m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, + get_wraped_wxString(_L("Hold SHIFT key and connect some two points of an object to cut by line"), 40)); ImGui::Separator(); render_build_size(); @@ -1642,13 +1668,6 @@ void GLGizmoCut3D::render_cut_plane_input_window(CutConnectors &connectors) reset_cut_plane(); m_imgui->disabled_end(); - ImGui::SameLine(2.25f * m_label_width); - ImGui::PushItemWidth(0.75f * m_label_width); - m_is_contour_changed = m_imgui->slider_float("contour width", &m_contour_width, 0.f, 3.f); - - if (auto oc = m_c->object_clipper(); oc && m_is_contour_changed) - oc->set_behavior(m_connectors_editing, m_connectors_editing, double(m_contour_width)); - if (wxGetApp().plater()->printer_technology() == ptFFF) { m_imgui->disabled_begin(!m_keep_upper || !m_keep_lower); if (m_imgui->button(_L("Add/Edit connectors"))) @@ -1658,18 +1677,25 @@ void GLGizmoCut3D::render_cut_plane_input_window(CutConnectors &connectors) ImGui::Separator(); - auto render_part_action_line = [this, connectors](const wxString& label, const wxString& suffix, bool& keep_part, bool& place_on_cut_part, bool& rotate_part) { + float label_width = 0; + for (const wxString& label : {_L("Upper part"), _L("Lower part")}) { + const float width = m_imgui->calc_text_size(label).x + m_imgui->scaled(1.5f); + if (label_width < width) + label_width = width; + } + + auto render_part_action_line = [this, label_width, connectors](const wxString& label, const wxString& suffix, bool& keep_part, bool& place_on_cut_part, bool& rotate_part) { bool keep = true; ImGui::AlignTextToFramePadding(); m_imgui->text(label); - ImGui::SameLine(m_label_width); + ImGui::SameLine(label_width); m_imgui->disabled_begin(!connectors.empty()); m_imgui->checkbox(_L("Keep") + suffix, connectors.empty() ? keep_part : keep); m_imgui->disabled_end(); - ImGui::SameLine(2 * m_label_width); + ImGui::SameLine(); m_imgui->disabled_begin(!keep_part); if (m_imgui->checkbox(_L("Place on cut") + suffix, place_on_cut_part)) @@ -1813,7 +1839,8 @@ void GLGizmoCut3D::on_render_input_window(float x, float y, float bottom_limit) m_imgui->end(); - render_debug_input_window(); + if (!m_connectors_editing) // connectors mode + render_debug_input_window(x); } // get volume transformation regarding to the "border". Border is related from the size of connectors diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp index 15d53c9de1..88027f6849 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp @@ -111,7 +111,9 @@ class GLGizmoCut3D : public GLGizmoBase bool force_update_clipper_on_render{false}; float m_contour_width{ 0.4f }; + float m_cut_plane_radius_koef{ 1.5f }; bool m_is_contour_changed{ false }; + float m_shortcut_label_width{ -1.f }; mutable std::vector m_selected; // which pins are currently selected int m_selected_count{ 0 }; @@ -199,7 +201,7 @@ protected: void on_stop_dragging() override; void on_render() override; - void render_debug_input_window(); + void render_debug_input_window(float x); void adjust_window_position(float x, float y, float bottom_limit); void unselect_all_connectors(); void select_all_connectors(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index ed9e2d0786..fc99e52c08 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -1359,10 +1359,10 @@ void GLGizmoMeasure::render_dimensioning() action_exit(); ImGui::SameLine(); - if (m_imgui->button(_u8L("Scale"))) + if (m_imgui->button(_CTX(L_CONTEXT("Scale", "Verb"), "Verb"))) action_scale(edit_value, curr_value); ImGui::SameLine(); - if (m_imgui->button(_u8L("Cancel"))) + if (m_imgui->button(_L("Cancel"))) action_exit(); ImGui::EndPopup(); } @@ -1991,7 +1991,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit radius = (on_circle - center).norm(); if (use_inches) radius = ObjectManipulation::mm_to_in * radius; - text += " (" + _u8L("Diameter:") + " " + format_double(2.0 * radius) + units + ")"; + text += " (" + _u8L("Diameter") + ": " + format_double(2.0 * radius) + units + ")"; } return text; }; @@ -2004,7 +2004,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit } m_imgui->disabled_begin(!m_selected_features.first.feature.has_value()); - if (m_imgui->button(_u8L("Restart selection"))) { + if (m_imgui->button(_L("Restart selection"))) { m_selected_features.reset(); m_selected_sphere_raycasters.clear(); m_imgui->set_requires_extra_frame(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp index 6e7cf9c832..0be1d16551 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp @@ -614,7 +614,7 @@ bool GLGizmoRotate3D::on_mouse(const wxMouseEvent &mouse_event) #if ENABLE_WORLD_COORDINATE TransformationType transformation_type; if (m_parent.get_selection().is_wipe_tower()) - transformation_type = TransformationType::Instance_Relative_Joint; + transformation_type = TransformationType::World_Relative_Joint; else { switch (wxGetApp().obj_manipul()->get_coordinates_type()) { diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index e242b6e6f3..ba8378d1f9 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -119,10 +119,10 @@ Selection::Selection() { this->set_bounding_boxes_dirty(); #if ENABLE_WORLD_COORDINATE - m_axes.set_stem_radius(0.15f); - m_axes.set_stem_length(3.0f); - m_axes.set_tip_radius(0.45f); - m_axes.set_tip_length(1.5f); + m_axes.set_stem_radius(0.5f); + m_axes.set_stem_length(20.0f); + m_axes.set_tip_radius(1.5f); + m_axes.set_tip_length(5.0f); #endif // ENABLE_WORLD_COORDINATE } @@ -828,18 +828,15 @@ void Selection::translate(const Vec3d& displacement, TransformationType transfor assert(is_from_fully_selected_instance(i)); if (transformation_type.world()) v.set_instance_transformation(Geometry::translation_transform(displacement) * volume_data.get_instance_full_matrix()); - else if (transformation_type.local()) { + else if (transformation_type.instance()) { const Vec3d world_displacement = volume_data.get_instance_rotation_matrix() * displacement; v.set_instance_transformation(Geometry::translation_transform(world_displacement) * volume_data.get_instance_full_matrix()); } else assert(false); } - else { - const Vec3d offset = transformation_type.local() ? - (Vec3d)(volume_data.get_volume_transform().get_rotation_matrix() * displacement) : displacement; - transform_volume_relative(v, volume_data, transformation_type, Geometry::translation_transform(offset)); - } + else + transform_volume_relative(v, volume_data, transformation_type, Geometry::translation_transform(displacement), m_cache.dragging_center); } #if !DISABLE_INSTANCES_SYNCH @@ -918,7 +915,7 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_ else { if (transformation_type.world()) new_rotation_matrix = rotation_matrix * inst_trafo.get_rotation_matrix(); - else if (transformation_type.local()) + else if (transformation_type.instance()) new_rotation_matrix = inst_trafo.get_rotation_matrix() * rotation_matrix; else assert(false); @@ -931,13 +928,14 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_ inst_trafo.get_scaling_factor_matrix(), inst_trafo.get_mirror_matrix())); } else { - if (transformation_type.absolute()) { - const Geometry::Transformation& volume_trafo = volume_data.get_volume_transform(); - v.set_volume_transformation(Geometry::assemble_transform(volume_trafo.get_offset_matrix(), Geometry::rotation_transform(rotation), - volume_trafo.get_scaling_factor_matrix(), volume_trafo.get_mirror_matrix())); + if (!is_single_volume_or_modifier()) { + assert(transformation_type.world()); + transform_volume_relative(v, volume_data, transformation_type, rotation_matrix, m_cache.dragging_center); + } + else { + transformation_type.set_independent(); + transform_volume_relative(v, volume_data, transformation_type, rotation_matrix, m_cache.dragging_center); } - else - transform_volume_relative(v, volume_data, transformation_type, Geometry::rotation_transform(rotation)); } } @@ -948,7 +946,7 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_ SyncRotationType synch; if (transformation_type.world() && rot_axis_max == 2) synch = SyncRotationType::NONE; - else if (transformation_type.local()) + else if (transformation_type.instance()) synch = SyncRotationType::FULL; else synch = SyncRotationType::GENERAL; @@ -1283,6 +1281,13 @@ void Selection::scale_to_fit_print_volume(const BuildVolume& volume) } } +#if ENABLE_WORLD_COORDINATE +void Selection::mirror(Axis axis, TransformationType transformation_type) +{ + const Vec3d mirror((axis == X) ? -1.0 : 1.0, (axis == Y) ? -1.0 : 1.0, (axis == Z) ? -1.0 : 1.0); + scale_and_translate(mirror, Vec3d::Zero(), transformation_type); +} +#else void Selection::mirror(Axis axis) { if (!m_valid) @@ -1305,6 +1310,7 @@ void Selection::mirror(Axis axis) set_bounding_boxes_dirty(); } +#endif // ENABLE_WORLD_COORDINATE #if ENABLE_WORLD_COORDINATE void Selection::scale_and_translate(const Vec3d& scale, const Vec3d& translation, TransformationType transformation_type) @@ -1322,24 +1328,32 @@ void Selection::scale_and_translate(const Vec3d& scale, const Vec3d& translation if (transformation_type.absolute()) { // convert from absolute scaling to relative scaling BoundingBoxf3 original_box; + BoundingBoxf3 reference_box = m_box.get_bounding_box(); if (m_mode == Instance) { - assert(is_from_fully_selected_instance(i)); + if (is_single_full_instance()) { if (transformation_type.world()) original_box = get_full_unscaled_instance_bounding_box(); else original_box = get_full_unscaled_instance_local_bounding_box(); + } + else + original_box = get_bounding_box(); } else { - if (transformation_type.world()) - original_box = v.transformed_convex_hull_bounding_box((volume_data.get_instance_transform() * - volume_data.get_volume_transform()).get_matrix_no_scaling_factor()); + if (!is_single_volume_or_modifier()) + original_box = get_bounding_box(); + else if (transformation_type.world()) + original_box = get_bounding_box(); else if (transformation_type.instance()) - original_box = v.transformed_convex_hull_bounding_box(volume_data.get_volume_transform().get_matrix_no_scaling_factor()); - else + original_box = v.transformed_convex_hull_bounding_box(volume_data.get_volume_transform().get_matrix()); + else { original_box = v.bounding_box(); + reference_box = v.bounding_box().transformed(volume_data.get_volume_transform().get_scaling_factor_matrix()); + } + transformation_type.set_relative(); } - relative_scale = original_box.size().cwiseProduct(scale).cwiseQuotient(m_box.get_bounding_box().size()); + relative_scale = original_box.size().cwiseProduct(scale).cwiseQuotient(reference_box.size()); } if (m_mode == Instance) { @@ -1353,7 +1367,7 @@ void Selection::scale_and_translate(const Vec3d& scale, const Vec3d& translation Geometry::translation_transform(translation) * inst_trafo.get_offset_matrix(); v.set_instance_transformation(offset_matrix * scale_matrix * inst_trafo.get_matrix_no_offset()); } - else if (transformation_type.local()) { + else if (transformation_type.instance()) { const Transform3d scale_matrix = Geometry::scale_transform(relative_scale); Vec3d offset; if (transformation_type.joint() && translation.isApprox(Vec3d::Zero())) { @@ -1370,8 +1384,16 @@ void Selection::scale_and_translate(const Vec3d& scale, const Vec3d& translation else assert(false); } - else - transform_volume_relative(v, volume_data, transformation_type, Geometry::translation_transform(translation) * Geometry::scale_transform(relative_scale)); + else { + if (!is_single_volume_or_modifier()) { + assert(transformation_type.world()); + transform_volume_relative(v, volume_data, transformation_type, Geometry::translation_transform(translation) * Geometry::scale_transform(relative_scale), m_cache.dragging_center); + } + else { + transformation_type.set_independent(); + transform_volume_relative(v, volume_data, transformation_type, Geometry::translation_transform(translation) * Geometry::scale_transform(relative_scale), m_cache.dragging_center); + } + } } #if !DISABLE_INSTANCES_SYNCH @@ -1707,8 +1729,8 @@ void Selection::render(float scale_factor) } else if (coordinates_type == ECoordinatesType::Local && is_single_volume_or_modifier()) { const GLVolume& v = *get_first_volume(); - box = v.transformed_convex_hull_bounding_box(v.get_volume_transformation().get_scaling_factor_matrix()); - trafo = v.get_instance_transformation().get_matrix() * v.get_volume_transformation().get_matrix_no_scaling_factor(); + box = v.bounding_box(); + trafo = v.world_matrix(); } else { const Selection::IndicesList& ids = get_volume_idxs(); @@ -1716,9 +1738,7 @@ void Selection::render(float scale_factor) const GLVolume& v = *get_volume(id); box.merge(v.transformed_convex_hull_bounding_box(v.get_volume_transformation().get_matrix())); } - const Geometry::Transformation inst_trafo = get_first_volume()->get_instance_transformation(); - box = box.transformed(inst_trafo.get_scaling_factor_matrix()); - trafo = inst_trafo.get_matrix_no_scaling_factor(); + trafo = get_first_volume()->get_instance_transformation().get_matrix(); } render_bounding_box(box, trafo, ColorRGB::WHITE()); @@ -1856,7 +1876,7 @@ void Selection::render_sidebar_hints(const std::string& sidebar_field) #if ENABLE_WORLD_COORDINATE if (!boost::starts_with(sidebar_field, "layer")) { - if (!wxGetApp().obj_manipul()->is_world_coordinates()) + if (wxGetApp().obj_manipul()->is_instance_coordinates()) m_axes.render(Geometry::translation_transform(axes_center) * orient_matrix, 0.25f); } #endif // ENABLE_WORLD_COORDINATE @@ -3021,17 +3041,24 @@ void Selection::paste_objects_from_clipboard() #if ENABLE_WORLD_COORDINATE void Selection::transform_volume_relative(GLVolume& volume, const VolumeCache& volume_data, TransformationType transformation_type, - const Transform3d& transform) + const Transform3d& transform, const Vec3d& world_pivot) { - const Geometry::Transformation& inst_trafo = volume_data.get_instance_transform(); + assert(transformation_type.relative()); + const Geometry::Transformation& volume_trafo = volume_data.get_volume_transform(); + const Geometry::Transformation& inst_trafo = volume_data.get_instance_transform(); + if (transformation_type.world()) { + const Vec3d inst_pivot = transformation_type.independent() ? volume_trafo.get_offset() : (Vec3d)(inst_trafo.get_matrix().inverse() * world_pivot); const Transform3d inst_matrix_no_offset = inst_trafo.get_matrix_no_offset(); - const Transform3d new_volume_matrix = inst_matrix_no_offset.inverse() * transform * inst_matrix_no_offset; - volume.set_volume_transformation(volume_trafo.get_offset_matrix() * new_volume_matrix * volume_trafo.get_matrix_no_offset()); + const Transform3d trafo = Geometry::translation_transform(inst_pivot) * inst_matrix_no_offset.inverse() * transform * inst_matrix_no_offset * Geometry::translation_transform(-inst_pivot); + volume.set_volume_transformation(trafo * volume_trafo.get_matrix()); + } + else if (transformation_type.instance()) { + const Vec3d inst_pivot = transformation_type.independent() ? volume_trafo.get_offset() : (Vec3d)(inst_trafo.get_matrix().inverse() * world_pivot); + const Transform3d trafo = Geometry::translation_transform(inst_pivot) * transform * Geometry::translation_transform(-inst_pivot); + volume.set_volume_transformation(trafo * volume_trafo.get_matrix()); } - else if (transformation_type.instance()) - volume.set_volume_transformation(volume_trafo.get_offset_matrix() * transform * volume_trafo.get_matrix_no_offset()); else if (transformation_type.local()) { const Geometry::Transformation trafo(transform); volume.set_volume_transformation(trafo.get_offset_matrix() * volume_trafo.get_matrix() * trafo.get_matrix_no_offset()); diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp index 107e56f41c..f6bc412601 100644 --- a/src/slic3r/GUI/Selection.hpp +++ b/src/slic3r/GUI/Selection.hpp @@ -300,7 +300,7 @@ public: void set_deserialized(EMode mode, const std::vector> &volumes_and_instances); // Update the selection based on the new instance IDs. - void instances_changed(const std::vector &instance_ids_selected); + void instances_changed(const std::vector &instance_ids_selected); // Update the selection based on the map from old indices to new indices after m_volumes changed. // If the current selection is by instance, this call may select newly added volumes, if they belong to already selected instances. void volumes_changed(const std::vector &map_volume_old_to_new); @@ -402,11 +402,12 @@ public: void flattening_rotate(const Vec3d& normal); void scale(const Vec3d& scale, TransformationType transformation_type); void scale_to_fit_print_volume(const BuildVolume& volume); - void mirror(Axis axis); #if ENABLE_WORLD_COORDINATE void scale_and_translate(const Vec3d& scale, const Vec3d& translation, TransformationType transformation_type); + void mirror(Axis axis, TransformationType transformation_type); void reset_skew(); #else + void mirror(Axis axis); void translate(unsigned int object_idx, const Vec3d& displacement); #endif // ENABLE_WORLD_COORDINATE void translate(unsigned int object_idx, unsigned int instance_idx, const Vec3d& displacement); @@ -501,7 +502,7 @@ private: #if ENABLE_WORLD_COORDINATE void transform_volume_relative(GLVolume& volume, const VolumeCache& volume_data, TransformationType transformation_type, - const Transform3d& transform); + const Transform3d& transform, const Vec3d& world_pivot); #endif // ENABLE_WORLD_COORDINATE };