boolean - Boolean cut/intersect/stitch meshes
This modules provide boolean operations for all kind of meshes.
Strictly speaking, boolean operations are operations on mathematically defined sets. In a n-dimensinal space it applies to subsets of point of the same dimension (volumes in 3D, surfaces in 2D). Here, volumes are defined by their exterior envelope (a Mesh) and surfaces by their contour (Web). So the boolean operation consist of intersecting the envelopes and contours and decide which cutted parts to keep.
This relies on a new intersection algorithm named syandana. It finds candidates for intersections using a spacial hashing of triangles over a voxel (see madcad.hashing). This is solving the problem of putting triangles in an octree. Also to avoid the increasing complexity of the operation with flat planes divided in multiple parallel triangles, the algorithm is implemented with a detection of ngons.
The syandana algorithm achieves intersections of meshes in nearly O(n)
where usual methods are O(n**2)
After intersection, the selection of surface sides to keep or not is done through a propagation.
Note
Web boolean operations theoretically means something only in a 2d space, and it takes place in a 3d space here, causing many situations where a web portion can be both inside and outside the contour. The algorithm here works even with meshes that are not planar at all. but it always assumes that the web you give it can be processed consistently as if it was.
Note
Mesh boolean operation is relying on the surface outer normal to decide what is exterior and interior. It’s always a local decision (ie. a decision made at the intersection), So the meshes must be well oriented.
Web boolean operations on the other hand CANNOT be local due to the 3d space it’s laying in. (a higher dimension than the surface it’s theoreticall meant to outline). So it may sometimes not behave the way you expect it. To solve ambiguities of interior and exterior, the most outer part of first mesh argument is always considered to belong to the exterior. And the information is propagated through the web.
Most common
-
pierce
(m, ref, side=False, prec=None)[source] Cut a web/mesh and remove its parts considered inside the
ref
shapeOverloads:
pierce(Mesh, Mesh) -> Mesh pierce(Web, Web) -> Web pierce(Web, Mesh) -> Web
side
decides which part of each mesh to keep- False keeps the exterior part (part exclusive to the other mesh)
- True keeps the interior part (the common part)
Between
Web
(The result is the white part, the green part is theref
parameter)
rect = web(
wire([vec3(-w, -h, 0), vec3(w, -h, 0), vec3(w, h, 0), vec3(-w, h, 0)])
.close()
.segmented()
)
hole = web(Circle((O, Z), 1.5))
result = pierce(rect, hole)
Between Web
and Mesh
:
rect = web(
wire([vec3(-w, -h, 0), vec3(w, -h, 0), vec3(w, h, 0), vec3(-w, h, 0)])
.close()
.segmented()
)
hole = extrusion(4 * Z, Circle((O, Z), 1.5), alignment=0.5)
result = pierce(rect, hole)
Between Mesh
:
rect = flatsurface(
wire([vec3(-w, -h, 0), vec3(w, -h, 0), vec3(w, h, 0), vec3(-w, h, 0)])
)
rect = rect.transform(Z) + rect.transform(-Z).flip()
hole = extrusion(4 * Z, flatsurface(Circle((O, Z), 1.5)).flip(), alignment=0.5)
result = pierce(rect, hole)
-
boolean
(a, b, sides=(False, True), prec=None)[source] Cut two web/mesh and keep its interior or exterior parts
Overloads:
boolean(Mesh, Mesh) -> Mesh boolean(Web, Web) -> Web
sides
decides which part of each mesh to keep- False keeps the exterior part (part exclusive to the other mesh)
- True keeps the common part
Between Web
:
w, h = 2, 1
a = web(
wire([vec3(-w, -h, 0), vec3(w, -h, 0), vec3(w, h, 0), vec3(-w, h, 0)])
.close()
.segmented()
)
b = web(Circle((O, Z), 1.5))
result = boolean(a, b, (False, False))
Between Mesh
:
w, h = 3, 2
rect = flatsurface(
wire([vec3(-w, -h, 0), vec3(w, -h, 0), vec3(w, h, 0), vec3(-w, h, 0)])
)
a = rect.transform(Z) + rect.transform(-Z).flip()
b = extrusion(4 * Z, flatsurface(Circle((O, Z), 1.5)).flip(), alignment=0.5)
result = boolean(a, b, (False, False))
Those are shortcuts for boolean
:
-
union
(a, b) Mesh [source] Return a mesh for the union of the volumes. It is a boolean with selector
(False,False)
More advanced
-
cut_web
(w1: Web, ref: Web, prec=None)[source] Cut the web edges at their intersectsions with the
ref
webReturns: (cutted, frontier)
cutted(Web): is w1
with the edges cutted, but representing the same lines as beforefrontier(Wire): is a Web where edges are the intersection edges, and whose groups are the causing faces in ref
-
cut_web_mesh
(w1: Web, ref: Mesh, prec=None)[source] Cut the web inplace at its intersections with the
ref
web.Returns: (cutted, frontier)
-
cut_mesh
(m1, m2, prec=None)[source] Cut m1 faces at their intersections with m2.
Returns: (cutted, frontier)
cutted(Mesh): is m1
with the faces cutted, but representing the same surface as beforefrontier(Web): is a Web where edges are the intersection edges, and whose groups are the causing faces in m2
Returning the intersection edges in m1 and associated m2 faces. The algorithm is using ngon intersections and retriangulation, in order to avoid infinite loops and intermediate triangles.