Skip to content

symmetry¤

Symmetry for either route: find the symmetry of a domain, mesh one unit, and expand it by the group.

Classes¤

SymmetryReport ¤

SymmetryReport(
    domain: Domain,
    group: SymmetryGroup,
    tol: float,
    near: float,
    include: Sequence[str],
    deviations: dict[str, tuple[float, Any]],
    near_misses: list[tuple[str, float, Any]],
    circle_like: bool,
    max_order: int,
)

The detected symmetry of a domain.

Attributes:

  • group (.group.SymmetryGroup) –

    The largest group whose every element passed.

  • centre ([x, y, z]) –
  • keys (list[str]) –

    The names a script picks a unit by -- R90, M45 ...

  • deviations (dict) –

    key -> (worst distance, (tag, point)) for every element of group. How far from exact the drawing is.

  • near_misses (list) –

    (key, worst distance, (tag, point)) for elements that did NOT pass but came within the near-miss limit -- almost always a drawing slightly off, and the tag says which curve.

  • tol, near (float) –
  • circle_like (bool) –

    Every tested rotation passed: the domain is (sampled from) a circle, and the reported order is only the highest one tested.

  • domain (.domain.Domain) –

Methods:¤

by_feature ¤
by_feature() -> list[tuple[str, SymmetryReport]]

The group with walls only, then adding holes, guides and poles in turn.

Returns:

  • list[label, SymmetryReport] –

    Only the stages that add something present in the domain. Comparing consecutive groups says which kind of feature breaks the symmetry.

geometry ¤
geometry(arc_radius: float | None = None) -> dict[str, Any]

Simple compas geometry that shows the symmetry.

Returns:

  • dict –

    'centre': a Point. 'mirrors': one Line per mirror axis, clipped to the outer wall. 'rotations': a Polyline arc from the first mirror axis (or +x) through the smallest rotation angle, with a short tick at its end. 'near_misses': a Point at the worst sample of each near miss.

notes ¤
notes() -> list[str]

Plain-language remarks a user should read before choosing a unit.

unit_outline ¤
unit_outline(
    keys: Sequence[str] | None = None, centre: str = "route", seam: Any = None
) -> dict[str, list[Polyline]]

The unit region for keys as closed Polylines, before any meshing.

Returns:

  • dict –

    'loops': the unit's walls (outer loops first), 'seams': the seam segments, as Polylines.

SymmetryGroup ¤

SymmetryGroup(
    centre: Sequence[float] = (0.0, 0.0, 0.0),
    n: int = 1,
    mirrors: bool = False,
    axis: float = 0.0,
)

Cn or Dn about a centre.

Parameters:

  • centre ([x, y, z], default: (0.0, 0.0, 0.0) ) –
  • n (int, default: 1 ) –

    Number of rotations, the identity included. 1 for no rotation.

  • mirrors (bool, default: False ) –

    True for Dn.

  • axis (float, default: 0.0 ) –

    Angle of one mirror axis, radians. Only meaningful for Dn; the others are at axis + k pi / n. Stored as the smallest of them.

Attributes¤

elements property ¤
elements: list[Element]

Identity first, then the rotations by increasing angle, then the mirrors by increasing axis angle.

Methods:¤

apply ¤
apply(element: Element, point: Sequence[float]) -> list[float]

element applied to a point, about centre.

compose ¤
compose(first: Element, second: Element) -> Element

The element first o second -- second applied first.

keys ¤
keys() -> list[str]

Every non-identity element's key.

subgroup ¤
subgroup(keys: str | Sequence[str] | None = None) -> SymmetryGroup

The subgroup generated by keys; None is the whole group, [] the trivial one.

subgroups ¤
subgroups() -> list[SymmetryGroup]

Every subgroup, largest first -- what a user can choose between.

Domain ¤

Domain(
    outer: Sequence[Any] | None = None,
    inners: Sequence[Sequence[Any]] | None = None,
    guides: Sequence[Sequence[Any]] | None = None,
    poles: Sequence[Sequence[float]] | None = None,
)

outer, inners, guides and poles as plain point lists (loops open), as compas Data.

Methods:¤

area_centroid ¤
area_centroid() -> list[float] | None

The centroid of the REGION: outer minus holes. None with no outer.

SymmetricUnit ¤

SymmetricUnit(*args: Any, **kwargs: Any)

A coarse quad layout of one symmetric unit.

Build one with decomposition.symmetry_unit(...) or build_unit.

Methods:¤

check ¤
check() -> tuple[bool, list[str]]

(ok, notes) -- whether this unit can be densified and expanded.

notes names every problem found; an empty list means none.

densification ¤
densification(*args: Any, **kwargs: Any) -> SymmetricQuadUnit

As CoarsePseudoQuadMesh.densification; returns a SymmetricQuadUnit.

expand_symmetrically ¤
expand_symmetrically() -> CoarsePseudoQuadMesh

The global COARSE layout: every copy of the unit, welded along the seams.

Returns a plain CoarsePseudoQuadMesh carrying the edge shapes and attributes['orbits'].

fingerprint ¤
fingerprint() -> str

What a dense unit was built from: densities, patterns and the corners.

from_coarse classmethod ¤
from_coarse(
    coarse: CoarsePseudoQuadMesh,
    data: dict[str, Any] | None = None,
    field: Any = None,
    decomposition: Any = None,
) -> SymmetricUnit

Wrap a coarse layout as a unit. data defaults to the layout's own attributes['symmetry'] -- for re-wrapping a copy that lost its class.

glued_strips ¤
glued_strips() -> list[list[int]]

Groups of strip keys that are one strip of the global mesh across rotation seams.

quad_mesh ¤
quad_mesh(*args: Any, **kwargs: Any) -> SymmetricQuadUnit

Densify the unit into a SymmetricQuadUnit, with the unit's own field by default.

seam_gaps ¤
seam_gaps() -> list[list[Any]]

Stretches of seam the layout's boundary does NOT run along, as [seam name, t_lo, t_hi]. Empty when every seam is fully covered.

seam_partners ¤
seam_partners() -> tuple[
    dict[int, int], list[tuple[float, int]], list[tuple[float, int]]
]

Rotation seams only: (partners, unmatched on A, unmatched on B).

snap_to_seams ¤
snap_to_seams(fraction: float = 0.25) -> int

Project boundary corners lying near a seam onto it, in place. Returns the number moved.

SymmetricQuadUnit ¤

The dense mesh of a symmetric unit. Made by SymmetricUnit.quad_mesh.

Methods:¤

expand_symmetrically ¤
expand_symmetrically(unit: SymmetricUnit | None = None) -> PseudoQuadMesh

The global quad mesh.

Parameters:

  • unit (SymmetricUnit, default: None ) –

    The coarse unit this was densified from. When given, it is checked against what the dense mesh was built from, and a mismatch raises -- a density changed after quad_mesh() would weld seams with different vertex counts on either side.

Returns:

  • PseudoQuadMesh –

    With attributes['orbits'].

Functions¤

find_symmetry ¤

find_symmetry(
    outer: Sequence[Any] | None = None,
    inners: Sequence[Sequence[Any]] | None = None,
    guides: Sequence[Sequence[Any]] | None = None,
    poles: Sequence[Sequence[float]] | None = None,
    tol: float | None = None,
    include: Sequence[str] = INCLUDE,
    max_order: int = 12,
    near: float | None = None,
    centre: Sequence[float] | None = None,
    domain: Domain | None = None,
) -> SymmetryReport

Detect the rotations and mirrors that map the input onto itself.

Parameters:

  • outer (Sequence[Any] | None, default: None ) –

    The domain. Or pass domain (a Domain) instead.

  • inners (Sequence[Any] | None, default: None ) –

    The domain. Or pass domain (a Domain) instead.

  • guides (Sequence[Any] | None, default: None ) –

    The domain. Or pass domain (a Domain) instead.

  • poles (Sequence[Any] | None, default: None ) –

    The domain. Or pass domain (a Domain) instead.

  • tol (float, default: None ) –

    Drawing precision: the largest distance at which an image still counts as landing on the input. Default 1e-4 times the bounding-box diagonal.

  • include (sequence of {'walls', 'holes', 'guides', 'poles'}, default: INCLUDE ) –

    What must be symmetric. Leave out 'guides' to get the symmetry of the plate regardless of an off-centre cable.

  • max_order (int, default: 12 ) –

    Highest rotation order tested.

  • near (float, default: None ) –

    Deviations up to this are reported as near-misses. Default 1e-2 times the diagonal.

  • centre ([x, y, z], default: None ) –

    Override the area centroid.

Returns:

build_unit ¤

build_unit(
    report: SymmetryReport,
    mesher: Callable[..., Any],
    keys: str | Sequence[str] | None = None,
    centre: str = "route",
    seam: float | None = None,
    route: str | None = None,
) -> SymmetricUnit

Cut the unit for keys, mesh it with mesher, return a SymmetricUnit.

Parameters:

  • report (SymmetryReport) –
  • mesher (callable) –

    mesher(outer, holes, guides, poles) -> (coarse, extras); see .routes.

  • keys (list[str], default: None ) –

    Symmetries to enforce, by key. Closed under composition. None is the whole detected group.

  • centre (str, default: 'route' ) –

    See .cut.cut_unit.

  • seam (str, default: 'route' ) –

    See .cut.cut_unit.