Skip to content

geomotif.core.motif

The motif contract: the one thing you implement to extend the library.

A motif is a parameterized recipe for geometry. Implement :meth:Motif.build -- usually a few lines of maths -- and arc-length resampling, every spacing curve, the transform layer, export and CLI exposure all come with it.

Two entry points, deliberately separated:

  • :meth:Motif.build -- the motif's own idea of itself, at its native resolution. This is what you write.
  • :meth:Motif.generate -- what you actually plot: a specific number of points, distributed the way you asked. This is what you call.

Classes:

Name Description
SupportsBuild

Structural contract -- any object with build() works everywhere.

Motif

Convenience base: implement :meth:build, inherit everything else.

SupportsBuild

Bases: Protocol

Structural contract -- any object with build() works everywhere.

Following the :class:typing.SupportsInt convention, this is the structural twin of :class:Motif: anything that can build a design is accepted wherever a motif is, so nobody is ever forced to inherit.

Methods:

Name Description
build

Return the design at its natural resolution.

build

build() -> Design

Return the design at its natural resolution.

Source code in src/geomotif/core/motif.py
def build(self) -> Design:
    """Return the design at its natural resolution."""
    ...

Motif

Bases: ABC

Convenience base: implement :meth:build, inherit everything else.

The ABC exists to hand you :meth:generate and registration, not to police the type -- see :class:SupportsBuild if you would rather not inherit at all.

Methods:

Name Description
build

Return the design at its natural/native resolution.

generate

Build, then resample to count points (or a fixed step distance).

build abstractmethod

build() -> Design

Return the design at its natural/native resolution.

Source code in src/geomotif/core/motif.py
@abstractmethod
def build(self) -> Design:
    """Return the design at its natural/native resolution."""

generate

generate(count: int | None = None, *, step: float | None = None, spacing: SpacingLike | None = None, distribute: Distribution = 'length', by: Placement = 'length') -> Design

Build, then resample to count points (or a fixed step distance).

Parameters:

Name Type Description Default
count int

Total number of points to return. Must be >= 2.

None
step float

Fixed real distance between consecutive points, letting the count fall out of the geometry. Mutually exclusive with count.

None
spacing SpacingCurve or callable

Distribution of points along the path. Defaults to equal spacing.

None
distribute ('length', 'even', 'per_path')

How count is split across a multi-path design.

"length"
by ('length', 'parameter')

Place points by real distance along the curve (the default), or by even steps through its parametrization.

"length"

Returns:

Type Description
Design

The resampled design, ready to plot or export.

Source code in src/geomotif/core/motif.py
def generate(
    self,
    count: int | None = None,
    *,
    step: float | None = None,
    spacing: SpacingLike | None = None,
    distribute: Distribution = "length",
    by: Placement = "length",
) -> Design:
    """Build, then resample to ``count`` points (or a fixed ``step`` distance).

    Parameters
    ----------
    count : int, optional
        Total number of points to return. Must be >= 2.
    step : float, optional
        Fixed real distance between consecutive points, letting the count
        fall out of the geometry. Mutually exclusive with ``count``.
    spacing : SpacingCurve or callable, optional
        Distribution of points along the path. Defaults to equal spacing.
    distribute : {"length", "even", "per_path"}, optional
        How ``count`` is split across a multi-path design.
    by : {"length", "parameter"}, optional
        Place points by real distance along the curve (the default), or
        by even steps through its parametrization.

    Returns
    -------
    Design
        The resampled design, ready to plot or export.
    """
    return resample(
        self.build(),
        count,
        step=step,
        spacing=spacing,
        distribute=distribute,
        by=by,
    )