geomotif.bases.polygon
¶
Base for motifs that are an exact list of corners.
Distinct from :class:~geomotif.ParametricMotif for a reason that matters:
a polygon fed through a parametric position(u) is measured by evaluating
it at evenly spaced parameters, and a corner survives that only if a sample
happens to land exactly on it. A pentagon measured at 512 samples has none of
its five corners land on one, so every vertex comes out slightly cut. Listing
the corners instead keeps them exact and costs five points rather than five
hundred.
Anything whose shape is decided by its vertices belongs here: rectangles,
regular polygons, stars, the whole {n/k} family, and open polylines such
as the Theodorus spiral's chain of triangles.
Classes:
| Name | Description |
|---|---|
PolygonMotif |
Base for a motif drawn as one or more exact corner sequences. |
PolygonMotif
dataclass
¶
Bases: Motif, ABC
Base for a motif drawn as one or more exact corner sequences.
Implement :meth:outlines; :meth:build turns each one into a
:class:~geomotif.Path::
@register("rectangle", family="primitive")
@dataclass(frozen=True, slots=True)
class Rectangle(PolygonMotif):
width: float = 1.0
height: float = 1.0
def outlines(self) -> Iterable[Sequence[Point]]:
w, h = self.width / 2.0, self.height / 2.0
yield ((-w, -h), (w, -h), (w, h), (-w, h))
:meth:outlines is plural because one shape is not always one loop: the
star polygon {6/2} is two overlaid triangles, and drawing it as a
single path would invent an edge between them that is not there.
Notes
Corners are emitted as given -- no deduplication, no collinear-point removal. A motif that wants a vertex repeated (to hold a pen, to mark a lattice site) is entitled to it, and guessing otherwise would silently change geometry the author chose.
Methods:
| Name | Description |
|---|---|
outlines |
Return the corner sequences to draw, one per stroke. At least one. |