Index
pleat.intersecting_cylinders ¶
Intersecting-cylinders curved origami crease patterns.
This subpackage builds curved-fold crease patterns from a tiling whose face
incircles are mutually tangential. The pattern places a small twist at every
face incenter and curved triangles whose flat sides connect adjacent incenters;
each curved triangle's apex meets at an original tiling vertex, where (with
r = 1) a spike is formed. With 0 < r < 1 a flat polygon (dual to the
original vertex) appears instead of the spike, and the curved triangles become
curved quadrilaterals reaching down to it.
The high-level entry point is :func:make_intersecting_cylinders;
cross-sections are described by :class:Profile (see :func:circular_profile);
the flat top-view projection is computed by :func:top_view; an interactive
3D preview is provided by :func:show_3d.
Profile
dataclass
¶
Arc-length-parametrised cross-section curve.
The cross-section is the curve (x, fn(x)) for x in [0, 1], where
fn(0) = 0 and fn is non-negative. Samples are simplified by the
Ramer-Douglas-Peucker algorithm and stored after rescaling so that the
total arc length is 1 (and the perpendicular extent is therefore
shrink_factor = 1 / unscaled_arc_length <= 1).
Attributes:
| Name | Type | Description |
|---|---|---|
t |
NDArray[float64]
|
Perpendicular coordinate, scaled to |
l |
NDArray[float64]
|
Arc length along the curve, scaled to |
y |
NDArray[float64]
|
Height |
shrink_factor |
float
|
|
from_function
classmethod
¶
from_function(
fn: Callable[[NDArray[float64]], NDArray[float64]],
n_samples: int = 1000,
rdp_tol: float = 0.0001,
) -> "Profile"
Build a :class:Profile from a height function fn on [0, 1].
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
fn
|
Callable[[NDArray[float64]], NDArray[float64]]
|
Height function with |
required |
n_samples
|
int
|
Number of samples used before RDP simplification. |
1000
|
rdp_tol
|
float
|
Ramer-Douglas-Peucker tolerance used to simplify the
|
0.0001
|
Returns:
| Name | Type | Description |
|---|---|---|
A |
'Profile'
|
class: |
Source code in pleat/intersecting_cylinders/profiles.py
plot ¶
Plot the simplified (t, y) polyline.
show_3d ¶
show_3d(
G: "EuclideanPositionHEG",
profile: Profile,
r: float = 1.0,
n_across_edge: int = 8,
max_profile_samples: int = 30,
color: str = "lightblue",
opacity: float = 1.0,
height: int = 600,
edge_color: str = "black",
edge_width: float = 2.0,
show_edges: bool = True,
) -> "Any"
Return an interactive plotly 3D figure of the folded model.
Requires :mod:plotly (pip install plotly or
pip install -e ".[intersecting_cylinders]").
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
G
|
'EuclideanPositionHEG'
|
Input tiling. |
required |
profile
|
Profile
|
Cross-section curve. |
required |
r
|
float
|
Triangle scaling matching :func: |
1.0
|
n_across_edge
|
int
|
Mesh resolution across each edge (linear direction). |
8
|
max_profile_samples
|
int
|
Cap on the number of sample points along the
curved (spike-depth) direction; see :func: |
30
|
color
|
str
|
Surface colour. |
'lightblue'
|
opacity
|
float
|
Surface opacity in |
1.0
|
height
|
int
|
Figure height in pixels. |
600
|
edge_color
|
str
|
Colour of the sharp-fold polylines. |
'black'
|
edge_width
|
float
|
Line width of the sharp-fold polylines. |
2.0
|
show_edges
|
bool
|
When |
True
|
Returns:
| Type | Description |
|---|---|
'Any'
|
Plotly |
Source code in pleat/intersecting_cylinders/mesh3d.py
490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 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 | |
to_3d_mesh ¶
to_3d_mesh(
G: "EuclideanPositionHEG",
profile: Profile,
r: float = 1.0,
n_across_edge: int = 8,
max_profile_samples: int = 30,
) -> tuple[NDArray[np.float64], NDArray[np.int64]]
Build a triangle mesh of the folded intersecting-cylinders surface.
See the module docstring for the geometric construction. Each ortho quad
(v, t1, c, t2) is split along its v-c diagonal into two
half-triangles (c, v, t); each half-triangle is decomposed into a
curved trapezoid {c, c_near_v, t_near_v, t} filling the outer part
plus (for r < 1) a flat tip triangle {v, c_near_v, t_near_v} at
the vertex. The curved trapezoid is lifted using the profile's
cross-section.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
G
|
'EuclideanPositionHEG'
|
Input tiling whose faces have well-defined (pseudo-)incenters. A working copy is taken; the input is not modified. |
required |
profile
|
Profile
|
Cross-section curve. |
required |
r
|
float
|
Triangle scaling matching :func: |
1.0
|
n_across_edge
|
int
|
Number of uniform subdivisions across each half-edge
(the |
8
|
max_profile_samples
|
int
|
Cap on the number of sample points used along the curved (spike-depth) direction. The profile's own RDP-simplified samples are used (so the resolution is highest where the curve is steepest); when there are more than this many, they are uniformly subsampled in index space, always keeping the first and last. |
30
|
Returns:
| Type | Description |
|---|---|
tuple[NDArray[float64], NDArray[int64]]
|
|
Source code in pleat/intersecting_cylinders/mesh3d.py
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 | |
make_intersecting_cylinders ¶
make_intersecting_cylinders(
G: "EuclideanPositionHEG",
profile: Profile,
r: float = 1.0,
) -> "EuclideanPositionHEG"
Construct an intersecting-cylinders crease pattern from a tiling.
Every face of G must have an incenter, and the incircles of adjacent
faces should be tangential to each other (touching at the shared edge) for
the resulting crease pattern to be foldable.
The pattern places a small triangle twist at every face incenter and curved
triangles between adjacent twists: each curved triangle's flat side
connects the incenters of two adjacent faces, and its apex meets at the
original tiling vertex shared by those two edges. With r = 1 the curved
triangles meet at the original vertices to form spikes; with 0 < r < 1
a downscaled copy of every face is preserved and a flat polygon (dual to
the original vertex) replaces the spike, turning the curved triangles into
curved quadrilaterals.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
G
|
'EuclideanPositionHEG'
|
Input tiling. Mutated in place to record midpoints, then a working copy is taken before applying Conway operators. |
required |
profile
|
Profile
|
Cross-section curve. See
:func: |
required |
r
|
float
|
Triangle scaling. |
1.0
|
Returns:
| Type | Description |
|---|---|
'EuclideanPositionHEG'
|
A new |
'EuclideanPositionHEG'
|
attributes (red curved creases, blue/black straight creases) and |
'EuclideanPositionHEG'
|
|
Source code in pleat/intersecting_cylinders/pipeline.py
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 | |
top_view ¶
Return the flat top-view projection of an intersecting-cylinders model.
The projection of every curved triangle (r = 1) or curved quadrilateral
(r < 1) onto the base plane is a flat polygon. For r = 1 these are
triangles spanning two adjacent face incenters and the original vertex they
share — i.e. the Conway join operator (which inserts a vertex at every
face incenter and joins it to the incident original vertices). For
r < 1 they are trapezoids reaching from each pair of adjacent face
incenters down to the corresponding edge of the down-scaled inner face
(the Conway chamfer operator with t = r).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
G
|
'EuclideanPositionHEG'
|
Input tiling whose faces have well-defined (pseudo-)incenters. A working copy is taken; the input is not modified. |
required |
r
|
float
|
Triangle scaling matching the value passed to
:func: |
1.0
|
Returns:
| Type | Description |
|---|---|
'EuclideanPositionHEG'
|
A new |
Source code in pleat/intersecting_cylinders/pipeline.py
circular_profile ¶
Quarter-ellipse cross-section y = scale * sqrt(1 - (1 - x)**2).
With scale = 1 this is the canonical quarter-circle and produces
intersecting half-cylinders for the platonic 4 and 3 tilings. Larger
values of scale make the bumps taller and steeper.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scale
|
float
|
Height multiplier on the quarter-circle. |
1.3
|
n_samples
|
int
|
Forwarded to :meth: |
1000
|
rdp_tol
|
float
|
Forwarded to :meth: |
0.0001
|
Source code in pleat/intersecting_cylinders/profiles.py
parabolic_profile ¶
Parabolic cross-section y = scale * (1 - (1 - x)**2).
This is a smoother curve than the circular profile, with zero slope at the start and a more gradual approach to the maximum height. The resulting crease pattern is less spiky and may be easier to fold.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scale
|
float
|
Height multiplier on the parabola. |
1.3
|
n_samples
|
int
|
Forwarded to :meth: |
1000
|
rdp_tol
|
float
|
Forwarded to :meth: |
0.0001
|
Source code in pleat/intersecting_cylinders/profiles.py
build_dual_circle_packings ¶
Return a styled ortho-graph representing the two dual circle packings.
The returned graph is a fresh copy: the input G is not modified. Every
vertex carries a color_key and vertex_radius attribute; circles
coming from original faces use red fill, circles coming from original
vertices use blue fill, and the tangent-point vertices are drawn as small
black dots. Halfedges are coloured black and have line_width set so
that only the vertex circles are outlined.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
G
|
'EuclideanPositionHEG'
|
A 2D Euclidean tiling whose faces have well-defined incenters such that the corresponding incircles are mutually tangential at every edge. |
required |
Returns:
| Type | Description |
|---|---|
'EuclideanPositionHEG'
|
A copy of the ortho-Conway graph of |
'EuclideanPositionHEG'
|
set, ready to pass to :meth: |
Source code in pleat/intersecting_cylinders/show_circle_packings.py
show_dual_circle_packings ¶
Render the two dual circle packings of a tiling.
This is a thin convenience wrapper around :func:build_dual_circle_packings
that calls :meth:HalfEdgeGraph.show on the resulting styled graph with
render_faces=False.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
G
|
'EuclideanPositionHEG'
|
A 2D Euclidean tiling -- see :func: |
required |
**show_kwargs
|
Any
|
Forwarded to :meth: |
{}
|
Source code in pleat/intersecting_cylinders/show_circle_packings.py
convert_all_to_triangle_twists ¶
Replace every interior degree-6 vertex with a flat-foldable triangle twist.
All other vertices in intersecting-cylinder crease patterns are of smaller degree, so this targets exactly the curved hubs.
Source code in pleat/intersecting_cylinders/triangle_twist.py
convert_to_triangle_twist ¶
Replace a 6-creased vertex with a flat-foldable triangle twist.
v must be an interior vertex where 3 curved (red) and 3 straight creases
meet — the typical hub produced by
:func:~pleat.intersecting_cylinders.pipeline.make_intersecting_cylinders.
The graph G is mutated in place: the curved creases are deleted, three
new edges are added forming the boundary of a flat-foldable twist, and the
central vertex is removed.