beckhoff-xts-viewer-3d 5.2.0 → 5.2.2
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/README.md +35 -8
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +880 -753
- package/dist/index.d.ts +880 -753
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/docs/screenshots/01-packaging-line.webp +0 -0
- package/docs/screenshots/02-standard-at.webp +0 -0
- package/docs/screenshots/03-eco-at2200.webp +0 -0
- package/docs/screenshots/04-nct-tools.webp +0 -0
- package/docs/screenshots/05-hygienic-ath.webp +0 -0
- package/docs/screenshots/06-hepco-gfx.webp +0 -0
- package/docs/screenshots/07-materials-closeup.webp +0 -0
- package/docs/screenshots/08-multi-track.webp +0 -0
- package/docs/screenshots/09-stations-areas.webp +0 -0
- package/docs/screenshots/10-dimensions.webp +0 -0
- package/docs/screenshots/11-stator-heatmap.webp +0 -0
- package/docs/screenshots/12-collision.webp +0 -0
- package/docs/screenshots/13-drive-status.webp +0 -0
- package/docs/screenshots/14-feed-segments.webp +0 -0
- package/docs/screenshots/15-measurements.webp +0 -0
- package/docs/screenshots/16-selection.webp +0 -0
- package/docs/screenshots/17-plan-view.webp +0 -0
- package/docs/screenshots/18-shadows.webp +0 -0
- package/docs/screenshots/19-perf-stress.webp +0 -0
- package/docs/screenshots/README.md +106 -46
- package/package.json +6 -3
- package/docs/screenshots/01-oval-loop.png +0 -0
- package/docs/screenshots/02-multi-track.png +0 -0
- package/docs/screenshots/03-stations-areas.png +0 -0
- package/docs/screenshots/04-stator-heatmap.png +0 -0
- package/docs/screenshots/05-collision.png +0 -0
- package/docs/screenshots/06-drive-status.png +0 -0
- package/docs/screenshots/07-perf-stress.png +0 -0
- package/docs/screenshots/08-shadows.png +0 -0
- package/docs/screenshots/09-screenshot-export.png +0 -0
- package/docs/screenshots/10-feed-segments.png +0 -0
package/dist/index.d.cts
CHANGED
|
@@ -12,7 +12,7 @@ import { GLTF } from 'three-stdlib';
|
|
|
12
12
|
* Run `npm run sync-version` (or any script that depends on it) to refresh
|
|
13
13
|
* after bumping the package version.
|
|
14
14
|
*/
|
|
15
|
-
declare const VERSION: "5.2.
|
|
15
|
+
declare const VERSION: "5.2.2";
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* Default CDN URL for the GLB asset bundle (`beckhoff-xts-viewer-3d-assets`).
|
|
@@ -35,273 +35,14 @@ declare const VERSION: "5.2.0";
|
|
|
35
35
|
declare const JSDELIVR_ASSETS_BASE_URL: "https://cdn.jsdelivr.net/npm/beckhoff-xts-viewer-3d-assets@2.0.1/models";
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
* Everything here is expressed in the viewer's WORLD frame — millimetres,
|
|
41
|
-
* Z-up, identical to `XtsViewer3DRef.getMoverWorldTransform()` and
|
|
42
|
-
* `CameraState.positionMm`. That is what makes one implementation serve both
|
|
43
|
-
* the perspective 3D view and the orthographic 2D plan view
|
|
44
|
-
* (`projection='orthographic'`): only the camera differs, the geometry does
|
|
45
|
-
* not.
|
|
46
|
-
*/
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* How a measurement point was derived. `'free'` is the raw ray hit (surface
|
|
50
|
-
* or ground plane); everything else is a snap the picker resolved to.
|
|
51
|
-
*/
|
|
52
|
-
type SnapKind = 'free' | 'vertex' | 'edge-midpoint' | 'face-center' | 'grid' | 'mover-center' | 'module-boundary' | 'module-center' | 'station-stop' | 'track-path';
|
|
53
|
-
/** Scene entity a picked point belongs to, when the picker could resolve one. */
|
|
54
|
-
type MeasuredEntityRef = {
|
|
55
|
-
kind: 'module';
|
|
56
|
-
ref: ModuleRef;
|
|
57
|
-
} | {
|
|
58
|
-
kind: 'mover';
|
|
59
|
-
ref: MoverRef;
|
|
60
|
-
} | {
|
|
61
|
-
kind: 'station';
|
|
62
|
-
stationId: number;
|
|
63
|
-
};
|
|
64
|
-
/** A position on a part's track path, in the XPU's user position frame. */
|
|
65
|
-
interface TrackAnchor {
|
|
66
|
-
processingUnitObjectId: number;
|
|
67
|
-
/** `PartConfig.objectId`. */
|
|
68
|
-
partObjectId: number;
|
|
69
|
-
/** Position along the part, user frame (same convention as movers). */
|
|
70
|
-
partPositionMm: number;
|
|
71
|
-
}
|
|
72
|
-
/** One measurement vertex. */
|
|
73
|
-
interface MeasurementPoint {
|
|
74
|
-
/** World position (mm). */
|
|
75
|
-
positionMm: Vec3;
|
|
76
|
-
/** How the point was obtained. Default `'free'` when omitted. */
|
|
77
|
-
snap?: SnapKind;
|
|
78
|
-
/** Entity the point sits on, when known. */
|
|
79
|
-
entity?: MeasuredEntityRef;
|
|
80
|
-
/**
|
|
81
|
-
* Track position, set whenever the point resolved onto a part's path.
|
|
82
|
-
* Required on both endpoints of a `'trackDistance'` measurement.
|
|
83
|
-
*/
|
|
84
|
-
track?: TrackAnchor;
|
|
85
|
-
}
|
|
86
|
-
/** Snapping configuration. */
|
|
87
|
-
interface SnapOptions {
|
|
88
|
-
/** Master switch. Default `true`. */
|
|
89
|
-
enabled?: boolean;
|
|
90
|
-
/**
|
|
91
|
-
* Snap kinds to consider, highest priority first. Default:
|
|
92
|
-
* `['vertex', 'edge-midpoint', 'mover-center', 'module-boundary',
|
|
93
|
-
* 'station-stop', 'track-path', 'face-center']`.
|
|
94
|
-
*/
|
|
95
|
-
kinds?: SnapKind[];
|
|
96
|
-
/** Screen-space radius (px) a candidate must fall within. Default `14`. */
|
|
97
|
-
radiusPx?: number;
|
|
98
|
-
/**
|
|
99
|
-
* Grid step (mm) for the `'grid'` snap, applied to the free hit point when
|
|
100
|
-
* no other candidate matched and `'grid'` is in `kinds`. Default `0` (off).
|
|
101
|
-
*/
|
|
102
|
-
gridMm?: number;
|
|
103
|
-
}
|
|
104
|
-
type MeasurementId = string;
|
|
105
|
-
type MeasurementKind = 'distance' | 'angle' | 'path' | 'trackDistance';
|
|
106
|
-
/** Axis constraint for a distance measurement. */
|
|
107
|
-
type MeasurementAxis = 'free' | 'x' | 'y' | 'z';
|
|
108
|
-
interface MeasurementBase {
|
|
109
|
-
id: MeasurementId;
|
|
110
|
-
/** Optional caption rendered above the value. */
|
|
111
|
-
label?: string;
|
|
112
|
-
/** Overrides `MeasurementStyle.color` for this one measurement. */
|
|
113
|
-
color?: string;
|
|
114
|
-
/** Default `true`. */
|
|
115
|
-
visible?: boolean;
|
|
116
|
-
/** Free-form payload the host can round-trip (never read by the viewer). */
|
|
117
|
-
meta?: Record<string, unknown>;
|
|
118
|
-
}
|
|
119
|
-
/** Straight-line distance between two points. */
|
|
120
|
-
interface DistanceMeasurement extends MeasurementBase {
|
|
121
|
-
kind: 'distance';
|
|
122
|
-
points: [MeasurementPoint, MeasurementPoint];
|
|
123
|
-
/** Constrain the reported value to one axis. Default `'free'`. */
|
|
124
|
-
axis?: MeasurementAxis;
|
|
125
|
-
/** Render dashed ΔX / ΔY / ΔZ guides. Default `false`. */
|
|
126
|
-
showComponents?: boolean;
|
|
127
|
-
}
|
|
128
|
-
/** Angle at `points[1]` between the legs to `points[0]` and `points[2]`. */
|
|
129
|
-
interface AngleMeasurement extends MeasurementBase {
|
|
130
|
-
kind: 'angle';
|
|
131
|
-
/** `[legA, vertex, legB]` — the middle point is the vertex. */
|
|
132
|
-
points: [MeasurementPoint, MeasurementPoint, MeasurementPoint];
|
|
133
|
-
}
|
|
134
|
-
/** Polyline through N points; reports per-segment and total length. */
|
|
135
|
-
interface PathMeasurement extends MeasurementBase {
|
|
136
|
-
kind: 'path';
|
|
137
|
-
points: MeasurementPoint[];
|
|
138
|
-
/** Close the polyline back to the first point. Default `false`. */
|
|
139
|
-
closed?: boolean;
|
|
140
|
-
/** Label every segment, not just the total. Default `true`. */
|
|
141
|
-
showSegmentLengths?: boolean;
|
|
142
|
-
}
|
|
143
|
-
/**
|
|
144
|
-
* Distance ALONG the XTS track between two points on the same part — the
|
|
145
|
-
* distance a mover actually travels, not the straight line.
|
|
146
|
-
*/
|
|
147
|
-
interface TrackDistanceMeasurement extends MeasurementBase {
|
|
148
|
-
kind: 'trackDistance';
|
|
149
|
-
points: [MeasurementPoint, MeasurementPoint];
|
|
150
|
-
}
|
|
151
|
-
type Measurement = DistanceMeasurement | AngleMeasurement | PathMeasurement | TrackDistanceMeasurement;
|
|
152
|
-
/** Same as `Measurement`, but the store generates the `id` when omitted. */
|
|
153
|
-
type MeasurementInput = (Omit<DistanceMeasurement, 'id'> & {
|
|
154
|
-
id?: MeasurementId;
|
|
155
|
-
}) | (Omit<AngleMeasurement, 'id'> & {
|
|
156
|
-
id?: MeasurementId;
|
|
157
|
-
}) | (Omit<PathMeasurement, 'id'> & {
|
|
158
|
-
id?: MeasurementId;
|
|
159
|
-
}) | (Omit<TrackDistanceMeasurement, 'id'> & {
|
|
160
|
-
id?: MeasurementId;
|
|
161
|
-
});
|
|
162
|
-
/** Computed value of a measurement. */
|
|
163
|
-
interface MeasurementResult {
|
|
164
|
-
id: MeasurementId;
|
|
165
|
-
kind: MeasurementKind;
|
|
166
|
-
/** Millimetres for lengths, degrees for angles. */
|
|
167
|
-
value: number;
|
|
168
|
-
unit: 'mm' | 'deg';
|
|
169
|
-
/** Formatted value as rendered in the scene (e.g. `'1 234.5 mm'`). */
|
|
170
|
-
text: string;
|
|
171
|
-
/** Signed component deltas — `'distance'` only. */
|
|
172
|
-
deltaMm?: Vec3;
|
|
173
|
-
/** Per-segment lengths — `'path'` only. */
|
|
174
|
-
segmentLengthsMm?: number[];
|
|
175
|
-
/**
|
|
176
|
-
* `true` when the measurement could not be evaluated (e.g. a
|
|
177
|
-
* `trackDistance` whose endpoints sit on different parts). `value` is then
|
|
178
|
-
* the straight-line fallback.
|
|
179
|
-
*/
|
|
180
|
-
incomplete?: boolean;
|
|
181
|
-
}
|
|
182
|
-
/** Where an annotation hangs. Mover anchors follow the live mover position. */
|
|
183
|
-
type AnnotationAnchor = {
|
|
184
|
-
kind: 'world';
|
|
185
|
-
positionMm: Vec3;
|
|
186
|
-
} | {
|
|
187
|
-
kind: 'mover';
|
|
188
|
-
ref: MoverRef;
|
|
189
|
-
} | {
|
|
190
|
-
kind: 'module';
|
|
191
|
-
ref: ModuleRef;
|
|
192
|
-
} | ({
|
|
193
|
-
kind: 'trackPosition';
|
|
194
|
-
} & TrackAnchor);
|
|
195
|
-
interface Annotation {
|
|
196
|
-
id: string;
|
|
197
|
-
text: string;
|
|
198
|
-
anchor: AnnotationAnchor;
|
|
199
|
-
/**
|
|
200
|
-
* Leader-line offset from the anchor to the label (mm, world frame).
|
|
201
|
-
* Default `[0, 0, 250]`.
|
|
202
|
-
*/
|
|
203
|
-
offsetMm?: Vec3;
|
|
204
|
-
color?: string;
|
|
205
|
-
/** Text height (mm). Default `MeasurementStyle.labelSizeMm`. */
|
|
206
|
-
sizeMm?: number;
|
|
207
|
-
/** Marker drawn at the anchor. Default `'Sphere'`. */
|
|
208
|
-
markerShape?: MarkerShape;
|
|
209
|
-
markerSizeMm?: number;
|
|
210
|
-
/** Default `true`. */
|
|
211
|
-
visible?: boolean;
|
|
212
|
-
meta?: Record<string, unknown>;
|
|
213
|
-
}
|
|
214
|
-
type AnnotationInput = Omit<Annotation, 'id'> & {
|
|
215
|
-
id?: string;
|
|
216
|
-
};
|
|
217
|
-
type MeasurementTool = 'none' | 'distance' | 'angle' | 'path' | 'trackDistance' | 'annotation';
|
|
218
|
-
/** In-progress pick. `null` while no tool is armed. */
|
|
219
|
-
interface MeasurementDraft {
|
|
220
|
-
tool: Exclude<MeasurementTool, 'none'>;
|
|
221
|
-
/** Points committed so far. */
|
|
222
|
-
points: MeasurementPoint[];
|
|
223
|
-
/** Point currently under the cursor, or `null` when off the scene. */
|
|
224
|
-
hover: MeasurementPoint | null;
|
|
225
|
-
}
|
|
226
|
-
interface MeasurementStyle {
|
|
227
|
-
/** Line + label colour of committed measurements. Default `'#00E5FF'`. */
|
|
228
|
-
color?: string;
|
|
229
|
-
/** Colour of the in-progress draft. Default `'#FFC400'`. */
|
|
230
|
-
draftColor?: string;
|
|
231
|
-
/** Annotation colour. Default `'#FFFFFF'`. */
|
|
232
|
-
annotationColor?: string;
|
|
233
|
-
/** Line width in pixels. Default `2`. */
|
|
234
|
-
lineWidthPx?: number;
|
|
235
|
-
/** Text height (mm). Default `40`. */
|
|
236
|
-
labelSizeMm?: number;
|
|
237
|
-
/** Endpoint marker diameter (mm). Default `18`. */
|
|
238
|
-
pointSizeMm?: number;
|
|
239
|
-
/** Decimal places on values. Default `1`. */
|
|
240
|
-
decimals?: number;
|
|
241
|
-
/** Unit suffix appended to lengths. Default `' mm'`. */
|
|
242
|
-
unitSuffix?: string;
|
|
243
|
-
/** Font URL passed to troika (see `DEFAULT_LABEL_FONT_URL`). */
|
|
244
|
-
fontFamily?: string;
|
|
245
|
-
/**
|
|
246
|
-
* Draw measurement lines and markers through solid geometry
|
|
247
|
-
* (`depthTest: false`). Default `true` — CAD viewers keep dimensions
|
|
248
|
-
* readable regardless of what is in front of them.
|
|
249
|
-
*/
|
|
250
|
-
alwaysOnTop?: boolean;
|
|
251
|
-
}
|
|
252
|
-
/** Serializable snapshot of everything the measurement feature holds. */
|
|
253
|
-
interface MeasurementDocument {
|
|
254
|
-
schemaVersion: 1;
|
|
255
|
-
measurements: Measurement[];
|
|
256
|
-
annotations: Annotation[];
|
|
257
|
-
}
|
|
258
|
-
/**
|
|
259
|
-
* `measurement` prop of `<XtsViewer3D>`. Data can be driven either
|
|
260
|
-
* declaratively (`measurements` / `annotations` — controlled arrays) or
|
|
261
|
-
* imperatively via `viewerRef.current.measurements`. When the controlled
|
|
262
|
-
* arrays are supplied they win on every render, so a host that uses them must
|
|
263
|
-
* persist what the change callbacks report.
|
|
264
|
-
*/
|
|
265
|
-
interface MeasurementOptions {
|
|
266
|
-
/** Armed tool. Default `'none'` — no picking, no cursor change. */
|
|
267
|
-
tool?: MeasurementTool;
|
|
268
|
-
/** Controlled measurement list. Omit to let the viewer keep its own. */
|
|
269
|
-
measurements?: MeasurementInput[];
|
|
270
|
-
/** Controlled annotation list. Omit to let the viewer keep its own. */
|
|
271
|
-
annotations?: AnnotationInput[];
|
|
272
|
-
snap?: SnapOptions;
|
|
273
|
-
style?: MeasurementStyle;
|
|
274
|
-
/**
|
|
275
|
-
* Z of the fallback pick plane (mm) used when the ray misses all geometry,
|
|
276
|
-
* so free space can be measured. Default `0`; `null` disables the fallback.
|
|
277
|
-
*/
|
|
278
|
-
groundPlaneZMm?: number | null;
|
|
279
|
-
/** Fired after every change to the measurement list. */
|
|
280
|
-
onMeasurementsChange?: (measurements: Measurement[], results: MeasurementResult[]) => void;
|
|
281
|
-
/** Fired once when a tool completes a measurement. */
|
|
282
|
-
onMeasurementCreate?: (measurement: Measurement, result: MeasurementResult) => void;
|
|
283
|
-
onAnnotationsChange?: (annotations: Annotation[]) => void;
|
|
284
|
-
onAnnotationCreate?: (annotation: Annotation) => void;
|
|
285
|
-
/** Fired on every draft change (point added, hover moved, cancelled). */
|
|
286
|
-
onDraftChange?: (draft: MeasurementDraft | null) => void;
|
|
287
|
-
/**
|
|
288
|
-
* Text for an annotation the `'annotation'` tool just placed. Return
|
|
289
|
-
* `null` to abort. Default: `'Annotation'`.
|
|
290
|
-
*/
|
|
291
|
-
annotationTextFactory?: (point: MeasurementPoint) => string | null;
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
/**
|
|
295
|
-
* Public type surface for beckhoff-xts-viewer-3d.
|
|
38
|
+
* Catalogue taxonomy — the string unions naming every module, mover, tool and
|
|
39
|
+
* guiding-rail the viewer can render.
|
|
296
40
|
*
|
|
297
|
-
*
|
|
298
|
-
*
|
|
299
|
-
*
|
|
300
|
-
*
|
|
301
|
-
* implementation (`measurement/types.ts`); only the serialized document shows
|
|
302
|
-
* up here, as part of `XtsModelDocument`.
|
|
41
|
+
* These are the identifiers the asset pipeline, the geometry catalogues
|
|
42
|
+
* (`geometry/ModuleCatalog`, `geometry/MoverCatalog`) and the sidecar files
|
|
43
|
+
* all key off, so they are the narrowest and most-depended-on part of the
|
|
44
|
+
* public type surface. Nothing here imports anything.
|
|
303
45
|
*/
|
|
304
|
-
|
|
305
46
|
/** Beckhoff XTS module types supported by the 3D viewer. */
|
|
306
47
|
type ModuleType3D = 'AT2000_0250' | 'AT2001_0250' | 'AT2002_0250' | 'AT2002_0249' | 'AT2002_0249_ZX2002_0001' | 'AT2000_0233' | 'AT2000_0249' | 'AT2100_0250' | 'AT2102_0250' | 'AT2020_0250' | 'AT2021_0250' | 'AT2025_0250' | 'AT2026_0250' | 'AT2040_0250' | 'AT2041_0250' | 'AT2042_0250' | 'AT2140_0250' | 'AT2050_0500' | 'AT2050_0501' | 'AT2050_0500_180' | 'AT2200_0500' | 'AT2202_0500' | 'ATH2000_0250' | 'ATH2001_0250' | 'ATH2002_0250' | 'ATH2020_0250' | 'ATH2040_0250' | 'ATH2041_0250' | 'ATH2042_0250' | 'ATH2050_0500' | 'ATH2050_0501' | 'ATH2050_0500_180';
|
|
307
48
|
/**
|
|
@@ -343,313 +84,28 @@ type MoverToolType3D = 'AT8200_1000_0100' | 'AT8200_2000_0100' | 'Custom';
|
|
|
343
84
|
* GLB and therefore do NOT receive a separate guiding-rail mesh.
|
|
344
85
|
*/
|
|
345
86
|
type RailType3D = 'AT9000_0249' | 'AT9000_0250' | 'AT9000_0500' | 'AT9020_1250' | 'AT9025_1466' | 'AT9040_0750' | 'AT9050_0500';
|
|
346
|
-
|
|
347
|
-
type Vec2 = [number, number];
|
|
348
|
-
/** Pose of the entire XTS group in the world frame. */
|
|
349
|
-
interface Orientation {
|
|
350
|
-
positionMm?: Vec3;
|
|
351
|
-
/** Intrinsic XYZ Euler angles in degrees. */
|
|
352
|
-
rotationDegEuler?: Vec3;
|
|
353
|
-
}
|
|
354
|
-
/**
|
|
355
|
-
* Per-part heatmap samples plus colour range. Rendered as a coloured
|
|
356
|
-
* tube running along each part's centerline (with optional lateral /
|
|
357
|
-
* vertical offset), with the tube's vertex colours interpolated between
|
|
358
|
-
* `minColor` and `maxColor` according to the consumer-supplied
|
|
359
|
-
* `(positionMm, value)` samples.
|
|
360
|
-
*
|
|
361
|
-
* Typical use: per-stator drive current, motor temperature, or fault
|
|
362
|
-
* counters streamed from the controller and overlaid on the layout in
|
|
363
|
-
* real time. Sample positions are interpreted in the XPU's user-frame
|
|
364
|
-
* (`ProcessingUnitConfig.positionFrame`), same convention as mover /
|
|
365
|
-
* station / area positions.
|
|
366
|
-
*/
|
|
367
|
-
interface StatorHeatmap {
|
|
368
|
-
/**
|
|
369
|
-
* One bucket per `PartConfig.globalNumber`. Parts not listed render
|
|
370
|
-
* no heatmap. Samples within a part are sorted by `positionMm`
|
|
371
|
-
* before interpolation; values between consecutive samples are
|
|
372
|
-
* linearly interpolated, values outside the sample range are
|
|
373
|
-
* held flat at the nearest sample.
|
|
374
|
-
*/
|
|
375
|
-
parts: Array<{
|
|
376
|
-
partOid: number;
|
|
377
|
-
samples: Array<{
|
|
378
|
-
positionMm: number;
|
|
379
|
-
value: number;
|
|
380
|
-
}>;
|
|
381
|
-
}>;
|
|
382
|
-
/** Value mapped to `minColor`. Values ≤ min clamp to `minColor`. */
|
|
383
|
-
min: number;
|
|
384
|
-
/** Value mapped to `maxColor`. Values ≥ max clamp to `maxColor`. */
|
|
385
|
-
max: number;
|
|
386
|
-
/** Colour at `min`. Default `'#22c55e'` (green). */
|
|
387
|
-
minColor?: string;
|
|
388
|
-
/** Colour at `max`. Default `'#ef4444'` (red). */
|
|
389
|
-
maxColor?: string;
|
|
390
|
-
/** Tube thickness in mm. Default 6. */
|
|
391
|
-
thicknessMm?: number;
|
|
392
|
-
/** Vertical Z lift (mm). Default -15 — sits just below the rail. */
|
|
393
|
-
displacementMm?: number;
|
|
394
|
-
/** Lateral Y displacement (mm). Default 0. */
|
|
395
|
-
lateralDisplacementMm?: number;
|
|
396
|
-
/**
|
|
397
|
-
* Path segments per module along the heatmap tube. More = smoother
|
|
398
|
-
* gradient, more triangles. Default 8 (= 32 segments on a 4-module
|
|
399
|
-
* straight, ~1 GPU vertex per 8 mm of track).
|
|
400
|
-
*/
|
|
401
|
-
segmentsPerModule?: number;
|
|
402
|
-
/** Tube opacity (0..1). Default 0.85. */
|
|
403
|
-
opacity?: number;
|
|
404
|
-
}
|
|
405
|
-
interface XtsConfig {
|
|
406
|
-
orientation?: Orientation;
|
|
407
|
-
processingUnits: ProcessingUnitConfig[];
|
|
408
|
-
stations?: StationConfig[];
|
|
409
|
-
/**
|
|
410
|
-
* Labelled regions along the track. Like a StationConfig, but
|
|
411
|
-
* without stop positions — only a coloured tube segment plus an
|
|
412
|
-
* optional description billboard. For zone markings (e.g. "Manual
|
|
413
|
-
* Access", "Safety Area", "Cleanroom") that have no
|
|
414
|
-
* machine stops.
|
|
415
|
-
*/
|
|
416
|
-
areas?: AreaConfig[];
|
|
417
|
-
infoBars?: InfoBarConfig[];
|
|
418
|
-
customAssets?: CustomAssetConfig[];
|
|
419
|
-
}
|
|
420
|
-
interface ProcessingUnitConfig {
|
|
421
|
-
/**
|
|
422
|
-
* Stable host-supplied 32-bit unique identifier for this XPU. Required
|
|
423
|
-
* at runtime — must be a non-negative integer that fits in a uint32
|
|
424
|
-
* and is unique across all XPUs in the config.
|
|
425
|
-
*/
|
|
426
|
-
objectId: number;
|
|
427
|
-
moverType: MoverType3D;
|
|
428
|
-
customMoverLayout?: CustomMoverLayout;
|
|
429
|
-
/** Default: 'Beckhoff'. */
|
|
430
|
-
railSystem?: RailSystem;
|
|
431
|
-
parts: PartConfig[];
|
|
432
|
-
movers: MoverConfig[];
|
|
433
|
-
/**
|
|
434
|
-
* Track-level pose, applied to the entire XPU subtree (modules, movers,
|
|
435
|
-
* tools, stations, info bars, mover-bound custom assets). Composes
|
|
436
|
-
* MULTIPLICATIVELY with the root `XtsConfig.orientation`:
|
|
437
|
-
*
|
|
438
|
-
* world = orientation ⊗ trackTransform ⊗ partTransformation ⊗ chain
|
|
439
|
-
*
|
|
440
|
-
* `scaleUniform` is applied as a uniform scale factor (default 1). Non-
|
|
441
|
-
* uniform scaling is intentionally not supported — it would distort path
|
|
442
|
-
* radii and break GLB lighting.
|
|
443
|
-
*/
|
|
444
|
-
trackTransform?: TrackTransform;
|
|
445
|
-
/**
|
|
446
|
-
* User-frame remap applied to every `partPositionMm`-style value inside
|
|
447
|
-
* this XPU (mover positions, station start/end/stops, area start/end,
|
|
448
|
-
* stop-position ghost movers). Lets a host that uses a different "zero"
|
|
449
|
-
* or sign convention than the GLB chain enter positions in their own
|
|
450
|
-
* frame; the renderer translates to the chain's intrinsic frame:
|
|
451
|
-
*
|
|
452
|
-
* chainPos = originMm + (direction === 'negative' ? -userPos : userPos)
|
|
453
|
-
*
|
|
454
|
-
* Defaults: `direction: 'positive'`, `originMm: 0` — i.e. user-frame
|
|
455
|
-
* equals chain-frame, no transform.
|
|
456
|
-
*/
|
|
457
|
-
positionFrame?: PositionFrame;
|
|
458
|
-
}
|
|
459
|
-
/**
|
|
460
|
-
* Sign + zero-offset convention for partPosition values within an XPU.
|
|
461
|
-
* See `ProcessingUnitConfig.positionFrame` for semantics.
|
|
462
|
-
*/
|
|
463
|
-
interface PositionFrame {
|
|
464
|
-
/** Travel direction. Default: `'positive'`. */
|
|
465
|
-
direction?: 'positive' | 'negative';
|
|
466
|
-
/** Zero-point shift (in chain-coordinates mm). Default: 0. */
|
|
467
|
-
originMm?: number;
|
|
468
|
-
}
|
|
469
|
-
interface TrackTransform {
|
|
470
|
-
positionMm?: Vec3;
|
|
471
|
-
/** Intrinsic XYZ Euler angles in degrees. */
|
|
472
|
-
rotationDegEuler?: Vec3;
|
|
473
|
-
/** Uniform scale factor. Default 1. */
|
|
474
|
-
scaleUniform?: number;
|
|
475
|
-
/** Hide the entire XPU when false. Default true. */
|
|
476
|
-
visible?: boolean;
|
|
477
|
-
}
|
|
478
|
-
interface PartConfig {
|
|
479
|
-
/**
|
|
480
|
-
* Stable host-supplied 32-bit unique identifier for this part. Distinct
|
|
481
|
-
* from `globalNumber` (server-side ObjectId): callers reference parts
|
|
482
|
-
* by `objectId` at runtime — e.g. in the array form of
|
|
483
|
-
* `XtsViewer3DRef.setMoverPositions` (`{partObjectId, partPosition}`).
|
|
484
|
-
* Required at runtime — must be a non-negative integer that fits in a
|
|
485
|
-
* uint32 and is unique across all parts in the system.
|
|
486
|
-
* `normalizeXtsConfig` emits a `missing-part-object-id` /
|
|
487
|
-
* `invalid-part-object-id` / `duplicate-part-object-id` warning when
|
|
488
|
-
* the contract is violated.
|
|
489
|
-
*/
|
|
490
|
-
objectId: number;
|
|
491
|
-
/** = ServerTypes.PartModel.ObjectId — unique system-wide. */
|
|
492
|
-
globalNumber: number;
|
|
493
|
-
modules: ModuleEntry[];
|
|
494
|
-
partTransformation?: PartTransformation;
|
|
495
|
-
}
|
|
496
|
-
interface ModuleEntry {
|
|
497
|
-
moduleType: ModuleType3D;
|
|
498
|
-
/**
|
|
499
|
-
* Stable host-supplied number for this module. Required at runtime —
|
|
500
|
-
* simply counted up per module (1, 2, 3, …) across the whole system
|
|
501
|
-
* and used as the index in `XtsViewer3DRef.setModuleStatuses(array)` —
|
|
502
|
-
* i.e. `statuses[m.globalNumber] === { warning?: …, error?: … }`.
|
|
503
|
-
* `normalizeXtsConfig` emits a `missing-module-global-number` /
|
|
504
|
-
* `invalid-module-global-number` / `duplicate-module-global-number`
|
|
505
|
-
* warning when the contract is violated. Typed optional only so
|
|
506
|
-
* legacy configs and tests keep compiling; new code MUST set it.
|
|
507
|
-
*/
|
|
508
|
-
globalNumber?: number;
|
|
509
|
-
/**
|
|
510
|
-
* Optional drive-status overlay for this module. Mirrors the
|
|
511
|
-
* `MoverConfig.status` shape; the same per-mesh emissive blink +
|
|
512
|
-
* billboard <DriveStatusIcon> surfaces both. Filtered by
|
|
513
|
-
* `display.showDriveWarnings` / `display.showDriveErrors`.
|
|
514
|
-
*
|
|
515
|
-
* For live updates (e.g. drive warnings/errors streamed from PLC),
|
|
516
|
-
* prefer the imperative
|
|
517
|
-
* `XtsViewer3DRef.setModuleStatuses(array)` channel — index = this
|
|
518
|
-
* module's `globalNumber`. The store wins over this config-time value.
|
|
519
|
-
*/
|
|
520
|
-
status?: {
|
|
521
|
-
warning?: boolean;
|
|
522
|
-
error?: boolean;
|
|
523
|
-
};
|
|
524
|
-
}
|
|
87
|
+
|
|
525
88
|
/**
|
|
526
|
-
*
|
|
527
|
-
* modules, guiding rails, movers, mover tools, mover-bound custom assets,
|
|
528
|
-
* and the path-derived overlays (stations, areas, dimensions, info bars,
|
|
529
|
-
* stop-position ghost movers, stator heatmap). Composes inside the
|
|
530
|
-
* per-XPU `trackTransform`:
|
|
531
|
-
*
|
|
532
|
-
* world = orientation ⊗ trackTransform ⊗ partTransformation ⊗ chain
|
|
533
|
-
*
|
|
534
|
-
* All fields are optional and default to identity (offset = [0,0,0],
|
|
535
|
-
* rotation = [0,0,0]). Whole-track placement is done via
|
|
536
|
-
* `ProcessingUnitConfig.trackTransform`; this transform is for moving a
|
|
537
|
-
* part WITHIN its XPU — e.g. lifts that translate along Z, parts
|
|
538
|
-
* mounted at an angle, or live-editable kinematics in the playground.
|
|
89
|
+
* Scalar tuples shared by every other type module.
|
|
539
90
|
*
|
|
540
|
-
*
|
|
541
|
-
*
|
|
542
|
-
*
|
|
543
|
-
*
|
|
544
|
-
* overlays to the part you want them to track.
|
|
91
|
+
* The leaf of the type graph: `Vec3` is a position or an Euler triple in
|
|
92
|
+
* millimetres / degrees, `Vec2` a viewport or margin pair in pixels. Kept
|
|
93
|
+
* apart from the layout types so `display`, `annotations` and `config` can
|
|
94
|
+
* all reach them without importing each other.
|
|
545
95
|
*/
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
index: number;
|
|
558
|
-
/**
|
|
559
|
-
* Stable host-supplied 32-bit unique identifier for this mover.
|
|
560
|
-
* Required, must be a non-negative integer that fits in a uint32 and
|
|
561
|
-
* is unique across all movers in the config.
|
|
562
|
-
*/
|
|
563
|
-
id: number;
|
|
564
|
-
/** References PartConfig.globalNumber. */
|
|
565
|
-
partOid: number;
|
|
566
|
-
/** [0, part.trackLengthMm] — clamped when out-of-bounds. */
|
|
567
|
-
partPositionMm: number;
|
|
568
|
-
status?: {
|
|
569
|
-
warning?: boolean;
|
|
570
|
-
error?: boolean;
|
|
571
|
-
};
|
|
572
|
-
selected?: boolean;
|
|
573
|
-
/** Predefined tool carriers or custom GLBs attached to this mover. */
|
|
574
|
-
tools?: MoverToolConfig[];
|
|
575
|
-
}
|
|
576
|
-
/**
|
|
577
|
-
* Runtime mover-position update entry — pushed through
|
|
578
|
-
* `XtsViewer3DRef.setMoverPositions(array)`. The array is indexed by
|
|
579
|
-
* `MoverConfig.index` (i.e. entry `i` targets the mover with
|
|
580
|
-
* `index === i`); use `null` / `undefined` to skip a slot. The
|
|
581
|
-
* `partObjectId` field references `PartConfig.objectId`.
|
|
582
|
-
*/
|
|
583
|
-
interface MoverPositionEntry {
|
|
584
|
-
/** = PartConfig.objectId (the host-side 32-bit unique part ID). */
|
|
585
|
-
partObjectId: number;
|
|
586
|
-
/** Position along the referenced part, in user-frame mm. */
|
|
587
|
-
partPosition: number;
|
|
588
|
-
}
|
|
589
|
-
/**
|
|
590
|
-
* Runtime drive-status entry for a single module — pushed through
|
|
591
|
-
* `XtsViewer3DRef.setModuleStatuses(array)`. The array is indexed by
|
|
592
|
-
* `ModuleEntry.globalNumber`; use `null` / `undefined` to clear a slot.
|
|
96
|
+
type Vec3 = [number, number, number];
|
|
97
|
+
type Vec2 = [number, number];
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Display options — how a layout is drawn, as opposed to what it is.
|
|
101
|
+
*
|
|
102
|
+
* Everything reachable from the `display` prop: visibility toggles, lighting
|
|
103
|
+
* and post-processing, and the per-overlay styling blocks (`StationOptions`,
|
|
104
|
+
* `AreaOptions`, `DimensionOptions`, …). The overlays these style are declared
|
|
105
|
+
* as configuration in `annotations.ts`; nothing here changes the layout, only
|
|
106
|
+
* its appearance.
|
|
593
107
|
*/
|
|
594
|
-
|
|
595
|
-
warning?: boolean;
|
|
596
|
-
error?: boolean;
|
|
597
|
-
}
|
|
598
|
-
interface MoverToolConfig {
|
|
599
|
-
toolType: MoverToolType3D;
|
|
600
|
-
/** Required when toolType === 'Custom'. */
|
|
601
|
-
customGlbUrl?: string;
|
|
602
|
-
customOriginCorrection?: {
|
|
603
|
-
translateMm: Vec3;
|
|
604
|
-
rotationDegEuler: Vec3;
|
|
605
|
-
};
|
|
606
|
-
/** Local placement on the mover, relative to the magnet-plate center. */
|
|
607
|
-
offsetMm?: Vec3;
|
|
608
|
-
rotationDegEuler?: Vec3;
|
|
609
|
-
opacity?: number;
|
|
610
|
-
visible?: boolean;
|
|
611
|
-
id?: string;
|
|
612
|
-
}
|
|
613
|
-
interface CustomMoverLayout {
|
|
614
|
-
glbUrl: string;
|
|
615
|
-
originCorrection?: {
|
|
616
|
-
translateMm: Vec3;
|
|
617
|
-
rotationDegEuler: Vec3;
|
|
618
|
-
};
|
|
619
|
-
magnetPlateCenterMm?: Vec3;
|
|
620
|
-
pathLengthMm?: number;
|
|
621
|
-
imageFrontUrl?: string;
|
|
622
|
-
imageBackUrl?: string;
|
|
623
|
-
}
|
|
624
|
-
type CustomAssetBinding = {
|
|
625
|
-
type: 'static';
|
|
626
|
-
positionMm: Vec3;
|
|
627
|
-
rotationDegEuler: Vec3;
|
|
628
|
-
scale?: number;
|
|
629
|
-
} | {
|
|
630
|
-
type: 'mover';
|
|
631
|
-
moverRef: {
|
|
632
|
-
processingUnitObjectId: number;
|
|
633
|
-
moverIndex: number;
|
|
634
|
-
};
|
|
635
|
-
offsetMm?: Vec3;
|
|
636
|
-
rotationDegEuler?: Vec3;
|
|
637
|
-
/** Uniform scale (default 1). */
|
|
638
|
-
scale?: number;
|
|
639
|
-
} | {
|
|
640
|
-
type: 'all-movers';
|
|
641
|
-
offsetMm?: Vec3;
|
|
642
|
-
rotationDegEuler?: Vec3;
|
|
643
|
-
/** Uniform scale (default 1). Applied per mover. */
|
|
644
|
-
scale?: number;
|
|
645
|
-
};
|
|
646
|
-
interface CustomAssetConfig {
|
|
647
|
-
id: string;
|
|
648
|
-
glbUrl: string;
|
|
649
|
-
binding: CustomAssetBinding;
|
|
650
|
-
opacity?: number;
|
|
651
|
-
visible?: boolean;
|
|
652
|
-
}
|
|
108
|
+
|
|
653
109
|
/**
|
|
654
110
|
* Y-axis / rotation convention for incoming position data.
|
|
655
111
|
*
|
|
@@ -1024,101 +480,436 @@ interface DimensionOptions {
|
|
|
1024
480
|
* Whether intermediate ticks also get value labels. Only applies when
|
|
1025
481
|
* `showValues` is true. Default: true.
|
|
1026
482
|
*/
|
|
1027
|
-
showIntermediateValues?: boolean;
|
|
483
|
+
showIntermediateValues?: boolean;
|
|
484
|
+
/**
|
|
485
|
+
* What number to display next to each tick:
|
|
486
|
+
* - 'partPosition' (default): cumulative mm from the part's start.
|
|
487
|
+
* - 'fromModule' : mm from the start of the containing module.
|
|
488
|
+
* - 'both' : "<part> mm (<module> mm)".
|
|
489
|
+
*/
|
|
490
|
+
valueMode?: 'partPosition' | 'fromModule' | 'both';
|
|
491
|
+
}
|
|
492
|
+
interface InfoBarOptions {
|
|
493
|
+
defaultThicknessMm?: number;
|
|
494
|
+
textOptions?: TextOptions;
|
|
495
|
+
}
|
|
496
|
+
interface TextOptions {
|
|
497
|
+
sizeMm?: number;
|
|
498
|
+
color?: string;
|
|
499
|
+
fontFamily?: string;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* Track annotations — stations, areas and info bars.
|
|
504
|
+
*
|
|
505
|
+
* Regions and labels a host places along the track. They are configuration,
|
|
506
|
+
* not geometry: each is anchored to part object ids and positions on those
|
|
507
|
+
* parts, and the renderer resolves them against the built chain. How they are
|
|
508
|
+
* styled lives in `display.ts`.
|
|
509
|
+
*/
|
|
510
|
+
|
|
511
|
+
interface StationConfig {
|
|
512
|
+
stationId: number;
|
|
513
|
+
description: string;
|
|
514
|
+
isEnabled: boolean;
|
|
515
|
+
partOids: number[];
|
|
516
|
+
startPositionOnPart: number;
|
|
517
|
+
endPositionOnPart: number;
|
|
518
|
+
/** ARGB int (same as 2D). */
|
|
519
|
+
stationColor: number;
|
|
520
|
+
stopPositions?: number[];
|
|
521
|
+
/**
|
|
522
|
+
* Reference frame for `stopPositions` values:
|
|
523
|
+
* - `'track'` (default) — values are absolute partPositionMm from
|
|
524
|
+
* track start. Same convention as
|
|
525
|
+
* `startPositionOnPart` / `endPositionOnPart`.
|
|
526
|
+
* - `'station'` — values are RELATIVE to `startPositionOnPart`. So
|
|
527
|
+
* `0` puts a stop right at the station's start;
|
|
528
|
+
* `100` puts one 100 mm into the station regardless
|
|
529
|
+
* of where the station lives on the part.
|
|
530
|
+
*
|
|
531
|
+
* Useful when stops are conceptually tied to the station's geometry
|
|
532
|
+
* (entry, mid, exit) rather than absolute mm marks on the track.
|
|
533
|
+
*/
|
|
534
|
+
stopPositionsRelativeTo?: 'track' | 'station';
|
|
535
|
+
/**
|
|
536
|
+
* Per-station override of the stop-marker geometry. Falls back to
|
|
537
|
+
* `display.stationMarkerOptions.shape` when omitted. Lets one station
|
|
538
|
+
* render Diamonds while a neighbour uses Cones, etc.
|
|
539
|
+
*/
|
|
540
|
+
stopMarkerShape?: MarkerShape;
|
|
541
|
+
/** Per-station override of the stop-marker size (mm). */
|
|
542
|
+
stopMarkerSizeMm?: number;
|
|
543
|
+
}
|
|
544
|
+
/**
|
|
545
|
+
* Labelled region along the track. Identical to
|
|
546
|
+
* `StationConfig`, but without stop positions — areas only carry text +
|
|
547
|
+
* colour and describe a zone (e.g. "Cleanroom", "Manual Access",
|
|
548
|
+
* "Safety Loop") that does not trigger machine stops.
|
|
549
|
+
*
|
|
550
|
+
* Multi-part: same semantics as `StationConfig.partOids`. With a single
|
|
551
|
+
* partOid and `endPositionOnPart < startPositionOnPart`, a closed loop
|
|
552
|
+
* is rendered (to the end of the track, then from 0 to End).
|
|
553
|
+
*/
|
|
554
|
+
interface AreaConfig {
|
|
555
|
+
areaId: number;
|
|
556
|
+
description: string;
|
|
557
|
+
isEnabled: boolean;
|
|
558
|
+
partOids: number[];
|
|
559
|
+
startPositionOnPart: number;
|
|
560
|
+
endPositionOnPart: number;
|
|
561
|
+
/** ARGB int (same as StationConfig). Used for tube + default label. */
|
|
562
|
+
color: number;
|
|
563
|
+
}
|
|
564
|
+
interface InfoBarConfig {
|
|
565
|
+
processingUnitObjectId: number;
|
|
566
|
+
partObjectId: number;
|
|
567
|
+
partStartPositionMm: number;
|
|
568
|
+
partEndPositionMm: number;
|
|
569
|
+
thickness: number;
|
|
570
|
+
displacement: number;
|
|
571
|
+
color: {
|
|
572
|
+
color: string;
|
|
573
|
+
};
|
|
574
|
+
visible: boolean;
|
|
575
|
+
text?: string;
|
|
576
|
+
textPlacement?: 'Left' | 'Center' | 'Right';
|
|
577
|
+
textDisplacement?: number;
|
|
578
|
+
textOptions?: TextOptions;
|
|
579
|
+
markers?: InfoBarMarkerConfig[];
|
|
580
|
+
zIndex: number;
|
|
581
|
+
}
|
|
582
|
+
interface InfoBarMarkerConfig {
|
|
583
|
+
positionMm: number;
|
|
584
|
+
shape: 'Diamond' | 'Tick' | 'None';
|
|
585
|
+
sizeMm: number;
|
|
586
|
+
color?: string;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
/**
|
|
590
|
+
* The configuration tree — what a host hands `<XtsViewer3D config={...}>`.
|
|
591
|
+
*
|
|
592
|
+
* `XtsConfig` down through processing units, parts, modules and movers: the
|
|
593
|
+
* description of a physical layout, independent of how it is drawn. Rendering
|
|
594
|
+
* preferences live in `display.ts`, and the overlays placed on top of a layout
|
|
595
|
+
* (stations, areas, info bars) in `annotations.ts`.
|
|
596
|
+
*/
|
|
597
|
+
|
|
598
|
+
/** Pose of the entire XTS group in the world frame. */
|
|
599
|
+
interface Orientation {
|
|
600
|
+
positionMm?: Vec3;
|
|
601
|
+
/** Intrinsic XYZ Euler angles in degrees. */
|
|
602
|
+
rotationDegEuler?: Vec3;
|
|
603
|
+
}
|
|
604
|
+
/**
|
|
605
|
+
* Per-part heatmap samples plus colour range. Rendered as a coloured
|
|
606
|
+
* tube running along each part's centerline (with optional lateral /
|
|
607
|
+
* vertical offset), with the tube's vertex colours interpolated between
|
|
608
|
+
* `minColor` and `maxColor` according to the consumer-supplied
|
|
609
|
+
* `(positionMm, value)` samples.
|
|
610
|
+
*
|
|
611
|
+
* Typical use: per-stator drive current, motor temperature, or fault
|
|
612
|
+
* counters streamed from the controller and overlaid on the layout in
|
|
613
|
+
* real time. Sample positions are interpreted in the XPU's user-frame
|
|
614
|
+
* (`ProcessingUnitConfig.positionFrame`), same convention as mover /
|
|
615
|
+
* station / area positions.
|
|
616
|
+
*/
|
|
617
|
+
interface StatorHeatmap {
|
|
618
|
+
/**
|
|
619
|
+
* One bucket per `PartConfig.globalNumber`. Parts not listed render
|
|
620
|
+
* no heatmap. Samples within a part are sorted by `positionMm`
|
|
621
|
+
* before interpolation; values between consecutive samples are
|
|
622
|
+
* linearly interpolated, values outside the sample range are
|
|
623
|
+
* held flat at the nearest sample.
|
|
624
|
+
*/
|
|
625
|
+
parts: Array<{
|
|
626
|
+
partOid: number;
|
|
627
|
+
samples: Array<{
|
|
628
|
+
positionMm: number;
|
|
629
|
+
value: number;
|
|
630
|
+
}>;
|
|
631
|
+
}>;
|
|
632
|
+
/** Value mapped to `minColor`. Values ≤ min clamp to `minColor`. */
|
|
633
|
+
min: number;
|
|
634
|
+
/** Value mapped to `maxColor`. Values ≥ max clamp to `maxColor`. */
|
|
635
|
+
max: number;
|
|
636
|
+
/** Colour at `min`. Default `'#22c55e'` (green). */
|
|
637
|
+
minColor?: string;
|
|
638
|
+
/** Colour at `max`. Default `'#ef4444'` (red). */
|
|
639
|
+
maxColor?: string;
|
|
640
|
+
/** Tube thickness in mm. Default 6. */
|
|
641
|
+
thicknessMm?: number;
|
|
642
|
+
/** Vertical Z lift (mm). Default -15 — sits just below the rail. */
|
|
643
|
+
displacementMm?: number;
|
|
644
|
+
/** Lateral Y displacement (mm). Default 0. */
|
|
645
|
+
lateralDisplacementMm?: number;
|
|
646
|
+
/**
|
|
647
|
+
* Path segments per module along the heatmap tube. More = smoother
|
|
648
|
+
* gradient, more triangles. Default 8 (= 32 segments on a 4-module
|
|
649
|
+
* straight, ~1 GPU vertex per 8 mm of track).
|
|
650
|
+
*/
|
|
651
|
+
segmentsPerModule?: number;
|
|
652
|
+
/** Tube opacity (0..1). Default 0.85. */
|
|
653
|
+
opacity?: number;
|
|
654
|
+
}
|
|
655
|
+
interface XtsConfig {
|
|
656
|
+
orientation?: Orientation;
|
|
657
|
+
processingUnits: ProcessingUnitConfig[];
|
|
658
|
+
stations?: StationConfig[];
|
|
659
|
+
/**
|
|
660
|
+
* Labelled regions along the track. Like a StationConfig, but
|
|
661
|
+
* without stop positions — only a coloured tube segment plus an
|
|
662
|
+
* optional description billboard. For zone markings (e.g. "Manual
|
|
663
|
+
* Access", "Safety Area", "Cleanroom") that have no
|
|
664
|
+
* machine stops.
|
|
665
|
+
*/
|
|
666
|
+
areas?: AreaConfig[];
|
|
667
|
+
infoBars?: InfoBarConfig[];
|
|
668
|
+
customAssets?: CustomAssetConfig[];
|
|
669
|
+
}
|
|
670
|
+
interface ProcessingUnitConfig {
|
|
671
|
+
/**
|
|
672
|
+
* Stable host-supplied 32-bit unique identifier for this XPU. Required
|
|
673
|
+
* at runtime — must be a non-negative integer that fits in a uint32
|
|
674
|
+
* and is unique across all XPUs in the config.
|
|
675
|
+
*/
|
|
676
|
+
objectId: number;
|
|
677
|
+
moverType: MoverType3D;
|
|
678
|
+
customMoverLayout?: CustomMoverLayout;
|
|
679
|
+
/** Default: 'Beckhoff'. */
|
|
680
|
+
railSystem?: RailSystem;
|
|
681
|
+
parts: PartConfig[];
|
|
682
|
+
movers: MoverConfig[];
|
|
683
|
+
/**
|
|
684
|
+
* Track-level pose, applied to the entire XPU subtree (modules, movers,
|
|
685
|
+
* tools, stations, info bars, mover-bound custom assets). Composes
|
|
686
|
+
* MULTIPLICATIVELY with the root `XtsConfig.orientation`:
|
|
687
|
+
*
|
|
688
|
+
* world = orientation ⊗ trackTransform ⊗ partTransformation ⊗ chain
|
|
689
|
+
*
|
|
690
|
+
* `scaleUniform` is applied as a uniform scale factor (default 1). Non-
|
|
691
|
+
* uniform scaling is intentionally not supported — it would distort path
|
|
692
|
+
* radii and break GLB lighting.
|
|
693
|
+
*/
|
|
694
|
+
trackTransform?: TrackTransform;
|
|
1028
695
|
/**
|
|
1029
|
-
*
|
|
1030
|
-
*
|
|
1031
|
-
*
|
|
1032
|
-
*
|
|
696
|
+
* User-frame remap applied to every `partPositionMm`-style value inside
|
|
697
|
+
* this XPU (mover positions, station start/end/stops, area start/end,
|
|
698
|
+
* stop-position ghost movers). Lets a host that uses a different "zero"
|
|
699
|
+
* or sign convention than the GLB chain enter positions in their own
|
|
700
|
+
* frame; the renderer translates to the chain's intrinsic frame:
|
|
701
|
+
*
|
|
702
|
+
* chainPos = originMm + (direction === 'negative' ? -userPos : userPos)
|
|
703
|
+
*
|
|
704
|
+
* Defaults: `direction: 'positive'`, `originMm: 0` — i.e. user-frame
|
|
705
|
+
* equals chain-frame, no transform.
|
|
1033
706
|
*/
|
|
1034
|
-
|
|
707
|
+
positionFrame?: PositionFrame;
|
|
1035
708
|
}
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
709
|
+
/**
|
|
710
|
+
* Sign + zero-offset convention for partPosition values within an XPU.
|
|
711
|
+
* See `ProcessingUnitConfig.positionFrame` for semantics.
|
|
712
|
+
*/
|
|
713
|
+
interface PositionFrame {
|
|
714
|
+
/** Travel direction. Default: `'positive'`. */
|
|
715
|
+
direction?: 'positive' | 'negative';
|
|
716
|
+
/** Zero-point shift (in chain-coordinates mm). Default: 0. */
|
|
717
|
+
originMm?: number;
|
|
1039
718
|
}
|
|
1040
|
-
interface
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
719
|
+
interface TrackTransform {
|
|
720
|
+
positionMm?: Vec3;
|
|
721
|
+
/** Intrinsic XYZ Euler angles in degrees. */
|
|
722
|
+
rotationDegEuler?: Vec3;
|
|
723
|
+
/** Uniform scale factor. Default 1. */
|
|
724
|
+
scaleUniform?: number;
|
|
725
|
+
/** Hide the entire XPU when false. Default true. */
|
|
726
|
+
visible?: boolean;
|
|
1044
727
|
}
|
|
1045
|
-
interface
|
|
1046
|
-
stationId: number;
|
|
1047
|
-
description: string;
|
|
1048
|
-
isEnabled: boolean;
|
|
1049
|
-
partOids: number[];
|
|
1050
|
-
startPositionOnPart: number;
|
|
1051
|
-
endPositionOnPart: number;
|
|
1052
|
-
/** ARGB int (same as 2D). */
|
|
1053
|
-
stationColor: number;
|
|
1054
|
-
stopPositions?: number[];
|
|
728
|
+
interface PartConfig {
|
|
1055
729
|
/**
|
|
1056
|
-
*
|
|
1057
|
-
*
|
|
1058
|
-
*
|
|
1059
|
-
*
|
|
1060
|
-
*
|
|
1061
|
-
*
|
|
1062
|
-
*
|
|
1063
|
-
*
|
|
1064
|
-
*
|
|
1065
|
-
* Useful when stops are conceptually tied to the station's geometry
|
|
1066
|
-
* (entry, mid, exit) rather than absolute mm marks on the track.
|
|
730
|
+
* Stable host-supplied 32-bit unique identifier for this part. Distinct
|
|
731
|
+
* from `globalNumber` (server-side ObjectId): callers reference parts
|
|
732
|
+
* by `objectId` at runtime — e.g. in the array form of
|
|
733
|
+
* `XtsViewer3DRef.setMoverPositions` (`{partObjectId, partPosition}`).
|
|
734
|
+
* Required at runtime — must be a non-negative integer that fits in a
|
|
735
|
+
* uint32 and is unique across all parts in the system.
|
|
736
|
+
* `normalizeXtsConfig` emits a `missing-part-object-id` /
|
|
737
|
+
* `invalid-part-object-id` / `duplicate-part-object-id` warning when
|
|
738
|
+
* the contract is violated.
|
|
1067
739
|
*/
|
|
1068
|
-
|
|
740
|
+
objectId: number;
|
|
741
|
+
/** = ServerTypes.PartModel.ObjectId — unique system-wide. */
|
|
742
|
+
globalNumber: number;
|
|
743
|
+
modules: ModuleEntry[];
|
|
744
|
+
partTransformation?: PartTransformation;
|
|
745
|
+
}
|
|
746
|
+
interface ModuleEntry {
|
|
747
|
+
moduleType: ModuleType3D;
|
|
1069
748
|
/**
|
|
1070
|
-
*
|
|
1071
|
-
*
|
|
1072
|
-
*
|
|
749
|
+
* Stable host-supplied number for this module. Required at runtime —
|
|
750
|
+
* simply counted up per module (1, 2, 3, …) across the whole system
|
|
751
|
+
* and used as the index in `XtsViewer3DRef.setModuleStatuses(array)` —
|
|
752
|
+
* i.e. `statuses[m.globalNumber] === { warning?: …, error?: … }`.
|
|
753
|
+
* `normalizeXtsConfig` emits a `missing-module-global-number` /
|
|
754
|
+
* `invalid-module-global-number` / `duplicate-module-global-number`
|
|
755
|
+
* warning when the contract is violated. Typed optional only so
|
|
756
|
+
* legacy configs and tests keep compiling; new code MUST set it.
|
|
1073
757
|
*/
|
|
1074
|
-
|
|
1075
|
-
/**
|
|
1076
|
-
|
|
758
|
+
globalNumber?: number;
|
|
759
|
+
/**
|
|
760
|
+
* Optional drive-status overlay for this module. Mirrors the
|
|
761
|
+
* `MoverConfig.status` shape; the same per-mesh emissive blink +
|
|
762
|
+
* billboard <DriveStatusIcon> surfaces both. Filtered by
|
|
763
|
+
* `display.showDriveWarnings` / `display.showDriveErrors`.
|
|
764
|
+
*
|
|
765
|
+
* For live updates (e.g. drive warnings/errors streamed from PLC),
|
|
766
|
+
* prefer the imperative
|
|
767
|
+
* `XtsViewer3DRef.setModuleStatuses(array)` channel — index = this
|
|
768
|
+
* module's `globalNumber`. The store wins over this config-time value.
|
|
769
|
+
*/
|
|
770
|
+
status?: {
|
|
771
|
+
warning?: boolean;
|
|
772
|
+
error?: boolean;
|
|
773
|
+
};
|
|
1077
774
|
}
|
|
1078
775
|
/**
|
|
1079
|
-
*
|
|
1080
|
-
*
|
|
1081
|
-
*
|
|
1082
|
-
*
|
|
776
|
+
* Per-part 3D pose, applied to EVERYTHING anchored to the part:
|
|
777
|
+
* modules, guiding rails, movers, mover tools, mover-bound custom assets,
|
|
778
|
+
* and the path-derived overlays (stations, areas, dimensions, info bars,
|
|
779
|
+
* stop-position ghost movers, stator heatmap). Composes inside the
|
|
780
|
+
* per-XPU `trackTransform`:
|
|
1083
781
|
*
|
|
1084
|
-
*
|
|
1085
|
-
*
|
|
1086
|
-
*
|
|
782
|
+
* world = orientation ⊗ trackTransform ⊗ partTransformation ⊗ chain
|
|
783
|
+
*
|
|
784
|
+
* All fields are optional and default to identity (offset = [0,0,0],
|
|
785
|
+
* rotation = [0,0,0]). Whole-track placement is done via
|
|
786
|
+
* `ProcessingUnitConfig.trackTransform`; this transform is for moving a
|
|
787
|
+
* part WITHIN its XPU — e.g. lifts that translate along Z, parts
|
|
788
|
+
* mounted at an angle, or live-editable kinematics in the playground.
|
|
789
|
+
*
|
|
790
|
+
* Multi-part overlays (stations / areas spanning multiple `partOids`)
|
|
791
|
+
* follow the transform of their FIRST partOid — the chain math
|
|
792
|
+
* upstream is part-local, and points from differently-transformed
|
|
793
|
+
* parts can't be stitched into a single tube. Anchor multi-part
|
|
794
|
+
* overlays to the part you want them to track.
|
|
1087
795
|
*/
|
|
1088
|
-
interface
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
color: number;
|
|
796
|
+
interface PartTransformation {
|
|
797
|
+
/** Translation in mm, in the XPU's track-transform frame. */
|
|
798
|
+
offsetMm?: Vec3;
|
|
799
|
+
/** Intrinsic XYZ Euler angles in degrees. */
|
|
800
|
+
rotationDegEuler?: Vec3;
|
|
801
|
+
partSide?: 'Default' | 'Driver' | 'Encoder';
|
|
802
|
+
/** Hide everything on this part when false. Default true. */
|
|
803
|
+
visible?: boolean;
|
|
1097
804
|
}
|
|
1098
|
-
interface
|
|
1099
|
-
|
|
805
|
+
interface MoverConfig {
|
|
806
|
+
/** Position-on-track index within the XPU. */
|
|
807
|
+
index: number;
|
|
808
|
+
/**
|
|
809
|
+
* Stable host-supplied 32-bit unique identifier for this mover.
|
|
810
|
+
* Required, must be a non-negative integer that fits in a uint32 and
|
|
811
|
+
* is unique across all movers in the config.
|
|
812
|
+
*/
|
|
813
|
+
id: number;
|
|
814
|
+
/** References PartConfig.globalNumber. */
|
|
815
|
+
partOid: number;
|
|
816
|
+
/** [0, part.trackLengthMm] — clamped when out-of-bounds. */
|
|
817
|
+
partPositionMm: number;
|
|
818
|
+
status?: {
|
|
819
|
+
warning?: boolean;
|
|
820
|
+
error?: boolean;
|
|
821
|
+
};
|
|
822
|
+
selected?: boolean;
|
|
823
|
+
/** Predefined tool carriers or custom GLBs attached to this mover. */
|
|
824
|
+
tools?: MoverToolConfig[];
|
|
825
|
+
}
|
|
826
|
+
/**
|
|
827
|
+
* Runtime mover-position update entry — pushed through
|
|
828
|
+
* `XtsViewer3DRef.setMoverPositions(array)`. The array is indexed by
|
|
829
|
+
* `MoverConfig.index` (i.e. entry `i` targets the mover with
|
|
830
|
+
* `index === i`); use `null` / `undefined` to skip a slot. The
|
|
831
|
+
* `partObjectId` field references `PartConfig.objectId`.
|
|
832
|
+
*/
|
|
833
|
+
interface MoverPositionEntry {
|
|
834
|
+
/** = PartConfig.objectId (the host-side 32-bit unique part ID). */
|
|
1100
835
|
partObjectId: number;
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
836
|
+
/** Position along the referenced part, in user-frame mm. */
|
|
837
|
+
partPosition: number;
|
|
838
|
+
}
|
|
839
|
+
/**
|
|
840
|
+
* Runtime drive-status entry for a single module — pushed through
|
|
841
|
+
* `XtsViewer3DRef.setModuleStatuses(array)`. The array is indexed by
|
|
842
|
+
* `ModuleEntry.globalNumber`; use `null` / `undefined` to clear a slot.
|
|
843
|
+
*/
|
|
844
|
+
interface ModuleStatusEntry {
|
|
845
|
+
warning?: boolean;
|
|
846
|
+
error?: boolean;
|
|
847
|
+
}
|
|
848
|
+
interface MoverToolConfig {
|
|
849
|
+
toolType: MoverToolType3D;
|
|
850
|
+
/** Required when toolType === 'Custom'. */
|
|
851
|
+
customGlbUrl?: string;
|
|
852
|
+
customOriginCorrection?: {
|
|
853
|
+
translateMm: Vec3;
|
|
854
|
+
rotationDegEuler: Vec3;
|
|
1107
855
|
};
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
zIndex: number;
|
|
856
|
+
/** Local placement on the mover, relative to the magnet-plate center. */
|
|
857
|
+
offsetMm?: Vec3;
|
|
858
|
+
rotationDegEuler?: Vec3;
|
|
859
|
+
opacity?: number;
|
|
860
|
+
visible?: boolean;
|
|
861
|
+
id?: string;
|
|
1115
862
|
}
|
|
1116
|
-
interface
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
863
|
+
interface CustomMoverLayout {
|
|
864
|
+
glbUrl: string;
|
|
865
|
+
originCorrection?: {
|
|
866
|
+
translateMm: Vec3;
|
|
867
|
+
rotationDegEuler: Vec3;
|
|
868
|
+
};
|
|
869
|
+
magnetPlateCenterMm?: Vec3;
|
|
870
|
+
pathLengthMm?: number;
|
|
871
|
+
imageFrontUrl?: string;
|
|
872
|
+
imageBackUrl?: string;
|
|
873
|
+
}
|
|
874
|
+
type CustomAssetBinding = {
|
|
875
|
+
type: 'static';
|
|
876
|
+
positionMm: Vec3;
|
|
877
|
+
rotationDegEuler: Vec3;
|
|
878
|
+
scale?: number;
|
|
879
|
+
} | {
|
|
880
|
+
type: 'mover';
|
|
881
|
+
moverRef: {
|
|
882
|
+
processingUnitObjectId: number;
|
|
883
|
+
moverIndex: number;
|
|
884
|
+
};
|
|
885
|
+
offsetMm?: Vec3;
|
|
886
|
+
rotationDegEuler?: Vec3;
|
|
887
|
+
/** Uniform scale (default 1). */
|
|
888
|
+
scale?: number;
|
|
889
|
+
} | {
|
|
890
|
+
type: 'all-movers';
|
|
891
|
+
offsetMm?: Vec3;
|
|
892
|
+
rotationDegEuler?: Vec3;
|
|
893
|
+
/** Uniform scale (default 1). Applied per mover. */
|
|
894
|
+
scale?: number;
|
|
895
|
+
};
|
|
896
|
+
interface CustomAssetConfig {
|
|
897
|
+
id: string;
|
|
898
|
+
glbUrl: string;
|
|
899
|
+
binding: CustomAssetBinding;
|
|
900
|
+
opacity?: number;
|
|
901
|
+
visible?: boolean;
|
|
1121
902
|
}
|
|
903
|
+
|
|
904
|
+
/**
|
|
905
|
+
* Interaction surface — selection, highlighting and the camera.
|
|
906
|
+
*
|
|
907
|
+
* The types a host exchanges with the viewer at runtime rather than at
|
|
908
|
+
* configuration time: what is addressed (`ModuleRef`, `MoverRef`), what is
|
|
909
|
+
* picked out (`SelectionState`, `ModuleHighlight`, `FeedSegmentHighlight`),
|
|
910
|
+
* and where the camera looks (`CameraState`, `FocusTarget`).
|
|
911
|
+
*/
|
|
912
|
+
|
|
1122
913
|
interface ModuleRef {
|
|
1123
914
|
processingUnitObjectId: number;
|
|
1124
915
|
partObjectId: number;
|
|
@@ -1183,125 +974,412 @@ interface FeedSegmentHighlight {
|
|
|
1183
974
|
color: string;
|
|
1184
975
|
}
|
|
1185
976
|
/**
|
|
1186
|
-
* One feed segment (Einspeisestrang) as detected in the configuration: the
|
|
1187
|
-
* contiguous run of modules starting at an infeed module (Einspeisemodul,
|
|
1188
|
-
* `ModuleCatalogEntry.isInfeed`) and ending right before the next infeed
|
|
1189
|
-
* module of the same part.
|
|
1190
|
-
*
|
|
1191
|
-
* On a closed chain (oval, U-turn pair — see `isChainClosed`) the modules
|
|
1192
|
-
* ahead of the part's first infeed module belong to the LAST segment, which
|
|
1193
|
-
* then carries `wrapsSeam: true`. On an open chain those leading modules
|
|
1194
|
-
* belong to no segment at all and cannot be tinted.
|
|
1195
|
-
*
|
|
1196
|
-
* Returned by `XtsViewer3DRef.getFeedSegments()`.
|
|
977
|
+
* One feed segment (Einspeisestrang) as detected in the configuration: the
|
|
978
|
+
* contiguous run of modules starting at an infeed module (Einspeisemodul,
|
|
979
|
+
* `ModuleCatalogEntry.isInfeed`) and ending right before the next infeed
|
|
980
|
+
* module of the same part.
|
|
981
|
+
*
|
|
982
|
+
* On a closed chain (oval, U-turn pair — see `isChainClosed`) the modules
|
|
983
|
+
* ahead of the part's first infeed module belong to the LAST segment, which
|
|
984
|
+
* then carries `wrapsSeam: true`. On an open chain those leading modules
|
|
985
|
+
* belong to no segment at all and cannot be tinted.
|
|
986
|
+
*
|
|
987
|
+
* Returned by `XtsViewer3DRef.getFeedSegments()`.
|
|
988
|
+
*/
|
|
989
|
+
interface FeedSegment {
|
|
990
|
+
processingUnitObjectId: number;
|
|
991
|
+
partObjectId: number;
|
|
992
|
+
/** 0-based, in chain order, counted from the part's first infeed module. */
|
|
993
|
+
segmentIndex: number;
|
|
994
|
+
/**
|
|
995
|
+
* `ModuleEntry.globalNumber` of the leading infeed module. `undefined` when
|
|
996
|
+
* the config does not set it — such a segment can only be addressed via
|
|
997
|
+
* `{ partObjectId, segmentIndex }`.
|
|
998
|
+
*/
|
|
999
|
+
infeedModuleGlobalNumber?: number;
|
|
1000
|
+
/** Module type of the leading infeed module. */
|
|
1001
|
+
infeedModuleType: ModuleType3D;
|
|
1002
|
+
/** Chain indices of every module in this segment, in chain order. */
|
|
1003
|
+
moduleIndices: number[];
|
|
1004
|
+
/** Σ of the segment's module lengths, in mm. */
|
|
1005
|
+
lengthMm: number;
|
|
1006
|
+
/** True when the segment wraps the closed-loop seam. */
|
|
1007
|
+
wrapsSeam: boolean;
|
|
1008
|
+
}
|
|
1009
|
+
interface CameraState {
|
|
1010
|
+
positionMm: Vec3;
|
|
1011
|
+
targetMm: Vec3;
|
|
1012
|
+
/** Always 'Z' in the current spec. */
|
|
1013
|
+
upAxis: 'Z' | 'Y';
|
|
1014
|
+
zoom?: number;
|
|
1015
|
+
}
|
|
1016
|
+
/**
|
|
1017
|
+
* Live camera projection.
|
|
1018
|
+
* - `'perspective'` (default) — the regular 3D view.
|
|
1019
|
+
* - `'orthographic'` — paired with `topDown`, gives the flat 2D plan view
|
|
1020
|
+
* that matches `exportScreenshot({ mode: 'top-down' })`.
|
|
1021
|
+
*/
|
|
1022
|
+
type CameraProjection = 'perspective' | 'orthographic';
|
|
1023
|
+
/**
|
|
1024
|
+
* Target for the imperative `viewerRef.current.focusOn(target, opts)` camera
|
|
1025
|
+
* animation. The viewer computes the target's world-space bounding box and
|
|
1026
|
+
* flies the camera so the whole object fits the frame:
|
|
1027
|
+
* - In `'perspective'` projection the current view angle is preserved
|
|
1028
|
+
* (the camera only dollies / re-centres).
|
|
1029
|
+
* - In `'orthographic'` top-down the frustum is re-framed and the camera
|
|
1030
|
+
* pans straight over the object.
|
|
1031
|
+
*/
|
|
1032
|
+
type FocusTarget = {
|
|
1033
|
+
kind: 'scene';
|
|
1034
|
+
} | {
|
|
1035
|
+
kind: 'station';
|
|
1036
|
+
stationId: number;
|
|
1037
|
+
} | {
|
|
1038
|
+
kind: 'area';
|
|
1039
|
+
areaId: number;
|
|
1040
|
+
} | {
|
|
1041
|
+
kind: 'mover';
|
|
1042
|
+
ref: MoverRef;
|
|
1043
|
+
} | {
|
|
1044
|
+
kind: 'module';
|
|
1045
|
+
ref: ModuleRef;
|
|
1046
|
+
};
|
|
1047
|
+
interface FocusOptions {
|
|
1048
|
+
/** Animation duration in ms. Default 700. `0` jumps immediately. */
|
|
1049
|
+
durationMs?: number;
|
|
1050
|
+
/**
|
|
1051
|
+
* Padding around the target's bounding box (1 = tight fit). Default 1.2 in
|
|
1052
|
+
* perspective, 1.1 in orthographic top-down.
|
|
1053
|
+
*/
|
|
1054
|
+
paddingFactor?: number;
|
|
1055
|
+
/** Easing curve. Default `'easeInOutCubic'`. */
|
|
1056
|
+
easing?: 'linear' | 'easeInOutCubic';
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
/**
|
|
1060
|
+
* Viewer errors.
|
|
1061
|
+
*
|
|
1062
|
+
* `XtsViewerErrorException` is the one runtime value in the public type
|
|
1063
|
+
* surface — everything else the viewer exports as `types` is erased at
|
|
1064
|
+
* compile time. It is thrown by the normalization pass for configurations
|
|
1065
|
+
* that cannot be rendered at all; recoverable problems are reported through
|
|
1066
|
+
* the `onError` callback as plain `XtsViewerError` records instead.
|
|
1067
|
+
*/
|
|
1068
|
+
type XtsViewerErrorCode = 'asset-load-failed' | 'unknown-module-type' | 'unknown-mover-type' | 'unknown-tool-type' | 'invalid-config' | 'unmatched-clothoid-half' | 'webgl-context-lost';
|
|
1069
|
+
interface XtsViewerError {
|
|
1070
|
+
code: XtsViewerErrorCode;
|
|
1071
|
+
message: string;
|
|
1072
|
+
details?: unknown;
|
|
1073
|
+
}
|
|
1074
|
+
declare class XtsViewerErrorException extends Error {
|
|
1075
|
+
readonly code: XtsViewerErrorCode;
|
|
1076
|
+
readonly details?: unknown;
|
|
1077
|
+
constructor(code: XtsViewerErrorCode, message: string, details?: unknown);
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
/**
|
|
1081
|
+
* Asset manifest — per-type overrides for the GLB URLs the viewer loads.
|
|
1082
|
+
*
|
|
1083
|
+
* A host registers custom or relocated assets here instead of replacing the
|
|
1084
|
+
* whole `assetsBaseUrl`. Entries fall back to the default CDN mapping for any
|
|
1085
|
+
* type they do not name.
|
|
1086
|
+
*/
|
|
1087
|
+
|
|
1088
|
+
interface AssetManifest {
|
|
1089
|
+
/** Override per moduleType. Falls back to default mapping otherwise. */
|
|
1090
|
+
modules?: Partial<Record<ModuleType3D, ModuleAssetEntry>>;
|
|
1091
|
+
movers?: Partial<Record<MoverType3D, MoverAssetEntry>>;
|
|
1092
|
+
tools?: Partial<Record<MoverToolType3D, MoverToolAssetEntry>>;
|
|
1093
|
+
guidingRails?: Partial<Record<RailType3D, RailAssetEntry>>;
|
|
1094
|
+
}
|
|
1095
|
+
interface RailAssetEntry {
|
|
1096
|
+
glbUrl: string;
|
|
1097
|
+
sidecarUrl?: string;
|
|
1098
|
+
}
|
|
1099
|
+
interface ModuleAssetEntry {
|
|
1100
|
+
/** Per-RailSystem GLB URL (relative to assetsBaseUrl). */
|
|
1101
|
+
glbByRailSystem: {
|
|
1102
|
+
Beckhoff: string | null;
|
|
1103
|
+
HepcoGfx?: string | null;
|
|
1104
|
+
};
|
|
1105
|
+
sidecarUrl?: string;
|
|
1106
|
+
}
|
|
1107
|
+
interface MoverAssetEntry {
|
|
1108
|
+
glbUrl: string;
|
|
1109
|
+
sidecarUrl?: string;
|
|
1110
|
+
}
|
|
1111
|
+
interface MoverToolAssetEntry {
|
|
1112
|
+
glbUrl: string;
|
|
1113
|
+
sidecarUrl?: string;
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
/**
|
|
1117
|
+
* Public types for the measurement + annotation feature.
|
|
1118
|
+
*
|
|
1119
|
+
* Everything here is expressed in the viewer's WORLD frame — millimetres,
|
|
1120
|
+
* Z-up, identical to `XtsViewer3DRef.getMoverWorldTransform()` and
|
|
1121
|
+
* `CameraState.positionMm`. That is what makes one implementation serve both
|
|
1122
|
+
* the perspective 3D view and the orthographic 2D plan view
|
|
1123
|
+
* (`projection='orthographic'`): only the camera differs, the geometry does
|
|
1124
|
+
* not.
|
|
1125
|
+
*/
|
|
1126
|
+
|
|
1127
|
+
/**
|
|
1128
|
+
* How a measurement point was derived. `'free'` is the raw ray hit (surface
|
|
1129
|
+
* or ground plane); everything else is a snap the picker resolved to.
|
|
1130
|
+
*/
|
|
1131
|
+
type SnapKind = 'free' | 'vertex' | 'edge-midpoint' | 'face-center' | 'grid' | 'mover-center' | 'module-boundary' | 'module-center' | 'station-stop' | 'track-path';
|
|
1132
|
+
/** Scene entity a picked point belongs to, when the picker could resolve one. */
|
|
1133
|
+
type MeasuredEntityRef = {
|
|
1134
|
+
kind: 'module';
|
|
1135
|
+
ref: ModuleRef;
|
|
1136
|
+
} | {
|
|
1137
|
+
kind: 'mover';
|
|
1138
|
+
ref: MoverRef;
|
|
1139
|
+
} | {
|
|
1140
|
+
kind: 'station';
|
|
1141
|
+
stationId: number;
|
|
1142
|
+
};
|
|
1143
|
+
/** A position on a part's track path, in the XPU's user position frame. */
|
|
1144
|
+
interface TrackAnchor {
|
|
1145
|
+
processingUnitObjectId: number;
|
|
1146
|
+
/** `PartConfig.objectId`. */
|
|
1147
|
+
partObjectId: number;
|
|
1148
|
+
/** Position along the part, user frame (same convention as movers). */
|
|
1149
|
+
partPositionMm: number;
|
|
1150
|
+
}
|
|
1151
|
+
/** One measurement vertex. */
|
|
1152
|
+
interface MeasurementPoint {
|
|
1153
|
+
/** World position (mm). */
|
|
1154
|
+
positionMm: Vec3;
|
|
1155
|
+
/** How the point was obtained. Default `'free'` when omitted. */
|
|
1156
|
+
snap?: SnapKind;
|
|
1157
|
+
/** Entity the point sits on, when known. */
|
|
1158
|
+
entity?: MeasuredEntityRef;
|
|
1159
|
+
/**
|
|
1160
|
+
* Track position, set whenever the point resolved onto a part's path.
|
|
1161
|
+
* Required on both endpoints of a `'trackDistance'` measurement.
|
|
1162
|
+
*/
|
|
1163
|
+
track?: TrackAnchor;
|
|
1164
|
+
}
|
|
1165
|
+
/** Snapping configuration. */
|
|
1166
|
+
interface SnapOptions {
|
|
1167
|
+
/** Master switch. Default `true`. */
|
|
1168
|
+
enabled?: boolean;
|
|
1169
|
+
/**
|
|
1170
|
+
* Snap kinds to consider, highest priority first. Default:
|
|
1171
|
+
* `['vertex', 'edge-midpoint', 'mover-center', 'module-boundary',
|
|
1172
|
+
* 'station-stop', 'track-path', 'face-center']`.
|
|
1173
|
+
*/
|
|
1174
|
+
kinds?: SnapKind[];
|
|
1175
|
+
/** Screen-space radius (px) a candidate must fall within. Default `14`. */
|
|
1176
|
+
radiusPx?: number;
|
|
1177
|
+
/**
|
|
1178
|
+
* Grid step (mm) for the `'grid'` snap, applied to the free hit point when
|
|
1179
|
+
* no other candidate matched and `'grid'` is in `kinds`. Default `0` (off).
|
|
1180
|
+
*/
|
|
1181
|
+
gridMm?: number;
|
|
1182
|
+
}
|
|
1183
|
+
type MeasurementId = string;
|
|
1184
|
+
type MeasurementKind = 'distance' | 'angle' | 'path' | 'trackDistance';
|
|
1185
|
+
/** Axis constraint for a distance measurement. */
|
|
1186
|
+
type MeasurementAxis = 'free' | 'x' | 'y' | 'z';
|
|
1187
|
+
interface MeasurementBase {
|
|
1188
|
+
id: MeasurementId;
|
|
1189
|
+
/** Optional caption rendered above the value. */
|
|
1190
|
+
label?: string;
|
|
1191
|
+
/** Overrides `MeasurementStyle.color` for this one measurement. */
|
|
1192
|
+
color?: string;
|
|
1193
|
+
/** Default `true`. */
|
|
1194
|
+
visible?: boolean;
|
|
1195
|
+
/** Free-form payload the host can round-trip (never read by the viewer). */
|
|
1196
|
+
meta?: Record<string, unknown>;
|
|
1197
|
+
}
|
|
1198
|
+
/** Straight-line distance between two points. */
|
|
1199
|
+
interface DistanceMeasurement extends MeasurementBase {
|
|
1200
|
+
kind: 'distance';
|
|
1201
|
+
points: [MeasurementPoint, MeasurementPoint];
|
|
1202
|
+
/** Constrain the reported value to one axis. Default `'free'`. */
|
|
1203
|
+
axis?: MeasurementAxis;
|
|
1204
|
+
/** Render dashed ΔX / ΔY / ΔZ guides. Default `false`. */
|
|
1205
|
+
showComponents?: boolean;
|
|
1206
|
+
}
|
|
1207
|
+
/** Angle at `points[1]` between the legs to `points[0]` and `points[2]`. */
|
|
1208
|
+
interface AngleMeasurement extends MeasurementBase {
|
|
1209
|
+
kind: 'angle';
|
|
1210
|
+
/** `[legA, vertex, legB]` — the middle point is the vertex. */
|
|
1211
|
+
points: [MeasurementPoint, MeasurementPoint, MeasurementPoint];
|
|
1212
|
+
}
|
|
1213
|
+
/** Polyline through N points; reports per-segment and total length. */
|
|
1214
|
+
interface PathMeasurement extends MeasurementBase {
|
|
1215
|
+
kind: 'path';
|
|
1216
|
+
points: MeasurementPoint[];
|
|
1217
|
+
/** Close the polyline back to the first point. Default `false`. */
|
|
1218
|
+
closed?: boolean;
|
|
1219
|
+
/** Label every segment, not just the total. Default `true`. */
|
|
1220
|
+
showSegmentLengths?: boolean;
|
|
1221
|
+
}
|
|
1222
|
+
/**
|
|
1223
|
+
* Distance ALONG the XTS track between two points on the same part — the
|
|
1224
|
+
* distance a mover actually travels, not the straight line.
|
|
1197
1225
|
*/
|
|
1198
|
-
interface
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1226
|
+
interface TrackDistanceMeasurement extends MeasurementBase {
|
|
1227
|
+
kind: 'trackDistance';
|
|
1228
|
+
points: [MeasurementPoint, MeasurementPoint];
|
|
1229
|
+
}
|
|
1230
|
+
type Measurement = DistanceMeasurement | AngleMeasurement | PathMeasurement | TrackDistanceMeasurement;
|
|
1231
|
+
/** Same as `Measurement`, but the store generates the `id` when omitted. */
|
|
1232
|
+
type MeasurementInput = (Omit<DistanceMeasurement, 'id'> & {
|
|
1233
|
+
id?: MeasurementId;
|
|
1234
|
+
}) | (Omit<AngleMeasurement, 'id'> & {
|
|
1235
|
+
id?: MeasurementId;
|
|
1236
|
+
}) | (Omit<PathMeasurement, 'id'> & {
|
|
1237
|
+
id?: MeasurementId;
|
|
1238
|
+
}) | (Omit<TrackDistanceMeasurement, 'id'> & {
|
|
1239
|
+
id?: MeasurementId;
|
|
1240
|
+
});
|
|
1241
|
+
/** Computed value of a measurement. */
|
|
1242
|
+
interface MeasurementResult {
|
|
1243
|
+
id: MeasurementId;
|
|
1244
|
+
kind: MeasurementKind;
|
|
1245
|
+
/** Millimetres for lengths, degrees for angles. */
|
|
1246
|
+
value: number;
|
|
1247
|
+
unit: 'mm' | 'deg';
|
|
1248
|
+
/** Formatted value as rendered in the scene (e.g. `'1 234.5 mm'`). */
|
|
1249
|
+
text: string;
|
|
1250
|
+
/** Signed component deltas — `'distance'` only. */
|
|
1251
|
+
deltaMm?: Vec3;
|
|
1252
|
+
/** Per-segment lengths — `'path'` only. */
|
|
1253
|
+
segmentLengthsMm?: number[];
|
|
1203
1254
|
/**
|
|
1204
|
-
* `
|
|
1205
|
-
*
|
|
1206
|
-
*
|
|
1255
|
+
* `true` when the measurement could not be evaluated (e.g. a
|
|
1256
|
+
* `trackDistance` whose endpoints sit on different parts). `value` is then
|
|
1257
|
+
* the straight-line fallback.
|
|
1207
1258
|
*/
|
|
1208
|
-
|
|
1209
|
-
/** Module type of the leading infeed module. */
|
|
1210
|
-
infeedModuleType: ModuleType3D;
|
|
1211
|
-
/** Chain indices of every module in this segment, in chain order. */
|
|
1212
|
-
moduleIndices: number[];
|
|
1213
|
-
/** Σ of the segment's module lengths, in mm. */
|
|
1214
|
-
lengthMm: number;
|
|
1215
|
-
/** True when the segment wraps the closed-loop seam. */
|
|
1216
|
-
wrapsSeam: boolean;
|
|
1259
|
+
incomplete?: boolean;
|
|
1217
1260
|
}
|
|
1218
|
-
|
|
1261
|
+
/** Where an annotation hangs. Mover anchors follow the live mover position. */
|
|
1262
|
+
type AnnotationAnchor = {
|
|
1263
|
+
kind: 'world';
|
|
1219
1264
|
positionMm: Vec3;
|
|
1220
|
-
targetMm: Vec3;
|
|
1221
|
-
/** Always 'Z' in the current spec. */
|
|
1222
|
-
upAxis: 'Z' | 'Y';
|
|
1223
|
-
zoom?: number;
|
|
1224
|
-
}
|
|
1225
|
-
/**
|
|
1226
|
-
* Live camera projection.
|
|
1227
|
-
* - `'perspective'` (default) — the regular 3D view.
|
|
1228
|
-
* - `'orthographic'` — paired with `topDown`, gives the flat 2D plan view
|
|
1229
|
-
* that matches `exportScreenshot({ mode: 'top-down' })`.
|
|
1230
|
-
*/
|
|
1231
|
-
type CameraProjection = 'perspective' | 'orthographic';
|
|
1232
|
-
/**
|
|
1233
|
-
* Target for the imperative `viewerRef.current.focusOn(target, opts)` camera
|
|
1234
|
-
* animation. The viewer computes the target's world-space bounding box and
|
|
1235
|
-
* flies the camera so the whole object fits the frame:
|
|
1236
|
-
* - In `'perspective'` projection the current view angle is preserved
|
|
1237
|
-
* (the camera only dollies / re-centres).
|
|
1238
|
-
* - In `'orthographic'` top-down the frustum is re-framed and the camera
|
|
1239
|
-
* pans straight over the object.
|
|
1240
|
-
*/
|
|
1241
|
-
type FocusTarget = {
|
|
1242
|
-
kind: 'scene';
|
|
1243
|
-
} | {
|
|
1244
|
-
kind: 'station';
|
|
1245
|
-
stationId: number;
|
|
1246
|
-
} | {
|
|
1247
|
-
kind: 'area';
|
|
1248
|
-
areaId: number;
|
|
1249
1265
|
} | {
|
|
1250
1266
|
kind: 'mover';
|
|
1251
1267
|
ref: MoverRef;
|
|
1252
1268
|
} | {
|
|
1253
1269
|
kind: 'module';
|
|
1254
1270
|
ref: ModuleRef;
|
|
1255
|
-
}
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1271
|
+
} | ({
|
|
1272
|
+
kind: 'trackPosition';
|
|
1273
|
+
} & TrackAnchor);
|
|
1274
|
+
interface Annotation {
|
|
1275
|
+
id: string;
|
|
1276
|
+
text: string;
|
|
1277
|
+
anchor: AnnotationAnchor;
|
|
1259
1278
|
/**
|
|
1260
|
-
*
|
|
1261
|
-
*
|
|
1279
|
+
* Leader-line offset from the anchor to the label (mm, world frame).
|
|
1280
|
+
* Default `[0, 0, 250]`.
|
|
1262
1281
|
*/
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
declare class XtsViewerErrorException extends Error {
|
|
1274
|
-
readonly code: XtsViewerErrorCode;
|
|
1275
|
-
readonly details?: unknown;
|
|
1276
|
-
constructor(code: XtsViewerErrorCode, message: string, details?: unknown);
|
|
1277
|
-
}
|
|
1278
|
-
interface AssetManifest {
|
|
1279
|
-
/** Override per moduleType. Falls back to default mapping otherwise. */
|
|
1280
|
-
modules?: Partial<Record<ModuleType3D, ModuleAssetEntry>>;
|
|
1281
|
-
movers?: Partial<Record<MoverType3D, MoverAssetEntry>>;
|
|
1282
|
-
tools?: Partial<Record<MoverToolType3D, MoverToolAssetEntry>>;
|
|
1283
|
-
guidingRails?: Partial<Record<RailType3D, RailAssetEntry>>;
|
|
1282
|
+
offsetMm?: Vec3;
|
|
1283
|
+
color?: string;
|
|
1284
|
+
/** Text height (mm). Default `MeasurementStyle.labelSizeMm`. */
|
|
1285
|
+
sizeMm?: number;
|
|
1286
|
+
/** Marker drawn at the anchor. Default `'Sphere'`. */
|
|
1287
|
+
markerShape?: MarkerShape;
|
|
1288
|
+
markerSizeMm?: number;
|
|
1289
|
+
/** Default `true`. */
|
|
1290
|
+
visible?: boolean;
|
|
1291
|
+
meta?: Record<string, unknown>;
|
|
1284
1292
|
}
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1293
|
+
type AnnotationInput = Omit<Annotation, 'id'> & {
|
|
1294
|
+
id?: string;
|
|
1295
|
+
};
|
|
1296
|
+
type MeasurementTool = 'none' | 'distance' | 'angle' | 'path' | 'trackDistance' | 'annotation';
|
|
1297
|
+
/** In-progress pick. `null` while no tool is armed. */
|
|
1298
|
+
interface MeasurementDraft {
|
|
1299
|
+
tool: Exclude<MeasurementTool, 'none'>;
|
|
1300
|
+
/** Points committed so far. */
|
|
1301
|
+
points: MeasurementPoint[];
|
|
1302
|
+
/** Point currently under the cursor, or `null` when off the scene. */
|
|
1303
|
+
hover: MeasurementPoint | null;
|
|
1288
1304
|
}
|
|
1289
|
-
interface
|
|
1290
|
-
/**
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1305
|
+
interface MeasurementStyle {
|
|
1306
|
+
/** Line + label colour of committed measurements. Default `'#00E5FF'`. */
|
|
1307
|
+
color?: string;
|
|
1308
|
+
/** Colour of the in-progress draft. Default `'#FFC400'`. */
|
|
1309
|
+
draftColor?: string;
|
|
1310
|
+
/** Annotation colour. Default `'#FFFFFF'`. */
|
|
1311
|
+
annotationColor?: string;
|
|
1312
|
+
/** Line width in pixels. Default `2`. */
|
|
1313
|
+
lineWidthPx?: number;
|
|
1314
|
+
/** Text height (mm). Default `40`. */
|
|
1315
|
+
labelSizeMm?: number;
|
|
1316
|
+
/** Endpoint marker diameter (mm). Default `18`. */
|
|
1317
|
+
pointSizeMm?: number;
|
|
1318
|
+
/** Decimal places on values. Default `1`. */
|
|
1319
|
+
decimals?: number;
|
|
1320
|
+
/** Unit suffix appended to lengths. Default `' mm'`. */
|
|
1321
|
+
unitSuffix?: string;
|
|
1322
|
+
/** Font URL passed to troika (see `DEFAULT_LABEL_FONT_URL`). */
|
|
1323
|
+
fontFamily?: string;
|
|
1324
|
+
/**
|
|
1325
|
+
* Draw measurement lines and markers through solid geometry
|
|
1326
|
+
* (`depthTest: false`). Default `true` — CAD viewers keep dimensions
|
|
1327
|
+
* readable regardless of what is in front of them.
|
|
1328
|
+
*/
|
|
1329
|
+
alwaysOnTop?: boolean;
|
|
1296
1330
|
}
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1331
|
+
/** Serializable snapshot of everything the measurement feature holds. */
|
|
1332
|
+
interface MeasurementDocument {
|
|
1333
|
+
schemaVersion: 1;
|
|
1334
|
+
measurements: Measurement[];
|
|
1335
|
+
annotations: Annotation[];
|
|
1300
1336
|
}
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1337
|
+
/**
|
|
1338
|
+
* `measurement` prop of `<XtsViewer3D>`. Data can be driven either
|
|
1339
|
+
* declaratively (`measurements` / `annotations` — controlled arrays) or
|
|
1340
|
+
* imperatively via `viewerRef.current.measurements`. When the controlled
|
|
1341
|
+
* arrays are supplied they win on every render, so a host that uses them must
|
|
1342
|
+
* persist what the change callbacks report.
|
|
1343
|
+
*/
|
|
1344
|
+
interface MeasurementOptions {
|
|
1345
|
+
/** Armed tool. Default `'none'` — no picking, no cursor change. */
|
|
1346
|
+
tool?: MeasurementTool;
|
|
1347
|
+
/** Controlled measurement list. Omit to let the viewer keep its own. */
|
|
1348
|
+
measurements?: MeasurementInput[];
|
|
1349
|
+
/** Controlled annotation list. Omit to let the viewer keep its own. */
|
|
1350
|
+
annotations?: AnnotationInput[];
|
|
1351
|
+
snap?: SnapOptions;
|
|
1352
|
+
style?: MeasurementStyle;
|
|
1353
|
+
/**
|
|
1354
|
+
* Z of the fallback pick plane (mm) used when the ray misses all geometry,
|
|
1355
|
+
* so free space can be measured. Default `0`; `null` disables the fallback.
|
|
1356
|
+
*/
|
|
1357
|
+
groundPlaneZMm?: number | null;
|
|
1358
|
+
/** Fired after every change to the measurement list. */
|
|
1359
|
+
onMeasurementsChange?: (measurements: Measurement[], results: MeasurementResult[]) => void;
|
|
1360
|
+
/** Fired once when a tool completes a measurement. */
|
|
1361
|
+
onMeasurementCreate?: (measurement: Measurement, result: MeasurementResult) => void;
|
|
1362
|
+
onAnnotationsChange?: (annotations: Annotation[]) => void;
|
|
1363
|
+
onAnnotationCreate?: (annotation: Annotation) => void;
|
|
1364
|
+
/** Fired on every draft change (point added, hover moved, cancelled). */
|
|
1365
|
+
onDraftChange?: (draft: MeasurementDraft | null) => void;
|
|
1366
|
+
/**
|
|
1367
|
+
* Text for an annotation the `'annotation'` tool just placed. Return
|
|
1368
|
+
* `null` to abort. Default: `'Annotation'`.
|
|
1369
|
+
*/
|
|
1370
|
+
annotationTextFactory?: (point: MeasurementPoint) => string | null;
|
|
1304
1371
|
}
|
|
1372
|
+
|
|
1373
|
+
/**
|
|
1374
|
+
* `XtsModelDocument` — the canonical serialized form of a viewer scene.
|
|
1375
|
+
*
|
|
1376
|
+
* What `viewerRef.current.exportModel()` produces and what a host persists:
|
|
1377
|
+
* the configuration, optionally the runtime mover state, and optionally the
|
|
1378
|
+
* measurements. The measurement half keeps its own types next to its
|
|
1379
|
+
* implementation (`measurement/types.ts`); only the serialized document
|
|
1380
|
+
* surfaces here.
|
|
1381
|
+
*/
|
|
1382
|
+
|
|
1305
1383
|
interface XtsModelDocument {
|
|
1306
1384
|
schemaVersion: 1;
|
|
1307
1385
|
meta: {
|
|
@@ -2524,12 +2602,13 @@ declare class SidecarLoader {
|
|
|
2524
2602
|
private readonly timeoutMs;
|
|
2525
2603
|
private readonly cache;
|
|
2526
2604
|
constructor(timeoutMs?: number);
|
|
2527
|
-
fetchModule(url: string): Promise<ModuleSidecar | undefined>;
|
|
2528
|
-
fetchMover(url: string): Promise<MoverSidecar | undefined>;
|
|
2529
|
-
fetchTool(url: string): Promise<MoverToolSidecar | undefined>;
|
|
2530
|
-
fetchRail(url: string): Promise<RailSidecar | undefined>;
|
|
2531
2605
|
clear(): void;
|
|
2532
|
-
|
|
2606
|
+
/**
|
|
2607
|
+
* Fetch and cache the sidecar at `url`. The loader validates the one field
|
|
2608
|
+
* every sidecar shape shares (`originCorrection`) and hands the rest to the
|
|
2609
|
+
* caller as `T` — the kind is a property of the URL, not of the loader.
|
|
2610
|
+
*/
|
|
2611
|
+
fetch<T>(url: string): Promise<T | undefined>;
|
|
2533
2612
|
}
|
|
2534
2613
|
/**
|
|
2535
2614
|
* Resolve the effective origin correction for a module sidecar — falls back
|
|
@@ -3615,6 +3694,54 @@ declare function getSharedAssetLoader(): AssetLoader;
|
|
|
3615
3694
|
/** Compose a URL from a base + a filename, normalising trailing slashes. */
|
|
3616
3695
|
declare function composeAssetUrl(baseUrl: string, filename: string): string;
|
|
3617
3696
|
|
|
3697
|
+
/**
|
|
3698
|
+
* The four sidecar kinds as data.
|
|
3699
|
+
*
|
|
3700
|
+
* Modules, movers, tools and rails all resolve their calibration the same
|
|
3701
|
+
* way — compiled-in table, else `<assetsBaseUrl>/<filename>`, else identity.
|
|
3702
|
+
* Only two things differ per kind: which built-in table to read and how the
|
|
3703
|
+
* filename is spelled. Keeping those two as a table (rather than four copies
|
|
3704
|
+
* of the resolution logic) means `useSidecar` and the calibration tool share
|
|
3705
|
+
* one implementation and a new kind is one entry, not one more branch.
|
|
3706
|
+
*
|
|
3707
|
+
* `filename` returning `null` marks an id that has no sidecar at all — the
|
|
3708
|
+
* `'Custom'` mover / tool, whose layout comes from the config instead. That
|
|
3709
|
+
* keeps "no lookup for Custom" a data fact rather than a special case each
|
|
3710
|
+
* consumer has to remember.
|
|
3711
|
+
*/
|
|
3712
|
+
|
|
3713
|
+
/** Id and sidecar shape carried by each kind. */
|
|
3714
|
+
interface SidecarKinds {
|
|
3715
|
+
module: {
|
|
3716
|
+
id: ModuleType3D;
|
|
3717
|
+
sidecar: ModuleSidecar;
|
|
3718
|
+
};
|
|
3719
|
+
mover: {
|
|
3720
|
+
id: MoverType3D;
|
|
3721
|
+
sidecar: MoverSidecar;
|
|
3722
|
+
};
|
|
3723
|
+
tool: {
|
|
3724
|
+
id: MoverToolType3D;
|
|
3725
|
+
sidecar: MoverToolSidecar;
|
|
3726
|
+
};
|
|
3727
|
+
rail: {
|
|
3728
|
+
id: RailType3D;
|
|
3729
|
+
sidecar: RailSidecar;
|
|
3730
|
+
};
|
|
3731
|
+
}
|
|
3732
|
+
type SidecarKind = keyof SidecarKinds;
|
|
3733
|
+
type SidecarIdOf<K extends SidecarKind> = SidecarKinds[K]['id'];
|
|
3734
|
+
type SidecarOf<K extends SidecarKind> = SidecarKinds[K]['sidecar'];
|
|
3735
|
+
interface SidecarKindSpec<K extends SidecarKind> {
|
|
3736
|
+
/** Sidecar filename for `id`, or `null` when the id carries no sidecar. */
|
|
3737
|
+
filename(id: SidecarIdOf<K>): string | null;
|
|
3738
|
+
/** Compiled-in sidecar for `id`, if the bundle carries one. */
|
|
3739
|
+
builtin(id: SidecarIdOf<K>): SidecarOf<K> | undefined;
|
|
3740
|
+
}
|
|
3741
|
+
declare const SIDECAR_KINDS: {
|
|
3742
|
+
[K in SidecarKind]: SidecarKindSpec<K>;
|
|
3743
|
+
};
|
|
3744
|
+
|
|
3618
3745
|
/**
|
|
3619
3746
|
* Style resolution for the measurement overlay — one place where every
|
|
3620
3747
|
* default lives, so the scene, the draft preview and the value formatting
|
|
@@ -3716,4 +3843,4 @@ declare function snapToGrid(positionMm: Vec3, gridMm: number): Vec3;
|
|
|
3716
3843
|
/** Convenience: `resolveSceneContext` + `toEntityRef`. */
|
|
3717
3844
|
declare function resolveEntityFromObject(object: Object3D | null, instanceId?: number): MeasuredEntityRef | null;
|
|
3718
3845
|
|
|
3719
|
-
export { type AngleMeasurement, type Annotation, type AnnotationAnchor, type AnnotationInput, type AreaConfig, type AreaOptions, AssetLoader, type AssetManifest, BUILTIN_MODULE_SIDECARS, BUILTIN_MOVER_SIDECARS, BUILTIN_RAIL_SIDECARS, BUILTIN_TOOL_SIDECARS, type BuiltChain, type BuiltModule, type CameraProjection, type CameraState, type CaptureMode, type CheckModuleCollisionsOptions, type CheckMoverCollisionsOptions, type ClickModifiers, type CoordinateSystem, type CustomAssetBinding, type CustomAssetConfig, type CustomMoverLayout, DEFAULT_LABEL_FONT_URL, DEFAULT_MEASUREMENT_STYLE, DEFAULT_MODULE_HALF_WIDTH_MM, DEFAULT_MODULE_HEIGHT_MM, DEFAULT_MODULE_MANIFEST, DEFAULT_MOVER_MANIFEST, DEFAULT_ORIGIN_CORRECTION, DEFAULT_RAIL_MANIFEST, DEFAULT_SNAP_KINDS, DEFAULT_SNAP_RADIUS_PX, DEFAULT_TOOL_MANIFEST, type DimensionOptions, type DisplayOptions, type DistanceMeasurement, EMPTY_SELECTION, type EndDelta, type FeedSegment, type FeedSegmentHighlight, type FeedSegmentSelector, type FeedSegmentSpan, type FocusOptions, type FocusTarget, type FrameCaptureOptions, type FrameCaptureSession, HEPCO_GFX_PROFILE, type HeatmapSample, type HepcoGfxRailProfileDims, IDENTITY_POSE, INFEED_MODULE_TYPES, type InfoBarConfig, type InfoBarMarkerConfig, type InfoBarOptions, JSDELIVR_ASSETS_BASE_URL, MODULE_CATALOG, MODULE_GUIDING_RAIL_MAP, MOVER_CATALOG, type MarkerOptions, type MarkerShape, type MeasuredEntityRef, type Measurement, type MeasurementApi, type MeasurementAxis, type MeasurementDocument, type MeasurementDraft, type MeasurementFormatOptions, type MeasurementId, type MeasurementInput, type MeasurementKind, type MeasurementOptions, type MeasurementPoint, type MeasurementResult, type MeasurementSnapshot, type MeasurementStyle, type MeasurementTool, type ModuleAssetEntry, type ModuleCatalogEntry, type ModuleCollision, type ModuleCollisionPartInput, type ModuleCollisionXpuInput, ModuleCornerMarkers, type ModuleEntry, type ModuleHighlight, type ModuleProbe, type ModuleRef, type ModuleSidecar, type ModuleStatusEntry, type ModuleType3D, type MoverAssetEntry, type MoverCatalogEntry, type MoverCollision, type MoverConfig, MoverIdLabel, type MoverIdLabelOptions, type MoverPositionEntry, type MoverProbe, type MoverRef, type MoverSidecar, type MoverToolAssetEntry, type MoverToolConfig, type MoverToolSidecar, type MoverToolType3D, type MoverType3D, type NormalizationWarning, type NormalizedXtsConfig, type Orientation, type OriginCorrection, type PartConfig, type PartPath, type PartTransformation, type PathMeasurement, type PathSample, type PathType, type PlanarPose, type PointCloud, type PointProjector, type PositionFrame, type ProcessingUnitConfig, type RailAssetEntry, type RailSidecar, type RailSystem, type RailType3D, type ResolvedMeasurementStyle, type ScreenshotFormat, type ScreenshotMode, type ScreenshotOptions, type ScreenshotResult, type SelectionMode, type SelectionState, SidecarLoader, type SidecarOverrides, type SidecarSourceConfig, SidecarSourceContext, type SnapCandidate, type SnapKind, type SnapOptions, type SplitFeedSegmentsOptions, type StationConfig, type StationOptions, type StatorHeatmap, type StopPositionMoverOptions, type TextOptions, type TrackAnchor, type TrackDistanceMeasurement, type TrackIndex, type TrackIndexEntry, type TrackMetrics, type TrackMetricsResolver, type TrackProjection, type TrackTransform, VERSION, type Vec2, type Vec3, XtsArcCurve3, type XtsConfig, XtsConfigNormalizer, type XtsModelDocument, XtsPointCloudCurve3, type XtsRuntimeState, XtsViewer3D, type XtsViewer3DProps, type XtsViewer3DRef, type XtsViewerError, type XtsViewerErrorCode, XtsViewerErrorException, angleDeg, applyBeckhoffXtsConvention, applyEmptyClick, applyModuleClick, applyMoverClick, arcPoints, axisDistanceMm, buildChain, buildModuleProbes, buildPartPath, buildTrackIndex, chainToUserPositionMm, checkModuleCollisions, checkSamePathCollisions, chooseSnapCandidate, collectFeedSegments, collectFeedSegmentsForXpu, collectTriangleSnapCandidates, composeAssetUrl, computeMeasurementResult, createHepcoGfxBaseplateShape, createHepcoGfxRailShape, deselectAll, distanceMm, findModuleAt, formatAngleDeg, formatLengthMm, getModuleEntry, getMoverEntry, getPointCloud, getSharedAssetLoader, interpolateHeatmapValue, isChainClosed, isKnownModuleType, isKnownMoverType, isModuleSelected, isMoverSelected, labelAnchorFor, moduleAnchorWorld, moduleEndDelta, moduleSidecarFilename, moverAnchorWorld, moverSidecarFilename, moverWorldAt, nearestTrackPoint, normaliseToHeatmapRange, normalizeXtsConfig, pathLengthsMm, pickGlbForRail, poseToMatrix4, railSidecarFilename, registerPointCloud, resolveEntityFromObject, resolveGuidingRailGlbUrl, resolveGuidingRailType, resolveHepcoGfxProfile, resolveMeasurementStyle, resolveModuleGlbUrl, resolveMoverGlbUrl, resolveOriginCorrection, resolveStopPositionMm, resolveToolGlbUrl, sampleChainPoint, sampleChainRange, sampleModulePath, snapToGrid, sortHeatmapSamples, splitIntoFeedSegments, toolSidecarFilename, trackAnchorWorld, trackDistanceMm, trackLengthOf, trackPolylineWorld, unregisterPointCloud, useSidecarSource, userToChainPositionMm, worldPointOnPart };
|
|
3846
|
+
export { type AngleMeasurement, type Annotation, type AnnotationAnchor, type AnnotationInput, type AreaConfig, type AreaOptions, AssetLoader, type AssetManifest, BUILTIN_MODULE_SIDECARS, BUILTIN_MOVER_SIDECARS, BUILTIN_RAIL_SIDECARS, BUILTIN_TOOL_SIDECARS, type BuiltChain, type BuiltModule, type CameraProjection, type CameraState, type CaptureMode, type CheckModuleCollisionsOptions, type CheckMoverCollisionsOptions, type ClickModifiers, type CoordinateSystem, type CustomAssetBinding, type CustomAssetConfig, type CustomMoverLayout, DEFAULT_LABEL_FONT_URL, DEFAULT_MEASUREMENT_STYLE, DEFAULT_MODULE_HALF_WIDTH_MM, DEFAULT_MODULE_HEIGHT_MM, DEFAULT_MODULE_MANIFEST, DEFAULT_MOVER_MANIFEST, DEFAULT_ORIGIN_CORRECTION, DEFAULT_RAIL_MANIFEST, DEFAULT_SNAP_KINDS, DEFAULT_SNAP_RADIUS_PX, DEFAULT_TOOL_MANIFEST, type DimensionOptions, type DisplayOptions, type DistanceMeasurement, EMPTY_SELECTION, type EndDelta, type FeedSegment, type FeedSegmentHighlight, type FeedSegmentSelector, type FeedSegmentSpan, type FocusOptions, type FocusTarget, type FrameCaptureOptions, type FrameCaptureSession, HEPCO_GFX_PROFILE, type HeatmapSample, type HepcoGfxRailProfileDims, IDENTITY_POSE, INFEED_MODULE_TYPES, type InfoBarConfig, type InfoBarMarkerConfig, type InfoBarOptions, JSDELIVR_ASSETS_BASE_URL, MODULE_CATALOG, MODULE_GUIDING_RAIL_MAP, MOVER_CATALOG, type MarkerOptions, type MarkerShape, type MeasuredEntityRef, type Measurement, type MeasurementApi, type MeasurementAxis, type MeasurementDocument, type MeasurementDraft, type MeasurementFormatOptions, type MeasurementId, type MeasurementInput, type MeasurementKind, type MeasurementOptions, type MeasurementPoint, type MeasurementResult, type MeasurementSnapshot, type MeasurementStyle, type MeasurementTool, type ModuleAssetEntry, type ModuleCatalogEntry, type ModuleCollision, type ModuleCollisionPartInput, type ModuleCollisionXpuInput, ModuleCornerMarkers, type ModuleEntry, type ModuleHighlight, type ModuleProbe, type ModuleRef, type ModuleSidecar, type ModuleStatusEntry, type ModuleType3D, type MoverAssetEntry, type MoverCatalogEntry, type MoverCollision, type MoverConfig, MoverIdLabel, type MoverIdLabelOptions, type MoverPositionEntry, type MoverProbe, type MoverRef, type MoverSidecar, type MoverToolAssetEntry, type MoverToolConfig, type MoverToolSidecar, type MoverToolType3D, type MoverType3D, type NormalizationWarning, type NormalizedXtsConfig, type Orientation, type OriginCorrection, type PartConfig, type PartPath, type PartTransformation, type PathMeasurement, type PathSample, type PathType, type PlanarPose, type PointCloud, type PointProjector, type PositionFrame, type ProcessingUnitConfig, type RailAssetEntry, type RailSidecar, type RailSystem, type RailType3D, type ResolvedMeasurementStyle, SIDECAR_KINDS, type ScreenshotFormat, type ScreenshotMode, type ScreenshotOptions, type ScreenshotResult, type SelectionMode, type SelectionState, type SidecarIdOf, type SidecarKind, type SidecarKindSpec, type SidecarKinds, SidecarLoader, type SidecarOf, type SidecarOverrides, type SidecarSourceConfig, SidecarSourceContext, type SnapCandidate, type SnapKind, type SnapOptions, type SplitFeedSegmentsOptions, type StationConfig, type StationOptions, type StatorHeatmap, type StopPositionMoverOptions, type TextOptions, type TrackAnchor, type TrackDistanceMeasurement, type TrackIndex, type TrackIndexEntry, type TrackMetrics, type TrackMetricsResolver, type TrackProjection, type TrackTransform, VERSION, type Vec2, type Vec3, XtsArcCurve3, type XtsConfig, XtsConfigNormalizer, type XtsModelDocument, XtsPointCloudCurve3, type XtsRuntimeState, XtsViewer3D, type XtsViewer3DProps, type XtsViewer3DRef, type XtsViewerError, type XtsViewerErrorCode, XtsViewerErrorException, angleDeg, applyBeckhoffXtsConvention, applyEmptyClick, applyModuleClick, applyMoverClick, arcPoints, axisDistanceMm, buildChain, buildModuleProbes, buildPartPath, buildTrackIndex, chainToUserPositionMm, checkModuleCollisions, checkSamePathCollisions, chooseSnapCandidate, collectFeedSegments, collectFeedSegmentsForXpu, collectTriangleSnapCandidates, composeAssetUrl, computeMeasurementResult, createHepcoGfxBaseplateShape, createHepcoGfxRailShape, deselectAll, distanceMm, findModuleAt, formatAngleDeg, formatLengthMm, getModuleEntry, getMoverEntry, getPointCloud, getSharedAssetLoader, interpolateHeatmapValue, isChainClosed, isKnownModuleType, isKnownMoverType, isModuleSelected, isMoverSelected, labelAnchorFor, moduleAnchorWorld, moduleEndDelta, moduleSidecarFilename, moverAnchorWorld, moverSidecarFilename, moverWorldAt, nearestTrackPoint, normaliseToHeatmapRange, normalizeXtsConfig, pathLengthsMm, pickGlbForRail, poseToMatrix4, railSidecarFilename, registerPointCloud, resolveEntityFromObject, resolveGuidingRailGlbUrl, resolveGuidingRailType, resolveHepcoGfxProfile, resolveMeasurementStyle, resolveModuleGlbUrl, resolveMoverGlbUrl, resolveOriginCorrection, resolveStopPositionMm, resolveToolGlbUrl, sampleChainPoint, sampleChainRange, sampleModulePath, snapToGrid, sortHeatmapSamples, splitIntoFeedSegments, toolSidecarFilename, trackAnchorWorld, trackDistanceMm, trackLengthOf, trackPolylineWorld, unregisterPointCloud, useSidecarSource, userToChainPositionMm, worldPointOnPart };
|