Skip to content

geomotif.motifs.primitives

The basic shapes: circles, polygons, stars, grids and point fields.

Unglamorous and load-bearing. These are what you compose with :func:~geomotif.radial_repeat and :func:~geomotif.tile, what you clip other motifs against, and what most designs are eventually made of.

Note which base each one uses. A circle is measured -- sampled at evenly spaced angles, and the denser the sampling the rounder it gets. A polygon is listed -- five corners are the shape, and sampling it at five hundred parameters would only round its corners off. That is the difference between :class:~geomotif.ParametricMotif and :class:~geomotif.PolygonMotif, and it is why a pentagon here costs five points rather than five hundred.

Classes:

Name Description
Circle

A circle of radius radius around center.

Ellipse

An ellipse with semi-axes rx and ry, optionally rotated.

Arc

Part of a circle: sweep radians of it, starting at start_angle.

Sector

A pie slice: an arc closed back to its center by two radii.

Line

A straight segment from start to end.

Rectangle

An axis-aligned rectangle centered on center.

RoundedRectangle

A rectangle with its corners replaced by quarter circles.

RegularPolygon

A regular sides-gon inscribed in a circle of radius radius.

StarPolygon

The {n/k} star polygon: every step-th corner of an n-gon.

Star

The star people actually draw: outer points joined through inner ones.

Superellipse

The curve |x/rx|**n + |y/ry|**n == 1, for any positive n.

Squircle

The square-circle midpoint: a :class:Superellipse with n = 4.

ReuleauxPolygon

A curve of constant width: the Reuleaux triangle and its odd-sided kin.

Egg

An oval fatter at one end than the other.

PointGrid

A rectangular lattice of loose points, optionally staggered.

PoissonDiscPoints

Points scattered at random, but never closer together than a set distance.

Circle dataclass

Circle(radius: float = 100.0, center: Point = (0.0, 0.0), *, resolution: int | None = None)

Bases: ParametricMotif

A circle of radius radius around center.

Parameters:

Name Type Description Default
radius float

Distance from the center.

100.0
center (float, float)

Point to draw around.

(0.0, 0.0)

Ellipse dataclass

Ellipse(rx: float = 120.0, ry: float = 70.0, center: Point = (0.0, 0.0), rotation: float = 0.0, *, resolution: int | None = None)

Bases: ParametricMotif

An ellipse with semi-axes rx and ry, optionally rotated.

Parameters:

Name Type Description Default
rx float

Semi-axis lengths, before rotation.

120.0
ry float

Semi-axis lengths, before rotation.

120.0
center (float, float)

Point to draw around.

(0.0, 0.0)
rotation float

Angle of the rx axis, in radians.

0.0

Arc dataclass

Arc(radius: float = 100.0, start_angle: float = 0.0, sweep: float = pi, center: Point = (0.0, 0.0), *, resolution: int | None = None)

Bases: ParametricMotif

Part of a circle: sweep radians of it, starting at start_angle.

Parameters:

Name Type Description Default
radius float

Distance from the center.

100.0
start_angle float

Where the arc begins, in radians.

0.0
sweep float

Angular extent, in radians. Negative sweeps run clockwise.

pi
center (float, float)

Point to draw around.

(0.0, 0.0)

Sector dataclass

Sector(radius: float = 100.0, start_angle: float = 0.0, sweep: float = pi / 3.0, center: Point = (0.0, 0.0))

Bases: Motif

A pie slice: an arc closed back to its center by two radii.

Parameters:

Name Type Description Default
radius float

Distance from the center to the arc.

100.0
start_angle float

Where the arc begins, in radians.

0.0
sweep float

Angular extent, in radians. Negative sweeps run clockwise.

pi / 3.0
center (float, float)

Point of the slice.

(0.0, 0.0)

Line dataclass

Line(start: Point = (0.0, 0.0), end: Point = (100.0, 100.0))

Bases: PolygonMotif

A straight segment from start to end.

Parameters:

Name Type Description Default
start (float, float)

The two endpoints.

(0.0, 0.0)
end (float, float)

The two endpoints.

(0.0, 0.0)

Rectangle dataclass

Rectangle(width: float = 160.0, height: float = 100.0, center: Point = (0.0, 0.0))

Bases: PolygonMotif

An axis-aligned rectangle centered on center.

Parameters:

Name Type Description Default
width float

Full extents, not half-extents.

160.0
height float

Full extents, not half-extents.

160.0
center (float, float)

Midpoint of the rectangle.

(0.0, 0.0)

RoundedRectangle dataclass

RoundedRectangle(width: float = 160.0, height: float = 100.0, corner_radius: float = 20.0, center: Point = (0.0, 0.0))

Bases: Motif

A rectangle with its corners replaced by quarter circles.

Parameters:

Name Type Description Default
width float

Full extents, not half-extents.

160.0
height float

Full extents, not half-extents.

160.0
corner_radius float

Radius of each corner arc. 0 gives a plain rectangle; the maximum is half the shorter side, which gives a stadium.

20.0
center (float, float)

Midpoint of the rectangle.

(0.0, 0.0)

RegularPolygon dataclass

RegularPolygon(sides: int = 6, radius: float = 100.0, center: Point = (0.0, 0.0), rotation: float = _UP)

Bases: PolygonMotif

A regular sides-gon inscribed in a circle of radius radius.

Parameters:

Name Type Description Default
sides int

Number of corners. At least 3.

6
radius float

Circumradius -- the distance from the center to a corner, not to an edge.

100.0
center (float, float)

Point to draw around.

(0.0, 0.0)
rotation float

Angle of the first corner, in radians. Defaults to straight up.

_UP

StarPolygon dataclass

StarPolygon(points: int = 5, step: int = 2, radius: float = 100.0, center: Point = (0.0, 0.0), rotation: float = _UP)

Bases: PolygonMotif

The {n/k} star polygon: every step-th corner of an n-gon.

{5/2} is the pentagram, {7/3} the heptagram, {6/2} the Star of David -- and that last one is two triangles, not one path, because n and k share a factor. Each component comes back as its own stroke; joining them would draw an edge that is not part of the figure.

Parameters:

Name Type Description Default
points int

The n in {n/k}: how many points the star has.

5
step int

The k: how many corners each edge skips ahead. Must be at least 2 and less than half of points, which is exactly the range in which the figure is a star rather than a convex polygon or a collection of straight lines.

2
radius float

Circumradius.

100.0
center (float, float)

Point to draw around.

(0.0, 0.0)
rotation float

Angle of the first corner, in radians. Defaults to straight up.

_UP

Star dataclass

Star(points: int = 5, inner_ratio: float = 0.382, radius: float = 100.0, center: Point = (0.0, 0.0), rotation: float = _UP)

Bases: PolygonMotif

The star people actually draw: outer points joined through inner ones.

Distinct from :class:StarPolygon, which is a single line visiting every step-th corner of one circle. This one has two circles and twice as many corners, so its arms can be as fat or as thin as you like -- and it works for any point count, including the even ones that {n/k} cannot draw in a single stroke.

Parameters:

Name Type Description Default
points int

Number of arms.

5
inner_ratio float

Inner radius as a fraction of the outer. The default is 1/phi**2, which reproduces the pentagram's proportions.

0.382
radius float

Outer radius.

100.0
center (float, float)

Point to draw around.

(0.0, 0.0)
rotation float

Angle of the first arm, in radians. Defaults to straight up.

_UP

Superellipse dataclass

Superellipse(exponent: float = 2.5, rx: float = 100.0, ry: float = 100.0, center: Point = (0.0, 0.0), *, resolution: int | None = None)

Bases: ParametricMotif

The curve |x/rx|**n + |y/ry|**n == 1, for any positive n.

One knob spans the whole range from a four-pointed astroid through the diamond (n = 1), the ellipse (n = 2) and Piet Hein's rounded rectangle (n = 2.5, the shape of Sergels torg) up to the rectangle itself as n grows.

Parameters:

Name Type Description Default
exponent float

The n. Below 2 the sides curve inward, above 2 they bulge out.

2.5
rx float

Half-extents along each axis.

100.0
ry float

Half-extents along each axis.

100.0
center (float, float)

Point to draw around.

(0.0, 0.0)

Squircle dataclass

Squircle(radius: float = 100.0, center: Point = (0.0, 0.0), *, resolution: int | None = None)

Bases: ParametricMotif

The square-circle midpoint: a :class:Superellipse with n = 4.

A preset rather than a new curve, and the one worth having a name for -- it is the rounded square of app icons and camera viewfinders, and it fills a noticeably larger fraction of its bounding box than a circle without reading as a square.

Parameters:

Name Type Description Default
radius float

Half-extent along both axes.

100.0
center (float, float)

Point to draw around.

(0.0, 0.0)

ReuleauxPolygon dataclass

ReuleauxPolygon(sides: int = 3, width: float = 150.0, center: Point = (0.0, 0.0), rotation: float = _UP)

Bases: Motif

A curve of constant width: the Reuleaux triangle and its odd-sided kin.

Every arc is centered on the corner opposite it, so the distance across the shape is the same in every direction -- it rolls under a plank as smoothly as a circle does, while being nothing like one. Only odd corner counts work: an even one has a corner opposite a corner rather than an edge, and there is nothing to center the arcs on.

Parameters:

Name Type Description Default
sides int

Number of corners. Must be odd and at least 3.

3
width float

The constant width, in every direction.

150.0
center (float, float)

Point to draw around.

(0.0, 0.0)
rotation float

Angle of the first corner, in radians. Defaults to straight up.

_UP

Egg dataclass

Egg(length: float = 140.0, width: float = 100.0, taper: float = 0.25, center: Point = (0.0, 0.0), *, resolution: int | None = None)

Bases: ParametricMotif

An oval fatter at one end than the other.

An ellipse whose height is tapered along its length, which is the simplest form that reads as an egg and stays smooth everywhere. taper = 0 is exactly an ellipse.

Parameters:

Name Type Description Default
length float

Full extent along the x-axis.

140.0
width float

Full extent across, before tapering.

100.0
taper float

How lopsided the egg is, between -1 and 1. Positive values put the blunt end on the right.

0.25
center (float, float)

Point to draw around.

(0.0, 0.0)

PointGrid dataclass

PointGrid(columns: int = 12, rows: int = 12, dx: float = 20.0, dy: float = 20.0, stagger: float = 0.0, center: Point = (0.0, 0.0))

Bases: Motif

A rectangular lattice of loose points, optionally staggered.

Produces points rather than strokes: this is the substrate for dot art, stipple fields and object placement, not something to draw a line through. stagger=0.5 offsets alternate rows by half a step, which turns the square lattice into a triangular one.

Parameters:

Name Type Description Default
columns int

Lattice size. At least 1 each.

12
rows int

Lattice size. At least 1 each.

12
dx float

Spacing between neighbours.

20.0
dy float

Spacing between neighbours.

20.0
stagger float

Fraction of dx to shift every other row by.

0.0
center (float, float)

Midpoint of the lattice.

(0.0, 0.0)

PoissonDiscPoints dataclass

PoissonDiscPoints(width: float = 300.0, height: float = 300.0, min_distance: float = 20.0, center: Point = (0.0, 0.0), *, seed: int = 0, attempts: int = 30)

Bases: Motif

Points scattered at random, but never closer together than a set distance.

Bridson's algorithm. The result looks organic in a way a plain random scatter does not: random points clump and leave holes, while these fill the area evenly without ever falling into a visible grid. It is what you want for stippling, foliage placement and any "natural" arrangement.

Parameters:

Name Type Description Default
width float

Size of the area to fill.

300.0
height float

Size of the area to fill.

300.0
min_distance float

Closest two points may ever be.

20.0
seed int

Seeds a private generator, so the same seed always gives the same field and the design stays reproducible from its metadata.

0
attempts int

Candidates tried around each accepted point before giving up on it. Higher packs slightly tighter and costs proportionally more.

30
center (float, float)

Midpoint of the area.

(0.0, 0.0)