Enhanced behaviour of scale 3D gizmo

This commit is contained in:
Enrico Turri 2018-08-22 11:22:07 +02:00
parent 889d0f1434
commit 0924bedd28
3 changed files with 117 additions and 52 deletions

View File

@ -89,6 +89,10 @@ class Linef3
explicit Linef3(Pointf3 _a, Pointf3 _b): a(_a), b(_b) {};
Pointf3 intersect_plane(double z) const;
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

View File

@ -819,7 +819,10 @@ bool GLGizmoScale3D::on_init()
void GLGizmoScale3D::on_start_dragging()
{
if (m_hover_id != -1)
{
m_starting_drag_position = m_grabbers[m_hover_id].center;
m_starting_center = m_box.center();
}
}
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)
{
// calculates the intersection of the mouse ray with the plane parallel to plane XY and passing through the box 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));
double ratio = calc_ratio(1, mouse_ray, m_starting_center);
Pointf mouse_pos = transform(mouse_ray, m).intersect_plane(0.0);
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;
if (ratio > 0.0)
m_scale_x = m_starting_scale_x * (float)ratio;
}
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
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));
double ratio = calc_ratio(2, mouse_ray, m_starting_center);
Pointf mouse_pos = transform(mouse_ray, m).intersect_plane(0.0);
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_y * (float)ratio;
// m_scale_y = m_starting_scale_y * (float)ratio;
if (ratio > 0.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)
{
// calculates the intersection of the mouse ray with the plane parallel to plane XZ and passing through the box 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));
double ratio = calc_ratio(1, mouse_ray, m_starting_center);
Pointf mouse_pos = transform(mouse_ray, m).intersect_plane(0.0);
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_z * (float)ratio;
// m_scale_z = m_starting_scale_z * (float)ratio;
if (m_scale_x > 10.0)
{
int a = 0;
}
if (ratio > 0.0)
m_scale_x = m_starting_scale_z * (float)ratio;
// m_scale_z = m_starting_scale_z * (float)ratio;
}
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
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)m_box.min.z));
Pointf3 center = m_starting_center;
center.z = m_box.min.z;
double ratio = calc_ratio(0, mouse_ray, center);
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);
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 GLGizmoScale3D::calc_ratio(unsigned int preferred_plane_id, const Linef3& mouse_ray, const Pointf3& center) const
{
double ratio = 0.0;
m_scale_x = m_starting_scale_y * (float)ratio;
m_scale_y = m_starting_scale_y * (float)ratio;
m_scale_z = m_starting_scale_z * (float)ratio;
Vectorf3 starting_vec = m_starting_drag_position - center;
double len_starting_vec = length(starting_vec);
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

View File

@ -265,6 +265,7 @@ class GLGizmoScale3D : public GLGizmoBase
float m_starting_scale_z;
Pointf3 m_starting_drag_position;
Pointf3 m_starting_center;
public:
GLGizmoScale3D();
@ -300,6 +301,8 @@ private:
void do_scale_y(const Linef3& mouse_ray);
void do_scale_z(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