brepjs 18.78.1 → 18.80.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/brepjs.js CHANGED
@@ -15,7 +15,7 @@ import { n as getAtOrThrow, r as lastOrThrow, t as firstOrThrow } from "./arrayA
15
15
  import { _ as makeThreePointArc, d as makeCircle, h as makeLine, l as makeBSplineInterpolation, n as fill, r as makeFace, s as assembleWire } from "./surfaceBuilders-hTXdNCYm.js";
16
16
  import { A as cutAll, C as threePointArc, D as wireLoop, E as wire, F as sectionToFace$1, I as slice$1, L as split$1, M as fuseAll, N as intersect$2, O as booleanPipeline, P as section$1, S as tangentArc, T as vertex, _ as polygon, a as circle, b as sphere$1, c as cylinder, d as ellipsoid, f as face, g as offsetFace, h as line, i as bsplineApprox, j as fuse$2, k as cut$2, l as ellipse, m as helix, n as bezier, o as compound, p as filledFace, r as box, s as cone, t as addHoles, u as ellipseArc, v as sewShells, w as torus$1, x as subFace, y as solid } from "./primitiveFns-BSKbI4Kl.js";
17
17
  import { A as edgesOfFace, C as shellWithEvolution, D as getNurbsCurveData, E as fuseAllBisect, F as chamferDistAngle, I as toBufferGeometryData, L as toGroupedBufferGeometryData, M as sharedEdges, N as verticesOfEdge, O as getNurbsSurfaceData, P as wiresOfFace, R as toLODGeometryData, S as intersectWithEvolution, T as cutAllBisect, _ as positionOnCurve, a as healFace, b as filletWithEvolution, c as isValid$1, d as draft$1, f as fillet$1, g as variableFillet, h as thicken$1, i as heal$1, j as facesOfEdge, k as adjacentFaces, l as solidFromShell, m as shell$1, n as fixSelfIntersection, o as healSolid, p as offset$1, r as fixShape, s as healWire, t as autoHeal, u as chamfer$1, v as chamferWithEvolution, w as checkBoolean, x as fuseWithEvolution, y as cutWithEvolution, z as toLineGeometryData } from "./healingFns-Bm-NdBj_.js";
18
- import { C as updateNode, D as linearPattern, O as exportAssemblySTEP, S as removeChild, T as circularPattern, _ as addChild, a as deserializeHistory, b as createAssemblyNode, c as modifyStep, d as replayFrom, f as replayHistory, g as undoLast, h as stepsFrom, i as createRegistry, k as createAssembly, l as registerOperation, m as stepCount, n as addStep, o as findStep, p as serializeHistory, r as createHistory, s as getShape, t as thread, u as registerShape, v as collectShapes, w as walkAssembly, x as findNode, y as countNodes } from "./threadFns-DGEyXFGP.js";
18
+ import { A as quatRotate, C as prismaticJoint, D as sphericalJoint, E as setJointValues, F as findNode, H as exportAssemblySTEP, I as removeChild, L as updateNode, M as collectShapes, N as countNodes, O as quatFromAxisAngle, P as createAssemblyNode, R as walkAssembly, S as planarJoint, T as setJointValue, U as createAssembly, V as linearPattern, _ as addJoint, a as deserializeHistory, b as jointTransform, c as modifyStep, d as replayFrom, f as replayHistory, g as undoLast, h as stepsFrom, i as createRegistry, j as addChild, k as quatFromTo, l as registerOperation, m as stepCount, n as addStep, o as findStep, p as serializeHistory, r as createHistory, s as getShape, t as thread, u as registerShape, v as cylindricalJoint, w as revoluteJoint, x as mechanismDOF, y as forwardKinematics, z as circularPattern } from "./threadFns-Cra0yHSF.js";
19
19
  import { n as BaseSketcher2d, r as organiseBlueprints, t as BlueprintSketcher } from "./blueprintSketcher-EYqKWQh0.js";
20
20
  import { a as createTypedFinder, i as wireFinder, n as edgeFinder, r as faceFinder, t as getSingleFace } from "./helpers-CD8EMZ5l.js";
21
21
  import { A as sketchEllipse, D as makeBaseBox, E as deserializeDrawing, F as sketchRectangle, I as sketchRoundedRectangle, L as FaceSketcher, M as sketchHelix, N as sketchParametricFunction, O as polysideInnerRadius, P as sketchPolysides, R as Sketcher, S as drawText, _ as drawPolysides, a as drawingIntersect, b as drawSingleCircle, c as rotateDrawing, d as drawFaceOutline, f as drawProjection, g as drawPointsInterpolation, h as drawParametricFunction, i as drawingFuse, j as sketchFaceOffset, k as sketchCircle, l as scaleDrawing, m as drawEllipse, n as drawingCut, o as drawingToSketchOnPlane, p as drawCircle, r as drawingFillet, s as mirrorDrawing, t as drawingChamfer, u as translateDrawing, v as drawRectangle, w as draw, x as drawSingleEllipse, y as drawRoundedRectangle } from "./drawFns-D_LwehLr.js";
@@ -2143,94 +2143,6 @@ function roof(w, options) {
2143
2143
  }
2144
2144
  }
2145
2145
  //#endregion
2146
- //#region src/utils/quaternion.ts
2147
- function dot$1(a, b) {
2148
- return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
2149
- }
2150
- function cross$1(a, b) {
2151
- return [
2152
- a[1] * b[2] - a[2] * b[1],
2153
- a[2] * b[0] - a[0] * b[2],
2154
- a[0] * b[1] - a[1] * b[0]
2155
- ];
2156
- }
2157
- function normalize$1(a) {
2158
- const l = Math.hypot(a[0], a[1], a[2]) || 1;
2159
- return [
2160
- a[0] / l,
2161
- a[1] / l,
2162
- a[2] / l
2163
- ];
2164
- }
2165
- /** A unit vector perpendicular to `v` (for the 180°/parallel degenerate cases). */
2166
- function anyPerpendicular$1(v) {
2167
- return normalize$1(cross$1(v, Math.abs(v[0]) < .9 ? [
2168
- 1,
2169
- 0,
2170
- 0
2171
- ] : [
2172
- 0,
2173
- 1,
2174
- 0
2175
- ]));
2176
- }
2177
- /** Rotate vector `v` by quaternion `q`. */
2178
- function quatRotate(q, v) {
2179
- const [w, x, y, z] = q;
2180
- const tx = 2 * (y * v[2] - z * v[1]);
2181
- const ty = 2 * (z * v[0] - x * v[2]);
2182
- const tz = 2 * (x * v[1] - y * v[0]);
2183
- return [
2184
- v[0] + w * tx + (y * tz - z * ty),
2185
- v[1] + w * ty + (z * tx - x * tz),
2186
- v[2] + w * tz + (x * ty - y * tx)
2187
- ];
2188
- }
2189
- /** Quaternion for a rotation of `angle` radians about (unit-normalized) `axis`. */
2190
- function quatFromAxisAngle(axis, angle) {
2191
- const h = angle / 2;
2192
- const s = Math.sin(h);
2193
- const u = normalize$1(axis);
2194
- return [
2195
- Math.cos(h),
2196
- u[0] * s,
2197
- u[1] * s,
2198
- u[2] * s
2199
- ];
2200
- }
2201
- /** Shortest-arc quaternion rotating unit vector `from` onto unit vector `to`. */
2202
- function quatFromTo(from, to) {
2203
- const a = normalize$1(from);
2204
- const b = normalize$1(to);
2205
- const d = dot$1(a, b);
2206
- if (d >= .999999999) return [
2207
- 1,
2208
- 0,
2209
- 0,
2210
- 0
2211
- ];
2212
- if (d <= -.999999999) return quatFromAxisAngle(anyPerpendicular$1(a), Math.PI);
2213
- const c = cross$1(a, b);
2214
- const len = Math.hypot(1 + d, c[0], c[1], c[2]) || 1;
2215
- return [
2216
- (1 + d) / len,
2217
- c[0] / len,
2218
- c[1] / len,
2219
- c[2] / len
2220
- ];
2221
- }
2222
- /** Hamilton product `a ⊗ b` — the rotation that applies `b` first, then `a`. */
2223
- function quatMultiply(a, b) {
2224
- const [aw, ax, ay, az] = a;
2225
- const [bw, bx, by, bz] = b;
2226
- return [
2227
- aw * bw - ax * bx - ay * by - az * bz,
2228
- aw * bx + ax * bw + ay * bz - az * by,
2229
- aw * by - ax * bz + ay * bw + az * bx,
2230
- aw * bz + ax * by - ay * bx + az * bw
2231
- ];
2232
- }
2233
- //#endregion
2234
2146
  //#region src/kernel/solverAdapter.ts
2235
2147
  /**
2236
2148
  * Constraint solver adapter — analytical solver for simple assembly mates.
@@ -2385,10 +2297,122 @@ function solveAngle(ref, dep, angleRad) {
2385
2297
  rotation: quatFromAxisAngle(Math.hypot(c[0], c[1], c[2]) < 1e-9 ? anyPerpendicular(nDep) : c, phi - angleRad)
2386
2298
  };
2387
2299
  }
2388
- /** Entity types each positioning constraint requires of (entityA, entityB). */
2300
+ /**
2301
+ * Point-point coincident/distance: place the dependent point on the reference
2302
+ * point (`extra` = 0) or at `extra` along the original separation direction.
2303
+ * If the points already coincide the direction is arbitrary (+X).
2304
+ */
2305
+ function solvePointPair(refOrigin, depOrigin, extra) {
2306
+ const sep = sub(depOrigin, refOrigin);
2307
+ const len = Math.hypot(sep[0], sep[1], sep[2]);
2308
+ return {
2309
+ position: sub(add$1(refOrigin, scale$2(len < 1e-9 ? [
2310
+ 1,
2311
+ 0,
2312
+ 0
2313
+ ] : scale$2(sep, 1 / len), extra)), depOrigin),
2314
+ rotation: IDENTITY_ROTATION
2315
+ };
2316
+ }
2317
+ /**
2318
+ * Move the dependent plane (normal `depNormal`, at the origin) so its signed
2319
+ * distance from the reference point equals `extra` (the mirror of `solvePlanePair`
2320
+ * for a point reference and a plane dependent).
2321
+ */
2322
+ function solvePlaneToPoint(depNormal, refOrigin, depOrigin, extra) {
2323
+ const n = normalize(depNormal);
2324
+ return {
2325
+ position: scale$2(n, dot(n, sub(refOrigin, depOrigin)) - extra),
2326
+ rotation: IDENTITY_ROTATION
2327
+ };
2328
+ }
2329
+ /**
2330
+ * Reference axis, dependent point: drop the point onto the axis line
2331
+ * (`extra` = 0) or place it at radial distance `extra` from the line, keeping
2332
+ * its along-axis position. A point already on the axis gets an arbitrary radial.
2333
+ */
2334
+ function solveAxisToPoint(ref, depOrigin, extra) {
2335
+ const d = normalize(ref.direction ?? [
2336
+ 0,
2337
+ 0,
2338
+ 1
2339
+ ]);
2340
+ const foot = add$1(ref.origin, scale$2(d, dot(d, sub(depOrigin, ref.origin))));
2341
+ if (extra === 0) return {
2342
+ position: sub(foot, depOrigin),
2343
+ rotation: IDENTITY_ROTATION
2344
+ };
2345
+ const radial = sub(depOrigin, foot);
2346
+ const rlen = Math.hypot(radial[0], radial[1], radial[2]);
2347
+ return {
2348
+ position: sub(add$1(foot, scale$2(rlen < 1e-9 ? anyPerpendicular(d) : scale$2(radial, 1 / rlen), extra)), depOrigin),
2349
+ rotation: IDENTITY_ROTATION
2350
+ };
2351
+ }
2352
+ /**
2353
+ * Reference point, dependent axis: translate the axis line so it passes through
2354
+ * the point (`extra` = 0) or lies at perpendicular distance `extra` from it.
2355
+ * Translation is purely perpendicular to the axis, so the line's direction and
2356
+ * along-axis parameterization are preserved.
2357
+ */
2358
+ function solvePointToAxis(refOrigin, dep, extra) {
2359
+ const d = normalize(dep.direction ?? [
2360
+ 0,
2361
+ 0,
2362
+ 1
2363
+ ]);
2364
+ const w = sub(dep.origin, refOrigin);
2365
+ const perp = sub(w, scale$2(d, dot(d, w)));
2366
+ const plen = Math.hypot(perp[0], perp[1], perp[2]);
2367
+ if (extra === 0) return {
2368
+ position: scale$2(perp, -1),
2369
+ rotation: IDENTITY_ROTATION
2370
+ };
2371
+ return {
2372
+ position: sub(scale$2(plen < 1e-9 ? anyPerpendicular(d) : scale$2(perp, 1 / plen), extra), perp),
2373
+ rotation: IDENTITY_ROTATION
2374
+ };
2375
+ }
2376
+ /**
2377
+ * Axis-axis distance: align the dependent axis parallel to the reference, then
2378
+ * offset it to perpendicular distance `extra` (parallel pin-and-spacer). With
2379
+ * `extra` = 0 the axes become collinear, matching `concentric`.
2380
+ */
2381
+ function solveAxisAxisDistance(ref, dep, extra) {
2382
+ const dRef = normalize(ref.direction ?? [
2383
+ 0,
2384
+ 0,
2385
+ 1
2386
+ ]);
2387
+ const rotation = quatFromTo(normalize(dep.direction ?? [
2388
+ 0,
2389
+ 0,
2390
+ 1
2391
+ ]), dRef);
2392
+ const w = sub(quatRotate(rotation, dep.origin), ref.origin);
2393
+ const perp = sub(w, scale$2(dRef, dot(dRef, w)));
2394
+ const plen = Math.hypot(perp[0], perp[1], perp[2]);
2395
+ return {
2396
+ position: sub(scale$2(plen < 1e-9 ? anyPerpendicular(dRef) : scale$2(perp, 1 / plen), extra), perp),
2397
+ rotation
2398
+ };
2399
+ }
2400
+ /**
2401
+ * Supported entity-type pairs for the translational mates (`coincident` /
2402
+ * `distance`), keyed `${entityA}-${entityB}`. Both orders are listed where the
2403
+ * solver handles them, so a user need not pre-order the entities.
2404
+ */
2405
+ var TRANSLATIONAL_PAIRS = new Set([
2406
+ "plane-plane",
2407
+ "plane-point",
2408
+ "point-plane",
2409
+ "point-point",
2410
+ "axis-axis",
2411
+ "axis-point",
2412
+ "point-axis"
2413
+ ]);
2414
+ /** Entity types the orientation/axis mates require of (entityA, entityB). */
2389
2415
  var REQUIRED_ENTITIES = {
2390
- coincident: "plane",
2391
- distance: "plane",
2392
2416
  angle: "plane",
2393
2417
  concentric: "axis"
2394
2418
  };
@@ -2398,21 +2422,51 @@ var POSITIONING_TYPES = new Set([
2398
2422
  "angle",
2399
2423
  "concentric"
2400
2424
  ]);
2425
+ /** Whether a positioning mate's entity pair is solvable. */
2426
+ function isSupportedPair(type, a, b) {
2427
+ const required = REQUIRED_ENTITIES[type];
2428
+ if (required) return a === required && b === required;
2429
+ return TRANSLATIONAL_PAIRS.has(`${a}-${b}`);
2430
+ }
2431
+ /**
2432
+ * Solve a `coincident` (extra = 0) or `distance` (extra = value) mate for any
2433
+ * supported entity-type pair. `ref` is already in world space; the dependent is
2434
+ * at the origin. Returns null only for an unsupported pair (filtered out
2435
+ * upstream by `isSupportedPair`).
2436
+ */
2437
+ function solveTranslational(ref, dep, extra) {
2438
+ switch (`${ref.type}-${dep.type}`) {
2439
+ case "plane-plane":
2440
+ case "plane-point": return solvePlanePair(ref, dep, extra);
2441
+ case "point-plane": return solvePlaneToPoint(dep.normal ?? [
2442
+ 0,
2443
+ 0,
2444
+ 1
2445
+ ], ref.origin, dep.origin, extra);
2446
+ case "point-point": return solvePointPair(ref.origin, dep.origin, extra);
2447
+ case "axis-axis": return extra === 0 ? solveConcentric(ref, dep) : solveAxisAxisDistance(ref, dep, extra);
2448
+ case "axis-point": return solveAxisToPoint(ref, dep.origin, extra);
2449
+ case "point-axis": return solvePointToAxis(ref.origin, dep, extra);
2450
+ default: return null;
2451
+ }
2452
+ }
2401
2453
  /** Dispatch a positioning mate to its solver. `ref` is already in world space. */
2402
2454
  function solveMate(c, ref, dep) {
2403
2455
  switch (c.type) {
2404
2456
  case "concentric": return solveConcentric(ref, dep);
2405
2457
  case "angle": return solveAngle(ref, dep, (c.value ?? 0) * Math.PI / 180);
2406
- case "distance": return solvePlanePair(ref, dep, c.value ?? 0);
2407
- default: return solvePlanePair(ref, dep, 0);
2458
+ case "distance": return solveTranslational(ref, dep, c.value ?? 0) ?? solvePlanePair(ref, dep, c.value ?? 0);
2459
+ default: return solveTranslational(ref, dep, 0) ?? solvePlanePair(ref, dep, 0);
2408
2460
  }
2409
2461
  }
2410
2462
  /**
2411
2463
  * Solve assembly constraints analytically.
2412
2464
  *
2413
- * Handles: fixed, coincident/distance (plane-plane), concentric (axis-axis), and
2414
- * angle (plane-plane orientation). For a positioning mate, entityA is the
2415
- * reference and entityB the dependent. Chain roots (nodes never positioned by a
2465
+ * Handles: fixed, concentric (axis-axis), angle (plane-plane orientation), and
2466
+ * coincident/distance for any supported entity-type pair (plane-plane,
2467
+ * plane-point, point-point, axis-axis, axis-point, and both point orders see
2468
+ * `TRANSLATIONAL_PAIRS`). For a positioning mate, entityA is the reference and
2469
+ * entityB the dependent. Chain roots (nodes never positioned by a
2416
2470
  * mate) and explicit `fixed` nodes anchor at the origin; constraints then resolve
2417
2471
  * in topological order — each places its dependent against the reference's solved
2418
2472
  * pose (rotation included), so multi-body chains compose. Returns
@@ -2439,9 +2493,10 @@ function solveConstraints(nodes, constraints) {
2439
2493
  const pending = [];
2440
2494
  for (const c of positioning) {
2441
2495
  if (!c.entityA || !c.entityB) continue;
2442
- const required = REQUIRED_ENTITIES[c.type];
2443
- if (c.entityA.entity.type !== required || c.entityB.entity.type !== required) {
2444
- unsupported.push(`${c.type}(${c.entityA.entity.type}-${c.entityB.entity.type})`);
2496
+ const a = c.entityA.entity.type;
2497
+ const b = c.entityB.entity.type;
2498
+ if (!isSupportedPair(c.type, a, b)) {
2499
+ unsupported.push(`${c.type}(${a}-${b})`);
2445
2500
  continue;
2446
2501
  }
2447
2502
  pending.push(c);
@@ -2630,191 +2685,6 @@ function solveAssembly(assembly) {
2630
2685
  }
2631
2686
  }
2632
2687
  //#endregion
2633
- //#region src/operations/jointFns.ts
2634
- var DEG2RAD$1 = Math.PI / 180;
2635
- function clamp(value, min, max) {
2636
- return Math.min(max, Math.max(min, value));
2637
- }
2638
- function unit(v) {
2639
- const l = Math.hypot(v[0], v[1], v[2]) || 1;
2640
- return [
2641
- v[0] / l,
2642
- v[1] / l,
2643
- v[2] / l
2644
- ];
2645
- }
2646
- function makeJoint(type, parent, child, axis, opts, defMin, defMax) {
2647
- const a = opts.min ?? defMin;
2648
- const b = opts.max ?? defMax;
2649
- const min = Math.min(a, b);
2650
- const max = Math.max(a, b);
2651
- return {
2652
- type,
2653
- parent,
2654
- child,
2655
- axis: {
2656
- origin: axis.origin,
2657
- direction: unit(axis.direction)
2658
- },
2659
- min,
2660
- max,
2661
- value: clamp(opts.value ?? 0, min, max)
2662
- };
2663
- }
2664
- /** A revolute (hinge) joint — the child rotates about `axis` by `value` degrees. */
2665
- function revoluteJoint(parent, child, axis, opts = {}) {
2666
- return makeJoint("revolute", parent, child, axis, opts, -180, 180);
2667
- }
2668
- /**
2669
- * A prismatic (slider) joint — the child translates along `axis` by `value`
2670
- * units. Only `axis.direction` is used; `axis.origin` is ignored (a pure
2671
- * translation has no anchor point), unlike a revolute joint which rotates about
2672
- * the axis line through `origin`.
2673
- */
2674
- function prismaticJoint(parent, child, axis, opts = {}) {
2675
- return makeJoint("prismatic", parent, child, axis, opts, 0, 100);
2676
- }
2677
- /** Return a copy of `joint` with its drivable parameter set (clamped to range). */
2678
- function setJointValue(joint, value) {
2679
- return {
2680
- ...joint,
2681
- value: clamp(value, joint.min, joint.max)
2682
- };
2683
- }
2684
- /**
2685
- * The child's local rigid transform (relative to the parent) for a joint value.
2686
- * Defaults to the joint's stored value; an explicit value is clamped to range.
2687
- *
2688
- * - **revolute**: rotation of `value` degrees about the axis line. Rotating
2689
- * about a line through `origin` is `p ↦ R·p + (origin − R·origin)`.
2690
- * - **prismatic**: translation of `value` units along the axis direction.
2691
- */
2692
- function jointTransform(joint, value = joint.value) {
2693
- const v = clamp(value, joint.min, joint.max);
2694
- const dir = unit(joint.axis.direction);
2695
- if (joint.type === "prismatic") return {
2696
- position: [
2697
- dir[0] * v,
2698
- dir[1] * v,
2699
- dir[2] * v
2700
- ],
2701
- rotation: [
2702
- 1,
2703
- 0,
2704
- 0,
2705
- 0
2706
- ]
2707
- };
2708
- const rotation = quatFromAxisAngle(dir, v * DEG2RAD$1);
2709
- const o = joint.axis.origin;
2710
- const ro = quatRotate(rotation, o);
2711
- return {
2712
- position: [
2713
- o[0] - ro[0],
2714
- o[1] - ro[1],
2715
- o[2] - ro[2]
2716
- ],
2717
- rotation
2718
- };
2719
- }
2720
- /** Attach a joint to an assembly node. Returns a new node (immutable). */
2721
- function addJoint(assembly, joint) {
2722
- const existing = assembly.joints ?? [];
2723
- return {
2724
- ...assembly,
2725
- joints: [...existing, joint]
2726
- };
2727
- }
2728
- var IDENTITY_POSE = {
2729
- position: [
2730
- 0,
2731
- 0,
2732
- 0
2733
- ],
2734
- rotation: [
2735
- 1,
2736
- 0,
2737
- 0,
2738
- 0
2739
- ]
2740
- };
2741
- /** Compose two poses: the result applies `b` in `a`'s frame (`a ∘ b`). */
2742
- function composePose(a, b) {
2743
- const rb = quatRotate(a.rotation, b.position);
2744
- return {
2745
- position: [
2746
- a.position[0] + rb[0],
2747
- a.position[1] + rb[1],
2748
- a.position[2] + rb[2]
2749
- ],
2750
- rotation: quatMultiply(a.rotation, b.rotation)
2751
- };
2752
- }
2753
- /** Collect every joint attached anywhere in the assembly tree. */
2754
- function collectJoints(assembly) {
2755
- const joints = [];
2756
- walkAssembly(assembly, (node) => {
2757
- if (node.joints) joints.push(...node.joints);
2758
- });
2759
- return joints;
2760
- }
2761
- /**
2762
- * Forward kinematics: set joint values and propagate world poses down the
2763
- * kinematic chain. Each joint's axis is interpreted in its **parent's** frame,
2764
- * so a child's world pose is `parentWorld ∘ jointTransform(joint, value)`.
2765
- *
2766
- * Bodies not driven by a joint (chain roots) start at the origin. `jointValues`
2767
- * overrides a joint's stored value, keyed by the **child** node name; omitted
2768
- * joints use `joint.value`. Resolution is topological (reuses the Phase-0
2769
- * ordering), so chains of any depth compose. Returns a world pose for every node.
2770
- */
2771
- function forwardKinematics(assembly, jointValues = {}) {
2772
- const joints = [];
2773
- const names = /* @__PURE__ */ new Set();
2774
- walkAssembly(assembly, (node) => {
2775
- names.add(node.name);
2776
- if (node.joints) joints.push(...node.joints);
2777
- });
2778
- const byChild = /* @__PURE__ */ new Map();
2779
- for (const j of joints) {
2780
- byChild.set(j.child, j);
2781
- names.add(j.parent);
2782
- names.add(j.child);
2783
- }
2784
- const poses = /* @__PURE__ */ new Map();
2785
- for (const name of names) if (!byChild.has(name)) poses.set(name, IDENTITY_POSE);
2786
- const pending = [...joints];
2787
- let progress = true;
2788
- while (progress && pending.length > 0) {
2789
- progress = false;
2790
- for (let i = pending.length - 1; i >= 0; i--) {
2791
- const j = pending[i];
2792
- if (!j) continue;
2793
- const parentPose = poses.get(j.parent);
2794
- if (!parentPose) continue;
2795
- pending.splice(i, 1);
2796
- progress = true;
2797
- if (poses.has(j.child)) continue;
2798
- const value = jointValues[j.child] ?? j.value;
2799
- poses.set(j.child, composePose(parentPose, jointTransform(j, value)));
2800
- }
2801
- }
2802
- for (const j of pending) if (!poses.has(j.child)) poses.set(j.child, IDENTITY_POSE);
2803
- return poses;
2804
- }
2805
- var JOINT_FREEDOM = {
2806
- revolute: 1,
2807
- prismatic: 1
2808
- };
2809
- /**
2810
- * Open-chain mobility — the number of independent degrees of freedom. Each
2811
- * revolute/prismatic joint contributes 1, so for a serial chain this equals the
2812
- * joint count. (Closed-loop Grübler/Kutzbach analysis is future work.)
2813
- */
2814
- function mechanismDOF(assembly) {
2815
- return collectJoints(assembly).reduce((sum, j) => sum + JOINT_FREEDOM[j.type], 0);
2816
- }
2817
- //#endregion
2818
2688
  //#region src/measurement/interferenceFns.ts
2819
2689
  /**
2820
2690
  * Interference detection between shapes.
@@ -6584,4 +6454,4 @@ var csg_exports = /* @__PURE__ */ __exportAll({
6584
6454
  withEvaluator: () => withEvaluator
6585
6455
  });
6586
6456
  //#endregion
6587
- export { BaseSketcher2d, BlueprintSketcher, BrepBugError, BrepErrorCode, BrepWrapperError, BrepkitAdapter, CompoundSketch, DEFAULT_CAPABILITIES, DEG2RAD, DisposalScope, EXACT_BREP_CAPABILITIES, FaceSketcher, HASH_CODE_MAX, OK, OcctWasmAdapter, RAD2DEG, Sketch, Sketcher, Sketches, addChild, addHoles, addJoint, addMate, addStep, adjacentFaces, all, andThen, applyGlue, applyMatrix, approximateCurve, as2D, as3D, asTopo, assignRoles, autoHeal, bezier, blueprintToDXF, booleanPipeline, booleans_exports as booleans, boss, box, bsplineApprox, bug, cameraFromPlane, cameraLookAt, captureHint, cast, castShape, castShape3D, chamfer, chamferDistAngle as chamferDistAngleShape, chamferWithEvolution, checkAllInterferences, checkBoolean, checkInterference, circle, circularPattern, classifyPointOnFace, clearMeshCache, clone, closedWire, collect, collectShapes, colorFaces, colorShape, complexExtrude, composeTransforms, compound, compoundSketchExtrude, compoundSketchFace, compoundSketchLoft, compoundSketchRevolve, computationError, computeStraightSkeleton, cone, construction_exports as construction, convexHull, cornerFinder, countNodes, createAssembly, createAssemblyNode, createBlueprint, createCamera, createCompound, createCompoundBlueprint, createDistanceQuery, createEdge, createFace, createHandle, createHistory, createKernelHandle, createMeshCache, createNamedPlane, createOperationRegistry, createPlane, createRef, createRegistry, createShell, createSolid, createTaskQueue, createVertex, createWire, createWorkerClient, createWorkerHandler, csg_exports as csg, currentQuality, curve2dBoundingBox, curve2dDistanceFrom, curve2dFirstPoint, curve2dIsOnCurve, curve2dLastPoint, curve2dParameter, curve2dSplitAt, curve2dTangentAt, curveAxis, curveEndPoint, curveIsClosed, curveIsPeriodic, curveLength, curvePeriod, curvePointAt, curveStartPoint, curveTangentAt, cut, cut2D, cutAll, cutAllBisect, cutBlueprints, cutWithEvolution, cylinder, defaultScorer, dequeueTask, describe, deserializeDrawing, deserializeHistory, fromBREP as deserializeShape, downcast, draft, draw, drawCircle, drawEllipse, drawFaceOutline, drawParametricFunction, drawPointsInterpolation, drawPolysides, drawProjection, drawRectangle, drawRoundedRectangle, drawSingleCircle, drawSingleEllipse, drawText, drawingChamfer, drawingCut, drawingFillet, drawingFuse, drawingIntersect, drawingToSketchOnPlane, drill, edgeFinder, edgesOfFace, ellipse, ellipseArc, ellipsoid, enqueueTask, err, exportAssemblySTEP, exportDXF, exportGlb, exportGltf, exportIGES, exportOBJ, exportSTEP, exportSTEPConfigured, exportSTL, exportThreeMF, extrude, extrudeAll, face, faceAxis, faceCenter, faceFinder, faceGeomType, faceOrientation, facesOfEdge, fieldBoolean, fieldContour, fieldOffset, fieldReinit, fieldShell, fill, filledFace, fillet, filletWithEvolution, findFacesByTag, findNode, findStep, fixSelfIntersection, fixShape, flatMap, flatten, flipFaceOrientation, flipOrientation, fontMetrics, forwardKinematics, fromBREP$1 as fromBREP, fromKernelDir, fromKernelPnt, fromKernelVec, fromNullable, fuse, fuse2D, fuseAll, fuseAllBisect, fuseBlueprints, fuseWithEvolution, gearGeometry, getActiveVoxelId, getBounds, getBounds2D, getCompSolids, getCurveType, getDisposalStats, getEdges, getFaceColor, getFaceOrigins, getFaceTags, getFaces, getFont, getHashCode, getShape as getHistoryShape, getKernel, getKernelCapabilities, getKernelTier, getNurbsCurveData, getNurbsSurfaceData, getOrientation, getOrientation2D, getPerformanceStats, getShapeColor, getShapeKind, getShells, getSingleFace, getSolids, getSurfaceType, getTagMetadata, getVertices, getVoxel, getWires, guidedSweep, heal, healFace, healSolid, healWire, helix, hull, importDXF, importGLB, importIGES, importOBJ, importSTEP, importSTL, importSVG, importSVGPathD, importThreeMF, init, initFromManifold, initFromOC, initVoxel, innerWires, interpolateCurve, intersect, intersect2D, intersectBlueprints, intersectWithEvolution, invalidateShapeCache, ioNs_exports as io, ioError, is2D, is3D, isChamferRadius, isClosedWire, isCompSolid, isCompound, isDisposeRequest, isEdge, isEmpty, isEqualShape, isErr, isErrorResponse, isFace, isFilletRadius, isInitRequest, isInside2D, isLive, isManifoldShell, isNumber, isOk, isOperationRequest, isOrientedFace, isPlanarFace, isPlanarWire, isProjectionPlane, isEmpty$1 as isQueueEmpty, isSameShape, isShape1D, isShape3D, isShell, isSolid, isSuccessResponse, isValid, isValidSolid, isVertex, isWire, iterCompSolids, iterEdges, iterFaces, iterShells, iterSolids, iterTopo, iterVertices, iterWires, jointTransform, kernelCall, kernelCallRaw, kernelCallScoped, kernelError, latticeInfill, latticeInfillShape, line, linearPattern, loadFont, loft, loftAll, makeBaseBox, makeExternalGear, makeInternalGear, makePlane, makePlanetaryGear, makeProjectedEdges, manifoldShell, map, mapBoth, mapErr, match, measureArea, measureCurvatureAt, measureCurvatureAtMid, measureDistance, measureDistanceProps, measureLength, measureLinearProps, measureSurfaceProps, measureVolume, measureVolumeProps, measurement_exports as measurement, mechanismDOF, mesh, meshEdges, meshMultiLOD, minkowski, mirror, mirror2D, mirrorDrawing, mirrorJoin, modifiers_exports as modifiers, modifyStep, moduleInitError, multiSectionSweep, normalAt, offset, offsetFace, offsetMesh, offsetShape, offsetWire2D, ok, or, orElse, organiseBlueprints, orientedFace, outerWire, patterns_exports as patterns, pendingCount, pipeline, pivotPlane, planarFace, planarWire, planetPlacements, pocket, pointOnSurface, pointsInside, polygon, polyhedron, polysideInnerRadius, polysidesBlueprint, positionOnCurve, prewarm, primitives_exports as primitives, prismaticJoint, projectEdges, projectPointOnFace, query_exports as query, queryError, rectangularPattern, registerHandler, registerKernel, registerKernelTier, registerOperation, registerShape, registerVoxel, rejectAll, removeChild, removeHolesFromFace, repairMesh, replayFrom, replayHistory, resetDisposalStats, resetPerformanceStats, resize, resolve, resolve3D, resolveDirection, resolvePlane, resolveRef, reverseCurve, revoluteJoint, revolve, roof, rotate, rotate2D, rotateDrawing, roundedRectangleBlueprint, scale, scale2D, scaleDrawing, box$1 as sdfBox, capsule as sdfCapsule, cone$1 as sdfCone, cylinder$1 as sdfCylinder, fieldAxialRamp as sdfFieldAxialRamp, fieldClamp as sdfFieldClamp, fieldConst as sdfFieldConst, fieldFromSdf as sdfFieldFromSdf, fieldRadialRamp as sdfFieldRadialRamp, lattice as sdfLattice, plane as sdfPlane, roundedBox as sdfRoundedBox, sphere as sdfSphere, strutLattice as sdfStrutLattice, sweep as sdfSweep, torus as sdfTorus, section, sectionToFace, serializeHistory, setJointValue, setShapeOrigin, setTagMetadata, sewShells, shape, shapeToMeshInput, shapeType, sharedEdges, shell, shellMesh, shellShape, shellWithEvolution, simplify, sketchCircle, sketchEllipse, sketchExtrude, sketchFace, sketchFaceOffset, sketchHelix, sketchLoft, sketchOnFace2D, sketchOnPlane2D, sketchParametricFunction, sketchPolysides, sketchRectangle, sketchRevolve, sketchRoundedRectangle, sketchSweep, sketchText, sketchWires, sketcherStateError, slice, solid, solidFromShell, solveAssembly, sphere$1 as sphere, split, stepCount, stepsFrom, stretch2D, subFace, supportExtrude, supportsConstraintSketch, supportsProjection, surfaceFromGrid, surfaceFromImage, sweep$1 as sweep, tagFaces, tangentArc, tap, tapErr, textBlueprints, textMetrics, thicken, thread, threePointArc, toBREP, toBufferGeometryData, toGroupedBufferGeometryData, toKernelVec, toLODGeometryData, toLineGeometryData, toSVGPathD, toVec2, toVec3, torus$1 as torus, tpmsLattice, transformCopy, transforms_exports as transforms, translate, translate2D, translateDrawing, translatePlane, tryCatch, tryCatchAsync, twistExtrude, typeCastError, undoLast, unsupportedError, unwrap, unwrapErr, unwrapOr, unwrapOrElse, updateNode, updateRoles, uvBounds, uvCoordinates, validSolid, validatePlanetary, validationError, variableFillet, vecAdd, vecAngle, vecCross, vecDistance, vecDot, vecEquals, vecIsZero, vecLength, vecLengthSq, vecNegate, vecNormalize, vecProjectToPlane, vecRepr, vecRotate, vecScale, vecSub, vertex, vertexFinder, vertexPosition, verticesOfEdge, voxelBoolean, voxelBooleanField, voxelBooleanFieldShapes, voxelBooleanShapes, voxelField, voxelFieldFromShape, walkAssembly, windingNumbers, wire, wireFinder, wireLoop, wiresOfFace, withKernel, withKernelDir, withKernelPnt, withKernelVec, withQuality, withScope, withScopeResult, withScopeResultAsync, withTier, zip as zipResults };
6457
+ export { BaseSketcher2d, BlueprintSketcher, BrepBugError, BrepErrorCode, BrepWrapperError, BrepkitAdapter, CompoundSketch, DEFAULT_CAPABILITIES, DEG2RAD, DisposalScope, EXACT_BREP_CAPABILITIES, FaceSketcher, HASH_CODE_MAX, OK, OcctWasmAdapter, RAD2DEG, Sketch, Sketcher, Sketches, addChild, addHoles, addJoint, addMate, addStep, adjacentFaces, all, andThen, applyGlue, applyMatrix, approximateCurve, as2D, as3D, asTopo, assignRoles, autoHeal, bezier, blueprintToDXF, booleanPipeline, booleans_exports as booleans, boss, box, bsplineApprox, bug, cameraFromPlane, cameraLookAt, captureHint, cast, castShape, castShape3D, chamfer, chamferDistAngle as chamferDistAngleShape, chamferWithEvolution, checkAllInterferences, checkBoolean, checkInterference, circle, circularPattern, classifyPointOnFace, clearMeshCache, clone, closedWire, collect, collectShapes, colorFaces, colorShape, complexExtrude, composeTransforms, compound, compoundSketchExtrude, compoundSketchFace, compoundSketchLoft, compoundSketchRevolve, computationError, computeStraightSkeleton, cone, construction_exports as construction, convexHull, cornerFinder, countNodes, createAssembly, createAssemblyNode, createBlueprint, createCamera, createCompound, createCompoundBlueprint, createDistanceQuery, createEdge, createFace, createHandle, createHistory, createKernelHandle, createMeshCache, createNamedPlane, createOperationRegistry, createPlane, createRef, createRegistry, createShell, createSolid, createTaskQueue, createVertex, createWire, createWorkerClient, createWorkerHandler, csg_exports as csg, currentQuality, curve2dBoundingBox, curve2dDistanceFrom, curve2dFirstPoint, curve2dIsOnCurve, curve2dLastPoint, curve2dParameter, curve2dSplitAt, curve2dTangentAt, curveAxis, curveEndPoint, curveIsClosed, curveIsPeriodic, curveLength, curvePeriod, curvePointAt, curveStartPoint, curveTangentAt, cut, cut2D, cutAll, cutAllBisect, cutBlueprints, cutWithEvolution, cylinder, cylindricalJoint, defaultScorer, dequeueTask, describe, deserializeDrawing, deserializeHistory, fromBREP as deserializeShape, downcast, draft, draw, drawCircle, drawEllipse, drawFaceOutline, drawParametricFunction, drawPointsInterpolation, drawPolysides, drawProjection, drawRectangle, drawRoundedRectangle, drawSingleCircle, drawSingleEllipse, drawText, drawingChamfer, drawingCut, drawingFillet, drawingFuse, drawingIntersect, drawingToSketchOnPlane, drill, edgeFinder, edgesOfFace, ellipse, ellipseArc, ellipsoid, enqueueTask, err, exportAssemblySTEP, exportDXF, exportGlb, exportGltf, exportIGES, exportOBJ, exportSTEP, exportSTEPConfigured, exportSTL, exportThreeMF, extrude, extrudeAll, face, faceAxis, faceCenter, faceFinder, faceGeomType, faceOrientation, facesOfEdge, fieldBoolean, fieldContour, fieldOffset, fieldReinit, fieldShell, fill, filledFace, fillet, filletWithEvolution, findFacesByTag, findNode, findStep, fixSelfIntersection, fixShape, flatMap, flatten, flipFaceOrientation, flipOrientation, fontMetrics, forwardKinematics, fromBREP$1 as fromBREP, fromKernelDir, fromKernelPnt, fromKernelVec, fromNullable, fuse, fuse2D, fuseAll, fuseAllBisect, fuseBlueprints, fuseWithEvolution, gearGeometry, getActiveVoxelId, getBounds, getBounds2D, getCompSolids, getCurveType, getDisposalStats, getEdges, getFaceColor, getFaceOrigins, getFaceTags, getFaces, getFont, getHashCode, getShape as getHistoryShape, getKernel, getKernelCapabilities, getKernelTier, getNurbsCurveData, getNurbsSurfaceData, getOrientation, getOrientation2D, getPerformanceStats, getShapeColor, getShapeKind, getShells, getSingleFace, getSolids, getSurfaceType, getTagMetadata, getVertices, getVoxel, getWires, guidedSweep, heal, healFace, healSolid, healWire, helix, hull, importDXF, importGLB, importIGES, importOBJ, importSTEP, importSTL, importSVG, importSVGPathD, importThreeMF, init, initFromManifold, initFromOC, initVoxel, innerWires, interpolateCurve, intersect, intersect2D, intersectBlueprints, intersectWithEvolution, invalidateShapeCache, ioNs_exports as io, ioError, is2D, is3D, isChamferRadius, isClosedWire, isCompSolid, isCompound, isDisposeRequest, isEdge, isEmpty, isEqualShape, isErr, isErrorResponse, isFace, isFilletRadius, isInitRequest, isInside2D, isLive, isManifoldShell, isNumber, isOk, isOperationRequest, isOrientedFace, isPlanarFace, isPlanarWire, isProjectionPlane, isEmpty$1 as isQueueEmpty, isSameShape, isShape1D, isShape3D, isShell, isSolid, isSuccessResponse, isValid, isValidSolid, isVertex, isWire, iterCompSolids, iterEdges, iterFaces, iterShells, iterSolids, iterTopo, iterVertices, iterWires, jointTransform, kernelCall, kernelCallRaw, kernelCallScoped, kernelError, latticeInfill, latticeInfillShape, line, linearPattern, loadFont, loft, loftAll, makeBaseBox, makeExternalGear, makeInternalGear, makePlane, makePlanetaryGear, makeProjectedEdges, manifoldShell, map, mapBoth, mapErr, match, measureArea, measureCurvatureAt, measureCurvatureAtMid, measureDistance, measureDistanceProps, measureLength, measureLinearProps, measureSurfaceProps, measureVolume, measureVolumeProps, measurement_exports as measurement, mechanismDOF, mesh, meshEdges, meshMultiLOD, minkowski, mirror, mirror2D, mirrorDrawing, mirrorJoin, modifiers_exports as modifiers, modifyStep, moduleInitError, multiSectionSweep, normalAt, offset, offsetFace, offsetMesh, offsetShape, offsetWire2D, ok, or, orElse, organiseBlueprints, orientedFace, outerWire, patterns_exports as patterns, pendingCount, pipeline, pivotPlane, planarFace, planarJoint, planarWire, planetPlacements, pocket, pointOnSurface, pointsInside, polygon, polyhedron, polysideInnerRadius, polysidesBlueprint, positionOnCurve, prewarm, primitives_exports as primitives, prismaticJoint, projectEdges, projectPointOnFace, query_exports as query, queryError, rectangularPattern, registerHandler, registerKernel, registerKernelTier, registerOperation, registerShape, registerVoxel, rejectAll, removeChild, removeHolesFromFace, repairMesh, replayFrom, replayHistory, resetDisposalStats, resetPerformanceStats, resize, resolve, resolve3D, resolveDirection, resolvePlane, resolveRef, reverseCurve, revoluteJoint, revolve, roof, rotate, rotate2D, rotateDrawing, roundedRectangleBlueprint, scale, scale2D, scaleDrawing, box$1 as sdfBox, capsule as sdfCapsule, cone$1 as sdfCone, cylinder$1 as sdfCylinder, fieldAxialRamp as sdfFieldAxialRamp, fieldClamp as sdfFieldClamp, fieldConst as sdfFieldConst, fieldFromSdf as sdfFieldFromSdf, fieldRadialRamp as sdfFieldRadialRamp, lattice as sdfLattice, plane as sdfPlane, roundedBox as sdfRoundedBox, sphere as sdfSphere, strutLattice as sdfStrutLattice, sweep as sdfSweep, torus as sdfTorus, section, sectionToFace, serializeHistory, setJointValue, setJointValues, setShapeOrigin, setTagMetadata, sewShells, shape, shapeToMeshInput, shapeType, sharedEdges, shell, shellMesh, shellShape, shellWithEvolution, simplify, sketchCircle, sketchEllipse, sketchExtrude, sketchFace, sketchFaceOffset, sketchHelix, sketchLoft, sketchOnFace2D, sketchOnPlane2D, sketchParametricFunction, sketchPolysides, sketchRectangle, sketchRevolve, sketchRoundedRectangle, sketchSweep, sketchText, sketchWires, sketcherStateError, slice, solid, solidFromShell, solveAssembly, sphere$1 as sphere, sphericalJoint, split, stepCount, stepsFrom, stretch2D, subFace, supportExtrude, supportsConstraintSketch, supportsProjection, surfaceFromGrid, surfaceFromImage, sweep$1 as sweep, tagFaces, tangentArc, tap, tapErr, textBlueprints, textMetrics, thicken, thread, threePointArc, toBREP, toBufferGeometryData, toGroupedBufferGeometryData, toKernelVec, toLODGeometryData, toLineGeometryData, toSVGPathD, toVec2, toVec3, torus$1 as torus, tpmsLattice, transformCopy, transforms_exports as transforms, translate, translate2D, translateDrawing, translatePlane, tryCatch, tryCatchAsync, twistExtrude, typeCastError, undoLast, unsupportedError, unwrap, unwrapErr, unwrapOr, unwrapOrElse, updateNode, updateRoles, uvBounds, uvCoordinates, validSolid, validatePlanetary, validationError, variableFillet, vecAdd, vecAngle, vecCross, vecDistance, vecDot, vecEquals, vecIsZero, vecLength, vecLengthSq, vecNegate, vecNormalize, vecProjectToPlane, vecRepr, vecRotate, vecScale, vecSub, vertex, vertexFinder, vertexPosition, verticesOfEdge, voxelBoolean, voxelBooleanField, voxelBooleanFieldShapes, voxelBooleanShapes, voxelField, voxelFieldFromShape, walkAssembly, windingNumbers, wire, wireFinder, wireLoop, wiresOfFace, withKernel, withKernelDir, withKernelPnt, withKernelVec, withQuality, withScope, withScopeResult, withScopeResultAsync, withTier, zip as zipResults };
package/dist/index.d.ts CHANGED
@@ -121,7 +121,7 @@ export { exportAssemblySTEP, type ShapeOptions, type SupportedUnit, } from './op
121
121
  export { linearPattern, circularPattern } from './operations/patternFns.js';
122
122
  export { createAssemblyNode, addChild, removeChild, updateNode, findNode, walkAssembly, countNodes, collectShapes, type AssemblyNode, type AssemblyNodeOptions, } from './operations/assemblyFns.js';
123
123
  export { addMate, solveAssembly, type MateConstraint, type MateEntity, type AssemblySolveResult, } from './operations/mateFns.js';
124
- export { revoluteJoint, prismaticJoint, setJointValue, jointTransform, addJoint, forwardKinematics, mechanismDOF, type Joint, type JointAxis, type JointType, type JointPose, type JointOptions, } from './operations/jointFns.js';
124
+ export { revoluteJoint, prismaticJoint, cylindricalJoint, planarJoint, sphericalJoint, setJointValue, setJointValues, jointTransform, addJoint, forwardKinematics, mechanismDOF, type Joint, type JointDOF, type JointAxis, type JointType, type JointPose, type JointOptions, type CylindricalOptions, type PlanarOptions, type SphericalOptions, } from './operations/jointFns.js';
125
125
  export { createHistory, addStep, undoLast, findStep, getShape as getHistoryShape, stepCount, stepsFrom, registerShape, createRegistry, registerOperation, replayHistory, replayFrom, modifyStep, serializeHistory, deserializeHistory, type OperationStep, type ModelHistory, type SerializedHistory, type OperationFn, type OperationRegistry as HistoryOperationRegistry, } from './operations/historyFns.js';
126
126
  export { measureVolume, measureArea, measureLength, measureDistance, measureDistanceProps, createDistanceQuery, measureVolumeProps, measureSurfaceProps, measureLinearProps, type PhysicalProps, type VolumeProps, type SurfaceProps, type LinearProps, type DistanceProps, measureCurvatureAt, measureCurvatureAtMid, type CurvatureResult, } from './measurement/measureFns.js';
127
127
  export { checkInterference, checkAllInterferences, type InterferenceResult, type InterferencePair, } from './measurement/interferenceFns.js';
@@ -34,9 +34,11 @@ export interface SolverResult {
34
34
  /**
35
35
  * Solve assembly constraints analytically.
36
36
  *
37
- * Handles: fixed, coincident/distance (plane-plane), concentric (axis-axis), and
38
- * angle (plane-plane orientation). For a positioning mate, entityA is the
39
- * reference and entityB the dependent. Chain roots (nodes never positioned by a
37
+ * Handles: fixed, concentric (axis-axis), angle (plane-plane orientation), and
38
+ * coincident/distance for any supported entity-type pair (plane-plane,
39
+ * plane-point, point-point, axis-axis, axis-point, and both point orders see
40
+ * `TRANSLATIONAL_PAIRS`). For a positioning mate, entityA is the reference and
41
+ * entityB the dependent. Chain roots (nodes never positioned by a
40
42
  * mate) and explicit `fixed` nodes anchor at the origin; constraints then resolve
41
43
  * in topological order — each places its dependent against the reference's solved
42
44
  * pose (rotation included), so multi-body chains compose. Returns