geometry icon indicating copy to clipboard operation
geometry copied to clipboard

feat: Implement is_valid algorithm for polyhedral surfaces

Open vissarion opened this issue 7 months ago • 6 comments

This PR introduces support for the is_valid algorithm for polyhedral surface geometries. A polyhedral_surface is a 3D composite geometry formed by a collection of polygonal faces that meet at shared edges. The implementation follows the OGC Simple Features Specification and introduces structural and topological checks for polyhedral surfaces.

The following properties should hold (following OGC standard):

  • Contiguity: All polygon patches must form a connected surface via shared boundary segments.
  • Shared Edges: Shared boundaries must be finite LineStrings used in at most two polygons.
  • Orientation: Shared boundaries must be traversed in opposite directions by adjacent polygons; global orientation must be consistent.

Six new validity failure types has been introduced that reflect the description of the standard.

Below there is a matrix with valid and invalid cases with visualizations. Those cases (and a few more) are included in the unit tests of this PR.

Name Geometry Figure
valid_surface POLYHEDRALSURFACE(((0 0 0,0 1 0,1 1 0,1 0 0,0 0 0)),((0 0 0,0 0 1,0 1 1,0 1 0,0 0 0)),((0 0 0,1 0 0,1 0 1,0 0 1,0 0 0)),((1 1 1,0 1 1,0 0 1,1 0 1,1 1 1)),((1 1 1,1 0 1,1 0 0,1 1 0,1 1 1)),((1 1 1,1 1 0,0 1 0,0 1 1,1 1 1))) Screenshot from 2025-05-21 16-52-54
valid_surface_non_convex POLYHEDRALSURFACE(((0 0 0,0 1 0,1 1 0,1 0 0,0 0 0)),((0 0 0,0 0 1,0 1 1,0 1 0,0 0 0)),((0 0 0,1 0 0,1 0 1,0 0 1,0 0 0)),((1 1 1,0 1 1,0 0 1,1 0 1,1 1 1)),((1 1 1,1 0 1,1 0 0,1 1 0,1 .5 .5,1 1 1))) Screenshot from 2025-05-21 16-53-30
valid_surface_holes POLYHEDRALSURFACE(((0 0 0,0 1 0,1 1 0,1 0 0,0 0 0),(0.2 0.2 0,0.2 0.5 0,0.5 0.5 0,0.5 0.2 0,0.2 0.2 0)),((0 0 0,0 0 1,0 1 1,0 1 0,0 0 0)),((0 0 0,1 0 0,1 0 1,0 0 1,0 0 0)),((1 1 1,0 1 1,0 0 1,1 0 1,1 1 1)),((1 1 1,1 0 1,1 0 0,1 1 0,1 1 1)),((1 1 1,1 1 0,0 1 0,0 1 1,1 1 1))) Screenshot from 2025-05-21 16-55-21
invalid_surface_non_planar_face POLYHEDRALSURFACE(((0 0 0,1 0 0,0 1 0,0 0 1,0 0 0)),((1 0 0,1 1 0,0 1 0,1 0 0))) Screenshot from 2025-05-21 17-20-01
invalid_surface_collinear_points POLYHEDRALSURFACE(((1 0 0,1 1 0,0 1 0,1 0 0)),((0 0 0,1 0 0,2 0 0,0 0 0))) Screenshot from 2025-05-21 17-10-21
invalid_surface_few_points POLYHEDRALSURFACE(((1 0 0,1 1 0,0 1 0,1 0 0)),((0 0 0,1 0 0,0 0 0))) Screenshot from 2025-05-21 17-11-01
invalid_surface_invalid_intersection_boundary_interior POLYHEDRALSURFACE(((0 0 0,1 0 0,0 0 1,0 0 0)),((0 1 0,0.5 -0.5 0.5,1 1 0,0 1 0))) Screenshot from 2025-05-21 17-11-20
invalid_surface_invalid_intersection_boundary_boundary POLYHEDRALSURFACE(((0 0 0,1 0 0,1 0 1,0 0 1,0 0 0)),((0 1 0,0 -1 1,1 -1 1,1 1 0,0 1 0))) Screenshot from 2025-05-21 17-11-36
invalid_surface_invalid_intersection_in_common_vertex POLYHEDRALSURFACE(((0 0 0,1 0 0,1 0 1,0 0 1,0 0 0)),((0 1 0,1 0 1,1 1 0,0 1 0))) Screenshot from 2025-05-21 17-11-57
invalid_surface_invalid_intersection_partial_edge POLYHEDRALSURFACE(((0 0 0,1 0 0,1 0 1,0 0 1,0 0 0)),((0 1 0,0.5 0 1,1 0 1,1 1 0,0 1 0))) Screenshot from 2025-05-21 17-12-11
invalid_surface_disconnected_polygons POLYHEDRALSURFACE(((0 0 0,1 0 0,0 1 0,0 0 0)),((1 1 0,2 1 0,2 2 0,1 2 0,1 1 0))) Screenshot from 2025-05-21 17-19-31
invalid_surface_invalid_intersection_vertex_edge POLYHEDRALSURFACE(((0 0 0,1 0 0,0 1 0,0 0 0)),((0.5 0.5 0,2 1 0,2 2 0,1 2 0,0.5 0.5 0))) Screenshot from 2025-05-21 17-12-52
invalid_surface_invalid_intersection_vertex_vertex POLYHEDRALSURFACE(((0 0 0,1 0 0,0 1 0,0 0 0)),((1 0 0,2 1 0,2 2 0,1 2 0,1 0 0))) Screenshot from 2025-05-21 17-13-07
invalid_surface_invalid_intersection_parallel_edges POLYHEDRALSURFACE(((0 0 0,1 0 0,0 1 0,0 0 0)),((0 1 0,0.5 0.5 0,1 0 0,2 1 0,2 2 0,1 2 0,0 1 0))) Screenshot from 2025-05-21 17-13-24
invalid_surface_invalid_intersection_operlapping_faces POLYHEDRALSURFACE(((0 0 0,1 0.5 0,0.5 1 0,0 0 0)),((0 1 0,1 0 0,2 1 0,2 2 0,1 2 0,0 1 0))) Screenshot from 2025-05-21 17-13-45
invalid_surface_invalid_intersection_operlapping_faces2 POLYHEDRALSURFACE(((0 0 0,1 0 0,0.5 1 0,0 0 0)),((0 1 0,1 0 0,2 1 0,2 2 0,1 2 0,0 1 0))) Screenshot from 2025-05-21 17-14-04
invalid_surface_invalid_face POLYHEDRALSURFACE(((0 0 0,1 0 0,0 1 0,0 0 0)),((0 1 0,1 0 0,2 2 0,2 1 0,1 2 0,0 1 0))) Screenshot from 2025-05-21 17-14-25
invalid_surface_non_manifold_edge POLYHEDRALSURFACE(((0 0 0,1 0 0,0 1 0,0 0 0)),((0 1 0,1 0 0,2 1 0,2 2 0,1 2 0,0 1 0)),((0 1 0,1 0 0,1 1 1,0 1 0))) Screenshot from 2025-05-21 17-14-43

Two unit tests are failing and are commented out. Those are dependent on https://github.com/boostorg/geometry/issues/1406

vissarion avatar May 21 '25 14:05 vissarion

Looks great! I will review it next Wednesday or Thursday.

barendgehrels avatar May 26 '25 16:05 barendgehrels

@tinko92 thanks for the comments. I fixed all but the ones about tolerance and the strategy. I need to think of a unified and consistent solution for those.

vissarion avatar May 28 '25 12:05 vissarion

Looks great! I will review it next Wednesday or Thursday.

I will continue tomorrow. It looks good but I had many suggestions already...

barendgehrels avatar May 28 '25 13:05 barendgehrels

Looks great! I will review it next Wednesday or Thursday.

I will continue tomorrow. It looks good but I had many suggestions already...

So I didn't continue tomorrow - but great that you processed our comments! Thanks! I plan now to continue this weekend.

barendgehrels avatar Jun 04 '25 18:06 barendgehrels

I refactor the code addressing almost all of the comments. Some things are left as todo for next PR(s). What is missing from this PR is the predicates (places in the code that use tolerance) that should be written as orientation checks implemented in strategies. I will work on it in the next days.

vissarion avatar Jun 04 '25 19:06 vissarion

@barendgehrels thanks for you comments! I addressed most of them. I need to work more on this PR. Apart from the orient3d some other simplifications can be implemented (the unaddressed comments of Barend are related to those simplifications). I will work on it next week.

vissarion avatar Jun 12 '25 15:06 vissarion

I have updated this PR. Now strategies are used (with 2d and 3d orientation predicates) and there are no constructions on new geometries apart from coordinate projections (that are not that vulnerable to numerical errors). Also a new algorithm for segment-polygon intersection in 3D that only uses orientation predicates is implemented.

vissarion avatar Jul 10 '25 14:07 vissarion

Cool changes, thanks for the splits - I'll try to finish my review this weekend

barendgehrels avatar Jul 10 '25 18:07 barendgehrels

Thanks for your reviews! I addressed all the comments. (However, I think @barendgehrels didn't finish his review yet)

vissarion avatar Jul 16 '25 13:07 vissarion

Thanks for the quick response. The latest force push broke b2 test, looks like a missing git add test/geometries/polyhedral_surface_fail.cpp.

tinko92 avatar Jul 17 '25 03:07 tinko92