Enhanced behaviour of scale 3D gizmo
This commit is contained in:
parent
889d0f1434
commit
0924bedd28
@ -89,6 +89,10 @@ class Linef3
|
|||||||
explicit Linef3(Pointf3 _a, Pointf3 _b): a(_a), b(_b) {};
|
explicit Linef3(Pointf3 _a, Pointf3 _b): a(_a), b(_b) {};
|
||||||
Pointf3 intersect_plane(double z) const;
|
Pointf3 intersect_plane(double z) const;
|
||||||
void scale(double factor);
|
void scale(double factor);
|
||||||
|
|
||||||
|
double length() const { return this->a.distance_to(this->b); }
|
||||||
|
Vectorf3 vector() const { return Vectorf3(this->b.x - this->a.x, this->b.y - this->a.y, this->b.z - this->a.z); }
|
||||||
|
Vectorf3 unit_vector() const { return (length() == 0.0) ? Vectorf3(0.0, 0.0, 0.0) : normalize(vector()); }
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
@ -819,7 +819,10 @@ bool GLGizmoScale3D::on_init()
|
|||||||
void GLGizmoScale3D::on_start_dragging()
|
void GLGizmoScale3D::on_start_dragging()
|
||||||
{
|
{
|
||||||
if (m_hover_id != -1)
|
if (m_hover_id != -1)
|
||||||
|
{
|
||||||
m_starting_drag_position = m_grabbers[m_hover_id].center;
|
m_starting_drag_position = m_grabbers[m_hover_id].center;
|
||||||
|
m_starting_center = m_box.center();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLGizmoScale3D::on_update(const Linef3& mouse_ray)
|
void GLGizmoScale3D::on_update(const Linef3& mouse_ray)
|
||||||
@ -991,76 +994,131 @@ Linef3 transform(const Linef3& line, const Eigen::Transform<float, 3, Eigen::Aff
|
|||||||
|
|
||||||
void GLGizmoScale3D::do_scale_x(const Linef3& mouse_ray)
|
void GLGizmoScale3D::do_scale_x(const Linef3& mouse_ray)
|
||||||
{
|
{
|
||||||
// calculates the intersection of the mouse ray with the plane parallel to plane XY and passing through the box center
|
double ratio = calc_ratio(1, mouse_ray, m_starting_center);
|
||||||
const Pointf3& center = m_box.center();
|
|
||||||
Eigen::Transform<float, 3, Eigen::Affine> m = Eigen::Transform<float, 3, Eigen::Affine>::Identity();
|
|
||||||
m.translate(Eigen::Vector3f(-(float)center.x, -(float)center.y, -(float)center.z));
|
|
||||||
|
|
||||||
Pointf mouse_pos = transform(mouse_ray, m).intersect_plane(0.0);
|
if (ratio > 0.0)
|
||||||
|
m_scale_x = m_starting_scale_x * (float)ratio;
|
||||||
coordf_t orig_len = length(m_starting_drag_position - center);
|
|
||||||
coordf_t new_len = length(mouse_pos);
|
|
||||||
coordf_t ratio = (orig_len != 0.0) ? new_len / orig_len : 1.0;
|
|
||||||
|
|
||||||
m_scale_x = m_starting_scale_x * (float)ratio;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLGizmoScale3D::do_scale_y(const Linef3& mouse_ray)
|
void GLGizmoScale3D::do_scale_y(const Linef3& mouse_ray)
|
||||||
{
|
{
|
||||||
// calculates the intersection of the mouse ray with the plane parallel to plane XY and passing through the box center
|
double ratio = calc_ratio(2, mouse_ray, m_starting_center);
|
||||||
const Pointf3& center = m_box.center();
|
|
||||||
Eigen::Transform<float, 3, Eigen::Affine> m = Eigen::Transform<float, 3, Eigen::Affine>::Identity();
|
|
||||||
m.translate(Eigen::Vector3f(-(float)center.x, -(float)center.y, -(float)center.z));
|
|
||||||
|
|
||||||
Pointf mouse_pos = transform(mouse_ray, m).intersect_plane(0.0);
|
if (ratio > 0.0)
|
||||||
|
m_scale_x = m_starting_scale_y * (float)ratio;
|
||||||
coordf_t orig_len = length(m_starting_drag_position - center);
|
// m_scale_y = m_starting_scale_y * (float)ratio;
|
||||||
coordf_t new_len = length(mouse_pos);
|
|
||||||
coordf_t ratio = (orig_len != 0.0) ? new_len / orig_len : 1.0;
|
|
||||||
|
|
||||||
m_scale_x = m_starting_scale_y * (float)ratio;
|
|
||||||
// m_scale_y = m_starting_scale_y * (float)ratio;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLGizmoScale3D::do_scale_z(const Linef3& mouse_ray)
|
void GLGizmoScale3D::do_scale_z(const Linef3& mouse_ray)
|
||||||
{
|
{
|
||||||
// calculates the intersection of the mouse ray with the plane parallel to plane XZ and passing through the box center
|
double ratio = calc_ratio(1, mouse_ray, m_starting_center);
|
||||||
const Pointf3& center = m_box.center();
|
|
||||||
Eigen::Transform<float, 3, Eigen::Affine> m = Eigen::Transform<float, 3, Eigen::Affine>::Identity();
|
|
||||||
m.rotate(Eigen::AngleAxisf(0.5f * (float)PI, Eigen::Vector3f::UnitX()));
|
|
||||||
m.translate(Eigen::Vector3f(-(float)center.x, -(float)center.y, -(float)center.z));
|
|
||||||
|
|
||||||
Pointf mouse_pos = transform(mouse_ray, m).intersect_plane(0.0);
|
if (ratio > 0.0)
|
||||||
|
m_scale_x = m_starting_scale_z * (float)ratio;
|
||||||
coordf_t orig_len = length(m_starting_drag_position - center);
|
// m_scale_z = m_starting_scale_z * (float)ratio;
|
||||||
coordf_t new_len = length(mouse_pos);
|
|
||||||
coordf_t ratio = (orig_len != 0.0) ? new_len / orig_len : 1.0;
|
|
||||||
|
|
||||||
m_scale_x = m_starting_scale_z * (float)ratio;
|
|
||||||
// m_scale_z = m_starting_scale_z * (float)ratio;
|
|
||||||
|
|
||||||
if (m_scale_x > 10.0)
|
|
||||||
{
|
|
||||||
int a = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLGizmoScale3D::do_scale_uniform(const Linef3& mouse_ray)
|
void GLGizmoScale3D::do_scale_uniform(const Linef3& mouse_ray)
|
||||||
{
|
{
|
||||||
// calculates the intersection of the mouse ray with the plane parallel to plane XY and passing through the box min point
|
Pointf3 center = m_starting_center;
|
||||||
const Pointf3& center = m_box.center();
|
center.z = m_box.min.z;
|
||||||
Eigen::Transform<float, 3, Eigen::Affine> m = Eigen::Transform<float, 3, Eigen::Affine>::Identity();
|
double ratio = calc_ratio(0, mouse_ray, center);
|
||||||
m.translate(Eigen::Vector3f(-(float)center.x, -(float)center.y, -(float)m_box.min.z));
|
|
||||||
|
|
||||||
Pointf mouse_pos = transform(mouse_ray, m).intersect_plane(0.0);
|
if (ratio > 0.0)
|
||||||
|
{
|
||||||
|
m_scale_x = m_starting_scale_x * (float)ratio;
|
||||||
|
m_scale_y = m_starting_scale_y * (float)ratio;
|
||||||
|
m_scale_z = m_starting_scale_z * (float)ratio;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
coordf_t orig_len = length(m_starting_drag_position - center);
|
double GLGizmoScale3D::calc_ratio(unsigned int preferred_plane_id, const Linef3& mouse_ray, const Pointf3& center) const
|
||||||
coordf_t new_len = length(Vectorf3(mouse_pos.x, mouse_pos.y, m_box.min.z - center.z));
|
{
|
||||||
coordf_t ratio = (orig_len != 0.0) ? new_len / orig_len : 1.0;
|
double ratio = 0.0;
|
||||||
|
|
||||||
m_scale_x = m_starting_scale_y * (float)ratio;
|
Vectorf3 starting_vec = m_starting_drag_position - center;
|
||||||
m_scale_y = m_starting_scale_y * (float)ratio;
|
double len_starting_vec = length(starting_vec);
|
||||||
m_scale_z = m_starting_scale_z * (float)ratio;
|
if (len_starting_vec == 0.0)
|
||||||
|
return ratio;
|
||||||
|
|
||||||
|
Vectorf3 starting_vec_dir = normalize(starting_vec);
|
||||||
|
Vectorf3 mouse_dir = mouse_ray.unit_vector();
|
||||||
|
unsigned int plane_id = preferred_plane_id;
|
||||||
|
|
||||||
|
// 1st try to see if the mouse direction is close enough to the preferred plane normal
|
||||||
|
double dot_to_normal = 0.0;
|
||||||
|
switch (plane_id)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
dot_to_normal = std::abs(dot(mouse_dir, Vectorf3(0.0, 0.0, 1.0)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
dot_to_normal = std::abs(dot(mouse_dir, Vectorf3(0.0, -1.0, 0.0)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
{
|
||||||
|
dot_to_normal = std::abs(dot(mouse_dir, Vectorf3(1.0, 0.0, 0.0)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dot_to_normal < 0.1)
|
||||||
|
{
|
||||||
|
// if not, select the plane who's normal is closest to the mouse direction
|
||||||
|
|
||||||
|
typedef std::map<double, unsigned int> ProjsMap;
|
||||||
|
ProjsMap projs_map;
|
||||||
|
|
||||||
|
projs_map.insert(ProjsMap::value_type(std::abs(dot(mouse_dir, Vectorf3(0.0, 0.0, 1.0))), 0)); // plane xy
|
||||||
|
projs_map.insert(ProjsMap::value_type(std::abs(dot(mouse_dir, Vectorf3(0.0, -1.0, 0.0))), 1)); // plane xz
|
||||||
|
projs_map.insert(ProjsMap::value_type(std::abs(dot(mouse_dir, Vectorf3(1.0, 0.0, 0.0))), 2)); // plane yz
|
||||||
|
plane_id = projs_map.rbegin()->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (plane_id)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
// calculates the intersection of the mouse ray with the plane parallel to plane XY and passing through the given center
|
||||||
|
Eigen::Transform<float, 3, Eigen::Affine> m = Eigen::Transform<float, 3, Eigen::Affine>::Identity();
|
||||||
|
m.translate(Eigen::Vector3f(-(float)center.x, -(float)center.y, -(float)center.z));
|
||||||
|
Pointf mouse_pos_2d = transform(mouse_ray, m).intersect_plane(0.0);
|
||||||
|
|
||||||
|
// ratio is given by the projection of the calculated intersection on the starting vector divided by the starting vector length
|
||||||
|
ratio = dot(Vectorf3(mouse_pos_2d.x, mouse_pos_2d.y, 0.0), starting_vec_dir) / len_starting_vec;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
// calculates the intersection of the mouse ray with the plane parallel to plane XZ and passing through the given center
|
||||||
|
Eigen::Transform<float, 3, Eigen::Affine> m = Eigen::Transform<float, 3, Eigen::Affine>::Identity();
|
||||||
|
m.rotate(Eigen::AngleAxisf(-0.5f * (float)PI, Eigen::Vector3f::UnitX()));
|
||||||
|
m.translate(Eigen::Vector3f(-(float)center.x, -(float)center.y, -(float)center.z));
|
||||||
|
Pointf mouse_pos_2d = transform(mouse_ray, m).intersect_plane(0.0);
|
||||||
|
|
||||||
|
// ratio is given by the projection of the calculated intersection on the starting vector divided by the starting vector length
|
||||||
|
ratio = dot(Vectorf3(mouse_pos_2d.x, 0.0, mouse_pos_2d.y), starting_vec_dir) / len_starting_vec;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
{
|
||||||
|
// calculates the intersection of the mouse ray with the plane parallel to plane YZ and passing through the given center
|
||||||
|
Eigen::Transform<float, 3, Eigen::Affine> m = Eigen::Transform<float, 3, Eigen::Affine>::Identity();
|
||||||
|
m.rotate(Eigen::AngleAxisf(-0.5f * (float)PI, Eigen::Vector3f::UnitY()));
|
||||||
|
m.translate(Eigen::Vector3f(-(float)center.x, -(float)center.y, -(float)center.z));
|
||||||
|
Pointf mouse_pos_2d = transform(mouse_ray, m).intersect_plane(0.0);
|
||||||
|
|
||||||
|
// ratio is given by the projection of the calculated intersection on the starting vector divided by the starting vector length
|
||||||
|
ratio = dot(Vectorf3(0.0, mouse_pos_2d.y, -mouse_pos_2d.x), starting_vec_dir) / len_starting_vec;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ratio;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace GUI
|
} // namespace GUI
|
||||||
|
@ -265,6 +265,7 @@ class GLGizmoScale3D : public GLGizmoBase
|
|||||||
float m_starting_scale_z;
|
float m_starting_scale_z;
|
||||||
|
|
||||||
Pointf3 m_starting_drag_position;
|
Pointf3 m_starting_drag_position;
|
||||||
|
Pointf3 m_starting_center;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GLGizmoScale3D();
|
GLGizmoScale3D();
|
||||||
@ -300,6 +301,8 @@ private:
|
|||||||
void do_scale_y(const Linef3& mouse_ray);
|
void do_scale_y(const Linef3& mouse_ray);
|
||||||
void do_scale_z(const Linef3& mouse_ray);
|
void do_scale_z(const Linef3& mouse_ray);
|
||||||
void do_scale_uniform(const Linef3& mouse_ray);
|
void do_scale_uniform(const Linef3& mouse_ray);
|
||||||
|
|
||||||
|
double calc_ratio(unsigned int preferred_plane_id, const Linef3& mouse_ray, const Pointf3& center) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace GUI
|
} // namespace GUI
|
||||||
|
Loading…
Reference in New Issue
Block a user