Rework of constrained scaling

This commit is contained in:
enricoturri1966 2023-03-07 14:32:18 +01:00
parent c28645b174
commit b32e936660
4 changed files with 87 additions and 118 deletions

View File

@ -21,7 +21,6 @@ const double GLGizmoScale3D::Offset = 5.0;
GLGizmoScale3D::GLGizmoScale3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) GLGizmoScale3D::GLGizmoScale3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
: GLGizmoBase(parent, icon_filename, sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id)
, m_scale(Vec3d::Ones()) , m_scale(Vec3d::Ones())
, m_offset(Vec3d::Zero())
, m_snap_step(0.05) , m_snap_step(0.05)
, m_base_color(DEFAULT_BASE_COLOR) , m_base_color(DEFAULT_BASE_COLOR)
, m_drag_color(DEFAULT_DRAG_COLOR) , m_drag_color(DEFAULT_DRAG_COLOR)
@ -68,6 +67,12 @@ std::string GLGizmoScale3D::get_tooltip() const
return ""; return "";
} }
static int constraint_id(int grabber_id)
{
static const std::vector<int> id_map = { 1, 0, 3, 2, 5, 4, 8, 9, 6, 7 };
return (0 <= grabber_id && grabber_id < id_map.size()) ? id_map[grabber_id] : -1;
}
bool GLGizmoScale3D::on_mouse(const wxMouseEvent &mouse_event) bool GLGizmoScale3D::on_mouse(const wxMouseEvent &mouse_event)
{ {
if (mouse_event.Dragging()) { if (mouse_event.Dragging()) {
@ -89,7 +94,18 @@ bool GLGizmoScale3D::on_mouse(const wxMouseEvent &mouse_event)
transformation_type.set_independent(); transformation_type.set_independent();
#if ENABLE_WORLD_COORDINATE #if ENABLE_WORLD_COORDINATE
m_parent.get_selection().scale_and_translate(m_scale, m_offset, transformation_type); Selection& selection = m_parent.get_selection();
selection.scale(m_scale, transformation_type);
if (m_starting.ctrl_down) {
// constrained scale:
// uses the performed scale to calculate the new position of the constrained grabber
// and from that calculates the offset (in world coordinates) to be applied to fullfill the constraint
update_render_data();
const Vec3d constraint_position = m_grabbers_transform * m_grabbers[constraint_id(m_hover_id)].center;
// re-apply the scale because the selection always applies the transformations with respect to the initial state
// set into on_start_dragging() with the call to selection.setup_cache()
m_parent.get_selection().scale_and_translate(m_scale, m_starting.constraint_position - constraint_position, transformation_type);
}
#else #else
Selection& selection = m_parent.get_selection(); Selection& selection = m_parent.get_selection();
selection.scale(m_scale, transformation_type); selection.scale(m_scale, transformation_type);
@ -176,6 +192,7 @@ void GLGizmoScale3D::on_start_dragging()
m_starting.box = m_bounding_box; m_starting.box = m_bounding_box;
m_starting.center = m_center; m_starting.center = m_center;
m_starting.instance_center = m_instance_center; m_starting.instance_center = m_instance_center;
m_starting.constraint_position = m_grabbers_transform * m_grabbers[constraint_id(m_hover_id)].center;
#else #else
m_starting.drag_position = m_grabbers[m_hover_id].center; m_starting.drag_position = m_grabbers[m_hover_id].center;
m_starting.box = (m_starting.ctrl_down && m_hover_id < 6) ? m_bounding_box : m_parent.get_selection().get_bounding_box(); m_starting.box = (m_starting.ctrl_down && m_hover_id < 6) ? m_bounding_box : m_parent.get_selection().get_bounding_box();
@ -190,8 +207,10 @@ void GLGizmoScale3D::on_start_dragging()
#endif // ENABLE_WORLD_COORDINATE #endif // ENABLE_WORLD_COORDINATE
} }
void GLGizmoScale3D::on_stop_dragging() { void GLGizmoScale3D::on_stop_dragging()
{
m_parent.do_scale(L("Gizmo-Scale")); m_parent.do_scale(L("Gizmo-Scale"));
m_starting.ctrl_down = false;
} }
void GLGizmoScale3D::on_dragging(const UpdateData& data) void GLGizmoScale3D::on_dragging(const UpdateData& data)
@ -214,52 +233,13 @@ void GLGizmoScale3D::on_render()
glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); glsafe(::glClear(GL_DEPTH_BUFFER_BIT));
glsafe(::glEnable(GL_DEPTH_TEST)); glsafe(::glEnable(GL_DEPTH_TEST));
const auto& [box, box_trafo] = selection.get_bounding_box_in_current_reference_system(); update_render_data();
m_bounding_box = box;
m_center = box_trafo.translation();
m_grabbers_transform = box_trafo;
m_instance_center = (selection.is_single_full_instance() || selection.is_single_volume_or_modifier()) ? selection.get_first_volume()->get_instance_offset() : m_center;
// x axis
const Vec3d box_half_size = 0.5 * m_bounding_box.size();
bool use_constrain = wxGetKeyState(WXK_CONTROL) && (selection.is_single_full_instance() || selection.is_single_volume_or_modifier());
m_grabbers[0].center = { -(box_half_size.x() + Offset), 0.0, 0.0 };
m_grabbers[0].color = (use_constrain && m_hover_id == 1) ? CONSTRAINED_COLOR : AXES_COLOR[0];
m_grabbers[1].center = { box_half_size.x() + Offset, 0.0, 0.0 };
m_grabbers[1].color = (use_constrain && m_hover_id == 0) ? CONSTRAINED_COLOR : AXES_COLOR[0];
// y axis
m_grabbers[2].center = { 0.0, -(box_half_size.y() + Offset), 0.0 };
m_grabbers[2].color = (use_constrain && m_hover_id == 3) ? CONSTRAINED_COLOR : AXES_COLOR[1];
m_grabbers[3].center = { 0.0, box_half_size.y() + Offset, 0.0 };
m_grabbers[3].color = (use_constrain && m_hover_id == 2) ? CONSTRAINED_COLOR : AXES_COLOR[1];
// z axis
m_grabbers[4].center = { 0.0, 0.0, -(box_half_size.z() + Offset) };
m_grabbers[4].color = (use_constrain && m_hover_id == 5) ? CONSTRAINED_COLOR : AXES_COLOR[2];
m_grabbers[5].center = { 0.0, 0.0, box_half_size.z() + Offset };
m_grabbers[5].color = (use_constrain && m_hover_id == 4) ? CONSTRAINED_COLOR : AXES_COLOR[2];
// uniform
m_grabbers[6].center = { -(box_half_size.x() + Offset), -(box_half_size.y() + Offset), 0.0 };
m_grabbers[6].color = (use_constrain && m_hover_id == 8) ? CONSTRAINED_COLOR : m_highlight_color;
m_grabbers[7].center = { box_half_size.x() + Offset, -(box_half_size.y() + Offset), 0.0 };
m_grabbers[7].color = (use_constrain && m_hover_id == 9) ? CONSTRAINED_COLOR : m_highlight_color;
m_grabbers[8].center = { box_half_size.x() + Offset, box_half_size.y() + Offset, 0.0 };
m_grabbers[8].color = (use_constrain && m_hover_id == 6) ? CONSTRAINED_COLOR : m_highlight_color;
m_grabbers[9].center = { -(box_half_size.x() + Offset), box_half_size.y() + Offset, 0.0 };
m_grabbers[9].color = (use_constrain && m_hover_id == 7) ? CONSTRAINED_COLOR : m_highlight_color;
#if ENABLE_GL_CORE_PROFILE #if ENABLE_GL_CORE_PROFILE
if (!OpenGLManager::get_gl_info().is_core_profile()) if (!OpenGLManager::get_gl_info().is_core_profile())
#endif // ENABLE_GL_CORE_PROFILE #endif // ENABLE_GL_CORE_PROFILE
glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f)); glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f));
for (int i = 0; i < 10; ++i) {
m_grabbers[i].matrix = m_grabbers_transform;
}
const float grabber_mean_size = (float)((m_bounding_box.size().x() + m_bounding_box.size().y() + m_bounding_box.size().z()) / 3.0); const float grabber_mean_size = (float)((m_bounding_box.size().x() + m_bounding_box.size().y() + m_bounding_box.size().z()) / 3.0);
if (m_hover_id == -1) { if (m_hover_id == -1) {
@ -743,38 +723,8 @@ void GLGizmoScale3D::do_scale_along_axis(Axis axis, const UpdateData& data)
double ratio = calc_ratio(data); double ratio = calc_ratio(data);
if (ratio > 0.0) { if (ratio > 0.0) {
Vec3d curr_scale = m_scale; Vec3d curr_scale = m_scale;
const Vec3d starting_scale = m_starting.scale; curr_scale(axis) = m_starting.scale(axis) * ratio;
const Selection& selection = m_parent.get_selection();
const ECoordinatesType coordinates_type = wxGetApp().obj_manipul()->get_coordinates_type();
curr_scale(axis) = starting_scale(axis) * ratio;
m_scale = curr_scale; m_scale = curr_scale;
if (m_starting.ctrl_down && (selection.is_single_full_instance() || selection.is_single_volume_or_modifier())) {
double local_offset = 0.5 * (ratio - 1.0) * m_starting.box.size()(axis);
if (m_hover_id == 2 * axis)
local_offset *= -1.0;
switch (axis)
{
case X: { m_offset = local_offset * Vec3d::UnitX(); break; }
case Y: { m_offset = local_offset * Vec3d::UnitY(); break; }
case Z: { m_offset = local_offset * Vec3d::UnitZ(); break; }
default: { m_offset = Vec3d::Zero(); break; }
}
if (selection.is_single_volume_or_modifier()) {
if (coordinates_type == ECoordinatesType::Instance)
m_offset = selection.get_first_volume()->get_instance_transformation().get_scaling_factor_matrix().inverse() * m_offset;
else if (coordinates_type == ECoordinatesType::Local) {
m_offset = selection.get_first_volume()->get_instance_transformation().get_scaling_factor_matrix().inverse() *
selection.get_first_volume()->get_volume_transformation().get_rotation_matrix() * m_offset;
}
}
}
else
m_offset = Vec3d::Zero();
} }
} }
#else #else
@ -811,31 +761,8 @@ void GLGizmoScale3D::do_scale_along_axis(Axis axis, const UpdateData& data)
void GLGizmoScale3D::do_scale_uniform(const UpdateData & data) void GLGizmoScale3D::do_scale_uniform(const UpdateData & data)
{ {
const double ratio = calc_ratio(data); const double ratio = calc_ratio(data);
if (ratio > 0.0) { if (ratio > 0.0)
m_scale = m_starting.scale * ratio; m_scale = m_starting.scale * ratio;
const Selection& selection = m_parent.get_selection();
const ECoordinatesType coordinates_type = wxGetApp().obj_manipul()->get_coordinates_type();
if (m_starting.ctrl_down && (selection.is_single_full_instance() || selection.is_single_volume_or_modifier())) {
m_offset = 0.5 * (ratio - 1.0) * m_starting.box.size();
if (m_hover_id == 6 || m_hover_id == 9)
m_offset.x() *= -1.0;
if (m_hover_id == 6 || m_hover_id == 7)
m_offset.y() *= -1.0;
if (selection.is_single_volume_or_modifier()) {
if (coordinates_type == ECoordinatesType::Instance)
m_offset = selection.get_first_volume()->get_instance_transformation().get_scaling_factor_matrix().inverse() * m_offset;
else if (coordinates_type == ECoordinatesType::Local) {
m_offset = selection.get_first_volume()->get_instance_transformation().get_scaling_factor_matrix().inverse() *
selection.get_first_volume()->get_volume_transformation().get_rotation_matrix() * m_offset;
}
}
}
else
m_offset = Vec3d::Zero();
}
} }
#else #else
void GLGizmoScale3D::do_scale_uniform(const UpdateData& data) void GLGizmoScale3D::do_scale_uniform(const UpdateData& data)
@ -883,5 +810,50 @@ double GLGizmoScale3D::calc_ratio(const UpdateData& data) const
return ratio; return ratio;
} }
void GLGizmoScale3D::update_render_data()
{
const Selection& selection = m_parent.get_selection();
const auto& [box, box_trafo] = selection.get_bounding_box_in_current_reference_system();
m_bounding_box = box;
m_center = box_trafo.translation();
m_grabbers_transform = box_trafo;
m_instance_center = (selection.is_single_full_instance() || selection.is_single_volume_or_modifier()) ? selection.get_first_volume()->get_instance_offset() : m_center;
const Vec3d box_half_size = 0.5 * m_bounding_box.size();
bool use_constrain = wxGetKeyState(WXK_CONTROL);
// x axis
m_grabbers[0].center = { -(box_half_size.x() + Offset), 0.0, 0.0 };
m_grabbers[0].color = (use_constrain && m_hover_id == 1) ? CONSTRAINED_COLOR : AXES_COLOR[0];
m_grabbers[1].center = { box_half_size.x() + Offset, 0.0, 0.0 };
m_grabbers[1].color = (use_constrain && m_hover_id == 0) ? CONSTRAINED_COLOR : AXES_COLOR[0];
// y axis
m_grabbers[2].center = { 0.0, -(box_half_size.y() + Offset), 0.0 };
m_grabbers[2].color = (use_constrain && m_hover_id == 3) ? CONSTRAINED_COLOR : AXES_COLOR[1];
m_grabbers[3].center = { 0.0, box_half_size.y() + Offset, 0.0 };
m_grabbers[3].color = (use_constrain && m_hover_id == 2) ? CONSTRAINED_COLOR : AXES_COLOR[1];
// z axis
m_grabbers[4].center = { 0.0, 0.0, -(box_half_size.z() + Offset) };
m_grabbers[4].color = (use_constrain && m_hover_id == 5) ? CONSTRAINED_COLOR : AXES_COLOR[2];
m_grabbers[5].center = { 0.0, 0.0, box_half_size.z() + Offset };
m_grabbers[5].color = (use_constrain && m_hover_id == 4) ? CONSTRAINED_COLOR : AXES_COLOR[2];
// uniform
m_grabbers[6].center = { -(box_half_size.x() + Offset), -(box_half_size.y() + Offset), 0.0 };
m_grabbers[6].color = (use_constrain && m_hover_id == 8) ? CONSTRAINED_COLOR : m_highlight_color;
m_grabbers[7].center = { box_half_size.x() + Offset, -(box_half_size.y() + Offset), 0.0 };
m_grabbers[7].color = (use_constrain && m_hover_id == 9) ? CONSTRAINED_COLOR : m_highlight_color;
m_grabbers[8].center = { box_half_size.x() + Offset, box_half_size.y() + Offset, 0.0 };
m_grabbers[8].color = (use_constrain && m_hover_id == 6) ? CONSTRAINED_COLOR : m_highlight_color;
m_grabbers[9].center = { -(box_half_size.x() + Offset), box_half_size.y() + Offset, 0.0 };
m_grabbers[9].color = (use_constrain && m_hover_id == 7) ? CONSTRAINED_COLOR : m_highlight_color;
for (int i = 0; i < 10; ++i) {
m_grabbers[i].matrix = m_grabbers_transform;
}
}
} // namespace GUI } // namespace GUI
} // namespace Slic3r } // namespace Slic3r

View File

@ -26,6 +26,7 @@ class GLGizmoScale3D : public GLGizmoBase
#if ENABLE_WORLD_COORDINATE #if ENABLE_WORLD_COORDINATE
Vec3d center{ Vec3d::Zero() }; Vec3d center{ Vec3d::Zero() };
Vec3d instance_center{ Vec3d::Zero() }; Vec3d instance_center{ Vec3d::Zero() };
Vec3d constraint_position{ Vec3d::Zero() };
#endif // ENABLE_WORLD_COORDINATE #endif // ENABLE_WORLD_COORDINATE
BoundingBoxf3 box; BoundingBoxf3 box;
#if !ENABLE_WORLD_COORDINATE #if !ENABLE_WORLD_COORDINATE
@ -44,7 +45,6 @@ class GLGizmoScale3D : public GLGizmoBase
Transform3d m_offsets_transform; Transform3d m_offsets_transform;
#endif // ENABLE_WORLD_COORDINATE #endif // ENABLE_WORLD_COORDINATE
Vec3d m_scale{ Vec3d::Ones() }; Vec3d m_scale{ Vec3d::Ones() };
Vec3d m_offset{ Vec3d::Zero() };
double m_snap_step{ 0.05 }; double m_snap_step{ 0.05 };
StartingData m_starting; StartingData m_starting;
@ -68,7 +68,7 @@ public:
const Vec3d& get_scale() const { return m_scale; } const Vec3d& get_scale() const { return m_scale; }
#if ENABLE_WORLD_COORDINATE #if ENABLE_WORLD_COORDINATE
void set_scale(const Vec3d& scale) { m_starting.scale = scale; m_scale = scale; m_offset = Vec3d::Zero(); } void set_scale(const Vec3d& scale) { m_starting.scale = scale; m_scale = scale; }
#else #else
void set_scale(const Vec3d& scale) { m_starting.scale = scale; m_scale = scale; } void set_scale(const Vec3d& scale) { m_starting.scale = scale; m_scale = scale; }
#endif // ENABLE_WORLD_COORDINATE #endif // ENABLE_WORLD_COORDINATE
@ -102,6 +102,7 @@ private:
void do_scale_uniform(const UpdateData& data); void do_scale_uniform(const UpdateData& data);
double calc_ratio(const UpdateData& data) const; double calc_ratio(const UpdateData& data) const;
void update_render_data();
}; };

View File

@ -1455,7 +1455,7 @@ void Selection::mirror(Axis axis)
#endif // ENABLE_WORLD_COORDINATE #endif // ENABLE_WORLD_COORDINATE
#if ENABLE_WORLD_COORDINATE #if ENABLE_WORLD_COORDINATE
void Selection::scale_and_translate(const Vec3d& scale, const Vec3d& translation, TransformationType transformation_type) void Selection::scale_and_translate(const Vec3d& scale, const Vec3d& world_translation, TransformationType transformation_type)
{ {
if (!m_valid) if (!m_valid)
return; return;
@ -1489,32 +1489,28 @@ void Selection::scale_and_translate(const Vec3d& scale, const Vec3d& translation
const Vec3d local_inst_pivot = inst_trafo.get_matrix_no_offset().inverse() * world_inst_pivot; const Vec3d local_inst_pivot = inst_trafo.get_matrix_no_offset().inverse() * world_inst_pivot;
Matrix3d inst_rotation, inst_scale; Matrix3d inst_rotation, inst_scale;
inst_trafo.get_matrix().computeRotationScaling(&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 offset_trafo = Geometry::translation_transform(inst_trafo.get_offset() + world_translation);
const Transform3d scale_trafo = Transform3d(inst_scale) * Geometry::scale_transform(relative_scale); 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)); v.set_instance_transformation(Geometry::translation_transform(world_inst_pivot) * offset_trafo * Transform3d(inst_rotation) * scale_trafo * Geometry::translation_transform(-local_inst_pivot));
} }
else else
transform_instance_relative(v, volume_data, transformation_type, Geometry::translation_transform(translation) * Geometry::scale_transform(relative_scale), m_cache.dragging_center); transform_instance_relative(v, volume_data, transformation_type, Geometry::translation_transform(world_translation) * Geometry::scale_transform(relative_scale), m_cache.dragging_center);
} }
else { else {
if (!is_single_volume_or_modifier()) { if (!is_single_volume_or_modifier()) {
assert(transformation_type.world()); assert(transformation_type.world());
transform_volume_relative(v, volume_data, transformation_type, Geometry::translation_transform(translation) * Geometry::scale_transform(scale), m_cache.dragging_center); transform_volume_relative(v, volume_data, transformation_type, Geometry::translation_transform(world_translation) * Geometry::scale_transform(scale), m_cache.dragging_center);
} }
else { else {
if (transformation_type.local() && transformation_type.absolute()) { transformation_type.set_independent();
const Geometry::Transformation& vol_trafo = volume_data.get_volume_transform(); Vec3d translation;
Matrix3d vol_rotation, vol_scale; if (transformation_type.local())
vol_trafo.get_matrix().computeRotationScaling(&vol_rotation, &vol_scale); translation = volume_data.get_volume_transform().get_matrix_no_offset().inverse() * inst_trafo.get_matrix_no_offset().inverse() * world_translation;
const Transform3d offset_trafo = Geometry::translation_transform(vol_trafo.get_offset() + vol_rotation * translation); else if (transformation_type.instance())
const Transform3d scale_trafo = Transform3d(vol_scale) * Geometry::scale_transform(scale); translation = inst_trafo.get_matrix_no_offset().inverse() * world_translation;
v.set_volume_transformation(offset_trafo * Transform3d(vol_rotation) * scale_trafo); else
} translation = world_translation;
else { transform_volume_relative(v, volume_data, transformation_type, Geometry::translation_transform(translation) * Geometry::scale_transform(scale), m_cache.dragging_center);
transformation_type.set_independent();
transformation_type.set_relative();
transform_volume_relative(v, volume_data, transformation_type, Geometry::translation_transform(translation) * Geometry::scale_transform(scale), m_cache.dragging_center);
}
} }
} }
} }

View File

@ -411,7 +411,7 @@ public:
void scale(const Vec3d& scale, TransformationType transformation_type); void scale(const Vec3d& scale, TransformationType transformation_type);
void scale_to_fit_print_volume(const BuildVolume& volume); void scale_to_fit_print_volume(const BuildVolume& volume);
#if ENABLE_WORLD_COORDINATE #if ENABLE_WORLD_COORDINATE
void scale_and_translate(const Vec3d& scale, const Vec3d& translation, TransformationType transformation_type); void scale_and_translate(const Vec3d& scale, const Vec3d& world_translation, TransformationType transformation_type);
void mirror(Axis axis, TransformationType transformation_type); void mirror(Axis axis, TransformationType transformation_type);
void reset_skew(); void reset_skew();
#else #else