diff --git a/src/libslic3r/Geometry.cpp b/src/libslic3r/Geometry.cpp index 0242a9eee..7366d2233 100644 --- a/src/libslic3r/Geometry.cpp +++ b/src/libslic3r/Geometry.cpp @@ -430,7 +430,26 @@ static bool contains_skew(const Transform3d& trafo) Matrix3d rotation; Matrix3d scale; trafo.computeRotationScaling(&rotation, &scale); - return !scale.isDiagonal(); + + if (scale.isDiagonal()) + return false; + + if (scale.determinant() >= 0.0) + return true; + + // the matrix contains mirror + const Matrix3d ratio = scale.cwiseQuotient(trafo.matrix().block<3,3>(0,0)); + + auto check_skew = [&ratio](int i, int j, bool& skew) { + if (!std::isnan(ratio(i, j)) && !std::isnan(ratio(j, i))) + skew |= std::abs(ratio(i, j) * ratio(j, i) - 1.0) > EPSILON; + }; + + bool has_skew = false; + check_skew(0, 1, has_skew); + check_skew(0, 2, has_skew); + check_skew(1, 2, has_skew); + return has_skew; } Vec3d Transformation::get_rotation() const diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index edf4d5b07..a0336c685 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -1198,7 +1198,11 @@ void ObjectManipulation::change_scale_value(int axis, double 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()) { + if (selection.is_single_volume_or_modifier()) { + if (is_local_coordinates()) + ref_scale = 100.0 * Vec3d::Ones(); + } + else if (selection.is_single_full_instance()) { scale = scale.cwiseQuotient(ref_scale); ref_scale = Vec3d::Ones(); } diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 1b536baa8..54de6cd56 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -4188,6 +4188,8 @@ void Plater::priv::on_select_preset(wxCommandEvent &evt) wxGetApp().preset_bundle->set_filament_preset(idx, preset_name); } + std::string last_selected_ph_printer_name = combo->get_selected_ph_printer_name(); + bool select_preset = !combo->selection_is_changed_according_to_physical_printers(); // TODO: ? if (preset_type == Preset::TYPE_FILAMENT && sidebar->is_multifilament()) { @@ -4196,7 +4198,7 @@ void Plater::priv::on_select_preset(wxCommandEvent &evt) } else if (select_preset) { wxWindowUpdateLocker noUpdates(sidebar->presets_panel()); - wxGetApp().get_tab(preset_type)->select_preset(preset_name); + wxGetApp().get_tab(preset_type)->select_preset(preset_name, false, last_selected_ph_printer_name); } if (preset_type != Preset::TYPE_PRINTER || select_preset) { diff --git a/src/slic3r/GUI/PresetComboBoxes.cpp b/src/slic3r/GUI/PresetComboBoxes.cpp index 6fcde3bf6..c4d0fc670 100644 --- a/src/slic3r/GUI/PresetComboBoxes.cpp +++ b/src/slic3r/GUI/PresetComboBoxes.cpp @@ -666,6 +666,18 @@ void PlaterPresetComboBox::OnSelect(wxCommandEvent &evt) evt.Skip(); } +std::string PlaterPresetComboBox::get_selected_ph_printer_name() const +{ + if (m_type != Preset::TYPE_PRINTER) + return {}; + + const PhysicalPrinterCollection& physical_printers = m_preset_bundle->physical_printers; + if (physical_printers.has_selection()) + return physical_printers.get_selected_full_printer_name(); + + return {}; +} + void PlaterPresetComboBox::switch_to_tab() { Tab* tab = wxGetApp().get_tab(m_type); diff --git a/src/slic3r/GUI/PresetComboBoxes.hpp b/src/slic3r/GUI/PresetComboBoxes.hpp index d0abbe203..2a477ac11 100644 --- a/src/slic3r/GUI/PresetComboBoxes.hpp +++ b/src/slic3r/GUI/PresetComboBoxes.hpp @@ -164,6 +164,8 @@ public: void sys_color_changed() override; void OnSelect(wxCommandEvent& evt) override; + std::string get_selected_ph_printer_name() const; + private: int m_extruder_idx = -1; }; diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index ba8378d1f..d7b129782 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -826,17 +826,26 @@ void Selection::translate(const Vec3d& displacement, TransformationType transfor const VolumeCache& volume_data = m_cache.volumes_data[i]; if (m_mode == Instance && !is_wipe_tower()) { 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.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()); + if (transformation_type.instance()) { + const Geometry::Transformation& inst_trafo = volume_data.get_instance_transform(); + v.set_instance_offset(inst_trafo.get_offset() + inst_trafo.get_rotation_matrix() * displacement); } else - assert(false); + transform_instance_relative(v, volume_data, transformation_type, Geometry::translation_transform(displacement), m_cache.dragging_center); + } + else { + if (transformation_type.local()) { + const Geometry::Transformation& vol_trafo = volume_data.get_volume_transform(); + v.set_volume_offset(vol_trafo.get_offset() + vol_trafo.get_rotation_matrix() * displacement); + } + else { + Vec3d relative_disp = displacement; + if (transformation_type.instance()) + relative_disp = volume_data.get_instance_scale_matrix().inverse() * relative_disp; + + transform_volume_relative(v, volume_data, transformation_type, Geometry::translation_transform(relative_disp), m_cache.dragging_center); + } } - else - transform_volume_relative(v, volume_data, transformation_type, Geometry::translation_transform(displacement), m_cache.dragging_center); } #if !DISABLE_INSTANCES_SYNCH @@ -909,23 +918,16 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_ const Geometry::Transformation& inst_trafo = volume_data.get_instance_transform(); if (m_mode == Instance && !is_wipe_tower()) { assert(is_from_fully_selected_instance(i)); - Transform3d new_rotation_matrix = Transform3d::Identity(); - if (transformation_type.absolute()) - new_rotation_matrix = rotation_matrix; - else { - if (transformation_type.world()) - new_rotation_matrix = rotation_matrix * inst_trafo.get_rotation_matrix(); - else if (transformation_type.instance()) - new_rotation_matrix = inst_trafo.get_rotation_matrix() * rotation_matrix; - else - assert(false); + if (transformation_type.instance()) { + const Vec3d world_inst_pivot = m_cache.dragging_center - inst_trafo.get_offset(); + const Vec3d local_inst_pivot = inst_trafo.get_matrix_no_offset().inverse() * world_inst_pivot; + Matrix3d inst_rotation, inst_scale; + inst_trafo.get_matrix().computeRotationScaling(&inst_rotation, &inst_scale); + const Transform3d trafo = inst_trafo.get_rotation_matrix() * rotation_matrix; + v.set_instance_transformation(Geometry::translation_transform(world_inst_pivot) * inst_trafo.get_offset_matrix() * trafo * Transform3d(inst_scale) * Geometry::translation_transform(-local_inst_pivot)); } - - const Vec3d new_offset = transformation_type.independent() ? inst_trafo.get_offset() : - m_cache.dragging_center + new_rotation_matrix * inst_trafo.get_rotation_matrix().inverse() * - (inst_trafo.get_offset() - m_cache.dragging_center); - v.set_instance_transformation(Geometry::assemble_transform(Geometry::translation_transform(new_offset), new_rotation_matrix, - inst_trafo.get_scaling_factor_matrix(), inst_trafo.get_mirror_matrix())); + else + transform_instance_relative(v, volume_data, transformation_type, rotation_matrix, m_cache.dragging_center); } else { if (!is_single_volume_or_modifier()) { @@ -933,8 +935,15 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_ 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); + if (transformation_type.local()) { + const Geometry::Transformation& vol_trafo = volume_data.get_volume_transform(); + Matrix3d vol_rotation, vol_scale; + vol_trafo.get_matrix().computeRotationScaling(&vol_rotation, &vol_scale); + const Transform3d trafo = vol_trafo.get_rotation_matrix() * rotation_matrix; + v.set_volume_transformation(vol_trafo.get_offset_matrix() * trafo * Transform3d(vol_scale)); + } + else + transform_volume_relative(v, volume_data, transformation_type, rotation_matrix, m_cache.dragging_center); } } } @@ -1357,32 +1366,17 @@ void Selection::scale_and_translate(const Vec3d& scale, const Vec3d& translation } if (m_mode == Instance) { - assert(is_from_fully_selected_instance(i)); - if (transformation_type.world()) { - const Transform3d scale_matrix = Geometry::scale_transform(relative_scale); - const Transform3d offset_matrix = (transformation_type.joint() && translation.isApprox(Vec3d::Zero())) ? - // non-constrained scaling - add offset to scale around selection center - Geometry::translation_transform(m_cache.dragging_center + scale_matrix * (inst_trafo.get_offset() - m_cache.dragging_center)) : - // constrained scaling - add offset to keep constraint - 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.instance()) { - const Transform3d scale_matrix = Geometry::scale_transform(relative_scale); - Vec3d offset; - if (transformation_type.joint() && translation.isApprox(Vec3d::Zero())) { - // non-constrained scaling - add offset to scale around selection center - offset = inst_trafo.get_matrix_no_offset().inverse() * (inst_trafo.get_offset() - m_cache.dragging_center); - offset = inst_trafo.get_matrix_no_offset() * (scale_matrix * offset - offset); - } - else - // constrained scaling - add offset to keep constraint - offset = translation; - - v.set_instance_transformation(Geometry::translation_transform(offset) * inst_trafo.get_matrix() * scale_matrix); + if (transformation_type.instance()) { + const Vec3d world_inst_pivot = m_cache.dragging_center - inst_trafo.get_offset(); + const Vec3d local_inst_pivot = inst_trafo.get_matrix_no_offset().inverse() * world_inst_pivot; + Matrix3d inst_rotation, inst_scale; + inst_trafo.get_matrix().computeRotationScaling(&inst_rotation, &inst_scale); + const Transform3d offset_trafo = Geometry::translation_transform(inst_trafo.get_offset() + inst_rotation * translation); + const Transform3d scale_trafo = Transform3d(inst_scale) * Geometry::scale_transform(relative_scale); + v.set_instance_transformation(Geometry::translation_transform(world_inst_pivot) * offset_trafo * Transform3d(inst_rotation) * scale_trafo * Geometry::translation_transform(-local_inst_pivot)); } else - assert(false); + transform_instance_relative(v, volume_data, transformation_type, Geometry::translation_transform(translation) * Geometry::scale_transform(relative_scale), m_cache.dragging_center); } else { if (!is_single_volume_or_modifier()) { @@ -1390,8 +1384,18 @@ void Selection::scale_and_translate(const Vec3d& scale, const Vec3d& translation 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 (transformation_type.local()) { + const Geometry::Transformation& vol_trafo = volume_data.get_volume_transform(); + Matrix3d vol_rotation, vol_scale; + vol_trafo.get_matrix().computeRotationScaling(&vol_rotation, &vol_scale); + const Transform3d offset_trafo = Geometry::translation_transform(vol_trafo.get_offset() + vol_rotation * translation); + const Transform3d scale_trafo = Transform3d(vol_scale) * Geometry::scale_transform(relative_scale); + v.set_volume_transformation(offset_trafo * Transform3d(vol_rotation) * scale_trafo); + } + 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); + } } } } @@ -3040,28 +3044,36 @@ void Selection::paste_objects_from_clipboard() } #if ENABLE_WORLD_COORDINATE +void Selection::transform_instance_relative(GLVolume& volume, const VolumeCache& volume_data, TransformationType transformation_type, + const Transform3d& transform, const Vec3d& world_pivot) +{ + assert(transformation_type.relative()); + assert(transformation_type.world()); + + const Geometry::Transformation& inst_trafo = volume_data.get_instance_transform(); + const Vec3d inst_pivot = transformation_type.independent() && !is_from_single_instance() ? inst_trafo.get_offset() : world_pivot; + const Transform3d trafo = Geometry::translation_transform(inst_pivot) * transform * Geometry::translation_transform(-inst_pivot); + volume.set_instance_transformation(trafo * inst_trafo.get_matrix()); +} + void Selection::transform_volume_relative(GLVolume& volume, const VolumeCache& volume_data, TransformationType transformation_type, const Transform3d& transform, const Vec3d& world_pivot) { assert(transformation_type.relative()); - const Geometry::Transformation& volume_trafo = volume_data.get_volume_transform(); + const Geometry::Transformation& vol_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 Vec3d inst_pivot = transformation_type.independent() ? vol_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 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()); + volume.set_volume_transformation(trafo * vol_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 Vec3d inst_pivot = transformation_type.independent() ? vol_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.local()) { - const Geometry::Transformation trafo(transform); - volume.set_volume_transformation(trafo.get_offset_matrix() * volume_trafo.get_matrix() * trafo.get_matrix_no_offset()); + volume.set_volume_transformation(trafo * vol_trafo.get_matrix()); } else assert(false); diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp index f6bc41260..029a70a25 100644 --- a/src/slic3r/GUI/Selection.hpp +++ b/src/slic3r/GUI/Selection.hpp @@ -501,6 +501,8 @@ private: void paste_objects_from_clipboard(); #if ENABLE_WORLD_COORDINATE + void transform_instance_relative(GLVolume& volume, const VolumeCache& volume_data, TransformationType transformation_type, + const Transform3d& transform, const Vec3d& world_pivot); void transform_volume_relative(GLVolume& volume, const VolumeCache& volume_data, TransformationType transformation_type, const Transform3d& transform, const Vec3d& world_pivot); #endif // ENABLE_WORLD_COORDINATE diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 8a7c41f62..cf3b96d80 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -2978,6 +2978,10 @@ void TabPrinter::activate_selected_page(std::function throw_if_canceled) void TabPrinter::clear_pages() { Tab::clear_pages(); + + m_machine_limits_description_line = nullptr; + m_fff_print_host_upload_description_line = nullptr; + m_sla_print_host_upload_description_line = nullptr; } void TabPrinter::toggle_options() @@ -3402,7 +3406,7 @@ void Tab::select_preset(std::string preset_name, bool delete_current /*=false*/, // If preset selection was canceled and previously was selected physical printer, we should select it back m_preset_bundle->physical_printers.select_printer(last_selected_ph_printer_name); } - if (m_preset_bundle->physical_printers.has_selection()) { + else if (m_preset_bundle->physical_printers.has_selection()) { // If preset selection was canceled and physical printer was selected // we must disable selection marker for the physical printers m_preset_bundle->physical_printers.unselect_printer(); diff --git a/src/slic3r/GUI/UnsavedChangesDialog.cpp b/src/slic3r/GUI/UnsavedChangesDialog.cpp index 158579c70..222a566cd 100644 --- a/src/slic3r/GUI/UnsavedChangesDialog.cpp +++ b/src/slic3r/GUI/UnsavedChangesDialog.cpp @@ -1571,6 +1571,13 @@ void DiffPresetDialog::create_tree() m_tree->GetColumn(DiffModel::colToggle)->SetHidden(true); } +static std::array types_list(PrinterTechnology pt) +{ + if (pt == ptFFF) + return { Preset::TYPE_PRINTER, Preset::TYPE_PRINT, Preset::TYPE_FILAMENT }; + return { Preset::TYPE_PRINTER, Preset::TYPE_SLA_PRINT, Preset::TYPE_SLA_MATERIAL }; +} + void DiffPresetDialog::create_buttons() { wxFont font = this->GetFont().Scaled(1.4f); @@ -1598,8 +1605,7 @@ void DiffPresetDialog::create_buttons() bool enable = m_tree->has_selection(); if (enable) { if (m_view_type == Preset::TYPE_INVALID) { - for (const Preset::Type& type : (m_pr_technology == ptFFF ? std::initializer_list{Preset::TYPE_PRINTER, Preset::TYPE_PRINT, Preset::TYPE_FILAMENT} : - std::initializer_list{ Preset::TYPE_PRINTER, Preset::TYPE_SLA_PRINT, Preset::TYPE_SLA_MATERIAL })) + for (const Preset::Type& type : types_list(m_pr_technology)) if (!enable_transfer(type)) { enable = false; break; @@ -2024,10 +2030,7 @@ bool DiffPresetDialog::is_save_confirmed() std::vector types_for_save; - const auto list = m_pr_technology == ptFFF ? std::initializer_list{Preset::TYPE_PRINTER, Preset::TYPE_PRINT, Preset::TYPE_FILAMENT} : - std::initializer_list{ Preset::TYPE_PRINTER, Preset::TYPE_SLA_PRINT, Preset::TYPE_SLA_MATERIAL }; - - for (const Preset::Type& type : list) { + for (const Preset::Type& type : types_list(m_pr_technology)) { if (!m_tree->options(type, true).empty()) { types_for_save.emplace_back(type); presets_to_save.emplace_back(PresetToSave{ type, get_left_preset_name(type), get_right_preset_name(type), get_right_preset_name(type) });