Repository navigation
feat(booleans): union and intersection of planar polyhedra, with containment - #58
Merged
Merged
Conversation
New creating tests cover crossing, nested, touching and non-convex pairs of flat-faced solids. Union and intersection of the crossing and non-convex pairs are refused today with CoverageGap, and subtracting a box that stands on a turned cuboid fails with InvalidTopology, so those tests are red. The nested turned boxes, the crossing-gable subtraction and the edge-only and corner-only contacts pass as guards: touching bodies union into two separate solids and intersect into an empty body through generic_non_intersecting_boolean, and their subtraction leaves the host unchanged. The multi-tool failure test now uses a tilted cylinder, whose union stays refused. The rotated-box matrix test now expects both rows to build through boolean_planar_polyhedra, and the step oracle expects 17 exported rows; both are red until the change and its fixture update land.
The general planar handler takes the operation. Host pieces are kept outside the other body for union and subtraction and inside it for intersection; cutter pieces are kept outside for union and inside for the other two, and are turned inside out only for subtraction. Union and intersection run under the new handler name boolean_planar_polyhedra; subtraction keeps subtract_planar_polyhedra and its results. The report carries the real operation. The rotated-box union and intersection matrix rows now build; their stored results and golden keys are rewritten from this kernel, and the golden hashes of the handler-name sets gain the new name.
Coplanar faces of the two bodies that face the same way become one coincident face naming the input faces of both bodies; faces of one body in one plane stay apart. Bodies that touch only at edges or corners, or dip into each other by less than the tolerance, are contact: their union is left to the non-intersecting route as before, and their intersection is the empty body that route builds for separate bodies. A body standing on a face unites into one solid, and subtracting it leaves the host whole: the convex shortcut makes no cut on a face the cutter lies wholly outside of. An arrangement that cannot close a cell below the classification tolerance is a coverage gap for union and intersection, so the generic route runs; subtraction keeps its error.
The migration guide gains an Unreleased entry: union and intersection of planar solids now build, how touching bodies behave, and the changed families of a planar refusal. Node tests check a crossing gable pair and a turned cube through the SDK.
When the host lies inside the tool and touches it on a face, an edge or a corner, every host piece is removed and the planar handler threw CoverageGap. The result is empty.
Faces of a polyhedron whose points are turned about a slanted axis can be parallel except for a normal cross product of about 1e-16. The plane intersection either failed with a singular system or returned a line far outside both faces, so a solid wholly inside another threw UnresolvedIntersection. Planes whose normals differ by a sine of at most 1e-11 are now parallel: coincident or apart by their distance.
The generic route for bodies whose boundaries do not cross tested a point moved inward from one face of each body. When the other body lay closer to that face than the step, the point fell inside it and both bodies looked inside each other. A point on one body's boundary, away from any contact, is inside or outside the other body, and that decides the containment.
One boundary point decides containment only for a body with one shell. A body with a cavity, or with several separate solids, can have shells on both sides of the other body, and the generic route then built a wrong result. Each shell now gives its own side; when they differ the route refuses, and a later handler may still build the pair.
The containment route sampled every shell in the topology, open sheets included, so a sheet could pass as a solid and a later subtraction indexed past the end of the solids. Shells now come from the solids only. Subtracting a contained body made a cavity from its last solid only and put it into the first solid of the host. Every solid of the contained body now becomes a cavity of the host solid that holds it; a contained body with a cavity of its own is refused.
The material left inside each cavity of the cutter becomes its own solid, and each cavity goes to the innermost solid that holds it.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Union and intersection of planar polyhedra, with the containment cases a building model needs:
Why
Floorkit's roof joins (valleys kept as true edges) and its seam unions need planar union and intersection of non-box solids.
Tests
fc2caf8), then the implementation.main/opengeometry-three/tests/node/planar-booleans.test.mjs.cargo test945 passed, 1 ignored, 0 failed; kernel node tests 319 of 319.Note
This PR and #59 both start from
main. They conflict inboolean/dispatch/table.rsand in the golden fixturetests/fixtures/golden/aarch64-apple-darwin.json. The second one to merge needs those two files resolved and the golden fixture regenerated.