Note
This is one of 199 standalone projects, maintained as part of the @thi.ng/umbrella monorepo and anti-framework.
🚀 Please help me to work full-time on these projects by sponsoring me on GitHub. Thank you! ❤️
For the Clojure version, please visit: thi.ng/geom-clj
- About
- Support packages
- Related packages
- Status
- Installation
- Dependencies
- Usage examples
- API
- Authors
- License
Functional, polymorphic API for 2D geometry types & SVG generation.
This project is a partially ported from the Clojure version of the same name. All polymorphic operations built on @thi.ng/defmulti.
The following 2D/3D shape primitives are provided. All these types are implemented as
basic data container classes with additional eponymous factory functions (e.g.
Circle
(class) => circle()
(function)), which are encouraged to be used
instead of calling class constructors directly. For many shapes there're
multiple ways to create them, please also check
linked sources and/or docs.
Important
Support for 3D shapes is WIP and currently limited to the various operations provided by this package, but does not yet find any usage outside (e.g. for visualization). Sill, even the ops supported so far can be useful for many use cases...
Shape/Form | Description | Hiccup support |
---|---|---|
AABB | 3D Axis-aligned bounding box | ✅(1) |
Arc | 2D elliptic arc | ✅ |
BPatch | 2D cubic bezier patch (4x4 points) | ✅ |
Circle | 2D circle | ✅ |
ComplexPolygon | 2D polygon w/ holes | ✅ |
Cubic | 2D cubic bezier | ✅ |
Cubic3 | 3D cubic bezier | ✅(1) |
Ellipse | 2D ellipse | ✅ |
Extra | Custom embedded hiccup/SVG data | ✅ |
Group | group of 2D shapes | ✅ |
Group3 | group of 3D shapes | ✅(1) |
Line | 2D line segment | ✅ |
Line3 | 3D line segment | ✅(1) |
Path | 2D path (w/ optional holes/sub-paths) | ✅ |
Path3 | 3D path (w/ optional holes/sub-paths) | ✅(1),(2) |
Plane | 3D plane | ✅(1) |
Points | 2D point cloud | ✅ |
Points3 | 3D point cloud | ✅(1) |
Polygon | 2D simple polygon (no holes) | ✅ |
Polygon3 | 3D simple polygon (no holes) | ✅ |
Polyline | 2D polyline | ✅ |
Polyline3 | 3D polyline | ✅(1) |
Quad | 2D quad (4-gon) | ✅ |
Quad3 | 2D quad (4-gon) | ✅(1) |
Quadratic | 2D quadratic bezier | ✅ |
Quadratic3 | 3D quadratic bezier | ✅(1) |
Ray | 2D ray | ✅ |
Ray3 | 3D ray | ✅(1) |
Rectangle | 2D rectangle | ✅ |
Sphere | 3D sphere | ✅(1) |
Text | Basic stub for text labels | ✅(3) |
Triangle | 2D triangle | ✅ |
Triangle3 | 3D triangle | ✅(1) |
- (1) valid hiccup format, but currently still missing external tool/library support
- (2) only lines, cubic & quadratic curve segments supported
- (3) merely treated as a point in space (e.g. used for placing text labels), no geometry of text itself
Note
Sidebar with background information for advanced usage only. Most users can safely ignore this.
With very few exceptions these all are implementing the IToHiccup
interface and so
can be easily converted (via
hiccup) to a
variety of other formats, incl. conversion to SVG.
By design, for more flexibility and for performance reasons, the hiccup flavor
used by this package is not compatible with that used by
thi.ng/hiccup-svg,
though the latter provides a
convertTree()
function for that purpose. This is only needed for some cases of dynamic
in-browser SVG DOM creation...
Instead, the hiccup format used here for interim interop is compatible with that used by the thi.ng/hiccup-canvas package (see its readme for details) and avoids extraneous stringification of geometry data and attrib values. A brief example to illustrate some differences:
import { circle, asSvg } from "@thi.ng/geom";
import { convertTree } from "@thi.ng/hiccup-svg";
// a circle with RGBA color attrib
const a = circle([100, 200], 300, { fill: [1, 0.5, 0, 1] });
// invocation of the IToHiccup interface (all shapes support it)
console.log(a.toHiccup());
// [ "circle", { fill: [ 1, 0, 0, 1 ] }, [ 100, 200 ], 300 ]
// convert shape into to a SVG compatible hiccup format
// (i.e. stringify attributes, convert colors etc.)
console.log(convertTree(a));
// [ "circle", { fill: "#ff8000", cx: "100", cy: "200", r: "300" } ]
// asSvg() automatically uses convertTree() when serializing shape(s) to SVG
console.log(asSvg(a));
// <circle fill="#ff8000" cx="100" cy="200" r="300"/>
For 2D shape types only, SVG conversion is included via the
asSvg()
and
svgDoc()
functions.
The following operations are provided (many also applicable to shape groups directly and/or perform automatic resampling/conversion if needed).
Operation | Description |
---|---|
applyTransforms() |
applies any spatial transformation attributes |
arcLength() |
compute arc length / perimeter of shape boundary |
area() |
signed/unsigned surface area |
asCubic() |
convert shape boundary to cubic bezier segments |
asPath() |
convert shape to path |
asPolygon() |
convert shape to polygon(s) |
asPolyline() |
convert shape to polyline(s) |
asSector() |
convert arc to sector (path) |
asSvg() |
serialize shape/group/hierarchy to SVG |
bounds() |
compute bounding box |
center() |
center shape around origin or point |
centroid() |
compute shape centroid |
classifyPoint() |
classify point in relation to shape boundary (in/out) |
clipConvex() |
clip shape against convex boundary |
closestPoint() |
compute closest point on shape boundary |
convexHull() |
compute convex hull (2d only) |
convolve() |
kernel based vertex convolution/filtering |
edges() |
extract edges |
edgesFromTessellation() |
extract unique edges from tessellation results |
fitIntoBounds2() |
rescale/reposition a 2D shape into a destination boundary |
fitIntoBounds3() |
rescale/reposition a 3D shape into a destination boundary |
fitAllIntoBounds2() |
rescale/reposition multiple 2D shapes into a boundary |
flip() |
reverse order (vertices or direction) |
graphFromTessellation() |
create graph from tessellation results |
intersects() |
pairwise shape intersection (various types) |
mapPoint() |
transform world space point into local shape UV space |
offset() |
shape/path offsetting |
pointAt() |
compute point on shape boundary at parametric position |
pointInside() |
check if point is inside shape |
proximity() |
distance from point to shape boundary |
resample() |
resample/convert shape |
rotate() |
rotate shape (2D only) |
rotateAroundAxis() |
rotate shape (3D only) |
rotateX() |
rotate shape (3D only) |
rotateY() |
rotate shape (3D only) |
rotateZ() |
rotate shape (3D only) |
scale() |
scale shape (uniformly/non-uniformly) |
scaleWithCenter() |
scale shape with pivot point |
scatter() |
create random points inside a shape boundary |
simplify() |
simplify shape/boundary (Douglas-Peucker) |
splitArcLength() |
split shapes & groups based on max. arc length |
splitAt() |
split shape/boundary at parametric position |
splitNearPoint() |
split shape/boundary near world position |
subdivCurve() |
recursively apply curve subdivision kernel |
tangentAt() |
compute tangent at parametric position |
tessellate() |
(recursively) tessellate shape |
transformVertices() |
apply custom function to each vertex |
transform() |
apply transformation matrix |
translate() |
translate shape |
union() |
compute shape union |
unmapPoint() |
transform local shape UV point into world space |
vertices() |
extract/sample vertices from shape boundary |
volume() |
compute shape volume (3D only) |
warpPoint() |
transfer single point between the local spaces defined by 2 shapes |
warpPoints() |
transfer points between the local spaces defined by 2 shapes |
warpPointsBPatch() |
transfer points to the local spaces of a bezier patch |
withAttribs() |
shallow copy of given shape with new attribs assigned |
In addition to the above listed direct shape type functions, the following additional shape creation helpers are provided:
- aabbFromMinMax()
- aabbFromMinMaxWithMargin()
- aabbFromCentroid()
- aabbWithCentroidAndMargin()
- intersectionAABB()
- inscribedAABB()
- rectFromMinMax()
- rectFromMinMaxWithMargin()
- rectWithCentroid()
- rectWithCentroidAndMargin()
- intersectionRect()
- inscribedSquare()
- inscribedSquareHex()
Some of the shape operations require configuration with specific algorithms and/or constants. In all cases this relies on a completely extensible mechanism, but the package provides presets for common options/implementations:
To be used with subdivideCurve()
:
To be used with tessellate()
:
See thi.ng/geom-tessellate readme for diagrams/illustrations of each algorithm!
- TESSELLATE_EARCUT
- TESSELLATE_EARCUT_COMPLEX
- TESSELLATE_EDGE_SPLIT
- TESSELLATE_INSET
- TESSELLATE_QUAD_FAN
- TESSELLATE_RIM_TRIS
- TESSELLATE_TRI_FAN
- TESSELLATE_TRI_FAN_BOUNDARY
- TESSELLATE_TRI_FAN_SPLIT
Tessellation behaviors:
- basicTessellation(): default impl
- meshTessellation(): uses kD-tree to deduplicate result points
Tessellation post-processing:
- edgesFromTessellation()
- edgePointsFromTessellation()
- graphFromTessellation()
- groupFromTessellation()
To be used with convolve()
:
This package acts as a higher-level frontend for most of the following related packages (which are more low-level, lightweight and usable by themselves too):
- @thi.ng/geom-accel - n-D spatial indexing data structures with a shared ES6 Map/Set-like API
- @thi.ng/geom-arc - 2D circular / elliptic arc operations
- @thi.ng/geom-axidraw - Conversion and preparation of thi.ng/geom shapes & shape groups to/from AxiDraw pen plotter draw commands
- @thi.ng/geom-clip-line - 2D line clipping (Liang-Barsky)
- @thi.ng/geom-clip-poly - 2D polygon clipping / offsetting (Sutherland-Hodgeman, Grainer-Hormann)
- @thi.ng/geom-closest-point - 2D / 3D closest point / proximity helpers
- @thi.ng/geom-fuzz - Highly configurable, fuzzy line & polygon creation with presets and composable fill & stroke styles. Canvas & SVG support
- @thi.ng/geom-hull - Fast 2D convex hull (Graham Scan)
- @thi.ng/geom-io-obj - Wavefront OBJ parser (& exporter soon)
- @thi.ng/geom-isec - 2D/3D shape intersection checks
- @thi.ng/geom-isoline - Fast 2D contour line extraction / generation
- @thi.ng/geom-poly-utils - 2D polygon/polyline analysis & processing utilities
- @thi.ng/geom-resample - Customizable nD polyline interpolation, re-sampling, splitting & nearest point computation
- @thi.ng/geom-sdf - 2D Signed Distance Field creation from @thi.ng/geom shapes, conversions, sampling, combinators
- @thi.ng/geom-splines - nD cubic & quadratic curve analysis, conversion, interpolation, splitting
- @thi.ng/geom-subdiv-curve - Freely customizable, iterative nD subdivision curves for open / closed geometries
- @thi.ng/geom-tessellate - 2D/3D convex polygon tessellators
- @thi.ng/geom-trace-bitmap - Bitmap image to hairline vector and point cloud conversions
- @thi.ng/geom-voronoi - Fast, incremental 2D Delaunay & Voronoi mesh implementation
- @thi.ng/geom-webgl - WebGL geometry/shape conversion & interop
- @thi.ng/axidraw - Minimal AxiDraw plotter/drawing machine controller for Node.js
- @thi.ng/color - Array-based color types, CSS parsing, conversions, transformations, declarative theme generation, gradients, presets
- @thi.ng/hiccup - HTML/SVG/XML serialization of nested data structures, iterables & closures
- @thi.ng/hiccup-canvas - Hiccup shape tree renderer for vanilla Canvas 2D contexts
- @thi.ng/hiccup-svg - SVG element functions for @thi.ng/hiccup & related tooling
- @thi.ng/viz - Declarative, functional & multi-format data visualization toolkit based around @thi.ng/hiccup
- @thi.ng/webgl - WebGL & GLSL abstraction layer
STABLE - used in production
Search or submit any issues for this package
yarn add @thi.ng/geom
ESM import:
import * as geom from "@thi.ng/geom";
Browser ESM import:
<script type="module" src="https://esm.run/@thi.ng/geom"></script>
For Node.js REPL:
const geom = await import("@thi.ng/geom");
Package sizes (brotli'd, pre-treeshake): ESM: 17.47 KB
- @thi.ng/adjacency
- @thi.ng/api
- @thi.ng/arrays
- @thi.ng/checks
- @thi.ng/defmulti
- @thi.ng/equiv
- @thi.ng/errors
- @thi.ng/geom-arc
- @thi.ng/geom-clip-line
- @thi.ng/geom-clip-poly
- @thi.ng/geom-closest-point
- @thi.ng/geom-hull
- @thi.ng/geom-isec
- @thi.ng/geom-poly-utils
- @thi.ng/geom-resample
- @thi.ng/geom-splines
- @thi.ng/geom-subdiv-curve
- @thi.ng/geom-tessellate
- @thi.ng/hiccup
- @thi.ng/hiccup-svg
- @thi.ng/math
- @thi.ng/matrices
- @thi.ng/object-utils
- @thi.ng/random
- @thi.ng/strings
- @thi.ng/transducers
- @thi.ng/vectors
Note: @thi.ng/api is in most cases a type-only import (not used at runtime)
37 projects in this repo's /examples directory are using this package:
Screenshot | Description | Live demo | Source |
---|---|---|---|
Basic 2D boid simulation and spatial indexing neighbor lookups | Demo | Source | |
Self-modifying, animated typographic grid with emergent complex patterns | Demo | Source | |
Fiber-based cooperative multitasking basics | Demo | Source | |
Polygon point classification (inside/boundary/outside) | Demo | Source | |
Shape conversions & operations using polygons with holes | Demo | Source | |
Convex hull & shape clipping of 2D polygons | Demo | Source | |
Piechart visualization of CSV data | Demo | Source | |
Embedding thi.ng/hiccup data/elements in thi.ng/geom shape hierarchies | Demo | Source | |
geom-fuzz basic shape & fill examples | Demo | Source | |
Hex grid generation & tessellations | Demo | Source | |
(Re)Constructing the thi.ng logo using a 2D signed-distance field | Demo | Source | |
SVG path to SDF, applying deformation and converting back to SVG | Demo | Source | |
2.5D hidden line visualization of digital elevation files (DEM) | Demo | Source | |
Animated, recursive polygon tessellations | Demo | Source | |
Iterating the unique edges of a tessellation | Demo | Source | |
Poisson-disk shape-aware sampling, Voronoi & Minimum Spanning Tree visualization | Demo | Source | |
Augmenting thi.ng/geom shapes for WebGL, using instancing & attribute buffers | Demo | Source | |
Converting thi.ng/geom shape types for WebGL | Demo | Source | |
Mouse gesture / stroke analysis, simplification, corner detection | Demo | Source | |
2D Bezier curve-guided particle system | Demo | Source | |
Animated arcs & drawing using hiccup-canvas | Demo | Source | |
Canvas based Immediate Mode GUI components | Demo | Source | |
Animated sine plasma effect visualized using contour lines | Demo | Source | |
k-means clustering visualization | Demo | Source | |
Live coding playground for 2D geometry generation using @thi.ng/pointfree-lang | Demo | Source | |
2D Poisson-disc sampler with procedural gradient map | Demo | Source | |
Polygon to cubic curve conversion & visualization | Demo | Source | |
Animated, iterative polygon subdivisions & visualization | Demo | Source | |
Quasi-random lattice generator | Demo | Source | |
Minimal rdom-canvas animation | Demo | Source | |
Animated Voronoi diagram, cubic splines & SVG download | Demo | Source | |
2D scenegraph & shape picking | Demo | Source | |
2D scenegraph & image map based geometry manipulation | Demo | Source | |
Compute cubic spline position & tangent using Dual Numbers | Demo | Source | |
SVG path parsing & dynamic resampling | Demo | Source | |
3D wireframe textmode demo | Demo | Source | |
Multi-layer vectorization & dithering of bitmap images | Demo | Source |
If this project contributes to an academic publication, please cite it as:
@misc{thing-geom,
title = "@thi.ng/geom",
author = "Karsten Schmidt",
note = "https://thi.ng/geom",
year = 2013
}
© 2013 - 2024 Karsten Schmidt // Apache License 2.0