cga
2D conformal geometric algebra for the plane: points, lines, circles, and dipoles, plus the segments, polygons, and polylines composed from them, and the versors (Motor, Flector) that move them — immutable Kotlin types joined by infix operators (join, meet, dot, on, intersects, distanceTo, angleTo, collide, escape, gap, coerceOut, coerceIn, coerceOn), the containment operator in/!in, the orientation flip -, and the transform action *.
The algebra is conformal GA over the null basis e1..e4 (e1, e2 Euclidean; e3 projective; e4 the point at infinity). Components are stored exact at full Double precision; equality and predicates round at the SCALE quantum — store exact, round only for identity.
Every shape class is open and carries a copy rebuild hook, and the shape-preserving operations (*, -, coerceOut, coerceIn, coerceOn, canonical) are generic over the receiver's type: a subclass that overrides its shape's copy comes back from every such operation as itself.
Packages
The constraint tier: operations that solve for the motion satisfying a geometric relation and return the shape already moved. The dual verbs coerceOut and coerceIn keep a polygon out of — respectively inside — an oriented solid region, in the standard library's coerce posture: an already-valid receiver comes back untouched, a violating one minimally moved — generic over the receiver's type, so a Polygon subclass comes back as its own class. coerceOn, the equality constraint beside them, rests a polygon against the region: where the two inequality verbs accept every pose that does not violate, coerceOn accepts exactly the touching ones — resolved through collide when the subject overlaps the region and through gap when it lies apart.
The algebra tier: infix operators over the shapes, returning geometry or Double raw at full precision (the segment-bounded meets return null on a miss) — scalar multiplication (*), the inner-product family (dot), join (join, the wedge ∧), meet (meet, the antiwedge ∨), and the two interior products: contraction (contract, the bulk contraction a ∨ b^★) and expansion (expand, the weight expansion a ∧ b^☆).
The projection tier: composite operations built from the products. Projection (project, b ∨ (a ∧ b^☆)) carries a shape onto a higher-grade target; antiprojection (antiproject, b ∧ (a ∨ b^☆)) carries one onto a lower-grade target. Both divide by the target's self-pairing b ∘ b, so the receiver's weight and orientation carry through — an imaginary target (negative self-pairing) negates every component, and a target whose self-pairing vanishes (a line at infinity, a zero-radius circle, coincident endpoints) floods the division instead of throwing. The one bounded target, a Segment, is reached through its carrier's projection and clamped to the segment — no self-pairing of its own.
The query tier, split by answer kind: predicates carries the Boolean queries, rounded at the SCALE quantum; measures carries the scalar measurements — raw Euclidean distances and angles; the data queries at this level — penetration and gap — answer with geometry-flavored data — offending edge, depth, normal, the shortest segment — whose values stay raw behind rounded existence gates.
The transform tier: the versors that move shapes — Motor (rotations and translations, built by the T and R factories) and Flector (reflections and glide reflections, built by F and G) — applied with shape * versor and composed with versor * versor. The per-shape actions live in the primitives and composites subpackages; a receiver typed only as Shape moves through the same spelling — the Shape * Versor dispatch delegates to the per-shape actions, preserving the receiver's class.
The action tier for the composites: shape * versor moves a segment by its endpoints and a polyline or polygon vertex-by-vertex, with the same * Motor / * Flector / * Versor trio per shape. Results carry full raw Double precision, and each form is generic over the receiver's type — the moved geometry returns through the shape's copy hook, so a subclass overriding it comes back as its own class.
The action tier for the primitives: shape * versor applies a versor's motion to each of the five primitives and returns the same primitive type — a * Motor form, a * Flector form, and a * Versor dispatch per shape. Results carry full raw Double precision, and each form is generic over the receiver's type — the moved geometry returns through the shape's copy hook, so a subclass overriding it comes back as its own class. A motor's rigid motion preserves orientation; a flector's mirror motion reverses it, and the oriented types — Line, Dipole, Circle — record the reversal in their own components. Imaginary and at-infinity operands transform faithfully — first-class data, never an error — and no action on a primitive throws.