This guide bridges the generated API reference and the full example applications. It explains how the public MTK Web classes work together in typical workflows: which classes take part, how they relate, in which order to call them, and which caveats to keep in mind. Each scenario links to the detailed API pages and names the example code that shows the complete integration.
MTK Web reads models in the MTKWEB format. Convert the original CAD files with Manufacturing Toolkit first. MTK Web supplies model data, geometry, and computations; it does not render anything and does not depend on a rendering library. The examples use Three.js, but any renderer can consume the same data, see Examples.
The examples are TypeScript. The Location line directly above an example names its source files, relative to the root of the examples project. An example with a Location line shows the code of those files as it is in the repository, limited to the parts that matter for the scenario. Imports contain only names used in the displayed code. Examples written for this guide have no Location line and are explicitly marked as not implemented in the repository.
Use this when you have a converted .mtkweb file with its companion files and want a Model in memory.
Typical sequence:
Model to receive the product structure and optional drawing.DataProvider, a function that returns the bytes of a requested file by its name.ModelReader and await read() with the main file name, the model, and the provider.Model.roots for the product structure and Model.drawing for a drawing.ModelLoader.load() finds the main .mtkweb file among the files of a file source, creates a data provider for all these files with createModelDataProvider(), and reads the model.
Location: shared/src/features/model/import/ModelLoader.ts
Notes and caveats:
read(), then with the names of the external data files that the main file references. In converted models these are UUID-named files stored next to the .mtkweb file, so the provider must serve every file of the converted model. Up to eight requests can be in flight at the same time. Each external file is requested once per read; only a failed request can be repeated.read() resolves, so the provider is not needed afterwards.ArrayBuffer that contains exactly the file content. The reader uses the whole buffer, so when your bytes come from a typed-array view such as a Node.js Buffer, pass a copy of the viewed range instead of the underlying ArrayBuffer.read() ordinarily resolves to false when the content is not a valid MTKWEB file or when an external file cannot be loaded or parsed. It may instead reject when the provider for the main file fails, decompression of the main buffer throws, or an unexpected parsing error escapes. Handle the false result and catch any rejection; do not assume that provider errors are the only reason the promise can reject.false leaves the model empty; after a rejected read, the model can contain partially read data, so discard it. Read into a new Model, and do not run two reads into the same model at the same time.Model.isEmpty() checks only roots. A file can contain only a drawing, so check model.drawing as well.Model.open() is equivalent; ModelReader.read() delegates to it. The model name is read from the file and can be null.Use this when you need to list assemblies, parts, and bodies, for example for a model tree or statistics, and to understand which data is shared.
| Class | Entry point | Responsibility |
|---|---|---|
ModelElement | @mtk/web/model-data | Base class of assemblies, instances, and parts: name, uuid, material, pmi. |
Assembly | @mtk/web/model-data | Groups child instances in instances. |
Instance | @mtk/web/model-data | One occurrence of an assembly or part in reference, with an optional transformation. |
Part | @mtk/web/model-data | Leaf element that owns bodies. |
Body | @mtk/web/model-data | Base class of SolidBody, SheetBody, WireframeBody, and MeshBody. |
Typical sequence:
model.roots; each root is an Assembly or a Part.assembly.instances; the direct children of an assembly are always instances.instance.reference, which can be null.part.bodies and branch on the body class.Notes and caveats:
Part or Assembly object can be the reference of several instances, so a traversal reaches a shared part once per occurrence. Recognize shared definitions by object identity, for example with a Set.Instance carries a transformation. Assemblies, parts, and bodies do not; see Traverse the Model and Compute World Transformations.Instance.transformation getter creates and stores an identity transformation when none is set and returns the stored object, not a copy. After that, hasTransformation() returns true. Call hasTransformation() first, and clone the transformation before modifying it. The setter stores a copy.Model.roots and Assembly.instances are read-only sets, while Part.bodies is a regular Set. Use roots.size, instances.size, and bodies.size to count elements, and bodies.add() to add a body.BaseObject, including model entities, has an id of type bigint; loaded entities keep the identifiers stored in the file. Convert an id with toString() before putting it into JSON. uuid can be null; Model.assignUuids() assigns new random UUIDs to all unique model elements and drawing entities.Model.addRoot(), Assembly.addInstance(), Assembly.removeInstance(), and Model.merge(). To share a part or an assembly, add it through a new instance for each parent; never put the same Instance object into two parents. MTK Web has no MTKWEB writer, so edits stay in memory.Use this when you need every occurrence of a body with its placement (rendering, world-space bounding boxes, totals), or every unique definition once (caches, per-part processing).
Typical sequence:
ModelElementVisitor as a class or an object literal; all callbacks are optional. To handle every element through one visitEnter() and visitLeave() pair, extend the abstract CombinedElementVisitor class.Model.accept(), or accept() on any model element for a subtree. For one visit per unique element, wrap your visitor in ModelElementUniqueVisitor.visitPart(). Returning false from visitAssemblyEnter() or visitInstanceEnter() skips the children; the matching leave method is still called.part.bodies yourself in visitPart().Transformation, which combines rotation, translation, and uniform scale. For a subtree, initialize it with the world transformation of the chosen parent occurrence. On every instance enter, push parent.multiplied(instance.transformation) if hasTransformation() returns true; otherwise push parent.clone(). Pop one entry on every instance leave.The following example is written for this guide and is not implemented in the repository. OccurrenceCounter counts assemblies and instances during a traversal, and collects parts in a Set to count unique definitions, so a shared part can be visited several times while appearing once in uniqueParts.
Before a measurement, getCombinedTransformation() computes the world transformation of a selected body from the path to it in the model tree: it walks from the body node up to the root and composes the transformations of the instances on the way.
Location: shared/src/features/model/measurements/ModelMeasurementTargetAdapter.ts
The example applications use ModelStructureBuilder to assign instance transformations to Three.js nodes and let the renderer compose them.
Location: shared/src/features/model/structure/ModelStructureBuilder.ts
To process each definition once, wrap the visitor. The import flow creates a PartAnalysisTargetCollector and passes it through ModelElementUniqueVisitor, so each shared part is converted once per model role.
Location: shared/src/features/mtk/import/AnalysisComposer.ts
Notes and caveats:
ModelElementUniqueVisitor passes each unique assembly, instance, and part to your visitor once. Later occurrences of an already visited element are skipped completely: your visitor receives neither enter nor leave calls for them, and their children are not visited. It therefore cannot provide per-occurrence transformations; use it for per-definition work only.multiplied() returns a new transformation that applies its argument first and then the transformation it is called on, so the world transformation is parentWorld.multiplied(localTransformation), whereas multiply() is the in-place variant.scaleFactor can be negative, and isNegative() reports a rotation matrix with a negative determinant.CombinedElementVisitor, the value returned from visitEnter() controls child visiting for assemblies and instances and is ignored for parts.Use this when external data, such as Manufacturing Toolkit process data, review notes, or saved settings, refers to model elements or drawing entities, or when such references must survive a reload of the model.
Use UUIDs for references that must survive a reload. The id inherited from BaseObject identifies an object within the loaded data; ModelElement.uuid provides the UUID of an assembly, instance, or part, or null.
Typical sequence:
Uuid is a TypeScript template string type in the canonical form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.ModelElementUniqueVisitor and look up each uuid.null and, when all-zero UUIDs must not match external data, use isNullUuid() to detect NULL_UUID.createRandomUuid(), which creates a random version 4 UUID using Web Crypto when available. Store references to model elements by uuid.Model.assignUuids() assigns random UUIDs to all unique model elements and drawing entities. Call it before storing references: it replaces existing UUIDs.Manufacturing Toolkit process data refers to parts by UUID. The default contribution provider reads target records from process-data files, extracts partId, and stores it as an AnalysisTargetKey. AnalysisComposer then matches those contribution keys with the targets previously seeded from model parts.
Location: shared/src/features/mtk/import/mtkAnalysisContributionProvider.ts
Objects that the application creates itself get new UUIDs.
A design review item, such as a note or a pin, receives its UUID from createRandomUuid().
Location: shared/src/features/design-review/DesignReviewItem.ts
Notes and caveats:
id is a bigint that identifies an object within the loaded data and links shapes to polygonal ranges. Nothing guarantees that it stays the same when a model is converted again, so use uuid for persistent references.uuid is null when the file stores none. A UUID stored as all zeros is read as NULL_UUID, not as null. The repository example checks only for null; also check isNullUuid(uuid) when all-zero UUIDs must not match external data.Instance or the chain of instance UUIDs from the root.Model.assignUuids() replaces every existing UUID with a new random one, so references stored for the previous values no longer resolve. Call it only for models whose elements have no stable UUIDs yet, for example a model built in memory, and before you store references.uuid; assignUuids() covers them when the model has a drawing.Uuid is a TypeScript type only. Validate UUID strings from external input yourself.Use this when you need the faces, edges, and vertices of a body, for example to inspect surface types, to resolve a selection, or to measure individual entities.
Shape is the base class of the B-Rep topology: Solid, Shell, Face, Wire, Edge, and Vertex.
Typical sequence:
part.bodies. SolidBody exposes its solid; SheetBody and WireframeBody expose their shapes. Handle MeshBody separately: its shapes are polygonal data without B-Rep topology.ShapeIterator with new ShapeIterator(body) for direct children. Pass a ShapeType enumeration value, for example new ShapeIterator(body, ShapeType.FACE), to visit all subshapes of that type in depth-first order.instanceof. A Face provides surface, an Edge provides curve, and a Vertex provides point.Set when the same subshape must be processed only once.AnalysisBuilder.indexShapesOfPart() iterates faces of solid and sheet bodies with a ShapeType.FACE filter, then iterates the edges of each face with a ShapeType.EDGE filter, and stores each shape by its id. Wireframe bodies have no faces, so the method indexes their edges directly.
Location: shared/src/features/mtk/analysis/base/AnalysisBuilder.ts
Notes and caveats:
SolidBody yields its solid, SheetBody and WireframeBody yield their shapes, a solid yields shells, and so on down to the start and end vertices of an edge.Set removes the duplicates.new ShapeIterator(sheetBody, ShapeType.SHELL) ignores faces that were added to the body directly.ShapeIterator can be consumed only once. Create a new iterator for every loop.MeshBody yields nothing; read MeshBody.shapes instead.Edge.curve is null for a degenerated edge (see isDegenerated()); Face.surface is always set.id) come from the file and link shapes to ranges of the polygonal data, see Get Polygonal Data for Visualization.Use this when you feed a renderer or implement picking. MTK Web provides the vertex, index, normal, and color arrays; the renderer and its scene are your choice.
An individual shape's stored triangulation is described by ShapeTriangulation and its specialized types FaceTriangulation, EdgeTriangulation, and VertexTriangulation. It contains a shared meshShape and the shape's primitives range within it.
Typical sequence:
computeCompoundTriangulation(defaultMaterial) on SolidBody, SheetBody, or WireframeBody; the same method is available on Solid, Shell, and Wire. Pass a material or null explicitly. It merges stored triangulations into a ShapeCompoundTriangulation, whose faces, edges, and vertices map meshes to primitive groups. Cache the result by body and effective material when materials differ between occurrences. For a MeshBody, read its shapes directly.vertices, colors, and counts from IndexedTriangleSet, PolylineSet, or PointSet. IndexedTriangleSet also provides vertexIndices, normals, and uvCoordinates.ShapeCompoundTriangulationPrimitivesGroup defines a range with one material. Its shapesPrimitives entries are ShapePrimitivesGroup ranges for individual shapes.MeshBVH to find a hit triangle, then map it to a face through shapesPrimitives and shapeId.ModelDataConverter.convertBody() reads the mesh shapes of a MeshBody, computes the compound triangulation of a B-Rep body, and converts each face mesh with its material groups, shape ranges, and bounding volume hierarchy to a Three.js object.
Location: shared/src/common/helpers/ThreeHelper.ts
The ranges use different units:
| Range | IndexedTriangleSet (faces) | PolylineSet (edges) | PointSet (vertices) |
|---|---|---|---|
start and count of a compound group, and primitives of Face.triangulation, Edge.triangulation, or Vertex.triangulation | Index-buffer entries, three per triangle | Polylines | Points |
start and count of an entry in shapesPrimitives | Triangles | start is the index of the first point in the flattened point sequence; count is the number of line segments | Points |
To find the face or edge under a picked primitive, ModelIntersectionMapper uses this sequence:
getShapeIdFromIntersection() takes the triangle index of a face hit or the index of the first point of a hit edge segment.ShapePrimitivesGroup[] stored on the render object by convertBody() and returns the shapeId of the range containing that index.mapToShape() uses ShapeIterator to traverse the hit body's faces or edges and returns the shape with the matching ID, or null if no match is found.The excerpt below shows the primitive-index-to-ID lookup. The shape traversal uses the same ShapeIterator API introduced in Explore B-Rep Topology.
Location: shared/src/features/model/interaction/ModelIntersectionMapper.ts
Notes and caveats:
IndexedTriangleSet: Face.triangulation holds the shared mesh and the range of the face. Drawing face.triangulation.meshShape for every face without limiting it to the face's primitives range draws the shared mesh repeatedly; draw the compound triangulation instead.computeCompoundTriangulation() is not cached. When a body uses only part of a stored mesh, it builds a new, compacted mesh on every call; the ranges in the returned groups always refer to the meshes in the returned maps.vertices, vertexIndices, normals, colors, and uvCoordinates build a new typed array on every read. Read each of them once per mesh. vertexIndices is a Uint16Array or a Uint32Array, depending on the largest index.normals, colors, and uvCoordinates are empty arrays when the mesh does not define them; colors are RGBA values per vertex. IndexedTriangleSet.triangleNormal() computes a flat normal when normals are missing.material is null on loaded elements and bodies, and per-vertex colors are the only appearance data from the file. The library applies only body.material, or the default material you pass, to all faces, edges, and vertices of the body; there are no per-face materials. Passing null as the default produces groups whose material can be null. Inheriting materials from parts, instances, and assemblies is an application policy: the examples use the nearest material on the path from the root, and a material assigned to the body overrides it.IndexedTriangleSet.bvh can be loaded from the file or be null, and a compacted compound mesh has none. The static MeshBVH.build() creates one, optionally limited to the given groups, or returns null if it cannot be built. See Pick Triangles with a Bounding Volume Hierarchy.Use this when you assign appearance to bodies or model elements, or convert MTK Web materials into the materials of your renderer.
VisualMaterial is the base class for the material of model elements, bodies, and compound groups. Its opacity is in the range [0, 1].
Typical sequence:
Color from RGBA components in [0, 1] or a hex string. Color.fromRGB() and Color.fromRGBA() accept the BaseRGB and BaseRGBA interfaces ({ r, g, b } and { r, g, b, a }), also accepted as color-array entries by mesh constructors. Read individual components through r, g, b, and a; toRGB() and toRGBA() return packed integers in 0xRRGGBB and 0xRRGGBBAA format.BasicMaterial for an unlit material with one color, for example new BasicMaterial(new Color(0, 0, 0)) for drawing lines. Use PhongMaterial for shaded bodies, with ambientColor, diffuseColor, specularColor, emissionColor, and shininess. Create each material once and share it.material on a body or model element, or pass it as the default material of computeCompoundTriangulation().MaterialManager.createMeshMaterial() converts BasicMaterial and PhongMaterial into Three.js materials, falls back to a default material, and copies the opacity; convertColor() converts a Color; and DrawingStructureBuilder draws drawing elements with a black BasicMaterial.
Location: shared/src/common/materials/convertColor.ts
Location: shared/src/common/materials/MaterialManager.ts
Location: shared/src/features/drawing/structure/DrawingStructureBuilder.ts
Notes and caveats:
0 to 1, not from 0 to 255; calling new Color() without arguments creates a color with unset components for which isNull() returns true. Pass at least one component or a hex string such as ‘’#9f9fa6'; an invalid hex string also leaves the color unset. -toRGB()drops the alpha component; opacity is carried byVisualMaterial.opacity, and the example copies it to the renderer material.The constructors and color setters ofBasicMaterialandPhongMaterialcopy the colors you pass, while the color getters return the stored objects, so modifying a returned color changes the material. Clone it first when you derive a color for another material.AVisualMaterialthat is neither aBasicMaterialnor aPhongMaterialis an application subclass; the examples useVisualThreeMaterialto carry a Three.js material through the MTK Web API. Keep a fallback branch for such materials. -Color.toJSON()returns aBaseRGBA` object, which is convenient for storing colors in application state.Use this when you implement picking or other spatial queries on large meshes and a linear scan over all triangles is too slow.
MeshBVH provides a hierarchy over the triangles, polylines, or points of one mesh shape; its primitives are their indices. It derives from the abstract BaseBVH, which provides traversal over primitives.
Typical sequence:
BVHBuildOptions provides optional maxLeafSize, maxDepth, and strategy settings. BVHSplitStrategy selects CENTER, AVERAGE, or SAH (surface area heuristic) splitting.mesh.bvh, or build one with MeshBVH.build(mesh, groups, options) and keep it with the render object. The options argument is optional. Check the result before traversal: build() returns null when it cannot build a hierarchy for the supplied mesh and groups.bvh.traverse() with a predicate that tests a node's Box (minCorner, maxCorner) against the ray and a callback that receives each candidate primitive index. The BVHNode interface describes bounds, children, and primitive ranges for hierarchy implementations; applications do not receive nodes.ModelDataConverter.convertBody(), shown in Get Polygonal Data for Visualization, reuses a loaded hierarchy or builds one per face mesh and passes it to getRaycast(). getRaycast() transforms the Three.js ray into the local coordinates of the mesh, and raycast() traverses the hierarchy with a ray-box test and intersects the candidate triangles.
Location: shared/src/common/helpers/getRaycast.ts
The example applications use the default build options: maxLeafSize is 10, maxDepth is 40, and strategy is BVHSplitStrategy.CENTER. Pass a BVHBuildOptions object as the third argument of MeshBVH.build() to change these values, for example to select BVHSplitStrategy.SAH.
Notes and caveats:
getRaycast() does with the inverse world matrix.IndexedTriangleSet, a primitive is a triangle index; its vertices are at index-buffer positions 3 * triangle, 3 * triangle + 1, and 3 * triangle + 2. The groups passed to build() use the units of MeshShapePrimitivesGroup, that is, index-buffer entries for triangle meshes.traverse() calls the primitive callback for every primitive in a node whose bounds pass the predicate; it does not sort by distance or stop early. The example collects every hit and leaves sorting to the Three.js raycaster; without such a raycaster, keep the nearest hit yourself.Box object for all nodes. Read its corners inside the predicate and do not keep a reference to it.MeshBVH.build() returns null when the mesh has no primitives or a group range is invalid. The example then falls back to the renderer's own raycasting.BaseBVH is the extension point for hierarchies over other primitives: a subclass supplies primitive bounds and builds its tree through protected members. Applications normally use MeshBVH.Use this when a selected face or edge must be classified by its exact geometry, for example to decide which measurements apply, to read a radius or an axis, or to place an annotation on the carrier of a shape.
Geometry is the base class of curves, surfaces, and polylines.
Typical sequence:
face.surface, a Surface, or edge.curve, a Curve. The curve is null for a degenerated edge.instanceof, or read type when you only need the kind of geometry. Surface types use SurfaceType; curve types use CurveType.ElementarySurface provides a position axis placement, a location, and a direction. Its concrete classes include Plane, CylindricalSurface, ConicalSurface, SphericalSurface, and ToroidalSurface. Read the applicable parameters, such as radius, semiAngle, majorRadius, or minorRadius.Line represents a straight line. Conic provides a position axis placement for Circle, Ellipse, Hyperbola, and Parabola. Read the applicable radius, majorRadius, minorRadius, or focal parameter.Axis3d describes a 3D coordinate system with location, axis, xDirection, and yDirection; use isRightHanded() to check its handedness. An Axis1d describes a location and one direction. Transform positions with the occurrence's world transformation before combining them with data from other occurrences.Curve2d is their base class. Line2d stores a location and direction. Conic2d provides an Axis2d position for Circle2d, Ellipse2d, Hyperbola2d, and Parabola2d.For a bounded solid cylinder, use Cylinder, defined by an Axis1d through its center, a radius, and a height. It provides volume, surfaceArea, and isContaining(); it is not a surface of the model.
Use instanceof to read the parameters of a concrete surface or curve. Compare CurveType and SurfaceType separately; their numeric values overlap.
RadialDimensionsBuilder reads the placement of a conic curve and transforms it.
Location: shared/src/features/measurements/radial/RadialDimensionsBuilder.ts
getRadialPlacementSpace() branches on spherical and cylindrical carrier surfaces.
Location: shared/src/features/measurements/radial/RadialPlacementSpace.ts
computeFlatPatternRotation() reads the direction of elementary and planar surfaces.
Location: shared/src/features/mtk/analysis/flat-pattern/computeFlatPatternRotation.ts
Cylinder is also useful independently of a loaded face. The following mathematical example is written for this guide and is not implemented in the repository: it constructs a cylinder from a radius and a height and reads its volume.
Notes and caveats:
CurveType and SurfaceType values overlap numerically; for example, CurveType.PARABOLA and SurfaceType.TORUS are both 4. Never put curve and surface types into one list or compare a curve type with a surface type. Compare type values only within one enumeration, or use instanceof.type on a plain Surface or Curve without parameters, so always keep a fallback branch.Axis3d.transformed() returns a transformed copy; parameters such as radii are not scaled, so multiply them by Math.abs(scaleFactor) as RadialDimensionsBuilder does.Face.surface, Edge.curve, and their position objects belong to the model. Clone them before you modify them.Cylinder is a standalone primitive. Its axis location is the center, not a base point, and negative radius and height values are clamped to 0.CurveSet and PiecewiseContour elements and the PMI Curve2dOutline expose only polygonal triangulation data. Use Curve2d and its subclasses for exact 2D geometry that your application builds; the drawing example samples the arc of an angular dimension into a Polyline2d instead, see Read Dimensions, Hatches, and Text.Radius and Angle in @mtk/web/measurements already evaluate these classes; see Measure Geometry and Compute Validation Properties before reimplementing a measurement.Use this when you pass MTK Web placements to a renderer, compose placements yourself, or compute positions in 3D or in 2D overlays.
Typical sequence:
Transformation combines rotation, translation, and a uniform scaleFactor; static factories such as scaleTransformation() construct placements. See Traverse the Model and Compute World Transformations.rotation multiplied by scaleFactor, and the last column is translation. Matrix3d and Matrix2d represent transformation rotations; their Matrix base class provides value(row, column), setRow(), and setColumn() for square matrices.Point for a position, Vector for a displacement, and Direction for a unit vector. new Vector(start, end) builds the displacement between two points.XYZ triples or XY pairs for temporary arithmetic in loops. The BaseXYZ ({ x, y, z }) and BaseXY ({ x, y }) interfaces describe the values accepted by fromXYZ() and fromXY() factories.Transformation2d with a Matrix2d rotation, a Vector2d translation, and a scale factor, and apply it to Point2d values. Direction2d and Axis2d provide a 2D unit vector and coordinate system.Polyline and Polyline2d store their points in points; obtain them from PolylineSet.polyline() and Polyline2dSet.polyline().The following mathematical example is written for this guide and is not implemented in the repository. A Vector keeps the displacement length, a Direction keeps only its orientation, and a translation moves a point by the displacement.
The convertTransformation() function creates a Three.js Matrix4 from these values.
Location: shared/src/common/helpers/ThreeHelper.ts
The following mathematical example is written for this guide and is not implemented in the repository. It scales a point about the origin, then translates it. In translation.multiplied(scale), the right-hand transformation is applied first. The copying methods leave point, scale, and translation unchanged.
Notes and caveats:
add() and added(), multiply() and multiplied(), transform() and transformed(). The in-place variant modifies the object it is called on, which is a common source of bugs when that object belongs to the model.point.subtracted(otherPoint) returns the Vector from the other point, while point.subtracted(vector) and point.added(vector) return a Point; a Direction is always normalized, and its constructor throws a RangeError when the length is not greater than 1e-5. Check the length before constructing a direction from a vector that may be zero.Transformation is rotation * scaleFactor. A negative scaleFactor or a rotation with a negative determinant mirrors geometry, see isNegative().Matrix.value() takes a row and a column. Renderers differ in the order of their matrix storage; Three.js Matrix4 accepts row-major values in its constructor but stores them column-major.XYZ and XY are containers without geometric meaning. Converting them with Point.fromXYZ(), Vector.fromXYZ(), Point2d.fromXY(), or Direction2d.fromXY() creates new objects.Polyline and Polyline2d store their points in the points array.These rules apply to measurements and plane sections:
Model carries no unit information. Areas are in square units, volumes in cubic units, and angles in radians.Model input, results include all instance transformations, that is, they are in the coordinates of the model roots. For an assembly, instance, or part input, results include the instance transformations inside that subtree; for an instance input, its own transformation is included as well. For a body, shape, or mesh input, results are local unless a transformation argument is accepted and passed. BoundingBox, Distance, Angle, and PlaneSection accept transformations; SurfaceArea, Volume, and both ValidationProperties methods do not.SurfaceArea, Volume, and PlaneSection work on the stored triangulation and have no accuracy parameter. BoundingBox and Distance use stored mesh data where available, but without triangulation they can fall back to exact B-Rep vertex points; Distance also represents an untriangulated edge by the straight segment between its endpoints, not by its exact curve. ValidationProperties uses stored polygonal data and can use exact vertex points and untriangulated straight edges. Length, Radius, and Angle use exact curves and surfaces where they are available. Faces without a triangulation contribute nothing to areas and sections and can make a volume or validation result unavailable or invalid.1e-7 are used; for example, lengths, areas, and volumes at or below this value are reported as not measurable.Use this when you need sizes, distances, angles, radii, areas, volumes, or mass properties. The classes in @mtk/web/measurements provide static methods that do not modify the model; ValidationPropertyData is the result type of ValidationProperties.compute(). Read Geometry Conventions first.
Whole-object properties:
| Method | Accepts | Result and failure value |
|---|---|---|
BoundingBox.compute() | Model, ModelElement, Body, Shape, or MeshShape; optional transformation except for Model; optional output Box | Box; an infinite box when nothing is measurable, check isInfinity() |
SurfaceArea.compute() | The same five input types; no transformation overload | Area, or -1 |
Volume.compute() | The same five input types; no transformation overload; only solids and closed triangle meshes have a volume | Volume, or -1 |
ValidationProperties.compute() | The same five input types; no transformation overload | ValidationPropertyData: volume, surface area, centroid, axes of inertia, and isValid; volume or surfaceArea is -1 when the input has no volume or no surface |
ValidationProperties.computeCentroid() | The same five input types; no transformation overload | Point; the origin when the centroid cannot be computed |
Entity measurements:
| Method | Accepts | Result and failure value |
|---|---|---|
Distance.compute() | Two objects, each a Body, Shape, or MeshShape; optional transformation per object; optional [Point, Point] output | Minimum distance, or -1 |
Angle.compute() | Two planar faces, two linear edges, three vertices, or three points; optional transformation per object | Angle in radians, or NaN |
Length.compute() | Edge, Wire, PolylineSet, or Polyline2dSet | Length, or -1 |
Radius.compute() | A circular, elliptic, or hyperbolic edge, or a cylindrical, conical, spherical, or toroidal face; optional curves and points outputs | Array of radii, empty when unsupported |
Typical sequence:
The following example is written for this guide and is not implemented in the repository. It computes the distance between two point sets, first in local coordinates, then with a translation applied to each input.
Notes and caveats:
SurfaceArea, Volume, ValidationProperties.compute(), and ValidationProperties.computeCentroid() cannot take a transformation for a body, shape, or mesh input. Use a Model or an enclosing Instance when you need occurrence-aware results. When only uniform scale affects a scalar result, you can adjust a local area by scaleFactor * scaleFactor and a local volume by Math.abs(scaleFactor ** 3); use an occurrence-aware input for full validation properties because placement also affects the centroid and axes of inertia.Length and Radius accept no transformation, so their values ignore the scale of the occurrence. For a scaled occurrence, multiply the value by Math.abs(world.scaleFactor), as the radial measurement example does.Distance writes the closest points only on success. Radius appends to the curves and points arrays without clearing them, and the returned curves can be objects of the model; do not modify them.ValidationPropertyData return stored objects; clone them before modifying. isValid is false when invalid entities were skipped, so treat the values with care in that case. A valid result can still report -1: volume is -1 for inputs without a volume, such as a sheet or a face, and both volume and surfaceArea are -1 for edges, wires, and vertices.computeCentroid() returns the origin when the centroid cannot be computed, which cannot be told apart from a real centroid at the origin. isValid does not distinguish this case either: for an input without any geometry, such as an empty body, part, or model, compute() returns a valid result with the centroid at the origin and a volume and surface area of 0.Angle supports only faces on a Plane surface and edges on a Line curve. See the API page for the value ranges of each input combination.Use this when you need the contour of a shape or a mesh in a plane, for example for section views or clipping outlines.
| Class | Entry point | Responsibility |
|---|---|---|
Plane | @mtk/web/geom | Section plane, for example new Plane(location, normal) or new Plane(a, b, c, d). |
PlaneSection | @mtk/web/operations | Static compute() of one shape or mesh shape with an optional transformation. |
PlaneSectionData | @mtk/web/operations | Result: polylines, points, and toShapes(). |
Typical sequence:
SolidBody.solid, the shapes of SheetBody and WireframeBody, or the shapes of MeshBody.PlaneSection.compute(input, plane, world) with the occurrence transformation, or convert the plane to body-local coordinates and omit the transformation.polylines and points of the result, or convert it to edges and vertices with toShapes().The following example is written for this guide and is not implemented in the repository. It intersects one triangle with the XY plane. The result contains one segment, from (0.5, 0, 0) to (0, 0.5, 0), and no isolated points.
Notes and caveats:
PlaneSection.compute() accepts a Shape or a MeshShape only, not a Body, a Part, or a Model.points; the points array can also contain points that lie on a section polyline. For B-Rep input, the points where triangulated edges cross the plane are reported there, and a triangulation vertex that lies exactly in the plane can be reported as well. Do not treat points as isolated points only.Use this when you need Product Manufacturing Information (PMI): dimensions, tolerances, datums, and notes, either as displayable graphics or as semantic values, and the saved views defined for it.
Read PMI through ModelElement.pmi on an assembly, instance, or part. This property contains a Data container or null. The container provides PMI elements and savedViews.
Typical sequence:
pmi property. Skip elements without PMI.pmi.elements. Each PMIElement has a type and can have graphical and semantic representations; either representation may be null. Branch on the type or on the available representations.GraphicalRepresentation contains outlined, text, and triangulated components; its plane places 2D content in 3D. Iterate graphicalRepresentation.components, or call its accept() with a GraphicalComponentVisitor. See Convert PMI Graphics.SemanticRepresentation contains dimension, geometric tolerance, datum, and surface finish components. Iterate semanticRepresentation.components and call each SemanticComponent's accept() with a SemanticComponentVisitor. Inside a component callback, iterate its attributes and call each attribute's accept() with a SemanticAttributeVisitor. See Collect Semantic PMI Values.pmi.savedViews. Each SavedView provides a Camera (location, target, up) and the PMI elements to show; its name can be null. Apply the camera and show only those elements.PMIStructureBuilder.collectElements() reads PMI elements both from the data container and from its saved views. A Set avoids adding the same element twice. PMISource belongs to the example application; its data field is the MTK Web Data container.
Location: shared/src/features/pmi/structure/PMIStructureBuilder.ts
Notes and caveats:
accept() received a component visitor or an attribute visitor by inspecting the visitor object's own properties. Pass plain object literals whose properties are only callbacks of one interface, as shown in Collect Semantic PMI Values. A fieldless class-based SemanticComponentVisitor can work because its empty own-property set is classified as a component visitor and its prototype callback is then called. A class-based SemanticAttributeVisitor passed through component.accept() is unreliable because it can be classified as a component visitor before the attributes are traversed; additional instance fields can also make either classification fail. TypeScript does not report these dispatch problems. Iterating component.attributes and calling attribute.accept(visitor) on each attribute avoids the component-level check. Graphical, outline, and drawing visitors are not affected.ModelElement.pmi is the public way to reach PMI from a model. The reader also associates PMI with B-Rep shapes, but the public API provides no way to read these associations from a Shape.TextComponent, Poly2dOutline, and Curve2dOutline) lies in the representation's plane. The PMI example reads PMI of assemblies and parts and maps 2D content to 3D through that plane.PMIElementType.NOTE has the value 0; compare type with === instead of testing it for truthiness.Data.elements together with the elements of all saved views. Data.addView() ignores a view whose name already exists.elements, savedViews, components, and attributes.Use this when you display the graphical representation of PMI elements: lines, curves, filled areas, and text of dimensions, tolerances, and notes.
To dispatch through callbacks, use GraphicalComponentVisitor for each component kind, or extend GraphicalComponentCombinedVisitor to handle all kinds through visitGraphicalComponent(). OutlineVisitor dispatches by outline kind, with visitEnter() and visitLeave() around a composite outline's children.
Typical sequence:
graphicalRepresentation and skip it when it is null. A GraphicalRepresentation contains GraphicalComponent objects and the plane that places 2D content in 3D.representation.plane.position.OutlinedComponent provides an outline, which can be null. A TextComponent provides text, fontSize, origin, and direction in the representation plane. A TriangulatedComponent provides filled areas in triangleSet, an IndexedTriangleSet or null.Outline is the base class. Recurse through a CompositeOutline's outlines, which can include other composite outlines.PolyOutline and Poly2dOutline provide a lineSet: a 3D PolylineSet or a Polyline2dSet in the representation plane. CurveOutline and Curve2dOutline provide curves as polygonal triangulation in the corresponding dimensions. Both lineSet and triangulation can be null; skip missing geometry.PolyOutline, CurveOutline, TriangulatedComponent) directly, and 2D content (Poly2dOutline, Curve2dOutline, TextComponent) through the plane placement.PMIConverter builds the plane placement once, and its helper classes PMIGraphicalComponentConverter and PMIOutlineConverter dispatch components and outlines with instanceof, recurse into composite outlines, and wrap 2D content in an object placed by the plane matrix.
Location: shared/src/common/helpers/pmi/PMIConverter.ts
The visitor interfaces express the same dispatch without instanceof. No example application uses them yet. The following example is written for this guide and is not implemented in the repository: a GraphicalComponentCombinedVisitor receives every graphical component through one method, and an OutlineVisitor brackets the children of a composite outline between visitEnter() and visitLeave().
Notes and caveats:
representation.plane.position: its xDirection, yDirection, and axis form the rotation columns and its location the translation. 3D content is already in the local coordinates of the owning element.TextComponent stores only the text, its size, and its placement. Choose a font and a text rendering method in your application; the example multiplies fontSize by a coefficient and replaces the line-break sequence \P with a newline.OutlinedComponent.outline, TriangulatedComponent.triangleSet, PolyOutline.lineSet, and CurveOutline.triangulation can be null; skip such entries.CompositeOutline.accept() calls visitEnter() before its children and visitLeave() after them. Returning false from visitEnter() skips the children; when visitEnter() is not defined, the children are visited.Use this when you need the machine-readable meaning of PMI, for example a table of nominal values, tolerances, datum references, and surface texture requirements.
Semantic components, reached through semanticRepresentation.components:
| Class | Entry point | Main values |
|---|---|---|
DimensionComponent | @mtk/web/pmi | nominalValue and type (DimensionType). |
GeometricToleranceComponent | @mtk/web/pmi | magnitude, type (ToleranceType), and toleranceZoneForm (ToleranceZoneFormType). |
DatumComponent | @mtk/web/pmi | label. |
SurfaceFinishComponent | @mtk/web/pmi | materialRemoval (MaterialRemovalType), layDirection (LayDirectionType), isAllAround, and manufacturingMethod. |
Semantic attributes, reached through component.attributes; SemanticAttribute is their base class:
| Class | Entry point | Main values |
|---|---|---|
ModifierAttribute, ModifierWithValueAttribute | @mtk/web/pmi | modifier, and modifier with value. |
QualifierAttribute | @mtk/web/pmi | qualifier. |
PlusMinusBoundsAttribute, RangeAttribute | @mtk/web/pmi | lowerBound and upperBound, or lowerLimit and upperLimit. |
LimitsAndFitsAttribute | @mtk/web/pmi | type and value of a fit designation. |
MaximumValueAttribute, DisplacementAttribute | @mtk/web/pmi | maxValue, or displacement. |
DatumTargetAttribute | @mtk/web/pmi | index and description. |
DatumRefAttribute | @mtk/web/pmi | precedence and targetLabel. |
DatumRefCompartmentAttribute | @mtk/web/pmi | Nested references and modifierAttributes. |
LengthUnitAttribute, AngleUnitAttribute | @mtk/web/pmi | unit (LengthUnit or AngleUnit from @mtk/web/measurements). |
MachiningAllowanceAttribute | @mtk/web/pmi | value, upperBound, and lowerBound. |
SurfaceTextureRequirementAttribute | @mtk/web/pmi | precedence, surfaceParameter (SurfaceParameterType), limitValue, specificationLimit (SpecificationLimitType), filters, evaluationLength, and comparisonRule (ComparisonRuleType). |
Typical sequence:
semanticRepresentation has components.accept() on each component with an object-literal SemanticComponentVisitor.accept() on each attribute of component.attributes with an object-literal SemanticAttributeVisitor.references and modifierAttributes with the same attribute visitor.ToleranceType[component.type].SemanticInformationRowCollector visits all four component kinds and all fifteen attribute kinds and converts every value to a table row.
Location: react/src/pages/pmi-explorer-viewer/semantic-information/SemanticInformationRowCollector.ts
Notes and caveats:
accept().DatumRefCompartmentAttribute is the only attribute with nested attributes. Visit them yourself; the attribute's accept() does not visit its children.LengthUnitAttribute or an AngleUnitAttribute, present that unit together with the values instead of assuming the model units.UNDEFINED members such as ToleranceType.UNDEFINED_TOLERANCE; show them as "not specified" instead of hiding the row.Use this when a model contains 2D drawing data and you want to list or display its sheets, views, and elements.
Typical sequence:
model.drawing; it is null when the file has no drawing. A Drawing contains sheets and layers.drawing.sheets, then sheet.views. Each Sheet has paper size and orientation, and each View contains drawing elements. Their Element base class covers geometries such as CurveSet, PiecewiseContour, and DrawingPointSet, as well as Hatch, Text, and dimensions.view.accept(visitor) with an ElementVisitor to dispatch by element type, or extend DrawingCombinedElementVisitor to handle every element through visitElement().position and scale to place the content on the sheet.Layer groups elements across views. Check isVisible, test membership with isContaining(), or visit the layer's elements with accept().DrawingVisualizationChecker counts drawing elements through one callback, regardless of their concrete type.
Location: shared/src/viewers/base-model-viewer/checkers/DrawingVisualizationChecker.ts
In BaseModelViewer.prepare(), drawing is taken from model.drawing and checked for null. With a DrawingVisualizationChecker assigned to checker, the viewer visits every view:
Location: shared/src/viewers/base-model-viewer/BaseModelViewer.ts
View placement is separate from traversal: apply view.scale in view-local coordinates, then use the axes and location in view.position to place the result on the sheet. See Work with Transformations, Matrices, and Vectors for transformation composition.
Notes and caveats:
Axis2d, and its scale, a Ratio whose toNumber() returns numerator / denominator.Sheet reports its size in width and height, and its format in paperSize (PaperSizeType) and orientation (OrientationType), while PaperSizeType.USER_DEFINED marks a custom size.CurveSet exposes only a polygonal approximation of its curves in triangulation, which can be null.accept() or isContaining(). An element belongs to at most one layer; to find it, test the layers in drawing.layers with isContaining().sheets, layers, views, elements, and points.Use this when you show the properties of drawing elements or draw dimensions, hatches, and text yourself.
| Class | Entry point | Responsibility |
|---|---|---|
DrawingGeometry | @mtk/web/drawing | Base class of the geometric elements CurveSet, PiecewiseContour, and DrawingPointSet. |
Dimension | @mtk/web/drawing | Base class of dimensions: measurementValue, isTextAlignedHorizontally, arrowheadPlacement (ArrowheadPlacementType), firstArrowType and secondArrowType (ArrowType), and the dimension text. |
LinearDimension | @mtk/web/drawing | Two reference points, a dimension line point, and rotation (RotationType). |
AngularDimension | @mtk/web/drawing | anglePoint, two reference points, and dimensionArcPoint. |
RadialDimension, DiametricDimension | @mtk/web/drawing | centerPoint and chordPoint, or two chord points, plus dimensionEndPoint. |
Text, TextProperties | @mtk/web/drawing | text and origin, and properties with fontSize in points, rotation in degrees, and justification (JustificationType). |
Hatch | @mtk/web/drawing | Filled area: pattern (PatternType), style (StyleType), scale, angle, contours with contour() and typeOfContour() (ContourType), and definitionLines. |
HatchDefinitionLine | @mtk/web/drawing | One line family of a hatch pattern: angle, basePoint, offset, and dashes. |
Polyline2dSet | @mtk/web/mesh | 2D polylines of curve sets, contours, and application-built annotation lines. |
Typical sequence:
DrawingGeometry, Dimension, Hatch, or Text.DrawingStructureBuilder.addElementToCategoryNode() groups drawing elements into geometries, dimensions, hatches, and texts by their base classes.
Location: shared/src/features/drawing/structure/DrawingStructureBuilder.ts
The property panel of the model explorer example lists the properties of the selected drawing element, and formatEnumValue() converts enumeration values to title-case names.
Location: react/src/pages/model-explorer-viewer/ui/property-panel/PropertyPanel.tsx
To draw the arc of an angular dimension:
The getConvertedAngularDimension() method of DrawingConverter shows the value in degrees, computes the arc radius from dimensionArcPoint, orders the reference points counterclockwise, and samples the arc into a Polyline2d.
Location: shared/src/common/helpers/drawing/DrawingConverter.ts
Hatch patterns other than SOLID and CUSTOM are standard ANSI and ISO patterns.
getHatchDefinitionLines() stores the definition of each predefined pattern as numbers (angle, base point, offset, and dashes) and creates the corresponding HatchDefinitionLine objects.
Location: shared/src/common/helpers/drawing/getHatchDefinitionLines.ts
Notes and caveats:
measurementValue is the value to display. The example shows an angular dimension value in degrees after multiplying it by 180 / Math.PI, so treat angular values as radians. The dimension text carries the text properties of the label.Text.properties.rotation is in degrees, while angles in @mtk/web/geom are in radians. The font size is properties.fontSize.SOLID hatch from the triangulations of its contours. For CUSTOM it draws the definitionLines of the element; for the predefined ANSI and ISO patterns it adds the generated definition lines. It appends them to hatch.definitionLines, which modifies the model; collect them in a separate array instead when a hatch can be converted more than once.scale and angle of a hatch apply to all definition lines. The example rotates each line by hatch.angle + line.angle, both in degrees, multiplies base points, offsets, and dashes by scale, and mirrors the lines for the MIRRORED and DOUBLE styles.Hatch.numberOfContours, contour(), and typeOfContour() are the way to read contours; definition lines and their dashes are in the definitionLines and dashes arrays.ArrowType.CLOSED_FILLED are available through the reverse mapping of numeric enumerations, which formatSemanticEnumValue() in Collect Semantic PMI Values uses. The formatEnumValue() function of the property panel instead finds the enumeration key of a value and converts it to title case.The example applications contain helper classes with names that look like library classes. They are not part of @mtk/web; copy and adapt them if they fit your application. Paths are relative to the root of the examples project.
| Example class or function | Location | Purpose |
|---|---|---|
ModelLoader, createModelDataProvider | shared/src/features/model/import/ | Finds the main .mtkweb file, creates a DataProvider, and calls ModelReader. |
FileSource, LocalFileSource, RemoteFileSource, FileEntry | shared/src/common/file-source/ | Enumerate and read files from a folder, an archive, or a server. |
ModelStructureBuilder, ModelStructure | shared/src/features/model/structure/ | Build the model tree and the Three.js scene graph, including material inheritance. |
ModelDataConverter, convertTransformation | shared/src/common/helpers/ThreeHelper.ts | Convert bodies and transformations to Three.js objects. |
MeshShapeConverter, PMIConverter, DrawingConverter | shared/src/common/helpers/ | Convert mesh shapes, PMI graphics, and drawing elements to Three.js objects. |
MaterialManager, VisualThreeMaterial, convertColor | shared/src/common/materials/ | Cache Three.js materials, carry them in a VisualMaterial, and convert colors. |
getRaycast | shared/src/common/helpers/getRaycast.ts | Raycast a Three.js mesh through a MeshBVH. |
getHatchDefinitionLines, getTextAnchor | shared/src/common/helpers/drawing/ | Definition lines of predefined hatch patterns and text anchors for drawing text justification. |
Viewport, Scene, CameraControls, SceneRaycaster | shared/src/features/viewport/ | Rendering, camera control, and raycasting. |
ModelIntersectionMapper, ModelHighlightManager | shared/src/features/model/interaction/ | Map raycast hits to bodies and B-Rep shapes, and highlight them. |
SectionPlane, SectionPlaneManager | shared/src/features/section-plane/ | Interactive section planes. |
PMIStructureBuilder | shared/src/features/pmi/structure/ | Build the PMI tree and place PMI graphics. |
DrawingStructureBuilder | shared/src/features/drawing/structure/ | Build the drawing tree and its graphics. |
MeasurementManager, Measurement and its subclasses, RadialDimensionsBuilder, CylinderAxisOffsetLimitsBuilder | shared/src/features/measurements/ | Visual measurements built on @mtk/web/measurements and on the exact geometry of faces and edges. |
DesignReviewItem | shared/src/features/design-review/ | Review notes and pins used by the example. |
BaseModelViewer, ModelStructureViewer, SelectionHandlingViewer, PMIExplorerViewer, and other viewers | shared/src/viewers/ | Complete example applications. |
SemanticInformationRowCollector | react/src/pages/pmi-explorer-viewer/semantic-information/ | Table rows for semantic PMI in the React PMI example. |
PropertyPanel | react/src/pages/model-explorer-viewer/ui/property-panel/ | Property table of model and drawing elements in the React model explorer example. |
false result of ModelReader.read() and not a rejected promise, or reading into a model whose content is still needed. See Load an MTKWEB Model.DataProvider that cannot serve the UUID-named companion files or returns a larger buffer than the file. See Load an MTKWEB Model.Model.isEmpty() as "the file is empty" for drawing-only files. See Load an MTKWEB Model.Instance.transformation without checking hasTransformation(), or modifying the returned object. See Navigate the Product Structure.Instance object into two parents. See Navigate the Product Structure.ModelElementUniqueVisitor where per-occurrence transformations are needed. See Traverse the Model and Compute World Transformations.parentWorld.multiplied(local). See Traverse the Model and Compute World Transformations.ShapeIterator, or expecting type-filtered iteration to return unique subshapes. See Explore B-Rep Topology.Face.triangulation.meshShape in full for every face, recomputing the compound triangulation for every occurrence, or reading the typed-array getters in loops. See Get Polygonal Data for Visualization.shapesPrimitives count triangles. See Get Polygonal Data for Visualization.Length and Radius. See Measure Geometry and Compute Validation Properties.-1, NaN, an empty array, or an infinite box). See Measure Geometry and Compute Validation Properties.PlaneSection.compute(). See Compute Plane Sections.SemanticAttributeVisitor through a semantic component's accept(), adding fields to semantic visitor objects, or expecting to read PMI from a face or an edge. See Read PMI and Saved Views.CompositeOutline, placing 2D PMI content without the representation plane, or expecting DatumRefCompartmentAttribute.accept() to visit its nested attributes. See Convert PMI Graphics and Collect Semantic PMI Values.@mtk/web/geom uses radians; or appending generated pattern lines to the definitionLines of a loaded hatch. See Read Dimensions, Hatches, and Text.CurveType and SurfaceType values into one list, or expecting a concrete class for every surface and curve type. See Inspect Surface and Curve Geometry.multiply() or transform(), or constructing a Direction from a zero-length vector. See Work with Transformations, Matrices, and Vectors.0 to 255, or with new Color() without arguments. See Choose Materials and Colors.Box passed to the traversal predicate. See Pick Triangles with a Bounding Volume Hierarchy.id values instead of UUIDs, treating only null as a missing UUID, or calling Model.assignUuids() on a model whose UUIDs are already referenced. See Identify Objects with UUIDs.ModelLoader or ModelDataConverter from @mtk/web. See Example Infrastructure Is Not Library API.