mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-15 02:37:51 -06:00
Fix constrainted scale (scale with ctrl key pressed) (#3717)
Fix constrainted scale (scale with ctrl key pressed) (#3699)
This commit is contained in:
parent
7eb45a0c73
commit
b2708fb1f4
2 changed files with 109 additions and 123 deletions
|
@ -74,10 +74,10 @@ std::string GLGizmoScale3D::get_tooltip() const
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLGizmoScale3D::enable_ununiversal_scale(bool enable)
|
static int constraint_id(int grabber_id)
|
||||||
{
|
{
|
||||||
for (unsigned int i = 0; i < 6; ++i)
|
static const std::vector<int> id_map = { 1, 0, 3, 2, 5, 4, 8, 9, 6, 7 };
|
||||||
m_grabbers[i].enabled = enable;
|
return (0 <= grabber_id && grabber_id < (int)id_map.size()) ? id_map[grabber_id] : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GLGizmoScale3D::on_mouse(const wxMouseEvent &mouse_event)
|
bool GLGizmoScale3D::on_mouse(const wxMouseEvent &mouse_event)
|
||||||
|
@ -99,12 +99,27 @@ bool GLGizmoScale3D::on_mouse(const wxMouseEvent &mouse_event)
|
||||||
transformation_type.set_independent();
|
transformation_type.set_independent();
|
||||||
|
|
||||||
selection.scale(m_scale, transformation_type);
|
selection.scale(m_scale, transformation_type);
|
||||||
if (mouse_event.CmdDown()) selection.translate(m_offset, transformation_type);
|
if (m_starting.ctrl_down && m_hover_id < 6) {
|
||||||
|
// 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[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.pivots[m_hover_id] - constraint_position, transformation_type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return use_grabbers(mouse_event);
|
return use_grabbers(mouse_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GLGizmoScale3D::enable_ununiversal_scale(bool enable)
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < 6; ++i)
|
||||||
|
m_grabbers[i].enabled = enable;
|
||||||
|
}
|
||||||
|
|
||||||
void GLGizmoScale3D::data_changed(bool is_serializing) {
|
void GLGizmoScale3D::data_changed(bool is_serializing) {
|
||||||
const Selection &selection = m_parent.get_selection();
|
const Selection &selection = m_parent.get_selection();
|
||||||
bool enable_scale_xyz = selection.is_single_full_instance() ||
|
bool enable_scale_xyz = selection.is_single_full_instance() ||
|
||||||
|
@ -156,19 +171,20 @@ void GLGizmoScale3D::on_start_dragging()
|
||||||
m_starting.plane_center = m_grabbers[4].center;
|
m_starting.plane_center = m_grabbers[4].center;
|
||||||
m_starting.plane_nromal = m_grabbers[5].center - m_grabbers[4].center;
|
m_starting.plane_nromal = m_grabbers[5].center - m_grabbers[4].center;
|
||||||
m_starting.ctrl_down = wxGetKeyState(WXK_CONTROL);
|
m_starting.ctrl_down = wxGetKeyState(WXK_CONTROL);
|
||||||
m_starting.box = (m_starting.ctrl_down && (m_hover_id < 6)) ? m_box : m_parent.get_selection().get_bounding_box();
|
m_starting.box = m_box;
|
||||||
|
|
||||||
const Vec3d& center = m_starting.box.center();
|
m_starting.pivots[0] = m_grabbers[1].center;
|
||||||
m_starting.pivots[0] = m_transform * Vec3d(m_starting.box.max.x(), center.y(), center.z());
|
m_starting.pivots[1] = m_grabbers[0].center;
|
||||||
m_starting.pivots[1] = m_transform * Vec3d(m_starting.box.min.x(), center.y(), center.z());
|
m_starting.pivots[2] = m_grabbers[3].center;
|
||||||
m_starting.pivots[2] = m_transform * Vec3d(center.x(), m_starting.box.max.y(), center.z());
|
m_starting.pivots[3] = m_grabbers[2].center;
|
||||||
m_starting.pivots[3] = m_transform * Vec3d(center.x(), m_starting.box.min.y(), center.z());
|
m_starting.pivots[4] = m_grabbers[5].center;
|
||||||
m_starting.pivots[4] = m_transform * Vec3d(center.x(), center.y(), m_starting.box.max.z());
|
m_starting.pivots[5] = m_grabbers[4].center;
|
||||||
m_starting.pivots[5] = m_transform * Vec3d(center.x(), center.y(), m_starting.box.min.z());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
|
@ -185,97 +201,14 @@ void GLGizmoScale3D::on_dragging(const UpdateData& data)
|
||||||
|
|
||||||
void GLGizmoScale3D::on_render()
|
void GLGizmoScale3D::on_render()
|
||||||
{
|
{
|
||||||
const Selection& selection = m_parent.get_selection();
|
|
||||||
|
|
||||||
bool single_instance = selection.is_single_full_instance();
|
|
||||||
bool single_volume = selection.is_single_volume_or_modifier();
|
|
||||||
|
|
||||||
glsafe(::glClear(GL_DEPTH_BUFFER_BIT));
|
glsafe(::glClear(GL_DEPTH_BUFFER_BIT));
|
||||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||||
|
|
||||||
m_box.reset();
|
update_render_data();
|
||||||
m_transform = Transform3d::Identity();
|
|
||||||
// Transforms grabbers' offsets to world refefence system
|
|
||||||
Transform3d offsets_transform = Transform3d::Identity();
|
|
||||||
m_offsets_transform = Transform3d::Identity();
|
|
||||||
Vec3d angles = Vec3d::Zero();
|
|
||||||
|
|
||||||
if (single_instance) {
|
|
||||||
// calculate bounding box in instance local reference system
|
|
||||||
const Selection::IndicesList& idxs = selection.get_volume_idxs();
|
|
||||||
for (unsigned int idx : idxs) {
|
|
||||||
const GLVolume* vol = selection.get_volume(idx);
|
|
||||||
m_box.merge(vol->bounding_box().transformed(vol->get_volume_transformation().get_matrix()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// gets transform from first selected volume
|
|
||||||
const GLVolume* v = selection.get_first_volume();
|
|
||||||
m_transform = v->get_instance_transformation().get_matrix();
|
|
||||||
// gets angles from first selected volume
|
|
||||||
angles = v->get_instance_rotation();
|
|
||||||
// consider rotation+mirror only components of the transform for offsets
|
|
||||||
offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), angles, Vec3d::Ones(), v->get_instance_mirror());
|
|
||||||
m_offsets_transform = offsets_transform;
|
|
||||||
}
|
|
||||||
else if (single_volume) {
|
|
||||||
const GLVolume* v = selection.get_first_volume();
|
|
||||||
m_box = v->bounding_box();
|
|
||||||
m_transform = v->world_matrix();
|
|
||||||
angles = Geometry::extract_euler_angles(m_transform);
|
|
||||||
// consider rotation+mirror only components of the transform for offsets
|
|
||||||
offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), angles, Vec3d::Ones(), v->get_instance_mirror());
|
|
||||||
m_offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), v->get_volume_rotation(), Vec3d::Ones(), v->get_volume_mirror());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
m_box = selection.get_bounding_box();
|
|
||||||
|
|
||||||
const Vec3d& center = m_box.center();
|
|
||||||
const Vec3d offset_x = offsets_transform * Vec3d((double)Offset, 0.0, 0.0);
|
|
||||||
const Vec3d offset_y = offsets_transform * Vec3d(0.0, (double)Offset, 0.0);
|
|
||||||
const Vec3d offset_z = offsets_transform * Vec3d(0.0, 0.0, (double)Offset);
|
|
||||||
|
|
||||||
const bool ctrl_down = (m_dragging && m_starting.ctrl_down) || (!m_dragging && wxGetKeyState(WXK_CONTROL));
|
|
||||||
|
|
||||||
// x axis
|
|
||||||
m_grabbers[0].center = m_transform * Vec3d(m_box.min.x(), center.y(), m_box.min.z());
|
|
||||||
m_grabbers[1].center = m_transform * Vec3d(m_box.max.x(), center.y(), m_box.min.z());
|
|
||||||
|
|
||||||
// y axis
|
|
||||||
m_grabbers[2].center = m_transform * Vec3d(center.x(), m_box.min.y(), m_box.min.z());
|
|
||||||
m_grabbers[3].center = m_transform * Vec3d(center.x(), m_box.max.y(), m_box.min.z());
|
|
||||||
|
|
||||||
// z axis do not show 4
|
|
||||||
m_grabbers[4].center = m_transform * Vec3d(center.x(), center.y(), m_box.min.z());
|
|
||||||
m_grabbers[4].enabled = false;
|
|
||||||
|
|
||||||
m_grabbers[5].center = m_transform * Vec3d(center.x(), center.y(), m_box.max.z());
|
|
||||||
|
|
||||||
// uniform
|
|
||||||
m_grabbers[6].center = m_transform * Vec3d(m_box.min.x(), m_box.min.y(), m_box.min.z());
|
|
||||||
m_grabbers[7].center = m_transform * Vec3d(m_box.max.x(), m_box.min.y(), m_box.min.z());
|
|
||||||
m_grabbers[8].center = m_transform * Vec3d(m_box.max.x(), m_box.max.y(), m_box.min.z());
|
|
||||||
m_grabbers[9].center = m_transform * Vec3d(m_box.min.x(), m_box.max.y(), m_box.min.z());
|
|
||||||
|
|
||||||
for (int i = 0; i < 6; ++i) {
|
|
||||||
m_grabbers[i].color = AXES_COLOR[i/2];
|
|
||||||
m_grabbers[i].hover_color = AXES_HOVER_COLOR[i/2];
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 6; i < 10; ++i) {
|
|
||||||
m_grabbers[i].color = GRABBER_UNIFORM_COL;
|
|
||||||
m_grabbers[i].hover_color = GRABBER_UNIFORM_HOVER_COL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// sets grabbers orientation
|
|
||||||
for (int i = 0; i < 10; ++i) {
|
|
||||||
m_grabbers[i].angles = angles;
|
|
||||||
}
|
|
||||||
|
|
||||||
glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f));
|
glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f));
|
||||||
|
|
||||||
const BoundingBoxf3& selection_box = selection.get_bounding_box();
|
const float grabber_mean_size = (float) ((m_box.size().x() + m_box.size().y() + m_box.size().z()) / 3.0);
|
||||||
|
|
||||||
const float grabber_mean_size = (float)((selection_box.size().x() + selection_box.size().y() + selection_box.size().z()) / 3.0);
|
|
||||||
|
|
||||||
//draw connections
|
//draw connections
|
||||||
GLShaderProgram* shader = wxGetApp().get_shader("flat");
|
GLShaderProgram* shader = wxGetApp().get_shader("flat");
|
||||||
|
@ -370,35 +303,17 @@ 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) {
|
||||||
m_scale(axis) = m_starting.scale(axis) * ratio;
|
Vec3d curr_scale = m_scale;
|
||||||
if (m_starting.ctrl_down) {
|
curr_scale(axis) = m_starting.scale(axis) * ratio;
|
||||||
double local_offset = 0.5 * (m_scale(axis) - m_starting.scale(axis)) * m_starting.box.size()(axis);
|
m_scale = curr_scale;
|
||||||
if (m_hover_id == 2 * axis)
|
|
||||||
local_offset *= -1.0;
|
|
||||||
|
|
||||||
Vec3d local_offset_vec;
|
|
||||||
switch (axis)
|
|
||||||
{
|
|
||||||
case X: { local_offset_vec = local_offset * Vec3d::UnitX(); break; }
|
|
||||||
case Y: { local_offset_vec = local_offset * Vec3d::UnitY(); break; }
|
|
||||||
case Z: { local_offset_vec = local_offset * Vec3d::UnitZ(); break; }
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_offset = m_offsets_transform * local_offset_vec;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
m_offset = Vec3d::Zero();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
m_offset = Vec3d::Zero();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
double GLGizmoScale3D::calc_ratio(const UpdateData& data) const
|
double GLGizmoScale3D::calc_ratio(const UpdateData& data) const
|
||||||
|
@ -436,5 +351,78 @@ double GLGizmoScale3D::calc_ratio(const UpdateData& data) const
|
||||||
return ratio;
|
return ratio;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GLGizmoScale3D::update_render_data()
|
||||||
|
{
|
||||||
|
|
||||||
|
const Selection& selection = m_parent.get_selection();
|
||||||
|
|
||||||
|
bool single_instance = selection.is_single_full_instance();
|
||||||
|
bool single_volume = selection.is_single_volume_or_modifier();
|
||||||
|
|
||||||
|
m_box.reset();
|
||||||
|
m_transform = Transform3d::Identity();
|
||||||
|
Vec3d angles = Vec3d::Zero();
|
||||||
|
|
||||||
|
if (single_instance) {
|
||||||
|
// calculate bounding box in instance local reference system
|
||||||
|
const Selection::IndicesList& idxs = selection.get_volume_idxs();
|
||||||
|
for (unsigned int idx : idxs) {
|
||||||
|
const GLVolume* vol = selection.get_volume(idx);
|
||||||
|
m_box.merge(vol->bounding_box().transformed(vol->get_volume_transformation().get_matrix()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// gets transform from first selected volume
|
||||||
|
const GLVolume* v = selection.get_first_volume();
|
||||||
|
m_transform = v->get_instance_transformation().get_matrix();
|
||||||
|
// gets angles from first selected volume
|
||||||
|
angles = v->get_instance_rotation();
|
||||||
|
}
|
||||||
|
else if (single_volume) {
|
||||||
|
const GLVolume* v = selection.get_first_volume();
|
||||||
|
m_box = v->bounding_box();
|
||||||
|
m_transform = v->world_matrix();
|
||||||
|
angles = Geometry::extract_euler_angles(m_transform);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_box = selection.get_bounding_box();
|
||||||
|
|
||||||
|
const Vec3d& center = m_box.center();
|
||||||
|
|
||||||
|
// x axis
|
||||||
|
m_grabbers[0].center = m_transform * Vec3d(m_box.min.x(), center.y(), m_box.min.z());
|
||||||
|
m_grabbers[1].center = m_transform * Vec3d(m_box.max.x(), center.y(), m_box.min.z());
|
||||||
|
|
||||||
|
// y axis
|
||||||
|
m_grabbers[2].center = m_transform * Vec3d(center.x(), m_box.min.y(), m_box.min.z());
|
||||||
|
m_grabbers[3].center = m_transform * Vec3d(center.x(), m_box.max.y(), m_box.min.z());
|
||||||
|
|
||||||
|
// z axis do not show 4
|
||||||
|
m_grabbers[4].center = m_transform * Vec3d(center.x(), center.y(), m_box.min.z());
|
||||||
|
m_grabbers[4].enabled = false;
|
||||||
|
|
||||||
|
m_grabbers[5].center = m_transform * Vec3d(center.x(), center.y(), m_box.max.z());
|
||||||
|
|
||||||
|
// uniform
|
||||||
|
m_grabbers[6].center = m_transform * Vec3d(m_box.min.x(), m_box.min.y(), m_box.min.z());
|
||||||
|
m_grabbers[7].center = m_transform * Vec3d(m_box.max.x(), m_box.min.y(), m_box.min.z());
|
||||||
|
m_grabbers[8].center = m_transform * Vec3d(m_box.max.x(), m_box.max.y(), m_box.min.z());
|
||||||
|
m_grabbers[9].center = m_transform * Vec3d(m_box.min.x(), m_box.max.y(), m_box.min.z());
|
||||||
|
|
||||||
|
for (int i = 0; i < 6; ++i) {
|
||||||
|
m_grabbers[i].color = AXES_COLOR[i/2];
|
||||||
|
m_grabbers[i].hover_color = AXES_HOVER_COLOR[i/2];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 6; i < 10; ++i) {
|
||||||
|
m_grabbers[i].color = GRABBER_UNIFORM_COL;
|
||||||
|
m_grabbers[i].hover_color = GRABBER_UNIFORM_HOVER_COL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sets grabbers orientation
|
||||||
|
for (int i = 0; i < 10; ++i) {
|
||||||
|
m_grabbers[i].angles = angles;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace GUI
|
} // namespace GUI
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
|
|
@ -34,10 +34,7 @@ class GLGizmoScale3D : public GLGizmoBase
|
||||||
|
|
||||||
BoundingBoxf3 m_box;
|
BoundingBoxf3 m_box;
|
||||||
Transform3d m_transform;
|
Transform3d m_transform;
|
||||||
// Transforms grabbers offsets to the proper reference system (world for instances, instance for volumes)
|
|
||||||
Transform3d m_offsets_transform;
|
|
||||||
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;
|
||||||
|
|
||||||
|
@ -99,6 +96,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();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue