circle_packing
pleat.circle_packing ¶
Discrete circle packing for half-edge graphs.
Implements Collins-Stephenson radii iteration on a triangulated half-edge graph, producing a circle packing whose combinatorics match the input. Two public entry points:
- :func:
pack_euclidean: euclidean packing with prescribed boundary radii. - :func:
pack_hyperbolic: maximal circle packing in the Poincaré disk.
Both functions require triangulated, simply-connected (disk topology) input
and raise :class:ValueError otherwise. Numerical non-convergence raises
:class:ConvergenceError.
The output is a fresh :class:EuclideanPositionHEG (copy of the input by
default; pass copy_graph=False to mutate in place) with:
v['pos']: euclidean center of the circle (complex for hyperbolic output, 2D real array for euclidean output).v['radius']: euclidean radius of the circle.
The "natural euclidean" mode (maximal packing transferred to euclidean geometry) is obtained by composition::
G_natural = pack_hyperbolic(G).convert_to_euclidean()
ConvergenceError ¶
Bases: RuntimeError
Raised when the radii iteration fails to reach the requested tolerance.
boundary_angles_from_positions ¶
Sum the incident-triangle angles at each boundary vertex from v['pos'].
For a flat triangulated tiling these angles automatically satisfy
Σ_bdy θ = π(F − 2 V_int) (Gauss-Bonnet), making the result a valid
input for :func:pack_euclidean in angle-prescribed mode. Suitable for
matching a packing's combinatorics-shape to an existing flat tiling.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
G
|
EuclideanPositionHEG
|
Half-edge graph with |
required |
Returns:
| Type | Description |
|---|---|
dict[Vertex, float]
|
Mapping from each boundary vertex to its total incident-triangle angle. |
Source code in pleat/circle_packing.py
pack_euclidean ¶
pack_euclidean(
G: EuclideanPositionHEG,
boundary_radii: (
float
| Mapping[Vertex, float]
| Callable[[Vertex], float]
| None
) = None,
*,
boundary_angles: (
float
| Mapping[Vertex, float]
| Callable[[Vertex], float]
| str
| None
) = None,
alpha: Vertex | None = None,
beta: Vertex | None = None,
tol: float = 1e-10,
max_iter: int = 10000,
copy_graph: bool = True
) -> EuclideanPositionHEG
Compute a euclidean circle packing with prescribed boundary data.
The boundary can be pinned in one of two ways (mutually exclusive):
boundary_radii: fix each boundary vertex's radius; iterate only interior vertices toward angle sum 2π. This is the classical euclidean boundary-value problem.boundary_angles: fix each boundary vertex's total incident-triangle angle; iterate every vertex (boundary and interior). For a flat input tiling pass"from_positions"to read the angles off the input positions. The angles must satisfy Gauss-Bonnet:Σ_bdy θ = π(F − 2 V_int).
If neither is given, defaults to boundary_radii=1.0.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
G
|
EuclideanPositionHEG
|
Triangulated, simply-connected disk EuclideanPositionHEG. |
required |
boundary_radii
|
float | Mapping[Vertex, float] | Callable[[Vertex], float] | None
|
Per-vertex boundary radii. Accepts a positive scalar (uniform), Mapping[Vertex, float], or callable Vertex -> float. |
None
|
boundary_angles
|
float | Mapping[Vertex, float] | Callable[[Vertex], float] | str | None
|
Per-vertex boundary angle sums in (0, 2π). Accepts
a scalar (uniform), Mapping, callable, or the string
|
None
|
alpha
|
Vertex | None
|
Optional anchor vertex (placed at origin). Defaults to the interior vertex with maximum graph-distance to the boundary. |
None
|
beta
|
Vertex | None
|
Optional second anchor (placed on +x axis through alpha). |
None
|
tol
|
float
|
Max permitted angle defect over iterated vertices. |
1e-10
|
max_iter
|
int
|
Maximum Collins-Stephenson iterations. |
10000
|
copy_graph
|
bool
|
If True (default), the input graph is copied. |
True
|
Returns:
| Type | Description |
|---|---|
EuclideanPositionHEG
|
EuclideanPositionHEG with EuclideanGeometry, |
EuclideanPositionHEG
|
array centers, and |
Raises:
| Type | Description |
|---|---|
ValueError
|
input not triangulated/disk; both modes specified; boundary_angles violate Gauss-Bonnet; invalid spec values. |
ConvergenceError
|
iteration did not reach |
Source code in pleat/circle_packing.py
654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 | |
pack_hyperbolic ¶
pack_hyperbolic(
G: EuclideanPositionHEG,
boundary_x_radii: (
float
| Mapping[Vertex, float]
| Callable[[Vertex], float]
) = 1.0,
*,
alpha: Vertex | None = None,
beta: Vertex | None = None,
tol: float = 1e-10,
max_iter: int = 10000,
copy_graph: bool = True
) -> EuclideanPositionHEG
Compute a hyperbolic circle packing in the Poincaré disk.
Boundary vertices are assigned the prescribed x-radii (where x = 1 - exp(-2h),
h being the hyperbolic radius); interior x-radii are iterated via
Collins-Stephenson to satisfy hyperbolic angle sum = 2*pi. Setting
boundary_x_radii = 1.0 produces a maximal packing (boundary horocycles).
The output stores the euclidean (Poincaré-disk) representation::
v['pos'] — euclidean center of the circle (complex, inside unit disk)
v['radius'] — euclidean radius of the circle (float)
Two hyperbolic disks are hyperbolically tangent iff their euclidean
representations are euclidean tangent, so adjacent circles satisfy
|c_u − c_v| = r_u + r_v. The intrinsic x-radius of each vertex is
recoverable via :func:_x_radius_from_euclidean (and equals 1 for
boundary horocycles).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
G
|
EuclideanPositionHEG
|
Triangulated, simply-connected disk EuclideanPositionHEG. |
required |
boundary_x_radii
|
float | Mapping[Vertex, float] | Callable[[Vertex], float]
|
Per-vertex boundary x-radii in (0, 1]. Accepts a
scalar (uniform), Mapping, or callable. Defaults to 0.5; pass
|
1.0
|
alpha
|
Vertex | None
|
Optional anchor vertex (placed at Poincaré disk origin). Must be interior. Defaults to the interior vertex with max graph-distance to the boundary. |
None
|
beta
|
Vertex | None
|
Optional second anchor (placed on +x axis through alpha). |
None
|
tol
|
float
|
Max angle defect over interior vertices. |
1e-10
|
max_iter
|
int
|
Max Collins-Stephenson iterations. |
10000
|
copy_graph
|
bool
|
If True (default), return a new EHEG; otherwise mutate. |
True
|
Returns:
| Type | Description |
|---|---|
EuclideanPositionHEG
|
EuclideanPositionHEG with PoincareDiskModel geometry. |
Source code in pleat/circle_packing.py
1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 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 | |