@nebula-spatial/viewer 0.4.3 → 0.4.4
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/CHANGELOG.md +47 -24
- package/README.md +65 -28
- package/dist/assets/types.d.ts +6 -1
- package/dist/{index-BDo6voB2.js → index-D-o1ODOX.js} +2018 -1480
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -1
- package/dist/inspection/types.d.ts +99 -0
- package/dist/{mjcf-visual--X39MVO9.js → mjcf-visual-M1lmyjvw.js} +1 -1
- package/dist/mujoco-runtime-C29PXDOl.js +258 -0
- package/dist/plugins.d.ts +5 -1
- package/dist/session-Cz6qHYMc.js +676 -0
- package/dist/{session-1duLyM88.js → session-c7xBLA4J.js} +2 -2
- package/dist/{stage-BKqg5vNe.js → stage-D113SHD8.js} +155 -138
- package/dist/types.d.ts +2 -0
- package/dist/ui/types.d.ts +2 -0
- package/dist/urdf-session-AP-cMuwd.js +3001 -0
- package/dist/{usd-session-zyj46Bcg.js → usd-session-CmSdkRw9.js} +3 -3
- package/package.json +3 -2
- package/dist/mujoco-runtime-s85kwjo7.js +0 -208
- package/dist/session-DhZXy40-.js +0 -653
- package/dist/urdf-session-C_LAfkkM.js +0 -439
package/dist/index.d.ts
CHANGED
|
@@ -5,3 +5,4 @@ export type { Disposable, ToolbarItem, ViewerState, ViewerInteractionHooks, View
|
|
|
5
5
|
export { configureViewerText } from './cad/text';
|
|
6
6
|
export type { ViewerTextBuilderOptions } from './cad/text';
|
|
7
7
|
export type { CadBlockModel, CadDocumentHandle, CadDocumentUnits, CadFontResolver, CadFontRequest, CadResolvedFont, CadResolvedTextFont, CadTextWarmupOptions, CadHudModel, CadHudSnapshot, CadInspectorModel, CadInspectorSnapshot, CadLayerModel, CadLayerRow, CadBlockUsageRow, CadSessionPhase, CadWorldBounds, CadScaleRulerState, CadInsertDetails, CadInsertSelection, CadInsertSelectionId, CadTextDetails, CadTextSelection, CadTextSelectionId, CadSelection, CadHit, CadViewerSnapshot, CadLoadProgress, CadViewerErrorCode, CadViewerErrorEvent, CadLoadSource, CadOpenOptions, CadSessionLoadTiming, RenderDebugBreakdownEntry, SplitBlockLayerDetail, CadViewerCapability, ResolveTextFont, CadViewerEventMap, CameraStateStore, Viewer, ViewerEventMap, ViewerEnvironment, ViewerFitViewOptions, ViewerHighlightOptions, ViewerOptions, ViewerPickOptions, ViewerPickResult, ViewerPointerEvent, ViewerObjectOptions, ViewerCameraSnapshot, ViewerOrthographicSnapshot, ViewerOrbitSnapshot, ViewerRenderStats, ViewerDocumentRect, ViewerCadUiKeyboardOptions, ViewerUiOptions, ViewerCadUiParts, ViewerCadUiOptions, ViewerUiPreset, ViewerCadUiStateStore, ViewerUiTheme, ViewerViewMode, CadInteractionMode, CameraChangeReason, ViewerUiTokens, } from './types';
|
|
8
|
+
export type { AssetInspection, UrdfEntityKind, UrdfInspection, UrdfInspectionEntity, UrdfInspectionIssue, UrdfInspectionJoint, UrdfInspectionLink, UrdfInspectionMode, UrdfInspectionNode, UrdfInspectionOverlays, UrdfInspectionRobot, UrdfInspectionSnapshot, UrdfSourceRange } from './inspection/types';
|
package/dist/index.js
CHANGED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
export type UrdfEntityKind = 'robot' | 'link' | 'joint';
|
|
2
|
+
export interface UrdfSourceRange {
|
|
3
|
+
readonly file: string;
|
|
4
|
+
readonly startOffset: number;
|
|
5
|
+
readonly endOffset: number;
|
|
6
|
+
readonly startLine: number;
|
|
7
|
+
readonly startColumn: number;
|
|
8
|
+
readonly endLine: number;
|
|
9
|
+
readonly endColumn: number;
|
|
10
|
+
}
|
|
11
|
+
export interface UrdfInspectionEntity {
|
|
12
|
+
readonly id: string;
|
|
13
|
+
readonly kind: UrdfEntityKind;
|
|
14
|
+
readonly name: string;
|
|
15
|
+
readonly parentId?: string;
|
|
16
|
+
readonly childIds: readonly string[];
|
|
17
|
+
readonly source?: UrdfSourceRange;
|
|
18
|
+
}
|
|
19
|
+
export interface UrdfInspectionLink extends UrdfInspectionEntity {
|
|
20
|
+
readonly kind: 'link';
|
|
21
|
+
readonly mass?: number;
|
|
22
|
+
readonly centerOfMass?: readonly number[];
|
|
23
|
+
readonly inertiaTensor?: readonly number[];
|
|
24
|
+
readonly inertiaMass?: number;
|
|
25
|
+
readonly visualCount: number;
|
|
26
|
+
readonly collisionCount: number;
|
|
27
|
+
}
|
|
28
|
+
export interface UrdfInspectionJoint extends UrdfInspectionEntity {
|
|
29
|
+
readonly kind: 'joint';
|
|
30
|
+
readonly jointType: string;
|
|
31
|
+
readonly parentLink: string;
|
|
32
|
+
readonly childLink: string;
|
|
33
|
+
readonly axis: readonly number[];
|
|
34
|
+
readonly originPosition: readonly number[];
|
|
35
|
+
readonly originRotationRpy: readonly number[];
|
|
36
|
+
readonly limits?: {
|
|
37
|
+
readonly lower: number;
|
|
38
|
+
readonly upper: number;
|
|
39
|
+
};
|
|
40
|
+
readonly effort?: number;
|
|
41
|
+
readonly velocity?: number;
|
|
42
|
+
readonly movable: boolean;
|
|
43
|
+
}
|
|
44
|
+
export interface UrdfInspectionRobot extends UrdfInspectionEntity {
|
|
45
|
+
readonly kind: 'robot';
|
|
46
|
+
readonly rootLinkIds: readonly string[];
|
|
47
|
+
}
|
|
48
|
+
export type UrdfInspectionNode = UrdfInspectionRobot | UrdfInspectionLink | UrdfInspectionJoint;
|
|
49
|
+
export interface UrdfInspectionIssue {
|
|
50
|
+
readonly id: string;
|
|
51
|
+
readonly ruleId: string;
|
|
52
|
+
readonly severity: 'error';
|
|
53
|
+
readonly title: string;
|
|
54
|
+
readonly message: string;
|
|
55
|
+
readonly entityId: string;
|
|
56
|
+
readonly source?: UrdfSourceRange;
|
|
57
|
+
readonly values?: Readonly<Record<string, unknown>>;
|
|
58
|
+
}
|
|
59
|
+
export interface UrdfInspectionOverlays {
|
|
60
|
+
readonly collision: boolean;
|
|
61
|
+
readonly jointAxis: boolean;
|
|
62
|
+
readonly centerOfMass: boolean;
|
|
63
|
+
readonly inertia?: boolean;
|
|
64
|
+
}
|
|
65
|
+
export type UrdfInspectionMode = 'kinematic' | 'dynamics-initializing' | 'dynamics-paused' | 'dynamics-running' | 'dynamics-unavailable';
|
|
66
|
+
export interface UrdfInspectionSnapshot {
|
|
67
|
+
readonly revision: number;
|
|
68
|
+
readonly kind: 'urdf';
|
|
69
|
+
readonly robotName: string;
|
|
70
|
+
readonly sourcePath: string;
|
|
71
|
+
readonly sourceText: string;
|
|
72
|
+
readonly nodes: readonly UrdfInspectionNode[];
|
|
73
|
+
readonly rootEntityId: string;
|
|
74
|
+
readonly selectedEntityId: string | null;
|
|
75
|
+
readonly jointValues: Readonly<Record<string, number>>;
|
|
76
|
+
readonly overlays: UrdfInspectionOverlays;
|
|
77
|
+
readonly issues: readonly UrdfInspectionIssue[];
|
|
78
|
+
readonly mode: UrdfInspectionMode;
|
|
79
|
+
readonly dynamicsAvailable: boolean;
|
|
80
|
+
readonly dynamicsMessage?: string;
|
|
81
|
+
}
|
|
82
|
+
export interface UrdfInspection {
|
|
83
|
+
readonly kind: 'urdf';
|
|
84
|
+
getSnapshot(): UrdfInspectionSnapshot;
|
|
85
|
+
subscribe(listener: (snapshot: UrdfInspectionSnapshot) => void): () => void;
|
|
86
|
+
select(entityId: string | null): void;
|
|
87
|
+
setJointValue(jointId: string, value: number): void;
|
|
88
|
+
resetJoint(jointId: string): void;
|
|
89
|
+
resetPose(): void;
|
|
90
|
+
setOverlay(name: keyof UrdfInspectionOverlays, visible: boolean): void;
|
|
91
|
+
enterKinematicPreview(): void;
|
|
92
|
+
jointWorldFrame?(jointId: string): {
|
|
93
|
+
position: import('three').Vector3;
|
|
94
|
+
axis: import('three').Vector3;
|
|
95
|
+
} | null;
|
|
96
|
+
pickRoots?(): readonly import('three').Object3D[];
|
|
97
|
+
}
|
|
98
|
+
/** Tagged inspection surface. Future formats can extend this union without changing AssetPreview. */
|
|
99
|
+
export type AssetInspection = UrdfInspection;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Group as A, Euler as C, BoxGeometry as E, SphereGeometry as F, CylinderGeometry as x, CapsuleGeometry as J, PlaneGeometry as q, MeshStandardMaterial as G, Mesh as z } from "three";
|
|
2
|
-
import { d as S } from "./stage-
|
|
2
|
+
import { d as S } from "./stage-D113SHD8.js";
|
|
3
3
|
function v(d) {
|
|
4
4
|
const f = d.extension.documents, l = new A();
|
|
5
5
|
l.name = d.name;
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
var M = Object.defineProperty;
|
|
2
|
+
var O = (l, t, i) => t in l ? M(l, t, { enumerable: !0, configurable: !0, writable: !0, value: i }) : l[t] = i;
|
|
3
|
+
var _ = (l, t, i) => O(l, typeof t != "symbol" ? t + "" : t, i);
|
|
4
|
+
import I from "@mujoco/mujoco";
|
|
5
|
+
import T from "@mujoco/mujoco/mujoco.wasm?url";
|
|
6
|
+
let v = 0;
|
|
7
|
+
function G(l, t) {
|
|
8
|
+
const i = `/viewer-simulation-${++v}`;
|
|
9
|
+
l.mkdir(i);
|
|
10
|
+
const n = /* @__PURE__ */ new Set([i]), o = /* @__PURE__ */ new Set(), a = (e, s) => {
|
|
11
|
+
const m = e.replaceAll("\\", "/").split("/");
|
|
12
|
+
if (m[0] === "" || m.some((d) => d === ".." || d.includes(":"))) throw p(`Invalid package path: ${e}`, "E_SIMULATION_PATH");
|
|
13
|
+
const h = m.filter((d) => d && d !== ".");
|
|
14
|
+
if (!h.length) throw p("Package path is empty.", "E_SIMULATION_PATH");
|
|
15
|
+
let c = i;
|
|
16
|
+
for (const d of h.slice(0, -1))
|
|
17
|
+
c += `/${d}`, n.has(c) || (l.mkdir(c), n.add(c));
|
|
18
|
+
const u = `${i}/${h.join("/")}`;
|
|
19
|
+
return l.writeFile(u, s), o.add(u), u;
|
|
20
|
+
}, r = () => {
|
|
21
|
+
for (const e of o) l.unlink(e);
|
|
22
|
+
o.clear();
|
|
23
|
+
for (const e of [...n].reverse()) l.rmdir(e);
|
|
24
|
+
n.clear();
|
|
25
|
+
};
|
|
26
|
+
try {
|
|
27
|
+
for (const [e, s] of t) a(e, s);
|
|
28
|
+
return { writeEntry: (e) => a("__viewer_entry.xml", e), dispose: r };
|
|
29
|
+
} catch (e) {
|
|
30
|
+
throw r(), e;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function p(l, t) {
|
|
34
|
+
return Object.assign(new Error(l), { code: t });
|
|
35
|
+
}
|
|
36
|
+
function w({
|
|
37
|
+
target: l,
|
|
38
|
+
point: t,
|
|
39
|
+
velocity: i,
|
|
40
|
+
stiffness: n,
|
|
41
|
+
damping: o,
|
|
42
|
+
maxForce: a,
|
|
43
|
+
strength: r
|
|
44
|
+
}) {
|
|
45
|
+
const e = [
|
|
46
|
+
n * (l[0] - t[0]) - o * i[0],
|
|
47
|
+
n * (l[1] - t[1]) - o * i[1],
|
|
48
|
+
n * (l[2] - t[2]) - o * i[2]
|
|
49
|
+
], s = Math.hypot(e[0], e[1], e[2]), m = a * r;
|
|
50
|
+
if (s > m && s > 0) {
|
|
51
|
+
const h = m / s;
|
|
52
|
+
e[0] *= h, e[1] *= h, e[2] *= h;
|
|
53
|
+
}
|
|
54
|
+
return e;
|
|
55
|
+
}
|
|
56
|
+
const g = 1 / 240, F = 0.05, x = 80, J = 1.15, b = 3.5, y = 14;
|
|
57
|
+
class S {
|
|
58
|
+
constructor() {
|
|
59
|
+
_(this, "mujoco", null);
|
|
60
|
+
_(this, "model", null);
|
|
61
|
+
_(this, "data", null);
|
|
62
|
+
_(this, "grab", null);
|
|
63
|
+
_(this, "lastGrabForce", [0, 0, 0]);
|
|
64
|
+
_(this, "velocityBuffer", new Float64Array(6));
|
|
65
|
+
_(this, "initialControls", []);
|
|
66
|
+
_(this, "accumulator", 0);
|
|
67
|
+
_(this, "initialGround", null);
|
|
68
|
+
_(this, "initialVelocities", []);
|
|
69
|
+
}
|
|
70
|
+
async initialize(t, i) {
|
|
71
|
+
var e;
|
|
72
|
+
this.mujoco ?? (this.mujoco = await I({ locateFile: (s) => s.endsWith(".wasm") ? i ? new URL(s, i).href : T : s }));
|
|
73
|
+
const n = G(this.mujoco.FS, t.files);
|
|
74
|
+
let o = null, a = null;
|
|
75
|
+
try {
|
|
76
|
+
o = this.mujoco.MjModel.from_xml_path(n.writeEntry(t.xml));
|
|
77
|
+
for (const s of t.massOverrides ?? []) {
|
|
78
|
+
const m = this.mujoco.mj_name2id(o, this.mujoco.mjtObj.mjOBJ_BODY.value, s.body);
|
|
79
|
+
if (m <= 0 || !Number.isFinite(s.mass) || s.mass <= 0 || !(o.body_mass[m] > 0)) throw new Error(`Invalid mass override: ${s.body}`);
|
|
80
|
+
const h = s.mass / o.body_mass[m];
|
|
81
|
+
o.body_mass[m] = s.mass;
|
|
82
|
+
for (let c = 0; c < 3; c++) o.body_inertia[m * 3 + c] *= h;
|
|
83
|
+
}
|
|
84
|
+
a = new this.mujoco.MjData(o), (e = t.massOverrides) != null && e.length && this.mujoco.mj_setConst(o, a), o.opt.timestep = g, this.applyInitialControls(a, t.initialControls), this.applyInitialVelocities(o, a, t.initialVelocities), this.mujoco.mj_forward(o, a), this.seatDefaultGround(o, a);
|
|
85
|
+
} catch (s) {
|
|
86
|
+
throw a == null || a.delete(), o == null || o.delete(), f(s, "E_MUJOCO_INITIALIZE");
|
|
87
|
+
} finally {
|
|
88
|
+
n.dispose();
|
|
89
|
+
}
|
|
90
|
+
this.disposeModel(), this.model = o, this.data = a, this.initialControls = t.initialControls ?? [], this.initialVelocities = t.initialVelocities ?? [], this.accumulator = 0;
|
|
91
|
+
const r = this.mujoco.mj_name2id(o, this.mujoco.mjtObj.mjOBJ_GEOM.value, "__viewer_default_ground__");
|
|
92
|
+
this.initialGround = r < 0 ? null : { id: r, height: o.geom_pos[r * 3 + 2], sameFrame: o.geom_sameframe[r] };
|
|
93
|
+
}
|
|
94
|
+
get defaultGroundHeight() {
|
|
95
|
+
if (!this.mujoco || !this.model) return;
|
|
96
|
+
const t = this.mujoco.mj_name2id(this.model, this.mujoco.mjtObj.mjOBJ_GEOM.value, "__viewer_default_ground__");
|
|
97
|
+
return t < 0 ? void 0 : this.model.geom_pos[t * 3 + 2];
|
|
98
|
+
}
|
|
99
|
+
/** Lower only the viewer-owned plane, never authored bodies or authored floors.
|
|
100
|
+
* Run after forward kinematics, not during stepping (the floor must not follow falling bodies).
|
|
101
|
+
*/
|
|
102
|
+
seatDefaultGround(t, i) {
|
|
103
|
+
const n = this.mujoco, o = n.mj_name2id(t, n.mjtObj.mjOBJ_GEOM.value, "__viewer_default_ground__");
|
|
104
|
+
if (o < 0 || t.geom_bodyid[o] !== 0 || t.geom_type[o] !== n.mjtGeom.mjGEOM_PLANE.value) return;
|
|
105
|
+
let a = t.geom_pos[o * 3 + 2];
|
|
106
|
+
for (let r = 0; r < t.ngeom; r++) {
|
|
107
|
+
if (r === o || t.geom_type[r] === n.mjtGeom.mjGEOM_PLANE.value || !(t.geom_contype[r] & t.geom_conaffinity[o]) && !(t.geom_conaffinity[r] & t.geom_contype[o])) continue;
|
|
108
|
+
const e = r * 6, s = r * 9, m = i.geom_xmat[s + 6], h = i.geom_xmat[s + 7], c = i.geom_xmat[s + 8], u = i.geom_xpos[r * 3 + 2] + m * t.geom_aabb[e] + h * t.geom_aabb[e + 1] + c * t.geom_aabb[e + 2], d = Math.abs(m) * t.geom_aabb[e + 3] + Math.abs(h) * t.geom_aabb[e + 4] + Math.abs(c) * t.geom_aabb[e + 5], j = u - d, E = Math.max(1e-3, t.geom_margin[r] + t.geom_margin[o]);
|
|
109
|
+
Number.isFinite(j) && j < a && (a = Math.min(a, j - E));
|
|
110
|
+
}
|
|
111
|
+
a !== t.geom_pos[o * 3 + 2] && (t.geom_pos[o * 3 + 2] = a, t.geom_sameframe[o] = 0, n.mj_forward(t, i));
|
|
112
|
+
}
|
|
113
|
+
beginGrab({
|
|
114
|
+
bodyId: t,
|
|
115
|
+
localPoint: i,
|
|
116
|
+
target: n,
|
|
117
|
+
stiffness: o = x,
|
|
118
|
+
damping: a,
|
|
119
|
+
maxForce: r,
|
|
120
|
+
dampingRatio: e = J,
|
|
121
|
+
maxTargetSpeed: s = b,
|
|
122
|
+
targetResponse: m = y
|
|
123
|
+
}) {
|
|
124
|
+
var j;
|
|
125
|
+
const h = Math.max(((j = this.model) == null ? void 0 : j.body_mass[t]) ?? 1, 1e-3), c = a ?? 2 * Math.sqrt(o * h) * e, u = r ?? Math.max(120, h * 60), d = [n[0], n[1], n[2]];
|
|
126
|
+
this.grab = {
|
|
127
|
+
bodyId: t,
|
|
128
|
+
localPoint: [i[0], i[1], i[2]],
|
|
129
|
+
target: [...d],
|
|
130
|
+
requestedTarget: d,
|
|
131
|
+
stiffness: o,
|
|
132
|
+
damping: c,
|
|
133
|
+
maxForce: u,
|
|
134
|
+
strength: 1,
|
|
135
|
+
maxTargetSpeed: s,
|
|
136
|
+
targetResponse: m
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
updateGrabTarget(t) {
|
|
140
|
+
this.grab && (this.grab.requestedTarget = [t[0], t[1], t[2]]);
|
|
141
|
+
}
|
|
142
|
+
updateGrabStrength(t) {
|
|
143
|
+
this.grab && (this.grab.strength = t);
|
|
144
|
+
}
|
|
145
|
+
applyGrabForce() {
|
|
146
|
+
if (!this.grab || !this.model || !this.data || !this.mujoco) return;
|
|
147
|
+
const { bodyId: t, localPoint: i, target: n, stiffness: o, damping: a, maxForce: r, strength: e } = this.grab, s = this.data.xmat.subarray(t * 9, t * 9 + 9), m = this.data.xpos.subarray(t * 3, t * 3 + 3), h = [
|
|
148
|
+
m[0] + s[0] * i[0] + s[1] * i[1] + s[2] * i[2],
|
|
149
|
+
m[1] + s[3] * i[0] + s[4] * i[1] + s[5] * i[2],
|
|
150
|
+
m[2] + s[6] * i[0] + s[7] * i[1] + s[8] * i[2]
|
|
151
|
+
];
|
|
152
|
+
this.mujoco.mj_objectVelocity(
|
|
153
|
+
this.model,
|
|
154
|
+
this.data,
|
|
155
|
+
this.mujoco.mjtObj.mjOBJ_BODY.value,
|
|
156
|
+
t,
|
|
157
|
+
this.velocityBuffer,
|
|
158
|
+
0
|
|
159
|
+
);
|
|
160
|
+
const c = this.velocityBuffer, u = [
|
|
161
|
+
h[0] - m[0],
|
|
162
|
+
h[1] - m[1],
|
|
163
|
+
h[2] - m[2]
|
|
164
|
+
], d = [
|
|
165
|
+
c[3] + c[1] * u[2] - c[2] * u[1],
|
|
166
|
+
c[4] + c[2] * u[0] - c[0] * u[2],
|
|
167
|
+
c[5] + c[0] * u[1] - c[1] * u[0]
|
|
168
|
+
], j = w({ target: n, point: h, velocity: d, stiffness: o, damping: a, maxForce: r, strength: e });
|
|
169
|
+
this.lastGrabForce = [...j], this.data.qfrc_applied.fill(0), this.mujoco.mj_applyFT(
|
|
170
|
+
this.model,
|
|
171
|
+
this.data,
|
|
172
|
+
j,
|
|
173
|
+
[0, 0, 0],
|
|
174
|
+
h,
|
|
175
|
+
t,
|
|
176
|
+
this.data.qfrc_applied
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
endGrab() {
|
|
180
|
+
this.data && this.data.qfrc_applied.fill(0), this.lastGrabForce = [0, 0, 0], this.grab = null;
|
|
181
|
+
}
|
|
182
|
+
step(t) {
|
|
183
|
+
if (!this.mujoco || !this.model || !this.data || t <= 0) return !1;
|
|
184
|
+
this.accumulator += Math.min(t, F);
|
|
185
|
+
let i = !1;
|
|
186
|
+
for (; this.accumulator >= g; )
|
|
187
|
+
this.updateGrabTargetForStep(), this.applyGrabForce(), this.mujoco.mj_step(this.model, this.data), this.accumulator -= g, i = !0;
|
|
188
|
+
return i;
|
|
189
|
+
}
|
|
190
|
+
updateGrabTargetForStep() {
|
|
191
|
+
const t = this.grab;
|
|
192
|
+
if (!t) return;
|
|
193
|
+
const i = t.requestedTarget ?? t.target, n = (t.maxTargetSpeed ?? b) * Math.max(1, Math.sqrt(t.strength)), o = t.targetResponse ?? y, a = 1 - Math.exp(-o * g), r = n * g;
|
|
194
|
+
for (let e = 0; e < 3; e++) {
|
|
195
|
+
const s = i[e] - t.target[e], m = Math.sign(s) * Math.min(Math.abs(s) * a, r);
|
|
196
|
+
t.target[e] += m;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
setJointValues(t) {
|
|
200
|
+
if (!(!this.mujoco || !this.model || !this.data)) {
|
|
201
|
+
for (const [i, n] of Object.entries(t)) {
|
|
202
|
+
const o = this.mujoco.mj_name2id(this.model, this.mujoco.mjtObj.mjOBJ_JOINT.value, i);
|
|
203
|
+
if (o < 0 || !Number.isFinite(n)) continue;
|
|
204
|
+
const a = this.model.jnt_type[o], r = this.mujoco.mjtJoint.mjJNT_HINGE.value, e = this.mujoco.mjtJoint.mjJNT_SLIDE.value;
|
|
205
|
+
a !== r && a !== e || (this.data.qpos[this.model.jnt_qposadr[o]] = n);
|
|
206
|
+
}
|
|
207
|
+
this.mujoco.mj_forward(this.model, this.data), this.seatDefaultGround(this.model, this.data), this.accumulator = 0;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
getJointValues(t) {
|
|
211
|
+
const i = {};
|
|
212
|
+
if (!this.mujoco || !this.model || !this.data) return i;
|
|
213
|
+
for (const n of t) {
|
|
214
|
+
const o = this.mujoco.mj_name2id(this.model, this.mujoco.mjtObj.mjOBJ_JOINT.value, n);
|
|
215
|
+
if (o < 0) continue;
|
|
216
|
+
const a = this.model.jnt_type[o], r = this.mujoco.mjtJoint.mjJNT_HINGE.value, e = this.mujoco.mjtJoint.mjJNT_SLIDE.value;
|
|
217
|
+
(a === r || a === e) && (i[n] = this.data.qpos[this.model.jnt_qposadr[o]]);
|
|
218
|
+
}
|
|
219
|
+
return i;
|
|
220
|
+
}
|
|
221
|
+
reset() {
|
|
222
|
+
if (!(!this.mujoco || !this.model || !this.data)) {
|
|
223
|
+
if (this.endGrab(), this.initialGround) {
|
|
224
|
+
const { id: t, height: i, sameFrame: n } = this.initialGround;
|
|
225
|
+
this.model.geom_pos[t * 3 + 2] = i, this.model.geom_sameframe[t] = n;
|
|
226
|
+
}
|
|
227
|
+
this.mujoco.mj_resetData(this.model, this.data), this.applyInitialControls(this.data, this.initialControls), this.applyInitialVelocities(this.model, this.data, this.initialVelocities), this.mujoco.mj_forward(this.model, this.data), this.accumulator = 0;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
dispose() {
|
|
231
|
+
this.disposeModel(), this.mujoco = null;
|
|
232
|
+
}
|
|
233
|
+
applyInitialControls(t, i) {
|
|
234
|
+
if (i != null && i.length) {
|
|
235
|
+
if (i.length !== t.ctrl.length) throw f(new Error(`Initial control count ${i.length} does not match MuJoCo actuator count ${t.ctrl.length}.`), "E_MUJOCO_INITIALIZE");
|
|
236
|
+
t.ctrl.set(i);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
applyInitialVelocities(t, i, n) {
|
|
240
|
+
for (const o of n ?? []) {
|
|
241
|
+
const a = this.mujoco.mj_name2id(t, this.mujoco.mjtObj.mjOBJ_BODY.value, o.body), r = a >= 0 ? t.body_jntadr[a] : -1;
|
|
242
|
+
if (r < 0 || t.jnt_type[r] !== this.mujoco.mjtJoint.mjJNT_FREE.value || o.velocity.length !== 6 || !o.velocity.every(Number.isFinite))
|
|
243
|
+
throw f(new Error(`Invalid free-body initial velocity: ${o.body}`), "E_MUJOCO_INITIALIZE");
|
|
244
|
+
i.qvel.set(o.velocity, t.jnt_dofadr[r]);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
disposeModel() {
|
|
248
|
+
var t, i;
|
|
249
|
+
this.endGrab(), (t = this.data) == null || t.delete(), (i = this.model) == null || i.delete(), this.data = null, this.model = null, this.initialGround = null, this.initialControls = [], this.initialVelocities = [], this.accumulator = 0;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
function f(l, t) {
|
|
253
|
+
const i = l instanceof Error ? l : new Error(String(l));
|
|
254
|
+
return Object.assign(i, { code: t });
|
|
255
|
+
}
|
|
256
|
+
export {
|
|
257
|
+
S as MujocoRuntime
|
|
258
|
+
};
|
package/dist/plugins.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { Box3, Object3D } from 'three';
|
|
|
2
2
|
import type { CadHit, CadSelection, CadViewerSnapshot, CadViewerEventMap } from './cad/types';
|
|
3
3
|
import type { ViewerEventMap, ViewerViewMode, ViewerUiTheme } from './types';
|
|
4
4
|
import type { AssetControlState, AssetLoaderContribution, AssetPreviewSnapshot, AssetUpAxis } from './assets/types';
|
|
5
|
+
import type { AssetInspection } from './inspection/types';
|
|
5
6
|
export interface Disposable {
|
|
6
7
|
dispose(): void;
|
|
7
8
|
}
|
|
@@ -27,6 +28,7 @@ export interface ViewerAssetReadApi {
|
|
|
27
28
|
$read(): AssetPreviewSnapshot | null;
|
|
28
29
|
/** Authoritative control state, safe to bind button pressed states to. */
|
|
29
30
|
$readControl(): AssetControlState;
|
|
31
|
+
$inspection(): AssetInspection | null;
|
|
30
32
|
}
|
|
31
33
|
export interface ViewerPluginContext {
|
|
32
34
|
readonly cad: {
|
|
@@ -112,6 +114,7 @@ type SnapshotReader = () => CadViewerSnapshot;
|
|
|
112
114
|
type StateReader = () => ViewerState;
|
|
113
115
|
type AssetReader = () => AssetPreviewSnapshot | null;
|
|
114
116
|
type ControlStateReader = () => AssetControlState;
|
|
117
|
+
type InspectionReader = () => AssetInspection | null;
|
|
115
118
|
type PluginEventMap = ViewerEventMap & CadViewerEventMap;
|
|
116
119
|
type EventSubscriber = <K extends keyof PluginEventMap>(type: K, listener: (event: PluginEventMap[K]) => void) => () => void;
|
|
117
120
|
type CommandApi = ViewerPluginContext['commands'];
|
|
@@ -137,6 +140,7 @@ export declare class ViewerPluginManager implements ViewerPluginRegistry {
|
|
|
137
140
|
private readonly commands;
|
|
138
141
|
private readonly hostElement;
|
|
139
142
|
private readonly layout;
|
|
143
|
+
private readonly readInspection;
|
|
140
144
|
private readonly pluginsById;
|
|
141
145
|
private readonly contributions;
|
|
142
146
|
private readonly commandContributions;
|
|
@@ -144,7 +148,7 @@ export declare class ViewerPluginManager implements ViewerPluginRegistry {
|
|
|
144
148
|
private readonly contributionRemovedListeners;
|
|
145
149
|
private refreshingInspectors;
|
|
146
150
|
private disposed;
|
|
147
|
-
constructor(readCad: SnapshotReader, readState: StateReader, readAsset: AssetReader, readControlState: ControlStateReader, subscribe: EventSubscriber, commands: CommandApi, hostElement: HTMLElement, layout?: PluginLayoutPort | null);
|
|
151
|
+
constructor(readCad: SnapshotReader, readState: StateReader, readAsset: AssetReader, readControlState: ControlStateReader, subscribe: EventSubscriber, commands: CommandApi, hostElement: HTMLElement, layout?: PluginLayoutPort | null, readInspection?: InspectionReader);
|
|
148
152
|
register(plugin: ViewerPlugin): Disposable;
|
|
149
153
|
use(plugins: readonly ViewerPlugin[], options?: {
|
|
150
154
|
replace?: boolean;
|