geomotif.bases.lsystem
¶
Turtle graphics driven by an L-system grammar.
An L-system is a start string plus rewrite rules applied a fixed number of times; the resulting string is then read as turtle instructions. It is the most economical description of the classic fractal curves there is -- Koch, Hilbert, Gosper, dragon, Sierpinski and the rest each reduce to an axiom, one or two rules and a turn angle.
The turtle alphabet, which follows the usual convention:
=========== ==================================================
Symbol Meaning
=========== ==================================================
F G A B move forward, drawing (see :attr:LSystemMotif.draw)
f g move forward without drawing, breaking the stroke
+ turn left by :attr:LSystemMotif.angle
- turn right by :attr:LSystemMotif.angle
| turn around
[ push position and heading
] pop position and heading, starting a new stroke
=========== ==================================================
Every other symbol is ignored while drawing, which is what lets grammars use
letters like X and Y purely to drive the rewriting.
Classes:
| Name | Description |
|---|---|
LSystemMotif |
Base for a motif described by a grammar and drawn with a turtle. |
LSystemMotif
dataclass
¶
Bases: Motif, ABC
Base for a motif described by a grammar and drawn with a turtle.
Define :attr:axiom, :attr:rules and :attr:angle as class variables;
everything else is a parameter with a sensible default. A concrete
fractal is four lines::
@register("koch", family="fractal")
@dataclass(frozen=True, slots=True)
class KochCurve(LSystemMotif):
axiom = "F"
rules: ClassVar[Mapping[str, str]] = {"F": "F+F--F+F"}
angle = math.pi / 3
The ClassVar annotation on :attr:rules is not decoration: without
it, a mutable class attribute in a dataclass body is ambiguous to reader
and linter alike, and annotating it as anything else would make it a
constructor parameter with a mutable default, which dataclasses reject.
Notes
Both the string expansion and the point count grow exponentially with
:attr:depth; the expansion is capped so that an accidental depth=20
raises instead of exhausting memory.
Methods:
| Name | Description |
|---|---|
expand |
Return the axiom rewritten :attr: |
expand
¶
Return the axiom rewritten :attr:depth times.
Raises:
| Type | Description |
|---|---|
ValueError
|
If |