From 70ea995f4a13a64975ae98642da3653b0f183711 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 1 Jul 2022 15:51:51 +0200 Subject: [PATCH] Measuring: First steps on extracting features --- src/libslic3r/SurfaceMesh.hpp | 1 + src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 204 ++++++++++++++++++----- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 20 ++- 3 files changed, 183 insertions(+), 42 deletions(-) diff --git a/src/libslic3r/SurfaceMesh.hpp b/src/libslic3r/SurfaceMesh.hpp index e8ada4cd80..a4b261ceb9 100644 --- a/src/libslic3r/SurfaceMesh.hpp +++ b/src/libslic3r/SurfaceMesh.hpp @@ -17,6 +17,7 @@ class Halfedge_index { public: Halfedge_index() : m_face(Face_index(-1)), m_side(0) {} Face_index face() const { return m_face; } + unsigned char side() const { return m_side; } bool is_invalid() const { return int(m_face) < 0; } bool operator!=(const Halfedge_index& rhs) const { return ! ((*this) == rhs); } bool operator==(const Halfedge_index& rhs) const { return m_face == rhs.m_face && m_side == rhs.m_side; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index de3fc398b9..6c95e70b7f 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -22,7 +22,10 @@ static const Slic3r::ColorRGBA DEFAULT_HOVER_PLANE_COLOR = { 0.9f, 0.2f, 0.2f, 1 GLGizmoMeasure::GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id) -{} +{ + m_vbo_sphere.init_from(its_make_sphere(1., M_PI/32.)); + m_vbo_cylinder.init_from(its_make_cylinder(1., 1.)); +} bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) { @@ -125,7 +128,7 @@ void GLGizmoMeasure::on_render() glsafe(::glEnable(GL_DEPTH_TEST)); glsafe(::glEnable(GL_BLEND)); - glsafe(::glLineWidth(5.f)); + glsafe(::glLineWidth(2.f)); if (selection.is_single_full_instance()) { const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(); @@ -144,22 +147,47 @@ void GLGizmoMeasure::on_render() ImGui::SameLine(); if (m_imgui->button("->")) ++m_currently_shown_plane; - m_currently_shown_plane = std::clamp(m_currently_shown_plane, 0, int(m_planes.size())-1); - m_imgui->text(std::to_string(m_currently_shown_plane)); + m_currently_shown_plane = std::clamp(m_currently_shown_plane, 0, std::max(0, int(m_planes.size())-1)); + m_imgui->text(std::to_string(m_currently_shown_plane)); + m_imgui->checkbox(wxString("Show all"), m_show_all); m_imgui->end(); - //for (int i = 0; i < (int)m_planes.size(); ++i) { - int i = m_currently_shown_plane; - std::cout << m_hover_id << "\t" << m_currently_shown_plane << "\t" << std::endl; - if (i < m_planes.size()) { + int i = m_show_all ? 0 : m_currently_shown_plane; + for (int i = 0; i < (int)m_planes.size(); ++i) { + // Render all the borders. for (int j=0; j<(int)m_planes[i].vbos.size(); ++j) { m_planes[i].vbos[j].set_color(j == m_hover_id ? DEFAULT_HOVER_PLANE_COLOR : DEFAULT_PLANE_COLOR); - if (j == m_hover_id) m_planes[i].vbos[j].render(); - std::cout << " * " << j; } - std::cout <::FromTwoVectors(Vec3d::UnitZ(), feature.endpoint - feature.pos); + view_feature_matrix *= q; + view_feature_matrix.scale(Vec3d(0.3, 0.3, (feature.endpoint - feature.pos).norm())); + shader->set_uniform("view_model_matrix", view_feature_matrix); + m_vbo_cylinder.set_color(ColorRGBA(0.7f, 0.7f, 0.f, 1.f)); + m_vbo_cylinder.render(); + } + + view_feature_matrix = view_model_matrix * Transform3d(Eigen::Translation3d(feature.pos)); + view_feature_matrix.scale(0.5); + shader->set_uniform("view_model_matrix", view_feature_matrix); + m_vbo_sphere.set_color(feature.type == SurfaceFeature::Line + ? ColorRGBA(1.f, 0.f, 0.f, 1.f) + : ColorRGBA(0.f, 1.f, 0.f, 1.f)); + m_vbo_sphere.render(); + + + shader->set_uniform("view_model_matrix", view_model_matrix); + } + + if (! m_show_all) + break; } } @@ -196,7 +224,7 @@ void GLGizmoMeasure::on_render_for_picking() glsafe(::glDisable(GL_DEPTH_TEST)); glsafe(::glDisable(GL_BLEND)); - glsafe(::glLineWidth(5.f)); + glsafe(::glLineWidth(2.f)); if (selection.is_single_full_instance() && !wxGetKeyState(WXK_CONTROL)) { const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(); @@ -235,6 +263,73 @@ void GLGizmoMeasure::set_flattening_data(const ModelObject* model_object) +void GLGizmoMeasure::extract_features(GLGizmoMeasure::PlaneData& plane) +{ + plane.surface_features.clear(); + const Vec3d& normal = plane.normal; + + const double edge_threshold = 10. * (M_PI/180.); + + + + for (const std::vector& border : plane.borders) { + assert(border.size() > 1); + assert(! border.front().isApprox(border.back())); + double last_angle = 0.; + size_t first_idx = 0; + + for (size_t i=0; i edge_threshold || i == border.size() - 1) { + // Current feature ended. Save it and remember current point as beginning of the next. + bool is_line = (i == first_idx + 1); + plane.surface_features.emplace_back(SurfaceFeature{ + is_line ? SurfaceFeature::Line : SurfaceFeature::Circle, + is_line ? border[first_idx] : border[first_idx], // FIXME + border[i], + 0. // FIXME + }); + first_idx = i; + } else if (Slic3r::is_approx(angle, last_angle)) { + // possibly a segment of a circle + } else { + first_idx = i; + + } + } + last_angle = angle; + } + + // FIXME: Possibly merge the first and last feature. + + + + std::cout << "==================== " << std::endl; + } + + + for (const SurfaceFeature& f : plane.surface_features) { + std::cout << "- detected " << (f.type == SurfaceFeature::Line ? "Line" : "Circle") << std::endl; + std::cout<< f.pos << std::endl << std::endl << f.endpoint << std::endl; + std::cout << "----------------" << std::endl; + } + + + +} + + + void GLGizmoMeasure::update_planes() { const ModelObject* mo = m_c->selection_info()->model_object(); @@ -292,6 +387,7 @@ void GLGizmoMeasure::update_planes() } m_planes.back().normal = normal_ptr->cast(); + std::sort(m_planes.back().facets.begin(), m_planes.back().facets.end()); } assert(std::none_of(face_to_plane.begin(), face_to_plane.end(), [](size_t val) { return val == size_t(-1); })); @@ -300,40 +396,57 @@ void GLGizmoMeasure::update_planes() for (int plane_id=0; plane_id < m_planes.size(); ++plane_id) { //int plane_id = 5; { const auto& facets = m_planes[plane_id].facets; - std::vector pts; + m_planes[plane_id].borders.clear(); + std::vector> visited(facets.size(), {false, false, false}); + for (int face_id=0; face_id()); - Vertex_index target = sm.target(he); - const Halfedge_index he_start = he; - - do { + // he is the first halfedge on the border. Now walk around and append the points. const Halfedge_index he_orig = he; - he = sm.next_around_target(he); - while ( face_to_plane[sm.face(he)] == plane_id && he != he_orig) - he = sm.next_around_target(he); - he = sm.opposite(he); - pts.emplace_back(sm.point(sm.source(he)).cast()); - } while (he != he_start); + m_planes[plane_id].borders.emplace_back(); + m_planes[plane_id].borders.back().emplace_back(sm.point(sm.source(he)).cast()); + Vertex_index target = sm.target(he); + const Halfedge_index he_start = he; + + Face_index fi = he.face(); + auto face_it = std::lower_bound(facets.begin(), facets.end(), int(fi)); + assert(face_it != facets.end()); + assert(*face_it == int(fi)); + visited[face_it - facets.begin()][he.side()] = true; - if (pts.size() != 1) { - m_planes[plane_id].borders.emplace_back(pts); - pts.clear(); + do { + const Halfedge_index he_orig = he; + he = sm.next_around_target(he); + while ( face_to_plane[sm.face(he)] == plane_id && he != he_orig) + he = sm.next_around_target(he); + he = sm.opposite(he); + + Face_index fi = he.face(); + auto face_it = std::lower_bound(facets.begin(), facets.end(), int(fi)); + assert(face_it != facets.end()); + assert(*face_it == int(fi)); + if (visited[face_it - facets.begin()][he.side()] && he != he_start) { + m_planes[plane_id].borders.back().resize(1); + break; + } + visited[face_it - facets.begin()][he.side()] = true; + + m_planes[plane_id].borders.back().emplace_back(sm.point(sm.source(he)).cast()); + } while (he != he_start); + + if (m_planes[plane_id].borders.back().size() == 1) + m_planes[plane_id].borders.pop_back(); } - } } @@ -365,8 +478,8 @@ void GLGizmoMeasure::update_planes() // And finally create respective VBOs. The polygon is convex with // the vertices in order, so triangulation is trivial. - for (auto& plane : m_planes) { - for (const auto& vertices : plane.borders) { + for (PlaneData& plane : m_planes) { + for (std::vector& vertices : plane.borders) { GLModel::Geometry init_data; init_data.format = { GLModel::Geometry::EPrimitiveType::LineStrip, GLModel::Geometry::EVertexLayout::P3N3 }; init_data.reserve_vertices(vertices.size()); @@ -378,8 +491,17 @@ void GLGizmoMeasure::update_planes() } plane.vbos.emplace_back(); plane.vbos.back().init_from(std::move(init_data)); + vertices.pop_back(); // first and last are the same } + static int n=0; + std::cout << "==================== " << std::endl; + std::cout << "==================== " << std::endl; + std::cout << "==================== " << std::endl; + std::cout << "Plane num. " << n++ << std::endl; + extract_features(plane); + + // FIXME: vertices should really be local, they need not // persist now when we use VBOs plane.borders.clear(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 32b43e6f84..3099366736 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -24,15 +24,33 @@ class GLGizmoMeasure : public GLGizmoBase private: int m_currently_shown_plane = 0; + bool m_show_all = false; + + GLModel m_vbo_sphere; + GLModel m_vbo_cylinder; + + struct SurfaceFeature { + enum Type { + Circle, + Line + }; + Type type; + Vec3d pos; + Vec3d endpoint; // for type == Line + double radius; // for type == Circle; + }; struct PlaneData { - std::vector> borders; // should be in fact local in update_planes() std::vector facets; + std::vector> borders; // should be in fact local in update_planes() + std::vector surface_features; std::vector vbos; Vec3d normal; float area; }; + static void extract_features(PlaneData& plane); + // This holds information to decide whether recalculation is necessary: std::vector m_volumes_matrices; std::vector m_volumes_types;