UNPKG

manifold-3d

Version:

Geometry library for topological robustness

1,297 lines (1,175 loc) 71.1 kB
/** * {@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.