Skip to content

geomotif.motifs.guilloche

Guilloché: the engine-turned line work on banknotes and watch dials.

The whole family is one trick. Draw a wavy curve; draw it again with the wave shifted a little; repeat twenty times. Nowhere do two lines cross at a shallow angle, so the eye reads the stack as a woven surface rather than as twenty separate strokes -- and because the pattern is the sum of two frequencies, copying it by hand is hopeless, which is exactly why engravers used it on money.

Three shapes cover what a rose engine could do. :class:GuillocheRosette runs the wave around a circle. :class:GuillocheBand runs it along a straight spine, for a border or a ribbon. :class:GuillochePattern puts one inside the other, which is the banknote layout: a rosette in the middle, a band around the edge, rules between them.

Two frequencies, not one, is the part worth keeping. A single sine shifted in phase just slides sideways and the stack looks like a comb. Adding a second wave that runs the other way makes each shifted copy a genuinely different curve, and the interference between them is the weave.

Classes:

Name Description
GuillocheRosette

A stack of rosettes, each turned a little further than the last.

GuillocheBand

A woven ribbon along a straight spine: the border of a banknote.

GuillochePattern

A rosette inside a woven border, with rules between: the banknote layout.

GuillocheRosette dataclass

GuillocheRosette(radius: float = 96.0, amplitude: float = 30.0, petals: float = 13.0, counter: float = 5.0, layers: int = 14, spread: float = 2.6, twist: float = 0.42, center: Point = (0.0, 0.0), *, resolution: int | None = None)

Bases: MultiCurveMotif

A stack of rosettes, each turned a little further than the last.

The wave runs around a circle instead of along a line, so every stroke closes. Successive layers step outward by :attr:spread and forward by :attr:twist, and where the two rates disagree the lines braid.

Parameters:

Name Type Description Default
radius float

Radius of the innermost layer's spine.

96.0
amplitude float

How far the wave carries a stroke off its spine.

30.0
petals float

Waves per revolution. Whole numbers close cleanly.

13.0
counter float

Waves per revolution of the backward-running second frequency.

5.0
layers int

How many strokes to stack.

14
spread float

Radial step between layers.

2.6
twist float

Phase step between layers, in radians. This is what turns a stack of identical rings into a weave.

0.42
center (float, float)

Middle of the rosette.

(0.0, 0.0)

GuillocheBand dataclass

GuillocheBand(length: float = 320.0, height: float = 76.0, waves: float = 5.0, counter: float = 8.0, lines: int = 18, center: Point = (0.0, 0.0), *, resolution: int | None = None)

Bases: MultiCurveMotif

A woven ribbon along a straight spine: the border of a banknote.

Each stroke is the same two-frequency wave at a different phase, so the stack fills a band of constant height with a pattern that never quite repeats along its length.

Parameters:

Name Type Description Default
length float

Length of the spine.

320.0
height float

Full height of the band.

76.0
waves float

Cycles of the forward wave along the whole length.

5.0
counter float

Cycles of the backward wave.

8.0
lines int

How many strokes to stack. Their phases divide one full cycle evenly.

18
center (float, float)

Middle of the band.

(0.0, 0.0)

GuillochePattern dataclass

GuillochePattern(radius: float = 150.0, layers: int = 12, petals: float = 11.0, border_lines: int = 16, border_height: float = 30.0, border_waves: float = 36.0, center: Point = (0.0, 0.0), *, rules: bool = True)

Bases: Motif

A rosette inside a woven border, with rules between: the banknote layout.

A composition rather than a curve of its own: two :class:GuillocheRosette instances, one broad and slow for the middle and one narrow and fast for the border, with a plain circle ruled either side of the border to close it off. A band bent into a ring is a rosette, so there is no third shape to write.

Parameters:

Name Type Description Default
radius float

Outer radius, to the middle of the border.

150.0
layers int

Strokes in the central rosette.

12
petals float

Waves per revolution in the central rosette.

11.0
border_lines int

Strokes in the border.

16
border_height float

Full width of the border band.

30.0
border_waves float

Waves around the border.

36.0
rules bool

Draw the two plain circles that fence the border in.

True
center (float, float)

Middle of the figure.

(0.0, 0.0)

Methods:

Name Description
rosette

Return the central rosette, sized to sit inside the border.

border

Return the border, which is a rosette with a tight, fast wave.

rosette

rosette() -> GuillocheRosette

Return the central rosette, sized to sit inside the border.

Source code in src/geomotif/motifs/guilloche.py
def rosette(self) -> GuillocheRosette:
    """Return the central rosette, sized to sit inside the border."""
    inner = self.radius - self.border_height
    spread = inner / (2.0 * self.layers)
    return GuillocheRosette(
        radius=inner / 2.0,
        amplitude=inner / 6.0,
        petals=self.petals,
        counter=self.petals / 2.0,
        layers=self.layers,
        spread=spread,
        twist=math.tau / (2.0 * self.layers),
        center=self.center,
    )

border

border() -> GuillocheRosette

Return the border, which is a rosette with a tight, fast wave.

Source code in src/geomotif/motifs/guilloche.py
def border(self) -> GuillocheRosette:
    """Return the border, which is a rosette with a tight, fast wave."""
    return GuillocheRosette(
        radius=self.radius - self.border_height / 2.0,
        amplitude=self.border_height / 2.0,
        petals=self.border_waves,
        counter=self.border_waves / 3.0,
        layers=self.border_lines,
        spread=0.0,
        twist=math.tau / self.border_lines,
        center=self.center,
    )