MeshClipper extended:

- direction and range of the clipping plane can be now set from the outside
- it is now able to show a contour of the cut (not yet ideal with multipart objects that overlap)
This commit is contained in:
Lukas Matena 2022-02-07 10:09:46 +01:00
parent 6c397e291c
commit 389b7ce4bd
10 changed files with 161 additions and 38 deletions

View File

@ -295,7 +295,7 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
else {
if (m_imgui->button(m_desc.at("reset_direction"))) {
wxGetApp().CallAfter([this](){
m_c->object_clipper()->set_position(-1., false);
m_c->object_clipper()->set_position_by_ratio(-1., false);
});
}
}
@ -304,7 +304,7 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
ImGui::SameLine(sliders_left_width);
ImGui::PushItemWidth(window_width - sliders_left_width - slider_icon_width);
if (m_imgui->slider_float("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f", 1.0f, true, _L("Ctrl + Mouse wheel")))
m_c->object_clipper()->set_position(clp_dist, true);
m_c->object_clipper()->set_position_by_ratio(clp_dist, true);
ImGui::Separator();
if (m_imgui->button(m_desc.at("remove_all"))) {

View File

@ -383,19 +383,19 @@ bool GLGizmoHollow::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_pos
if (action == SLAGizmoEventType::MouseWheelUp && control_down) {
double pos = m_c->object_clipper()->get_position();
pos = std::min(1., pos + 0.01);
m_c->object_clipper()->set_position(pos, true);
m_c->object_clipper()->set_position_by_ratio(pos, true);
return true;
}
if (action == SLAGizmoEventType::MouseWheelDown && control_down) {
double pos = m_c->object_clipper()->get_position();
pos = std::max(0., pos - 0.01);
m_c->object_clipper()->set_position(pos, true);
m_c->object_clipper()->set_position_by_ratio(pos, true);
return true;
}
if (action == SLAGizmoEventType::ResetClippingPlane) {
m_c->object_clipper()->set_position(-1., false);
m_c->object_clipper()->set_position_by_ratio(-1., false);
return true;
}
@ -693,7 +693,7 @@ RENDER_AGAIN:
else {
if (m_imgui->button(m_desc.at("reset_direction"))) {
wxGetApp().CallAfter([this](){
m_c->object_clipper()->set_position(-1., false);
m_c->object_clipper()->set_position_by_ratio(-1., false);
});
}
}
@ -702,7 +702,7 @@ RENDER_AGAIN:
ImGui::PushItemWidth(window_width - settings_sliders_left);
float clp_dist = m_c->object_clipper()->get_position();
if (m_imgui->slider_float("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f"))
m_c->object_clipper()->set_position(clp_dist, true);
m_c->object_clipper()->set_position_by_ratio(clp_dist, true);
// make sure supports are shown/hidden as appropriate
bool show_sups = m_c->instances_hider()->are_supports_shown();

View File

@ -463,7 +463,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
m_imgui->text(m_desc.at("clipping_of_view"));
} else {
if (m_imgui->button(m_desc.at("reset_direction"))) {
wxGetApp().CallAfter([this]() { m_c->object_clipper()->set_position(-1., false); });
wxGetApp().CallAfter([this]() { m_c->object_clipper()->set_position_by_ratio(-1., false); });
}
}
@ -471,7 +471,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
ImGui::SameLine(sliders_left_width);
ImGui::PushItemWidth(window_width - sliders_left_width - slider_icon_width);
if (m_imgui->slider_float("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f", 1.0f, true, _L("Ctrl + Mouse wheel")))
m_c->object_clipper()->set_position(clp_dist, true);
m_c->object_clipper()->set_position_by_ratio(clp_dist, true);
ImGui::Separator();
if (m_imgui->button(m_desc.at("remove_all"))) {

View File

@ -429,7 +429,7 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
pos = action == SLAGizmoEventType::MouseWheelDown
? std::max(0., pos - 0.01)
: std::min(1., pos + 0.01);
m_c->object_clipper()->set_position(pos, true);
m_c->object_clipper()->set_position_by_ratio(pos, true);
return true;
}
else if (alt_down) {
@ -461,7 +461,7 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
}
if (action == SLAGizmoEventType::ResetClippingPlane) {
m_c->object_clipper()->set_position(-1., false);
m_c->object_clipper()->set_position_by_ratio(-1., false);
return true;
}

View File

@ -157,7 +157,7 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit)
else {
if (m_imgui->button(m_desc.at("reset_direction"))) {
wxGetApp().CallAfter([this](){
m_c->object_clipper()->set_position(-1., false);
m_c->object_clipper()->set_position_by_ratio(-1., false);
});
}
}
@ -166,7 +166,7 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit)
ImGui::SameLine(sliders_left_width);
ImGui::PushItemWidth(window_width - sliders_left_width - slider_icon_width);
if (m_imgui->slider_float("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f", 1.0f, true, _L("Ctrl + Mouse wheel")))
m_c->object_clipper()->set_position(clp_dist, true);
m_c->object_clipper()->set_position_by_ratio(clp_dist, true);
ImGui::Separator();
if (m_imgui->button(m_desc.at("remove_all"))) {

View File

@ -516,19 +516,19 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
if (action == SLAGizmoEventType::MouseWheelUp && control_down) {
double pos = m_c->object_clipper()->get_position();
pos = std::min(1., pos + 0.01);
m_c->object_clipper()->set_position(pos, true);
m_c->object_clipper()->set_position_by_ratio(pos, true);
return true;
}
if (action == SLAGizmoEventType::MouseWheelDown && control_down) {
double pos = m_c->object_clipper()->get_position();
pos = std::max(0., pos - 0.01);
m_c->object_clipper()->set_position(pos, true);
m_c->object_clipper()->set_position_by_ratio(pos, true);
return true;
}
if (action == SLAGizmoEventType::ResetClippingPlane) {
m_c->object_clipper()->set_position(-1., false);
m_c->object_clipper()->set_position_by_ratio(-1., false);
return true;
}
@ -826,7 +826,7 @@ RENDER_AGAIN:
else {
if (m_imgui->button(m_desc.at("reset_direction"))) {
wxGetApp().CallAfter([this](){
m_c->object_clipper()->set_position(-1., false);
m_c->object_clipper()->set_position_by_ratio(-1., false);
});
}
}
@ -835,7 +835,7 @@ RENDER_AGAIN:
ImGui::PushItemWidth(window_width - clipping_slider_left);
float clp_dist = m_c->object_clipper()->get_position();
if (m_imgui->slider_float("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f"))
m_c->object_clipper()->set_position(clp_dist, true);
m_c->object_clipper()->set_position_by_ratio(clp_dist, true);
if (m_imgui->button("?")) {

View File

@ -425,18 +425,20 @@ void ObjectClipper::render_cut() const
glsafe(::glPushMatrix());
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
clipper->render_cut({ 1.0f, 0.37f, 0.0f, 1.0f });
clipper->render_contour({ 1.f, 1.f, 1.f, 1.f});
#else
glsafe(::glColor3f(1.0f, 0.37f, 0.0f));
clipper->render_cut();
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
glsafe(::glColor3f(1.f, 1.f, 1.f));
clipper->render_contour();
#endif
glsafe(::glPopMatrix());
++clipper_id;
}
}
void ObjectClipper::set_position(double pos, bool keep_normal)
void ObjectClipper::set_position_by_ratio(double pos, bool keep_normal)
{
const ModelObject* mo = get_pool()->selection_info()->model_object();
int active_inst = get_pool()->selection_info()->get_active_instance();
@ -454,6 +456,28 @@ void ObjectClipper::set_position(double pos, bool keep_normal)
get_pool()->get_canvas()->set_as_dirty();
}
void ObjectClipper::set_range_and_pos(const Vec3d& origin, const Vec3d& end, double pos)
{
Vec3d normal = end-origin;
double norm = normal.norm();
pos = std::clamp(pos, 0.0001, norm);
m_clp.reset(new ClippingPlane(normal, pos));
m_clp_ratio = pos/norm;
get_pool()->get_canvas()->set_as_dirty();
}
const ClippingPlane* ObjectClipper::get_clipping_plane() const
{
static const ClippingPlane no_clip = ClippingPlane::ClipsNothing();
return m_hide_clipped ? m_clp.get() : &no_clip;
}
void ObjectClipper::set_behavior(bool hide_clipped, bool fill_cut, double contour_width)
{
m_hide_clipped = hide_clipped;
for (auto& clipper : m_clippers)
clipper->set_behaviour(fill_cut, contour_width);
}
void SupportsClipper::on_update()
@ -542,9 +566,12 @@ void SupportsClipper::render_cut() const
glsafe(::glPushMatrix());
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
m_clipper->render_cut({ 1.0f, 0.f, 0.37f, 1.0f });
m_clipper->render_contour({ 1.f, 1.f, 1.f, 1.f });
#else
glsafe(::glColor3f(1.0f, 0.f, 0.37f));
m_clipper->render_cut();
glsafe(::glColor3f(1.0f, 1.f, 1.f));
m_clipper->render_contour();
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
glsafe(::glPopMatrix());
}

View File

@ -255,10 +255,13 @@ public:
CommonGizmosDataID get_dependencies() const override { return CommonGizmosDataID::SelectionInfo; }
#endif // NDEBUG
void set_position(double pos, bool keep_normal);
void set_normal(const Vec3d& dir);
double get_position() const { return m_clp_ratio; }
ClippingPlane* get_clipping_plane() const { return m_clp.get(); }
const ClippingPlane* get_clipping_plane() const;
void render_cut() const;
void set_position_by_ratio(double pos, bool keep_normal);
void set_range_and_pos(const Vec3d& origin, const Vec3d& end, double pos);
void set_behavior(bool hide_clipped, bool fill_cut, double contour_width);
protected:
@ -271,6 +274,7 @@ private:
std::unique_ptr<ClippingPlane> m_clp;
double m_clp_ratio = 0.;
double m_active_inst_bb_radius = 0.;
bool m_hide_clipped = true;
};

View File

@ -19,6 +19,16 @@
namespace Slic3r {
namespace GUI {
void MeshClipper::set_behaviour(bool fill_cut, double contour_width)
{
if (fill_cut != m_fill_cut || contour_width != m_contour_width)
m_triangles_valid = false;
m_fill_cut = fill_cut;
m_contour_width = contour_width;
}
void MeshClipper::set_plane(const ClippingPlane& plane)
{
if (m_plane != plane) {
@ -43,7 +53,6 @@ void MeshClipper::set_mesh(const TriangleMesh& mesh)
if (m_mesh != &mesh) {
m_mesh = &mesh;
m_triangles_valid = false;
m_triangles2d.resize(0);
}
}
@ -52,7 +61,6 @@ void MeshClipper::set_negative_mesh(const TriangleMesh& mesh)
if (m_negative_mesh != &mesh) {
m_negative_mesh = &mesh;
m_triangles_valid = false;
m_triangles2d.resize(0);
}
}
@ -63,12 +71,10 @@ void MeshClipper::set_transformation(const Geometry::Transformation& trafo)
if (! m_trafo.get_matrix().isApprox(trafo.get_matrix())) {
m_trafo = trafo;
m_triangles_valid = false;
m_triangles2d.resize(0);
}
}
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
void MeshClipper::render_cut(const ColorRGBA& color)
#else
@ -77,7 +83,6 @@ void MeshClipper::render_cut()
{
if (! m_triangles_valid)
recalculate_triangles();
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
GLShaderProgram* curr_shader = wxGetApp().get_current_shader();
if (curr_shader != nullptr)
@ -100,6 +105,36 @@ void MeshClipper::render_cut()
}
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
void MeshClipper::render_contour(const ColorRGBA& color)
#else
void MeshClipper::render_contour()
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
{
if (! m_triangles_valid)
recalculate_triangles();
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
GLShaderProgram* curr_shader = wxGetApp().get_current_shader();
if (curr_shader != nullptr)
curr_shader->stop_using();
GLShaderProgram* shader = wxGetApp().get_shader("flat");
if (shader != nullptr) {
shader->start_using();
m_model_expanded.set_color(color);
m_model_expanded.render();
shader->stop_using();
}
if (curr_shader != nullptr)
curr_shader->start_using();
#else
if (m_vertex_array_expanded.has_VBOs())
m_vertex_array_expanded.render();
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
}
void MeshClipper::recalculate_triangles()
{
@ -181,24 +216,25 @@ void MeshClipper::recalculate_triangles()
}
}
m_triangles2d = triangulate_expolygons_2f(expolys, m_trafo.get_matrix().matrix().determinant() < 0.);
tr.pretranslate(0.001 * m_plane.get_normal().normalized()); // to avoid z-fighting
std::vector<Vec2f> triangles2d = m_fill_cut
? triangulate_expolygons_2f(expolys, m_trafo.get_matrix().matrix().determinant() < 0.)
: std::vector<Vec2f>();
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
m_model.reset();
GLModel::Geometry init_data;
init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::index_type(m_triangles2d.size()) };
init_data.reserve_vertices(m_triangles2d.size());
init_data.reserve_indices(m_triangles2d.size());
init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::index_type(triangles2d.size()) };
init_data.reserve_vertices(triangles2d.size());
init_data.reserve_indices(triangles2d.size());
// vertices + indices
for (auto it = m_triangles2d.cbegin(); it != m_triangles2d.cend(); it = it + 3) {
for (auto it = triangles2d.cbegin(); it != triangles2d.cend(); it = it + 3) {
init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 0)).x(), (*(it + 0)).y(), height_mesh)).cast<float>(), (Vec3f)up.cast<float>());
init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 1)).x(), (*(it + 1)).y(), height_mesh)).cast<float>(), (Vec3f)up.cast<float>());
init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 2)).x(), (*(it + 2)).y(), height_mesh)).cast<float>(), (Vec3f)up.cast<float>());
const size_t idx = it - m_triangles2d.cbegin();
const size_t idx = it - triangles2d.cbegin();
if (init_data.format.index_type == GLModel::Geometry::EIndexType::USHORT)
init_data.add_ushort_triangle((unsigned short)idx, (unsigned short)idx + 1, (unsigned short)idx + 2);
else
@ -209,16 +245,61 @@ void MeshClipper::recalculate_triangles()
m_model.init_from(std::move(init_data));
#else
m_vertex_array.release_geometry();
for (auto it=m_triangles2d.cbegin(); it != m_triangles2d.cend(); it=it+3) {
for (auto it=triangles2d.cbegin(); it != triangles2d.cend(); it=it+3) {
m_vertex_array.push_geometry(tr * Vec3d((*(it+0))(0), (*(it+0))(1), height_mesh), up);
m_vertex_array.push_geometry(tr * Vec3d((*(it+1))(0), (*(it+1))(1), height_mesh), up);
m_vertex_array.push_geometry(tr * Vec3d((*(it+2))(0), (*(it+2))(1), height_mesh), up);
const size_t idx = it - m_triangles2d.cbegin();
const size_t idx = it - triangles2d.cbegin();
m_vertex_array.push_triangle(idx, idx+1, idx+2);
}
m_vertex_array.finalize_geometry(true);
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
triangles2d = {};
if (m_contour_width != 0.) {
ExPolygons expolys_exp = offset_ex(expolys, scale_(m_contour_width));
expolys_exp = diff_ex(expolys_exp, expolys);
triangles2d = triangulate_expolygons_2f(expolys_exp, m_trafo.get_matrix().matrix().determinant() < 0.);
}
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
m_model_expanded.reset();
init_data = GLModel::Geometry();
init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::index_type(triangles2d.size()) };
init_data.reserve_vertices(triangles2d.size());
init_data.reserve_indices(triangles2d.size());
// vertices + indices
for (auto it = triangles2d.cbegin(); it != triangles2d.cend(); it = it + 3) {
init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 0)).x(), (*(it + 0)).y(), height_mesh)).cast<float>(), (Vec3f)up.cast<float>());
init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 1)).x(), (*(it + 1)).y(), height_mesh)).cast<float>(), (Vec3f)up.cast<float>());
init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 2)).x(), (*(it + 2)).y(), height_mesh)).cast<float>(), (Vec3f)up.cast<float>());
const size_t idx = it - triangles2d.cbegin();
if (init_data.format.index_type == GLModel::Geometry::EIndexType::USHORT)
init_data.add_ushort_triangle((unsigned short)idx, (unsigned short)idx + 1, (unsigned short)idx + 2);
else
init_data.add_uint_triangle((unsigned int)idx, (unsigned int)idx + 1, (unsigned int)idx + 2);
}
if (!init_data.is_empty())
m_model_expanded.init_from(std::move(init_data));
#else
m_vertex_array_expanded.release_geometry();
for (auto it=triangles2d.cbegin(); it != triangles2d.cend(); it=it+3) {
m_vertex_array_expanded.push_geometry(tr * Vec3d((*(it+0))(0), (*(it+0))(1), height_mesh), up);
m_vertex_array_expanded.push_geometry(tr * Vec3d((*(it+1))(0), (*(it+1))(1), height_mesh), up);
m_vertex_array_expanded.push_geometry(tr * Vec3d((*(it+2))(0), (*(it+2))(1), height_mesh), up);
const size_t idx = it - triangles2d.cbegin();
m_vertex_array_expanded.push_triangle(idx, idx+1, idx+2);
}
m_vertex_array_expanded.finalize_geometry(true);
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
m_triangles_valid = true;
}

View File

@ -77,6 +77,10 @@ public:
class MeshClipper
{
public:
// Set whether the cut should be triangulated and whether a cut
// contour should be calculated and shown.
void set_behaviour(bool fill_cut, double contour_width);
// Inform MeshClipper about which plane we want to use to cut the mesh
// This is supposed to be in world coordinates.
void set_plane(const ClippingPlane& plane);
@ -100,8 +104,12 @@ public:
// be set in world coords.
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
void render_cut(const ColorRGBA& color);
void render_contour(const ColorRGBA& color);
#else
void render_cut();
// Render the triangulated contour. Transformation matrices should
// be set in world coords.
void render_contour();
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
private:
@ -112,13 +120,16 @@ private:
const TriangleMesh* m_negative_mesh = nullptr;
ClippingPlane m_plane;
ClippingPlane m_limiting_plane = ClippingPlane::ClipsNothing();
std::vector<Vec2f> m_triangles2d;
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
GLModel m_model;
GLModel m_model_expanded;
#else
GLIndexedVertexArray m_vertex_array;
GLIndexedVertexArray m_vertex_array_expanded;
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
bool m_triangles_valid = false;
bool m_fill_cut = true;
double m_contour_width = 0.;
};