[{"data":1,"prerenderedAt":360},["ShallowReactive",2],{"algo-fast-and-exact-mesh-booleans-and-arrangements":3},{"id":4,"title":5,"author":6,"body":7,"date":332,"description":333,"extension":334,"keywords":335,"meta":350,"navigation":351,"path":352,"published":351,"seo":353,"stem":354,"tags":355,"__hash__":359},"algorithms\u002Falgorithms\u002Ffast-and-exact-mesh-booleans-and-arrangements.md","Fast and Exact Mesh Booleans and Arrangements","Žiga Sajovic",{"type":8,"value":9,"toc":305},"minimark",[10,14,18,22,30,36,41,44,49,52,56,62,66,69,73,76,88,92,95,99,106,109,112,116,119,123,129,132,136,139,143,146,150,157,161,164,168,171,175,179,183,192,196,201,206,210,213,234,238,241,245,249,252,256,260,263,267,278,301],[11,12,13],"p",{},"Mesh arrangements decompose overlapping geometry into classified regions — splitting faces along intersection curves so every face belongs to exactly one region. Mesh booleans select which regions to keep: union, intersection, difference.",[15,16],"article-cta",{":buttons":17},"[{\"label\":\"trueform\",\"to\":\"\u002Ftrueform\",\"icon\":\"i-lucide-cpu\",\"variant\":\"soft\",\"color\":\"neutral\"},{\"label\":\"GitHub\",\"to\":\"https:\u002F\u002Fgithub.com\u002Fpolydera\u002Ftrueform\",\"icon\":\"i-simple-icons-github\",\"variant\":\"soft\",\"color\":\"neutral\"},{\"label\":\"Documentation\",\"to\":\"https:\u002F\u002Ftrueform.polydera.com\",\"variant\":\"soft\",\"color\":\"neutral\"},{\"label\":\"Try it live\",\"to\":\"https:\u002F\u002Ftrueform.polydera.com\u002Flive-examples\u002Fboolean\",\"icon\":\"i-lucide-play\"}]",[19,20],"headline-numbers",{":items":21},"[{\"value\":\"7ms\",\"label\":\"Intersection curves\",\"detail\":\"2×1M polygons · 233× CGAL\"},{\"value\":\"28ms\",\"label\":\"Boolean union\",\"detail\":\"2×1M polygons · 6× MeshLib · 84× CGAL\"},{\"value\":\"173ms\",\"label\":\"Polygon arrangements\",\"detail\":\"2×1M polygons · 32× libigl\"}]",[11,23,24,25,29],{},"Real meshes are not ideal manifolds. They carry non-manifold flaps, inconsistent winding, coplanar faces, and accumulated pipeline artifacts. ",[26,27,28],"code",{},"trueform"," handles all of them.",[31,32],"data-table",{":headers":33,":highlight":34,":rows":35},"[\"Feature\",\"Handling\"]","0","[[\"Convex polygons\",\"Native — not limited to triangles\"],[\"Non-manifold edges\",\"Handled directly\"],[\"Inconsistent winding\",\"Bayesian classifiers per manifold edge-connected component\"],[\"Self-intersecting input\",\"Resolved via polygon arrangements\"],[\"Coplanar primitives\",\"Resolved via topological exactness — aligned\u002Fopposing boundary classification\"],[\"Hole cuts\",\"Hole patching into the face\"],[\"Contour crossings\",\"Resolved via indirect predicates\"]]",[37,38,40],"h2",{"id":39},"exactness","Exactness",[11,42,43],{},"Two kinds of exactness matter in mesh arrangements: geometric and topological.",[45,46,48],"h3",{"id":47},"geometric-exactness","Geometric exactness",[11,50,51],{},"Input coordinates are scaled to exact integer space. All predicates — orientation tests, intersection points, determinants — are computed with exact integer arithmetic through a precision chain. No floating-point operation participates in any geometric decision.",[31,53],{":headers":54,":highlight":34,":rows":55},"[\"\",\"Coordinates\",\"Intermediate\",\"Predicates\"]","[[\"int32 base (default)\",\"int32\",\"int64\",\"int128\"],[\"int64 base (extended)\",\"int64\",\"int128\",\"int256 (custom)\"]]",[11,57,58,61],{},[26,59,60],{},"orient3d_sign"," returns −1, 0, or +1 — exactly. Zero means coplanar, not \"close to coplanar.\"",[45,63,65],{"id":64},"topological-exactness","Topological exactness",[11,67,68],{},"An intersection point can land on a vertex, on an edge, or at the meeting point of two coplanar edges. Five distinct configurations:",[31,70],{":headers":71,":highlight":34,":rows":72},"[\"Type\",\"Configuration\",\"Resolution\"]","[[\"EF\",\"Edge pierces face\",\"Signed volume ratios\"],[\"EE\",\"Coplanar edge crossing\",\"2D orient2d on projected plane\"],[\"VE\",\"Vertex on edge\",\"orient2d + between test\"],[\"VF\",\"Vertex in face interior\",\"2D winding test\"],[\"VV\",\"Coincident vertices\",\"Exact coordinate match\"]]",[11,74,75],{},"Geometric exactness without topological exactness is typically paired with Simulation of Simplicity (SoS). SoS perturbs input so all configurations collapse to EF — deterministic but arbitrary. A square placed into a cube with edges on faces might produce no intersections, partial, or all, depending on perturbation order. These configurations are not edge cases to avoid — they define contour crossings in multi-mesh arrangements.",[11,77,78,80,81,83,84,87],{},[26,79,28],{}," classifies all five exactly — ",[26,82,60],{}," separates coplanar from non-coplanar, ",[26,85,86],{},"orient2d_sign"," resolves the coplanar cases. Each configuration is resolved to its canonical form.",[37,89,91],{"id":90},"arrangements","Arrangements",[11,93,94],{},"Arrangements resolve multiple mutually intersecting meshes simultaneously.",[45,96,98],{"id":97},"indirect-predicates","Indirect predicates",[11,100,101,102,105],{},"An intersection edge is defined by its originating face pair. An intersection point between two edges is defined by the union of their face pair IDs — a unique triplet of three faces. This identifies points topologically, avoiding geometric ambiguity. Coordinates are computed from the triplet via ",[26,103,104],{},"orient2d","-based interpolation in integer arithmetic, only when needed.",[107,108],"algo-arrangement-diagram",{},[11,110,111],{},"Indirect predicates allow the arrangement to be formulated in two stages: compute pairwise intersection contours between all mesh pairs, then intersect those contours within each face.",[45,113,115],{"id":114},"stage-1-pairwise-intersection-contours","Stage 1: pairwise intersection contours",[11,117,118],{},"An AABB tree narrows candidates to overlapping face pairs. For each pair, intersections are computed exactly. Each intersection produces an edge on both faces, tagged with its originating face pair.",[45,120,122],{"id":121},"stage-2-per-face-contour-intersections","Stage 2: per-face contour intersections",[11,124,125,126,128],{},"Each intersected face carries a small number of edges from different mesh pairs — typically 2–5. These are projected to the face plane and intersected with topological exactness: VV, VE, and EE configurations classified via ",[26,127,104],{},". The result is an intersection graph embedded in the face, defining how it will be split.",[11,130,131],{},"Each face has few edges — trivial to process. Each face is independent — all processed in parallel. Points are identified across faces via their triplets.",[37,133,135],{"id":134},"booleans","Booleans",[11,137,138],{},"A boolean is an arrangement with a classification step. After splitting faces along intersection curves, each resulting face must be labeled as inside or outside the other mesh. The boolean operation selects which labels to keep.",[45,140,142],{"id":141},"components","Components",[11,144,145],{},"Faces are grouped into manifold edge-connected components. Two faces belong to the same component if they share a manifold edge that is not an intersection edge. Non-manifold edges and intersection edges act as barriers — they prohibit crossing between components. Each component receives a single label.",[45,147,149],{"id":148},"wedge-classification","Wedge classification",[11,151,152,153,156],{},"For each intersection edge in a component, the two same-mesh faces sharing that edge form a wedge. A test point from the opposite-mesh neighbor is classified against this wedge using exact ",[26,154,155],{},"orient3d",":",[31,158],{":headers":159,":highlight":34,":rows":160},"[\"Result\",\"Meaning\",\"Vote\"]","[[\"on_negative_side\",\"Test point inside wedge\",\"inside\"],[\"on_positive_side\",\"Test point outside wedge\",\"outside\"],[\"on_boundary\",\"Coplanar — skip\",\"—\"]]",[11,162,163],{},"Coplanar face pairs are classified directly as aligned or opposing boundary based on normal direction.",[45,165,167],{"id":166},"bayesian-classification","Bayesian classification",[11,169,170],{},"Each intersection edge contributes an observation to its component — inside or outside. The per-component label is determined by a Beta-Bernoulli classifier over these observations: inside, outside, aligned boundary, or opposing boundary. Components with no intersection edges fall back to signed distance or ray-based containment tests.",[45,172,174],{"id":173},"operation-mapping","Operation mapping",[31,176],{":headers":177,":highlight":34,":rows":178},"[\"Operation\",\"Keep from A\",\"Keep from B\"]","[[\"Union\",\"outside + aligned boundary\",\"outside\"],[\"Intersection\",\"inside + aligned boundary\",\"inside\"],[\"Difference\",\"outside + opposing boundary\",\"inside\"]]",[37,180,182],{"id":181},"mesh-boolean-comparison","Mesh boolean comparison",[11,184,185,186,188,189,191],{},"Four libraries are commonly used for mesh booleans: ",[26,187,28],{},", CGAL, libigl, and MeshLib. ",[26,190,28],{}," is the fastest mesh boolean library available. Exact arithmetic, canonical topology. It is the only one that handles non-manifold edges, inconsistent winding, and N-mesh arrangements without preprocessing.",[45,193,195],{"id":194},"capabilities","Capabilities",[31,197],{":headers":198,":highlight":199,":rows":200},"[\"Feature\",\"trueform\",\"MeshLib\",\"CGAL\",\"libigl\"]","1","[[\"Convex polygons\",\"✓\",\"Triangles\",\"✓\",\"Triangles\"],[\"Non-manifold edges\",\"✓\",\"Auto-deletes\",\"Requires manifold\",\"Requires manifold\"],[\"Inconsistent winding\",\"Bayesian\",\"✗\",\"✗\",\"✗\"],[\"Self-intersecting input\",\"✓\",\"Limited\",\"✓\",\"✓\"],[\"Coplanar primitives\",\"Exact\",\"SoS\",\"Kernel-dep.\",\"EPECK\"],[\"Hole cuts\",\"✓\",\"✗\",\"✓\",\"✓\"],[\"N-mesh arrangements\",\"✓\",\"✗\",\"✗\",\"✗\"],[\"Curve extraction\",\"Standalone\",\"✗\",\"Indirect\",\"Indirect\"]]",[11,202,203,205],{},[26,204,28],{}," is a robust CGAL alternative with real-time performance. A mesh boolean library available in C++, Python, and TypeScript, providing exact results on non-ideal input at interactive speed.",[45,207,209],{"id":208},"performance","Performance",[11,211,212],{},"Stanford Dragon at varying resolutions. Linear scaling is maintained through 2M+ polygons.",[11,214,215,221,222,221,226,221,230],{},[216,217,220],"span",{"className":218},[219],"tag-pill","Apple M4 Max"," ",[216,223,225],{"className":224},[219],"16 threads",[216,227,229],{"className":228},[219],"Clang -O3",[216,231,233],{"className":232},[219],"mimalloc",[45,235,237],{"id":236},"boolean-union","Boolean union",[11,239,240],{},"trueform uses exact predicates and canonical topology. MeshLib uses SoS with int32. CGAL uses EPIC kernel. libigl uses EPECK (GMP).",[31,242],{":headers":243,":highlight":199,":rows":244},"[\"Polygons\",\"trueform\",\"MeshLib\",\"CGAL\",\"libigl\"]","[[\"2 × 58K\",\"6.4 ms\",\"14.9 ms\",\"133 ms\",\"588 ms\"],[\"2 × 142K\",\"9.0 ms\",\"25.1 ms\",\"329 ms\",\"1225 ms\"],[\"2 × 244K\",\"12.4 ms\",\"54.4 ms\",\"573 ms\",\"1973 ms\"],[\"2 × 481K\",\"16.8 ms\",\"124.7 ms\",\"1082 ms\",\"3666 ms\"],[\"2 × 723K\",\"22.7 ms\",\"112.1 ms\",\"1746 ms\",\"5703 ms\"],[\"2 × 1.03M\",\"27.8 ms\",\"161.5 ms\",\"2339 ms\",\"7735 ms\"]]",[45,246,248],{"id":247},"polygon-arrangements","Polygon arrangements",[11,250,251],{},"Two copies concatenated into a single self-intersecting mesh. MeshLib not benchmarked — refuses nested contour crossings.",[31,253],{":headers":254,":highlight":199,":rows":255},"[\"Polygons\",\"trueform\",\"libigl\"]","[[\"117K\",\"12.7 ms\",\"642 ms\"],[\"284K\",\"27.0 ms\",\"1205 ms\"],[\"488K\",\"42.4 ms\",\"1785 ms\"],[\"962K\",\"78.1 ms\",\"2907 ms\"],[\"1.45M\",\"128.4 ms\",\"4382 ms\"],[\"2.05M\",\"173.2 ms\",\"5509 ms\"]]",[45,257,259],{"id":258},"intersection-curves","Intersection curves",[11,261,262],{},"Standalone extraction of crossing polylines. Most SDKs only provide curves as a side-effect of a full boolean operation.",[31,264],{":headers":265,":highlight":199,":rows":266},"[\"Polygons\",\"trueform\",\"CGAL\"]","[[\"2 × 58K\",\"2.3 ms\",\"86.9 ms\"],[\"2 × 142K\",\"3.4 ms\",\"230.7 ms\"],[\"2 × 244K\",\"4.1 ms\",\"416.7 ms\"],[\"2 × 481K\",\"5.4 ms\",\"777.1 ms\"],[\"2 × 723K\",\"7.0 ms\",\"1266.8 ms\"],[\"2 × 1.03M\",\"7.3 ms\",\"1695.6 ms\"]]",[11,268,269,270,277],{},"Interactive charts, full methodology, and source code: ",[271,272,276],"a",{"href":273,"rel":274},"https:\u002F\u002Ftrueform.polydera.com\u002Fcpp\u002Fbenchmarks",[275],"nofollow","trueform benchmarks",".",[11,279,280,285,286,285,291,285,296],{},[271,281,284],{"href":282,"rel":283},"https:\u002F\u002Ftrueform.polydera.com\u002Flive-examples\u002Fboolean",[275],"Try it live"," · ",[271,287,290],{"href":288,"rel":289},"https:\u002F\u002Ftrueform.polydera.com",[275],"Documentation",[271,292,295],{"href":293,"rel":294},"https:\u002F\u002Fgithub.com\u002Fpolydera\u002Ftrueform",[275],"GitHub",[271,297,300],{"href":298,"rel":299},"https:\u002F\u002Flunar.polydera.com",[275],"Open Lunar",[302,303],"cite-as",{"author":304,"title":5},"Sajovic, {\\v{Z}}iga",{"title":306,"searchDepth":307,"depth":307,"links":308},"",2,[309,314,319,325],{"id":39,"depth":307,"text":40,"children":310},[311,313],{"id":47,"depth":312,"text":48},3,{"id":64,"depth":312,"text":65},{"id":90,"depth":307,"text":91,"children":315},[316,317,318],{"id":97,"depth":312,"text":98},{"id":114,"depth":312,"text":115},{"id":121,"depth":312,"text":122},{"id":134,"depth":307,"text":135,"children":320},[321,322,323,324],{"id":141,"depth":312,"text":142},{"id":148,"depth":312,"text":149},{"id":166,"depth":312,"text":167},{"id":173,"depth":312,"text":174},{"id":181,"depth":307,"text":182,"children":326},[327,328,329,330,331],{"id":194,"depth":312,"text":195},{"id":208,"depth":312,"text":209},{"id":236,"depth":312,"text":237},{"id":247,"depth":312,"text":248},{"id":258,"depth":312,"text":259},"2026-04-20","Fastest mesh boolean library. Exact. Arrangements, booleans, and self-intersection resolution at interactive speeds on million-polygon meshes. 6× faster than MeshLib, 84× faster than CGAL. Available in C++, Python, and TypeScript.","md",[336,337,338,339,340,341,342,343,344,345,346,347,348,349],"fast mesh boolean","fastest mesh boolean","real-time mesh boolean","exact mesh boolean","mesh boolean library","CGAL alternative","mesh boolean comparison","mesh self-intersection","mesh arrangement algorithm","multi mesh arrangements","exact geometry processing","python mesh boolean","typescript mesh boolean","javascript mesh boolean",{},true,"\u002Falgorithms\u002Ffast-and-exact-mesh-booleans-and-arrangements",{"title":5,"description":333},"algorithms\u002Ffast-and-exact-mesh-booleans-and-arrangements",[356,357,358,134,90],"topology","exact-arithmetic","parallel","E-Qv6IE_XSMG1hMFA5adGjsIA81Ur8hHA3z5xsO-YeU",1779353828807]