linkcad.libgraph
High-performance boolean geometry engine for polygon operations. Wraps the native libgraph library.
from linkcad.v1.libgraph import ( ShapeProcessor, ShapeGroup, Operation, FillRule, HolesMode, Result, boolean_and, boolean_or, boolean_xor, boolean_difference, succeeded, failed,)Convenience Functions
For simple two-polygon operations, use these functions directly. Each accepts vertex lists as sequences of (x, y) tuples and returns a list of result polygons (each a list of (x, y) tuples). They raise RuntimeError if the operation fails.
from linkcad.v1.libgraph import boolean_and, boolean_or, boolean_xor, boolean_difference
square = [(0, 0), (10, 0), (10, 10), (0, 10)]triangle = [(5, 5), (15, 5), (10, 15)]
result = boolean_and(square, triangle) # intersectionresult = boolean_or(square, triangle) # unionresult = boolean_xor(square, triangle) # exclusive ORresult = boolean_difference(square, triangle) # square minus triangle| Function | Description |
|---|---|
boolean_and(vtx1, vtx2, fill_rule=FillRule.EvenOdd) | Intersection of two polygons |
boolean_or(vtx1, vtx2, fill_rule=FillRule.EvenOdd) | Union of two polygons |
boolean_xor(vtx1, vtx2, fill_rule=FillRule.EvenOdd) | Symmetric difference of two polygons |
boolean_difference(vtx1, vtx2, fill_rule=FillRule.EvenOdd) | Difference — regions in vtx1 but not vtx2 |
Coordinates are integers. If your geometry is in database units, that is already the case.
ShapeProcessor
For multi-polygon operations, or when you need control over the fill rule and hole handling, use ShapeProcessor:
from linkcad.v1.libgraph import ( FillRule, HolesMode, Operation, ShapeGroup, ShapeProcessor, succeeded,)
sp = ShapeProcessor()sp.add_polygon(ShapeGroup.A, [(0, 0), (10, 0), (10, 10), (0, 10)])sp.add_polygon(ShapeGroup.B, [(5, 5), (15, 5), (10, 15)])
result = sp.execute(Operation.And, FillRule.NonZero, HolesMode.Link)if not succeeded(result): raise RuntimeError(f"Boolean failed: {result}")
polygons = []while sp.has_next_polygon(): poly = sp.get_next_polygon() if poly is None: break polygons.append(poly)| Property / Method | Description |
|---|---|
ShapeProcessor(granularity=1) | Create a new processor |
sp.add_polygon(group, vertices, combine_with_previous=False) | Add a polygon to group A, B, or AB. Returns an internal shape ID |
sp.execute(operation, fill_mode=FillRule.NonZero, hole_mode=HolesMode.Link, process_vertically=False) | Run the operation; returns a Result |
sp.has_next_polygon() | Whether more result polygons are available |
sp.get_next_polygon() | Next result polygon, or None when exhausted |
sp.get_next_hole() | Next hole of the current polygon, or None. Only meaningful with HolesMode.Extract |
sp.clear() | Discard all polygons and prepare for reuse |
sp.empty | True if the processor holds no polygons |
sp.set_license(license) | Set a license key; returns True if valid |
execute() returns a Result; there is no sp.result attribute. Test it with the module-level helpers:
| Function | Description |
|---|---|
succeeded(result) | True for SuccessModified or SuccessNotModified |
failed(result) | True for any error result |
Set combine_with_previous=True on add_polygon() to attach a sub-path — a hole, or a second contour — to the polygon added just before it.
Enums
ShapeGroup
Determines which operand a polygon belongs to.
| Value | Description |
|---|---|
ShapeGroup.A | First operand |
ShapeGroup.B | Second operand |
ShapeGroup.AB | Belongs to both operands simultaneously |
Operation
The boolean operation to perform.
| Value | Description |
|---|---|
Operation.Or | Union (A ∪ B) |
Operation.And | Intersection (A ∩ B) |
Operation.Xor | Symmetric difference (A △ B) |
Operation.AMinusB | Difference (A − B) |
Operation.BMinusA | Difference (B − A) |
Operation.SplitOnB | Split the polygons in A along the boundary of B |
Operation.Noop | Simplify the polygons in A without combining them |
Operation.KeepInternalEdges | Union while keeping internal edges |
Operation.OrNoMerge | Union without merging internal edges |
Operation.AndNoMerge | Intersection without merging internal edges |
Operation.XorNoMerge | XOR without merging internal edges |
Operation.AMinusBNoMerge | A − B without merging internal edges |
Operation.BMinusANoMerge | B − A without merging internal edges |
FillRule
Controls how overlapping polygon edges determine “inside” versus “outside”.
| Value | Description |
|---|---|
FillRule.NonZero | Non-zero winding rule |
FillRule.EvenOdd | Even-odd rule (fastest) |
FillRule.NonZeroGroup | Non-zero winding rule applied per group |
FillRule.EvenOddGroup | Even-odd rule applied per group |
FillRule.OuterGroup | Fill only the outermost area |
HolesMode
Controls how holes in output polygons are represented.
| Value | Description |
|---|---|
HolesMode.Extract | Return holes separately, via get_next_hole() |
HolesMode.Link | Connect holes to the outer boundary with zero-width bridges |
HolesMode.Split | Split the result into simple polygons with no holes |
HolesMode.Keep | Keep holes as separate polygons |
Result
Status returned by ShapeProcessor.execute().
| Value | Description |
|---|---|
Result.SuccessModified | Succeeded; the geometry changed |
Result.SuccessNotModified | Succeeded; the geometry was already in the requested form |
Result.Failed | Operation failed |
Result.Cancelled | Operation was cancelled |
Result.NoLicense | Invalid license key |
Result.InvalidFillRule | Fill rule not valid for this operation |
Result.InvalidHolesMode | Holes mode not valid for this operation |