Tech ENABLE_WORLD_COORDINATE_SCALE_REVISITED - Alternate implementation of manipulating scale for instances and volumes using gizmo scale and sidebar object manipulator fields - 1st installment

This commit is contained in:
enricoturri1966 2022-02-18 08:57:26 +01:00
parent cf245a7995
commit db852fe74f
10 changed files with 238 additions and 16 deletions

View File

@ -1412,9 +1412,11 @@ void ModelObject::bake_xy_rotation_into_meshes(size_t instance_idx)
assert(instance_idx < this->instances.size());
const Geometry::Transformation reference_trafo = this->instances[instance_idx]->get_transformation();
#if !ENABLE_WORLD_COORDINATE_SCALE_REVISITED
if (Geometry::is_rotation_ninety_degrees(reference_trafo.get_rotation()))
// nothing to do, scaling in the world coordinate space is possible in the representation of Geometry::Transformation.
return;
#endif // !ENABLE_WORLD_COORDINATE_SCALE_REVISITED
bool left_handed = reference_trafo.is_left_handed();
bool has_mirrorring = ! reference_trafo.get_mirror().isApprox(Vec3d(1., 1., 1.));

View File

@ -86,6 +86,8 @@
#define ENABLE_COORDINATE_DEPENDENT_SELECTION_BOX (1 && ENABLE_WORLD_COORDINATE)
// Enable showing the axes of the current reference system when sidebar hints are active
#define ENABLE_WORLD_COORDINATE_SHOW_AXES (1 && ENABLE_WORLD_COORDINATE)
// Enable alternate implementation of manipulating scale for instances and volumes
#define ENABLE_WORLD_COORDINATE_SCALE_REVISITED (1 && ENABLE_WORLD_COORDINATE)
#endif // _prusaslicer_technologies_h_

View File

@ -627,10 +627,17 @@ void ObjectManipulation::update_settings_value(const Selection& selection)
if (m_world_coordinates) {
#endif // ENABLE_WORLD_COORDINATE
m_new_rotate_label_string = L("Rotate");
#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED
m_new_scale_label_string = L("Scale");
#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED
m_new_rotation = Vec3d::Zero();
m_new_size = selection.get_scaled_instance_bounding_box().size();
m_new_scale = m_new_size.cwiseProduct(selection.get_unscaled_instance_bounding_box().size().cwiseInverse()) * 100.0;
}
#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED
m_new_scale = Vec3d(100.0, 100.0, 100.0);
#else
m_new_scale = m_new_size.cwiseProduct(selection.get_unscaled_instance_bounding_box().size().cwiseInverse()) * 100.0;
#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED
}
else {
#if ENABLE_WORLD_COORDINATE
m_new_move_label_string = L("Translate");
@ -672,9 +679,16 @@ void ObjectManipulation::update_settings_value(const Selection& selection)
m_new_position = offset;
m_new_rotate_label_string = L("Rotate");
#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED
m_new_scale_label_string = L("Scale");
#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED
m_new_rotation = Vec3d::Zero();
m_new_size = volume->transformed_convex_hull_bounding_box(trafo.get_matrix()).size();
#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED
m_new_scale = Vec3d(100.0, 100.0, 100.0);
#else
m_new_scale = m_new_size.cwiseProduct(volume->transformed_convex_hull_bounding_box(volume->get_instance_transformation().get_matrix() * volume->get_volume_transformation().get_matrix(false, false, true, false)).size().cwiseInverse()) * 100.0;
#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED
}
else if (is_local_coordinates()) {
m_new_move_label_string = L("Translate");
@ -687,10 +701,17 @@ void ObjectManipulation::update_settings_value(const Selection& selection)
#endif // ENABLE_WORLD_COORDINATE
m_new_position = volume->get_volume_offset();
m_new_rotate_label_string = L("Rotate");
#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED
m_new_scale_label_string = L("Scale");
#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED
m_new_rotation = Vec3d::Zero();
#if ENABLE_WORLD_COORDINATE
m_new_size = volume->transformed_convex_hull_bounding_box(volume->get_volume_transformation().get_matrix()).size();
#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED
m_new_scale = Vec3d(100.0, 100.0, 100.0);
#else
m_new_scale = m_new_size.cwiseProduct(volume->transformed_convex_hull_bounding_box(volume->get_volume_transformation().get_matrix(false, false, true, false)).size().cwiseInverse()) * 100.0;
#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED
}
#else
m_new_scale = volume->get_volume_scaling_factor() * 100.0;
@ -767,20 +788,26 @@ void ObjectManipulation::update_if_dirty()
#else
if (selection.requires_uniform_scale()) {
#endif // ENABLE_WORLD_COORDINATE
#if !ENABLE_WORLD_COORDINATE_SCALE_REVISITED
m_lock_bnt->SetLock(true);
#endif // !ENABLE_WORLD_COORDINATE_SCALE_REVISITED
#if ENABLE_WORLD_COORDINATE
wxString tooltip;
if (selection.is_single_volume_or_modifier()) {
#if !ENABLE_WORLD_COORDINATE_SCALE_REVISITED
if (reason == Selection::EUniformScaleRequiredReason::VolumeNotAxisAligned_Instance)
tooltip = _L("You cannot use non-uniform scaling mode for parts non aligned with the instance local axes");
else if (reason == Selection::EUniformScaleRequiredReason::VolumeNotAxisAligned_World)
tooltip = _L("You cannot use non-uniform scaling mode for parts non aligned with the printer axes");
#endif // !ENABLE_WORLD_COORDINATE_SCALE_REVISITED
}
else if (selection.is_single_full_instance()) {
#if !ENABLE_WORLD_COORDINATE_SCALE_REVISITED
if (reason == Selection::EUniformScaleRequiredReason::InstanceNotAxisAligned_World)
tooltip = _L("You cannot use non-uniform scaling mode for instances non aligned with the printer axes");
else if (reason == Selection::EUniformScaleRequiredReason::VolumeNotAxisAligned_Instance)
tooltip = _L("You cannot use non-uniform scaling mode for instances containing non locally axis-aligned parts");
#endif // !ENABLE_WORLD_COORDINATE_SCALE_REVISITED
}
else
tooltip = _L("You cannot use non-uniform scaling mode for multiple objects/parts selection");
@ -789,7 +816,9 @@ void ObjectManipulation::update_if_dirty()
#else
m_lock_bnt->SetToolTip(_L("You cannot use non-uniform scaling mode for multiple objects/parts selection"));
#endif // ENABLE_WORLD_COORDINATE
#if !ENABLE_WORLD_COORDINATE_SCALE_REVISITED
m_lock_bnt->disable();
#endif // !ENABLE_WORLD_COORDINATE_SCALE_REVISITED
}
else {
m_lock_bnt->SetLock(m_uniform_scale);
@ -1110,7 +1139,11 @@ void ObjectManipulation::change_size_value(int axis, double value)
selection.get_unscaled_instance_bounding_box().size() :
wxGetApp().model().objects[selection.get_volume(*selection.get_volume_idxs().begin())->object_idx()]->raw_mesh_bounding_box().size();
#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED
this->do_size(axis, size.cwiseQuotient(ref_size));
#else
this->do_scale(axis, size.cwiseQuotient(ref_size));
#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED
m_cache.size = size;
m_cache.size_rounded(axis) = DBL_MAX;
@ -1126,8 +1159,18 @@ void ObjectManipulation::do_scale(int axis, const Vec3d &scale) const
#if ENABLE_WORLD_COORDINATE
TransformationType transformation_type;
#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED
if (is_local_coordinates())
transformation_type.set_local();
else if (is_instance_coordinates())
transformation_type.set_instance();
if (!is_local_coordinates())
transformation_type.set_relative();
#else
if (!is_world_coordinates())
transformation_type.set_local();
#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED
bool uniform_scale = m_uniform_scale || selection.requires_uniform_scale();
Vec3d scaling_factor = uniform_scale ? scale(axis) * Vec3d::Ones() : scale;
@ -1159,6 +1202,37 @@ void ObjectManipulation::do_scale(int axis, const Vec3d &scale) const
wxGetApp().plater()->canvas3D()->do_scale(L("Set Scale"));
}
#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED
void ObjectManipulation::do_size(int axis, const Vec3d& scale) const
{
Selection& selection = wxGetApp().plater()->canvas3D()->get_selection();
TransformationType transformation_type;
if (is_local_coordinates())
transformation_type.set_local();
else if (is_instance_coordinates())
transformation_type.set_instance();
bool uniform_scale = m_uniform_scale || selection.requires_uniform_scale();
Vec3d scaling_factor = uniform_scale ? scale(axis) * Vec3d::Ones() : scale;
if (!uniform_scale && is_world_coordinates()) {
if (selection.is_single_full_instance())
scaling_factor = (Geometry::assemble_transform(Vec3d::Zero(), selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_rotation()).inverse() * scaling_factor).cwiseAbs();
else if (selection.is_single_volume_or_modifier()) {
const Transform3d mi = Geometry::assemble_transform(Vec3d::Zero(), selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_rotation()).inverse();
const Transform3d mv = Geometry::assemble_transform(Vec3d::Zero(), selection.get_volume(*selection.get_volume_idxs().begin())->get_volume_rotation()).inverse();
scaling_factor = (mv * mi * scaling_factor).cwiseAbs();
}
}
selection.start_dragging();
selection.scale(scaling_factor, transformation_type);
selection.stop_dragging();
wxGetApp().plater()->canvas3D()->do_scale(L("Set Size"));
}
#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED
void ObjectManipulation::on_change(const std::string& opt_key, int axis, double new_value)
{
if (!m_cache.is_valid())
@ -1193,21 +1267,37 @@ void ObjectManipulation::on_change(const std::string& opt_key, int axis, double
}
}
void ObjectManipulation::set_uniform_scaling(const bool new_value)
void ObjectManipulation::set_uniform_scaling(const bool use_uniform_scale)
{
const Selection &selection = wxGetApp().plater()->canvas3D()->get_selection();
#if ENABLE_WORLD_COORDINATE
if (selection.is_single_full_instance() && is_world_coordinates() && !new_value) {
#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED
if (!use_uniform_scale) {
int res = selection.bake_transform_if_needed(false);
if (res == -1) {
// Enforce uniform scaling.
m_lock_bnt->SetLock(true);
return;
}
else if (res == 0) {
// Recalculate cached values at this panel, refresh the screen.
this->UpdateAndShow(true);
}
}
m_uniform_scale = use_uniform_scale;
#else
if (selection.is_single_full_instance() && m_world_coordinates && !new_value) {
#if ENABLE_WORLD_COORDINATE
if (selection.is_single_full_instance() && is_world_coordinates() && !use_uniform_scale) {
#else
if (selection.is_single_full_instance() && m_world_coordinates && !use_uniform_scale) {
#endif // ENABLE_WORLD_COORDINATE
// Verify whether the instance rotation is multiples of 90 degrees, so that the scaling in world coordinates is possible.
// all volumes in the selection belongs to the same instance, any of them contains the needed instance data, so we take the first one
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
// Is the angle close to a multiple of 90 degrees?
if (! Geometry::is_rotation_ninety_degrees(volume->get_instance_rotation())) {
if (!Geometry::is_rotation_ninety_degrees(volume->get_instance_rotation())) {
// Cannot apply scaling in the world coordinate system.
//wxMessageDialog dlg(GUI::wxGetApp().mainframe,
//wxMessageDialog dlg(GUI::wxGetApp().mainframe,
MessageDialog dlg(GUI::wxGetApp().mainframe,
_L("The currently manipulated object is tilted (rotation angles are not multiples of 90°).\n"
"Non-uniform scaling of tilted objects is only possible in the World coordinate system,\n"
@ -1215,7 +1305,7 @@ void ObjectManipulation::set_uniform_scaling(const bool new_value)
_L("This operation is irreversible.\n"
"Do you want to proceed?"),
SLIC3R_APP_NAME,
wxYES_NO | wxCANCEL | wxCANCEL_DEFAULT | wxICON_QUESTION);
wxYES_NO | wxCANCEL | wxCANCEL_DEFAULT | wxICON_QUESTION);
if (dlg.ShowModal() != wxID_YES) {
// Enforce uniform scaling.
m_lock_bnt->SetLock(true);
@ -1229,7 +1319,9 @@ void ObjectManipulation::set_uniform_scaling(const bool new_value)
this->UpdateAndShow(true);
}
}
m_uniform_scale = new_value;
m_uniform_scale = use_uniform_scale;
#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED
}
#if ENABLE_WORLD_COORDINATE

View File

@ -196,7 +196,7 @@ public:
// Called from the App to update the UI if dirty.
void update_if_dirty();
void set_uniform_scaling(const bool uniform_scale);
void set_uniform_scaling(const bool use_uniform_scale);
bool get_uniform_scaling() const { return m_uniform_scale; }
#if ENABLE_WORLD_COORDINATE
void set_coordinates_type(ECoordinatesType type);
@ -256,6 +256,9 @@ private:
void change_scale_value(int axis, double value);
void change_size_value(int axis, double value);
void do_scale(int axis, const Vec3d &scale) const;
#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED
void do_size(int axis, const Vec3d& scale) const;
#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED
#if ENABLE_WORLD_COORDINATE
void set_coordinates_type(const wxString& type_string);

View File

@ -62,6 +62,10 @@ public:
const Vec3d& get_scale() const { return m_scale; }
void set_scale(const Vec3d& scale) { m_starting.scale = scale; m_scale = scale; }
#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED
const Vec3d& get_starting_scale() const { return m_starting.scale; }
#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED
const Vec3d& get_offset() const { return m_offset; }
std::string get_tooltip() const override;

View File

@ -242,13 +242,17 @@ void GLGizmosManager::update_data()
enable_grabber(Rotate, 1, !is_wipe_tower);
#if ENABLE_WORLD_COORDINATE
#if !ENABLE_WORLD_COORDINATE_SCALE_REVISITED
bool enable_scale_xyz = !selection.requires_uniform_scale();
#endif // !ENABLE_WORLD_COORDINATE_SCALE_REVISITED
#else
bool enable_scale_xyz = selection.is_single_full_instance() || selection.is_single_volume() || selection.is_single_modifier();
#endif // ENABLE_WORLD_COORDINATE
#if !ENABLE_WORLD_COORDINATE_SCALE_REVISITED
for (unsigned int i = 0; i < 6; ++i) {
enable_grabber(Scale, i, enable_scale_xyz);
}
#endif // !ENABLE_WORLD_COORDINATE_SCALE_REVISITED
if (m_common_gizmos_data)
m_common_gizmos_data->update(get_current()
@ -370,6 +374,16 @@ void GLGizmosManager::set_scale(const Vec3d& scale)
dynamic_cast<GLGizmoScale3D*>(m_gizmos[Scale].get())->set_scale(scale);
}
#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED
Vec3d GLGizmosManager::get_starting_scale() const
{
if (!m_enabled)
return Vec3d::Ones();
return dynamic_cast<GLGizmoScale3D*>(m_gizmos[Scale].get())->get_starting_scale();
}
#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED
Vec3d GLGizmosManager::get_scale_offset() const
{
if (!m_enabled || m_gizmos.empty())
@ -553,7 +567,8 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt)
m_tooltip = update_hover_state(mouse_pos);
if (m_current == MmuSegmentation || m_current == FdmSupports)
gizmo_event(SLAGizmoEventType::Moving, mouse_pos, evt.ShiftDown(), evt.AltDown());
} else if (evt.LeftUp()) {
}
else if (evt.LeftUp()) {
if (m_mouse_capture.left) {
processed = true;
m_mouse_capture.left = false;
@ -561,7 +576,30 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt)
else if (is_dragging()) {
switch (m_current) {
case Move: { m_parent.do_move(L("Gizmo-Move")); break; }
#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED
case Scale: {
const Vec3d scale = get_scale();
const Vec3d starting_scale = get_starting_scale();
wxGetApp().CallAfter([this, &selection, scale, starting_scale]() {
int res = 1;
if (scale.x() != scale.y() || scale.x() != scale.z())
res = selection.bake_transform_if_needed(L("Gizmo-Scale"));
if (res == 1)
m_parent.do_scale(L("Gizmo-Scale"));
else if (res == -1) {
TransformationType transformation_type;
if (!wxGetApp().obj_manipul()->is_world_coordinates())
transformation_type.set_local();
selection.scale(starting_scale, transformation_type);
}
}
);
break;
}
#else
case Scale: { m_parent.do_scale(L("Gizmo-Scale")); break; }
#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED
case Rotate: { m_parent.do_rotate(L("Gizmo-Rotate")); break; }
default: break;
}

View File

@ -209,7 +209,9 @@ public:
Vec3d get_scale() const;
void set_scale(const Vec3d& scale);
#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED
Vec3d get_starting_scale() const;
#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED
Vec3d get_scale_offset() const;
Vec3d get_rotation() const;

View File

@ -7,9 +7,14 @@
#include "GUI.hpp"
#include "GUI_ObjectManipulation.hpp"
#include "GUI_ObjectList.hpp"
#include "Gizmos/GLGizmoBase.hpp"
#include "Camera.hpp"
#include "Plater.hpp"
#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED
#include "MsgDialog.hpp"
#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED
#include "Gizmos/GLGizmoBase.hpp"
#include "slic3r/Utils/UndoRedo.hpp"
#include "libslic3r/LocalesUtils.hpp"
@ -605,6 +610,9 @@ bool Selection::requires_uniform_scale() const
#endif // ENABLE_WORLD_COORDINATE
{
#if ENABLE_WORLD_COORDINATE
if (is_empty())
return false;
ECoordinatesType coord_type = wxGetApp().obj_manipul()->get_coordinates_type();
if (is_single_volume_or_modifier()) {
if (coord_type == ECoordinatesType::World) {
@ -639,7 +647,6 @@ bool Selection::requires_uniform_scale() const
}
}
}
return false;
}
else {
for (unsigned int i : m_list) {
@ -649,8 +656,8 @@ bool Selection::requires_uniform_scale() const
return true;
}
}
return false;
}
return false;
}
if (reason != nullptr)
@ -1301,6 +1308,65 @@ void Selection::translate(unsigned int object_idx, unsigned int instance_idx, co
this->set_bounding_boxes_dirty();
}
#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED
int Selection::bake_transform_if_needed(bool apply_scale) const
{
if ((is_single_full_instance() && wxGetApp().obj_manipul()->is_world_coordinates()) ||
(is_single_volume_or_modifier() && !wxGetApp().obj_manipul()->is_local_coordinates())) {
// Verify whether the instance rotation is multiples of 90 degrees, so that the scaling in world coordinates is possible.
// all volumes in the selection belongs to the same instance, any of them contains the needed instance data, so we take the first one
const GLVolume& volume = *get_volume(*get_volume_idxs().begin());
bool needs_baking = false;
if (is_single_full_instance()) {
// Is the instance angle close to a multiple of 90 degrees?
needs_baking |= !Geometry::is_rotation_ninety_degrees(volume.get_instance_rotation());
// Are all volumes angles close to a multiple of 90 degrees?
for (unsigned int id : get_volume_idxs()) {
if (needs_baking)
break;
needs_baking |= !Geometry::is_rotation_ninety_degrees(get_volume(id)->get_volume_rotation());
}
}
else if (is_single_volume_or_modifier()) {
// is the volume angle close to a multiple of 90 degrees?
needs_baking |= !Geometry::is_rotation_ninety_degrees(volume.get_volume_rotation());
if (wxGetApp().obj_manipul()->is_world_coordinates())
// Is the instance angle close to a multiple of 90 degrees?
needs_baking |= !Geometry::is_rotation_ninety_degrees(volume.get_instance_rotation());
}
if (needs_baking) {
MessageDialog dlg((wxWindow*)wxGetApp().mainframe,
_L("The currently manipulated object is tilted or contains tilted parts (rotation angles are not multiples of 90°). "
"Non-uniform scaling of tilted objects is only possible in non-local coordinate systems, "
"once the rotation is embedded into the object coordinates.") + "\n" +
_L("This operation is irreversible.") + "\n" +
_L("Do you want to proceed?"),
SLIC3R_APP_NAME,
wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION);
if (dlg.ShowModal() != wxID_YES)
return -1;
if (apply_scale) {
wxGetApp().plater()->get_current_canvas3D()->do_scale(L("Scale + Bake transform"));
Plater::SuppressSnapshots suppress(wxGetApp().plater());
wxGetApp().plater()->take_snapshot(_("Bake transform"));
}
else
wxGetApp().plater()->take_snapshot(_("Bake transform"));
// Bake the rotation into the meshes of the object.
wxGetApp().model().objects[volume.composite_id.object_id]->bake_xy_rotation_into_meshes(volume.composite_id.instance_id);
// Update the 3D scene, selections etc.
wxGetApp().plater()->update();
return 0;
}
}
return 1;
}
#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED
void Selection::erase()
{
if (!m_valid)

View File

@ -369,6 +369,15 @@ public:
void translate(unsigned int object_idx, const Vec3d& displacement);
void translate(unsigned int object_idx, unsigned int instance_idx, const Vec3d& displacement);
#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED
// returns:
// -1 if the user refused to proceed with baking when asked
// 0 if the baking was performed
// 1 if no baking was needed
// if apply_scale == true the scaling of the current selection is applied
int bake_transform_if_needed(bool apply_scale) const;
#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED
void erase();
void render(float scale_factor = 1.0);

View File

@ -581,8 +581,12 @@ void LockButton::OnButton(wxCommandEvent& event)
if (m_disabled)
return;
#if ENABLE_WORLD_COORDINATE_SCALE_REVISITED
SetLock(!m_is_pushed);
#else
m_is_pushed = !m_is_pushed;
update_button_bitmaps();
#endif // ENABLE_WORLD_COORDINATE_SCALE_REVISITED
event.Skip();
}