OPNS/IPNS flag on the algebra — the OPNS/IPNS interpretation flag
moves off per-call opns=... keyword arguments and onto the algebra
itself. Algebra.opns (mutable, default True) is delegated by
MV.opns and forwarded by all eight Basis* classes, so the setting is
read once from the algebra for both creation and analysis.
Typed per-entity analyzers — explicit public analyzers
(analyze_point, analyze_direction, analyze_line, analyze_plane,
analyze_circle, analyze_sphere, analyze_point_pair,
analyze_hpoint, analyze_hdirection, analyze_space) in every
analysis_* module, reading mv.algebra.opns and raising on a
mismatched structure.
MV-accepting entity constructors — Point(mv), Direction(mv),
Line(mv), Plane(mv), Circle(mv), Sphere(mv), PointPair(mv),
HPoint(mv), HDirection(mv), and Space(mv) convert a multivector via
the matching typed analyzer. Nested fields auto-convert their MV
arguments too (each Point/Direction/scalar component), plus
Line.from_points(start, end).
Geometry.__call__ — geo(obj) now forwards to create(obj) for
entities/operators and to analyze(obj) for multivectors.
E = einf ^ eo member added to BasisN3 and BasisN2.
Color enum — a default colour palette (StrEnum) in
viz/_colors.py, exported from viz.
MV.prune(tol=...) — prune() now accepts an optional tolerance,
defaulting to algebra.precision, instead of silently using a hard-coded
value.
Random entity generators — RndPoint/RndDirection (plus the
Distribution/Uniform/Normal base classes) generate Point/Direction
dataclasses from per-coordinate distributions. Geometry(algebra, seed=...)
owns a seeded NumPy generator (geo.rng), and geo(RndPoint(...)) /
geo([RndPoint(...) for _ in range(n)]) (or count=n) materialize them into
MVs via the algebra's create dispatch, honoring OPNS/IPNS.
macOS compilation (Apple Intel + Apple Silicon) — the C++ bindings now
compile on macOS. Apple Clang/libc++ portability fixes (removing the invalid
std forward declaration in StrideIterator.h and fixing a lambda
this-capture in Matrix.h) enable Intel (x86_64) builds, while gating the
x86-only includes/intrinsics (<x86intrin.h>, _mm_popcnt_u32) and compile
flags (-msse4.1/-mpopcnt) behind an x86 check enables Apple Silicon
(arm64) builds.
Precompiled Apple Silicon wheels — the publish workflow now builds and
uploads precompiled macosx_*_arm64 wheels (via macos-14) for CPython 3.12
and 3.13, alongside the existing Linux/Windows wheels.
Removed opns from the analysis and creation paths — analyze*,
analyze_entity, create_entity, create, and Geometry no longer
accept an opns override; they read algebra.opns.
Removed geometry-creating methods from basis classes —
point/direction/line/plane/vector/rotor no longer live on
Basis*; geometry is created only through the geometry submodule.
E2/E3 create_point no longer raises — a point maps to its Euclidean
components independent of OPNS/IPNS.
Imaginary entities now raise NotImplementedError — ImagPointPair,
ImagCircle, and imaginary ImagSphere in N2/N3 are not yet implemented.
N2/N3 point-pair separation — the point-pair decomposer returned the
wrong point distance (half the true value in N2) and an unnormalized
direction. S* is now normalized by its e₀ coefficient and
separation = 2·half_dist.
N2/N3 circle/point-pair normalisation — the IPNS circle/point-pair was
not normalized by its e₀ coefficient before extracting centre and
radius, so a globally scaled MV produced a wrong radius. Fixed in
_decompose_circle and mirrored into the other N2/N3 decomposers.
Entities split into per-entity modules — the 700-line entities.py
is split into entities/ (point, direction, line, plane, circle, sphere,
point_pair, hpoint, hdirection, space) with shared _util.py /
_coerce.py helpers (to_point / to_direction / to_float).
Analyzer registry — analysis.py registers the typed analyzers with
entities at import time, removing the lazy-import cycle.
Operator constructors — operators.py now explicitly coerces
entity/MV/float arguments, and ReflectionLine/ReflectionPlane no
longer accept legacy keyword fallbacks.
Example scripts updated — all examples under py/examples/ now use
the new API: no opns= keyword arguments, geometry created through the
geometry submodule (or string conversion) instead of the removed basis
factories, PGA demos rewritten around e0/e0_recip rather than
einf/eo, and geo.create/geo.which_entity/geo.which_operator
annotated with the dual create/analyze behavior of Geometry.__call__.