geomotif.motifs.curves
¶
The named curves: the ones that earned a name before they earned a use.
Hearts, lemniscates, ovals, astroids, cycloids -- shapes that turn up in optics, in mechanisms and on tombstones, and that people go looking for by name. Each one is a formula and nothing else, so each one is a base class and three lines.
Two conventions hold throughout this module.
size is the curve's largest extent. A curve with a single free scale
takes size, and at size=100 its bounding box measures 100 across its
longer axis -- so a heart and a butterfly composed at the same size come
out the same size. Curves whose shape depends on the ratio of two numbers
(:class:CassiniOval, :class:Limacon, :class:Folium) take those two
numbers directly instead, because a third scale knob would only be a way of
saying the same thing twice.
center is the curve's own origin, not the middle of its bounding box:
the cusp of a cardioid, the crossing point of a lemniscate, the first contact
point of a cycloid. That is the point the formula is written about, and the
point that stays put when you change the other parameters. Call
:meth:~geomotif.Design.fit if what you want is the box centered.
None of these takes a rotation. Turning a design is
:meth:~geomotif.Design.transformed with :meth:~geomotif.Affine.rotate,
and a per-motif copy of it would only be a worse one.
Classes:
| Name | Description |
|---|---|
Heart |
A heart, in either of the two shapes that go by the name. |
Cardioid |
The heart-shaped |
Lemniscate |
Bernoulli's lemniscate: the infinity symbol. |
LemniscateOfGerono |
Gerono's lemniscate: the other figure eight, |
CassiniOval |
Points whose distances to two foci multiply to a constant. |
Limacon |
Pascal's snail, |
Folium |
The leaf curve |
Butterfly |
Temple Fay's butterfly: twelve revolutions that draw two wings. |
FishCurve |
A fish, tail and all, from |
BowCurve |
The bow, |
Astroid |
The four-cusped star |
Deltoid |
The three-cusped tricuspoid, Euler's curve of 1745. |
Nephroid |
The kidney: the two-cusped epicycloid, |
Cornoid |
The cornoid, |
Cochleoid |
The snail shell |
Cycloid |
The path of a point on a rolling wheel's rim. |
Trochoid |
The path of a point fixed to a rolling wheel, on the rim or off it. |
Witch |
The witch of Agnesi: a bell curve with an exact algebraic definition. |
Heart
dataclass
¶
Heart(size: float = 100.0, form: HeartForm = 'classic', center: Point = (0.0, 0.0), *, resolution: int | None = None)
Bases: ParametricMotif
A heart, in either of the two shapes that go by the name.
"classic" is the valentine: the 16*sin(t)**3 curve, with the
dimple on top and a proper point at the bottom. "cardioid" is
r = 1 - sin(theta), which is the same cardioid as
:class:Cardioid stood on end -- rounder, symmetrical, and the one that
falls out of the maths rather than out of a greetings card.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
size
|
float
|
Largest extent of the curve. |
100.0
|
form
|
('classic', 'cardioid')
|
Which heart to draw. |
"classic"
|
center
|
(float, float)
|
The curve's own origin, which for both forms is the dimple between the two lobes. |
(0.0, 0.0)
|
Cardioid
dataclass
¶
Bases: ParametricMotif
The heart-shaped r = 1 + cos(theta): one circle rolled around another.
An epicycloid with a single cusp, and the shape of the bright caustic in
a coffee cup. Also the limiting case of :class:Limacon where the inner
loop has shrunk to a point.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
size
|
float
|
Largest extent of the curve. |
100.0
|
center
|
(float, float)
|
The cusp, which is where the curve's own origin sits. |
(0.0, 0.0)
|
Lemniscate
dataclass
¶
Bases: ParametricMotif
Bernoulli's lemniscate: the infinity symbol.
The locus of points whose distances to two foci multiply to a constant --
the one case of :class:CassiniOval where the two lobes have just met.
Drawn from its rational parametrization rather than from
r**2 = a**2 * cos(2*theta), which goes imaginary over half its range
and would have to be stitched together from two arcs.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
size
|
float
|
Largest extent of the curve: the full width across both lobes. |
100.0
|
center
|
(float, float)
|
The crossing point in the middle. |
(0.0, 0.0)
|
LemniscateOfGerono
dataclass
¶
LemniscateOfGerono(size: float = 100.0, center: Point = (0.0, 0.0), *, resolution: int | None = None)
Bases: ParametricMotif
Gerono's lemniscate: the other figure eight, x**4 = x**2 - y**2.
Fatter and blunter than :class:Lemniscate, and far easier to say:
x = cos(t), y = sin(t)*cos(t). Worth having both -- they are
drawn interchangeably and they are not the same curve.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
size
|
float
|
Largest extent of the curve: the full width across both lobes. |
100.0
|
center
|
(float, float)
|
The crossing point in the middle. |
(0.0, 0.0)
|
CassiniOval
dataclass
¶
CassiniOval(a: float = 70.0, b: float = 80.0, center: Point = (0.0, 0.0), *, resolution: int | None = None)
Bases: MultiCurveMotif
Points whose distances to two foci multiply to a constant.
An ellipse adds those distances; a Cassini oval multiplies them, and the difference is a shape that changes topology as the constant crosses the focal separation. Cassini proposed it for planetary orbits and was wrong, which has not stopped it being the more interesting curve.
Three regimes, and the class draws each one honestly:
b > a-- a single closed loop, either an oval or, onceb < a*sqrt(2), the pinched peanut.b < a-- two separate loops, one around each focus, returned as two strokes rather than one path with an invented bridge between them.b == a-- the loops have just touched, and the curve is Bernoulli's lemniscate. Rejected here, because that case is :class:Lemniscateand it draws it better.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
a
|
float
|
Half the distance between the foci, which sit at |
70.0
|
b
|
float
|
Square root of the constant product. Compare it to |
80.0
|
center
|
(float, float)
|
Midpoint between the foci. |
(0.0, 0.0)
|
Limacon
dataclass
¶
Limacon(a: float = 100.0, b: float = 60.0, center: Point = (0.0, 0.0), *, resolution: int | None = None)
Bases: ParametricMotif
Pascal's snail, r = b + a*cos(theta), inner loop and all.
One knob spans a whole family. abs(a) > abs(b) gives the looped
limacon, whose inner loop is drawn correctly because a negative radius
reflects onto the opposite ray rather than being clipped away.
a == b is the :class:Cardioid. abs(b) >= 2*abs(a) is convex,
with not even a dimple left.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
a
|
float
|
Amplitude of the cosine term: how lopsided the curve is. |
100.0
|
b
|
float
|
Constant term: the radius the curve would have if |
60.0
|
center
|
(float, float)
|
The pole the radius is measured from. |
(0.0, 0.0)
|
Folium
dataclass
¶
Folium(a: float = 100.0, b: float = 100.0, center: Point = (0.0, 0.0), *, resolution: int | None = None)
Bases: ParametricMotif
The leaf curve r = cos(theta) * (4*a*sin(theta)**2 - b).
Three named shapes live in two numbers: b == a is the trifolium's
three petals, b == 4*a is the single-petalled simple folium, and
b == 0 is the bifolium's two. Anything between them is a legitimate
intermediate.
Half a revolution draws the whole thing. The other half retraces it,
because r(theta + pi) == -r(theta) and a negative radius lands back
on the ray it came from.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
a
|
float
|
Scale of the petals. |
100.0
|
b
|
float
|
Petal count, in effect: see the shapes listed above. |
100.0
|
center
|
(float, float)
|
The pole all the petals meet at. |
(0.0, 0.0)
|
Butterfly
dataclass
¶
Bases: ParametricMotif
Temple Fay's butterfly: twelve revolutions that draw two wings.
r = exp(cos(theta)) - 2*cos(4*theta) + sin(theta/12)**5. The last
term has twelve times the period of the rest, so the curve takes twelve
turns to close and each turn lays down a slightly different outline --
which is the whole trick, and why it is the one transcendental doodle
everybody recognizes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
size
|
float
|
Largest extent of the curve. |
100.0
|
center
|
(float, float)
|
The body, which is where the pole sits. |
(0.0, 0.0)
|
FishCurve
dataclass
¶
Bases: ParametricMotif
A fish, tail and all, from x = cos(t) - sin(t)**2 / sqrt(2).
The negative pedal of an ellipse at a particular eccentricity, which is a dry way of saying that the tail crosses itself exactly where a tail should.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
size
|
float
|
Largest extent of the curve, nose to tail. |
100.0
|
center
|
(float, float)
|
The curve's own origin, just behind the head. |
(0.0, 0.0)
|
BowCurve
dataclass
¶
Bases: ParametricMotif
The bow, x**4 == x**2*y - y**3: two loops pinched at the origin.
Rational all the way through -- x = t - t**3, y = t**2 - t**4 --
so it needs no trigonometry and no domain surgery.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
size
|
float
|
Largest extent of the curve: the full width across both loops. |
100.0
|
center
|
(float, float)
|
The pinch point where the two loops meet. |
(0.0, 0.0)
|
Astroid
dataclass
¶
Bases: ParametricMotif
The four-cusped star x**(2/3) + y**(2/3) == 1.
A hypocycloid with four cusps, and the envelope of a ladder sliding down a wall -- which is why it turns up in string art without anyone having set out to draw it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
size
|
float
|
Largest extent of the curve: cusp to opposite cusp. |
100.0
|
center
|
(float, float)
|
The middle, equidistant from all four cusps. |
(0.0, 0.0)
|
Deltoid
dataclass
¶
Bases: ParametricMotif
The three-cusped tricuspoid, Euler's curve of 1745.
The hypocycloid a wheel traces rolling inside a ring three times its size, and the shape of the caustic you get reflecting parallel light off the inside of a cup.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
size
|
float
|
Largest extent of the curve. |
100.0
|
center
|
(float, float)
|
The middle, equidistant from all three cusps. |
(0.0, 0.0)
|
Nephroid
dataclass
¶
Bases: ParametricMotif
The kidney: the two-cusped epicycloid, r = 3cos(t) - cos(3t).
The caustic of a circle lit from infinity, which is the bright cusp of light in a teacup that everyone has seen and few have named.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
size
|
float
|
Largest extent of the curve, across the two lobes. |
100.0
|
center
|
(float, float)
|
The middle, on the line joining the cusps. |
(0.0, 0.0)
|
Cornoid
dataclass
¶
Bases: ParametricMotif
The cornoid, x = cos(t)cos(2t), y = sin(t)(2 + cos(2t)).
An oval with a pair of cusped loops tucked inside it, one near each end. A closed sextic, and one of the few named curves that looks like nothing else in the catalog.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
size
|
float
|
Largest extent of the curve, along the oval. |
100.0
|
center
|
(float, float)
|
The middle, between the two inner loops. |
(0.0, 0.0)
|
Cochleoid
dataclass
¶
Cochleoid(size: float = 100.0, loops: int = 4, center: Point = (0.0, 0.0), *, resolution: int | None = None)
Bases: ParametricMotif
The snail shell r = sin(theta) / theta, coiling in on itself.
Every loop touches the pole and every loop is smaller than the last, so
the whole family of them nests inside the first. The curve is symmetric
about the x-axis -- r(-theta) == r(theta) -- so it is drawn from
-loops turns to +loops, in one stroke through the point at
theta = 0.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
size
|
float
|
Largest extent of the curve. Set by the outermost loop, so adding loops makes the picture busier rather than bigger. |
100.0
|
loops
|
int
|
Loops drawn on each side of the axis. |
4
|
center
|
(float, float)
|
The pole every loop passes through. |
(0.0, 0.0)
|
Cycloid
dataclass
¶
Cycloid(radius: float = 40.0, arches: int = 3, center: Point = (0.0, 0.0), *, resolution: int | None = None)
Bases: ParametricMotif
The path of a point on a rolling wheel's rim.
The brachistochrone and the tautochrone at once: the curve a bead slides down fastest, and the curve it takes the same time to slide down from anywhere. Seventeenth-century mathematicians fought over it enough for it to be nicknamed the Helen of geometers.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
radius
|
float
|
Radius of the rolling wheel. Each arch is |
40.0
|
arches
|
int
|
How many arches to roll out. |
3
|
center
|
(float, float)
|
Where the first arch touches the ground. |
(0.0, 0.0)
|
Trochoid
dataclass
¶
Trochoid(radius: float = 40.0, arm: float = 60.0, arches: int = 3, center: Point = (0.0, 0.0), *, resolution: int | None = None)
Bases: ParametricMotif
The path of a point fixed to a rolling wheel, on the rim or off it.
arm < radius is the curtate trochoid, the gentle wave a point inside
the wheel traces. arm > radius is the prolate one, whose overhanging
point runs backwards once per revolution and cuts a loop. arm ==
radius is exactly the :class:Cycloid.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
radius
|
float
|
Radius of the rolling wheel. |
40.0
|
arm
|
float
|
Distance from the wheel's center to the traced point. |
60.0
|
arches
|
int
|
How many revolutions to roll out. |
3
|
center
|
(float, float)
|
Where the wheel's center starts, projected onto the ground. |
(0.0, 0.0)
|
Witch
dataclass
¶
Witch(radius: float = 50.0, extent: float = 3.0, center: Point = (0.0, 0.0), *, resolution: int | None = None)
Bases: ParametricMotif
The witch of Agnesi: a bell curve with an exact algebraic definition.
y = 8a**3 / (x**2 + 4a**2), constructed from a circle of radius a
sitting on the origin. Named a witch by a translator who mistook
versiera for avversiera; the curve has been stuck with it since.
It approaches its asymptote without reaching it, so it has to be cut off
somewhere -- that is what extent is for.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
radius
|
float
|
Radius of the generating circle. The peak sits at |
50.0
|
extent
|
float
|
How far out to draw, in units of the peak's height. The curve has
fallen to a fifth of its height by |
3.0
|
center
|
(float, float)
|
The point on the asymptote directly below the peak. |
(0.0, 0.0)
|