2D geometry — Point, Rect, Circle, Line, Polygon, hit-testing, intersections.
Module geom | Source packages/front/fw/src/io/math/geom.js | Deps linalg | Worker-safe yes
2D geometric primitives with hit-testing, intersections, polygon simplification (Ramer-Douglas-Peucker) and transform via linalg.mat3. No 3D geometry, polygon clipping, or Voronoi.
Resolve
const geom = runtime.resolve('geom');
// Returns: { Point, Rect, Circle, Line, Polygon, hitTest, transform }
API
Point
| Method |
Signature |
Returns |
create |
(x, y) => {x, y} |
Point |
distance |
(a, b) => number |
Euclidean distance |
midpoint |
(a, b) => Point |
Midpoint |
equals |
(a, b, eps?) => boolean |
Comparison with epsilon |
Rect (left/top inclusive, right/bottom exclusive)
| Method |
Signature |
Returns |
create |
(x, y, w, h) => Rect |
Rectangle |
contains |
(rect, point) => boolean |
Hit-test |
intersects |
(a, b) => boolean |
Overlap |
intersection |
(a, b) => Rect | null |
Overlap area |
union |
(a, b) => Rect |
Bounding union |
area |
(rect) => number |
w×h |
center |
(rect) => Point |
Center |
normalize |
(rect) => Rect |
Ensures w,h ≥ 0 |
Circle
| Method |
Signature |
Returns |
create |
(cx, cy, r) => Circle |
Circle |
contains |
(circle, point) => boolean |
Point inside the circle |
intersectsCircle |
(a, b) => boolean |
Two circles |
intersectsRect |
(circle, rect) => boolean |
Circle/rectangle |
Line (segment)
| Method |
Signature |
Returns |
create |
(x1, y1, x2, y2) => Line |
Segment |
length |
(line) => number |
Length |
intersects |
(a, b) => boolean |
Intersecting |
intersection |
(a, b) => Point | null |
Intersection point |
distanceToPoint |
(line, point) => number |
Minimum distance |
closestPoint |
(line, point) => Point |
Closest point on the segment |
Polygon
| Method |
Signature |
Returns |
create |
(points: Point[]) => Polygon |
Polygon |
area |
(poly) => number |
Signed area (> 0 = CCW) |
isCcw |
(poly) => boolean |
Counter-clockwise orientation |
contains |
(poly, point) => boolean |
Ray-casting |
bbox |
(poly) => Rect |
Bounding box |
simplify |
(poly, tolerance) => Polygon |
Ramer-Douglas-Peucker |
Global helpers
| Method |
Description |
hitTest(shape, point) |
Dispatches to Rect / Circle / Polygon |
transform(point, mat3) |
Applies linalg.mat3.transform |
Examples
Generic hit-test
const geom = runtime.resolve('geom');
const rect = geom.Rect.create(0, 0, 100, 50);
const circle = geom.Circle.create(50, 25, 30);
geom.hitTest(rect, { x: 10, y: 10 }); // true
geom.hitTest(circle, { x: 50, y: 25 }); // true
Rectangle intersection
const a = geom.Rect.create(0, 0, 10, 10);
const b = geom.Rect.create(5, 5, 10, 10);
if (geom.Rect.intersects(a, b)) {
const overlap = geom.Rect.intersection(a, b);
// { x: 5, y: 5, w: 5, h: 5 }
}
Simplify a GPS polygon
const path = geom.Polygon.create(gpsPoints);
const simplified = geom.Polygon.simplify(path, 0.001); // tolerance in degrees
Worker Usage
const worker = fw.createWorker(
function ({ libs, args }) {
const geom = libs.geom;
const rect = geom.Rect.create(args.x, args.y, args.w, args.h);
const hits = args.points.filter(p => geom.Rect.contains(rect, geom.Point.create(p[0], p[1])));
self.postMessage(hits);
},
{ dependencies: ['geom'], args: { x: 0, y: 0, w: 100, h: 100, points: [[10, 10], [200, 200]] } }
);
Notes
- Border convention:
Rect.contains — left/top inclusive, right/bottom exclusive (x < rect.x + rect.w).
- Non-closed polygon: the last point is auto-closed back to the first for
area and contains.
Polygon.area returns a signed value — positive = CCW, negative = CW. Use Math.abs for the geometric area.
hitTest dispatches by duck-typing: presence of w/h → Rect, cx/r → Circle, points → Polygon.
See also
- linalg — linear algebra (matrix transforms)
- interp — spatial interpolation (Bézier, barycentric)