Security News
Oracle Drags Its Feet in the JavaScript Trademark Dispute
Oracle seeks to dismiss fraud claims in the JavaScript trademark dispute, delaying the case and avoiding questions about its right to the name.
@thi.ng/geom
Advanced tools
[!NOTE] This is one of 201 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
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) |
[!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:
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!
Tessellation behaviors:
Tessellation post-processing:
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):
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.42 KB
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 - 2025 Karsten Schmidt // Apache License 2.0
FAQs
Functional, polymorphic API for 2D geometry types & SVG generation
We found that @thi.ng/geom demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Oracle seeks to dismiss fraud claims in the JavaScript trademark dispute, delaying the case and avoiding questions about its right to the name.
Security News
The Linux Foundation is warning open source developers that compliance with global sanctions is mandatory, highlighting legal risks and restrictions on contributions.
Security News
Maven Central now validates Sigstore signatures, making it easier for developers to verify the provenance of Java packages.