Skip to content

Commit 97687c7

Browse files
committed
fix(BRepMeshesManifold): add test to detect non manifold facets and edges
1 parent 28edebc commit 97687c7

File tree

2 files changed

+125
-0
lines changed

2 files changed

+125
-0
lines changed

include/geode/inspector/criterion/manifold/brep_meshes_manifold.hpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,12 @@ namespace geode
4848
std::vector< uuid > component_ids;
4949
};
5050

51+
struct BRepNonManifoldFacet
52+
{
53+
std::array< index_t, 3 > facet;
54+
std::vector< uuid > component_ids;
55+
};
56+
5157
struct opengeode_inspector_inspector_api BRepMeshesManifoldInspectionResult
5258
{
5359
InspectionIssuesMap< index_t > meshes_non_manifold_vertices{
@@ -65,6 +71,10 @@ namespace geode
6571
"BRep non manifold edges"
6672
};
6773

74+
InspectionIssues< BRepNonManifoldFacet > brep_non_manifold_facets{
75+
"BRep non manifold facets"
76+
};
77+
6878
[[nodiscard]] std::string string() const;
6979

7080
[[nodiscard]] std::string inspection_type() const;

src/geode/inspector/criterion/manifold/brep_meshes_manifold.cpp

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,12 @@
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

@@ -40,6 +42,56 @@
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+
4395
namespace 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

Comments
 (0)