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
};