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.cjs +172 -298
- package/dist/brepjs.js +156 -286
- package/dist/index.d.ts +1 -1
- package/dist/kernel/solverAdapter.d.ts +5 -3
- package/dist/operations/jointFns.d.ts +88 -14
- package/dist/operations.cjs +12 -1
- package/dist/operations.d.ts +1 -0
- package/dist/operations.js +2 -2
- package/dist/{threadFns-a_C2wGGt.cjs → threadFns-B7a1EVpS.cjs} +498 -0
- package/dist/{threadFns-DGEyXFGP.js → threadFns-Cra0yHSF.js} +415 -1
- package/package.json +1 -1
package/dist/brepjs.cjs
CHANGED
|
@@ -17,7 +17,7 @@ const require_arrayAccess = require("./arrayAccess-e4H9cBfh.cjs");
|
|
|
17
17
|
const require_surfaceBuilders = require("./surfaceBuilders-B8aVZamB.cjs");
|
|
18
18
|
const require_primitiveFns = require("./primitiveFns-DEBQdEkG.cjs");
|
|
19
19
|
const require_healingFns = require("./healingFns--PtL9j2K.cjs");
|
|
20
|
-
const require_threadFns = require("./threadFns-
|
|
20
|
+
const require_threadFns = require("./threadFns-B7a1EVpS.cjs");
|
|
21
21
|
const require_blueprintSketcher = require("./blueprintSketcher-BJPBKhF3.cjs");
|
|
22
22
|
const require_helpers = require("./helpers-B8mE35Fm.cjs");
|
|
23
23
|
const require_drawFns = require("./drawFns-DTpCthM5.cjs");
|
|
@@ -2132,94 +2132,6 @@ function roof(w, options) {
|
|
|
2132
2132
|
}
|
|
2133
2133
|
}
|
|
2134
2134
|
//#endregion
|
|
2135
|
-
//#region src/utils/quaternion.ts
|
|
2136
|
-
function dot$1(a, b) {
|
|
2137
|
-
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
|
|
2138
|
-
}
|
|
2139
|
-
function cross$1(a, b) {
|
|
2140
|
-
return [
|
|
2141
|
-
a[1] * b[2] - a[2] * b[1],
|
|
2142
|
-
a[2] * b[0] - a[0] * b[2],
|
|
2143
|
-
a[0] * b[1] - a[1] * b[0]
|
|
2144
|
-
];
|
|
2145
|
-
}
|
|
2146
|
-
function normalize$1(a) {
|
|
2147
|
-
const l = Math.hypot(a[0], a[1], a[2]) || 1;
|
|
2148
|
-
return [
|
|
2149
|
-
a[0] / l,
|
|
2150
|
-
a[1] / l,
|
|
2151
|
-
a[2] / l
|
|
2152
|
-
];
|
|
2153
|
-
}
|
|
2154
|
-
/** A unit vector perpendicular to `v` (for the 180°/parallel degenerate cases). */
|
|
2155
|
-
function anyPerpendicular$1(v) {
|
|
2156
|
-
return normalize$1(cross$1(v, Math.abs(v[0]) < .9 ? [
|
|
2157
|
-
1,
|
|
2158
|
-
0,
|
|
2159
|
-
0
|
|
2160
|
-
] : [
|
|
2161
|
-
0,
|
|
2162
|
-
1,
|
|
2163
|
-
0
|
|
2164
|
-
]));
|
|
2165
|
-
}
|
|
2166
|
-
/** Rotate vector `v` by quaternion `q`. */
|
|
2167
|
-
function quatRotate(q, v) {
|
|
2168
|
-
const [w, x, y, z] = q;
|
|
2169
|
-
const tx = 2 * (y * v[2] - z * v[1]);
|
|
2170
|
-
const ty = 2 * (z * v[0] - x * v[2]);
|
|
2171
|
-
const tz = 2 * (x * v[1] - y * v[0]);
|
|
2172
|
-
return [
|
|
2173
|
-
v[0] + w * tx + (y * tz - z * ty),
|
|
2174
|
-
v[1] + w * ty + (z * tx - x * tz),
|
|
2175
|
-
v[2] + w * tz + (x * ty - y * tx)
|
|
2176
|
-
];
|
|
2177
|
-
}
|
|
2178
|
-
/** Quaternion for a rotation of `angle` radians about (unit-normalized) `axis`. */
|
|
2179
|
-
function quatFromAxisAngle(axis, angle) {
|
|
2180
|
-
const h = angle / 2;
|
|
2181
|
-
const s = Math.sin(h);
|
|
2182
|
-
const u = normalize$1(axis);
|
|
2183
|
-
return [
|
|
2184
|
-
Math.cos(h),
|
|
2185
|
-
u[0] * s,
|
|
2186
|
-
u[1] * s,
|
|
2187
|
-
u[2] * s
|
|
2188
|
-
];
|
|
2189
|
-
}
|
|
2190
|
-
/** Shortest-arc quaternion rotating unit vector `from` onto unit vector `to`. */
|
|
2191
|
-
function quatFromTo(from, to) {
|
|
2192
|
-
const a = normalize$1(from);
|
|
2193
|
-
const b = normalize$1(to);
|
|
2194
|
-
const d = dot$1(a, b);
|
|
2195
|
-
if (d >= .999999999) return [
|
|
2196
|
-
1,
|
|
2197
|
-
0,
|
|
2198
|
-
0,
|
|
2199
|
-
0
|
|
2200
|
-
];
|
|
2201
|
-
if (d <= -.999999999) return quatFromAxisAngle(anyPerpendicular$1(a), Math.PI);
|
|
2202
|
-
const c = cross$1(a, b);
|
|
2203
|
-
const len = Math.hypot(1 + d, c[0], c[1], c[2]) || 1;
|
|
2204
|
-
return [
|
|
2205
|
-
(1 + d) / len,
|
|
2206
|
-
c[0] / len,
|
|
2207
|
-
c[1] / len,
|
|
2208
|
-
c[2] / len
|
|
2209
|
-
];
|
|
2210
|
-
}
|
|
2211
|
-
/** Hamilton product `a ⊗ b` — the rotation that applies `b` first, then `a`. */
|
|
2212
|
-
function quatMultiply(a, b) {
|
|
2213
|
-
const [aw, ax, ay, az] = a;
|
|
2214
|
-
const [bw, bx, by, bz] = b;
|
|
2215
|
-
return [
|
|
2216
|
-
aw * bw - ax * bx - ay * by - az * bz,
|
|
2217
|
-
aw * bx + ax * bw + ay * bz - az * by,
|
|
2218
|
-
aw * by - ax * bz + ay * bw + az * bx,
|
|
2219
|
-
aw * bz + ax * by - ay * bx + az * bw
|
|
2220
|
-
];
|
|
2221
|
-
}
|
|
2222
|
-
//#endregion
|
|
2223
2135
|
//#region src/kernel/solverAdapter.ts
|
|
2224
2136
|
/**
|
|
2225
2137
|
* Constraint solver adapter — analytical solver for simple assembly mates.
|
|
@@ -2297,12 +2209,12 @@ function anyPerpendicular(v) {
|
|
|
2297
2209
|
}
|
|
2298
2210
|
/** Apply a pose (rotate then translate) to an entity's origin and any directions. */
|
|
2299
2211
|
function transformEntity(e, pose) {
|
|
2300
|
-
const origin = add$1(quatRotate(pose.rotation, e.origin), pose.position);
|
|
2212
|
+
const origin = add$1(require_threadFns.quatRotate(pose.rotation, e.origin), pose.position);
|
|
2301
2213
|
return {
|
|
2302
2214
|
type: e.type,
|
|
2303
2215
|
origin,
|
|
2304
|
-
...e.normal ? { normal: quatRotate(pose.rotation, e.normal) } : {},
|
|
2305
|
-
...e.direction ? { direction: quatRotate(pose.rotation, e.direction) } : {}
|
|
2216
|
+
...e.normal ? { normal: require_threadFns.quatRotate(pose.rotation, e.normal) } : {},
|
|
2217
|
+
...e.direction ? { direction: require_threadFns.quatRotate(pose.rotation, e.direction) } : {}
|
|
2306
2218
|
};
|
|
2307
2219
|
}
|
|
2308
2220
|
/**
|
|
@@ -2336,12 +2248,12 @@ function solveConcentric(ref, dep) {
|
|
|
2336
2248
|
0,
|
|
2337
2249
|
1
|
|
2338
2250
|
];
|
|
2339
|
-
const rotation = quatFromTo(dep.direction ?? [
|
|
2251
|
+
const rotation = require_threadFns.quatFromTo(dep.direction ?? [
|
|
2340
2252
|
0,
|
|
2341
2253
|
0,
|
|
2342
2254
|
1
|
|
2343
2255
|
], dRef);
|
|
2344
|
-
const rotatedOrigin = quatRotate(rotation, dep.origin);
|
|
2256
|
+
const rotatedOrigin = require_threadFns.quatRotate(rotation, dep.origin);
|
|
2345
2257
|
return {
|
|
2346
2258
|
position: sub(ref.origin, rotatedOrigin),
|
|
2347
2259
|
rotation
|
|
@@ -2371,13 +2283,125 @@ function solveAngle(ref, dep, angleRad) {
|
|
|
2371
2283
|
0,
|
|
2372
2284
|
0
|
|
2373
2285
|
],
|
|
2374
|
-
rotation: quatFromAxisAngle(Math.hypot(c[0], c[1], c[2]) < 1e-9 ? anyPerpendicular(nDep) : c, phi - angleRad)
|
|
2286
|
+
rotation: require_threadFns.quatFromAxisAngle(Math.hypot(c[0], c[1], c[2]) < 1e-9 ? anyPerpendicular(nDep) : c, phi - angleRad)
|
|
2287
|
+
};
|
|
2288
|
+
}
|
|
2289
|
+
/**
|
|
2290
|
+
* Point-point coincident/distance: place the dependent point on the reference
|
|
2291
|
+
* point (`extra` = 0) or at `extra` along the original separation direction.
|
|
2292
|
+
* If the points already coincide the direction is arbitrary (+X).
|
|
2293
|
+
*/
|
|
2294
|
+
function solvePointPair(refOrigin, depOrigin, extra) {
|
|
2295
|
+
const sep = sub(depOrigin, refOrigin);
|
|
2296
|
+
const len = Math.hypot(sep[0], sep[1], sep[2]);
|
|
2297
|
+
return {
|
|
2298
|
+
position: sub(add$1(refOrigin, scale$2(len < 1e-9 ? [
|
|
2299
|
+
1,
|
|
2300
|
+
0,
|
|
2301
|
+
0
|
|
2302
|
+
] : scale$2(sep, 1 / len), extra)), depOrigin),
|
|
2303
|
+
rotation: IDENTITY_ROTATION
|
|
2304
|
+
};
|
|
2305
|
+
}
|
|
2306
|
+
/**
|
|
2307
|
+
* Move the dependent plane (normal `depNormal`, at the origin) so its signed
|
|
2308
|
+
* distance from the reference point equals `extra` (the mirror of `solvePlanePair`
|
|
2309
|
+
* for a point reference and a plane dependent).
|
|
2310
|
+
*/
|
|
2311
|
+
function solvePlaneToPoint(depNormal, refOrigin, depOrigin, extra) {
|
|
2312
|
+
const n = normalize(depNormal);
|
|
2313
|
+
return {
|
|
2314
|
+
position: scale$2(n, dot(n, sub(refOrigin, depOrigin)) - extra),
|
|
2315
|
+
rotation: IDENTITY_ROTATION
|
|
2316
|
+
};
|
|
2317
|
+
}
|
|
2318
|
+
/**
|
|
2319
|
+
* Reference axis, dependent point: drop the point onto the axis line
|
|
2320
|
+
* (`extra` = 0) or place it at radial distance `extra` from the line, keeping
|
|
2321
|
+
* its along-axis position. A point already on the axis gets an arbitrary radial.
|
|
2322
|
+
*/
|
|
2323
|
+
function solveAxisToPoint(ref, depOrigin, extra) {
|
|
2324
|
+
const d = normalize(ref.direction ?? [
|
|
2325
|
+
0,
|
|
2326
|
+
0,
|
|
2327
|
+
1
|
|
2328
|
+
]);
|
|
2329
|
+
const foot = add$1(ref.origin, scale$2(d, dot(d, sub(depOrigin, ref.origin))));
|
|
2330
|
+
if (extra === 0) return {
|
|
2331
|
+
position: sub(foot, depOrigin),
|
|
2332
|
+
rotation: IDENTITY_ROTATION
|
|
2333
|
+
};
|
|
2334
|
+
const radial = sub(depOrigin, foot);
|
|
2335
|
+
const rlen = Math.hypot(radial[0], radial[1], radial[2]);
|
|
2336
|
+
return {
|
|
2337
|
+
position: sub(add$1(foot, scale$2(rlen < 1e-9 ? anyPerpendicular(d) : scale$2(radial, 1 / rlen), extra)), depOrigin),
|
|
2338
|
+
rotation: IDENTITY_ROTATION
|
|
2339
|
+
};
|
|
2340
|
+
}
|
|
2341
|
+
/**
|
|
2342
|
+
* Reference point, dependent axis: translate the axis line so it passes through
|
|
2343
|
+
* the point (`extra` = 0) or lies at perpendicular distance `extra` from it.
|
|
2344
|
+
* Translation is purely perpendicular to the axis, so the line's direction and
|
|
2345
|
+
* along-axis parameterization are preserved.
|
|
2346
|
+
*/
|
|
2347
|
+
function solvePointToAxis(refOrigin, dep, extra) {
|
|
2348
|
+
const d = normalize(dep.direction ?? [
|
|
2349
|
+
0,
|
|
2350
|
+
0,
|
|
2351
|
+
1
|
|
2352
|
+
]);
|
|
2353
|
+
const w = sub(dep.origin, refOrigin);
|
|
2354
|
+
const perp = sub(w, scale$2(d, dot(d, w)));
|
|
2355
|
+
const plen = Math.hypot(perp[0], perp[1], perp[2]);
|
|
2356
|
+
if (extra === 0) return {
|
|
2357
|
+
position: scale$2(perp, -1),
|
|
2358
|
+
rotation: IDENTITY_ROTATION
|
|
2359
|
+
};
|
|
2360
|
+
return {
|
|
2361
|
+
position: sub(scale$2(plen < 1e-9 ? anyPerpendicular(d) : scale$2(perp, 1 / plen), extra), perp),
|
|
2362
|
+
rotation: IDENTITY_ROTATION
|
|
2363
|
+
};
|
|
2364
|
+
}
|
|
2365
|
+
/**
|
|
2366
|
+
* Axis-axis distance: align the dependent axis parallel to the reference, then
|
|
2367
|
+
* offset it to perpendicular distance `extra` (parallel pin-and-spacer). With
|
|
2368
|
+
* `extra` = 0 the axes become collinear, matching `concentric`.
|
|
2369
|
+
*/
|
|
2370
|
+
function solveAxisAxisDistance(ref, dep, extra) {
|
|
2371
|
+
const dRef = normalize(ref.direction ?? [
|
|
2372
|
+
0,
|
|
2373
|
+
0,
|
|
2374
|
+
1
|
|
2375
|
+
]);
|
|
2376
|
+
const rotation = require_threadFns.quatFromTo(normalize(dep.direction ?? [
|
|
2377
|
+
0,
|
|
2378
|
+
0,
|
|
2379
|
+
1
|
|
2380
|
+
]), dRef);
|
|
2381
|
+
const w = sub(require_threadFns.quatRotate(rotation, dep.origin), ref.origin);
|
|
2382
|
+
const perp = sub(w, scale$2(dRef, dot(dRef, w)));
|
|
2383
|
+
const plen = Math.hypot(perp[0], perp[1], perp[2]);
|
|
2384
|
+
return {
|
|
2385
|
+
position: sub(scale$2(plen < 1e-9 ? anyPerpendicular(dRef) : scale$2(perp, 1 / plen), extra), perp),
|
|
2386
|
+
rotation
|
|
2375
2387
|
};
|
|
2376
2388
|
}
|
|
2377
|
-
/**
|
|
2389
|
+
/**
|
|
2390
|
+
* Supported entity-type pairs for the translational mates (`coincident` /
|
|
2391
|
+
* `distance`), keyed `${entityA}-${entityB}`. Both orders are listed where the
|
|
2392
|
+
* solver handles them, so a user need not pre-order the entities.
|
|
2393
|
+
*/
|
|
2394
|
+
var TRANSLATIONAL_PAIRS = new Set([
|
|
2395
|
+
"plane-plane",
|
|
2396
|
+
"plane-point",
|
|
2397
|
+
"point-plane",
|
|
2398
|
+
"point-point",
|
|
2399
|
+
"axis-axis",
|
|
2400
|
+
"axis-point",
|
|
2401
|
+
"point-axis"
|
|
2402
|
+
]);
|
|
2403
|
+
/** Entity types the orientation/axis mates require of (entityA, entityB). */
|
|
2378
2404
|
var REQUIRED_ENTITIES = {
|
|
2379
|
-
coincident: "plane",
|
|
2380
|
-
distance: "plane",
|
|
2381
2405
|
angle: "plane",
|
|
2382
2406
|
concentric: "axis"
|
|
2383
2407
|
};
|
|
@@ -2387,21 +2411,51 @@ var POSITIONING_TYPES = new Set([
|
|
|
2387
2411
|
"angle",
|
|
2388
2412
|
"concentric"
|
|
2389
2413
|
]);
|
|
2414
|
+
/** Whether a positioning mate's entity pair is solvable. */
|
|
2415
|
+
function isSupportedPair(type, a, b) {
|
|
2416
|
+
const required = REQUIRED_ENTITIES[type];
|
|
2417
|
+
if (required) return a === required && b === required;
|
|
2418
|
+
return TRANSLATIONAL_PAIRS.has(`${a}-${b}`);
|
|
2419
|
+
}
|
|
2420
|
+
/**
|
|
2421
|
+
* Solve a `coincident` (extra = 0) or `distance` (extra = value) mate for any
|
|
2422
|
+
* supported entity-type pair. `ref` is already in world space; the dependent is
|
|
2423
|
+
* at the origin. Returns null only for an unsupported pair (filtered out
|
|
2424
|
+
* upstream by `isSupportedPair`).
|
|
2425
|
+
*/
|
|
2426
|
+
function solveTranslational(ref, dep, extra) {
|
|
2427
|
+
switch (`${ref.type}-${dep.type}`) {
|
|
2428
|
+
case "plane-plane":
|
|
2429
|
+
case "plane-point": return solvePlanePair(ref, dep, extra);
|
|
2430
|
+
case "point-plane": return solvePlaneToPoint(dep.normal ?? [
|
|
2431
|
+
0,
|
|
2432
|
+
0,
|
|
2433
|
+
1
|
|
2434
|
+
], ref.origin, dep.origin, extra);
|
|
2435
|
+
case "point-point": return solvePointPair(ref.origin, dep.origin, extra);
|
|
2436
|
+
case "axis-axis": return extra === 0 ? solveConcentric(ref, dep) : solveAxisAxisDistance(ref, dep, extra);
|
|
2437
|
+
case "axis-point": return solveAxisToPoint(ref, dep.origin, extra);
|
|
2438
|
+
case "point-axis": return solvePointToAxis(ref.origin, dep, extra);
|
|
2439
|
+
default: return null;
|
|
2440
|
+
}
|
|
2441
|
+
}
|
|
2390
2442
|
/** Dispatch a positioning mate to its solver. `ref` is already in world space. */
|
|
2391
2443
|
function solveMate(c, ref, dep) {
|
|
2392
2444
|
switch (c.type) {
|
|
2393
2445
|
case "concentric": return solveConcentric(ref, dep);
|
|
2394
2446
|
case "angle": return solveAngle(ref, dep, (c.value ?? 0) * Math.PI / 180);
|
|
2395
|
-
case "distance": return solvePlanePair(ref, dep, c.value ?? 0);
|
|
2396
|
-
default: return solvePlanePair(ref, dep, 0);
|
|
2447
|
+
case "distance": return solveTranslational(ref, dep, c.value ?? 0) ?? solvePlanePair(ref, dep, c.value ?? 0);
|
|
2448
|
+
default: return solveTranslational(ref, dep, 0) ?? solvePlanePair(ref, dep, 0);
|
|
2397
2449
|
}
|
|
2398
2450
|
}
|
|
2399
2451
|
/**
|
|
2400
2452
|
* Solve assembly constraints analytically.
|
|
2401
2453
|
*
|
|
2402
|
-
* Handles: fixed,
|
|
2403
|
-
*
|
|
2404
|
-
*
|
|
2454
|
+
* Handles: fixed, concentric (axis-axis), angle (plane-plane orientation), and
|
|
2455
|
+
* coincident/distance for any supported entity-type pair (plane-plane,
|
|
2456
|
+
* plane-point, point-point, axis-axis, axis-point, and both point orders — see
|
|
2457
|
+
* `TRANSLATIONAL_PAIRS`). For a positioning mate, entityA is the reference and
|
|
2458
|
+
* entityB the dependent. Chain roots (nodes never positioned by a
|
|
2405
2459
|
* mate) and explicit `fixed` nodes anchor at the origin; constraints then resolve
|
|
2406
2460
|
* in topological order — each places its dependent against the reference's solved
|
|
2407
2461
|
* pose (rotation included), so multi-body chains compose. Returns
|
|
@@ -2428,9 +2482,10 @@ function solveConstraints(nodes, constraints) {
|
|
|
2428
2482
|
const pending = [];
|
|
2429
2483
|
for (const c of positioning) {
|
|
2430
2484
|
if (!c.entityA || !c.entityB) continue;
|
|
2431
|
-
const
|
|
2432
|
-
|
|
2433
|
-
|
|
2485
|
+
const a = c.entityA.entity.type;
|
|
2486
|
+
const b = c.entityB.entity.type;
|
|
2487
|
+
if (!isSupportedPair(c.type, a, b)) {
|
|
2488
|
+
unsupported.push(`${c.type}(${a}-${b})`);
|
|
2434
2489
|
continue;
|
|
2435
2490
|
}
|
|
2436
2491
|
pending.push(c);
|
|
@@ -2619,191 +2674,6 @@ function solveAssembly(assembly) {
|
|
|
2619
2674
|
}
|
|
2620
2675
|
}
|
|
2621
2676
|
//#endregion
|
|
2622
|
-
//#region src/operations/jointFns.ts
|
|
2623
|
-
var DEG2RAD$1 = Math.PI / 180;
|
|
2624
|
-
function clamp(value, min, max) {
|
|
2625
|
-
return Math.min(max, Math.max(min, value));
|
|
2626
|
-
}
|
|
2627
|
-
function unit(v) {
|
|
2628
|
-
const l = Math.hypot(v[0], v[1], v[2]) || 1;
|
|
2629
|
-
return [
|
|
2630
|
-
v[0] / l,
|
|
2631
|
-
v[1] / l,
|
|
2632
|
-
v[2] / l
|
|
2633
|
-
];
|
|
2634
|
-
}
|
|
2635
|
-
function makeJoint(type, parent, child, axis, opts, defMin, defMax) {
|
|
2636
|
-
const a = opts.min ?? defMin;
|
|
2637
|
-
const b = opts.max ?? defMax;
|
|
2638
|
-
const min = Math.min(a, b);
|
|
2639
|
-
const max = Math.max(a, b);
|
|
2640
|
-
return {
|
|
2641
|
-
type,
|
|
2642
|
-
parent,
|
|
2643
|
-
child,
|
|
2644
|
-
axis: {
|
|
2645
|
-
origin: axis.origin,
|
|
2646
|
-
direction: unit(axis.direction)
|
|
2647
|
-
},
|
|
2648
|
-
min,
|
|
2649
|
-
max,
|
|
2650
|
-
value: clamp(opts.value ?? 0, min, max)
|
|
2651
|
-
};
|
|
2652
|
-
}
|
|
2653
|
-
/** A revolute (hinge) joint — the child rotates about `axis` by `value` degrees. */
|
|
2654
|
-
function revoluteJoint(parent, child, axis, opts = {}) {
|
|
2655
|
-
return makeJoint("revolute", parent, child, axis, opts, -180, 180);
|
|
2656
|
-
}
|
|
2657
|
-
/**
|
|
2658
|
-
* A prismatic (slider) joint — the child translates along `axis` by `value`
|
|
2659
|
-
* units. Only `axis.direction` is used; `axis.origin` is ignored (a pure
|
|
2660
|
-
* translation has no anchor point), unlike a revolute joint which rotates about
|
|
2661
|
-
* the axis line through `origin`.
|
|
2662
|
-
*/
|
|
2663
|
-
function prismaticJoint(parent, child, axis, opts = {}) {
|
|
2664
|
-
return makeJoint("prismatic", parent, child, axis, opts, 0, 100);
|
|
2665
|
-
}
|
|
2666
|
-
/** Return a copy of `joint` with its drivable parameter set (clamped to range). */
|
|
2667
|
-
function setJointValue(joint, value) {
|
|
2668
|
-
return {
|
|
2669
|
-
...joint,
|
|
2670
|
-
value: clamp(value, joint.min, joint.max)
|
|
2671
|
-
};
|
|
2672
|
-
}
|
|
2673
|
-
/**
|
|
2674
|
-
* The child's local rigid transform (relative to the parent) for a joint value.
|
|
2675
|
-
* Defaults to the joint's stored value; an explicit value is clamped to range.
|
|
2676
|
-
*
|
|
2677
|
-
* - **revolute**: rotation of `value` degrees about the axis line. Rotating
|
|
2678
|
-
* about a line through `origin` is `p ↦ R·p + (origin − R·origin)`.
|
|
2679
|
-
* - **prismatic**: translation of `value` units along the axis direction.
|
|
2680
|
-
*/
|
|
2681
|
-
function jointTransform(joint, value = joint.value) {
|
|
2682
|
-
const v = clamp(value, joint.min, joint.max);
|
|
2683
|
-
const dir = unit(joint.axis.direction);
|
|
2684
|
-
if (joint.type === "prismatic") return {
|
|
2685
|
-
position: [
|
|
2686
|
-
dir[0] * v,
|
|
2687
|
-
dir[1] * v,
|
|
2688
|
-
dir[2] * v
|
|
2689
|
-
],
|
|
2690
|
-
rotation: [
|
|
2691
|
-
1,
|
|
2692
|
-
0,
|
|
2693
|
-
0,
|
|
2694
|
-
0
|
|
2695
|
-
]
|
|
2696
|
-
};
|
|
2697
|
-
const rotation = quatFromAxisAngle(dir, v * DEG2RAD$1);
|
|
2698
|
-
const o = joint.axis.origin;
|
|
2699
|
-
const ro = quatRotate(rotation, o);
|
|
2700
|
-
return {
|
|
2701
|
-
position: [
|
|
2702
|
-
o[0] - ro[0],
|
|
2703
|
-
o[1] - ro[1],
|
|
2704
|
-
o[2] - ro[2]
|
|
2705
|
-
],
|
|
2706
|
-
rotation
|
|
2707
|
-
};
|
|
2708
|
-
}
|
|
2709
|
-
/** Attach a joint to an assembly node. Returns a new node (immutable). */
|
|
2710
|
-
function addJoint(assembly, joint) {
|
|
2711
|
-
const existing = assembly.joints ?? [];
|
|
2712
|
-
return {
|
|
2713
|
-
...assembly,
|
|
2714
|
-
joints: [...existing, joint]
|
|
2715
|
-
};
|
|
2716
|
-
}
|
|
2717
|
-
var IDENTITY_POSE = {
|
|
2718
|
-
position: [
|
|
2719
|
-
0,
|
|
2720
|
-
0,
|
|
2721
|
-
0
|
|
2722
|
-
],
|
|
2723
|
-
rotation: [
|
|
2724
|
-
1,
|
|
2725
|
-
0,
|
|
2726
|
-
0,
|
|
2727
|
-
0
|
|
2728
|
-
]
|
|
2729
|
-
};
|
|
2730
|
-
/** Compose two poses: the result applies `b` in `a`'s frame (`a ∘ b`). */
|
|
2731
|
-
function composePose(a, b) {
|
|
2732
|
-
const rb = quatRotate(a.rotation, b.position);
|
|
2733
|
-
return {
|
|
2734
|
-
position: [
|
|
2735
|
-
a.position[0] + rb[0],
|
|
2736
|
-
a.position[1] + rb[1],
|
|
2737
|
-
a.position[2] + rb[2]
|
|
2738
|
-
],
|
|
2739
|
-
rotation: quatMultiply(a.rotation, b.rotation)
|
|
2740
|
-
};
|
|
2741
|
-
}
|
|
2742
|
-
/** Collect every joint attached anywhere in the assembly tree. */
|
|
2743
|
-
function collectJoints(assembly) {
|
|
2744
|
-
const joints = [];
|
|
2745
|
-
require_threadFns.walkAssembly(assembly, (node) => {
|
|
2746
|
-
if (node.joints) joints.push(...node.joints);
|
|
2747
|
-
});
|
|
2748
|
-
return joints;
|
|
2749
|
-
}
|
|
2750
|
-
/**
|
|
2751
|
-
* Forward kinematics: set joint values and propagate world poses down the
|
|
2752
|
-
* kinematic chain. Each joint's axis is interpreted in its **parent's** frame,
|
|
2753
|
-
* so a child's world pose is `parentWorld ∘ jointTransform(joint, value)`.
|
|
2754
|
-
*
|
|
2755
|
-
* Bodies not driven by a joint (chain roots) start at the origin. `jointValues`
|
|
2756
|
-
* overrides a joint's stored value, keyed by the **child** node name; omitted
|
|
2757
|
-
* joints use `joint.value`. Resolution is topological (reuses the Phase-0
|
|
2758
|
-
* ordering), so chains of any depth compose. Returns a world pose for every node.
|
|
2759
|
-
*/
|
|
2760
|
-
function forwardKinematics(assembly, jointValues = {}) {
|
|
2761
|
-
const joints = [];
|
|
2762
|
-
const names = /* @__PURE__ */ new Set();
|
|
2763
|
-
require_threadFns.walkAssembly(assembly, (node) => {
|
|
2764
|
-
names.add(node.name);
|
|
2765
|
-
if (node.joints) joints.push(...node.joints);
|
|
2766
|
-
});
|
|
2767
|
-
const byChild = /* @__PURE__ */ new Map();
|
|
2768
|
-
for (const j of joints) {
|
|
2769
|
-
byChild.set(j.child, j);
|
|
2770
|
-
names.add(j.parent);
|
|
2771
|
-
names.add(j.child);
|
|
2772
|
-
}
|
|
2773
|
-
const poses = /* @__PURE__ */ new Map();
|
|
2774
|
-
for (const name of names) if (!byChild.has(name)) poses.set(name, IDENTITY_POSE);
|
|
2775
|
-
const pending = [...joints];
|
|
2776
|
-
let progress = true;
|
|
2777
|
-
while (progress && pending.length > 0) {
|
|
2778
|
-
progress = false;
|
|
2779
|
-
for (let i = pending.length - 1; i >= 0; i--) {
|
|
2780
|
-
const j = pending[i];
|
|
2781
|
-
if (!j) continue;
|
|
2782
|
-
const parentPose = poses.get(j.parent);
|
|
2783
|
-
if (!parentPose) continue;
|
|
2784
|
-
pending.splice(i, 1);
|
|
2785
|
-
progress = true;
|
|
2786
|
-
if (poses.has(j.child)) continue;
|
|
2787
|
-
const value = jointValues[j.child] ?? j.value;
|
|
2788
|
-
poses.set(j.child, composePose(parentPose, jointTransform(j, value)));
|
|
2789
|
-
}
|
|
2790
|
-
}
|
|
2791
|
-
for (const j of pending) if (!poses.has(j.child)) poses.set(j.child, IDENTITY_POSE);
|
|
2792
|
-
return poses;
|
|
2793
|
-
}
|
|
2794
|
-
var JOINT_FREEDOM = {
|
|
2795
|
-
revolute: 1,
|
|
2796
|
-
prismatic: 1
|
|
2797
|
-
};
|
|
2798
|
-
/**
|
|
2799
|
-
* Open-chain mobility — the number of independent degrees of freedom. Each
|
|
2800
|
-
* revolute/prismatic joint contributes 1, so for a serial chain this equals the
|
|
2801
|
-
* joint count. (Closed-loop Grübler/Kutzbach analysis is future work.)
|
|
2802
|
-
*/
|
|
2803
|
-
function mechanismDOF(assembly) {
|
|
2804
|
-
return collectJoints(assembly).reduce((sum, j) => sum + JOINT_FREEDOM[j.type], 0);
|
|
2805
|
-
}
|
|
2806
|
-
//#endregion
|
|
2807
2677
|
//#region src/measurement/interferenceFns.ts
|
|
2808
2678
|
/**
|
|
2809
2679
|
* Interference detection between shapes.
|
|
@@ -6602,7 +6472,7 @@ exports.Sketcher = require_drawFns.Sketcher;
|
|
|
6602
6472
|
exports.Sketches = require_textBlueprints.Sketches;
|
|
6603
6473
|
exports.addChild = require_threadFns.addChild;
|
|
6604
6474
|
exports.addHoles = require_primitiveFns.addHoles;
|
|
6605
|
-
exports.addJoint = addJoint;
|
|
6475
|
+
exports.addJoint = require_threadFns.addJoint;
|
|
6606
6476
|
exports.addMate = addMate;
|
|
6607
6477
|
exports.addStep = require_threadFns.addStep;
|
|
6608
6478
|
exports.adjacentFaces = require_healingFns.adjacentFaces;
|
|
@@ -6726,6 +6596,7 @@ exports.cutAllBisect = require_healingFns.cutAllBisect;
|
|
|
6726
6596
|
exports.cutBlueprints = require_boolean2D.cutBlueprints;
|
|
6727
6597
|
exports.cutWithEvolution = require_healingFns.cutWithEvolution;
|
|
6728
6598
|
exports.cylinder = require_primitiveFns.cylinder;
|
|
6599
|
+
exports.cylindricalJoint = require_threadFns.cylindricalJoint;
|
|
6729
6600
|
exports.defaultScorer = require_shapeRefFns.defaultScorer;
|
|
6730
6601
|
exports.dequeueTask = require_workerHandler.dequeueTask;
|
|
6731
6602
|
exports.describe = describe;
|
|
@@ -6799,7 +6670,7 @@ exports.flatten = require_errors.flatten;
|
|
|
6799
6670
|
exports.flipFaceOrientation = require_faceFns.flipFaceOrientation;
|
|
6800
6671
|
exports.flipOrientation = require_curveFns.flipOrientation;
|
|
6801
6672
|
exports.fontMetrics = require_textMetrics.fontMetrics;
|
|
6802
|
-
exports.forwardKinematics = forwardKinematics;
|
|
6673
|
+
exports.forwardKinematics = require_threadFns.forwardKinematics;
|
|
6803
6674
|
exports.fromBREP = fromBREP$1;
|
|
6804
6675
|
exports.fromKernelDir = fromKernelDir;
|
|
6805
6676
|
exports.fromKernelPnt = fromKernelPnt;
|
|
@@ -6922,7 +6793,7 @@ exports.iterSolids = require_topologyQueryFns.iterSolids;
|
|
|
6922
6793
|
exports.iterTopo = require_faceFns.iterTopo;
|
|
6923
6794
|
exports.iterVertices = require_topologyQueryFns.iterVertices;
|
|
6924
6795
|
exports.iterWires = require_topologyQueryFns.iterWires;
|
|
6925
|
-
exports.jointTransform = jointTransform;
|
|
6796
|
+
exports.jointTransform = require_threadFns.jointTransform;
|
|
6926
6797
|
exports.kernelCall = require_topologyQueryFns.kernelCall;
|
|
6927
6798
|
exports.kernelCallRaw = require_topologyQueryFns.kernelCallRaw;
|
|
6928
6799
|
exports.kernelCallScoped = require_topologyQueryFns.kernelCallScoped;
|
|
@@ -6961,7 +6832,7 @@ Object.defineProperty(exports, "measurement", {
|
|
|
6961
6832
|
return measurement_exports;
|
|
6962
6833
|
}
|
|
6963
6834
|
});
|
|
6964
|
-
exports.mechanismDOF = mechanismDOF;
|
|
6835
|
+
exports.mechanismDOF = require_threadFns.mechanismDOF;
|
|
6965
6836
|
exports.mesh = mesh;
|
|
6966
6837
|
exports.meshEdges = meshEdges;
|
|
6967
6838
|
exports.meshMultiLOD = require_meshFns.meshMultiLOD;
|
|
@@ -7001,6 +6872,7 @@ exports.pendingCount = require_workerHandler.pendingCount;
|
|
|
7001
6872
|
exports.pipeline = require_errors.pipeline;
|
|
7002
6873
|
exports.pivotPlane = require_planeOps.pivotPlane;
|
|
7003
6874
|
exports.planarFace = require_shapeTypes.planarFace;
|
|
6875
|
+
exports.planarJoint = require_threadFns.planarJoint;
|
|
7004
6876
|
exports.planarWire = require_shapeTypes.planarWire;
|
|
7005
6877
|
exports.planetPlacements = planetPlacements;
|
|
7006
6878
|
exports.pocket = pocket;
|
|
@@ -7018,7 +6890,7 @@ Object.defineProperty(exports, "primitives", {
|
|
|
7018
6890
|
return primitives_exports;
|
|
7019
6891
|
}
|
|
7020
6892
|
});
|
|
7021
|
-
exports.prismaticJoint = prismaticJoint;
|
|
6893
|
+
exports.prismaticJoint = require_threadFns.prismaticJoint;
|
|
7022
6894
|
exports.projectEdges = require_cameraFns.projectEdges;
|
|
7023
6895
|
exports.projectPointOnFace = require_faceFns.projectPointOnFace;
|
|
7024
6896
|
Object.defineProperty(exports, "query", {
|
|
@@ -7050,7 +6922,7 @@ exports.resolveDirection = require_types.resolveDirection;
|
|
|
7050
6922
|
exports.resolvePlane = require_planeOps.resolvePlane;
|
|
7051
6923
|
exports.resolveRef = require_shapeRefFns.resolveRef;
|
|
7052
6924
|
exports.reverseCurve = require_blueprintFns.reverseCurve;
|
|
7053
|
-
exports.revoluteJoint = revoluteJoint;
|
|
6925
|
+
exports.revoluteJoint = require_threadFns.revoluteJoint;
|
|
7054
6926
|
exports.revolve = revolve;
|
|
7055
6927
|
exports.roof = roof;
|
|
7056
6928
|
exports.rotate = rotate;
|
|
@@ -7079,7 +6951,8 @@ exports.sdfTorus = torus;
|
|
|
7079
6951
|
exports.section = section;
|
|
7080
6952
|
exports.sectionToFace = sectionToFace;
|
|
7081
6953
|
exports.serializeHistory = require_threadFns.serializeHistory;
|
|
7082
|
-
exports.setJointValue = setJointValue;
|
|
6954
|
+
exports.setJointValue = require_threadFns.setJointValue;
|
|
6955
|
+
exports.setJointValues = require_threadFns.setJointValues;
|
|
7083
6956
|
exports.setShapeOrigin = require_shapeFns.setShapeOrigin;
|
|
7084
6957
|
exports.setTagMetadata = require_shapeFns.setTagMetadata;
|
|
7085
6958
|
exports.sewShells = require_primitiveFns.sewShells;
|
|
@@ -7115,6 +6988,7 @@ exports.solid = require_primitiveFns.solid;
|
|
|
7115
6988
|
exports.solidFromShell = require_healingFns.solidFromShell;
|
|
7116
6989
|
exports.solveAssembly = solveAssembly;
|
|
7117
6990
|
exports.sphere = require_primitiveFns.sphere;
|
|
6991
|
+
exports.sphericalJoint = require_threadFns.sphericalJoint;
|
|
7118
6992
|
exports.split = split;
|
|
7119
6993
|
exports.stepCount = require_threadFns.stepCount;
|
|
7120
6994
|
exports.stepsFrom = require_threadFns.stepsFrom;
|