@rickosborne/planar
TypeScript icon, indicating that this package has built-in type declarations

2025.3.12 • Public • Published

@rickosborne/planar

A small collection of 2D Cartesian and graphics related data structures and algorithms. Built on @rickosborne/typical for types, @rickosborne/guard for guards, and @rickosborne/foundation for basic data structures and algorithms.

Usage

Install via your favorite package manager.

Each package supports CommonJS require, ESM import, and TypeScript usage.

You also have a choice: barrel imports or direct imports.

Barrel imports mean you're going to require/import everything from the same package-level namespace:

// CommonJS
const { isPlainObject, isListOf } = require("@rickosborne/guard");
// ESM / TypeScript
import { isPlainObject, isListOf } from "@rickosborne/guard";

Implications:

  • Nice and simple.
  • Your build system needs to do tree-shaking well ... or you'll end up adding the entire package even if you only import two functions.

The other option is to use direct imports:

// CommonJS
const { isPlainObject } = require("@rickosborne/guard/is-object");
const { isListOf } = require("@rickosborne/guard/is-list-of");
// ESM / TypeScript
import { isPlainObject } from "@rickosborne/guard/is-object.js";
import { isListOf } from "@rickosborne/guard/is-list-of.js";

Implications:

  • You (probably) don't have to worry about tree-shaking as your build (likely) ends up with only the functions you need.

If you're using a modern build system, there aren't any strong reasons to prefer one way over the other. It's really just down to your personal preference.

A quick note about file extensions

Do you need to use file extensions? And if so, which extensions?

Honestly ... this is a dumpster fire question. It really comes down to your own setup and configuration.

Within each package itself:

  • The CommonJS files all have .cjs extensions.
  • The ESM files all have .mjs extensions.
  • Node subpath exports have been set up to send .js imports to the .cjs (via require) or .mjs (via import) files, depending on your setup.

So, in theory, the only extension which won't work would be .ts because the source isn't included.

If you run into a problem with a particular configuration, file a GitHub issue with:

  • Your tsconfig.json's module, moduleResolution, and target settings.
  • Your package.json's type and imports settings.
  • An example of another package which imports correctly for you.

License

This package is licensed as CC-BY-NC-SA-4.0 unless otherwise noted. That is, Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International.


API

Enums

Orientation

 enum Orientation 

Measure of the turn of an angle, based on the order of the three points which define it.

Functions

angle

angle: (area: number, orientation: Orientation, rad: number) => Angle

angleMeasures

angleMeasures: (a: Point, b: Point, c: Point) => AngleMeasures

Calculate the intermediary values used in measuring an angle defined by the intersection of two line segments along three points: A, B, and C.

boundingBoxOf

boundingBoxOf: (shape: Shape | LineSegment) => Rect

Calculate the bounding box of the given shape, meaning a minimum point plus a width and height. Note that the x and y values will be the numeric minimums, which will be bottom-left in Cartesian space and top-left in pixel space.

boundingBoxOfCircle

boundingBoxOfCircle: (circle: Circle) => Rect

Calculate the bounding box of the given circle, meaning a minimum point plus a width and height. Note that the x and y values will be the numeric minimums, which will be bottom-left in Cartesian space and top-left in pixel space.

boundingBoxOfLineSegment

boundingBoxOfLineSegment: (segment: LineSegment) => Rect

Calculate the bounding box which would contain the given line segment.

boundingBoxOfPath

boundingBoxOfPath: (path: Path) => Rect

Calculate the bounding box which would contain the points in the given path.

cartesianOrientationOfPolygon

cartesianOrientationOfPolygon: (poly: Polygon) => Orientation

Calculate the orientation of a polygon as defined by the order of its points and its signed area. This does not necessarily imply the polygon is convex. This version uses Cartesian coordinates, where the origin is in the bottom left. See also gfxOrientationOfPolygon.

centroidOfPolygon

centroidOfPolygon: (poly: Polygon) => Point

Calculate the centroid of a polygon, which is the weighted mean of its points. If the polygon has zero signed area, the centroid of the polygon's bounding box will be returned. The centroid is not guaranteed to be within the polygon if it is not convex.

detailedIsConvex

detailedIsConvex: (poly: Polygon) => IsConvex

More detailed check to see if a polygon is convex. Tracks "bad" points and returns them if found. Slower than fastIsConvex, and doesn't necessarily return a better result, though it may give more information in scenarios where you want to try to split the polygon into smaller convex polygons.

fastIsConvex

fastIsConvex: (poly: Polygon) => boolean

Performs a rudimentary check of a polygon, calculating angles at each vertex and checking for sign flips in the line segment cross products. The result may not be reliable for symmetric shapes where the signed areas cancel out. This version also does not track "bad" points.

gfxOrientationOfPolygon

gfxOrientationOfPolygon: (poly: Polygon) => Orientation

Calculate the orientation of a polygon as defined by the order of its points and its signed area. This does not necessarily imply the polygon is convex. This version uses graphics coordinates, where the origin is in the top left. See also cartesianOrientationOfPolygon.

isCircle

isCircle: (obj: unknown) => obj is Circle

Guard for whether the given value has x and y coordinates plus a radius r measure. May have more!

isDirectedSegment

isDirectedSegment: (obj: unknown) => obj is DirectedSegment

Guard for whether the given value has a and b Point properties. May have more!

isLineSegment

isLineSegment: (obj: unknown) => obj is LineSegment

Guard for whether the given value has blue and gold Point properties. May have more!

isPath

isPath: (obj: unknown, deep?: boolean) => obj is Path

Guard for whether the given value has a list of points. It will not exhaustively check the points for validity unless deep is true.

isPoint

isPoint: (obj: unknown) => obj is Point

Guard for whether the given value has x and y coordinates. May have more!

isRect

isRect: (obj: unknown) => obj is Rect

Guard for whether the given value has x and y coordinates plus w and h measures. May have more!

measureAngle

measureAngle: (a: Point, b: Point, c: Point) => Angle

Given three points which define the ordered intersection of two line segments, calculate the angle between them.

measureAngles

measureAngles: (poly: Polygon) => PolygonWithRadians

Upgrade a polygon to include angle measurements for its vertices.

perimeterOfPolygon

perimeterOfPolygon: (poly: Polygon) => number

point

point: (x: number, y: number) => Point

pointAdd

pointAdd: (a: Point, b: Point) => Point

pointEq

pointEq: (a: Point, b: Point) => boolean

polygonFromLineSegment

polygonFromLineSegment: (segment: LineSegment) => Polygon

Convert the given LineSegment to Polygon format. Arbitrarily places the left/bottom point first and right/top point second.

polygonFromRect

polygonFromRect: (rect: Rect) => Polygon

Convert the given Rect to Polygon format.

prettyRad

prettyRad: (rad: number, epsilon?: number) => string

Try to figure out a reasonably human-readable fraction for the given angle in radians.

reversePolygon

reversePolygon: <P extends Polygon>(poly: P) => P

Reverse the point order of a polygon, while keeping the starting point the same.

signedAreaOfPolygon

signedAreaOfPolygon: (poly: Polygon) => number

Calculate the signed area of a polygon.

signOf

signOf: (n: number) => Sign

Reduce a number to a unit (1) with a sign.

TypeAliases

Angle

type Angle = {
    area: number;
    orientation: Orientation;
    rad: number;
};

An angle between two line segments, often as an interior angle for a polygon.

AngleMeasures

type AngleMeasures = {
    abx: number;
    aby: number;
    bcx: number;
    bcy: number;
    area: number;
    orientation: Orientation;
};

Mixin for the intermediary values used for calculating angles defined by the intersection of two line segments across three points: A, B, and C.

Circle

type Circle = Point & {
    r: number;
};

An equal radius out from a center point.

ConvexWithOrientation

type ConvexWithOrientation = {
    convex: true;
    orientation: Orientation.Counter | Orientation.Clockwise;
};

Result of a calculation of whether a polygon is convex indicating the polygon is complex.

DirectedSegment

type DirectedSegment = {
    a: Point;
    b: Point;
};

A directed line segment joining two points in a specific order.

IsConvex

type IsConvex = Either<ConvexWithOrientation, NotConvex>;

Result of a calculation of whether a polygon is convex.

LineSegment

type LineSegment = {
    blue: Point;
    gold: Point;
};

An undirected line segment joining two points.

NotConvex

type NotConvex = {
    badPoints?: number[];
    convex: false;
    firstOrientation?: Orientation | undefined;
    overallOrientation?: Orientation | undefined;
};

Result of a calculation of whether a polygon is convex, indicating that it does not seem to be, or is still unknown.

Path

type Path = {
    points: Point[];
};

An ordered sequence of points.

Point

type Point = {
    x: number;
    y: number;
};

Coordinates in 2D space.

Polygon

type Polygon = Path;

An ordered sequence of points, generally assuming the last point connects back around to the first.

PolygonWithRadians

type PolygonWithRadians = {
    points: WithAngles<Point>[];
};

A sequence of points where the interior angle at each has been measured.

Rect

type Rect = Point & {
    h: number;
    w: number;
};

A rectangle with no rotation. Note that this structure does not encode whether the origin point is in the bottom left (Cartesian) or top left (graphics).

Shape

type Shape = Polygon | Rect | Circle;

For algorithms which work on basic shapes.

Sign

type Sign = -1 | 0 | 1;

Could be an Orientation, or just a simple indication of the sign of a number.

WithAngles

type WithAngles<T extends object> = T & Angle;

Mixin which adds angle information to some other type.

Variables

CCW

CCW = Orientation.Counter

Shorter version of Orientation.Counter.

CONVEX_TRUE_CCW

CONVEX_TRUE_CCW: IsConvex

Basic shared value for a true IsConvex result with a counterclockwise orientation.

CONVEX_TRUE_CW

CONVEX_TRUE_CW: IsConvex

Basic shared value for a true IsConvex result with a clockwise orientation.

CW

CW = Orientation.Clockwise

Shorter version of Orientation.Clockwise.

EPSILON

EPSILON = 0.00001

ORIGIN

ORIGIN: Readonly<{
    x: 0;
    y: 0;
}>

PI

PI: number

PI_2

PI_2: number

PI_2_3

PI_2_3: number

PI_3

PI_3: number

PI_3_4

PI_3_4: number

PI_4

PI_4: number

PI_5

PI_5: number

PI_6

PI_6: number

PI_7

PI_7: number

PI_8

PI_8: number

PI_9

PI_9: number

SQRT_2

SQRT_2: number

SQRT_3

SQRT_3: number

SQRT_5

SQRT_5: number

STRAIGHT

STRAIGHT = Orientation.Straight

Shorter version of Orientation.Straight.

TWO_PI

TWO_PI: number

Package Sidebar

Install

npm i @rickosborne/planar

Weekly Downloads

12

Version

2025.3.12

License

CC-BY-NC-SA-4.0

Unpacked Size

115 kB

Total Files

104

Last publish

Collaborators

  • rickosborne