half
pleat.half ¶
Half-edge data structure (DCEL) for planar graphs.
This module implements the core data structure used throughout pleat. A half-edge
graph stores topology via HalfEdge, Vertex, and Face objects linked
through rev/nex/pre pointers, with progressive specializations that
add interior angles (InAngleHEG), pluggable geometry (GeometricHEG), and
Euclidean vertex positions (EuclideanPositionHEG).
Class hierarchy::
AttributeObject โ IdObject โ HalfEdge, Vertex, Face
HalfEdgeGraph โ CyclicHalfedgeGraph
HalfEdgeGraph โ InAngleHEG โ GeometricHEG โ EuclideanPositionHEG
AttributeObject ¶
IdObject ¶
Bases: AttributeObject
AttributeObject with an auto-incrementing id attribute per subclass.
Call IdObject.reset_ids() to reset all counters (useful between
independent test runs).
Source code in pleat/half.py
reset_ids
classmethod
¶
Reset id counters.
When called on :class:IdObject itself, clears every counter.
When called on a subclass, resets only that subclass's counter.
Source code in pleat/half.py
HalfEdge ¶
HalfEdge(
rev: HalfEdge | None = None,
nex: HalfEdge | None = None,
pre: HalfEdge | None = None,
orig: Vertex | None = None,
dest: Vertex | None = None,
face: Face | None = None,
)
Bases: IdObject
A directed half-edge in the DCEL.
Each undirected edge is represented by a pair of half-edges linked via
rev. Navigation around a face uses nex / pre; to traverse around a vertex use nex.rev/pre.rev. Border edges have face set to None on the half-edge pointing into the graph.
Attributes:
| Name | Type | Description |
|---|---|---|
rev |
The reverse (twin) half-edge. |
|
nex |
The next half-edge around the same face. |
|
pre |
The previous half-edge around the same face. |
|
orig |
The origin vertex. |
|
dest |
The destination vertex. |
|
face |
The face to the left, or |
Source code in pleat/half.py
Vertex ¶
Bases: IdObject
A vertex in the DCEL.
Links to one arbitrary outgoing half-edge (any_outgoing). All incident
half-edges and faces are reachable via outgoing_iter() and
face_iter().
Source code in pleat/half.py
outgoing_iter ¶
Yield outgoing half-edges in counter-clockwise order around this vertex.
reverse_outgoing_iter ¶
Yield outgoing half-edges in clockwise order around this vertex.
order ¶
incoming_iter ¶
face_iter ¶
true_face_iter ¶
vertex_iter ¶
common_faces_iter ¶
Yield faces incident to both this vertex and other.
on_border ¶
get_outgoing_border ¶
Return the unique outgoing border half-edge, asserting there is exactly one.
Source code in pleat/half.py
combine_with ¶
Merge other's attributes into this vertex (this vertex's values win on conflict).
Source code in pleat/half.py
check_consistency ¶
Assert that outgoing_iter is a finite cycle and incident edges agree on orig/dest.
Source code in pleat/half.py
angle_sum ¶
Return the sum of interior angles at this vertex (excluding border faces).
Face ¶
Bases: IdObject
A face (polygon) in the DCEL.
Links to one arbitrary bounding half-edge (any_side). Iterate
over boundary half-edges with halfedge_iter() and vertices with
vertex_iter().
Source code in pleat/half.py
halfedge_iter ¶
Yield boundary half-edges in counter-clockwise order around this face.
reverse_halfedge_iter ¶
order ¶
__len__ ¶
vertex_iter ¶
face_iter ¶
true_face_iter ¶
on_border ¶
outgoing_edge_at ¶
incoming_edge_at ¶
common_halfedge_iter ¶
Yield half-edges of this face whose reverse lies on other.
Source code in pleat/half.py
common_vertex_iter ¶
common_face_iter ¶
midpoint ¶
Return the (cached) face midpoint, falling back to the vertex centroid.
pseudo_incenter ¶
recompute_lengths_and_angles ¶
Recompute the length and in_angle attributes from current vertex positions.
Source code in pleat/half.py
area ¶
check_consistency ¶
Assert that halfedge_iter is a finite cycle and every boundary edge points back to this face.
Source code in pleat/half.py
HalfEdgeGraph ¶
Topology-only half-edge graph (DCEL).
Stores sets of vertices, halfedges, and faces. Supports
gluing, copying, deletion, subdivision, and consistency checking.
Most methods mutate the graph in-place and return None; use
.copy() first if you need the original.
Source code in pleat/half.py
add_graph ¶
Add all elements of other to this graph (without re-linking topology).
Source code in pleat/half.py
add_vertex ¶
add_vertices ¶
add_face ¶
add_faces ¶
add_halfedge ¶
add_halfedges ¶
delete_face ¶
fill_holes ¶
delete_faces ¶
Delete all faces in fs and any half-edges/vertices they leave dangling.
Source code in pleat/half.py
delete_subset ¶
Delete a mixed collection of faces, half-edges, and vertices, repairing topology.
Accepts individual Face/HalfEdge/Vertex objects or iterables
of them as positional arguments. Border structure is updated; new faces
may be created when an edge cut splits an existing face.
Source code in pleat/half.py
565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 | |
delete_edge ¶
Remove the edge (h, h.rev) and merge its two adjacent faces.
If both sides share the same face, h is required to be a dangling
spike (one endpoint has degree 1).
Source code in pleat/half.py
join_vertex ¶
Remove a degree-2 vertex by merging its two incident edges into one.
Source code in pleat/half.py
join_order_2_boundary_vertices ¶
Simplify the boundary by joining all degree-2 vertices on the boundary.
Source code in pleat/half.py
join_edge ¶
Contract the half-edge h (and its reverse), merging its two endpoints.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
h
|
HalfEdge
|
The half-edge to contract. |
required |
Returns:
| Type | Description |
|---|---|
Vertex
|
The remaining vertex (originally |
Source code in pleat/half.py
subdivide_edge ¶
subdivide_edge(
h: HalfEdge,
copy_edge_attributes: bool = True,
**vertex_attributes: object
) -> tuple[HalfEdge, Vertex]
Insert a new vertex on the edge h, splitting it into two.
A new half-edge h2 is created with h.nex == h2. The reverse
side is split symmetrically.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
h
|
HalfEdge
|
The half-edge to subdivide. |
required |
copy_edge_attributes
|
bool
|
If True, copy the attributes of |
True
|
**vertex_attributes
|
object
|
Attributes to set on the newly inserted vertex. |
{}
|
Returns:
| Type | Description |
|---|---|
HalfEdge
|
|
Vertex
|
( |
Source code in pleat/half.py
subdivide_face ¶
subdivide_face(
f: Face,
v1: Vertex,
v2: Vertex,
**halfedge_attributes: object
) -> tuple[HalfEdge, Face]
Subdivide face f along a new edge from v1 to v2.
Two new half-edges h12 (v1 -> v2) and h21 (v2 -> v1)
are added together with a new face f2 on the h12 side; the
original face f remains on the h21 side.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
f
|
Face
|
The face to subdivide. |
required |
v1
|
Vertex
|
First endpoint of the new edge (must lie on |
required |
v2
|
Vertex
|
Second endpoint of the new edge (must lie on |
required |
**halfedge_attributes
|
object
|
Attributes to set on both new half-edges. |
{}
|
Returns:
| Type | Description |
|---|---|
HalfEdge
|
|
Face
|
|
Source code in pleat/half.py
halfedges_representing_edges ¶
to_networkx_undirected ¶
Return a :class:networkx.Graph of this graph's underlying undirected topology.
get_any_border ¶
Return some border half-edge, caching the result; raise if none exists.
Source code in pleat/half.py
border_edge_iter ¶
Yield border half-edges. For simply connected graphs, in cyclic order.
Source code in pleat/half.py
border_edges ¶
boundary_cycle ¶
Return border half-edges of one boundary component in cyclic order.
Unlike :meth:border_edge_iter, this does not consult the
simply_connected flag โ it always traverses h.nex from
:meth:get_any_border. The returned list contains exactly one
boundary component; if the graph has multiple, only the component
containing the seed edge is returned.
Raises :class:LookupError if the graph has no border.
Source code in pleat/half.py
border_vertex_iter ¶
border_vertices ¶
glue_v2v ¶
glue_v2v(
v1: Vertex | None = None,
v2: Vertex | None = None,
v1_out: HalfEdge | None = None,
v2_out: HalfEdge | None = None,
) -> None
Identify two boundary vertices, merging them into a single vertex.
Either v1 or v1_out must be specified (likewise for v2).
When only the vertex is given, an outgoing border half-edge is found
automatically.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
v1
|
Vertex | None
|
First vertex to merge. |
None
|
v2
|
Vertex | None
|
Second vertex to merge. |
None
|
v1_out
|
HalfEdge | None
|
Outgoing border half-edge at |
None
|
v2_out
|
HalfEdge | None
|
Outgoing border half-edge at |
None
|
Source code in pleat/half.py
glue_e2e ¶
Identify two border half-edges, sewing the boundary together.
e1 and e2 must both lie on the border (or together bound a
single inner face that gets eliminated). Their endpoints are merged
via :meth:glue_v2v.
Source code in pleat/half.py
glue_graph_e2e ¶
close_vertex ¶
Close a boundary corner at v by gluing its two incident border edges.
twocolorable ¶
Return True if every interior vertex has even order (necessary for face 2-coloring).
twocolor_faces ¶
Two-color the faces of the graph.
Each face will get the attribute key set to True or False;
the initial face is labelled True.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
str
|
Attribute name to write the boolean color into. |
'color_key'
|
initial_face
|
Face | None
|
Face to start the BFS from. Defaults to an arbitrary face. |
None
|
Source code in pleat/half.py
execute_edge_instruction ¶
Run a tile-gluing or growth instruction on the border half-edge h.
If instruction is omitted, it is read from h[key] (default key
'instruction').
Source code in pleat/half.py
execute_all_edge_instructions ¶
Execute :meth:execute_edge_instruction on every border half-edge.
show_spring_layout ¶
show_spring_layout(
figsize: tuple[float, float] = (15, 15),
emph_func: "callable | None" = None,
) -> None
Display the underlying undirected graph using NetworkX's spring layout.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
figsize
|
tuple[float, float]
|
Matplotlib figure size. |
(15, 15)
|
emph_func
|
'callable | None'
|
Callable |
None
|
Source code in pleat/half.py
check_consistency ¶
Verify the graph's topology is internally consistent.
Runs the local :meth:check_consistency of every half-edge, vertex,
and face, and additionally verifies that every reference (nex,
pre, rev, orig, dest, face, any_outgoing,
any_side) points to an element registered with this graph.
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If any inconsistency is detected. |
Source code in pleat/half.py
1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 | |
copy ¶
copy(
deepcopy_attributes: bool = False,
return_mappings: bool = False,
) -> "HalfEdgeGraph | tuple[HalfEdgeGraph, tuple[dict, dict, dict]]"
Return an independent copy of this graph.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
deepcopy_attributes
|
bool
|
If True, attribute dicts are deep-copied; otherwise they are shallow-copied. |
False
|
return_mappings
|
bool
|
If True, also return |
False
|
Returns:
| Type | Description |
|---|---|
'HalfEdgeGraph | tuple[HalfEdgeGraph, tuple[dict, dict, dict]]'
|
The copied graph -- a tuple |
Source code in pleat/half.py
1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 | |
delete_attribute ¶
Delete the attribute key from all vertices, half-edges, and faces.
InAngleHEG ¶
InAngleHEG(
angle_sum: float | None = None,
eps: float | None = None,
other: "HalfEdgeGraph | None" = None,
)
Bases: HalfEdgeGraph
Half-edge graph with interior angles and edge lengths.
The angle between e and e.nex is stored in e['in_angle'].
Edge lengths are stored in e['length']. Every non-border half-edge
should carry both attributes.
Create an angle-aware half-edge graph.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
angle_sum
|
float | None
|
Total angle around an interior vertex ( |
None
|
eps
|
float | None
|
Tolerance for angle/length equality. Defaults to |
None
|
other
|
'HalfEdgeGraph | None'
|
Optional graph to copy elements from (forwarded to base). |
None
|
Source code in pleat/half.py
is_tau ¶
delete_edge ¶
Remove edge h and merge the two surrounding interior angles.
close_vertex ¶
Glue together the two border edges incident at v.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
v
|
Vertex
|
Boundary vertex whose two adjacent border edges are to be sewn. |
required |
reverse
|
bool
|
Swaps which side's vertex is kept. |
False
|
Returns:
| Type | Description |
|---|---|
Vertex
|
The vertex that remains after the gluing. |
Source code in pleat/half.py
autoclose_vertex ¶
Close v if its boundary angle sum equals tau; recurse on the new vertex.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
v
|
Vertex
|
Boundary vertex to check. |
required |
reverse
|
bool
|
Forwarded to :meth: |
False
|
recursive
|
bool
|
If True, recurse into the resulting vertex. |
True
|
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If the vertex's angle sum exceeds |
Source code in pleat/half.py
glue_e2e ¶
glue_e2e(
e1: HalfEdge,
e2: HalfEdge,
auto_close: bool = True,
auto_close_recursive: bool = True,
) -> None
Glue e1 to e2 and optionally close any resulting full corners.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
e1
|
HalfEdge
|
First border half-edge. |
required |
e2
|
HalfEdge
|
Second border half-edge. |
required |
auto_close
|
bool
|
If True, automatically close vertices whose interior
angle sum reaches |
True
|
auto_close_recursive
|
bool
|
If True, propagate auto-closing recursively. |
True
|
Source code in pleat/half.py
GeometricHEG ¶
Bases: InAngleHEG
Half-edge graph with a pluggable geometry backend.
The geometry attribute (default :class:EuclideanGeometry) provides
distance, angle, and center_of_mass operations that are
used for position recomputation and length/angle calculations.
Create a graph backed by the given geometry.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
geometry
|
object
|
A geometry backend exposing |
EuclideanGeometry
|
**super_kwargs
|
object
|
Forwarded to :class: |
{}
|
Source code in pleat/half.py
positions_coincide ¶
lengths_equal ¶
glue_graph_e2e ¶
Add graph to self and glue e1 to e2, then recompute positions of new vertices.
Source code in pleat/half.py
join_edge ¶
Contract edge h and place the resulting vertex at the midpoint.
recompute_positions ¶
recompute_positions(
edge_to_start: HalfEdge | None = None,
faces: "set[Face] | None" = None,
) -> None
Recompute vertex positions from edge lengths and interior angles.
Performs a heap-ordered BFS over faces, propagating positions
outward from the edge edge_to_start (whose two endpoints keep
their existing positions). Faces are processed in order of the
smallest accumulated propagation depth, which keeps numerical error
from compounding on the longest paths first.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
edge_to_start
|
HalfEdge | None
|
Non-border half-edge whose endpoints anchor the computation. Defaults to the longest interior edge. |
None
|
faces
|
'set[Face] | None'
|
Iterable of faces to process. Defaults to all faces. |
None
|
Source code in pleat/half.py
1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 | |
construct_next_point ¶
Construct the point c such that angle(a, b, c) == angle and |bc| == length.
Source code in pleat/half.py
recompute_lengths_and_angles ¶
Recompute every length and in_angle attribute from current positions.
Source code in pleat/half.py
get_position_view ¶
get_position_view(
vertices: list[Vertex] | None = None,
return_vertices: bool = True,
position_key: str = "pos",
) -> "np.ndarray | tuple[np.ndarray, list[Vertex]]"
Return a single (N, d) array view of all vertex (and curve) positions.
Mutating the returned array updates the underlying vertex/curve attributes. Useful for vectorized geometric transformations.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
vertices
|
list[Vertex] | None
|
Vertices whose positions to gather. Defaults to all. |
None
|
return_vertices
|
bool
|
If True, also return the list of vertices. |
True
|
position_key
|
str
|
Vertex attribute to read/write. |
'pos'
|
Returns:
| Type | Description |
|---|---|
'np.ndarray | tuple[np.ndarray, list[Vertex]]'
|
|
Source code in pleat/half.py
normalize_positions ¶
Center positions at the origin and rescale so the maximum distance is 1.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
position_key
|
str
|
Vertex attribute to read/write. Defaults to "pos". |
'pos'
|
Source code in pleat/half.py
scale_positions ¶
Multiply every vertex position by factor (Euclidean geometry only).
Source code in pleat/half.py
normalize_edge_lengths ¶
Scale the graph so the average edge length equals factor.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mode
|
str
|
One of |
'geometric'
|
factor
|
float
|
Desired mean edge length after scaling. |
1
|
Source code in pleat/half.py
convert_to_euclidean ¶
Project all positions to the Euclidean plane and switch the geometry backend.
Source code in pleat/half.py
render ¶
render(
render_faces: bool = True,
render_edges: bool = True,
render_vertices: bool = True,
for_cutting: bool = False,
**renderer_kwargs: object
) -> "Rendering"
Render the graph with Cairo and return an in-memory :class:Rendering.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
render_faces
|
bool
|
Whether to draw face fills. |
True
|
render_edges
|
bool
|
Whether to draw edges. |
True
|
render_vertices
|
bool
|
Whether to draw vertex markers. |
True
|
for_cutting
|
bool
|
Reorder edges for a plotter (currently unsupported). |
False
|
**renderer_kwargs
|
object
|
Forwarded to :class: |
{}
|
Returns:
| Name | Type | Description |
|---|---|---|
A |
'Rendering'
|
class: |
Source code in pleat/half.py
show ¶
Render and display the graph (inline in Jupyter, a window in scripts).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
**style
|
object
|
Forwarded to :meth: |
{}
|
save ¶
Render the graph and write it to path.
path with no extension writes both path.svg and path.png.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str
|
Destination path; extension selects the format(s). |
required |
**style
|
object
|
Forwarded to :meth: |
{}
|
Source code in pleat/half.py
central_face ¶
Return the face whose midpoint is closest to the origin (Euclidean only).
Source code in pleat/half.py
central_vertex ¶
Return the vertex closest to the origin (Euclidean only).
Source code in pleat/half.py
EuclideanPositionHEG ¶
Bases: GeometricHEG
GeometricHEG specialized for Euclidean geometry with 2D vertex positions.
Vertices carry pos attributes (numpy arrays of shape (2,)). Provides epsilon-based vertex merging and position-aware graph operations.
Create a Euclidean-geometry half-edge graph.
Source code in pleat/half.py
CyclicHalfedgeGraph ¶
CyclicHalfedgeGraph(
vs: list[Vertex],
inner_hs: list[HalfEdge] | None = None,
outer_hs: list[HalfEdge] | None = None,
f: Face | None = None,
)
Bases: HalfEdgeGraph
A single-face polygon as a half-edge graph.
Constructed from a list of vertices, creating one interior face and a border. Useful as a building block for gluing larger graphs.
Build a single-face cyclic graph from the vertex sequence vs.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
vs
|
list[Vertex]
|
Vertices of the polygon, in cyclic order. |
required |
inner_hs
|
list[HalfEdge] | None
|
Optional pre-existing inner half-edges (one per vertex). |
None
|
outer_hs
|
list[HalfEdge] | None
|
Optional pre-existing outer (border) half-edges. |
None
|
f
|
Face | None
|
Optional pre-existing :class: |
None
|
Source code in pleat/half.py
RegularNGon ¶
Bases: CyclicHalfedgeGraph, InAngleHEG
A regular n-gon as a half-edge graph with positions and angles.
Construct a regular n-gon with interior angle (n-2)/n * pi.
Source code in pleat/half.py
check_cyclic_iterator_consistency ¶
Assert that every item yielded by iterator is unique (no cycles repeat).
Source code in pleat/half.py
pseudo_incenter ¶
Return a face's pseudo-incenter (true incenter for tangential polygons).
For tangential polygons the result is the actual incenter. Otherwise it is the side-length-weighted centroid of the vertices, which is a smooth interior point convenient for label placement.
Source code in pleat/half.py
pseudo_circumcenter ¶
Compute the "best fit" circumcenter of a polygon.
Finds the interior point that minimizes the standard deviation of distances to the vertices.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ps
|
array_like
|
Polygon vertices, shape (N, 2). |
required |
return_radius
|
bool
|
If True, also return the circumradius. |
False
|
Returns:
| Type | Description |
|---|---|
ndarray | tuple[ndarray, float]
|
The circumcenter (shape |
Source code in pleat/half.py
rotate_by ¶
Cyclically rotate list_like by offset positions.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
list_like
|
'list | tuple'
|
Sequence to rotate. |
required |
offset
|
'int | tuple[int, ...]'
|
Either an integer shift, or an iterable of integer shifts in which case the function returns the zip of the corresponding rotations. |
required |
Returns:
| Type | Description |
|---|---|
'list | zip'
|
The rotated list -- a zip iterator over rotations when |
Source code in pleat/half.py
any_element ¶
make_polygon_graph ¶
Create a single-face Euclidean polygon graph from a sequence of 2D positions.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
positions
|
ndarray
|
Iterable of 2D points, in cyclic order around the polygon. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
A |
'EuclideanPositionHEG'
|
class: |