Skip to content

Math & Geometry

Ripl ships with a focused set of math and geometry utilities used throughout the rendering engine. These cover angle conversion, point operations, bounding boxes, polygon generation, and SVG path sampling. Generic numeric helpers like numberClamp, numberExtent, and numberSum are provided by the @ripl/utilities package.

NOTE

For the full API, see the Math & Geometry API Reference.

Demo

The demo below visualizes several geometry utilities: polygon vertex generation, midpoints, waypoints, and bounding boxes.

Points

A Point is a simple [x, y] tuple used throughout Ripl:

ts
import type {
    Point,
} from '@ripl/web';

const p: Point = [100, 200];

Midpoint and Waypoint

ts
import {
    getMidpoint,
    getWaypoint,
} from '@ripl/web';

const a: Point = [0, 0];
const b: Point = [100, 100];

getMidpoint(a, b); // [50, 50]
getWaypoint(a, b, 0.25); // [25, 25]
getWaypoint(a, b, 0.75); // [75, 75]

Equality and Distance

ts
import {
    arePointsEqual,
    getHypLength,
} from '@ripl/web';

arePointsEqual([0, 0], [0, 0]); // true
getHypLength(3, 4); // 5

Angles

ts
import {
    degreesToRadians,
    radiansToDegrees,
    TAU,
} from '@ripl/web';

degreesToRadians(90); // π/2
radiansToDegrees(TAU); // 360
TAU; // 6.283... (2π)

Theta Points

Compute a point at a given angle and distance from a center:

ts
import {
    getThetaPoint,
} from '@ripl/web';

getThetaPoint(0, 100, 200, 200); // [300, 200]
getThetaPoint(Math.PI / 2, 100, 200, 200); // [200, 300]

Polygons

Generate vertex points for a regular polygon:

ts
import {
    getPolygonPoints,
} from '@ripl/web';

const hexagon = getPolygonPoints(6, 200, 200, 80);
// 7 points (6 vertices + closing point)

const triangle = getPolygonPoints(3, 100, 100, 50, false);
// 3 points (no closing point)

Bounding Boxes

The Box class represents an axis-aligned bounding box:

ts
import {
    Box,
    getContainingBox,
    isPointInBox,
} from '@ripl/web';

const box = new Box(10, 20, 110, 220);
box.width; // 200
box.height; // 100

isPointInBox([50, 50], box); // true
isPointInBox([0, 0], box); // false

Box.empty(); // Box(0, 0, 0, 0)

Containing Box

Compute the smallest box that contains a collection of items:

ts
const boxes = [
    new Box(0, 0, 50, 50),
    new Box(100, 100, 200, 200),
];

const container = getContainingBox(boxes, box => box);
// Box(0, 0, 200, 200)

Numeric Helpers

Generic numeric helpers live in @ripl/utilities. The plain min/max wrappers have been removed in favour of the native Math.min/Math.max.

ts
import {
    numberClamp,
    numberExtent,
    numberFractional,
    numberMaxOf,
    numberMinOf,
    numberSum,
} from '@ripl/utilities';

numberClamp(150, 0, 100); // 100
numberClamp(-5, 0, 100); // 0
numberFractional(3.7); // 0.7

Math.min(10, 20, 5); // 5
Math.max(10, 20, 5); // 20

const data = [{ v: 10 }, { v: 50 }, { v: 30 }];
numberMinOf(data, d => d.v); // 10
numberMaxOf(data, d => d.v); // 50
numberExtent(data, d => d.v); // [10, 50]
numberSum(data, d => d.v); // 90

SVG Path Utilities

Measure and sample points along SVG path strings:

ts
import {
    getPathLength,
    samplePathPoint,
} from '@ripl/web';

const d = 'M 0,0 L 100,0 L 100,100';
getPathLength(d); // ~200

const point = samplePathPoint(d, 50);
// { x: 50, y: 0, angle: 0 }

samplePathPoint returns the position and tangent angle at a given distance along the path, which powers the Text on Path feature.

Border Radius

Normalize a border radius value into a four-corner tuple:

ts
import {
    normalizeBorderRadius,
} from '@ripl/web';

normalizeBorderRadius(8); // [8, 8, 8, 8]
normalizeBorderRadius([4, 8, 4, 8]); // [4, 8, 4, 8]