Refactoring the SLA clipping plane

The plane is now internally stored as a plane in world coordinates
This commit is contained in:
Lukas Matena 2019-09-12 13:18:02 +02:00
parent 177a96a768
commit cf23146ee3
3 changed files with 53 additions and 48 deletions

View file

@ -89,11 +89,29 @@ public:
m_data[3] = offset; m_data[3] = offset;
} }
bool operator==(const ClippingPlane& cp) const {
return m_data[0]==cp.m_data[0] && m_data[1]==cp.m_data[1] && m_data[2]==cp.m_data[2] && m_data[3]==cp.m_data[3];
}
bool operator!=(const ClippingPlane& cp) const { return ! (*this==cp); }
double distance(const Vec3d& pt) const {
assert(is_approx(get_normal().norm(), 1.));
return (-get_normal().dot(pt) + m_data[3]);
}
void set_normal(const Vec3d& normal) { for (size_t i=0; i<3; ++i) m_data[i] = normal(i); }
void set_offset(double offset) { m_data[3] = offset; }
Vec3d get_normal() const { return Vec3d(m_data[0], m_data[1], m_data[2]); }
bool is_active() const { return m_data[3] != DBL_MAX; } bool is_active() const { return m_data[3] != DBL_MAX; }
static ClippingPlane ClipsNothing() { return ClippingPlane(Vec3d(0., 0., 1.), DBL_MAX); } static ClippingPlane ClipsNothing() { return ClippingPlane(Vec3d(0., 0., 1.), DBL_MAX); }
const double* get_data() const { return m_data; } const double* get_data() const { return m_data; }
// Serialization through cereal library
template <class Archive>
void serialize( Archive & ar )
{
ar( m_data[0], m_data[1], m_data[2], m_data[3] );
}
}; };

View file

@ -26,6 +26,8 @@ GLGizmoSlaSupports::GLGizmoSlaSupports(GLCanvas3D& parent, const std::string& ic
, m_quadric(nullptr) , m_quadric(nullptr)
, m_its(nullptr) , m_its(nullptr)
{ {
m_clipping_plane.reset(new ClippingPlane(Vec3d::Zero(), 0.));
m_old_clipping_plane.reset(new ClippingPlane(Vec3d::Zero(), 0.));
m_quadric = ::gluNewQuadric(); m_quadric = ::gluNewQuadric();
if (m_quadric != nullptr) if (m_quadric != nullptr)
// using GLU_FILL does not work when the instance's transformation // using GLU_FILL does not work when the instance's transformation
@ -137,10 +139,7 @@ void GLGizmoSlaSupports::render_clipping_plane(const Selection& selection) const
if (m_clipping_plane_distance == 0.f) if (m_clipping_plane_distance == 0.f)
return; return;
if (m_clipping_plane_normal == Vec3d::Zero()) const Vec3d& center = m_model_object->instances[m_active_instance]->get_offset() + Vec3d(0., 0., m_z_shift);
reset_clipping_plane_normal();
const Vec3d& direction_to_camera = m_clipping_plane_normal;
// First cache instance transformation to be used later. // First cache instance transformation to be used later.
const GLVolume* vol = selection.get_volume(*selection.get_volume_idxs().begin()); const GLVolume* vol = selection.get_volume(*selection.get_volume_idxs().begin());
@ -148,27 +147,24 @@ void GLGizmoSlaSupports::render_clipping_plane(const Selection& selection) const
Transform3f instance_matrix_no_translation_no_scaling = vol->get_instance_transformation().get_matrix(true,false,true).cast<float>(); Transform3f instance_matrix_no_translation_no_scaling = vol->get_instance_transformation().get_matrix(true,false,true).cast<float>();
Vec3f scaling = vol->get_instance_scaling_factor().cast<float>(); Vec3f scaling = vol->get_instance_scaling_factor().cast<float>();
Vec3d instance_offset = vol->get_instance_offset(); Vec3d instance_offset = vol->get_instance_offset();
// Calculate distance from mesh origin to the clipping plane (in mesh coordinates). // Calculate distance from mesh origin to the clipping plane (in mesh coordinates).
Vec3f up_noscale = instance_matrix_no_translation_no_scaling.inverse() * direction_to_camera.cast<float>(); Vec3f up_noscale = instance_matrix_no_translation_no_scaling.inverse() * m_clipping_plane->get_normal().cast<float>();
Vec3f up = Vec3f(up_noscale(0)*scaling(0), up_noscale(1)*scaling(1), up_noscale(2)*scaling(2)); Vec3f up = Vec3f(up_noscale(0)*scaling(0), up_noscale(1)*scaling(1), up_noscale(2)*scaling(2));
float height_mesh = (m_active_instance_bb_radius - m_clipping_plane_distance * 2*m_active_instance_bb_radius) * (up_noscale.norm()/up.norm()); float height_mesh = m_clipping_plane->distance(center) * (up_noscale.norm()/up.norm());
// Get transformation of the supports and calculate how far from its origin the clipping plane is. // Get transformation of the supports and calculate how far from its origin the clipping plane is.
Transform3d supports_trafo = Transform3d::Identity(); Transform3d supports_trafo = Transform3d::Identity();
supports_trafo = supports_trafo.rotate(Eigen::AngleAxisd(vol->get_instance_rotation()(2), Vec3d::UnitZ())); supports_trafo = supports_trafo.rotate(Eigen::AngleAxisd(vol->get_instance_rotation()(2), Vec3d::UnitZ()));
Vec3f up_supports = (supports_trafo.inverse() * direction_to_camera).cast<float>(); Vec3f up_supports = (supports_trafo.inverse() * m_clipping_plane->get_normal()).cast<float>();
supports_trafo = supports_trafo.pretranslate(Vec3d(instance_offset(0), instance_offset(1), vol->get_sla_shift_z())); supports_trafo = supports_trafo.pretranslate(Vec3d(instance_offset(0), instance_offset(1), vol->get_sla_shift_z()));
// Instance and supports origin do not coincide, so the following is quite messy: // Instance and supports origin do not coincide, so the following is quite messy:
float height_supports = height_mesh * (up.norm() / up_supports.norm()) + instance_offset(2) * (direction_to_camera(2) / direction_to_camera.norm()); float height_supports = height_mesh * (up.norm() / up_supports.norm()) + instance_offset(2) * (m_clipping_plane->get_normal()(2));
// In case either of these was recently changed, the cached triangulated ExPolygons are invalid now. // In case either of these was recently changed, the cached triangulated ExPolygons are invalid now.
// We are gonna recalculate them both for the object and for the support structures. // We are gonna recalculate them both for the object and for the support structures.
if (m_clipping_plane_distance != m_old_clipping_plane_distance if (*m_old_clipping_plane != *m_clipping_plane) {
|| m_old_clipping_plane_normal != direction_to_camera) {
m_old_clipping_plane_normal = direction_to_camera; *m_old_clipping_plane = *m_clipping_plane;
m_old_clipping_plane_distance = m_clipping_plane_distance;
// Now initialize the TMS for the object, perform the cut and save the result. // Now initialize the TMS for the object, perform the cut and save the result.
if (! m_tms) { if (! m_tms) {
@ -379,15 +375,12 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking)
bool GLGizmoSlaSupports::is_point_clipped(const Vec3d& point) const bool GLGizmoSlaSupports::is_point_clipped(const Vec3d& point) const
{ {
const Vec3d& direction_to_camera = m_clipping_plane_normal;
if (m_clipping_plane_distance == 0.f) if (m_clipping_plane_distance == 0.f)
return false; return false;
Vec3d transformed_point = m_model_object->instances.front()->get_transformation().get_matrix() * point; Vec3d transformed_point = m_model_object->instances.front()->get_transformation().get_matrix() * point;
transformed_point(2) += m_z_shift; transformed_point(2) += m_z_shift;
return direction_to_camera.dot(m_model_object->instances[m_active_instance]->get_offset() + Vec3d(0., 0., m_z_shift)) + m_active_instance_bb_radius return m_clipping_plane->distance(transformed_point) < 0.;
- m_clipping_plane_distance * 2*m_active_instance_bb_radius < direction_to_camera.dot(transformed_point);
} }
@ -693,18 +686,18 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
if (action == SLAGizmoEventType::MouseWheelUp && control_down) { if (action == SLAGizmoEventType::MouseWheelUp && control_down) {
m_clipping_plane_distance = std::min(1.f, m_clipping_plane_distance + 0.01f); m_clipping_plane_distance = std::min(1.f, m_clipping_plane_distance + 0.01f);
m_parent.set_as_dirty(); update_clipping_plane(true);
return true; return true;
} }
if (action == SLAGizmoEventType::MouseWheelDown && control_down) { if (action == SLAGizmoEventType::MouseWheelDown && control_down) {
m_clipping_plane_distance = std::max(0.f, m_clipping_plane_distance - 0.01f); m_clipping_plane_distance = std::max(0.f, m_clipping_plane_distance - 0.01f);
m_parent.set_as_dirty(); update_clipping_plane(true);
return true; return true;
} }
if (action == SLAGizmoEventType::ResetClippingPlane) { if (action == SLAGizmoEventType::ResetClippingPlane) {
reset_clipping_plane_normal(); update_clipping_plane();
return true; return true;
} }
@ -796,18 +789,10 @@ void GLGizmoSlaSupports::update_cache_entry_normal(size_t i) const
ClippingPlane GLGizmoSlaSupports::get_sla_clipping_plane() const ClippingPlane GLGizmoSlaSupports::get_sla_clipping_plane() const
{ {
if (!m_model_object || m_state == Off) if (!m_model_object || m_state == Off || m_clipping_plane_distance == 0.f)
return ClippingPlane::ClipsNothing(); return ClippingPlane::ClipsNothing();
else
//Eigen::Matrix<GLdouble, 4, 4, Eigen::DontAlign> modelview_matrix; return ClippingPlane(-m_clipping_plane->get_normal(), m_clipping_plane->get_data()[3]);
//::glGetDoublev(GL_MODELVIEW_MATRIX, modelview_matrix.data());
// we'll recover current look direction from the modelview matrix (in world coords):
//Vec3d direction_to_camera(modelview_matrix.data()[2], modelview_matrix.data()[6], modelview_matrix.data()[10]);
const Vec3d& direction_to_camera = m_clipping_plane_normal;
float dist = direction_to_camera.dot(m_model_object->instances[m_active_instance]->get_offset() + Vec3d(0., 0., m_z_shift));
return ClippingPlane(-direction_to_camera.normalized(),(dist - (-m_active_instance_bb_radius) - m_clipping_plane_distance * 2*m_active_instance_bb_radius));
} }
@ -1019,14 +1004,15 @@ RENDER_AGAIN:
else { else {
if (m_imgui->button(m_desc.at("reset_direction"))) { if (m_imgui->button(m_desc.at("reset_direction"))) {
wxGetApp().CallAfter([this](){ wxGetApp().CallAfter([this](){
reset_clipping_plane_normal(); update_clipping_plane();
}); });
} }
} }
ImGui::SameLine(clipping_slider_left); ImGui::SameLine(clipping_slider_left);
ImGui::PushItemWidth(window_width - clipping_slider_left); ImGui::PushItemWidth(window_width - clipping_slider_left);
ImGui::SliderFloat(" ", &m_clipping_plane_distance, 0.f, 1.f, "%.2f"); if (ImGui::SliderFloat(" ", &m_clipping_plane_distance, 0.f, 1.f, "%.2f"))
update_clipping_plane(true);
if (m_imgui->button("?")) { if (m_imgui->button("?")) {
@ -1198,7 +1184,7 @@ void GLGizmoSlaSupports::on_stop_dragging()
void GLGizmoSlaSupports::on_load(cereal::BinaryInputArchive& ar) void GLGizmoSlaSupports::on_load(cereal::BinaryInputArchive& ar)
{ {
ar(m_clipping_plane_distance, ar(m_clipping_plane_distance,
m_clipping_plane_normal, *m_clipping_plane,
m_model_object_id, m_model_object_id,
m_new_point_head_diameter, m_new_point_head_diameter,
m_normal_cache, m_normal_cache,
@ -1212,7 +1198,7 @@ void GLGizmoSlaSupports::on_load(cereal::BinaryInputArchive& ar)
void GLGizmoSlaSupports::on_save(cereal::BinaryOutputArchive& ar) const void GLGizmoSlaSupports::on_save(cereal::BinaryOutputArchive& ar) const
{ {
ar(m_clipping_plane_distance, ar(m_clipping_plane_distance,
m_clipping_plane_normal, *m_clipping_plane,
m_model_object_id, m_model_object_id,
m_new_point_head_diameter, m_new_point_head_diameter,
m_normal_cache, m_normal_cache,
@ -1401,17 +1387,19 @@ bool GLGizmoSlaSupports::unsaved_changes() const
} }
void GLGizmoSlaSupports::reset_clipping_plane_normal() const void GLGizmoSlaSupports::update_clipping_plane(bool keep_normal) const
{ {
Eigen::Matrix<double, 4, 4, Eigen::DontAlign> modelview_matrix; Vec3d normal = (keep_normal && m_clipping_plane->get_normal() != Vec3d::Zero() ?
::glGetDoublev(GL_MODELVIEW_MATRIX, modelview_matrix.data()); m_clipping_plane->get_normal() : -m_parent.get_camera().get_dir_forward());
m_clipping_plane_normal = Vec3d(modelview_matrix.data()[2], modelview_matrix.data()[6], modelview_matrix.data()[10]);
const Vec3d& center = m_model_object->instances[m_active_instance]->get_offset() + Vec3d(0., 0., m_z_shift);
float dist = normal.dot(center);
*m_clipping_plane = ClippingPlane(normal, (dist - (-m_active_instance_bb_radius) - m_clipping_plane_distance * 2*m_active_instance_bb_radius));
m_parent.set_as_dirty(); m_parent.set_as_dirty();
} }
SlaGizmoHelpDialog::SlaGizmoHelpDialog() SlaGizmoHelpDialog::SlaGizmoHelpDialog()
: wxDialog(NULL, wxID_ANY, _(L("SLA gizmo keyboard shortcuts")), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER) : wxDialog(nullptr, wxID_ANY, _(L("SLA gizmo keyboard shortcuts")), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER)
{ {
SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
const wxString ctrl = GUI::shortkey_ctrl_prefix(); const wxString ctrl = GUI::shortkey_ctrl_prefix();

View file

@ -4,6 +4,7 @@
#include "GLGizmoBase.hpp" #include "GLGizmoBase.hpp"
#include "GLGizmos.hpp" #include "GLGizmos.hpp"
#include "slic3r/GUI/GLSelectionRectangle.hpp" #include "slic3r/GUI/GLSelectionRectangle.hpp"
#include "slic3r/GUI/GLSelectionRectangle.hpp"
// There is an L function in igl that would be overridden by our localization macro - let's undefine it... // There is an L function in igl that would be overridden by our localization macro - let's undefine it...
#undef L #undef L
@ -19,10 +20,8 @@
namespace Slic3r { namespace Slic3r {
namespace GUI { namespace GUI {
class ClippingPlane; class ClippingPlane;
class GLGizmoSlaSupports : public GLGizmoBase class GLGizmoSlaSupports : public GLGizmoBase
{ {
private: private:
@ -114,9 +113,8 @@ private:
std::vector<sla::SupportPoint> m_normal_cache; // to restore after discarding changes or undo/redo std::vector<sla::SupportPoint> m_normal_cache; // to restore after discarding changes or undo/redo
float m_clipping_plane_distance = 0.f; float m_clipping_plane_distance = 0.f;
mutable float m_old_clipping_plane_distance = 0.f; std::unique_ptr<ClippingPlane> m_clipping_plane;
mutable Vec3d m_old_clipping_plane_normal; std::unique_ptr<ClippingPlane> m_old_clipping_plane;
mutable Vec3d m_clipping_plane_normal = Vec3d::Zero();
// This map holds all translated description texts, so they can be easily referenced during layout calculations // This map holds all translated description texts, so they can be easily referenced during layout calculations
// etc. When language changes, GUI is recreated and this class constructed again, so the change takes effect. // etc. When language changes, GUI is recreated and this class constructed again, so the change takes effect.
@ -151,6 +149,7 @@ private:
void switch_to_editing_mode(); void switch_to_editing_mode();
void disable_editing_mode(); void disable_editing_mode();
void reset_clipping_plane_normal() const; void reset_clipping_plane_normal() const;
void update_clipping_plane(bool keep_normal = false) const;
protected: protected:
void on_set_state() override; void on_set_state() override;