geomotif.compose.mandala
¶
Rings, symmetry groups and snowflakes: arranging a motif rather than drawing one.
Four composers and one value type, which between them cover most of what people mean by "mandala".
:class:Mandala is the general one -- a list of :class:Ring s, each saying
what to repeat, how many times, and how far out. :class:Kaleidoscope is the
single-unit case, under a named symmetry group. :class:SpokePattern and
:class:LayeredRings are the scaffolding a mandala is usually hung on, worth
having because they are what you reach for first and neither deserves ten
lines at the call site. :class:Snowflake is the odd one out: it grows its
own arm if you do not give it one, because a snowflake's arm is a random
dendrite and there is no other motif in the library that is one.
Classes:
| Name | Description |
|---|---|
Ring |
One ring of a :class: |
Mandala |
Concentric rings of repeated motifs. |
Kaleidoscope |
One motif, repeated under a cyclic or dihedral symmetry group. |
SpokePattern |
Radial lines from an inner circle to an outer one. |
LayeredRings |
Concentric circles: the other half of a mandala's scaffolding. |
Snowflake |
Six identical arms, each mirrored in its own axis. |
Ring
dataclass
¶
Ring(unit: SupportsBuild, count: int, radius: float, phase: float = 0.0, spin: float = 0.0, face: bool = True, mirror: bool = False)
One ring of a :class:Mandala: what to repeat, how often, how far out.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
unit
|
Motif or anything with ``build()``
|
The unit to repeat. |
required |
count
|
int
|
How many copies to place around the ring. |
required |
radius
|
float
|
Distance from the mandala's middle to each copy's own origin. |
required |
phase
|
float
|
Angle of the first copy, in radians. |
0.0
|
spin
|
float
|
Extra rotation applied to every copy, on top of whichever way
:attr: |
0.0
|
face
|
bool
|
Turn each copy to face outward, so a petal drawn along the x-axis points away from the middle wherever it lands. Turn this off to keep every copy at its original angle, which is what you want for a shape that has to stay upright. |
True
|
mirror
|
bool
|
Also place each copy's reflection in its own ray, giving the ring mirror symmetry as well as rotational. |
False
|
Methods:
| Name | Description |
|---|---|
placements |
Return the transform that puts each copy where it belongs. |
placements
¶
placements(center: Point = (0.0, 0.0)) -> tuple[Affine, ...]
Return the transform that puts each copy where it belongs.
Source code in src/geomotif/compose/mandala.py
Mandala
dataclass
¶
Mandala(rings: tuple[Ring, ...], center: Point = (0.0, 0.0))
Bases: Motif
Concentric rings of repeated motifs.
The workhorse. Each :class:Ring is built once and then placed by an
affine transform per copy, so a hundred-fold ring costs one build and a
hundred cheap transforms rather than a hundred builds.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
rings
|
tuple of Ring
|
The rings, innermost first by convention. Nothing enforces an order, and rings are free to overlap. |
required |
center
|
(float, float)
|
Middle of the figure. |
(0.0, 0.0)
|
Kaleidoscope
dataclass
¶
Kaleidoscope(unit: SupportsBuild, group: str = 'D6', center: Point = (0.0, 0.0))
Bases: Motif
One motif, repeated under a cyclic or dihedral symmetry group.
"C6" turns the motif six ways; "D6" turns it six ways and mirrors
each, giving twelve copies and the look of a real kaleidoscope, where
every second image is reflected because it has bounced off a mirror an
odd number of times.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
unit
|
Motif or anything with ``build()``
|
The fundamental domain: the one wedge everything else is made from. |
required |
group
|
str
|
|
'D6'
|
center
|
(float, float)
|
Point the symmetry is about. |
(0.0, 0.0)
|
SpokePattern
dataclass
¶
SpokePattern(count: int = 24, inner: float = 40.0, outer: float = 140.0, stagger: float = 0.0, rotation: float = 0.0, center: Point = (0.0, 0.0))
Bases: Motif
Radial lines from an inner circle to an outer one.
The bones of most mandalas, and a decent motif on its own. With
:attr:stagger set, every other spoke stops short, which is the ticked
dial of a compass rose.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
count
|
int
|
How many spokes. |
24
|
inner
|
float
|
Where each spoke starts and ends. |
40.0
|
outer
|
float
|
Where each spoke starts and ends. |
40.0
|
stagger
|
float
|
How far short every second spoke stops, as a fraction of its length.
|
0.0
|
rotation
|
float
|
Angle of the first spoke, in radians. |
0.0
|
center
|
(float, float)
|
Point they radiate from. |
(0.0, 0.0)
|
LayeredRings
dataclass
¶
LayeredRings(count: int = 7, inner: float = 24.0, step: float = 20.0, growth: float = 1.0, center: Point = (0.0, 0.0))
Bases: Motif
Concentric circles: the other half of a mandala's scaffolding.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
count
|
int
|
How many circles. |
7
|
inner
|
float
|
Radius of the innermost. |
24.0
|
step
|
float
|
Radial gap between the first two circles. |
20.0
|
growth
|
float
|
Multiplier applied to the gap each time out. |
1.0
|
center
|
(float, float)
|
Middle of the figure. |
(0.0, 0.0)
|
Methods:
| Name | Description |
|---|---|
radii |
Return each circle's radius, innermost first. |
radii
¶
Return each circle's radius, innermost first.
Source code in src/geomotif/compose/mandala.py
Snowflake
dataclass
¶
Snowflake(unit: SupportsBuild | None = None, size: float = 150.0, branches: int = 4, depth: int = 2, seed: int = 0, *, center: Point = (0.0, 0.0))
Bases: Motif
Six identical arms, each mirrored in its own axis.
A real snowflake is sixfold because a water molecule is, and identical across its six arms because every arm grew in the same air. Both facts are in the construction: one arm is grown, then reflected in its own axis and turned six ways.
Give it a unit to use that as the arm. Otherwise it grows a
dendrite -- a spine with side branches at sixty degrees, each of which may
branch again -- from :attr:seed, so the same seed always yields the same
crystal and a different one never does.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
unit
|
Motif or anything with ``build()``
|
The arm, drawn along the positive x-axis and mirrored in it. |
None
|
size
|
float
|
Length of the grown arm's spine. Ignored when a unit is given. |
150.0
|
branches
|
int
|
Side branches per spine. Ignored when a unit is given. |
4
|
depth
|
int
|
How many times a branch may branch again. Ignored when a unit is given. |
2
|
seed
|
int
|
Fixes the growth. The generator is private to the call, so nothing else in the program can change what you get. |
0
|
center
|
(float, float)
|
Middle of the crystal. |
(0.0, 0.0)
|
Methods:
| Name | Description |
|---|---|
arm |
Return the single arm, before it is mirrored and repeated. |