UNPKG

@dimforge/rapier3d

Version:

3-dimensional physics engine in Rust - official JS bindings.

814 lines 30.7 kB
import { VectorOps, RotationOps } from "../math"; import { RawShape, RawShapeType } from "../raw"; import { ShapeContact } from "./contact"; import { PointProjection } from "./point"; import { RayIntersection } from "./ray"; import { ShapeCastHit } from "./toi"; export class Shape { /** * instant mode without cache */ static fromRaw(rawSet, handle) { const rawType = rawSet.coShapeType(handle); let extents; let borderRadius; let vs; let indices; let halfHeight; let radius; let normal; switch (rawType) { case RawShapeType.Ball: return new Ball(rawSet.coRadius(handle)); case RawShapeType.Cuboid: extents = rawSet.coHalfExtents(handle); // #if DIM3 return new Cuboid(extents.x, extents.y, extents.z); // #endif case RawShapeType.RoundCuboid: extents = rawSet.coHalfExtents(handle); borderRadius = rawSet.coRoundRadius(handle); // #if DIM3 return new RoundCuboid(extents.x, extents.y, extents.z, borderRadius); // #endif case RawShapeType.Capsule: halfHeight = rawSet.coHalfHeight(handle); radius = rawSet.coRadius(handle); return new Capsule(halfHeight, radius); case RawShapeType.Segment: vs = rawSet.coVertices(handle); // #if DIM3 return new Segment(VectorOps.new(vs[0], vs[1], vs[2]), VectorOps.new(vs[3], vs[4], vs[5])); // #endif case RawShapeType.Polyline: vs = rawSet.coVertices(handle); indices = rawSet.coIndices(handle); return new Polyline(vs, indices); case RawShapeType.Triangle: vs = rawSet.coVertices(handle); // #if DIM3 return new Triangle(VectorOps.new(vs[0], vs[1], vs[2]), VectorOps.new(vs[3], vs[4], vs[5]), VectorOps.new(vs[6], vs[7], vs[8])); // #endif case RawShapeType.RoundTriangle: vs = rawSet.coVertices(handle); borderRadius = rawSet.coRoundRadius(handle); // #if DIM3 return new RoundTriangle(VectorOps.new(vs[0], vs[1], vs[2]), VectorOps.new(vs[3], vs[4], vs[5]), VectorOps.new(vs[6], vs[7], vs[8]), borderRadius); // #endif case RawShapeType.HalfSpace: normal = VectorOps.fromRaw(rawSet.coHalfspaceNormal(handle)); return new HalfSpace(normal); case RawShapeType.Voxels: const vox_data = rawSet.coVoxelData(handle); const vox_size = rawSet.coVoxelSize(handle); return new Voxels(vox_data, vox_size); case RawShapeType.TriMesh: vs = rawSet.coVertices(handle); indices = rawSet.coIndices(handle); const tri_flags = rawSet.coTriMeshFlags(handle); return new TriMesh(vs, indices, tri_flags); case RawShapeType.HeightField: const scale = rawSet.coHeightfieldScale(handle); const heights = rawSet.coHeightfieldHeights(handle); // #if DIM3 const nrows = rawSet.coHeightfieldNRows(handle); const ncols = rawSet.coHeightfieldNCols(handle); const hf_flags = rawSet.coHeightFieldFlags(handle); return new Heightfield(nrows, ncols, heights, scale, hf_flags); // #endif // #if DIM3 case RawShapeType.ConvexPolyhedron: vs = rawSet.coVertices(handle); indices = rawSet.coIndices(handle); return new ConvexPolyhedron(vs, indices); case RawShapeType.RoundConvexPolyhedron: vs = rawSet.coVertices(handle); indices = rawSet.coIndices(handle); borderRadius = rawSet.coRoundRadius(handle); return new RoundConvexPolyhedron(vs, indices, borderRadius); case RawShapeType.Cylinder: halfHeight = rawSet.coHalfHeight(handle); radius = rawSet.coRadius(handle); return new Cylinder(halfHeight, radius); case RawShapeType.RoundCylinder: halfHeight = rawSet.coHalfHeight(handle); radius = rawSet.coRadius(handle); borderRadius = rawSet.coRoundRadius(handle); return new RoundCylinder(halfHeight, radius, borderRadius); case RawShapeType.Cone: halfHeight = rawSet.coHalfHeight(handle); radius = rawSet.coRadius(handle); return new Cone(halfHeight, radius); case RawShapeType.RoundCone: halfHeight = rawSet.coHalfHeight(handle); radius = rawSet.coRadius(handle); borderRadius = rawSet.coRoundRadius(handle); return new RoundCone(halfHeight, radius, borderRadius); // #endif default: throw new Error("unknown shape type: " + rawType); } } /** * Computes the time of impact between two moving shapes. * @param shapePos1 - The initial position of this sahpe. * @param shapeRot1 - The rotation of this shape. * @param shapeVel1 - The velocity of this shape. * @param shape2 - The second moving shape. * @param shapePos2 - The initial position of the second shape. * @param shapeRot2 - The rotation of the second shape. * @param shapeVel2 - The velocity of the second shape. * @param targetDistance − If the shape moves closer to this distance from a collider, a hit * will be returned. * @param maxToi - The maximum time when the impact can happen. * @param stopAtPenetration - If set to `false`, the linear shape-cast won’t immediately stop if * the shape is penetrating another shape at its starting point **and** its trajectory is such * that it’s on a path to exit that penetration state. * @returns If the two moving shapes collider at some point along their trajectories, this returns the * time at which the two shape collider as well as the contact information during the impact. Returns * `null`if the two shapes never collide along their paths. */ castShape(shapePos1, shapeRot1, shapeVel1, shape2, shapePos2, shapeRot2, shapeVel2, targetDistance, maxToi, stopAtPenetration) { let rawPos1 = VectorOps.intoRaw(shapePos1); let rawRot1 = RotationOps.intoRaw(shapeRot1); let rawVel1 = VectorOps.intoRaw(shapeVel1); let rawPos2 = VectorOps.intoRaw(shapePos2); let rawRot2 = RotationOps.intoRaw(shapeRot2); let rawVel2 = VectorOps.intoRaw(shapeVel2); let rawShape1 = this.intoRaw(); let rawShape2 = shape2.intoRaw(); let result = ShapeCastHit.fromRaw(null, rawShape1.castShape(rawPos1, rawRot1, rawVel1, rawShape2, rawPos2, rawRot2, rawVel2, targetDistance, maxToi, stopAtPenetration)); rawPos1.free(); rawRot1.free(); rawVel1.free(); rawPos2.free(); rawRot2.free(); rawVel2.free(); rawShape1.free(); rawShape2.free(); return result; } /** * Tests if this shape intersects another shape. * * @param shapePos1 - The position of this shape. * @param shapeRot1 - The rotation of this shape. * @param shape2 - The second shape to test. * @param shapePos2 - The position of the second shape. * @param shapeRot2 - The rotation of the second shape. * @returns `true` if the two shapes intersect, `false` if they don’t. */ intersectsShape(shapePos1, shapeRot1, shape2, shapePos2, shapeRot2) { let rawPos1 = VectorOps.intoRaw(shapePos1); let rawRot1 = RotationOps.intoRaw(shapeRot1); let rawPos2 = VectorOps.intoRaw(shapePos2); let rawRot2 = RotationOps.intoRaw(shapeRot2); let rawShape1 = this.intoRaw(); let rawShape2 = shape2.intoRaw(); let result = rawShape1.intersectsShape(rawPos1, rawRot1, rawShape2, rawPos2, rawRot2); rawPos1.free(); rawRot1.free(); rawPos2.free(); rawRot2.free(); rawShape1.free(); rawShape2.free(); return result; } /** * Computes one pair of contact points between two shapes. * * @param shapePos1 - The initial position of this sahpe. * @param shapeRot1 - The rotation of this shape. * @param shape2 - The second shape. * @param shapePos2 - The initial position of the second shape. * @param shapeRot2 - The rotation of the second shape. * @param prediction - The prediction value, if the shapes are separated by a distance greater than this value, test will fail. * @returns `null` if the shapes are separated by a distance greater than prediction, otherwise contact details. The result is given in world-space. */ contactShape(shapePos1, shapeRot1, shape2, shapePos2, shapeRot2, prediction) { let rawPos1 = VectorOps.intoRaw(shapePos1); let rawRot1 = RotationOps.intoRaw(shapeRot1); let rawPos2 = VectorOps.intoRaw(shapePos2); let rawRot2 = RotationOps.intoRaw(shapeRot2); let rawShape1 = this.intoRaw(); let rawShape2 = shape2.intoRaw(); let result = ShapeContact.fromRaw(rawShape1.contactShape(rawPos1, rawRot1, rawShape2, rawPos2, rawRot2, prediction)); rawPos1.free(); rawRot1.free(); rawPos2.free(); rawRot2.free(); rawShape1.free(); rawShape2.free(); return result; } containsPoint(shapePos, shapeRot, point) { let rawPos = VectorOps.intoRaw(shapePos); let rawRot = RotationOps.intoRaw(shapeRot); let rawPoint = VectorOps.intoRaw(point); let rawShape = this.intoRaw(); let result = rawShape.containsPoint(rawPos, rawRot, rawPoint); rawPos.free(); rawRot.free(); rawPoint.free(); rawShape.free(); return result; } projectPoint(shapePos, shapeRot, point, solid) { let rawPos = VectorOps.intoRaw(shapePos); let rawRot = RotationOps.intoRaw(shapeRot); let rawPoint = VectorOps.intoRaw(point); let rawShape = this.intoRaw(); let result = PointProjection.fromRaw(rawShape.projectPoint(rawPos, rawRot, rawPoint, solid)); rawPos.free(); rawRot.free(); rawPoint.free(); rawShape.free(); return result; } intersectsRay(ray, shapePos, shapeRot, maxToi) { let rawPos = VectorOps.intoRaw(shapePos); let rawRot = RotationOps.intoRaw(shapeRot); let rawRayOrig = VectorOps.intoRaw(ray.origin); let rawRayDir = VectorOps.intoRaw(ray.dir); let rawShape = this.intoRaw(); let result = rawShape.intersectsRay(rawPos, rawRot, rawRayOrig, rawRayDir, maxToi); rawPos.free(); rawRot.free(); rawRayOrig.free(); rawRayDir.free(); rawShape.free(); return result; } castRay(ray, shapePos, shapeRot, maxToi, solid) { let rawPos = VectorOps.intoRaw(shapePos); let rawRot = RotationOps.intoRaw(shapeRot); let rawRayOrig = VectorOps.intoRaw(ray.origin); let rawRayDir = VectorOps.intoRaw(ray.dir); let rawShape = this.intoRaw(); let result = rawShape.castRay(rawPos, rawRot, rawRayOrig, rawRayDir, maxToi, solid); rawPos.free(); rawRot.free(); rawRayOrig.free(); rawRayDir.free(); rawShape.free(); return result; } castRayAndGetNormal(ray, shapePos, shapeRot, maxToi, solid) { let rawPos = VectorOps.intoRaw(shapePos); let rawRot = RotationOps.intoRaw(shapeRot); let rawRayOrig = VectorOps.intoRaw(ray.origin); let rawRayDir = VectorOps.intoRaw(ray.dir); let rawShape = this.intoRaw(); let result = RayIntersection.fromRaw(rawShape.castRayAndGetNormal(rawPos, rawRot, rawRayOrig, rawRayDir, maxToi, solid)); rawPos.free(); rawRot.free(); rawRayOrig.free(); rawRayDir.free(); rawShape.free(); return result; } } // #if DIM3 /** * An enumeration representing the type of a shape. */ export var ShapeType; (function (ShapeType) { ShapeType[ShapeType["Ball"] = 0] = "Ball"; ShapeType[ShapeType["Cuboid"] = 1] = "Cuboid"; ShapeType[ShapeType["Capsule"] = 2] = "Capsule"; ShapeType[ShapeType["Segment"] = 3] = "Segment"; ShapeType[ShapeType["Polyline"] = 4] = "Polyline"; ShapeType[ShapeType["Triangle"] = 5] = "Triangle"; ShapeType[ShapeType["TriMesh"] = 6] = "TriMesh"; ShapeType[ShapeType["HeightField"] = 7] = "HeightField"; // Compound = 8, ShapeType[ShapeType["ConvexPolyhedron"] = 9] = "ConvexPolyhedron"; ShapeType[ShapeType["Cylinder"] = 10] = "Cylinder"; ShapeType[ShapeType["Cone"] = 11] = "Cone"; ShapeType[ShapeType["RoundCuboid"] = 12] = "RoundCuboid"; ShapeType[ShapeType["RoundTriangle"] = 13] = "RoundTriangle"; ShapeType[ShapeType["RoundCylinder"] = 14] = "RoundCylinder"; ShapeType[ShapeType["RoundCone"] = 15] = "RoundCone"; ShapeType[ShapeType["RoundConvexPolyhedron"] = 16] = "RoundConvexPolyhedron"; ShapeType[ShapeType["HalfSpace"] = 17] = "HalfSpace"; ShapeType[ShapeType["Voxels"] = 18] = "Voxels"; })(ShapeType || (ShapeType = {})); // NOTE: this **must** match the bits in the HeightFieldFlags on the rust side. /** * Flags controlling the behavior of some operations involving heightfields. */ export var HeightFieldFlags; (function (HeightFieldFlags) { /** * If set, a special treatment will be applied to contact manifold calculation to eliminate * or fix contacts normals that could lead to incorrect bumps in physics simulation (especially * on flat surfaces). * * This is achieved by taking into account adjacent triangle normals when computing contact * points for a given triangle. */ HeightFieldFlags[HeightFieldFlags["FIX_INTERNAL_EDGES"] = 1] = "FIX_INTERNAL_EDGES"; })(HeightFieldFlags || (HeightFieldFlags = {})); // #endif // NOTE: this **must** match the TriMeshFlags on the rust side. /** * Flags controlling the behavior of the triangle mesh creation and of some * operations involving triangle meshes. */ export var TriMeshFlags; (function (TriMeshFlags) { // NOTE: these two flags are not really useful in JS. // // /** // * If set, the half-edge topology of the trimesh will be computed if possible. // */ // HALF_EDGE_TOPOLOGY = 0b0000_0001, // /** If set, the half-edge topology and connected components of the trimesh will be computed if possible. // * // * Because of the way it is currently implemented, connected components can only be computed on // * a mesh where the half-edge topology computation succeeds. It will no longer be the case in the // * future once we decouple the computations. // */ // CONNECTED_COMPONENTS = 0b0000_0010, /** * If set, any triangle that results in a failing half-hedge topology computation will be deleted. */ TriMeshFlags[TriMeshFlags["DELETE_BAD_TOPOLOGY_TRIANGLES"] = 4] = "DELETE_BAD_TOPOLOGY_TRIANGLES"; /** * If set, the trimesh will be assumed to be oriented (with outward normals). * * The pseudo-normals of its vertices and edges will be computed. */ TriMeshFlags[TriMeshFlags["ORIENTED"] = 8] = "ORIENTED"; /** * If set, the duplicate vertices of the trimesh will be merged. * * Two vertices with the exact same coordinates will share the same entry on the * vertex buffer and the index buffer is adjusted accordingly. */ TriMeshFlags[TriMeshFlags["MERGE_DUPLICATE_VERTICES"] = 16] = "MERGE_DUPLICATE_VERTICES"; /** * If set, the triangles sharing two vertices with identical index values will be removed. * * Because of the way it is currently implemented, this methods implies that duplicate * vertices will be merged. It will no longer be the case in the future once we decouple * the computations. */ TriMeshFlags[TriMeshFlags["DELETE_DEGENERATE_TRIANGLES"] = 32] = "DELETE_DEGENERATE_TRIANGLES"; /** * If set, two triangles sharing three vertices with identical index values (in any order) * will be removed. * * Because of the way it is currently implemented, this methods implies that duplicate * vertices will be merged. It will no longer be the case in the future once we decouple * the computations. */ TriMeshFlags[TriMeshFlags["DELETE_DUPLICATE_TRIANGLES"] = 64] = "DELETE_DUPLICATE_TRIANGLES"; /** * If set, a special treatment will be applied to contact manifold calculation to eliminate * or fix contacts normals that could lead to incorrect bumps in physics simulation * (especially on flat surfaces). * * This is achieved by taking into account adjacent triangle normals when computing contact * points for a given triangle. * * /!\ NOT SUPPORTED IN THE 2D VERSION OF RAPIER. */ TriMeshFlags[TriMeshFlags["FIX_INTERNAL_EDGES"] = 144] = "FIX_INTERNAL_EDGES"; })(TriMeshFlags || (TriMeshFlags = {})); /** * A shape that is a sphere in 3D and a circle in 2D. */ export class Ball extends Shape { /** * Creates a new ball with the given radius. * @param radius - The balls radius. */ constructor(radius) { super(); this.type = ShapeType.Ball; this.radius = radius; } intoRaw() { return RawShape.ball(this.radius); } } export class HalfSpace extends Shape { /** * Creates a new halfspace delimited by an infinite plane. * * @param normal - The outward normal of the plane. */ constructor(normal) { super(); this.type = ShapeType.HalfSpace; this.normal = normal; } intoRaw() { let n = VectorOps.intoRaw(this.normal); let result = RawShape.halfspace(n); n.free(); return result; } } /** * A shape that is a box in 3D and a rectangle in 2D. */ export class Cuboid extends Shape { // #if DIM3 /** * Creates a new 3D cuboid. * @param hx - The half width of the cuboid. * @param hy - The half height of the cuboid. * @param hz - The half depth of the cuboid. */ constructor(hx, hy, hz) { super(); this.type = ShapeType.Cuboid; this.halfExtents = VectorOps.new(hx, hy, hz); } // #endif intoRaw() { // #if DIM3 return RawShape.cuboid(this.halfExtents.x, this.halfExtents.y, this.halfExtents.z); // #endif } } /** * A shape that is a box in 3D and a rectangle in 2D, with round corners. */ export class RoundCuboid extends Shape { // #if DIM3 /** * Creates a new 3D cuboid. * @param hx - The half width of the cuboid. * @param hy - The half height of the cuboid. * @param hz - The half depth of the cuboid. * @param borderRadius - The radius of the borders of this cuboid. This will * effectively increase the half-extents of the cuboid by this radius. */ constructor(hx, hy, hz, borderRadius) { super(); this.type = ShapeType.RoundCuboid; this.halfExtents = VectorOps.new(hx, hy, hz); this.borderRadius = borderRadius; } // #endif intoRaw() { // #if DIM3 return RawShape.roundCuboid(this.halfExtents.x, this.halfExtents.y, this.halfExtents.z, this.borderRadius); // #endif } } /** * A shape that is a capsule. */ export class Capsule extends Shape { /** * Creates a new capsule with the given radius and half-height. * @param halfHeight - The balls half-height along the `y` axis. * @param radius - The balls radius. */ constructor(halfHeight, radius) { super(); this.type = ShapeType.Capsule; this.halfHeight = halfHeight; this.radius = radius; } intoRaw() { return RawShape.capsule(this.halfHeight, this.radius); } } /** * A shape that is a segment. */ export class Segment extends Shape { /** * Creates a new segment shape. * @param a - The first point of the segment. * @param b - The second point of the segment. */ constructor(a, b) { super(); this.type = ShapeType.Segment; this.a = a; this.b = b; } intoRaw() { let ra = VectorOps.intoRaw(this.a); let rb = VectorOps.intoRaw(this.b); let result = RawShape.segment(ra, rb); ra.free(); rb.free(); return result; } } /** * A shape that is a segment. */ export class Triangle extends Shape { /** * Creates a new triangle shape. * * @param a - The first point of the triangle. * @param b - The second point of the triangle. * @param c - The third point of the triangle. */ constructor(a, b, c) { super(); this.type = ShapeType.Triangle; this.a = a; this.b = b; this.c = c; } intoRaw() { let ra = VectorOps.intoRaw(this.a); let rb = VectorOps.intoRaw(this.b); let rc = VectorOps.intoRaw(this.c); let result = RawShape.triangle(ra, rb, rc); ra.free(); rb.free(); rc.free(); return result; } } /** * A shape that is a triangle with round borders and a non-zero thickness. */ export class RoundTriangle extends Shape { /** * Creates a new triangle shape with round corners. * * @param a - The first point of the triangle. * @param b - The second point of the triangle. * @param c - The third point of the triangle. * @param borderRadius - The radius of the borders of this triangle. In 3D, * this is also equal to half the thickness of the triangle. */ constructor(a, b, c, borderRadius) { super(); this.type = ShapeType.RoundTriangle; this.a = a; this.b = b; this.c = c; this.borderRadius = borderRadius; } intoRaw() { let ra = VectorOps.intoRaw(this.a); let rb = VectorOps.intoRaw(this.b); let rc = VectorOps.intoRaw(this.c); let result = RawShape.roundTriangle(ra, rb, rc, this.borderRadius); ra.free(); rb.free(); rc.free(); return result; } } /** * A shape that is a triangle mesh. */ export class Polyline extends Shape { /** * Creates a new polyline shape. * * @param vertices - The coordinates of the polyline's vertices. * @param indices - The indices of the polyline's segments. If this is `null` or not provided, then * the vertices are assumed to form a line strip. */ constructor(vertices, indices) { super(); this.type = ShapeType.Polyline; this.vertices = vertices; this.indices = indices !== null && indices !== void 0 ? indices : new Uint32Array(0); } intoRaw() { return RawShape.polyline(this.vertices, this.indices); } } /** * A shape made of voxels. */ export class Voxels extends Shape { /** * Creates a new shape made of voxels. * * @param data - Defines the set of voxels. If this is a `Int32Array` then * each voxel is defined from its (signed) grid coordinates, * with 3 (resp 2) contiguous integers per voxel in 3D (resp 2D). * If this is a `Float32Array`, each voxel will be such that * they contain at least one point from this array (where each * point is defined from 3 (resp 2) contiguous numbers per point * in 3D (resp 2D). * @param voxelSize - The size of each voxel. */ constructor(data, voxelSize) { super(); this.type = ShapeType.Voxels; this.data = data; this.voxelSize = voxelSize; } intoRaw() { let voxelSize = VectorOps.intoRaw(this.voxelSize); let result; if (this.data instanceof Int32Array) { result = RawShape.voxels(voxelSize, this.data); } else { result = RawShape.voxelsFromPoints(voxelSize, this.data); } voxelSize.free(); return result; } } /** * A shape that is a triangle mesh. */ export class TriMesh extends Shape { /** * Creates a new triangle mesh shape. * * @param vertices - The coordinates of the triangle mesh's vertices. * @param indices - The indices of the triangle mesh's triangles. */ constructor(vertices, indices, flags) { super(); this.type = ShapeType.TriMesh; this.vertices = vertices; this.indices = indices; this.flags = flags; } intoRaw() { return RawShape.trimesh(this.vertices, this.indices, this.flags); } } // #if DIM3 /** * A shape that is a convex polygon. */ export class ConvexPolyhedron extends Shape { /** * Creates a new convex polygon shape. * * @param vertices - The coordinates of the convex polygon's vertices. * @param indices - The index buffer of this convex mesh. If this is `null` * or `undefined`, the convex-hull of the input vertices will be computed * automatically. Otherwise, it will be assumed that the mesh you provide * is already convex. */ constructor(vertices, indices) { super(); this.type = ShapeType.ConvexPolyhedron; this.vertices = vertices; this.indices = indices; } intoRaw() { if (!!this.indices) { return RawShape.convexMesh(this.vertices, this.indices); } else { return RawShape.convexHull(this.vertices); } } } /** * A shape that is a convex polygon. */ export class RoundConvexPolyhedron extends Shape { /** * Creates a new convex polygon shape. * * @param vertices - The coordinates of the convex polygon's vertices. * @param indices - The index buffer of this convex mesh. If this is `null` * or `undefined`, the convex-hull of the input vertices will be computed * automatically. Otherwise, it will be assumed that the mesh you provide * is already convex. * @param borderRadius - The radius of the borders of this convex polyhedron. */ constructor(vertices, indices, borderRadius) { super(); this.type = ShapeType.RoundConvexPolyhedron; this.vertices = vertices; this.indices = indices; this.borderRadius = borderRadius; } intoRaw() { if (!!this.indices) { return RawShape.roundConvexMesh(this.vertices, this.indices, this.borderRadius); } else { return RawShape.roundConvexHull(this.vertices, this.borderRadius); } } } /** * A shape that is a heightfield. */ export class Heightfield extends Shape { /** * Creates a new heightfield shape. * * @param nrows − The number of rows in the heights matrix. * @param ncols - The number of columns in the heights matrix. * @param heights - The heights of the heightfield along its local `y` axis, * provided as a matrix stored in column-major order. * @param scale - The dimensions of the heightfield's local `x,z` plane. */ constructor(nrows, ncols, heights, scale, flags) { super(); this.type = ShapeType.HeightField; this.nrows = nrows; this.ncols = ncols; this.heights = heights; this.scale = scale; this.flags = flags; } intoRaw() { let rawScale = VectorOps.intoRaw(this.scale); let rawShape = RawShape.heightfield(this.nrows, this.ncols, this.heights, rawScale, this.flags); rawScale.free(); return rawShape; } } /** * A shape that is a 3D cylinder. */ export class Cylinder extends Shape { /** * Creates a new cylinder with the given radius and half-height. * @param halfHeight - The balls half-height along the `y` axis. * @param radius - The balls radius. */ constructor(halfHeight, radius) { super(); this.type = ShapeType.Cylinder; this.halfHeight = halfHeight; this.radius = radius; } intoRaw() { return RawShape.cylinder(this.halfHeight, this.radius); } } /** * A shape that is a 3D cylinder with round corners. */ export class RoundCylinder extends Shape { /** * Creates a new cylinder with the given radius and half-height. * @param halfHeight - The balls half-height along the `y` axis. * @param radius - The balls radius. * @param borderRadius - The radius of the borders of this cylinder. */ constructor(halfHeight, radius, borderRadius) { super(); this.type = ShapeType.RoundCylinder; this.borderRadius = borderRadius; this.halfHeight = halfHeight; this.radius = radius; } intoRaw() { return RawShape.roundCylinder(this.halfHeight, this.radius, this.borderRadius); } } /** * A shape that is a 3D cone. */ export class Cone extends Shape { /** * Creates a new cone with the given radius and half-height. * @param halfHeight - The balls half-height along the `y` axis. * @param radius - The balls radius. */ constructor(halfHeight, radius) { super(); this.type = ShapeType.Cone; this.halfHeight = halfHeight; this.radius = radius; } intoRaw() { return RawShape.cone(this.halfHeight, this.radius); } } /** * A shape that is a 3D cone with round corners. */ export class RoundCone extends Shape { /** * Creates a new cone with the given radius and half-height. * @param halfHeight - The balls half-height along the `y` axis. * @param radius - The balls radius. * @param borderRadius - The radius of the borders of this cone. */ constructor(halfHeight, radius, borderRadius) { super(); this.type = ShapeType.RoundCone; this.halfHeight = halfHeight; this.radius = radius; this.borderRadius = borderRadius; } intoRaw() { return RawShape.roundCone(this.halfHeight, this.radius, this.borderRadius); } } // #endif //# sourceMappingURL=shape.js.map