2828#include < geode/basic/pimpl_impl.hpp>
2929
3030#include < geode/mesh/core/detail/vertex_cycle.hpp>
31+ #include < geode/mesh/core/edged_curve.hpp>
3132#include < geode/mesh/core/solid_mesh.hpp>
3233#include < geode/mesh/core/surface_mesh.hpp>
3334
3435#include < geode/model/mixin/core/block.hpp>
36+ #include < geode/model/mixin/core/line.hpp>
3537#include < geode/model/mixin/core/surface.hpp>
3638#include < geode/model/representation/core/brep.hpp>
3739
4042#include < geode/inspector/criterion/manifold/solid_facet_manifold.hpp>
4143#include < geode/inspector/criterion/manifold/solid_vertex_manifold.hpp>
4244
45+ namespace
46+ {
47+ bool is_vertex_on_free_border ( const geode::Surface3D& surface,
48+ geode::index_t vertex,
49+ const geode::BRep& model )
50+ {
51+ const auto unique_vertex =
52+ model.unique_vertex ( { surface.component_id (), vertex } );
53+ for ( const auto & cmv : model.component_mesh_vertices ( unique_vertex ) )
54+ {
55+ if ( cmv.component_id .type ()
56+ != geode::Line3D::component_type_static () )
57+ {
58+ continue ;
59+ }
60+ if ( !model.relation_index ( cmv.component_id .id (), surface.id () )
61+ .has_value () )
62+ {
63+ continue ;
64+ }
65+ if ( model.is_internal (
66+ model.line ( cmv.component_id .id () ), surface ) )
67+ {
68+ continue ;
69+ }
70+ if ( model.nb_incidences ( cmv.component_id .id () ) > 1 )
71+ {
72+ continue ;
73+ }
74+ return true ;
75+ }
76+ return false ;
77+ }
78+
79+ std::vector< bool > vertices_on_free_border (
80+ const geode::Surface3D& surface,
81+ const geode::SurfaceMesh3D& surface_mesh,
82+ const geode::BRep& model )
83+ {
84+ std::vector< bool > is_on_free_border (
85+ surface_mesh.nb_vertices (), false );
86+ for ( const auto vertex : geode::Range{ surface_mesh.nb_vertices () } )
87+ {
88+ is_on_free_border[vertex] =
89+ is_vertex_on_free_border ( surface, vertex, model );
90+ }
91+ return is_on_free_border;
92+ }
93+ } // namespace
94+
4395namespace geode
4496{
4597 std::string BRepMeshesManifoldInspectionResult::string () const
@@ -188,6 +240,68 @@ namespace geode
188240 edge.first .vertices (), edge.second },
189241 message );
190242 }
243+ const auto & surface = model ().surface ( edge.second [0 ] );
244+ const auto & mesh = surface.mesh ();
245+ const auto is_on_free_border =
246+ vertices_on_free_border ( surface, mesh, model () );
247+ if ( !is_on_free_border[edge.first .vertices ()[0 ]]
248+ || !is_on_free_border[edge.first .vertices ()[1 ]] )
249+ {
250+ continue ;
251+ }
252+ std::string message = absl::StrCat (
253+ " Model edge between unique vertices " ,
254+ edge.first .vertices ()[0 ], " and " , edge.first .vertices ()[1 ],
255+ " is not manifold: it has 2 point on the free border "
256+ " without being on the border of surface " );
257+ absl::StrAppend ( &message, edge.second [0 ].string (), " , " );
258+ issues.add_issue (
259+ BRepNonManifoldEdge{ edge.first .vertices (), edge.second },
260+ message );
261+ }
262+ for ( const auto & line : model ().lines () )
263+ {
264+ const auto & mesh = line.mesh ();
265+ if ( mesh.nb_edges () == 1
266+ && model ().nb_embedding_surfaces ( line ) > 0 )
267+ {
268+ std::string message = absl::StrCat (
269+ " Model edge between unique unique vertices " ,
270+ mesh.edge_vertices ( 0 )[0 ], " and " ,
271+ mesh.edge_vertices ( 0 )[1 ],
272+ " is not manifold: it belongs to an internal line with "
273+ " only one edge" );
274+ issues.add_issue (
275+ BRepNonManifoldEdge{ mesh.edge_vertices ( 0 ), {} },
276+ message );
277+ }
278+ }
279+ }
280+
281+ void add_model_non_manifold_facets (
282+ InspectionIssues< BRepNonManifoldFacet >& issues ) const
283+ {
284+ for ( const auto & surface : model ().surfaces () )
285+ {
286+ const auto & mesh = surface.mesh ();
287+ if ( mesh.nb_polygons () == 1
288+ && model ().nb_embedding_blocks ( surface ) > 0 )
289+ {
290+ std::string message =
291+ absl::StrCat ( " Model facet between unique vertices " ,
292+ mesh.polygon_vertices ( 0 )[0 ], " " ,
293+ mesh.polygon_vertices ( 0 )[1 ], " and " ,
294+ mesh.polygon_vertices ( 0 )[2 ],
295+ " is not manifold: it belongs to an internal "
296+ " surface with only one facet" );
297+ issues.add_issue (
298+ BRepNonManifoldFacet{
299+ { mesh.polygon_vertices ( 0 )[0 ],
300+ mesh.polygon_vertices ( 0 )[1 ],
301+ mesh.polygon_vertices ( 0 )[2 ] },
302+ {} },
303+ message );
304+ }
191305 }
192306 }
193307 };
@@ -211,6 +325,7 @@ namespace geode
211325 impl_->add_component_meshes_non_manifold_facets (
212326 result.meshes_non_manifold_facets );
213327 impl_->add_model_non_manifold_edges ( result.brep_non_manifold_edges );
328+ impl_->add_model_non_manifold_facets ( result.brep_non_manifold_facets );
214329 return result;
215330 }
216331
0 commit comments