manifold-3d
Version:
Geometry library for topological robustness
1,297 lines (1,175 loc) • 71.1 kB
TypeScript
/**
* {@include ../README.md#IncludeInUserGuide}
*
* {@include ../documents/using-manifoldcad.md}
*
* {@include ../documents/tips.md}
*
* @packageDocumentation
* @module manifoldCAD
*/
import type * as GLTFTransform from '@gltf-transform/core';
/**
* @hidden
* @inline
*/
export declare type AnimationMode = 'loop' | 'ping-pong';
/**
* The abstract class from which other classes inherit. Common methods and
* properties live here.
* @group Scene Graph
*/
export declare abstract class BaseGLTFNode {
/** @internal */
private _parent?;
name?: string;
translation?: Vec3 | ((t: number) => Vec3);
/**
* From the reference frame of the model being rotated, rotations are applied
* in *z-y'-x"* order. That is yaw first, then pitch and finally roll.
*
* From the global reference frame, a model will be rotated in *x-y-z* order.
* That is about the global X axis, then global Y axis, and finally global Z.
*
* This matches the behaviour of `Manifold.rotate()`.
*/
rotation?: Vec3 | ((t: number) => Vec3);
scale?: Vec3 | ((t: number) => Vec3);
constructor(parent?: BaseGLTFNode);
get parent(): BaseGLTFNode | undefined;
/**
* Does this node have any geometry that needs to be converted on export?
* @internal
*/
isEmpty(): boolean;
}
/**
* A three dimensional box, aligned to the coordinate system.
*
* @see {@link Manifold.boundingBox}
* @see {@link Manifold.levelSet}
*/
export declare type Box = {
min: Vec3,
max: Vec3
};
/**
* Two-dimensional cross sections guaranteed to be without self-intersections,
* or overlaps between polygons (from construction onwards). This class makes
* use of the Clipper2 library for polygon clipping (boolean) and offsetting
* operations.
*
* @see {@link https://manifoldcad.org/docs/html/classmanifold_1_1_cross_section.html | C++ API: CrossSection Class Reference}
* @see {@link https://www.angusj.com/clipper2/Docs/Overview.htm | Clipper2 - Polygon Clipping Offsetting & Triangulating}
* @group Basics
*/
export declare class CrossSection {
/**
* Create a 2d cross-section from a set of contours (complex polygons). A
* boolean union operation (with Positive filling rule by default) is
* performed to combine overlapping polygons and ensure the resulting
* CrossSection is free of intersections.
*
* @param contours A set of closed paths describing zero or more complex
* polygons.
* @param fillRule The filling rule used to interpret polygon sub-regions in
* contours.
* @group Basics
*/
constructor(contours: Polygons, fillRule?: FillRule);
// Shapes
/**
* Constructs a square with the given XY dimensions. By default it is
* positioned in the first quadrant, touching the origin. If any dimensions in
* size are negative, or if all are zero, an empty Manifold will be returned.
*
* @param size The X, and Y dimensions of the square.
* @param center Set to true to shift the center to the origin.
* @group Constructors
*/
static square(size?: Readonly<Vec2>|number, center?: boolean): CrossSection;
/**
* Constructs a circle of a given radius.
*
* @param radius Radius of the circle. Must be positive.
* @param circularSegments Number of segments along its diameter. Default is
* calculated by the static Quality defaults according to the radius.
* @group Constructors
*/
static circle(radius: number, circularSegments?: number): CrossSection;
// Extrusions (2d to 3d manifold)
/**
* Constructs a manifold by extruding the cross-section along Z-axis.
*
* @param height Z-extent of extrusion.
* @param nDivisions Number of extra copies of the crossSection to insert into
* the shape vertically; especially useful in combination with twistDegrees to
* avoid interpolation artifacts. Default is none.
* @param twistDegrees Amount to twist the top crossSection relative to the
* bottom, interpolated linearly for the divisions in between.
* @param scaleTop Amount to scale the top (independently in X and Y). If the
* scale is {0, 0}, a pure cone is formed with only a single vertex at the
* top. Default {1, 1}.
* @param center If true, the extrusion is centered on the z-axis through the
* origin
* as opposed to resting on the XY plane as is default.
* @group Transformations
*/
extrude(
height: number, nDivisions?: number, twistDegrees?: number,
scaleTop?: Readonly<Vec2>|number, center?: boolean): Manifold;
/**
* Constructs a manifold by revolving this cross-section around its Y-axis and
* then setting this as the Z-axis of the resulting manifold. If the contours
* cross the Y-axis, only the part on the positive X side is used.
* Geometrically valid input will result in geometrically valid output.
*
* @param circularSegments Number of segments along its diameter. Default is
* calculated by the static Defaults.
* @group Transformations
*/
revolve(circularSegments?: number, revolveDegrees?: number): Manifold;
// Transformations
/**
* Transform this CrossSection in space. Stored in column-major order. This
* operation can be chained. Transforms are combined and applied lazily.
*
* @param m The affine transformation matrix to apply to all the vertices. The
* last row is ignored.
* @group Transformations
*/
transform(m: Mat3): CrossSection;
/**
* Move this CrossSection in space. This operation can be chained. Transforms
* are combined and applied lazily.
*
* @param v The vector to add to every vertex.
* @group Transformations
*/
translate(v: Readonly<Vec2>): CrossSection;
translate(x: number, y?: number): CrossSection;
/**
* Applies a (Z-axis) rotation to the CrossSection, in degrees. This operation
* can be chained. Transforms are combined and applied lazily.
*
* @param degrees degrees about the Z-axis to rotate.
* @group Transformations
*/
rotate(degrees: number): CrossSection;
/**
* Scale this CrossSection in space. This operation can be chained. Transforms
* are combined and applied lazily.
*
* @param v The vector to multiply every vertex by per component.
* @group Transformations
*/
scale(v: Readonly<Vec2>|number): CrossSection;
/**
* Mirror this CrossSection over the arbitrary axis described by the unit form
* of the given vector. If the length of the vector is zero, an empty
* CrossSection is returned. This operation can be chained. Transforms are
* combined and applied lazily.
*
* @param ax the axis to be mirrored over
* @group Transformations
*/
mirror(ax: Readonly<Vec2>): CrossSection;
/**
* Move the vertices of this CrossSection (creating a new one) according to
* any arbitrary input function, followed by a union operation (with a
* Positive fill rule) that ensures any introduced intersections are not
* included in the result.
*
* @param warpFunc A function that modifies a given vertex position.
* @group Transformations
*/
warp(warpFunc: (vert: Vec2) => void): CrossSection;
/**
* Inflate the contours in CrossSection by the specified delta, handling
* corners according to the given JoinType.
*
* @param delta Positive deltas will cause the expansion of outlining contours
* to expand, and retraction of inner (hole) contours. Negative deltas will
* have the opposite effect.
* @param joinType The join type specifying the treatment of contour joins
* (corners). Defaults to Round
* @param miterLimit The maximum distance in multiples of delta that vertices
* can be offset from their original positions with before squaring is
* applied, **when the join type is Miter** (default is 2, which is the
* minimum allowed). See the [Clipper2
* MiterLimit](http://www.angusj.com/clipper2/Docs/Units/Clipper.Offset/Classes/ClipperOffset/Properties/MiterLimit.htm)
* page for a visual example.
* @param circularSegments Number of segments per 360 degrees of
* <B>JoinType::Round</B> corners (roughly, the number of vertices that
* will be added to each contour). Default is calculated by the static Quality
* defaults according to the radius.
* @group Transformations
*/
offset(
delta: number, joinType?: JoinType, miterLimit?: number,
circularSegments?: number): CrossSection;
/**
* Remove vertices from the contours in this CrossSection that are less than
* the specified distance epsilon from an imaginary line that passes through
* its two adjacent vertices. Near duplicate vertices and collinear points
* will be removed at lower epsilons, with elimination of line segments
* becoming increasingly aggressive with larger epsilons.
*
* It is recommended to apply this function following Offset, in order to
* clean up any spurious tiny line segments introduced that do not improve
* quality in any meaningful way. This is particularly important if further
* offseting operations are to be performed, which would compound the issue.
*
* @param epsilon minimum distance vertices must diverge from the hypothetical
* outline without them in order to be included in the output (default
* 1e-6)
* @group Transformations
*/
simplify(epsilon?: number): CrossSection;
// Clipping Operations
/**
* Boolean union
* @group Boolean
*/
add(other: CrossSection|Polygons): CrossSection;
/**
* Boolean difference
* @group Boolean
*/
subtract(other: CrossSection|Polygons): CrossSection;
/**
* Boolean intersection
* @group Boolean
*/
intersect(other: CrossSection|Polygons): CrossSection;
/**
* Boolean union of the cross-sections a and b
* @group Boolean
*/
static union(a: CrossSection|Polygons, b: CrossSection|Polygons):
CrossSection;
/**
* Boolean difference of the cross-section b from the cross-section a
* @group Boolean
*/
static difference(a: CrossSection|Polygons, b: CrossSection|Polygons):
CrossSection;
/**
* Boolean intersection of the cross-sections a and b
* @group Boolean
*/
static intersection(a: CrossSection|Polygons, b: CrossSection|Polygons):
CrossSection;
/**
* Boolean union of a list of cross-sections
* @group Boolean
*/
static union(polygons: readonly(CrossSection|Polygons)[]): CrossSection;
/**
* Boolean difference of the tail of a list of cross-sections from its head
* @group Boolean
*/
static difference(polygons: readonly(CrossSection|Polygons)[]): CrossSection;
/**
* Boolean intersection of a list of cross-sections
*/
static intersection(polygons: readonly(CrossSection|Polygons)[]):
CrossSection;
// Convex Hulls
/**
* Compute the convex hull of the contours in this CrossSection.
* @group Convex Hull
*/
hull(): CrossSection;
/**
* Compute the convex hull of all points in a list of polygons/cross-sections.
* @group Convex Hull
*/
static hull(polygons: readonly(CrossSection|Polygons)[]): CrossSection;
// Topological Operations
/**
* Construct a CrossSection from a vector of other Polygons (batch
* boolean union).
* @group Boolean
*/
static compose(polygons: readonly(CrossSection|Polygons)[]): CrossSection;
/**
* This operation returns a vector of CrossSections that are topologically
* disconnected, each containing one outline contour with zero or more
* holes.
* @group Constructors
*/
decompose(): CrossSection[];
// Polygon Conversion
/**
* Create a 2d cross-section from a set of contours (complex polygons). A
* boolean union operation (with Positive filling rule by default) is
* performed to combine overlapping polygons and ensure the resulting
* CrossSection is free of intersections.
*
* @param contours A set of closed paths describing zero or more complex
* polygons.
* @param fillRule The filling rule used to interpret polygon sub-regions in
* contours.
* @group Input & Output
*/
static ofPolygons(contours: Polygons, fillRule?: FillRule): CrossSection;
/**
* Return the contours of this CrossSection as a list of simple polygons.
* @group Input & Output
*/
toPolygons(): SimplePolygon[];
// Properties
/**
* Return the total area covered by complex polygons making up the
* CrossSection.
* @group Information
*/
area(): number;
/**
* Does the CrossSection (not) have any contours?
* @group Information
*/
isEmpty(): boolean;
/**
* The number of vertices in the CrossSection.
* @group Information
*/
numVert(): number;
/**
* The number of contours in the CrossSection.
* @group Information
*/
numContour(): number;
/**
* Returns the axis-aligned bounding rectangle of all the CrossSection's
* vertices.
* @group Information
*/
bounds(): Rect;
// Memory
/**
* Frees the WASM memory of this CrossSection, since these cannot be
* garbage-collected automatically.
* @group Basics
*/
delete(): void;
}
/**
* Display a CrossSection in 3D space.
*
* A CrossSection object is two dimensional. Attaching it as a node
* allows it to be included in the final exported file, complete with
* transformations.
*
* > [!NOTE]
* >
* > CrossSections are not -- and can never be -- manifold. That means
* > some exporters (like `.3mf`) will just skip over them entirely.
*
* @group Scene Graph
*/
export declare class CrossSectionGLTFNode extends BaseGLTFNode {
crossSection?: CrossSection;
material?: GLTFMaterial;
private _runid?;
constructor(parent?: BaseGLTFNode);
clone(newParent?: BaseGLTFNode): CrossSectionGLTFNode;
isEmpty(): boolean;
/**
* Get the runID for this node.
* If there is no runID set, lazily assign one.
*
* We don't need these for regular operations, but they do help when
* converting to meshes for export.
* @internal
*/
get runID(): number;
}
/**
* @see {@link Manifold.status}
*/
export declare type ErrorStatus = 'NoError'|'NonFiniteVertex'|'NotManifold'|
'VertexOutOfBounds'|'PropertiesWrongLength'|'MissingPositionProperties'|
'MergeVectorsDifferentLengths'|'MergeIndexOutOfBounds'|
'TransformWrongLength'|'RunIndexWrongLength'|'FaceIDWrongLength'|
'InvalidConstruction'|'ResultTooLarge'|'InvalidTangents'|'Cancelled';
/**
* Observe and control a long-running Manifold evaluation. Attach to a
* Manifold via Manifold.withContext(); the next eager op invoked on the
* result (status(), one of the refine* family, hull(), or minkowskiSum() /
* minkowskiDifference()) snapshots the ctx and reports progress / observes
* cancellation through it. Deferred ops (Boolean, transforms, batch ops)
* ignore any attached ctx. Safe to read/write from any thread/worker.
*
* Cancellation is permanent for a Manifold: once cancelled and detected,
* the Manifold's status becomes 'Cancelled' and stays 'Cancelled'.
*/
export declare interface ExecutionContext {
/** Request cancellation. Can be called from any context. Idempotent. */
cancel(): void;
/** Has cancellation been requested? */
cancelled(): boolean;
/**
* Normalized progress in [0, 1]. Monotonic within an evaluation.
* Returns 1 when no work has been scheduled (interpreted as trivially
* complete -- e.g. a single-leaf manifold has nothing to evaluate).
*/
progress(): number;
// Memory
/**
* Frees the WASM memory of this ExecutionContext, since these cannot be
* garbage-collected automatically.
* @group Basics
*/
delete(): void;
}
export declare type FillRule = 'EvenOdd'|'NonZero'|'Positive'|'Negative';
/**
* Get the current duruation of the animation, in seconds.
*/
export declare function getAnimationDuration(): number;
/**
* Get the current animation frame rate.
*/
export declare function getAnimationFPS(): number;
/**
* Get the current animation repeat mode.
*/
export declare function getAnimationMode(): AnimationMode;
/**
* Determine the appropriate number of segments for a given radius.
*
* @param radius For a given radius of circle, determine how many default
* segments there will be.
*/
export declare function getCircularSegments(radius: number): number;
/**
* Get a list of GLTF nodes that have been created in this model.
*
* This function only works in scripts directly evaluated by the manifoldCAD
* website or CLI. When called in an imported library it will always return an
* empty array, and nodes created in libraries will not be included in the
* result. This is intentional; libraries must not create geometry as a side
* effect.
*
* @returns An array of GLTFNodes.
*/
export declare function getGLTFNodes(): BaseGLTFNode[];
/**
* Get the current angle constraint.
*
* @returns The minimum angle in degrees between consecutive segments. The
* angle will increase if the the segments hit the minimum edge length.
* Default is 10 degrees.
*/
export declare function getMinCircularAngle(): number;
/**
* Get the current edge length constraint.
*
* @returns The minimum length of segments. The length will
* increase if the the segments hit the minimum angle. Default is 1.0.
*/
export declare function getMinCircularEdgeLength(): number;
/**
* @inline
* @internal
*/
export declare type GLTFAttribute = 'POSITION' | 'NORMAL' | 'TANGENT' | 'TEXCOORD_0' | 'TEXCOORD_1' | 'COLOR_0' | 'JOINTS_0' | 'WEIGHTS_0' | 'SKIP_1' | 'SKIP_2' | 'SKIP_3' | 'SKIP_4';
/**
* Define a material using the glTF metallic-roughness physically-based
* rendering model. Materials can be applied to a model through `setMaterial()`,
* or set as a {@link GLTFNode.material | GLTFNode property}.
*
* @see {@link https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#materials | glTF 2.0 Specification: Materials}
* @see {@link https://physicallybased.info/ | Physically Based - The PBR values database}
* @sortStrategy source-order
* @group Material
*/
export declare interface GLTFMaterial {
/**
* Every vertex in a glTF Mesh has a set of attributes.
* `POSITION` cannot be specified -- ManifoldCAD will set it internally.
*
* This array specifies how vertex properties are arranged in memory.
* For example, a value of `['TEXCOORD_0', 'NORMAL', 'SKIP_2', 'COLOR_0']`
* would implicitly use property channels 0-2 for position, followed by
* channels 3-4 for texture, 5-7 for surface normal, ignore 8-9, and 10-12 for
* color.
*
* Some properties such as `TEXCOORD_0` or `COLOR_0` may be set when importing
* a model that has a texture or material.
*
* When vertex property `COLOR_0` is specified, it will be multiplied
* against {@link baseColorFactor}.
*
* @see {@link https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#meshes-overview | glTF 2.0 Specification: Meshes Overview}
* @see {@link https://manifoldcad.org/#Tetrahedron%20Puzzle | ManifoldCAD Example: Tetrahedron Puzzle}
*/
attributes?: GLTFAttribute[];
/**
* Roughness of the material.
* Ranges from 0 (smooth, specular) to 1.0 (rough, diffuse).
*
* @default 0.2
*/
roughness?: number;
/**
* Metallic property of the material.
* Ranges from 0 (dielectric, e.g.: yellow plastic) to 1.0 (conductor, e.g:
* gold). Generally speaking materials are either one or the other and
* intermediate values are just for blending.
*
* @default 1.0 // Metallic
*/
metallic?: number;
/**
* Base colour of the material.
* RGB values, ranging from 0 to 1.0.
*
* If the {@link attributes | attribute} `COLOR_0` is specifed, it will be
* multiplied against `baseColorFactor`. In this case, use an appropriate
* value like `[1.0, 1.0, 1.0]`.
* @default [1.0, 1.0, 0.0] // Yellow
*/
baseColorFactor?: [number, number, number];
/**
* Transparency of the material.
* Ranges from 0 (fully transparent) to 1.0 (fully opaque).
* @default 1.0 // Opaque
*/
alpha?: number;
/**
* Render model as unlit or shadeless, as opposed to physically based
* rendering.
*
* @see {@link https://github.com/KhronosGroup/gltf/tree/main/extensions/2.0/Khronos/KHR_materials_unlit | KHR_materials_unlit}
* @see {@link https://gltf-transform.dev/modules/extensions/classes/KHRMaterialsUnlit | glTF Transform: KHRMaterialsUnlit}
* @default false // Lit and shadowed.
*/
unlit?: boolean;
/**
* Material name. Will be passed through when exported.
*/
name?: string;
/**
* If set, this material is a copy of another material on an in-memory glTF
* model. This is used by `importManifold` and `importModel` to pass original
* materials and textures through manifold.
* @internal
*/
sourceMaterial?: GLTFTransform.Material;
/**
* If set, this material is a copy of another material on an in-memory glTF
* model. This is used by `importManifold` and `importModel` to pass original
* materials and textures through manifold.
* @internal
*/
sourceRunID?: number;
/**
* Treat this material as double sided.
* This is implied for translucent materials (`alpha < 1.0`) and
* CrossSections.
* @internal
*/
doubleSided?: boolean;
}
/**
* Position a manifold model for later export.
* @group Scene Graph
*/
export declare class GLTFNode extends BaseGLTFNode {
manifold?: Manifold;
material?: GLTFMaterial;
clone(newParent?: BaseGLTFNode): GLTFNode;
isEmpty(): boolean;
}
/**
* Import a model, and convert it to a Manifold object for manipulation.
*
* The original imported model may consist of an entire tree of nodes, each of
* which may or may not be manifold. This method will convert each child node,
* and then union the results together. If a child node has no mesh, the mesh
* has no geometry, or the mesh is not manifold, that child node will be
* silently excluded.
*/
export declare function importManifold(source: string | Blob | URL | ArrayBuffer, options?: ImportOptions): Promise<Manifold>;
/**
* Import a model, for display only.
*/
export declare function importModel(source: string | Blob | URL | ArrayBuffer, options?: ImportOptions): Promise<VisualizationGLTFNode>;
/**
* @group Management
* @inline
* @internal
*/
export declare interface ImportOptions {
/**
* Use `mimetype` to determine the format of the imported model, rather than
* inferring it.
*/
mimetype?: string;
/**
* When an imported model is not manifold, try closing gaps smaller than
* tolerance in an effort to make it manifold.
*/
tolerance?: number;
}
/**
* Is this module running in manifoldCAD.org or the ManifoldCAD CLI?
*
* @returns boolean
* @group Information
*/
export declare function isManifoldCAD(): boolean
export declare type JoinType = 'Square'|'Round'|'Miter';
/**
* This library's internal representation of an oriented, 2-manifold, triangle
* mesh - a simple boundary-representation of a solid object. Use this class to
* store and operate on solids, and use MeshGL for input and output, or
* potentially Mesh if only basic geometry is required.
*
* In addition to storing geometric data, a Manifold can also store an arbitrary
* number of vertex properties. These could be anything, e.g. normals, UV
* coordinates, colors, etc, but this library is completely agnostic. All
* properties are merely float values indexed by channel number. It is up to the
* user to associate channel numbers with meaning.
*
* Manifold allows vertex properties to be shared for efficient storage, or to
* have multiple property verts associated with a single geometric vertex,
* allowing sudden property changes, e.g. at Boolean intersections, without
* sacrificing manifoldness.
*
* Manifolds also keep track of their relationships to their inputs, via
* OriginalIDs and the faceIDs and transforms accessible through MeshGL. This
* allows object-level properties to be re-associated with the output after many
* operations, particularly useful for materials. Since separate object's
* properties are not mixed, there is no requirement that channels have
* consistent meaning between different inputs.
*
* @see {@link https://manifoldcad.org/docs/html/classmanifold_1_1_manifold.html | C++ API: Manifold Class Reference}
* @group Basics
*/
export declare class Manifold {
/**
* Convert a Mesh into a Manifold, retaining its properties and merging only
* the positions according to the merge vectors. Will throw an error if the
* result is not an oriented 2-manifold. Will collapse degenerate triangles
* and unnecessary vertices.
*
* All fields are read, making this structure suitable for a lossless
* round-trip of data from getMesh(). For multi-material input, use
* reserveIDs() to set a unique originalID for each material, and sort the
* materials into triangle runs.
*
* @group Basics
*/
constructor(mesh: Mesh);
// Shapes
/**
* Constructs a tetrahedron centered at the origin with one vertex at (1,1,1)
* and the rest at similarly symmetric points.
* @group Constructors
*/
static tetrahedron(): Manifold;
/**
* Constructs a unit cube (edge lengths all one), by default in the first
* octant, touching the origin.
*
* @param size The X, Y, and Z dimensions of the box.
* @param center Set to true to shift the center to the origin.
* @group Constructors
*/
static cube(size?: Readonly<Vec3>|number, center?: boolean): Manifold;
/**
* A convenience constructor for the common case of extruding a circle. Can
* also form cones if both radii are specified.
*
* @param height Z-extent
* @param radiusLow Radius of bottom circle. Must be positive.
* @param radiusHigh Radius of top circle. Can equal zero. Default is equal to
* radiusLow.
* @param circularSegments How many line segments to use around the circle.
* Default is calculated by the static Defaults.
* @param center Set to true to shift the center to the origin. Default is
* origin at the bottom.
* @group Constructors
*/
static cylinder(
height: number, radiusLow: number, radiusHigh?: number,
circularSegments?: number, center?: boolean): Manifold;
/**
* Constructs a geodesic sphere of a given radius.
*
* @param radius Radius of the sphere. Must be positive.
* @param circularSegments Number of segments along its
* diameter. This number will always be rounded up to the nearest factor of
* four, as this sphere is constructed by refining an octahedron. This means
* there are a circle of vertices on all three of the axis planes. Default is
* calculated by the static Defaults.
* @group Constructors
*/
static sphere(radius: number, circularSegments?: number): Manifold;
// Extrusions from 2d shapes
/**
* Constructs a manifold from a set of polygons/cross-section by extruding
* them along the Z-axis.
*
* @param polygons A set of non-overlapping polygons to extrude.
* @param height Z-extent of extrusion.
* @param nDivisions Number of extra copies of the crossSection to insert into
* the shape vertically; especially useful in combination with twistDegrees to
* avoid interpolation artifacts. Default is none.
* @param twistDegrees Amount to twist the top crossSection relative to the
* bottom, interpolated linearly for the divisions in between.
* @param scaleTop Amount to scale the top (independently in X and Y). If the
* scale is {0, 0}, a pure cone is formed with only a single vertex at the
* top. Default {1, 1}.
* @param center If true, the extrusion is centered on the z-axis through the
* origin
* as opposed to resting on the XY plane as is default.
* @group Polygons
*/
static extrude(
polygons: CrossSection|Polygons, height: number, nDivisions?: number,
twistDegrees?: number, scaleTop?: Readonly<Vec2>|number,
center?: boolean): Manifold;
/**
* Constructs a manifold from a set of polygons/cross-section by revolving
* them around the Y-axis and then setting this as the Z-axis of the resulting
* manifold. If the polygons cross the Y-axis, only the part on the positive X
* side is used. Geometrically valid input will result in geometrically valid
* output.
*
* @param polygons A set of non-overlapping polygons to revolve.
* @param circularSegments Number of segments along its diameter. Default is
* calculated by the static Defaults.
* @param revolveDegrees Number of degrees to revolve. Default is 360 degrees.
* @group Polygons
*/
static revolve(
polygons: CrossSection|Polygons, circularSegments?: number,
revolveDegrees?: number): Manifold;
// Mesh Conversion
/**
* Convert a Mesh into a Manifold, retaining its properties and merging only
* the positions according to the merge vectors. Will throw an error if the
* result is not an oriented 2-manifold. Will collapse degenerate triangles
* and unnecessary vertices.
*
* All fields are read, making this structure suitable for a lossless
* round-trip of data from getMesh(). For multi-material input, use
* reserveIDs() to set a unique originalID for each material, and sort the
* materials into triangle runs.
* @group Input & Output
*/
static ofMesh(mesh: Mesh): Manifold;
/**
* Constructs a smooth version of the input mesh by creating tangents; this
* method will throw if you have supplied tangents with your mesh already. The
* actual triangle resolution is unchanged; use the Refine() method to
* interpolate to a higher-resolution curve.
*
* By default, every edge is calculated for maximum smoothness (very much
* approximately), attempting to minimize the maximum mean Curvature
* magnitude. No higher-order derivatives are considered, as the interpolation
* is independent per triangle, only sharing constraints on their boundaries.
*
* @param mesh input Mesh.
* @param sharpenedEdges If desired, you can supply a vector of sharpened
* halfedges, which should in general be a small subset of all halfedges.
* Order of entries doesn't matter, as each one specifies the desired
* smoothness (between zero and one, with one the default for all unspecified
* halfedges) and the halfedge index (3 * triangle index + [0,1,2] where 0 is
* the edge between triVert 0 and 1, etc).
*
* At a smoothness value of zero, a sharp crease is made. The smoothness is
* interpolated along each edge, so the specified value should be thought of
* as an average. Where exactly two sharpened edges meet at a vertex, their
* tangents are rotated to be colinear so that the sharpened edge can be
* continuous. Vertices with only one sharpened edge are completely smooth,
* allowing sharpened edges to smoothly vanish at termination. A single vertex
* can be sharpened by sharping all edges that are incident on it, allowing
* cones to be formed.
*
* @group Smoothing
*/
static smooth(mesh: Mesh, sharpenedEdges?: readonly Smoothness[]): Manifold;
// Signed Distance Functions
/**
* Constructs a level-set Mesh from the input Signed-Distance Function (SDF).
* This uses a form of Marching Tetrahedra (akin to Marching Cubes, but better
* for manifoldness). Instead of using a cubic grid, it uses a body-centered
* cubic grid (two shifted cubic grids). This means if your function's
* interior exceeds the given bounds, you will see a kind of egg-crate shape
* closing off the manifold, which is due to the underlying grid.
*
* @param sdf The signed-distance function which returns the signed distance
* of
* a given point in R^3. Positive values are inside, negative outside.
* @param bounds An axis-aligned box that defines the extent of the grid.
* @param edgeLength Approximate maximum edge length of the triangles in the
* final result. This affects grid spacing, and hence has a strong effect on
* performance.
* @param level You can inset your Mesh by using a positive value, or outset
* it with a negative value.
* @param tolerance Ensure each vertex is within this distance of the true
* surface. Defaults to -1, which will return the interpolated
* crossing-point based on the two nearest grid points. Small positive values
* will require more sdf evaluations per output vertex.
* @group Constructors
*/
static levelSet(
sdf: (point: Vec3) => number, bounds: Box, edgeLength: number,
level?: number, tolerance?: number): Manifold;
// Transformations
/**
* Transform this Manifold in space. Stored in column-major order. This
* operation can be chained. Transforms are combined and applied lazily.
*
* @param m The affine transformation matrix to apply to all the vertices. The
* last row is ignored.
* @group Transformations
*/
transform(m: Mat4): Manifold;
/**
* Move this Manifold in space. This operation can be chained. Transforms are
* combined and applied lazily.
*
* @param v The vector to add to every vertex.
* @group Transformations
*/
translate(v: Readonly<Vec3>): Manifold;
translate(x: number, y?: number, z?: number): Manifold;
/**
* Applies an Euler or Tait-Bryan angle rotation to the manifold. This
* operation can be chained. Transforms are combined and applied lazily.
*
* We use degrees so that we can minimize rounding error, and eliminate it
* completely for any multiples of 90 degrees. Additionally, more efficient
* code paths are used to update the manifold when the transforms only rotate
* by multiples of 90 degrees.
*
* From the reference frame of the model being rotated, rotations are applied
* in *z-y'-x"* order. That is yaw first, then pitch and finally roll.
*
* From the global reference frame, a model will be rotated in *x-y-z* order.
* That is about the global X axis, then global Y axis, and finally global Z.
*
* @param v [X, Y, Z] rotation in degrees.
* @group Transformations
*/
rotate(v: Readonly<Vec3>): Manifold;
rotate(x: number, y?: number, z?: number): Manifold;
/**
* Scale this Manifold in space. This operation can be chained. Transforms are
* combined and applied lazily.
*
* @param v The vector to multiply every vertex by per component.
* @group Transformations
*/
scale(v: Readonly<Vec3>|number): Manifold;
/**
* Mirror this Manifold over the plane described by the unit form of the given
* normal vector. If the length of the normal is zero, an empty Manifold is
* returned. This operation can be chained. Transforms are combined and
* applied lazily.
*
* @param normal The normal vector of the plane to be mirrored over
* @group Transformations
*/
mirror(normal: Readonly<Vec3>): Manifold;
/**
* This function does not change the topology, but allows the vertices to be
* moved according to any arbitrary input function. It is easy to create a
* function that warps a geometrically valid object into one which overlaps,
* but that is not checked here, so it is up to the user to choose their
* function with discretion.
*
* @param warpFunc A function that modifies a given vertex position.
* @group Transformations
*/
warp(warpFunc: (vert: Vec3) => void): Manifold;
/**
* Batch version of warp(). The callback receives a flat array of xyzxyz...
* (length = count * 3) and may modify it in-place.
*/
warpBatch(warpFunc: (verts: Float64Array, count: number) => void): Manifold;
/**
* Smooths out the Manifold by filling in the halfedgeTangent vectors. The
* geometry will remain unchanged until Refine or RefineToLength is called to
* interpolate the surface. This version uses the supplied vertex normal
* properties to define the tangent vectors.
*
* @param normalIdx The first property channel of the normals. NumProp must be
* at least normalIdx + 3. Any vertex where multiple normals exist and don't
* agree will result in a sharp edge. Default is 0, the standard slot.
* Non-zero values are retained for compatibility and will not be supported
* in a future release.
* @group Smoothing
*/
smoothByNormals(normalIdx?: number): Manifold;
/**
* Smooths out the Manifold by filling in the halfedgeTangent vectors. The
* geometry will remain unchanged until Refine or RefineToLength is called to
* interpolate the surface. This version uses the geometry of the triangles
* and pseudo-normals to define the tangent vectors.
*
* @param minSharpAngle degrees, default 52.5. Any edges with angles greater
* than this value will remain sharp. The rest will be smoothed to G1
* continuity, with the caveat that flat faces of three or more triangles will
* always remain flat. With a value of zero, the model is faceted, but in this
* case there is no point in smoothing.
*
* @param minSmoothness range: 0 - 1, default 0. The smoothness applied to
* sharp angles. The default gives a hard edge, while values > 0 will give a
* small fillet on these sharp edges. A value of 1 is equivalent to a
* minSharpAngle of 180 - all edges will be smooth.
* @group Smoothing
*/
smoothOut(minSharpAngle?: number, minSmoothness?: number): Manifold;
/**
* Increase the density of the mesh by splitting every edge into n pieces. For
* instance, with n = 2, each triangle will be split into 4 triangles. These
* will all be coplanar (and will not be immediately collapsed) unless the
* Mesh/Manifold has halfedgeTangents specified (e.g. from the Smooth()
* constructor), in which case the new vertices will be moved to the
* interpolated surface according to their barycentric coordinates.
*
* @param n The number of pieces to split every edge into. Must be > 1.
* @group Smoothing
*/
refine(n: number): Manifold;
/**
* Increase the density of the mesh by splitting each edge into pieces of
* roughly the input length. Interior verts are added to keep the rest of the
* triangulation edges also of roughly the same length. If halfedgeTangents
* are present (e.g. from the Smooth() constructor), the new vertices will be
* moved to the interpolated surface according to their barycentric
* coordinates.
*
* @param length The length that edges will be broken down to.
* @group Smoothing
*/
refineToLength(length: number): Manifold;
/**
* Increase the density of the mesh by splitting each edge into pieces such
* that any point on the resulting triangles is roughly within tolerance of
* the smoothly curved surface defined by the tangent vectors. This means
* tightly curving regions will be divided more finely than smoother regions.
* If halfedgeTangents are not present, the result will simply be a copy of
* the original. Quads will ignore their interior triangle bisector.
*
* @param tolerance The desired maximum distance between the faceted mesh
* produced and the exact smoothly curving surface. All vertices are exactly
* on the surface, within rounding error.
* @group Smoothing
*/
refineToTolerance(tolerance: number): Manifold;
/**
* Create a new copy of this manifold with updated vertex properties by
* supplying a function that takes the existing position and properties as
* input. You may specify any number of output properties, allowing creation
* and removal of channels. Note: undefined behavior will result if you read
* past the number of input properties or write past the number of output
* properties.
*
* @param numProp The new number of properties per vertex.
* @param propFunc A function that modifies the properties of a given vertex.
* @group Properties
*/
setProperties(
numProp: number,
propFunc: (newProp: number[], position: Vec3, oldProp: number[]) => void):
Manifold;
/**
* Curvature is the inverse of the radius of curvature, and signed such that
* positive is convex and negative is concave. There are two orthogonal
* principal curvatures at any point on a manifold, with one maximum and the
* other minimum. Gaussian curvature is their product, while mean
* curvature is their sum. This approximates them for every vertex and assigns
* them as vertex properties on the given channels.
*
* @param gaussianIdx The property channel index in which to store the
* Gaussian curvature. An index < 0 will be ignored (stores nothing). The
* property set will be automatically expanded to include the channel
* index specified.
* @param meanIdx The property channel index in which to store the mean
* curvature. An index < 0 will be ignored (stores nothing). The property
* set will be automatically expanded to include the channel index
* specified.
* @group Properties
*/
calculateCurvature(gaussianIdx: number, meanIdx: number): Manifold;
/**
* Fills in vertex properties for normal vectors, calculated from the mesh
* geometry. Flat faces composed of three or more triangles will remain flat.
*
* @param normalIdx The property channel in which to store the X values of the
* normals. The X, Y, and Z channels will be sequential. The property set will
* be automatically expanded to include up through normalIdx + 2. Default is
* 0, the standard slot; in that case the Manifold records the recording so
* a subsequent getMesh() without an explicit normalIdx returns solid-frame
* normals. Non-zero values are retained for compatibility and will not be
* supported in a future release.
*
* @param minSharpAngle Any edges with angles greater than this value will
* remain sharp, getting different normal vector properties on each side of
* the edge. By default, no edges are sharp and all normals are shared. With a
* value of zero, the model is faceted and all normals match their triangle
* normals, but in this case it would be better not to calculate normals at
* all.
* @group Properties
*/
calculateNormals(normalIdx?: number, minSharpAngle?: number): Manifold;
// Boolean Operations
/**
* Boolean union
*
* @group Boolean
*/
add(other: Manifold): Manifold;
/**
* Boolean difference
*
* @group Boolean
*/
subtract(other: Manifold): Manifold;
/**
* Boolean intersection
*
* @group Boolean
*/
intersect(other: Manifold): Manifold;
/**
* Boolean union of the manifolds a and b
*
* @group Boolean
*/
static union(a: Manifold, b: Manifold): Manifold;
/**
* Boolean difference of the manifold b from the manifold a
*
* @group Boolean
*/
static difference(a: Manifold, b: Manifold): Manifold;
/**
* Boolean intersection of the manifolds a and b
*
* @group Boolean
*/
static intersection(a: Manifold, b: Manifold): Manifold;
/**
* Boolean union of a list of manifolds
*
* @group Boolean
*/
static union(manifolds: readonly Manifold[]): Manifold;
/**
* Boolean difference of the tail of a list of manifolds from its head
*
* @group Boolean
*/
static difference(manifolds: readonly Manifold[]): Manifold;
/**
* Boolean intersection of a list of manifolds
*
* @group Boolean
*/
static intersection(manifolds: readonly Manifold[]): Manifold;
/**
* Split cuts this manifold in two using the cutter manifold. The first result
* is the intersection, second is the difference. This is more efficient than
* doing them separately.
*
* @param cutter
* @group Boolean
*/
split(cutter: Manifold): [Manifold, Manifold];
/**
* Convenient version of Split() for a half-space.
*
* @param normal This vector is normal to the cutting plane and its length
* does
* not matter. The first result is in the direction of this vector, the second
* result is on the opposite side.
* @param originOffset The distance of the plane from the origin in the
* direction of the normal vector.
* @group Boolean
*/
splitByPlane(normal: Readonly<Vec3>, originOffset: number):
[Manifold, Manifold];
/**
* Removes everything behind the given half-space plane.
*
* @param normal This vector is normal to the cutting plane and its length
* does not matter. The result is in the direction of this vector from the
* plane.
* @param originOffset The distance of the plane from the origin in the
* direction of the normal vector.
*
* @group Boolean
*/
trimByPlane(normal: Readonly<Vec3>, originOffset: number): Manifold;
/**
* Compute the minkowski sum of this manifold with another.
* This corresponds to the morphological dilation of the manifold.
*
* @param other The other manifold to minkowski sum to this one.
* @group Boolean
*/
minkowskiSum(other: Manifold): Manifold;
/**
* Subtract the sweep of the other manifold across this manifold's surface.
* This corresponds to the morphological erosion of the manifold.
*
* @param other The other manifold to minkowski subtract from this one.
* @group Boolean
*/
minkowskiDifference(other: Manifold): Manifold;
/**
* Returns the cross section of this object parallel to the X-Y plane at the
* specified height. Using a height equal to the bottom
* of the bounding box will return the bottom faces, while using a height
* equal to the top of the bounding box will return empty.
*
* @param height Z-level of slice.
* @group Polygons
*/
slice(height: number): CrossSection;
/**
* Returns a cross section representing the projected outline of this object
* onto the X-Y plane.
*
* @group Polygons
*/
project(): CrossSection;
// Convex Hulls
/**
* Compute the convex hull of all points in this Manifold.
*
* @group Convex Hull
*/
hull(): Manifold;
/**
* Compute the convex hull of all points contained within a set of Manifolds
* and point vectors.
*
* @group Convex Hull
*/
static hull(points: readonly(Manifold|Vec3)[]): Manifold;
// Topological Operations
/**
* Constructs a new manifold from a list of other manifolds. This is a purely
* topological operation, so care should be taken to avoid creating
* overlapping results. It is the inverse operation of Decompose().
*
* @param manifolds A list of Manifolds to lazy-union together.
* @deprecated Please use {@link add} or {@link union} instead.
* @group Constructors
*/
static compose(manifolds: readonly Manifold[]): Manifold;
/**
* This operation returns a vector of Manifolds that are topologically
* disconnected. If everything is connected, the vector is length one,
* containing a copy of the original.