@solid-labs/fab-one-widget 0.1.5 → 0.1.7

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.
Files changed (34) hide show
  1. package/dist/GirthManagerWidget-C5L2H3Y2.js +4786 -0
  2. package/dist/GirthManagerWidget-C5L2H3Y2.js.map +1 -0
  3. package/dist/girth-manager-ui/src/GirthManagerCore.d.ts +11 -5
  4. package/dist/girth-manager-ui/src/components/CameraFit.d.ts +5 -1
  5. package/dist/girth-manager-ui/src/components/CircumferenceMeasurements.d.ts +4 -1
  6. package/dist/girth-manager-ui/src/components/CircumferenceSlice.d.ts +6 -1
  7. package/dist/girth-manager-ui/src/components/ClickableMesh.d.ts +5 -1
  8. package/dist/girth-manager-ui/src/components/DebugOverlays.d.ts +14 -2
  9. package/dist/girth-manager-ui/src/components/DebugPanel.d.ts +2 -1
  10. package/dist/girth-manager-ui/src/components/ErrorBoundary.d.ts +16 -0
  11. package/dist/girth-manager-ui/src/components/MeasurementInputForm.d.ts +14 -0
  12. package/dist/girth-manager-ui/src/components/VerticalDimension.d.ts +3 -1
  13. package/dist/girth-manager-ui/src/config.d.ts +2 -2
  14. package/dist/girth-manager-ui/src/index.d.ts +10 -6
  15. package/dist/girth-manager-ui/src/processing/logger.d.ts +13 -0
  16. package/dist/girth-manager-ui/src/processing/mesh-ops.d.ts +0 -22
  17. package/dist/girth-manager-ui/src/processing/pipeline.d.ts +34 -6
  18. package/dist/girth-manager-ui/src/processing/types.d.ts +112 -12
  19. package/dist/girth-manager-ui/src/processing/vertex-colors.d.ts +6 -1
  20. package/dist/girth-manager-ui/src/processing/wasm-loader.d.ts +16 -16
  21. package/dist/girth-manager-web-widget/src/GirthManagerWidget.d.ts +3 -5
  22. package/dist/girth-manager-web-widget/src/index.d.ts +1 -1
  23. package/dist/girth-manager-web-widget/src/types.d.ts +57 -0
  24. package/dist/girth-manager-web-widget/src/web-component.d.ts +2 -2
  25. package/dist/html2canvas.esm-Dmi1NfiH.js +4871 -0
  26. package/dist/html2canvas.esm-Dmi1NfiH.js.map +1 -0
  27. package/dist/index.js +1 -1
  28. package/dist/web-component.js +2 -2
  29. package/dist/web-component.js.map +1 -1
  30. package/package.json +9 -9
  31. package/dist/GirthManagerWidget-v0RZXFKb.js +0 -4122
  32. package/dist/GirthManagerWidget-v0RZXFKb.js.map +0 -1
  33. package/dist/galileo_core_geo-DFVJmkI7.js +0 -298
  34. package/dist/galileo_core_geo-DFVJmkI7.js.map +0 -1
@@ -1,4122 +0,0 @@
1
- import { jsxs as W, jsx as d, Fragment as He } from "react/jsx-runtime";
2
- import { createContext as tn, useCallback as Fe, useMemo as de, useState as q, memo as nn, useEffect as Se, useRef as Ie } from "react";
3
- import { useFrame as Lt, useThree as on, Canvas as sn } from "@react-three/fiber";
4
- import { Html as Ke, Line as ge, OrbitControls as Dt } from "@react-three/drei";
5
- import * as J from "three";
6
- import { Plane as it, Vector3 as h, Box3 as Tt, Line3 as ht, Quaternion as Oe, Matrix4 as kt } from "three";
7
- import { create as rn } from "zustand";
8
- import { OBJLoader as ln } from "three/examples/jsm/loaders/OBJLoader.js";
9
- import { STLLoader as an } from "three/examples/jsm/loaders/STLLoader.js";
10
- import { MeshBVH as $e } from "three-mesh-bvh";
11
- let bo, dt, ao, Nt;
12
- let __tla = (async () => {
13
- const cn = {
14
- showDragDrop: true,
15
- showStartOver: true,
16
- showInsertMeasurement: true,
17
- showDebug: true,
18
- showSpacingToggle: true,
19
- showAmputationModal: true,
20
- showNavigation: true,
21
- showToolbar: true
22
- }, fn = {
23
- showDragDrop: false,
24
- showStartOver: false,
25
- showInsertMeasurement: false,
26
- showDebug: false,
27
- showSpacingToggle: false,
28
- showAmputationModal: false,
29
- showNavigation: false,
30
- showToolbar: false
31
- }, dn = tn(cn), gt = rn((e, s) => ({
32
- landmarkPoints: [],
33
- isAligned: false,
34
- isCut: false,
35
- addLandmarkPoint: (o) => e((t) => t.landmarkPoints.length >= 3 ? t : {
36
- landmarkPoints: [
37
- ...t.landmarkPoints,
38
- o
39
- ]
40
- }),
41
- removeLandmarkPoint: (o) => e((t) => ({
42
- landmarkPoints: t.landmarkPoints.filter((l, a) => a !== o)
43
- })),
44
- clearLandmarkPoints: () => e({
45
- landmarkPoints: [],
46
- isAligned: false,
47
- isCut: false
48
- }),
49
- updateLandmarkPositions: (o) => e((t) => ({
50
- landmarkPoints: t.landmarkPoints.map((l, a) => ({
51
- ...l,
52
- position: o[a] ?? l.position
53
- }))
54
- })),
55
- setAligned: (o) => e({
56
- isAligned: o
57
- }),
58
- setCut: (o) => e({
59
- isCut: o
60
- }),
61
- isSelectionComplete: () => s().landmarkPoints.length === 3
62
- })), un = 0.45, Ye = 3, ut = 1e-3, We = 25.4, pn = 5, hn = [
63
- 0.25,
64
- -0.25,
65
- 0.5,
66
- -0.5
67
- ];
68
- function gn(e) {
69
- const s = e.split(`
70
- `), o = [], t = [];
71
- let l = false;
72
- for (const a of s) if (a.startsWith("v ")) {
73
- const c = a.trim().split(/\s+/);
74
- if (c.length >= 7) {
75
- o.push(parseFloat(c[1]), parseFloat(c[2]), parseFloat(c[3]));
76
- let u = parseFloat(c[4]), n = parseFloat(c[5]), i = parseFloat(c[6]);
77
- (u > 1 || n > 1 || i > 1) && (u /= 255, n /= 255, i /= 255), t.push(u, n, i), l = true;
78
- } else c.length >= 4 && (o.push(parseFloat(c[1]), parseFloat(c[2]), parseFloat(c[3])), t.push(0, 0, 0));
79
- }
80
- return l ? {
81
- positions: new Float32Array(o),
82
- colors: new Float32Array(t)
83
- } : null;
84
- }
85
- function mn(e, s, o, t) {
86
- const l = e.getAttribute("position"), a = l.count, c = new Float32Array(a * 3), u = s.length / 3;
87
- let n = 1 / 0, i = 1 / 0, r = 1 / 0, f = -1 / 0, y = -1 / 0, p = -1 / 0;
88
- for (let b = 0; b < u; b++) {
89
- const S = s[b * 3] * t, v = s[b * 3 + 1] * t, M = s[b * 3 + 2] * t;
90
- S < n && (n = S), S > f && (f = S), v < i && (i = v), v > y && (y = v), M < r && (r = M), M > p && (p = M);
91
- }
92
- const m = Math.min(128, Math.max(16, Math.round(Math.cbrt(u)))), g = (f - n + 1e-6) / m, w = (y - i + 1e-6) / m, C = (p - r + 1e-6) / m, x = /* @__PURE__ */ new Map();
93
- for (let b = 0; b < u; b++) {
94
- const S = Math.min(m - 1, Math.floor((s[b * 3] * t - n) / g)), v = Math.min(m - 1, Math.floor((s[b * 3 + 1] * t - i) / w)), M = Math.min(m - 1, Math.floor((s[b * 3 + 2] * t - r) / C)), L = S * m * m + v * m + M;
95
- let P = x.get(L);
96
- P || (P = [], x.set(L, P)), P.push(b);
97
- }
98
- for (let b = 0; b < a; b++) {
99
- const S = l.getX(b), v = l.getY(b), M = l.getZ(b), L = Math.min(m - 1, Math.max(0, Math.floor((S - n) / g))), P = Math.min(m - 1, Math.max(0, Math.floor((v - i) / w))), H = Math.min(m - 1, Math.max(0, Math.floor((M - r) / C)));
100
- let O = 1 / 0, $ = 0;
101
- for (let R = 0; R <= m && O > 0; R++) {
102
- for (let Y = -R; Y <= R; Y++) for (let N = -R; N <= R; N++) for (let ne = -R; ne <= R; ne++) {
103
- if (R > 0 && Math.abs(Y) < R && Math.abs(N) < R && Math.abs(ne) < R) continue;
104
- const oe = L + Y, le = P + N, ee = H + ne;
105
- if (oe < 0 || oe >= m || le < 0 || le >= m || ee < 0 || ee >= m) continue;
106
- const D = x.get(oe * m * m + le * m + ee);
107
- if (D) for (const z of D) {
108
- const F = s[z * 3] * t, V = s[z * 3 + 1] * t, B = s[z * 3 + 2] * t, T = (S - F) ** 2 + (v - V) ** 2 + (M - B) ** 2;
109
- T < O && (O = T, $ = z);
110
- }
111
- }
112
- if (O < 1 / 0) break;
113
- }
114
- c[b * 3] = o[$ * 3], c[b * 3 + 1] = o[$ * 3 + 1], c[b * 3 + 2] = o[$ * 3 + 2];
115
- }
116
- e.setAttribute("color", new J.Float32BufferAttribute(c, 3));
117
- }
118
- const xn = 30, zt = [
119
- "#4488ff",
120
- "#ff4444",
121
- "#44cc44",
122
- "#ffaa00",
123
- "#cc44ff",
124
- "#44ffcc"
125
- ];
126
- function yn(e, s) {
127
- const o = e.getVertices(), t = e.getFaces(), l = e.getComponentLabels(), a = /* @__PURE__ */ new Map();
128
- for (let r = 0; r < l.length; r++) {
129
- const f = l[r];
130
- a.has(f) || a.set(f, []), a.get(f).push(r);
131
- }
132
- const c = [
133
- ...a.keys()
134
- ].sort((r, f) => r - f), u = [], n = [], i = [];
135
- for (const r of c) {
136
- const f = a.get(r), y = /* @__PURE__ */ new Map(), p = [], m = [];
137
- for (const x of f) for (let b = 0; b < 3; b++) {
138
- const S = t[x * 3 + b];
139
- if (!y.has(S)) {
140
- const v = p.length / 3;
141
- p.push(o[S * 3], o[S * 3 + 1], o[S * 3 + 2]), y.set(S, v);
142
- }
143
- m.push(y.get(S));
144
- }
145
- const g = new J.BufferGeometry();
146
- g.setAttribute("position", new J.Float32BufferAttribute(p, 3)), g.setIndex(m), g.computeVertexNormals(), u.push(g);
147
- const C = r === s ? `#${r} inner` : r === 0 ? `#${r} outer` : `#${r} (${f.length} faces)`;
148
- n.push(C), i.push(zt[r % zt.length]);
149
- }
150
- return {
151
- geometries: u,
152
- labels: n,
153
- colors: i,
154
- innerIdx: s
155
- };
156
- }
157
- async function bn(e, s, o) {
158
- let t = null;
159
- try {
160
- const l = gn(e);
161
- o == null ? void 0 : o("Loading mesh..."), t = new s.WasmMeshSet(), t.loadObjString(e), o == null ? void 0 : o("Detecting units...");
162
- const a = t.autoScaleToMm(pn);
163
- o == null ? void 0 : o("Merging close vertices..."), t.applyMergeCloseVertices(1e-4), o == null ? void 0 : o("Analyzing mesh components...");
164
- let c = false, u = null;
165
- if (t.getComponentCount() >= 2) {
166
- o == null ? void 0 : o("Building component debug info...");
167
- const y = yn(t, null);
168
- o == null ? void 0 : o("Extracting inner shell..."), c = t.extractInnerShell(xn), c ? (console.log("Inner shell extracted from double-shell mesh"), y.innerIdx = 1, y.labels[1] = "#1 inner (extracted)", y.labels[0] && (y.labels[0] = "#0 outer (discarded)"), u = y) : (o == null ? void 0 : o("Removing floating artifacts..."), t.splitAndKeepLargest(), u = y);
169
- } else o == null ? void 0 : o("Removing floating artifacts..."), t.splitAndKeepLargest();
170
- o == null ? void 0 : o("Closing holes..."), t.applyCloseHoles(30), t.applyMergeCloseVertices(1e-4), o == null ? void 0 : o("Extracting geometry...");
171
- const i = t.getVertices(), r = t.getFaces();
172
- if (i.length === 0) return null;
173
- const f = new J.BufferGeometry();
174
- if (f.setAttribute("position", new J.Float32BufferAttribute(i, 3)), f.setIndex(Array.from(r)), f.computeVertexNormals(), l) {
175
- const y = a ? 1e3 : 1;
176
- mn(f, l.positions, l.colors, y);
177
- }
178
- return {
179
- geometry: f,
180
- wasScaled: a,
181
- innerShellExtracted: c,
182
- componentDebug: u
183
- };
184
- } catch (l) {
185
- return console.error("WASM processing failed:", l), null;
186
- } finally {
187
- if (t) try {
188
- t.free();
189
- } catch {
190
- }
191
- }
192
- }
193
- function wn(e) {
194
- const o = new ln().parse(e);
195
- let t = null;
196
- return o.traverse((l) => {
197
- l.isMesh && !t && (t = l.geometry);
198
- }), t;
199
- }
200
- async function ft(e) {
201
- const s = await e.arrayBuffer(), l = new an().parse(s).getAttribute("position");
202
- if (!l || l.count === 0) throw new Error("Empty STL geometry");
203
- const a = [];
204
- for (let c = 0; c < l.count; c++) a.push(`v ${l.getX(c)} ${l.getY(c)} ${l.getZ(c)}`);
205
- for (let c = 0; c < l.count; c += 3) a.push(`f ${c + 1} ${c + 2} ${c + 3}`);
206
- return a.join(`
207
- `);
208
- }
209
- function Bt(e, s) {
210
- const o = 1 / s;
211
- return `${Math.round(e.x * o)}_${Math.round(e.y * o)}_${Math.round(e.z * o)}`;
212
- }
213
- function Rt(e, s) {
214
- if (!e.length) return [];
215
- const o = [];
216
- for (const t of e) (o.length === 0 || o[o.length - 1].distanceTo(t) > s) && o.push(t.clone());
217
- return o.length > 2 && o[0].distanceTo(o[o.length - 1]) > s && o.push(o[0].clone()), o;
218
- }
219
- function je(e) {
220
- let s = 0;
221
- for (let o = 0; o < e.length - 1; o++) s += e[o].distanceTo(e[o + 1]);
222
- return s;
223
- }
224
- function Et(e, s = 1e-3, o = false) {
225
- if (!e.length) return [];
226
- const t = /* @__PURE__ */ new Map(), l = (i) => {
227
- const r = Bt(i, s);
228
- let f = t.get(r);
229
- return f || (f = i.clone(), t.set(r, f)), f;
230
- }, a = e.map((i) => ({
231
- a: l(i.a),
232
- b: l(i.b)
233
- })), c = [];
234
- for (; a.length; ) {
235
- const i = a.pop(), r = [
236
- i.a,
237
- i.b
238
- ];
239
- let f = true;
240
- for (; f; ) {
241
- f = false;
242
- for (let p = a.length - 1; p >= 0; p--) {
243
- const { a: m, b: g } = a[p];
244
- if (m.equals(r[r.length - 1])) r.push(g);
245
- else if (g.equals(r[r.length - 1])) r.push(m);
246
- else if (m.equals(r[0])) r.unshift(g);
247
- else if (g.equals(r[0])) r.unshift(m);
248
- else continue;
249
- a.splice(p, 1), f = true;
250
- }
251
- }
252
- const y = Rt(r, s);
253
- y.length > 1 && c.push(y);
254
- }
255
- if (!c.length) return [];
256
- if (c.sort((i, r) => je(r) - je(i)), !o) return c[0] ?? [];
257
- const u = je(c[0]), n = c.filter((i) => je(i) >= u * 0.3);
258
- return n[n.length - 1] ?? c[0];
259
- }
260
- function Ct(e, s, o, t = false) {
261
- const l = new it(new h(0, 1, 0), -o), a = [], c = new Tt();
262
- c.setFromBufferAttribute(s.getAttribute("position"));
263
- const u = {
264
- linePoints: [],
265
- lineLength: 0,
266
- rightmostPoint: new h(0, o, 0)
267
- };
268
- if (!l.intersectsBox(c)) return u;
269
- const n = new ht(), i = new h();
270
- e.shapecast({
271
- intersectsBounds: (g) => l.intersectsBox(g),
272
- intersectsTriangle: (g) => {
273
- const w = [];
274
- n.set(g.a, g.b), l.intersectLine(n, i) && w.push(i.clone()), n.set(g.b, g.c), l.intersectLine(n, i) && w.push(i.clone()), n.set(g.c, g.a), l.intersectLine(n, i) && w.push(i.clone()), w.length === 2 && a.push({
275
- a: w[0],
276
- b: w[1]
277
- });
278
- }
279
- });
280
- const r = Et(a, ut, t), f = je(r);
281
- if (r.length < 2) return u;
282
- let y = -1 / 0, p = new h(0, o, 0);
283
- for (const g of r) g.x > y && (y = g.x, p = g.clone());
284
- const m = r.length > 2 && r[0].distanceTo(r[r.length - 1]) < ut * 10;
285
- return {
286
- linePoints: r,
287
- lineLength: f,
288
- rightmostPoint: p,
289
- isClosed: m
290
- };
291
- }
292
- function Ze(e, s, o, t = false) {
293
- const l = Ct(e, s, o, t);
294
- if (l.isClosed && l.linePoints.length >= 3) return l;
295
- console.warn(`[slice] y=${o.toFixed(2)} failed (pts=${l.linePoints.length}, closed=${l.isClosed}), retrying...`);
296
- let a = l;
297
- for (const c of hn) {
298
- const u = Ct(e, s, o + c, t);
299
- if (u.isClosed && u.linePoints.length >= 3) return console.log(`[slice] y=${o.toFixed(2)} recovered with offset ${c > 0 ? "+" : ""}${c}mm (pts=${u.linePoints.length}, len=${u.lineLength.toFixed(1)}mm)`), u;
300
- u.linePoints.length > a.linePoints.length && (a = u);
301
- }
302
- return console.warn(`[slice] y=${o.toFixed(2)} all retries exhausted (pts=${a.linePoints.length}, closed=${a.isClosed})`), a;
303
- }
304
- function pt(e, s, o, t) {
305
- const l = new it().setFromNormalAndCoplanarPoint(t.clone().normalize(), o), a = new Tt();
306
- if (a.setFromBufferAttribute(s.getAttribute("position")), !l.intersectsBox(a)) return 0;
307
- const c = [], u = new ht(), n = new h();
308
- e.shapecast({
309
- intersectsBounds: (r) => l.intersectsBox(r),
310
- intersectsTriangle: (r) => {
311
- const f = [];
312
- u.set(r.a, r.b), l.intersectLine(u, n) && f.push(n.clone()), u.set(r.b, r.c), l.intersectLine(u, n) && f.push(n.clone()), u.set(r.c, r.a), l.intersectLine(u, n) && f.push(n.clone()), f.length === 2 && c.push({
313
- a: f[0],
314
- b: f[1]
315
- });
316
- }
317
- });
318
- const i = Et(c, ut);
319
- return je(i);
320
- }
321
- function ot(e) {
322
- return new $e(e, {
323
- maxLeafTris: Ye
324
- });
325
- }
326
- function vt(e, s, o) {
327
- const t = e instanceof $e ? e : new $e(e, {
328
- maxLeafTris: Ye
329
- }), l = new it().setFromNormalAndCoplanarPoint(o.clone().normalize(), s), a = [], c = new ht(), u = new h();
330
- return t.shapecast({
331
- intersectsBounds: (n) => l.intersectsBox(n),
332
- intersectsTriangle: (n) => {
333
- const i = [];
334
- c.set(n.a, n.b), l.intersectLine(c, u) && i.push(u.clone()), c.set(n.b, n.c), l.intersectLine(c, u) && i.push(u.clone()), c.set(n.c, n.a), l.intersectLine(c, u) && i.push(u.clone()), i.length === 2 && a.push({
335
- a: i[0],
336
- b: i[1]
337
- });
338
- }
339
- }), a;
340
- }
341
- function Mt(e, s, o = 1e-3) {
342
- if (!e.length) return [];
343
- const t = /* @__PURE__ */ new Map(), l = (i) => {
344
- const r = Bt(i, o);
345
- let f = t.get(r);
346
- return f || (f = i.clone(), t.set(r, f)), f;
347
- }, a = e.map((i) => ({
348
- a: l(i.a),
349
- b: l(i.b)
350
- })), c = [];
351
- for (; a.length; ) {
352
- const i = a.pop(), r = [
353
- i.a,
354
- i.b
355
- ];
356
- let f = true;
357
- for (; f; ) {
358
- f = false;
359
- for (let p = a.length - 1; p >= 0; p--) {
360
- const { a: m, b: g } = a[p];
361
- if (m.equals(r[r.length - 1])) r.push(g);
362
- else if (g.equals(r[r.length - 1])) r.push(m);
363
- else if (m.equals(r[0])) r.unshift(g);
364
- else if (g.equals(r[0])) r.unshift(m);
365
- else continue;
366
- a.splice(p, 1), f = true;
367
- }
368
- }
369
- const y = Rt(r, o);
370
- y.length > 1 && c.push(y);
371
- }
372
- if (!c.length) return [];
373
- let u = [], n = 1 / 0;
374
- for (const i of c) {
375
- if (i.length < 3 || !(i[0].distanceTo(i[i.length - 1]) < 2)) continue;
376
- const f = new h();
377
- for (const p of i) f.add(p);
378
- f.divideScalar(i.length);
379
- const y = f.distanceTo(s);
380
- y < n && (n = y, u = i);
381
- }
382
- if (u.length === 0) for (const i of c) {
383
- if (i.length < 3) continue;
384
- const r = new h();
385
- for (const y of i) r.add(y);
386
- r.divideScalar(i.length);
387
- const f = r.distanceTo(s);
388
- f < n && (n = f, u = i);
389
- }
390
- return u;
391
- }
392
- function Sn(e) {
393
- const s = new h();
394
- for (const o of e) s.add(o);
395
- return s.divideScalar(e.length);
396
- }
397
- function zn(e, s, o) {
398
- const t = new $e(e, {
399
- maxLeafTris: Ye
400
- }), l = new h().subVectors(s, o).normalize(), c = s.distanceTo(o) * 0.05;
401
- let u = l.clone();
402
- const n = (C) => {
403
- const x = [];
404
- for (let $ = -10; $ <= 0; $++) {
405
- const R = s.clone().addScaledVector(C, $ * c), Y = vt(t, R, C), N = Mt(Y, R, 1);
406
- N.length >= 3 && N[0].distanceTo(N[N.length - 1]) < 1 && x.push(Sn(N));
407
- }
408
- if (x.length < 3) return null;
409
- const b = new h();
410
- for (const $ of x) b.add($);
411
- b.divideScalar(x.length);
412
- let S = 0, v = 0, M = 0, L = 0, P = 0, H = 0;
413
- for (const $ of x) {
414
- const R = $.x - b.x, Y = $.y - b.y, N = $.z - b.z;
415
- S += R * R, v += R * Y, M += R * N, L += Y * Y, P += Y * N, H += N * N;
416
- }
417
- let O = C.clone();
418
- for (let $ = 0; $ < 30; $++) {
419
- const R = S * O.x + v * O.y + M * O.z, Y = v * O.x + L * O.y + P * O.z, N = M * O.x + P * O.y + H * O.z, ne = new h(R, Y, N), oe = ne.length();
420
- if (oe < 1e-10 || (ne.divideScalar(oe), O.distanceTo(ne) < 1e-8)) break;
421
- O = ne;
422
- }
423
- return O.dot(l) < 0 && O.negate(), O;
424
- };
425
- for (let C = 0; C < 3; C++) {
426
- const x = n(u);
427
- if (!x) break;
428
- const b = u.angleTo(x);
429
- if (u = x, b < 1e-3) break;
430
- }
431
- const i = new h();
432
- Math.abs(u.x) < 0.9 ? i.set(1, 0, 0) : i.set(0, 1, 0), i.crossVectors(u, i).normalize();
433
- const r = new h().crossVectors(u, i).normalize(), f = (C) => {
434
- const x = vt(t, s, C), b = Mt(x, s, 1);
435
- if (b.length < 3) return {
436
- circumference: 1 / 0,
437
- closed: false
438
- };
439
- const S = b[0].distanceTo(b[b.length - 1]) < 1;
440
- return {
441
- circumference: je(b),
442
- closed: S
443
- };
444
- };
445
- let y = u.clone(), p = 1 / 0;
446
- for (let C = -3; C <= 3; C += 1) for (let x = -3; x <= 3; x += 1) {
447
- const b = C * Math.PI / 180, S = x * Math.PI / 180, v = u.clone().applyQuaternion(new Oe().setFromAxisAngle(i, b)).applyQuaternion(new Oe().setFromAxisAngle(r, S)).normalize(), M = f(v);
448
- M.closed && M.circumference < p && (p = M.circumference, y = v);
449
- }
450
- const m = y.clone(), g = new h();
451
- Math.abs(m.x) < 0.9 ? g.set(1, 0, 0) : g.set(0, 1, 0), g.crossVectors(m, g).normalize();
452
- const w = new h().crossVectors(m, g).normalize();
453
- for (let C = -5; C <= 5; C += 1) for (let x = -5; x <= 5; x += 1) {
454
- const b = C * 0.1 * Math.PI / 180, S = x * 0.1 * Math.PI / 180, v = m.clone().applyQuaternion(new Oe().setFromAxisAngle(g, b)).applyQuaternion(new Oe().setFromAxisAngle(w, S)).normalize(), M = f(v);
455
- M.closed && M.circumference < p && (p = M.circumference, y = v);
456
- }
457
- return p === 1 / 0 && (p = f(u).circumference, y = u), {
458
- normal: y,
459
- circumference: p
460
- };
461
- }
462
- function Cn(e, s, o) {
463
- const t = e.getAttribute("position"), l = e.getIndex();
464
- if (!l) return {
465
- isDoubleShell: false,
466
- sampledFaces: 0,
467
- opposingPairs: 0,
468
- confidence: 0
469
- };
470
- const a = l.array, c = t.array, u = new h().subVectors(o, s).normalize(), n = o.distanceTo(s), i = Math.min(n * 0.06, 15), r = new $e(e, {
471
- maxLeafTris: Ye
472
- });
473
- let f = new h(1, 0, 0);
474
- Math.abs(u.dot(f)) > 0.9 && (f = new h(0, 1, 0)), f.sub(u.clone().multiplyScalar(u.dot(f))).normalize();
475
- const y = new h().crossVectors(u, f).normalize(), p = 12, m = new h();
476
- let g = 0, w = 0, C = 0;
477
- for (const S of [
478
- 0.65,
479
- 0.78,
480
- 0.9
481
- ]) {
482
- const v = new h().lerpVectors(s, o, S);
483
- let M = 0, L = 0, P = 0, H = 0;
484
- for (let Y = 0; Y < a.length; Y += 3) {
485
- const N = a[Y], ne = a[Y + 1], oe = a[Y + 2], le = (c[N * 3] + c[ne * 3] + c[oe * 3]) / 3, ee = (c[N * 3 + 1] + c[ne * 3 + 1] + c[oe * 3 + 1]) / 3, D = (c[N * 3 + 2] + c[ne * 3 + 2] + c[oe * 3 + 2]) / 3, z = le - v.x, F = ee - v.y, V = D - v.z;
486
- Math.abs(z * u.x + F * u.y + V * u.z) > i || (M += le, L += ee, P += D, H++);
487
- }
488
- if (H < 8) continue;
489
- const O = new h(M / H, L / H, P / H);
490
- let $ = 0;
491
- for (let Y = 0; Y < p; Y++) {
492
- const N = Y / p * Math.PI * 2, ne = new h().addScaledVector(f, Math.cos(N)).addScaledVector(y, Math.sin(N)), oe = new J.Ray(O, ne);
493
- let le = 0;
494
- r.shapecast({
495
- intersectsBounds: (ee) => oe.intersectsBox(ee),
496
- intersectsTriangle: (ee) => (oe.intersectTriangle(ee.a, ee.b, ee.c, false, m) && le++, false)
497
- }), $ += le, w++;
498
- }
499
- g += $, $ / p > 1.5 && C++;
500
- }
501
- if (w === 0) return {
502
- isDoubleShell: false,
503
- sampledFaces: 0,
504
- opposingPairs: 0,
505
- confidence: 0
506
- };
507
- const x = g / w;
508
- return {
509
- isDoubleShell: C >= 2,
510
- sampledFaces: w,
511
- opposingPairs: g,
512
- confidence: x
513
- };
514
- }
515
- function vn(e, s, o, t) {
516
- const l = new h().subVectors(o, s), a = new h().subVectors(t, s), c = new h().subVectors(e, s), u = l.dot(l), n = l.dot(a), i = l.dot(c), r = a.dot(a), f = a.dot(c), y = 1 / (u * r - n * n), p = (r * i - n * f) * y, m = (u * f - n * i) * y;
517
- return {
518
- u: 1 - p - m,
519
- v: p,
520
- w: m
521
- };
522
- }
523
- function st(e, s, o, t, l = false) {
524
- const a = o.clone().normalize(), c = e.getAttribute("position"), u = e.getIndex();
525
- if (!u) throw new Error("No index buffer");
526
- const n = new h().subVectors(t, s).dot(a), i = Math.abs(n) < 1e-6 ? 1 : Math.sign(n), r = c.array, f = u.array, y = e.getAttribute("color"), p = y ? y.array : null, m = [], g = [], w = [], C = (D, z, F) => {
527
- const V = m.length / 3;
528
- return m.push(D, z, F), V;
529
- }, x = (D) => new h(r[D * 3], r[D * 3 + 1], r[D * 3 + 2]), b = (D, z) => {
530
- const F = new h().subVectors(D, s).dot(a), V = new h().subVectors(z, s).dot(a), B = F / (F - V);
531
- return new h().lerpVectors(D, z, B);
532
- }, S = /* @__PURE__ */ new Map(), v = /* @__PURE__ */ new Map(), M = /* @__PURE__ */ new Map(), L = (D) => {
533
- let z = M.get(D);
534
- return z === void 0 && (z = new h().subVectors(x(D), s).dot(a), M.set(D, z)), z;
535
- }, P = (D) => {
536
- if (S.has(D)) return S.get(D);
537
- const z = x(D), F = C(z.x, z.y, z.z);
538
- return p && g.push(p[D * 3], p[D * 3 + 1], p[D * 3 + 2]), S.set(D, F), F;
539
- }, H = (D, z) => {
540
- const F = D < z ? `${D}_${z}` : `${z}_${D}`;
541
- if (v.has(F)) return v.get(F);
542
- const V = b(x(D), x(z)), B = C(V.x, V.y, V.z);
543
- if (p) {
544
- const T = L(D), E = L(z), j = T / (T - E);
545
- g.push(p[D * 3] + j * (p[z * 3] - p[D * 3]), p[D * 3 + 1] + j * (p[z * 3 + 1] - p[D * 3 + 1]), p[D * 3 + 2] + j * (p[z * 3 + 2] - p[D * 3 + 2]));
546
- }
547
- return v.set(F, B), B;
548
- }, O = (D) => {
549
- const z = L(D);
550
- return Math.sign(z) === i || Math.abs(z) < 1e-6;
551
- };
552
- for (let D = 0; D < f.length; D += 3) {
553
- const z = f[D], F = f[D + 1], V = f[D + 2], B = O(z), T = O(F), E = O(V), j = (B ? 1 : 0) + (T ? 1 : 0) + (E ? 1 : 0);
554
- if (j !== 0) if (j === 3) w.push(P(z), P(F), P(V));
555
- else if (j === 1) {
556
- let X, Q, ie;
557
- B ? (X = z, Q = F, ie = V) : T ? (X = F, Q = V, ie = z) : (X = V, Q = z, ie = F), w.push(P(X), H(X, Q), H(X, ie));
558
- } else {
559
- let X, Q, ie;
560
- B ? T ? (X = V, Q = z, ie = F) : (X = F, Q = V, ie = z) : (X = z, Q = F, ie = V);
561
- const se = P(Q), A = P(ie), I = H(Q, X), k = H(ie, X);
562
- w.push(se, I, A), w.push(A, I, k);
563
- }
564
- }
565
- const $ = w.length / 3;
566
- let R;
567
- if (l) R = Array.from({
568
- length: $
569
- }, (D, z) => z);
570
- else {
571
- const D = /* @__PURE__ */ new Map();
572
- for (let T = 0; T < $; T++) for (let E = 0; E < 3; E++) {
573
- const j = w[T * 3 + E];
574
- D.has(j) || D.set(j, []), D.get(j).push(T);
575
- }
576
- const z = /* @__PURE__ */ new Set(), F = [];
577
- for (let T = 0; T < $; T++) {
578
- if (z.has(T)) continue;
579
- const E = [], j = [
580
- T
581
- ];
582
- for (z.add(T); j.length > 0; ) {
583
- const X = j.shift();
584
- E.push(X);
585
- for (let Q = 0; Q < 3; Q++) {
586
- const ie = w[X * 3 + Q];
587
- for (const se of D.get(ie)) z.has(se) || (z.add(se), j.push(se));
588
- }
589
- }
590
- F.push(E);
591
- }
592
- let V = F[0] || [], B = 1 / 0;
593
- for (const T of F) {
594
- let E = 1 / 0;
595
- for (const j of T) {
596
- for (let X = 0; X < 3; X++) {
597
- const Q = w[j * 3 + X], ie = m[Q * 3] - t.x, se = m[Q * 3 + 1] - t.y, A = m[Q * 3 + 2] - t.z, I = ie * ie + se * se + A * A;
598
- I < E && (E = I);
599
- }
600
- if (E < B) break;
601
- }
602
- E < B && (B = E, V = T);
603
- }
604
- R = V;
605
- }
606
- const Y = /* @__PURE__ */ new Map(), N = [], ne = [], oe = [];
607
- let le = 0;
608
- for (const D of R) for (let z = 0; z < 3; z++) {
609
- const F = w[D * 3 + z];
610
- Y.has(F) || (N.push(m[F * 3], m[F * 3 + 1], m[F * 3 + 2]), p && ne.push(g[F * 3], g[F * 3 + 1], g[F * 3 + 2]), Y.set(F, le++)), oe.push(Y.get(F));
611
- }
612
- const ee = new J.BufferGeometry();
613
- return ee.setAttribute("position", new J.Float32BufferAttribute(N, 3)), p && ne.length > 0 && ee.setAttribute("color", new J.Float32BufferAttribute(ne, 3)), ee.setIndex(oe), ee.computeVertexNormals(), ee.computeBoundingBox(), ee;
614
- }
615
- function rt(e, s, o) {
616
- const t = e.getAttribute("position"), l = o - s;
617
- if (l < 1) return null;
618
- const a = 30, c = l / a, u = [];
619
- for (let w = 0; w < a; w++) {
620
- const C = s + w * c, x = s + (w + 1) * c;
621
- let b = 0, S = 0, v = 0, M = 0;
622
- for (let L = 0; L < t.count; L++) {
623
- const P = t.getY(L);
624
- P >= C && P < x && (b += t.getX(L), S += P, v += t.getZ(L), M++);
625
- }
626
- M > 20 && u.push(new h(b / M, S / M, v / M));
627
- }
628
- if (u.length < 5) return null;
629
- const n = new h();
630
- for (const w of u) n.add(w);
631
- n.divideScalar(u.length);
632
- let i = 0, r = 0, f = 0, y = 0, p = 0, m = 0;
633
- for (const w of u) {
634
- const C = w.x - n.x, x = w.y - n.y, b = w.z - n.z;
635
- i += C * C, r += C * x, f += C * b, y += x * x, p += x * b, m += b * b;
636
- }
637
- let g = new h(0.01, 1, 0.01).normalize();
638
- for (let w = 0; w < 30; w++) {
639
- const C = i * g.x + r * g.y + f * g.z, x = r * g.x + y * g.y + p * g.z, b = f * g.x + p * g.y + m * g.z, S = new h(C, x, b), v = S.length();
640
- if (v < 1e-10 || (S.divideScalar(v), g.distanceTo(S) < 1e-8)) break;
641
- g = S;
642
- }
643
- return g.y < 0 && g.negate(), g;
644
- }
645
- function Wt(e, s, o, t) {
646
- const l = e.getIndex(), a = l ? l.count / 3 : 0;
647
- if (a < 10) return {
648
- valid: false,
649
- reason: `Geometry is empty or degenerate (${a} faces)`
650
- };
651
- const c = s - o;
652
- if (c < 4) return {
653
- valid: false,
654
- reason: `Height too small (${c.toFixed(1)}mm < 4mm)`
655
- };
656
- if (c > 1e3) return {
657
- valid: false,
658
- reason: `Height too large (${c.toFixed(1)}mm > 1000mm)`
659
- };
660
- const u = new $e(e, {
661
- maxLeafTris: Ye
662
- }), n = Ze(u, e, s);
663
- if (n.lineLength === 0) return {
664
- valid: false,
665
- reason: "No circumference at green point \u2014 mesh may be empty at that height"
666
- };
667
- const i = s - t;
668
- if (i <= o) return {
669
- valid: true,
670
- reason: ""
671
- };
672
- const r = Ze(u, e, i);
673
- if (n.lineLength > 0 && r.lineLength > 0) {
674
- const y = n.lineLength / r.lineLength;
675
- if (y < 0.5) return {
676
- valid: false,
677
- reason: `First circumference is too small relative to second (ratio ${y.toFixed(2)} < 0.5) \u2014 possible trimmed angle`
678
- };
679
- }
680
- const f = s - t * 2;
681
- if (f > o) {
682
- const y = Ze(u, e, f);
683
- if (r.lineLength > 0 && y.lineLength > 0) {
684
- const p = r.lineLength / y.lineLength;
685
- if (p < 0.5) return {
686
- valid: false,
687
- reason: `Second circumference is too small relative to third (ratio ${p.toFixed(2)} < 0.5) \u2014 possible trimmed angle`
688
- };
689
- }
690
- }
691
- return {
692
- valid: true,
693
- reason: ""
694
- };
695
- }
696
- const Mn = [
697
- {
698
- nudge: 3,
699
- angle: 0,
700
- cutOffset: 5
701
- },
702
- {
703
- nudge: 5,
704
- angle: Math.PI * 2 / 3,
705
- cutOffset: 3
706
- },
707
- {
708
- nudge: 8,
709
- angle: Math.PI * 4 / 3,
710
- cutOffset: 4
711
- },
712
- {
713
- nudge: -5,
714
- angle: 0,
715
- cutOffset: 6
716
- }
717
- ], nt = 5;
718
- function Vt(e, s, o, t) {
719
- const l = new Oe().setFromAxisAngle(o, t);
720
- return e.applyMatrix4(new kt().makeRotationFromQuaternion(l)), s.map((a) => a.clone().applyQuaternion(l));
721
- }
722
- function _t(e, s, o) {
723
- const t = new Oe().setFromAxisAngle(s, o);
724
- e.applyMatrix4(new kt().makeRotationFromQuaternion(t));
725
- }
726
- function An(e, s, o, t, l, a) {
727
- const c = o.getAttribute("position"), u = o.getIndex();
728
- if (!u) return s;
729
- const i = s[1].y + t * We, r = c.array, f = u.array, y = o.getAttribute("color"), p = y ? y.array : null, m = [], g = [], w = [], C = (A, I, k) => {
730
- const G = m.length / 3;
731
- return m.push(A, I, k), G;
732
- }, x = (A) => [
733
- r[A * 3],
734
- r[A * 3 + 1],
735
- r[A * 3 + 2]
736
- ], b = (A, I) => {
737
- const k = (i - A[1]) / (I[1] - A[1]);
738
- return [
739
- A[0] + k * (I[0] - A[0]),
740
- i,
741
- A[2] + k * (I[2] - A[2])
742
- ];
743
- }, S = /* @__PURE__ */ new Map(), v = /* @__PURE__ */ new Map(), M = (A) => {
744
- if (S.has(A)) return S.get(A);
745
- const [I, k, G] = x(A), U = C(I, k, G);
746
- return p && g.push(p[A * 3], p[A * 3 + 1], p[A * 3 + 2]), S.set(A, U), U;
747
- }, L = (A, I) => {
748
- const k = A < I ? `${A}_${I}` : `${I}_${A}`;
749
- if (v.has(k)) return v.get(k);
750
- const G = x(A), U = x(I), [re, Pe, me] = b(G, U), ae = C(re, Pe, me);
751
- if (p) {
752
- const xe = (i - G[1]) / (U[1] - G[1]);
753
- g.push(p[A * 3] + xe * (p[I * 3] - p[A * 3]), p[A * 3 + 1] + xe * (p[I * 3 + 1] - p[A * 3 + 1]), p[A * 3 + 2] + xe * (p[I * 3 + 2] - p[A * 3 + 2]));
754
- }
755
- return v.set(k, ae), ae;
756
- };
757
- for (let A = 0; A < f.length; A += 3) {
758
- const I = f[A], k = f[A + 1], G = f[A + 2], U = x(I), re = x(k), Pe = x(G), me = U[1] < i, ae = re[1] < i, xe = Pe[1] < i, Re = (me ? 1 : 0) + (ae ? 1 : 0) + (xe ? 1 : 0);
759
- if (Re !== 0) if (Re === 3) w.push(M(I), M(k), M(G));
760
- else if (Re === 1) {
761
- let pe, we, he;
762
- me ? (pe = I, we = k, he = G) : ae ? (pe = k, we = G, he = I) : (pe = G, we = I, he = k), w.push(M(pe), L(pe, we), L(pe, he));
763
- } else {
764
- let pe, we, he;
765
- me ? ae ? (pe = G, we = I, he = k) : (pe = k, we = G, he = I) : (pe = I, we = k, he = G);
766
- const Ge = M(we), fe = M(he), Ne = L(we, pe), Le = L(he, pe);
767
- w.push(Ge, Ne, fe), w.push(fe, Ne, Le);
768
- }
769
- }
770
- const P = w.length / 3, H = /* @__PURE__ */ new Map();
771
- for (let A = 0; A < P; A++) for (let I = 0; I < 3; I++) {
772
- const k = w[A * 3 + I];
773
- H.has(k) || H.set(k, []), H.get(k).push(A);
774
- }
775
- const O = /* @__PURE__ */ new Map();
776
- for (let A = 0; A < P; A++) O.set(A, /* @__PURE__ */ new Set());
777
- for (const [, A] of H) for (const I of A) for (const k of A) I !== k && O.get(I).add(k);
778
- const $ = /* @__PURE__ */ new Set(), R = [];
779
- for (let A = 0; A < P; A++) {
780
- if ($.has(A)) continue;
781
- const I = [], k = [
782
- A
783
- ];
784
- for ($.add(A); k.length > 0; ) {
785
- const G = k.shift();
786
- I.push(G);
787
- for (const U of O.get(G)) $.has(U) || ($.add(U), k.push(U));
788
- }
789
- R.push(I);
790
- }
791
- const Y = s[0];
792
- let N = R[0] || [], ne = 1 / 0;
793
- for (const A of R) {
794
- let I = 1 / 0;
795
- for (const k of A) {
796
- for (let G = 0; G < 3; G++) {
797
- const U = w[k * 3 + G], re = m[U * 3] - Y.x, Pe = m[U * 3 + 1] - Y.y, me = m[U * 3 + 2] - Y.z, ae = re * re + Pe * Pe + me * me;
798
- ae < I && (I = ae);
799
- }
800
- if (I < ne) break;
801
- }
802
- I < ne && (ne = I, N = A);
803
- }
804
- const oe = /* @__PURE__ */ new Map(), le = [], ee = [], D = [];
805
- let z = 0;
806
- for (const A of N) for (let I = 0; I < 3; I++) {
807
- const k = w[A * 3 + I];
808
- oe.has(k) || (le.push(m[k * 3], m[k * 3 + 1], m[k * 3 + 2]), p && ee.push(g[k * 3], g[k * 3 + 1], g[k * 3 + 2]), oe.set(k, z++)), D.push(oe.get(k));
809
- }
810
- const F = new J.BufferGeometry();
811
- F.setAttribute("position", new J.Float32BufferAttribute(le, 3)), p && ee.length > 0 && F.setAttribute("color", new J.Float32BufferAttribute(ee, 3)), F.setIndex(D), F.computeVertexNormals(), F.computeBoundingBox(), e.geometry.dispose(), e.geometry = F, l.onStatus("Refining alignment...");
812
- const V = new h(0, 1, 0);
813
- let B = [
814
- ...s
815
- ];
816
- const T = (A, I) => {
817
- B = Vt(F, B, A, I), a && _t(a, A, I);
818
- };
819
- for (let A = 0; A < 5; A++) {
820
- const I = F.getAttribute("position"), k = Math.min(B[0].y, B[1].y), U = Math.max(B[0].y, B[1].y) - k;
821
- if (U < 1) break;
822
- const re = 30, Pe = U / re, me = [];
823
- for (let ye = 0; ye < re; ye++) {
824
- const Te = k + ye * Pe, Me = k + (ye + 1) * Pe;
825
- let Ae = 0, De = 0, ze = 0, Ee = 0;
826
- for (let ke = 0; ke < I.count; ke++) {
827
- const Ue = I.getY(ke);
828
- Ue >= Te && Ue < Me && (Ae += I.getX(ke), De += Ue, ze += I.getZ(ke), Ee++);
829
- }
830
- Ee > 20 && me.push(new h(Ae / Ee, De / Ee, ze / Ee));
831
- }
832
- if (me.length < 5) break;
833
- const ae = new h();
834
- for (const ye of me) ae.add(ye);
835
- ae.divideScalar(me.length);
836
- let xe = 0, Re = 0, pe = 0, we = 0, he = 0, Ge = 0;
837
- for (const ye of me) {
838
- const Te = ye.x - ae.x, Me = ye.y - ae.y, Ae = ye.z - ae.z;
839
- xe += Te * Te, Re += Te * Me, pe += Te * Ae, we += Me * Me, he += Me * Ae, Ge += Ae * Ae;
840
- }
841
- let fe = new h(0.01, 1, 0.01).normalize();
842
- for (let ye = 0; ye < 30; ye++) {
843
- const Te = xe * fe.x + Re * fe.y + pe * fe.z, Me = Re * fe.x + we * fe.y + he * fe.z, Ae = pe * fe.x + he * fe.y + Ge * fe.z, De = new h(Te, Me, Ae), ze = De.length();
844
- if (ze < 1e-10 || (De.divideScalar(ze), fe.distanceTo(De) < 1e-8)) break;
845
- fe = De;
846
- }
847
- fe.y < 0 && fe.negate();
848
- const Ne = fe.dot(V);
849
- if (Math.acos(Math.min(1, Math.abs(Ne))) * 180 / Math.PI < 0.1) break;
850
- const Le = new h().crossVectors(fe, V);
851
- Le.length() > 1e-4 && (Le.normalize(), T(Le, Math.acos(Math.min(1, Math.max(-1, Ne)))));
852
- }
853
- B[0].y > B[1].y && T(new h(1, 0, 0), Math.PI);
854
- const E = B[0];
855
- F.translate(-E.x, -E.y, -E.z), a && a.translate(-E.x, -E.y, -E.z), B = B.map((A) => new h(A.x - E.x, A.y - E.y, A.z - E.z));
856
- const X = B[1].y + 5 * We, Q = st(F, new h(0, X, 0), new h(0, 1, 0), B[0]);
857
- e.geometry.dispose(), e.geometry = Q, Q.computeVertexNormals(), Q.computeBoundingBox(), l.updateLandmarkPositions(B.map((A) => ({
858
- x: A.x,
859
- y: A.y,
860
- z: A.z
861
- })));
862
- const ie = Q.boundingBox, se = new h();
863
- return ie.getSize(se), l.setModelSize(Math.max(se.x, se.y, se.z)), l.setCut(true), l.setAdjustedStartY(null), l.setAdjustedEndY(null), l.setOriginalEndY(B[1].y + 2 * We), B;
864
- }
865
- function Fn(e, s, o, t) {
866
- const l = s.map((m) => new h(m.position.x, m.position.y, m.position.z)), a = l[0], c = l[1];
867
- t.onStatus("Cutting double shell above green point...");
868
- const u = c.y + 2 * We, n = new h(c.x, u, c.z), i = e.geometry, r = st(i, n, new h(0, 1, 0), a, true);
869
- i.dispose(), e.geometry = r, r.computeVertexNormals(), r.computeBoundingBox(), t.onStatus("Setting blue point..."), t.addLandmarkPoint({
870
- faceIndex: -1,
871
- vertexIndices: [
872
- 0,
873
- 1,
874
- 2
875
- ],
876
- position: {
877
- x: a.x,
878
- y: a.y,
879
- z: a.z
880
- },
881
- barycentricCoords: {
882
- u: 0.33,
883
- v: 0.33,
884
- w: 0.34
885
- }
886
- }), l.push(a.clone()), t.updateLandmarkPositions(l.map((m) => ({
887
- x: m.x,
888
- y: m.y,
889
- z: m.z
890
- }))), t.setAligned(true), t.setCut(true), t.setAdjustedStartY(null), t.setAdjustedEndY(null), t.setOriginalEndY(c.y);
891
- const f = r.boundingBox, y = new h();
892
- f.getSize(y), t.setModelSize(Math.max(y.x, y.y, y.z)), t.onStatus("Validating results...");
893
- const p = Wt(r, c.y, a.y, o);
894
- p.valid || console.warn(`Double shell validation warning: ${p.reason}`);
895
- }
896
- function In(e, s, o, t) {
897
- var _a, _b;
898
- const l = e.geometry.clone(), a = s.map((n) => ({
899
- ...n
900
- })), c = new h(0, 1, 0);
901
- if (t.skipDoubleShellDetection) console.log("Skipping double-shell detection: inner shell already extracted");
902
- else {
903
- const n = new h(s[0].position.x, s[0].position.y, s[0].position.z), i = new h(s[1].position.x, s[1].position.y, s[1].position.z);
904
- t.onStatus("Detecting shell type...");
905
- const r = Cn(e.geometry, n, i);
906
- if (console.log(`Shell detection: ${r.isDoubleShell ? "DOUBLE" : "SINGLE"} shell (${r.opposingPairs} inward/${r.sampledFaces} total faces, confidence ${(r.confidence * 100).toFixed(0)}%)`), r.isDoubleShell) {
907
- (_a = t.setDoubleShell) == null ? void 0 : _a.call(t, true), Fn(e, a, o, t), t.setClippedReferenceGeometry ? (l.computeVertexNormals(), t.setClippedReferenceGeometry(l)) : l.dispose();
908
- return;
909
- }
910
- (_b = t.setDoubleShell) == null ? void 0 : _b.call(t, false);
911
- }
912
- let u = "";
913
- for (let n = 0; n < nt; n++) try {
914
- n > 0 && (t.onStatus(`Retry ${n}/${nt - 1} \u2014 ${u}`), e.geometry.dispose(), e.geometry = l.clone(), t.removeLandmarkPoint(2), t.setAligned(false), t.setCut(false));
915
- let i = e.geometry, r = a.map((z) => new h(z.position.x, z.position.y, z.position.z));
916
- const f = t.setClippedReferenceGeometry ? l.clone() : null;
917
- let y = 5;
918
- if (n > 0) {
919
- const z = Mn[n - 1];
920
- y = z.cutOffset;
921
- const F = new h().subVectors(r[1], r[0]).normalize();
922
- if (z.nudge < 0) r[1].addScaledVector(F, z.nudge);
923
- else {
924
- const E = new h();
925
- Math.abs(F.x) < 0.9 ? E.crossVectors(F, new h(1, 0, 0)).normalize() : E.crossVectors(F, new h(0, 0, 1)).normalize(), E.applyAxisAngle(F, z.angle), r[1].addScaledVector(E, z.nudge);
926
- }
927
- const V = i.getAttribute("position");
928
- let B = 1 / 0, T = 0;
929
- for (let E = 0; E < V.count; E++) {
930
- const j = V.getX(E) - r[1].x, X = V.getY(E) - r[1].y, Q = V.getZ(E) - r[1].z, ie = j * j + X * X + Q * Q;
931
- ie < B && (B = ie, T = E);
932
- }
933
- r[1].set(V.getX(T), V.getY(T), V.getZ(T)), console.log(`Retry ${n}: nudge=${z.nudge}mm angle=${(z.angle * 180 / Math.PI).toFixed(0)}\xB0 cutOffset=${z.cutOffset}" \u2192 green=(${r[1].x.toFixed(1)}, ${r[1].y.toFixed(1)}, ${r[1].z.toFixed(1)})`);
934
- }
935
- const p = (z, F) => {
936
- r = Vt(i, r, z, F), f && _t(f, z, F);
937
- }, m = r[0], g = r[1], { normal: w } = zn(i, g, m);
938
- t.onStatus(n > 0 ? `Retry ${n}: Slicing mesh...` : "Slicing mesh at cut plane...");
939
- const C = new h().subVectors(g, m).normalize(), x = Math.sign(C.dot(w)), b = g.clone().addScaledVector(w, x * y * We), S = st(i, b, w, m);
940
- i.dispose(), i = S, e.geometry = i, t.onStatus(n > 0 ? `Retry ${n}: Rough alignment...` : "Rough alignment...");
941
- const v = new h().subVectors(r[1], r[0]).normalize();
942
- let M = v.dot(c), L = new h().crossVectors(v, c);
943
- L.length() > 1e-4 && (L.normalize(), p(L, Math.acos(Math.min(1, Math.max(-1, M))))), r[0].y > r[1].y && p(new h(1, 0, 0), Math.PI), i.computeVertexNormals(), t.onStatus(n > 0 ? `Retry ${n}: Translating...` : "Translating to origin...");
944
- const P = r[0].clone();
945
- i.translate(-P.x, -P.y, -P.z), f && f.translate(-P.x, -P.y, -P.z), r = r.map((z) => new h(z.x - P.x, z.y - P.y, z.z - P.z)), t.onStatus(n > 0 ? `Retry ${n}: Isolating limb...` : "Isolating limb region...");
946
- {
947
- const z = ot(i), F = r[0].y, V = r[1].y, B = new h(0, 1, 0), T = 5;
948
- i.computeBoundingBox();
949
- const E = i.boundingBox.max.y, j = [];
950
- for (let X = F + T; X < E; X += T) {
951
- const Q = pt(z, i, new h(0, X, 0), B);
952
- Q > 0 && j.push({
953
- y: X,
954
- circ: Q
955
- });
956
- }
957
- if (j.length > 5) {
958
- const X = V - F, Q = F + X * 0.3, ie = F + X * 0.7, se = j.filter((A) => A.y >= Q && A.y <= ie);
959
- if (se.length >= 3) {
960
- const A = se.map((U) => U.circ).sort((U, re) => U - re), I = A[Math.floor(A.length / 2)], k = 1.6;
961
- let G = null;
962
- for (const U of j) if (!(U.y < V - T * 2) && U.circ > I * k) {
963
- G = U.y - T;
964
- break;
965
- }
966
- if (G === null) {
967
- const U = j.find((re) => Math.abs(re.y - V) < T);
968
- if (U && U.circ > I * k) {
969
- for (let re = j.length - 1; re >= 0; re--) if (!(j[re].y > V + T) && j[re].circ <= I * k) {
970
- G = j[re].y + T;
971
- break;
972
- }
973
- }
974
- }
975
- if (G !== null && G > F + X * 0.5) {
976
- console.log(`Limb isolation: cutting at Y=${G.toFixed(1)}mm (baseline circ=${I.toFixed(1)}mm, threshold=${(I * k).toFixed(1)}mm)`);
977
- const U = st(i, new h(0, G, 0), B, r[0]);
978
- i.dispose(), i = U, e.geometry = i, i.computeVertexNormals(), i.computeBoundingBox();
979
- } else console.log(`Limb isolation: no anomaly detected (baseline=${I.toFixed(1)}mm)`);
980
- }
981
- }
982
- }
983
- t.onStatus(n > 0 ? `Retry ${n}: PCA alignment...` : "Iterative PCA alignment...");
984
- const H = 10, O = 80, $ = r[0].y, R = r[1].y;
985
- let Y = R - H;
986
- for (let z = 0; z < O; z++) {
987
- const F = Math.min(Y, R), V = Math.max(Y, R), B = rt(i, F, V);
988
- if (B && (M = B.dot(c), Math.acos(Math.min(1, Math.abs(M))) * 180 / Math.PI > 0.1 && (L = new h().crossVectors(B, c), L.length() > 1e-4))) {
989
- L.normalize(), p(L, Math.acos(Math.min(1, Math.max(-1, M))));
990
- const E = r[0].clone();
991
- i.translate(-E.x, -E.y, -E.z), f && f.translate(-E.x, -E.y, -E.z), r = r.map((j) => new h(j.x - E.x, j.y - E.y, j.z - E.z));
992
- }
993
- if (Y -= H, Y <= $) break;
994
- }
995
- i.computeVertexNormals(), t.onStatus(n > 0 ? `Retry ${n}: Setting blue point...` : "Setting blue point...");
996
- const N = new h(r[0].x, r[0].y, r[0].z);
997
- r.push(N), t.addLandmarkPoint({
998
- faceIndex: -1,
999
- vertexIndices: [
1000
- 0,
1001
- 1,
1002
- 2
1003
- ],
1004
- position: {
1005
- x: N.x,
1006
- y: N.y,
1007
- z: N.z
1008
- },
1009
- barycentricCoords: {
1010
- u: 0.33,
1011
- v: 0.33,
1012
- w: 0.34
1013
- }
1014
- }), t.onStatus(n > 0 ? `Retry ${n}: Final PCA...` : "Final PCA refinement...");
1015
- for (let z = 0; z < 3; z++) {
1016
- const F = rt(i, 0, r[1].y);
1017
- if (F) {
1018
- if (M = F.dot(c), Math.acos(Math.min(1, Math.abs(M))) * 180 / Math.PI < 0.1) break;
1019
- if (L = new h().crossVectors(F, c), L.length() > 1e-4) {
1020
- L.normalize(), p(L, Math.acos(Math.min(1, Math.max(-1, M))));
1021
- const B = r[0].clone();
1022
- i.translate(-B.x, -B.y, -B.z), f && f.translate(-B.x, -B.y, -B.z), r = r.map((T) => new h(T.x - B.x, T.y - B.y, T.z - B.z));
1023
- }
1024
- }
1025
- }
1026
- if (r[1].y < r[0].y) {
1027
- p(new h(1, 0, 0), Math.PI);
1028
- const z = r[0].clone();
1029
- i.translate(-z.x, -z.y, -z.z), f && f.translate(-z.x, -z.y, -z.z), r = r.map((F) => new h(F.x - z.x, F.y - z.y, F.z - z.z));
1030
- }
1031
- i.computeVertexNormals(), i.computeBoundingBox(), t.onStatus(n > 0 ? `Retry ${n}: Circumference refinement...` : "Circumference refinement...");
1032
- {
1033
- const z = ot(i), F = r[1].y, V = r[0].y, B = [
1034
- F - We,
1035
- F - 2 * We,
1036
- F - 3 * We
1037
- ].filter((T) => T > V + 5);
1038
- if (B.length >= 2) {
1039
- const T = Math.PI / 180, E = (I, k) => {
1040
- const G = new h(0, 1, 0);
1041
- Math.abs(I) > 1e-10 && G.applyQuaternion(new Oe().setFromAxisAngle(new h(1, 0, 0), I)), Math.abs(k) > 1e-10 && G.applyQuaternion(new Oe().setFromAxisAngle(new h(0, 0, 1), k));
1042
- let U = 0;
1043
- for (const re of B) U += pt(z, i, new h(0, re, 0), G);
1044
- return U;
1045
- };
1046
- let j = 0, X = 0, Q = E(0, 0);
1047
- for (let I = -3; I <= 3; I += 0.5) for (let k = -3; k <= 3; k += 0.5) {
1048
- const G = E(I * T, k * T);
1049
- G > 0 && G < Q && (Q = G, j = I * T, X = k * T);
1050
- }
1051
- const ie = j, se = X;
1052
- for (let I = -5; I <= 5; I++) for (let k = -5; k <= 5; k++) {
1053
- const G = ie + I * 0.1 * T, U = se + k * 0.1 * T, re = E(G, U);
1054
- re > 0 && re < Q && (Q = re, j = G, X = U);
1055
- }
1056
- const A = Math.sqrt(j * j + X * X);
1057
- if (A > 0.05 * T) {
1058
- console.log(`Circumference refinement: rotating ${(-j / T).toFixed(2)}\xB0X ${(-X / T).toFixed(2)}\xB0Z`), Math.abs(j) > 0.01 * T && p(new h(1, 0, 0), -j), Math.abs(X) > 0.01 * T && p(new h(0, 0, 1), -X);
1059
- const I = r[0].clone();
1060
- i.translate(-I.x, -I.y, -I.z), f && f.translate(-I.x, -I.y, -I.z), r = r.map((k) => new h(k.x - I.x, k.y - I.y, k.z - I.z)), i.computeVertexNormals();
1061
- } else console.log(`Circumference refinement: already optimal (${(A / T).toFixed(3)}\xB0)`);
1062
- }
1063
- }
1064
- const ne = r.map((z) => ({
1065
- x: z.x,
1066
- y: z.y,
1067
- z: z.z
1068
- }));
1069
- t.updateLandmarkPositions(ne), t.setAligned(true), t.onStatus(n > 0 ? `Retry ${n}: Cutting mesh...` : 'Cutting mesh 2" above green...'), r = An(e, r, i, 5, t, f), t.onStatus("Validating results...");
1070
- const oe = e.geometry, le = r[1].y, ee = r[0].y, D = Wt(oe, le, ee, o);
1071
- if (D.valid) {
1072
- console.log(`Processing succeeded on attempt ${n + 1}`), f && t.setClippedReferenceGeometry && (f.computeVertexNormals(), t.setClippedReferenceGeometry(f));
1073
- break;
1074
- }
1075
- console.warn(`Attempt ${n + 1} failed validation: ${D.reason}`), u = D.reason, f && f.dispose(), n === nt - 1 && (t.setError(`Processing produced unusual results after ${nt} attempts: ${D.reason}`), e.geometry.dispose(), e.geometry = l.clone(), t.removeLandmarkPoint(2), t.setAligned(false), t.setCut(false));
1076
- } catch (i) {
1077
- console.error("Processing failed:", i), t.setError(i instanceof Error ? i.message : "Failed to process mesh.");
1078
- break;
1079
- }
1080
- l.dispose();
1081
- }
1082
- const Pn = ({ message: e, onDismiss: s }) => W("div", {
1083
- style: {
1084
- position: "absolute",
1085
- top: 16,
1086
- right: 16,
1087
- padding: "12px 16px",
1088
- backgroundColor: "rgba(220, 53, 69, 0.95)",
1089
- borderRadius: 8,
1090
- color: "#fff",
1091
- fontSize: 14,
1092
- maxWidth: 300,
1093
- zIndex: 100,
1094
- display: "flex",
1095
- alignItems: "flex-start",
1096
- gap: 12
1097
- },
1098
- children: [
1099
- W("div", {
1100
- style: {
1101
- flex: 1
1102
- },
1103
- children: [
1104
- d("div", {
1105
- style: {
1106
- fontWeight: "bold",
1107
- marginBottom: 4
1108
- },
1109
- children: "Error"
1110
- }),
1111
- d("div", {
1112
- style: {
1113
- fontSize: 12,
1114
- opacity: 0.9
1115
- },
1116
- children: e
1117
- })
1118
- ]
1119
- }),
1120
- d("button", {
1121
- onClick: s,
1122
- style: {
1123
- background: "none",
1124
- border: "none",
1125
- color: "#fff",
1126
- cursor: "pointer",
1127
- fontSize: 18,
1128
- padding: 0,
1129
- lineHeight: 1,
1130
- opacity: 0.7
1131
- },
1132
- children: "x"
1133
- })
1134
- ]
1135
- }), At = ({ message: e }) => W("div", {
1136
- style: {
1137
- position: "absolute",
1138
- top: 0,
1139
- left: 0,
1140
- right: 0,
1141
- bottom: 0,
1142
- backgroundColor: "rgba(0, 0, 0, 0.7)",
1143
- display: "flex",
1144
- flexDirection: "column",
1145
- alignItems: "center",
1146
- justifyContent: "center",
1147
- zIndex: 100
1148
- },
1149
- children: [
1150
- d("div", {
1151
- style: {
1152
- width: 48,
1153
- height: 48,
1154
- border: "4px solid rgba(255, 255, 255, 0.2)",
1155
- borderTopColor: "#4a90d9",
1156
- borderRadius: "50%",
1157
- animation: "spin 1s linear infinite"
1158
- }
1159
- }),
1160
- e && d("div", {
1161
- style: {
1162
- marginTop: 16,
1163
- color: "#fff",
1164
- fontSize: 14
1165
- },
1166
- children: e
1167
- }),
1168
- d("style", {
1169
- children: "@keyframes spin { to { transform: rotate(360deg); } }"
1170
- })
1171
- ]
1172
- }), Ln = ({ mesh: e, maxPoints: s = 2, meshColor: o = "#c8c8c8", meshOpacity: t = 1 }) => {
1173
- const { addLandmarkPoint: l, landmarkPoints: a } = gt(), c = Fe((i) => {
1174
- if (a.length >= s) return;
1175
- i.stopPropagation();
1176
- const r = i.intersections[0], f = r == null ? void 0 : r.faceIndex;
1177
- if (!r || f == null) return;
1178
- const y = e.geometry, p = y.index;
1179
- let m;
1180
- p ? m = [
1181
- p.getX(f * 3),
1182
- p.getX(f * 3 + 1),
1183
- p.getX(f * 3 + 2)
1184
- ] : m = [
1185
- f * 3,
1186
- f * 3 + 1,
1187
- f * 3 + 2
1188
- ];
1189
- const g = y.getAttribute("position"), w = new h().fromBufferAttribute(g, m[0]), C = new h().fromBufferAttribute(g, m[1]), x = new h().fromBufferAttribute(g, m[2]);
1190
- w.applyMatrix4(e.matrixWorld), C.applyMatrix4(e.matrixWorld), x.applyMatrix4(e.matrixWorld);
1191
- const b = r.point, S = vn(b, w, C, x), v = {
1192
- faceIndex: f,
1193
- vertexIndices: m,
1194
- position: {
1195
- x: b.x,
1196
- y: b.y,
1197
- z: b.z
1198
- },
1199
- barycentricCoords: S
1200
- };
1201
- l(v);
1202
- }, [
1203
- e,
1204
- l,
1205
- a.length,
1206
- s
1207
- ]), u = de(() => !!e.geometry.getAttribute("color"), [
1208
- e
1209
- ]), n = de(() => new J.MeshStandardMaterial({
1210
- color: u ? "#ffffff" : o,
1211
- side: J.DoubleSide,
1212
- roughness: 0.6,
1213
- metalness: 0.1,
1214
- transparent: t < 1,
1215
- opacity: t,
1216
- vertexColors: u
1217
- }), [
1218
- o,
1219
- t,
1220
- u
1221
- ]);
1222
- return d("primitive", {
1223
- object: e,
1224
- onClick: c,
1225
- material: n
1226
- });
1227
- }, Dn = ({ point: e, index: s, markerSize: o, color: t, label: l }) => {
1228
- const [a, c] = q(false);
1229
- return W("mesh", {
1230
- position: [
1231
- e.position.x,
1232
- e.position.y,
1233
- e.position.z
1234
- ],
1235
- onPointerOver: () => c(true),
1236
- onPointerOut: () => c(false),
1237
- children: [
1238
- d("sphereGeometry", {
1239
- args: [
1240
- o,
1241
- 16,
1242
- 16
1243
- ]
1244
- }),
1245
- d("meshBasicMaterial", {
1246
- color: t
1247
- }),
1248
- a && d(Ke, {
1249
- center: true,
1250
- style: {
1251
- pointerEvents: "none"
1252
- },
1253
- children: d("div", {
1254
- style: {
1255
- padding: "3px 8px",
1256
- backgroundColor: "rgba(0, 0, 0, 0.75)",
1257
- borderRadius: 4,
1258
- color: "#fff",
1259
- fontSize: 12,
1260
- fontFamily: "system-ui, sans-serif",
1261
- whiteSpace: "nowrap",
1262
- transform: "translateY(-24px)"
1263
- },
1264
- children: l
1265
- })
1266
- })
1267
- ]
1268
- }, s);
1269
- }, Tn = ({ modelSize: e, labels: s }) => {
1270
- const { landmarkPoints: o } = gt(), t = e * 0.02, l = [
1271
- "#ff4444",
1272
- "#44ff44",
1273
- "#4444ff"
1274
- ], c = s ?? [
1275
- "Origin",
1276
- "MPT",
1277
- "Cut Plane"
1278
- ];
1279
- return d(He, {
1280
- children: o.map((u, n) => d(Dn, {
1281
- point: u,
1282
- index: n,
1283
- markerSize: t,
1284
- color: l[n],
1285
- label: c[n]
1286
- }, n))
1287
- });
1288
- };
1289
- function kn(e) {
1290
- return de(() => e ? new $e(e, {
1291
- maxLeafTris: Ye
1292
- }) : null, [
1293
- e
1294
- ]);
1295
- }
1296
- const Ft = (e, s) => {
1297
- const o = Math.abs(e - s);
1298
- return o < 1 ? "#8BC34A" : o < 5 ? "#FFC107" : "#FF5722";
1299
- }, It = new J.Color("#8BC34A"), Pt = new J.Color("#FFC107"), Bn = new J.Color("#FF5722"), Rn = (e) => {
1300
- if (e < 1) return It.clone();
1301
- if (e < 5) {
1302
- const o = (e - 1) / 4;
1303
- return It.clone().lerp(Pt, o);
1304
- }
1305
- const s = Math.min((e - 5) / 5, 1);
1306
- return Pt.clone().lerp(Bn, s);
1307
- }, En = (e, s) => {
1308
- const o = e.length, t = new Float32Array(o * 2 * 3), l = new Float32Array(o * 2 * 3), a = [];
1309
- for (let n = 0; n < o; n++) {
1310
- const i = e[n], r = s[n], f = i.distanceTo(r), y = Rn(f);
1311
- if (t[n * 6] = i.x, t[n * 6 + 1] = i.y, t[n * 6 + 2] = i.z, l[n * 6] = y.r, l[n * 6 + 1] = y.g, l[n * 6 + 2] = y.b, t[n * 6 + 3] = r.x, t[n * 6 + 4] = r.y, t[n * 6 + 5] = r.z, l[n * 6 + 3] = y.r, l[n * 6 + 4] = y.g, l[n * 6 + 5] = y.b, n < o - 1) {
1312
- const p = n * 2, m = p + 1, g = (n + 1) * 2, w = g + 1;
1313
- a.push(p, m, g, m, w, g);
1314
- }
1315
- }
1316
- const c = new J.BufferGeometry();
1317
- c.setAttribute("position", new J.Float32BufferAttribute(t, 3)), c.setAttribute("color", new J.Float32BufferAttribute(l, 3)), c.setIndex(a);
1318
- const u = new J.MeshBasicMaterial({
1319
- vertexColors: true,
1320
- transparent: true,
1321
- opacity: 0.25,
1322
- side: J.DoubleSide,
1323
- depthTest: false,
1324
- depthWrite: false
1325
- });
1326
- return new J.Mesh(c, u);
1327
- }, Wn = ({ bvh: e, geometry: s, yPosition: o, color: t = "#00ff00", labelX: l, onDataChange: a, displayUnit: c = "mm", useInnerSurface: u = false, formValue: n, lineWidth: i = 1.5 }) => {
1328
- const r = de(() => Ze(e, s, o, u), [
1329
- e,
1330
- s,
1331
- o,
1332
- u
1333
- ]), { linePoints: f, lineLength: y } = r, p = de(() => {
1334
- if (n == null || y <= 0 || f.length < 2) return null;
1335
- const C = n / y, x = f.reduce((S, v) => S + v.x, 0) / f.length, b = f.reduce((S, v) => S + v.z, 0) / f.length;
1336
- return f.map((S) => new h(x + (S.x - x) * C, S.y, b + (S.z - b) * C));
1337
- }, [
1338
- f,
1339
- y,
1340
- n
1341
- ]), m = de(() => !p || f.length < 2 ? null : En(f, p), [
1342
- f,
1343
- p
1344
- ]);
1345
- Se(() => () => {
1346
- m && (m.geometry.dispose(), m.material.dispose());
1347
- }, [
1348
- m
1349
- ]);
1350
- const g = Ie(null), w = de(() => {
1351
- const C = new J.BufferGeometry();
1352
- C.setAttribute("position", new J.Float32BufferAttribute(new Float32Array(6), 3));
1353
- const x = new J.LineBasicMaterial({
1354
- color: 6710886,
1355
- depthTest: false,
1356
- depthWrite: false,
1357
- transparent: true
1358
- });
1359
- return new J.Line(C, x);
1360
- }, []);
1361
- return Se(() => () => {
1362
- w.geometry.dispose(), w.material.dispose();
1363
- }, [
1364
- w
1365
- ]), Se(() => {
1366
- y > 0 && (a == null ? void 0 : a({
1367
- yPosition: o,
1368
- originalValue: y,
1369
- modifiedValue: null
1370
- }));
1371
- }, [
1372
- y,
1373
- o,
1374
- a
1375
- ]), Lt(({ camera: C }) => {
1376
- if (!g.current || f.length < 2) return;
1377
- const x = new h();
1378
- C.getWorldDirection(x);
1379
- const b = new h(x.x, 0, x.z);
1380
- if (b.lengthSq() < 1e-8) return;
1381
- b.normalize();
1382
- const S = new h().crossVectors(b, new h(0, 1, 0)).normalize();
1383
- let v = -1 / 0, M = f[0];
1384
- for (const O of f) {
1385
- const $ = S.x * O.x + S.z * O.z;
1386
- $ > v && (v = $, M = O);
1387
- }
1388
- const L = l * 0.35, P = new h(M.x + S.x * L, o, M.z + S.z * L);
1389
- g.current.position.copy(P);
1390
- const H = w.geometry.getAttribute("position");
1391
- H.setXYZ(0, M.x, M.y, M.z), H.setXYZ(1, P.x, P.y, P.z), H.needsUpdate = true;
1392
- }), f.length < 2 ? null : W("group", {
1393
- children: [
1394
- d(ge, {
1395
- points: f,
1396
- color: t,
1397
- lineWidth: i,
1398
- depthTest: false,
1399
- depthWrite: false,
1400
- transparent: true
1401
- }),
1402
- m && d("primitive", {
1403
- object: m
1404
- }),
1405
- p && n != null && d(ge, {
1406
- points: p,
1407
- color: Ft(y, n),
1408
- lineWidth: 2.5,
1409
- dashed: true,
1410
- dashSize: 2,
1411
- gapSize: 1.5,
1412
- depthTest: false,
1413
- depthWrite: false,
1414
- transparent: true,
1415
- opacity: 0.8
1416
- }),
1417
- d("primitive", {
1418
- object: w
1419
- }),
1420
- d("group", {
1421
- ref: g,
1422
- children: d(Ke, {
1423
- zIndexRange: [
1424
- 100,
1425
- 0
1426
- ],
1427
- style: {
1428
- pointerEvents: "none",
1429
- transform: "translateY(-50%)"
1430
- },
1431
- children: W("div", {
1432
- style: {
1433
- display: "flex",
1434
- alignItems: "stretch",
1435
- gap: 0,
1436
- marginLeft: 10,
1437
- pointerEvents: "none",
1438
- whiteSpace: "nowrap"
1439
- },
1440
- children: [
1441
- W("div", {
1442
- style: {
1443
- display: "flex",
1444
- alignItems: "center",
1445
- gap: 4,
1446
- padding: "5px 10px",
1447
- backgroundColor: "rgba(0, 0, 0, 0.75)",
1448
- borderRadius: n != null ? "4px 0 0 4px" : 4
1449
- },
1450
- children: [
1451
- d("span", {
1452
- style: {
1453
- fontSize: 14,
1454
- color: "#fff",
1455
- fontFamily: "monospace",
1456
- minWidth: 52,
1457
- textAlign: "right"
1458
- },
1459
- children: c === "inch" ? (y / 25.4).toFixed(2) : y.toFixed(1)
1460
- }),
1461
- d("span", {
1462
- style: {
1463
- fontSize: 11,
1464
- color: "rgba(255,255,255,0.6)",
1465
- fontFamily: "monospace"
1466
- },
1467
- children: c === "inch" ? "in" : "mm"
1468
- })
1469
- ]
1470
- }),
1471
- n != null && y > 0 && (() => {
1472
- const C = y - n, x = C > 0.5 ? "\u25B2" : C < -0.5 ? "\u25BC" : "", b = Ft(y, n);
1473
- return W("div", {
1474
- style: {
1475
- display: "flex",
1476
- alignItems: "center",
1477
- gap: 5,
1478
- padding: "5px 10px",
1479
- backgroundColor: "rgba(0, 0, 0, 0.55)",
1480
- borderRadius: "0 4px 4px 0",
1481
- borderLeft: "1px solid rgba(255,255,255,0.12)"
1482
- },
1483
- children: [
1484
- x && d("span", {
1485
- style: {
1486
- fontSize: 10,
1487
- color: b,
1488
- lineHeight: 1
1489
- },
1490
- children: x
1491
- }),
1492
- W("span", {
1493
- style: {
1494
- fontSize: 13,
1495
- color: b,
1496
- fontFamily: "monospace",
1497
- fontWeight: 600
1498
- },
1499
- children: [
1500
- C > 0 ? "+" : "",
1501
- c === "inch" ? (C / 25.4).toFixed(2) : C.toFixed(1)
1502
- ]
1503
- }),
1504
- W("span", {
1505
- style: {
1506
- fontSize: 11,
1507
- color: "rgba(255,255,255,0.4)",
1508
- fontFamily: "monospace"
1509
- },
1510
- children: [
1511
- "form ",
1512
- c === "inch" ? (n / 25.4).toFixed(2) : n.toFixed(0)
1513
- ]
1514
- })
1515
- ]
1516
- });
1517
- })()
1518
- ]
1519
- })
1520
- })
1521
- })
1522
- ]
1523
- });
1524
- }, Vn = nn(Wn), _n = ({ mesh: e, startY: s, endY: o, spacing: t, modelSize: l, onMeasurementsChange: a, reverseOrder: c = false, displayUnit: u = "mm", useInnerSurface: n = false, formMeasurements: i, originY: r }) => {
1525
- const f = Ie(/* @__PURE__ */ new Map()), y = e.geometry, p = kn(y), m = de(() => {
1526
- const x = [];
1527
- if (c) for (let b = o; b >= s; b -= t) x.push(b);
1528
- else for (let b = s; b <= o; b += t) x.push(b);
1529
- return x;
1530
- }, [
1531
- s,
1532
- o,
1533
- t,
1534
- c
1535
- ]);
1536
- Se(() => {
1537
- f.current.clear();
1538
- }, [
1539
- m
1540
- ]);
1541
- const g = [
1542
- "#5B9BD5"
1543
- ], w = l * un, C = Fe((x) => {
1544
- f.current.set(x.yPosition, x);
1545
- const b = Array.from(f.current.values()).sort((S, v) => c ? v.yPosition - S.yPosition : S.yPosition - v.yPosition);
1546
- a == null ? void 0 : a(b);
1547
- }, [
1548
- a,
1549
- c
1550
- ]);
1551
- return p ? d(He, {
1552
- children: m.map((x, b) => d(Vn, {
1553
- bvh: p,
1554
- geometry: y,
1555
- yPosition: x,
1556
- color: r != null && Math.abs(x - r) < t * 0.5 ? "#44ff44" : g[b % g.length],
1557
- labelX: w,
1558
- onDataChange: C,
1559
- displayUnit: u,
1560
- useInnerSurface: n,
1561
- formValue: i == null ? void 0 : i[b],
1562
- lineWidth: r != null && Math.abs(x - r) < t * 0.5 ? 4 : 1.5
1563
- }, x))
1564
- }) : null;
1565
- }, On = ({ mesh: e, greenY: s, modelSize: o, displayUnit: t = "mm" }) => {
1566
- var _a;
1567
- const l = e.geometry;
1568
- l.computeBoundingBox();
1569
- const a = ((_a = l.boundingBox) == null ? void 0 : _a.min.y) ?? 0, c = s - a, u = o * 0.4, n = o * 0.03, i = Ie(null);
1570
- Lt(({ camera: C }) => {
1571
- if (!i.current) return;
1572
- const x = new h();
1573
- C.getWorldDirection(x);
1574
- const b = new h(x.x, 0, x.z);
1575
- if (b.lengthSq() < 1e-8) return;
1576
- b.normalize();
1577
- const S = new h().crossVectors(new h(0, 1, 0), b).normalize();
1578
- i.current.position.set(S.x * u, 0, S.z * u);
1579
- const v = C.position.x - i.current.position.x, M = C.position.z - i.current.position.z;
1580
- i.current.rotation.y = Math.atan2(v, M);
1581
- });
1582
- const r = new h(0, s, 0), f = new h(0, a, 0), y = new h(0, (s + a) / 2, 0), p = new h(-n, s, 0), m = new h(n, s, 0), g = new h(-n, a, 0), w = new h(n, a, 0);
1583
- return W("group", {
1584
- ref: i,
1585
- children: [
1586
- d(ge, {
1587
- points: [
1588
- r,
1589
- f
1590
- ],
1591
- color: "#888888",
1592
- lineWidth: 1.5,
1593
- depthTest: false
1594
- }),
1595
- d(ge, {
1596
- points: [
1597
- p,
1598
- m
1599
- ],
1600
- color: "#888888",
1601
- lineWidth: 1.5,
1602
- depthTest: false
1603
- }),
1604
- d(ge, {
1605
- points: [
1606
- g,
1607
- w
1608
- ],
1609
- color: "#888888",
1610
- lineWidth: 1.5,
1611
- depthTest: false
1612
- }),
1613
- d("mesh", {
1614
- position: y,
1615
- children: d(Ke, {
1616
- center: true,
1617
- style: {
1618
- pointerEvents: "none"
1619
- },
1620
- children: W("div", {
1621
- style: {
1622
- padding: "4px 8px",
1623
- backgroundColor: "rgba(0, 0, 0, 0.7)",
1624
- borderRadius: 4,
1625
- color: "#fff",
1626
- fontSize: 16,
1627
- fontFamily: "monospace",
1628
- whiteSpace: "nowrap",
1629
- transform: "rotate(-90deg)",
1630
- transformOrigin: "center center",
1631
- pointerEvents: "none"
1632
- },
1633
- children: [
1634
- t === "inch" ? (c / 25.4).toFixed(2) : c.toFixed(1),
1635
- " ",
1636
- t === "inch" ? "in" : "mm"
1637
- ]
1638
- })
1639
- })
1640
- })
1641
- ]
1642
- });
1643
- }, $n = ({ modelSize: e, isAligned: s, isCut: o, mesh: t, viewMode: l, sliceY: a, landmarkCount: c = 0 }) => {
1644
- const { set: u, size: n, camera: i, invalidate: r } = on(), f = Ie(false), y = Ie(s), p = Ie(o), m = Ie(l), g = Ie(new h()), w = Ie(null), C = Ie(c), x = Fe(() => {
1645
- if (!t || e <= 0) return;
1646
- const S = t.geometry;
1647
- S.computeBoundingBox();
1648
- const v = S.boundingBox, M = new h();
1649
- v.getCenter(M);
1650
- const L = new h();
1651
- v.getSize(L), g.current.copy(L);
1652
- const P = n.width / n.height, H = Math.max(L.y, L.x / P) * 1.2, O = H * P, $ = new J.OrthographicCamera(-O / 2, O / 2, H / 2, -H / 2, 0.1, e * 10);
1653
- $.position.set(0, M.y, e * 2), $.lookAt(0, M.y, 0), u({
1654
- camera: $
1655
- });
1656
- }, [
1657
- t,
1658
- e,
1659
- n,
1660
- u
1661
- ]), b = Fe((S) => {
1662
- const v = S.position.clone(), M = v.length(), L = Math.atan2(v.x, v.z), P = Math.acos(v.y / M), O = L + 0.02;
1663
- S.position.set(M * Math.sin(P) * Math.sin(O), M * Math.cos(P), M * Math.sin(P) * Math.cos(O)), S.lookAt(0, 0, 0), S.updateMatrixWorld(true), r();
1664
- }, [
1665
- r
1666
- ]);
1667
- return Se(() => {
1668
- if (e > 0 && !f.current && !s) {
1669
- f.current = true;
1670
- const S = new J.PerspectiveCamera(50, n.width / n.height, 0.1, e * 10);
1671
- S.position.set(e * 0.3, e * 0.2, e * 1.5), S.lookAt(0, 0, 0), u({
1672
- camera: S
1673
- }), requestAnimationFrame(() => b(S));
1674
- }
1675
- }, [
1676
- e,
1677
- n,
1678
- u,
1679
- s,
1680
- b
1681
- ]), Se(() => {
1682
- const S = C.current;
1683
- C.current = c, S === 0 && c === 1 && !s && requestAnimationFrame(() => b(i));
1684
- }, [
1685
- c,
1686
- s,
1687
- i,
1688
- b
1689
- ]), Se(() => {
1690
- y.current === s && p.current === o || (y.current = s, p.current = o, s && l === "3D" && x());
1691
- }, [
1692
- s,
1693
- o,
1694
- l,
1695
- x
1696
- ]), Se(() => {
1697
- if (m.current === l) return;
1698
- const S = m.current;
1699
- if (m.current = l, !(!s || !t || e <= 0)) if (l === "2D" && a != null) {
1700
- w.current = i;
1701
- const v = t.geometry, M = v.getAttribute("position"), L = M.array, P = e * 0.15;
1702
- let H = 1 / 0, O = -1 / 0, $ = 1 / 0, R = -1 / 0, Y = false;
1703
- for (let B = 0; B < M.count; B++) if (Math.abs(L[B * 3 + 1] - a) < P) {
1704
- const T = L[B * 3], E = L[B * 3 + 2];
1705
- T < H && (H = T), T > O && (O = T), E < $ && ($ = E), E > R && (R = E), Y = true;
1706
- }
1707
- if (!Y) {
1708
- v.computeBoundingBox();
1709
- const B = v.boundingBox;
1710
- H = B.min.x, O = B.max.x, $ = B.min.z, R = B.max.z;
1711
- }
1712
- const N = (H + O) / 2, ne = ($ + R) / 2, oe = n.width / n.height, le = 1.4, ee = (O - H) * le, D = (R - $) * le;
1713
- let z, F;
1714
- ee / D > oe ? (z = ee, F = ee / oe) : (F = D, z = D * oe);
1715
- const V = new J.OrthographicCamera(-z / 2, z / 2, F / 2, -F / 2, 0.1, e * 10);
1716
- V.position.set(N, a + e * 2, ne), V.up.set(0, 0, -1), V.lookAt(N, a, ne), u({
1717
- camera: V
1718
- });
1719
- } else S === "2D" && (w.current ? (u({
1720
- camera: w.current
1721
- }), w.current = null) : x());
1722
- }, [
1723
- l,
1724
- a,
1725
- s,
1726
- t,
1727
- e,
1728
- n,
1729
- u,
1730
- i,
1731
- x
1732
- ]), Se(() => {
1733
- if (!s || !i || !i.isOrthographicCamera) return;
1734
- const S = i;
1735
- if (l === "2D") {
1736
- if (!t || a == null) return;
1737
- const v = t.geometry, M = v.getAttribute("position"), L = M.array, P = e * 0.15;
1738
- let H = 1 / 0, O = -1 / 0, $ = 1 / 0, R = -1 / 0, Y = false;
1739
- for (let z = 0; z < M.count; z++) if (Math.abs(L[z * 3 + 1] - a) < P) {
1740
- const F = L[z * 3], V = L[z * 3 + 2];
1741
- F < H && (H = F), F > O && (O = F), V < $ && ($ = V), V > R && (R = V), Y = true;
1742
- }
1743
- if (!Y) {
1744
- v.computeBoundingBox();
1745
- const z = v.boundingBox;
1746
- H = z.min.x, O = z.max.x, $ = z.min.z, R = z.max.z;
1747
- }
1748
- const N = n.width / n.height, ne = 1.4, oe = (O - H) * ne, le = (R - $) * ne;
1749
- let ee, D;
1750
- oe / le > N ? (ee = oe, D = oe / N) : (D = le, ee = le * N), S.left = -ee / 2, S.right = ee / 2, S.top = D / 2, S.bottom = -D / 2;
1751
- } else {
1752
- const v = g.current, M = n.width / n.height, L = Math.max(v.y, v.x / M) * 1.2, P = L * M;
1753
- S.left = -P / 2, S.right = P / 2, S.top = L / 2, S.bottom = -L / 2;
1754
- }
1755
- S.updateProjectionMatrix();
1756
- }, [
1757
- n.width,
1758
- n.height,
1759
- s,
1760
- i,
1761
- l,
1762
- t
1763
- ]), null;
1764
- }, Nn = ({ mesh: e, isDragging: s }) => {
1765
- var _a;
1766
- const o = e.geometry;
1767
- o.computeBoundingBox();
1768
- const t = new h();
1769
- return (_a = o.boundingBox) == null ? void 0 : _a.getCenter(t), d(Dt, {
1770
- enableDamping: false,
1771
- enablePan: false,
1772
- minPolarAngle: Math.PI * 0.15,
1773
- maxPolarAngle: Math.PI * 0.85,
1774
- minZoom: 0.5,
1775
- maxZoom: 3,
1776
- enabled: !s,
1777
- target: [
1778
- t.x,
1779
- t.y,
1780
- t.z
1781
- ]
1782
- });
1783
- }, jn = ({ wasAutoScaled: e, onDismiss: s }) => W("div", {
1784
- style: {
1785
- position: "absolute",
1786
- bottom: 16,
1787
- left: 16,
1788
- zIndex: 10,
1789
- display: "flex",
1790
- alignItems: "flex-start",
1791
- gap: 10,
1792
- padding: "10px 14px",
1793
- maxWidth: 320,
1794
- backgroundColor: e ? "rgba(30, 70, 160, 0.92)" : "rgba(40, 40, 40, 0.88)",
1795
- borderRadius: 8,
1796
- boxShadow: "0 2px 12px rgba(0,0,0,0.15)",
1797
- fontFamily: "system-ui, sans-serif"
1798
- },
1799
- children: [
1800
- d("span", {
1801
- style: {
1802
- fontSize: 13,
1803
- color: "#fff",
1804
- lineHeight: "20px"
1805
- },
1806
- children: e ? "Units detected as meters - converted to mm" : "Units detected as mm"
1807
- }),
1808
- d("button", {
1809
- onClick: s,
1810
- style: {
1811
- background: "none",
1812
- border: "none",
1813
- color: "rgba(255,255,255,0.7)",
1814
- cursor: "pointer",
1815
- fontSize: 16,
1816
- lineHeight: "20px",
1817
- padding: 0,
1818
- marginLeft: "auto",
1819
- flexShrink: 0
1820
- },
1821
- children: "X"
1822
- })
1823
- ]
1824
- }), Hn = ({ isDoubleShell: e, onDismiss: s }) => W("div", {
1825
- style: {
1826
- position: "absolute",
1827
- bottom: 68,
1828
- left: 16,
1829
- zIndex: 10,
1830
- display: "flex",
1831
- alignItems: "flex-start",
1832
- gap: 10,
1833
- padding: "10px 14px",
1834
- maxWidth: 320,
1835
- backgroundColor: e ? "rgba(130, 80, 20, 0.92)" : "rgba(40, 40, 40, 0.88)",
1836
- borderRadius: 8,
1837
- boxShadow: "0 2px 12px rgba(0,0,0,0.15)",
1838
- fontFamily: "system-ui, sans-serif"
1839
- },
1840
- children: [
1841
- d("span", {
1842
- style: {
1843
- fontSize: 13,
1844
- color: "#fff",
1845
- lineHeight: "20px"
1846
- },
1847
- children: e ? "Double shell scan detected" : "Single shell scan detected"
1848
- }),
1849
- d("button", {
1850
- onClick: s,
1851
- style: {
1852
- background: "none",
1853
- border: "none",
1854
- color: "rgba(255,255,255,0.7)",
1855
- cursor: "pointer",
1856
- fontSize: 16,
1857
- lineHeight: "20px",
1858
- padding: 0,
1859
- marginLeft: "auto",
1860
- flexShrink: 0
1861
- },
1862
- children: "X"
1863
- })
1864
- ]
1865
- }), Yn = ({ steps: e, currentStep: s, accentColor: o = "rgb(12, 67, 173)" }) => d("div", {
1866
- style: {
1867
- backgroundColor: "#fff",
1868
- borderBottom: "1px solid #e0e0e0",
1869
- display: "flex",
1870
- alignItems: "center",
1871
- padding: "24px 24px",
1872
- flexShrink: 0
1873
- },
1874
- children: e.map((t, l) => {
1875
- const a = t.number < s, c = t.number === s;
1876
- return W("div", {
1877
- style: {
1878
- display: "contents"
1879
- },
1880
- children: [
1881
- W("div", {
1882
- style: {
1883
- display: "flex",
1884
- alignItems: "center",
1885
- gap: 8,
1886
- padding: "0 8px",
1887
- flexShrink: 0,
1888
- cursor: "default"
1889
- },
1890
- children: [
1891
- d("div", {
1892
- style: {
1893
- width: 24,
1894
- height: 24,
1895
- borderRadius: "50%",
1896
- backgroundColor: a || c ? o : "rgba(0, 0, 0, 0.38)",
1897
- color: "#fff",
1898
- display: "flex",
1899
- alignItems: "center",
1900
- justifyContent: "center",
1901
- fontSize: 12,
1902
- fontFamily: "system-ui, sans-serif",
1903
- flexShrink: 0
1904
- },
1905
- children: a ? "\u2713" : t.number
1906
- }),
1907
- d("div", {
1908
- style: {
1909
- fontSize: 14,
1910
- fontWeight: c ? 600 : 400,
1911
- color: c ? "rgba(0, 0, 0, 0.87)" : "rgba(0, 0, 0, 0.54)",
1912
- fontFamily: "system-ui, sans-serif",
1913
- whiteSpace: "nowrap"
1914
- },
1915
- children: t.label
1916
- })
1917
- ]
1918
- }),
1919
- l < e.length - 1 && d("div", {
1920
- style: {
1921
- flex: "auto",
1922
- borderTop: "1px solid #bdbdbd",
1923
- margin: "0 8px"
1924
- }
1925
- })
1926
- ]
1927
- }, t.number);
1928
- })
1929
- }), Gn = ({ mesh: e, upperY: s, originY: o, modelSize: t, meshColor: l = "#c8c8c8", displayUnit: a = "mm" }) => {
1930
- const c = e.geometry, u = de(() => new $e(c, {
1931
- maxLeafTris: Ye
1932
- }), [
1933
- c
1934
- ]), n = de(() => Ze(u, c, o), [
1935
- u,
1936
- c,
1937
- o
1938
- ]), i = de(() => new it(new h(0, -1, 0), s), [
1939
- s
1940
- ]), { mlLine: r, apLine: f, mlWidth: y, apWidth: p } = de(() => {
1941
- let w = null, C = null, x = 0, b = 0;
1942
- if (n.linePoints.length >= 2) {
1943
- let S = n.linePoints[0], v = n.linePoints[0], M = n.linePoints[0], L = n.linePoints[0];
1944
- for (const P of n.linePoints) P.x < S.x && (S = P), P.x > v.x && (v = P), P.z < M.z && (M = P), P.z > L.z && (L = P);
1945
- w = [
1946
- new h(S.x, o, S.z),
1947
- new h(v.x, o, v.z)
1948
- ], C = [
1949
- new h(M.x, o, M.z),
1950
- new h(L.x, o, L.z)
1951
- ], x = w[0].distanceTo(w[1]), b = C[0].distanceTo(C[1]);
1952
- }
1953
- return {
1954
- mlLine: w,
1955
- apLine: C,
1956
- mlWidth: x,
1957
- apWidth: b
1958
- };
1959
- }, [
1960
- n,
1961
- o
1962
- ]), m = (w) => a === "inch" ? (w / 25.4).toFixed(2) : w.toFixed(1), g = a === "inch" ? "in" : "mm";
1963
- return W(He, {
1964
- children: [
1965
- d("mesh", {
1966
- geometry: e.geometry,
1967
- children: d("meshStandardMaterial", {
1968
- color: l,
1969
- side: J.DoubleSide,
1970
- transparent: true,
1971
- opacity: 0.15,
1972
- depthWrite: false,
1973
- clippingPlanes: [
1974
- i
1975
- ]
1976
- })
1977
- }),
1978
- n.linePoints.length >= 2 && d(ge, {
1979
- points: n.linePoints,
1980
- color: "#00ff00",
1981
- lineWidth: 3,
1982
- depthTest: false,
1983
- depthWrite: false,
1984
- transparent: true
1985
- }),
1986
- r && W(He, {
1987
- children: [
1988
- d(ge, {
1989
- points: r,
1990
- color: "#ff8800",
1991
- lineWidth: 2,
1992
- depthTest: false,
1993
- depthWrite: false,
1994
- transparent: true
1995
- }),
1996
- d(Ke, {
1997
- position: [
1998
- r[0].x,
1999
- o,
2000
- r[0].z - t * 0.02
2001
- ],
2002
- center: true,
2003
- style: {
2004
- pointerEvents: "none"
2005
- },
2006
- children: d("div", {
2007
- style: {
2008
- whiteSpace: "nowrap",
2009
- padding: "2px 6px",
2010
- backgroundColor: "rgba(0,0,0,0.75)",
2011
- borderRadius: 3
2012
- },
2013
- children: W("span", {
2014
- style: {
2015
- fontSize: 12,
2016
- color: "#ff8800",
2017
- fontFamily: "monospace"
2018
- },
2019
- children: [
2020
- "ML ",
2021
- m(y),
2022
- " ",
2023
- g
2024
- ]
2025
- })
2026
- })
2027
- })
2028
- ]
2029
- }),
2030
- f && W(He, {
2031
- children: [
2032
- d(ge, {
2033
- points: f,
2034
- color: "#ff00ff",
2035
- lineWidth: 2,
2036
- depthTest: false,
2037
- depthWrite: false,
2038
- transparent: true
2039
- }),
2040
- d(Ke, {
2041
- position: [
2042
- Math.max(f[0].x, f[1].x) + t * 0.02,
2043
- o,
2044
- f[0].z > f[1].z ? f[0].z : f[1].z
2045
- ],
2046
- center: true,
2047
- style: {
2048
- pointerEvents: "none"
2049
- },
2050
- children: d("div", {
2051
- style: {
2052
- whiteSpace: "nowrap",
2053
- padding: "2px 6px",
2054
- backgroundColor: "rgba(0,0,0,0.75)",
2055
- borderRadius: 3
2056
- },
2057
- children: W("span", {
2058
- style: {
2059
- fontSize: 12,
2060
- color: "#ff00ff",
2061
- fontFamily: "monospace"
2062
- },
2063
- children: [
2064
- "AP ",
2065
- m(p),
2066
- " ",
2067
- g
2068
- ]
2069
- })
2070
- })
2071
- })
2072
- ]
2073
- })
2074
- ]
2075
- });
2076
- }, Xn = {
2077
- pcaAxes: true,
2078
- obb: true,
2079
- obbAxis: true,
2080
- shellComponents: true,
2081
- circumferenceScan: false,
2082
- landmarkAxis: true,
2083
- iterativePCA: false,
2084
- fullRegionPCA: true
2085
- }, Zn = [
2086
- "#ff4444",
2087
- "#44cc44",
2088
- "#4488ff"
2089
- ];
2090
- function Ot(e) {
2091
- const s = e.getAttribute("position"), o = s.count, t = new h();
2092
- for (let g = 0; g < o; g++) t.x += s.getX(g), t.y += s.getY(g), t.z += s.getZ(g);
2093
- t.divideScalar(o);
2094
- let l = 0, a = 0, c = 0, u = 0, n = 0, i = 0;
2095
- for (let g = 0; g < o; g++) {
2096
- const w = s.getX(g) - t.x, C = s.getY(g) - t.y, x = s.getZ(g) - t.z;
2097
- l += w * w, a += w * C, c += w * x, u += C * C, n += C * x, i += x * x;
2098
- }
2099
- l /= o, a /= o, c /= o, u /= o, n /= o, i /= o;
2100
- const r = [], f = [], y = [
2101
- [
2102
- l,
2103
- a,
2104
- c
2105
- ],
2106
- [
2107
- a,
2108
- u,
2109
- n
2110
- ],
2111
- [
2112
- c,
2113
- n,
2114
- i
2115
- ]
2116
- ];
2117
- for (let g = 0; g < 3; g++) {
2118
- let w = new h(1 + g * 0.1, 1 - g * 0.1, 0.5 + g * 0.3).normalize(), C = 0;
2119
- for (let x = 0; x < 100; x++) {
2120
- const b = y[0][0] * w.x + y[0][1] * w.y + y[0][2] * w.z, S = y[1][0] * w.x + y[1][1] * w.y + y[1][2] * w.z, v = y[2][0] * w.x + y[2][1] * w.y + y[2][2] * w.z, M = new h(b, S, v);
2121
- if (C = M.length(), C < 1e-12) break;
2122
- if (M.divideScalar(C), w.distanceTo(M) < 1e-10) {
2123
- w = M;
2124
- break;
2125
- }
2126
- w = M;
2127
- }
2128
- r.push(w.clone()), f.push(C);
2129
- for (let x = 0; x < 3; x++) for (let b = 0; b < 3; b++) {
2130
- const S = [
2131
- w.x,
2132
- w.y,
2133
- w.z
2134
- ][x], v = [
2135
- w.x,
2136
- w.y,
2137
- w.z
2138
- ][b];
2139
- y[x][b] -= C * S * v;
2140
- }
2141
- }
2142
- const p = new h();
2143
- for (let g = 0; g < o; g++) p.x += s.getX(g), p.y += s.getY(g), p.z += s.getZ(g);
2144
- p.divideScalar(o);
2145
- const m = [
2146
- 0,
2147
- 0,
2148
- 0
2149
- ];
2150
- for (let g = 0; g < 3; g++) {
2151
- let w = 1 / 0, C = -1 / 0;
2152
- const x = r[g];
2153
- for (let b = 0; b < o; b++) {
2154
- const S = s.getX(b) - p.x, v = s.getY(b) - p.y, M = s.getZ(b) - p.z, L = S * x.x + v * x.y + M * x.z;
2155
- L < w && (w = L), L > C && (C = L);
2156
- }
2157
- m[g] = (C - w) / 2;
2158
- }
2159
- return {
2160
- axes: r,
2161
- eigenvalues: f,
2162
- center: p,
2163
- halfExtents: m
2164
- };
2165
- }
2166
- function Kn({ pca: e }) {
2167
- return d("group", {
2168
- children: e.axes.map((s, o) => {
2169
- const t = e.center.clone().addScaledVector(s, e.halfExtents[o]), l = e.center.clone().addScaledVector(s, -e.halfExtents[o]);
2170
- return d(ge, {
2171
- points: [
2172
- l,
2173
- t
2174
- ],
2175
- color: Zn[o],
2176
- lineWidth: 2
2177
- }, o);
2178
- })
2179
- });
2180
- }
2181
- function Un({ pca: e }) {
2182
- const s = de(() => {
2183
- const { center: o, axes: t, halfExtents: l } = e, a = [];
2184
- for (let u = -1; u <= 1; u += 2) for (let n = -1; n <= 1; n += 2) for (let i = -1; i <= 1; i += 2) a.push(o.clone().addScaledVector(t[0], u * l[0]).addScaledVector(t[1], n * l[1]).addScaledVector(t[2], i * l[2]));
2185
- return [
2186
- [
2187
- 0,
2188
- 1
2189
- ],
2190
- [
2191
- 2,
2192
- 3
2193
- ],
2194
- [
2195
- 4,
2196
- 5
2197
- ],
2198
- [
2199
- 6,
2200
- 7
2201
- ],
2202
- [
2203
- 0,
2204
- 2
2205
- ],
2206
- [
2207
- 1,
2208
- 3
2209
- ],
2210
- [
2211
- 4,
2212
- 6
2213
- ],
2214
- [
2215
- 5,
2216
- 7
2217
- ],
2218
- [
2219
- 0,
2220
- 4
2221
- ],
2222
- [
2223
- 1,
2224
- 5
2225
- ],
2226
- [
2227
- 2,
2228
- 6
2229
- ],
2230
- [
2231
- 3,
2232
- 7
2233
- ]
2234
- ].map(([u, n]) => [
2235
- a[u],
2236
- a[n]
2237
- ]);
2238
- }, [
2239
- e
2240
- ]);
2241
- return d("group", {
2242
- children: s.map((o, t) => d(ge, {
2243
- points: o,
2244
- color: "#ffaa00",
2245
- lineWidth: 1,
2246
- transparent: true,
2247
- opacity: 0.5
2248
- }, t))
2249
- });
2250
- }
2251
- function Qn({ redPoint: e, greenPoint: s }) {
2252
- const o = de(() => new h().subVectors(s, e).normalize(), [
2253
- e,
2254
- s
2255
- ]), t = de(() => {
2256
- const a = o.dot(new h(0, 1, 0));
2257
- return Math.acos(Math.min(1, Math.abs(a))) * 180 / Math.PI;
2258
- }, [
2259
- o
2260
- ]), l = t < 1 ? "#44ff44" : t < 5 ? "#ffcc00" : "#ff4444";
2261
- return W("group", {
2262
- children: [
2263
- d(ge, {
2264
- points: [
2265
- e,
2266
- s
2267
- ],
2268
- color: l,
2269
- lineWidth: 3
2270
- }),
2271
- W("mesh", {
2272
- position: e,
2273
- children: [
2274
- d("sphereGeometry", {
2275
- args: [
2276
- 1.5,
2277
- 8,
2278
- 8
2279
- ]
2280
- }),
2281
- d("meshBasicMaterial", {
2282
- color: "#ff4444"
2283
- })
2284
- ]
2285
- }),
2286
- W("mesh", {
2287
- position: s,
2288
- children: [
2289
- d("sphereGeometry", {
2290
- args: [
2291
- 1.5,
2292
- 8,
2293
- 8
2294
- ]
2295
- }),
2296
- d("meshBasicMaterial", {
2297
- color: "#44ff44"
2298
- })
2299
- ]
2300
- })
2301
- ]
2302
- });
2303
- }
2304
- function qn({ geometry: e, redY: s, greenY: o, modelSize: t }) {
2305
- const a = t * 0.15, c = de(() => {
2306
- const u = [];
2307
- let n = o - 10;
2308
- const i = new h(0, 1, 0);
2309
- for (; n > s; ) {
2310
- const r = Math.min(n, o), f = Math.max(n, o), y = rt(e, r, f);
2311
- if (y) {
2312
- const p = y.dot(i), m = Math.acos(Math.min(1, Math.abs(p))) * 180 / Math.PI;
2313
- u.push({
2314
- axis: y,
2315
- regionMin: r,
2316
- regionMax: f,
2317
- angleDeg: m
2318
- });
2319
- }
2320
- n -= 10;
2321
- }
2322
- return u;
2323
- }, [
2324
- e,
2325
- s,
2326
- o
2327
- ]);
2328
- return d("group", {
2329
- children: c.map((u, n) => {
2330
- const i = (u.regionMin + u.regionMax) / 2, r = new h(0, i, 0), f = r.clone().addScaledVector(u.axis, a), y = r.clone().addScaledVector(u.axis, -a), p = n / Math.max(1, c.length - 1), m = u.angleDeg < 0.5 ? `hsl(${120 - p * 120}, 80%, 60%)` : `hsl(${40 - u.angleDeg * 2}, 90%, 55%)`;
2331
- return W("group", {
2332
- children: [
2333
- d(ge, {
2334
- points: [
2335
- y,
2336
- f
2337
- ],
2338
- color: m,
2339
- lineWidth: 1.5,
2340
- transparent: true,
2341
- opacity: 0.7
2342
- }),
2343
- d(ge, {
2344
- points: [
2345
- new h(-a * 0.3, u.regionMin, 0),
2346
- new h(a * 0.3, u.regionMin, 0)
2347
- ],
2348
- color: m,
2349
- lineWidth: 0.5,
2350
- transparent: true,
2351
- opacity: 0.3
2352
- })
2353
- ]
2354
- }, n);
2355
- })
2356
- });
2357
- }
2358
- function Jn({ geometry: e, redY: s, greenY: o, modelSize: t }) {
2359
- const l = de(() => {
2360
- const f = rt(e, s, o);
2361
- if (!f) return null;
2362
- const y = f.dot(new h(0, 1, 0)), p = Math.acos(Math.min(1, Math.abs(y))) * 180 / Math.PI;
2363
- return {
2364
- axis: f,
2365
- angleDeg: p
2366
- };
2367
- }, [
2368
- e,
2369
- s,
2370
- o
2371
- ]);
2372
- if (!l) return null;
2373
- const a = (s + o) / 2, c = new h(0, a, 0), u = t * 0.4, n = c.clone().addScaledVector(l.axis, u), i = c.clone().addScaledVector(l.axis, -u), r = l.angleDeg < 0.5 ? "#00ffff" : l.angleDeg < 2 ? "#ffcc00" : "#ff6600";
2374
- return d("group", {
2375
- children: d(ge, {
2376
- points: [
2377
- i,
2378
- n
2379
- ],
2380
- color: r,
2381
- lineWidth: 3,
2382
- dashed: true,
2383
- dashSize: 3,
2384
- gapSize: 2
2385
- })
2386
- });
2387
- }
2388
- function eo({ pca: e, modelSize: s }) {
2389
- const o = e.axes[0], t = s * 0.6, l = e.center.clone().addScaledVector(o, t), a = e.center.clone().addScaledVector(o, -t);
2390
- return d(ge, {
2391
- points: [
2392
- a,
2393
- l
2394
- ],
2395
- color: "#ff8800",
2396
- lineWidth: 2,
2397
- dashed: true,
2398
- dashSize: 3,
2399
- gapSize: 2
2400
- });
2401
- }
2402
- function to({ geometry: e, redY: s, greenY: o, modelSize: t }) {
2403
- const l = de(() => {
2404
- const i = ot(e), r = new h(0, 1, 0), f = 5;
2405
- e.computeBoundingBox();
2406
- const y = e.boundingBox.max.y, p = [];
2407
- for (let v = s + f; v < y; v += f) {
2408
- const M = pt(i, e, new h(0, v, 0), r);
2409
- M > 0 && p.push({
2410
- y: v,
2411
- circ: M
2412
- });
2413
- }
2414
- if (p.length < 5) return null;
2415
- const m = o - s, g = s + m * 0.3, w = s + m * 0.7, C = p.filter((v) => v.y >= g && v.y <= w);
2416
- if (C.length < 3) return null;
2417
- const x = C.map((v) => v.circ).sort((v, M) => v - M), b = x[Math.floor(x.length / 2)], S = Math.max(...p.map((v) => v.circ));
2418
- return {
2419
- circumferences: p,
2420
- baseline: b,
2421
- maxCirc: S
2422
- };
2423
- }, [
2424
- e,
2425
- s,
2426
- o
2427
- ]);
2428
- if (!l) return null;
2429
- const { circumferences: a, baseline: c, maxCirc: u } = l, n = t * 0.3 / u;
2430
- return W("group", {
2431
- children: [
2432
- a.map(({ y: i, circ: r }, f) => {
2433
- const y = r / c, p = y > 1.6 ? "#ff4444" : y > 1.3 ? "#ffcc00" : "#22cc66", m = r * n;
2434
- return d(ge, {
2435
- points: [
2436
- new h(-m, i, 0),
2437
- new h(m, i, 0)
2438
- ],
2439
- color: p,
2440
- lineWidth: 1.5,
2441
- transparent: true,
2442
- opacity: 0.6
2443
- }, f);
2444
- }),
2445
- (() => {
2446
- const i = c * 1.6 * n, r = a[0].y, f = a[a.length - 1].y;
2447
- return W(He, {
2448
- children: [
2449
- d(ge, {
2450
- points: [
2451
- new h(-i, r, 0),
2452
- new h(-i, f, 0)
2453
- ],
2454
- color: "#ff4444",
2455
- lineWidth: 1,
2456
- dashed: true,
2457
- dashSize: 3,
2458
- gapSize: 2,
2459
- transparent: true,
2460
- opacity: 0.4
2461
- }),
2462
- d(ge, {
2463
- points: [
2464
- new h(i, r, 0),
2465
- new h(i, f, 0)
2466
- ],
2467
- color: "#ff4444",
2468
- lineWidth: 1,
2469
- dashed: true,
2470
- dashSize: 3,
2471
- gapSize: 2,
2472
- transparent: true,
2473
- opacity: 0.4
2474
- })
2475
- ]
2476
- });
2477
- })()
2478
- ]
2479
- });
2480
- }
2481
- function no({ componentDebug: e }) {
2482
- return d("group", {
2483
- children: e.geometries.map((s, o) => {
2484
- const t = e.colors[o] ?? "#888888", l = o === e.innerIdx;
2485
- s.computeBoundingBox();
2486
- const a = new h();
2487
- return s.boundingBox.getCenter(a), W("group", {
2488
- children: [
2489
- d("mesh", {
2490
- geometry: s,
2491
- renderOrder: l ? 2 : 1,
2492
- children: d("meshStandardMaterial", {
2493
- color: t,
2494
- transparent: true,
2495
- opacity: l ? 0.5 : 0.2,
2496
- side: J.DoubleSide,
2497
- depthWrite: false,
2498
- polygonOffset: true,
2499
- polygonOffsetFactor: 1,
2500
- polygonOffsetUnits: 1
2501
- })
2502
- }),
2503
- d("mesh", {
2504
- geometry: s,
2505
- renderOrder: l ? 2 : 1,
2506
- children: d("meshBasicMaterial", {
2507
- color: t,
2508
- wireframe: true,
2509
- transparent: true,
2510
- opacity: l ? 0.4 : 0.15
2511
- })
2512
- }),
2513
- d("group", {
2514
- position: a,
2515
- children: d(Ke, {
2516
- center: true,
2517
- style: {
2518
- pointerEvents: "none"
2519
- },
2520
- children: d("div", {
2521
- style: {
2522
- padding: "2px 8px",
2523
- backgroundColor: "rgba(0,0,0,0.8)",
2524
- borderRadius: 4,
2525
- border: `1px solid ${t}`,
2526
- whiteSpace: "nowrap"
2527
- },
2528
- children: d("span", {
2529
- style: {
2530
- fontSize: 11,
2531
- color: t,
2532
- fontFamily: "monospace",
2533
- fontWeight: l ? 700 : 400
2534
- },
2535
- children: e.labels[o]
2536
- })
2537
- })
2538
- })
2539
- })
2540
- ]
2541
- }, o);
2542
- })
2543
- });
2544
- }
2545
- function oo({ mesh: e, layers: s, landmarkPoints: o, componentDebug: t }) {
2546
- const l = e.geometry, a = de(() => l.getAttribute("position") ? Ot(l) : null, [
2547
- l
2548
- ]), c = de(() => !o || o.length < 2 ? null : {
2549
- red: new h(o[0].position.x, o[0].position.y, o[0].position.z),
2550
- green: new h(o[1].position.x, o[1].position.y, o[1].position.z)
2551
- }, [
2552
- o
2553
- ]);
2554
- return W("group", {
2555
- children: [
2556
- s.pcaAxes && a && d(Kn, {
2557
- pca: a
2558
- }),
2559
- s.obb && a && d(Un, {
2560
- pca: a
2561
- }),
2562
- s.obbAxis && a && d(eo, {
2563
- pca: a,
2564
- modelSize: a.halfExtents[0] ? Math.max(...a.halfExtents) * 2 : 100
2565
- }),
2566
- s.shellComponents && t && d(no, {
2567
- componentDebug: t
2568
- }),
2569
- s.circumferenceScan && c && d(to, {
2570
- geometry: l,
2571
- redY: c.red.y,
2572
- greenY: c.green.y,
2573
- modelSize: (a == null ? void 0 : a.halfExtents[0]) ? Math.max(...a.halfExtents) * 2 : 100
2574
- }),
2575
- s.landmarkAxis && c && d(Qn, {
2576
- redPoint: c.red,
2577
- greenPoint: c.green
2578
- }),
2579
- s.iterativePCA && c && d(qn, {
2580
- geometry: l,
2581
- redY: c.red.y,
2582
- greenY: c.green.y,
2583
- modelSize: (a == null ? void 0 : a.halfExtents[0]) ? Math.max(...a.halfExtents) * 2 : 100
2584
- }),
2585
- s.fullRegionPCA && c && d(Jn, {
2586
- geometry: l,
2587
- redY: c.red.y,
2588
- greenY: c.green.y,
2589
- modelSize: (a == null ? void 0 : a.halfExtents[0]) ? Math.max(...a.halfExtents) * 2 : 100
2590
- })
2591
- ]
2592
- });
2593
- }
2594
- function so({ mesh: e }) {
2595
- const s = e.geometry, o = de(() => {
2596
- if (!s.getAttribute("position")) return null;
2597
- const a = Ot(s), c = a.axes[0], u = a.halfExtents[0] * 1.3;
2598
- return {
2599
- axis: c,
2600
- center: a.center,
2601
- halfLen: u
2602
- };
2603
- }, [
2604
- s
2605
- ]);
2606
- if (!o) return null;
2607
- const t = o.center.clone().addScaledVector(o.axis, o.halfLen), l = o.center.clone().addScaledVector(o.axis, -o.halfLen);
2608
- return d(ge, {
2609
- points: [
2610
- l,
2611
- t
2612
- ],
2613
- color: "#666",
2614
- lineWidth: 1,
2615
- dashed: true,
2616
- dashSize: 4,
2617
- gapSize: 3,
2618
- transparent: true,
2619
- opacity: 0.4,
2620
- depthTest: false,
2621
- renderOrder: 999
2622
- });
2623
- }
2624
- const $t = [
2625
- {
2626
- key: "pcaAxes",
2627
- label: "PCA Axes (full mesh)",
2628
- color: "#ff4444",
2629
- group: "Geometry"
2630
- },
2631
- {
2632
- key: "obb",
2633
- label: "OBB Wireframe",
2634
- color: "#ffaa00",
2635
- group: "Geometry"
2636
- },
2637
- {
2638
- key: "obbAxis",
2639
- label: "OBB Primary Axis",
2640
- color: "#ff8800",
2641
- group: "Geometry"
2642
- },
2643
- {
2644
- key: "shellComponents",
2645
- label: "Shell Components",
2646
- color: "#4488ff",
2647
- group: "Shell Detection"
2648
- },
2649
- {
2650
- key: "circumferenceScan",
2651
- label: "Circumference Scan (step 4.5)",
2652
- color: "#22cc66",
2653
- group: "Isolation"
2654
- },
2655
- {
2656
- key: "landmarkAxis",
2657
- label: "Landmark Axis (rough align)",
2658
- color: "#44ff44",
2659
- group: "Alignment"
2660
- },
2661
- {
2662
- key: "iterativePCA",
2663
- label: "Iterative PCA (step 5)",
2664
- color: "#cc66ff",
2665
- group: "Alignment"
2666
- },
2667
- {
2668
- key: "fullRegionPCA",
2669
- label: "Full Region PCA (step 7)",
2670
- color: "#00ffff",
2671
- group: "Alignment"
2672
- }
2673
- ], ro = [
2674
- ...new Set($t.map((e) => e.group))
2675
- ];
2676
- function io({ layers: e, onToggleLayer: s }) {
2677
- return W("div", {
2678
- style: {
2679
- position: "absolute",
2680
- top: 16,
2681
- left: 16,
2682
- zIndex: 20,
2683
- backgroundColor: "rgba(7, 6, 17, 0.9)",
2684
- border: "1px solid rgba(255,255,255,0.1)",
2685
- borderRadius: 6,
2686
- padding: "10px 12px",
2687
- fontFamily: "system-ui, sans-serif",
2688
- fontSize: 12,
2689
- color: "#ccc",
2690
- minWidth: 180,
2691
- backdropFilter: "blur(8px)"
2692
- },
2693
- children: [
2694
- d("div", {
2695
- style: {
2696
- fontSize: 10,
2697
- fontWeight: 600,
2698
- textTransform: "uppercase",
2699
- letterSpacing: "0.5px",
2700
- color: "#888",
2701
- marginBottom: 8
2702
- },
2703
- children: "Debug Layers"
2704
- }),
2705
- ro.map((o) => W("div", {
2706
- children: [
2707
- d("div", {
2708
- style: {
2709
- fontSize: 9,
2710
- fontWeight: 600,
2711
- textTransform: "uppercase",
2712
- letterSpacing: "0.5px",
2713
- color: "#555",
2714
- marginTop: 6,
2715
- marginBottom: 4
2716
- },
2717
- children: o
2718
- }),
2719
- $t.filter((t) => t.group === o).map(({ key: t, label: l, color: a }) => W("label", {
2720
- style: {
2721
- display: "flex",
2722
- alignItems: "center",
2723
- gap: 8,
2724
- padding: "3px 0",
2725
- cursor: "pointer",
2726
- userSelect: "none"
2727
- },
2728
- children: [
2729
- d("input", {
2730
- type: "checkbox",
2731
- checked: e[t],
2732
- onChange: () => s(t),
2733
- style: {
2734
- accentColor: a,
2735
- width: 14,
2736
- height: 14,
2737
- cursor: "pointer"
2738
- }
2739
- }),
2740
- d("span", {
2741
- style: {
2742
- width: 8,
2743
- height: 8,
2744
- borderRadius: "50%",
2745
- backgroundColor: a,
2746
- opacity: e[t] ? 1 : 0.3,
2747
- flexShrink: 0
2748
- }
2749
- }),
2750
- d("span", {
2751
- style: {
2752
- opacity: e[t] ? 1 : 0.5
2753
- },
2754
- children: l
2755
- })
2756
- ]
2757
- }, t))
2758
- ]
2759
- }, o))
2760
- ]
2761
- });
2762
- }
2763
- const lo = ({ config: e, spacingType: s, scanUrl: o, formMeasurements: t, onComplete: l, isDebugUser: a = false, onAnalyticsEvent: c, wasmModule: u }) => {
2764
- const [n, i] = q(null), [r, f] = q(0), [y, p] = q(false), [m, g] = q(false), [w, C] = q(""), [x, b] = q("3D"), [S, v] = q(s === "AK" ? 2 : 1), [M, L] = q(false), [P, H] = q(null), [O, $] = q(null), [R, Y] = q(s ?? null), [N, ne] = q("mm"), [oe, le] = q(false), [ee, D] = q(""), [z, F] = q(false), [V, B] = q(false), [T, E] = q(false), [j, X] = q(false), [Q, ie] = q(false), [se, A] = q([]), [I, k] = q(null), [G, U] = q(null), [re, Pe] = q(null), [me, ae] = q(null), [xe, Re] = q(false), [pe, we] = q(Xn), [he, Ge] = q(false), [fe, Ne] = q(null), [Le, ye] = q("obj"), [Te, Me] = q(false), [Ae, De] = q({}), [ze, Ee] = q(t), [ke, Ue] = q(true), [mt] = q("#c8c8c8"), [jt] = q(1), [Xe, Ht] = q(false), lt = Ie(null), { landmarkPoints: ce, clearLandmarkPoints: Yt, addLandmarkPoint: xt, removeLandmarkPoint: yt, updateLandmarkPositions: bt, setAligned: wt, isAligned: be, setCut: St, isCut: Gt } = gt(), at = S * We;
2765
- Se(() => {
2766
- t && Ee(t);
2767
- }, [
2768
- t
2769
- ]), Se(() => {
2770
- t || (Ee(void 0), De({}));
2771
- }, [
2772
- S
2773
- ]);
2774
- const ct = Ie(false);
2775
- Se(() => {
2776
- if (!be || se.length === 0 || ct.current || !c) return;
2777
- ct.current = true;
2778
- const _ = ce.length >= 3 ? Math.abs(ce[2].position.y - ce[1].position.y) : null;
2779
- c("dimensions_calculated", {
2780
- spacing_type: R,
2781
- source_unit: "mm",
2782
- file_format: Le,
2783
- measurement_source: "scan_derived",
2784
- is_double_wall: T,
2785
- is_unit_converted: false,
2786
- form_measurements: (ze == null ? void 0 : ze.filter((K) => K != null)) ?? null,
2787
- scan_measurements: se.map((K) => +(K.modifiedValue ?? K.originalValue).toFixed(1)),
2788
- measurement_variance: ze ? se.map((K, ue) => {
2789
- const Z = ze[ue];
2790
- return Z == null ? null : +((K.modifiedValue ?? K.originalValue) - Z).toFixed(1);
2791
- }) : null,
2792
- frontal_height: _ !== null ? +_.toFixed(1) : null
2793
- });
2794
- }, [
2795
- be,
2796
- se
2797
- ]), Se(() => {
2798
- u !== void 0 && (lt.current = u), Ht(true);
2799
- }, [
2800
- u
2801
- ]);
2802
- const Qe = Fe((_, K) => {
2803
- _.computeBoundingBox();
2804
- const ue = _.boundingBox, Z = new h();
2805
- ue.getCenter(Z), _.translate(-Z.x, -Z.y, -Z.z), _.computeBoundingBox();
2806
- const Be = _.boundingBox, te = new h();
2807
- Be.getSize(te), f(Math.max(te.x, te.y, te.z));
2808
- const ve = new J.Mesh(_, new J.MeshStandardMaterial({
2809
- color: 8947848,
2810
- side: J.DoubleSide
2811
- }));
2812
- i(ve), F(K), B(true);
2813
- }, []), qe = Fe(async (_, K) => {
2814
- ae(null);
2815
- const ue = K.toLowerCase(), Z = ue.endsWith(".stl");
2816
- if (!ue.endsWith(".obj") && !Z) {
2817
- ae("Unsupported file format. Please use OBJ or STL.");
2818
- return;
2819
- }
2820
- ye(Z ? "stl" : "obj"), g(true), C("Processing file...");
2821
- try {
2822
- let te;
2823
- if (Z) if (C("Converting STL..."), _ instanceof ArrayBuffer) {
2824
- const Ce = new Blob([
2825
- _
2826
- ]), Ve = new File([
2827
- Ce
2828
- ], K);
2829
- te = await ft(Ve);
2830
- } else {
2831
- const Ce = new Blob([
2832
- _
2833
- ]), Ve = new File([
2834
- Ce
2835
- ], K);
2836
- te = await ft(Ve);
2837
- }
2838
- else te = typeof _ == "string" ? _ : new TextDecoder().decode(_);
2839
- const ve = lt.current ? await bn(te, lt.current, C) : null;
2840
- if (ve) e.showAmputationModal && !s ? (H(ve), L(true)) : (Qe(ve.geometry, ve.wasScaled), ve.innerShellExtracted && (X(true), E(true)), ve.componentDebug && $(ve.componentDebug));
2841
- else {
2842
- C("Using fallback loader...");
2843
- const Ce = wn(te);
2844
- Ce ? e.showAmputationModal && !s ? (H({
2845
- geometry: Ce,
2846
- wasScaled: false,
2847
- innerShellExtracted: false
2848
- }), L(true)) : Qe(Ce, false) : ae("Failed to parse the mesh.");
2849
- }
2850
- } catch (te) {
2851
- ae(te instanceof Error ? te.message : "Failed to process the mesh file.");
2852
- } finally {
2853
- g(false), C("");
2854
- }
2855
- }, [
2856
- Xe,
2857
- e.showAmputationModal,
2858
- s,
2859
- Qe
2860
- ]);
2861
- Se(() => {
2862
- if (!o || !Xe) return;
2863
- (async () => {
2864
- g(true), C("Downloading scan...");
2865
- try {
2866
- const K = await fetch(o);
2867
- if (!K.ok) throw new Error(`Failed to download scan: ${K.status}`);
2868
- const Z = new URL(o).pathname.split("/").pop() || "scan.obj";
2869
- if (Z.toLowerCase().endsWith(".stl")) {
2870
- const te = await K.arrayBuffer();
2871
- await qe(te, Z);
2872
- } else {
2873
- const te = await K.text();
2874
- await qe(te, Z);
2875
- }
2876
- } catch (K) {
2877
- ae(K instanceof Error ? K.message : "Failed to load scan from URL."), g(false), C("");
2878
- }
2879
- })();
2880
- }, [
2881
- o,
2882
- Xe
2883
- ]);
2884
- const Xt = Fe((_) => {
2885
- _.preventDefault(), p(true);
2886
- }, []), Zt = Fe((_) => {
2887
- _.preventDefault(), p(false);
2888
- }, []), Kt = Fe(async (_) => {
2889
- if (_.preventDefault(), p(false), !Xe) {
2890
- ae("WASM module is still loading. Please wait.");
2891
- return;
2892
- }
2893
- const K = _.dataTransfer.files[0];
2894
- if (!K) return;
2895
- const ue = K.name.toLowerCase();
2896
- if (!ue.endsWith(".obj") && !ue.endsWith(".stl")) {
2897
- ae("Please drop an OBJ or STL file.");
2898
- return;
2899
- }
2900
- if (ue.endsWith(".stl")) {
2901
- ye("stl"), g(true), C("Converting STL...");
2902
- try {
2903
- const Z = await ft(K);
2904
- await qe(Z, K.name);
2905
- } catch (Z) {
2906
- ae(Z instanceof Error ? Z.message : "Failed to process STL file."), g(false), C("");
2907
- }
2908
- } else {
2909
- const Z = await K.text();
2910
- await qe(Z, K.name);
2911
- }
2912
- }, [
2913
- Xe,
2914
- qe
2915
- ]), Ut = Fe((_) => {
2916
- Y(_), v(_ === "AK" ? 2 : 1), L(false), P && (Qe(P.geometry, P.wasScaled), P.innerShellExtracted && (X(true), E(true)), P.componentDebug && $(P.componentDebug), H(null)), c == null ? void 0 : c("file_loaded", {
2917
- spacing_type: _,
2918
- file_format: Le,
2919
- is_double_wall: (P == null ? void 0 : P.innerShellExtracted) ?? false
2920
- });
2921
- }, [
2922
- P,
2923
- Qe,
2924
- c,
2925
- Le
2926
- ]), Qt = Fe(() => {
2927
- !n || ce.length < 2 || (le(true), D("Please wait..."), setTimeout(() => {
2928
- In(n, ce, at, {
2929
- onStatus: D,
2930
- addLandmarkPoint: xt,
2931
- removeLandmarkPoint: yt,
2932
- updateLandmarkPositions: bt,
2933
- setAligned: wt,
2934
- setCut: St,
2935
- setModelSize: f,
2936
- setOriginalEndY: Pe,
2937
- setAdjustedStartY: k,
2938
- setAdjustedEndY: U,
2939
- setError: ae,
2940
- setDoubleShell: (_) => {
2941
- E(_), ie(true);
2942
- },
2943
- setClippedReferenceGeometry: Ne,
2944
- skipDoubleShellDetection: j
2945
- }), ct.current = false, le(false);
2946
- }, 50));
2947
- }, [
2948
- n,
2949
- ce,
2950
- bt,
2951
- wt,
2952
- xt,
2953
- yt,
2954
- St,
2955
- at,
2956
- j
2957
- ]), qt = Fe(() => {
2958
- if (!l || !n || se.length === 0 || !R) return;
2959
- let _ = 0, K = 0;
2960
- const ue = ce.length >= 3 ? Math.abs(ce[2].position.y - ce[1].position.y) : 0;
2961
- if (ce.length >= 2) {
2962
- const Z = n.geometry, te = ce[1].position.y;
2963
- try {
2964
- const ve = ot(Z), Ce = Ze(ve, Z, te);
2965
- if (Ce.linePoints.length >= 2) {
2966
- let Ve = Ce.linePoints[0], Je = Ce.linePoints[0], et = Ce.linePoints[0], tt = Ce.linePoints[0];
2967
- for (const _e of Ce.linePoints) _e.x < Ve.x && (Ve = _e), _e.x > Je.x && (Je = _e), _e.z < et.z && (et = _e), _e.z > tt.z && (tt = _e);
2968
- _ = new h(Ve.x, te, Ve.z).distanceTo(new h(Je.x, te, Je.z)), K = new h(et.x, te, et.z).distanceTo(new h(tt.x, te, tt.z));
2969
- }
2970
- } catch {
2971
- }
2972
- }
2973
- l({
2974
- spacingType: R,
2975
- sourceUnit: "mm",
2976
- fileFormat: Le,
2977
- measurementSource: ze ? "form_provided" : "scan_derived",
2978
- isDoubleWall: T,
2979
- isUnitConverted: false,
2980
- formMeasurements: ze,
2981
- scanMeasurements: se,
2982
- frontalHeight: ue,
2983
- transverseML: _,
2984
- transverseAP: K,
2985
- scanUrl: o
2986
- });
2987
- }, [
2988
- l,
2989
- n,
2990
- se,
2991
- R,
2992
- ce,
2993
- Le,
2994
- T,
2995
- ze,
2996
- o
2997
- ]), Jt = be ? 4 : n ? ce.length === 0 ? 2 : 3 : 1, en = [
2998
- {
2999
- label: "Load File",
3000
- number: 1
3001
- },
3002
- {
3003
- label: "Set Origin",
3004
- number: 2
3005
- },
3006
- {
3007
- label: R === "AK" ? "Set IT/Perineum" : "Set MPT",
3008
- number: 3
3009
- },
3010
- {
3011
- label: "Results",
3012
- number: 4
3013
- }
3014
- ];
3015
- return W(dn.Provider, {
3016
- value: e,
3017
- children: [
3018
- W("div", {
3019
- style: {
3020
- flex: 1,
3021
- display: "flex",
3022
- flexDirection: "column",
3023
- backgroundColor: "#F9F9FA",
3024
- minWidth: 0,
3025
- position: "relative",
3026
- height: "100%"
3027
- },
3028
- children: [
3029
- e.showToolbar && d("div", {
3030
- style: {
3031
- height: 83,
3032
- backgroundColor: "#9e9e9e",
3033
- flexShrink: 0,
3034
- position: "relative",
3035
- overflow: "hidden"
3036
- },
3037
- children: d("div", {
3038
- style: {
3039
- position: "absolute",
3040
- inset: 0,
3041
- opacity: 0.1,
3042
- backgroundImage: "repeating-linear-gradient(45deg, transparent, transparent 10px, #fff 10px, #fff 12px)",
3043
- pointerEvents: "none"
3044
- }
3045
- })
3046
- }),
3047
- d(Yn, {
3048
- steps: en,
3049
- currentStep: Jt
3050
- }),
3051
- W("div", {
3052
- style: {
3053
- flex: 1,
3054
- display: "flex",
3055
- flexDirection: "column",
3056
- minHeight: 0
3057
- },
3058
- children: [
3059
- W("div", {
3060
- style: {
3061
- flex: 1,
3062
- position: "relative",
3063
- minHeight: 0,
3064
- overflow: "hidden"
3065
- },
3066
- onDragOver: e.showDragDrop ? Xt : void 0,
3067
- onDragLeave: e.showDragDrop ? Zt : void 0,
3068
- onDrop: e.showDragDrop ? Kt : void 0,
3069
- children: [
3070
- e.showDragDrop && !n && !m && d("div", {
3071
- style: {
3072
- position: "absolute",
3073
- inset: 16,
3074
- border: "3px dashed #ccc",
3075
- borderRadius: 4,
3076
- display: "flex",
3077
- alignItems: "center",
3078
- justifyContent: "center",
3079
- pointerEvents: "none"
3080
- },
3081
- children: Xe ? d("div", {
3082
- style: {
3083
- fontSize: 18,
3084
- color: "#aaa",
3085
- fontWeight: 400,
3086
- fontFamily: "system-ui, sans-serif"
3087
- },
3088
- children: "Drag & Drop Files Here"
3089
- }) : W("div", {
3090
- style: {
3091
- textAlign: "center"
3092
- },
3093
- children: [
3094
- d("div", {
3095
- style: {
3096
- width: 32,
3097
- height: 32,
3098
- border: "3px solid rgba(0,0,0,0.1)",
3099
- borderTopColor: "#4a90d9",
3100
- borderRadius: "50%",
3101
- animation: "spin 1s linear infinite",
3102
- margin: "0 auto 12px"
3103
- }
3104
- }),
3105
- d("div", {
3106
- style: {
3107
- fontSize: 16,
3108
- color: "#999",
3109
- fontFamily: "system-ui, sans-serif"
3110
- },
3111
- children: "Loading WASM module..."
3112
- }),
3113
- d("style", {
3114
- children: "@keyframes spin { to { transform: rotate(360deg); } }"
3115
- })
3116
- ]
3117
- })
3118
- }),
3119
- !e.showDragDrop && !n && !m && !me && d("div", {
3120
- style: {
3121
- position: "absolute",
3122
- inset: 0,
3123
- display: "flex",
3124
- alignItems: "center",
3125
- justifyContent: "center"
3126
- },
3127
- children: W("div", {
3128
- style: {
3129
- textAlign: "center"
3130
- },
3131
- children: [
3132
- d("div", {
3133
- style: {
3134
- width: 32,
3135
- height: 32,
3136
- border: "3px solid rgba(0,0,0,0.1)",
3137
- borderTopColor: "#4a90d9",
3138
- borderRadius: "50%",
3139
- animation: "spin 1s linear infinite",
3140
- margin: "0 auto 12px"
3141
- }
3142
- }),
3143
- d("div", {
3144
- style: {
3145
- fontSize: 16,
3146
- color: "#999",
3147
- fontFamily: "system-ui, sans-serif"
3148
- },
3149
- children: "Loading scan..."
3150
- }),
3151
- d("style", {
3152
- children: "@keyframes spin { to { transform: rotate(360deg); } }"
3153
- })
3154
- ]
3155
- })
3156
- }),
3157
- n && !be && ce.length === 0 && W("div", {
3158
- style: {
3159
- position: "absolute",
3160
- top: 16,
3161
- left: "50%",
3162
- transform: "translateX(-50%)",
3163
- display: "flex",
3164
- alignItems: "center",
3165
- gap: 8,
3166
- padding: "8px 16px",
3167
- backgroundColor: "rgba(0, 0, 0, 0.6)",
3168
- borderRadius: 8,
3169
- color: "#fff",
3170
- fontSize: 13,
3171
- pointerEvents: "none",
3172
- zIndex: 5,
3173
- fontFamily: "system-ui, sans-serif"
3174
- },
3175
- children: [
3176
- d("div", {
3177
- style: {
3178
- width: 10,
3179
- height: 10,
3180
- borderRadius: "50%",
3181
- backgroundColor: "#ff4444",
3182
- flexShrink: 0
3183
- }
3184
- }),
3185
- "Click mesh to set Origin"
3186
- ]
3187
- }),
3188
- n && !be && ce.length === 1 && W("div", {
3189
- style: {
3190
- position: "absolute",
3191
- top: 16,
3192
- left: "50%",
3193
- transform: "translateX(-50%)",
3194
- display: "flex",
3195
- alignItems: "center",
3196
- gap: 8,
3197
- padding: "8px 16px",
3198
- backgroundColor: "rgba(0, 0, 0, 0.6)",
3199
- borderRadius: 8,
3200
- color: "#fff",
3201
- fontSize: 13,
3202
- pointerEvents: "none",
3203
- zIndex: 5,
3204
- fontFamily: "system-ui, sans-serif"
3205
- },
3206
- children: [
3207
- d("div", {
3208
- style: {
3209
- width: 10,
3210
- height: 10,
3211
- borderRadius: "50%",
3212
- backgroundColor: "#44ff44",
3213
- flexShrink: 0
3214
- }
3215
- }),
3216
- "Click mesh to set ",
3217
- R === "AK" ? "IT/Perineum" : "MPT"
3218
- ]
3219
- }),
3220
- m && d(At, {
3221
- message: w || "Processing mesh..."
3222
- }),
3223
- oe && d(At, {
3224
- message: ee
3225
- }),
3226
- me && d(Pn, {
3227
- message: me,
3228
- onDismiss: () => ae(null)
3229
- }),
3230
- e.showAmputationModal && M && d("div", {
3231
- style: {
3232
- position: "absolute",
3233
- inset: 0,
3234
- backgroundColor: "rgba(0,0,0,0.32)",
3235
- display: "flex",
3236
- alignItems: "center",
3237
- justifyContent: "center",
3238
- zIndex: 20
3239
- },
3240
- children: W("div", {
3241
- style: {
3242
- backgroundColor: "#fff",
3243
- borderRadius: 4,
3244
- width: 560,
3245
- boxShadow: "0 11px 15px -7px rgba(0,0,0,0.2), 0 24px 38px 3px rgba(0,0,0,0.14), 0 9px 46px 8px rgba(0,0,0,0.12)",
3246
- fontFamily: "system-ui, sans-serif"
3247
- },
3248
- children: [
3249
- W("div", {
3250
- style: {
3251
- padding: "24px 24px 20px"
3252
- },
3253
- children: [
3254
- d("div", {
3255
- style: {
3256
- fontSize: 20,
3257
- fontWeight: 500,
3258
- color: "rgba(0,0,0,0.87)",
3259
- marginBottom: 8
3260
- },
3261
- children: "Select Spacing Type"
3262
- }),
3263
- d("div", {
3264
- style: {
3265
- fontSize: 14,
3266
- color: "rgba(0,0,0,0.54)",
3267
- marginBottom: 24
3268
- },
3269
- children: "Choose the measurement spacing for this scan"
3270
- }),
3271
- d("div", {
3272
- style: {
3273
- display: "flex",
3274
- gap: 16
3275
- },
3276
- children: [
3277
- "AK",
3278
- "BK"
3279
- ].map((_) => W("label", {
3280
- onClick: () => Y(_),
3281
- style: {
3282
- flex: 1,
3283
- display: "flex",
3284
- flexDirection: "column",
3285
- padding: "20px 24px",
3286
- border: "2px solid",
3287
- borderRadius: 4,
3288
- cursor: "pointer",
3289
- borderColor: R === _ ? "rgb(12, 67, 173)" : "#e0e0e0",
3290
- backgroundColor: R === _ ? "rgba(12, 67, 173, 0.04)" : "#fff",
3291
- transition: "border-color 0.15s, background-color 0.15s"
3292
- },
3293
- children: [
3294
- d("input", {
3295
- type: "radio",
3296
- name: "ampType",
3297
- checked: R === _,
3298
- onChange: () => Y(_),
3299
- style: {
3300
- accentColor: "rgb(12, 67, 173)",
3301
- marginBottom: 12,
3302
- width: 18,
3303
- height: 18
3304
- }
3305
- }),
3306
- d("span", {
3307
- style: {
3308
- fontSize: 18,
3309
- fontWeight: 600,
3310
- color: "rgba(0,0,0,0.87)",
3311
- marginBottom: 4
3312
- },
3313
- children: _
3314
- }),
3315
- W("span", {
3316
- style: {
3317
- fontSize: 13,
3318
- color: "rgba(0,0,0,0.54)"
3319
- },
3320
- children: [
3321
- _ === "AK" ? "2" : "1",
3322
- "-inch measurement spacing"
3323
- ]
3324
- })
3325
- ]
3326
- }, _))
3327
- })
3328
- ]
3329
- }),
3330
- W("div", {
3331
- style: {
3332
- display: "flex",
3333
- justifyContent: "flex-end",
3334
- gap: 8,
3335
- padding: "12px 24px 20px",
3336
- borderTop: "1px solid #e0e0e0"
3337
- },
3338
- children: [
3339
- d("button", {
3340
- onClick: () => {
3341
- L(false), H(null);
3342
- },
3343
- style: {
3344
- padding: "6px 16px",
3345
- borderRadius: 4,
3346
- fontSize: 14,
3347
- fontWeight: 500,
3348
- backgroundColor: "#fff",
3349
- border: "1px solid #bdbdbd",
3350
- color: "rgba(0,0,0,0.87)",
3351
- cursor: "pointer",
3352
- fontFamily: "system-ui, sans-serif",
3353
- lineHeight: "36px",
3354
- letterSpacing: "0.4px"
3355
- },
3356
- children: "Cancel"
3357
- }),
3358
- d("button", {
3359
- onClick: () => R && Ut(R),
3360
- disabled: !R,
3361
- style: {
3362
- padding: "6px 16px",
3363
- borderRadius: 4,
3364
- fontSize: 14,
3365
- fontWeight: 500,
3366
- backgroundColor: R ? "rgb(12, 67, 173)" : "#e0e0e0",
3367
- border: "none",
3368
- color: R ? "#fff" : "#9e9e9e",
3369
- cursor: R ? "pointer" : "not-allowed",
3370
- fontFamily: "system-ui, sans-serif",
3371
- lineHeight: "36px",
3372
- letterSpacing: "0.4px"
3373
- },
3374
- children: "Next \xBB"
3375
- })
3376
- ]
3377
- })
3378
- ]
3379
- })
3380
- }),
3381
- e.showDragDrop && y && d("div", {
3382
- style: {
3383
- position: "absolute",
3384
- inset: 0,
3385
- backgroundColor: "rgba(12, 67, 173, 0.1)",
3386
- border: "2px dashed rgb(12, 67, 173)",
3387
- pointerEvents: "none",
3388
- zIndex: 10
3389
- }
3390
- }),
3391
- W(sn, {
3392
- camera: {
3393
- position: [
3394
- 0,
3395
- 0,
3396
- 5
3397
- ]
3398
- },
3399
- style: {
3400
- display: n ? "block" : "none",
3401
- backgroundColor: xe ? "#070611" : void 0
3402
- },
3403
- gl: {
3404
- localClippingEnabled: true
3405
- },
3406
- scene: {
3407
- background: xe ? new J.Color("#070611") : null
3408
- },
3409
- children: [
3410
- d("ambientLight", {
3411
- intensity: 0.4
3412
- }),
3413
- d("directionalLight", {
3414
- position: [
3415
- 10,
3416
- 10,
3417
- 5
3418
- ],
3419
- intensity: 1.2
3420
- }),
3421
- d("directionalLight", {
3422
- position: [
3423
- -5,
3424
- 5,
3425
- -5
3426
- ],
3427
- intensity: 0.4
3428
- }),
3429
- d("directionalLight", {
3430
- position: [
3431
- 0,
3432
- -10,
3433
- 0
3434
- ],
3435
- intensity: 0.2
3436
- }),
3437
- n && x === "3D" && d(Ln, {
3438
- mesh: n,
3439
- maxPoints: 2,
3440
- meshColor: mt,
3441
- meshOpacity: xe ? 0.3 : jt
3442
- }),
3443
- he && fe && x === "3D" && d("mesh", {
3444
- geometry: fe,
3445
- renderOrder: 1,
3446
- children: d("meshStandardMaterial", {
3447
- color: "#c8c8c8",
3448
- transparent: true,
3449
- opacity: 0.35,
3450
- side: J.DoubleSide,
3451
- depthWrite: false,
3452
- polygonOffset: true,
3453
- polygonOffsetFactor: 1,
3454
- polygonOffsetUnits: 1
3455
- })
3456
- }),
3457
- n && x === "3D" && d(Tn, {
3458
- modelSize: r,
3459
- labels: [
3460
- "Origin",
3461
- R === "AK" ? "IT/Perineum" : "MPT",
3462
- "Cut Plane"
3463
- ]
3464
- }),
3465
- d($n, {
3466
- modelSize: r,
3467
- isAligned: be,
3468
- isCut: Gt,
3469
- mesh: n,
3470
- viewMode: x,
3471
- sliceY: be && ce.length >= 2 ? G ?? re ?? ce[1].position.y : void 0,
3472
- landmarkCount: ce.length
3473
- }),
3474
- !be && d(Dt, {
3475
- enableDamping: false
3476
- }),
3477
- be && se.length > 0 && n && x === "3D" && d(Nn, {
3478
- mesh: n,
3479
- isDragging: false
3480
- }),
3481
- n && be && ce.length >= 3 && (() => {
3482
- const K = n.geometry.getIndex();
3483
- if (!K || K.count < 30) return null;
3484
- const ue = ce[2], Z = ce[1], Be = I ?? ue.position.y, te = G ?? re ?? Z.position.y;
3485
- return x === "2D" ? d(Gn, {
3486
- mesh: n,
3487
- upperY: te,
3488
- originY: Z.position.y,
3489
- modelSize: r,
3490
- meshColor: mt,
3491
- displayUnit: N
3492
- }) : W(He, {
3493
- children: [
3494
- d(_n, {
3495
- mesh: n,
3496
- startY: Be,
3497
- endY: te,
3498
- spacing: at,
3499
- modelSize: r,
3500
- onMeasurementsChange: A,
3501
- reverseOrder: true,
3502
- displayUnit: N,
3503
- useInnerSurface: T && !j,
3504
- formMeasurements: ke ? ze : void 0,
3505
- originY: Z.position.y
3506
- }),
3507
- (!T || j) && d(On, {
3508
- mesh: n,
3509
- greenY: Z.position.y,
3510
- modelSize: r,
3511
- displayUnit: N
3512
- })
3513
- ]
3514
- });
3515
- })(),
3516
- n && be && x === "3D" && d(so, {
3517
- mesh: n
3518
- }),
3519
- n && e.showDebug && xe && x === "3D" && d(oo, {
3520
- mesh: n,
3521
- modelSize: r,
3522
- layers: pe,
3523
- landmarkPoints: ce,
3524
- componentDebug: O
3525
- })
3526
- ]
3527
- }),
3528
- n && (e.showStartOver || e.showInsertMeasurement) && W("div", {
3529
- style: {
3530
- position: "absolute",
3531
- top: 16,
3532
- left: 16,
3533
- zIndex: 10,
3534
- display: "flex",
3535
- gap: 8
3536
- },
3537
- children: [
3538
- e.showStartOver && d("button", {
3539
- onClick: () => window.location.reload(),
3540
- style: {
3541
- padding: "6px 16px",
3542
- borderRadius: 4,
3543
- fontSize: 13,
3544
- fontWeight: 500,
3545
- backgroundColor: "#fff",
3546
- border: "1px solid #bdbdbd",
3547
- color: "#333",
3548
- cursor: "pointer",
3549
- fontFamily: "system-ui, sans-serif",
3550
- letterSpacing: "0.4px",
3551
- boxShadow: "0 2px 8px rgba(0,0,0,0.1)"
3552
- },
3553
- children: "Start Over"
3554
- }),
3555
- e.showInsertMeasurement && d("button", {
3556
- onClick: () => Me(true),
3557
- style: {
3558
- padding: "6px 16px",
3559
- borderRadius: 4,
3560
- fontSize: 13,
3561
- fontWeight: 500,
3562
- backgroundColor: "rgb(12, 67, 173)",
3563
- border: "none",
3564
- color: "#fff",
3565
- cursor: "pointer",
3566
- fontFamily: "system-ui, sans-serif",
3567
- letterSpacing: "0.4px",
3568
- boxShadow: "0 2px 8px rgba(0,0,0,0.1)"
3569
- },
3570
- children: "Insert Measurement"
3571
- })
3572
- ]
3573
- }),
3574
- e.showDebug && xe && n && x === "3D" && d(io, {
3575
- layers: pe,
3576
- onToggleLayer: (_) => we((K) => ({
3577
- ...K,
3578
- [_]: !K[_]
3579
- }))
3580
- }),
3581
- be && se.length > 0 && W("div", {
3582
- style: {
3583
- position: "absolute",
3584
- top: 16,
3585
- right: 16,
3586
- display: "flex",
3587
- gap: 8,
3588
- zIndex: 10
3589
- },
3590
- children: [
3591
- W("div", {
3592
- style: {
3593
- display: "flex",
3594
- borderRadius: 6,
3595
- overflow: "hidden",
3596
- border: "1px solid #ccc",
3597
- boxShadow: "0 2px 8px rgba(0,0,0,0.1)"
3598
- },
3599
- children: [
3600
- d("button", {
3601
- onClick: () => b("3D"),
3602
- style: {
3603
- padding: "6px 14px",
3604
- fontSize: 13,
3605
- fontWeight: x === "3D" ? 600 : 400,
3606
- backgroundColor: x === "3D" ? "rgb(12, 67, 173)" : "#fff",
3607
- color: x === "3D" ? "#fff" : "#666",
3608
- border: "none",
3609
- cursor: "pointer",
3610
- fontFamily: "system-ui, sans-serif"
3611
- },
3612
- children: "Frontal"
3613
- }),
3614
- d("button", {
3615
- onClick: () => b("2D"),
3616
- style: {
3617
- padding: "6px 14px",
3618
- fontSize: 13,
3619
- fontWeight: x === "2D" ? 600 : 400,
3620
- backgroundColor: x === "2D" ? "rgb(12, 67, 173)" : "#fff",
3621
- color: x === "2D" ? "#fff" : "#666",
3622
- border: "none",
3623
- borderLeft: "1px solid #ccc",
3624
- cursor: "pointer",
3625
- fontFamily: "system-ui, sans-serif"
3626
- },
3627
- children: "Transverse"
3628
- })
3629
- ]
3630
- }),
3631
- W("div", {
3632
- style: {
3633
- display: "flex",
3634
- borderRadius: 6,
3635
- overflow: "hidden",
3636
- border: "1px solid #ccc",
3637
- boxShadow: "0 2px 8px rgba(0,0,0,0.1)"
3638
- },
3639
- children: [
3640
- d("button", {
3641
- onClick: () => ne("mm"),
3642
- style: {
3643
- padding: "6px 14px",
3644
- fontSize: 13,
3645
- fontWeight: N === "mm" ? 600 : 400,
3646
- backgroundColor: N === "mm" ? "rgb(12, 67, 173)" : "#fff",
3647
- color: N === "mm" ? "#fff" : "#666",
3648
- border: "none",
3649
- cursor: "pointer",
3650
- fontFamily: "system-ui, sans-serif"
3651
- },
3652
- children: "mm"
3653
- }),
3654
- d("button", {
3655
- onClick: () => ne("inch"),
3656
- style: {
3657
- padding: "6px 14px",
3658
- fontSize: 13,
3659
- fontWeight: N === "inch" ? 600 : 400,
3660
- backgroundColor: N === "inch" ? "rgb(12, 67, 173)" : "#fff",
3661
- color: N === "inch" ? "#fff" : "#666",
3662
- border: "none",
3663
- borderLeft: "1px solid #ccc",
3664
- cursor: "pointer",
3665
- fontFamily: "system-ui, sans-serif"
3666
- },
3667
- children: "in"
3668
- })
3669
- ]
3670
- }),
3671
- e.showSpacingToggle && x === "3D" && W("div", {
3672
- style: {
3673
- display: "flex",
3674
- borderRadius: 6,
3675
- overflow: "hidden",
3676
- border: "1px solid #ccc",
3677
- boxShadow: "0 2px 8px rgba(0,0,0,0.1)"
3678
- },
3679
- children: [
3680
- d("button", {
3681
- onClick: () => v(1),
3682
- style: {
3683
- padding: "6px 14px",
3684
- fontSize: 13,
3685
- fontWeight: S === 1 ? 600 : 400,
3686
- backgroundColor: S === 1 ? "rgb(12, 67, 173)" : "#fff",
3687
- color: S === 1 ? "#fff" : "#666",
3688
- border: "none",
3689
- cursor: "pointer",
3690
- fontFamily: "system-ui, sans-serif"
3691
- },
3692
- children: '1"'
3693
- }),
3694
- d("button", {
3695
- onClick: () => v(2),
3696
- style: {
3697
- padding: "6px 14px",
3698
- fontSize: 13,
3699
- fontWeight: S === 2 ? 600 : 400,
3700
- backgroundColor: S === 2 ? "rgb(12, 67, 173)" : "#fff",
3701
- color: S === 2 ? "#fff" : "#666",
3702
- border: "none",
3703
- borderLeft: "1px solid #ccc",
3704
- cursor: "pointer",
3705
- fontFamily: "system-ui, sans-serif"
3706
- },
3707
- children: '2"'
3708
- })
3709
- ]
3710
- }),
3711
- x === "3D" && fe && d("div", {
3712
- style: {
3713
- display: "flex",
3714
- borderRadius: 6,
3715
- overflow: "hidden",
3716
- border: "1px solid #ccc",
3717
- boxShadow: "0 2px 8px rgba(0,0,0,0.1)"
3718
- },
3719
- children: d("button", {
3720
- onClick: () => Ge((_) => !_),
3721
- style: {
3722
- padding: "6px 14px",
3723
- fontSize: 13,
3724
- fontWeight: he ? 600 : 400,
3725
- backgroundColor: he ? "rgb(12, 67, 173)" : "#fff",
3726
- color: he ? "#fff" : "#666",
3727
- border: "none",
3728
- cursor: "pointer",
3729
- fontFamily: "system-ui, sans-serif"
3730
- },
3731
- children: "Show Full Scan"
3732
- })
3733
- }),
3734
- x === "3D" && ze && d("div", {
3735
- style: {
3736
- display: "flex",
3737
- borderRadius: 6,
3738
- overflow: "hidden",
3739
- border: "1px solid #ccc",
3740
- boxShadow: "0 2px 8px rgba(0,0,0,0.1)"
3741
- },
3742
- children: d("button", {
3743
- onClick: () => Ue((_) => !_),
3744
- style: {
3745
- padding: "6px 14px",
3746
- fontSize: 13,
3747
- fontWeight: ke ? 600 : 400,
3748
- backgroundColor: ke ? "rgb(12, 67, 173)" : "#fff",
3749
- color: ke ? "#fff" : "#666",
3750
- border: "none",
3751
- cursor: "pointer",
3752
- fontFamily: "system-ui, sans-serif"
3753
- },
3754
- children: "Form Overlay"
3755
- })
3756
- }),
3757
- e.showDebug && a && d("div", {
3758
- style: {
3759
- display: "flex",
3760
- borderRadius: 6,
3761
- overflow: "hidden",
3762
- border: "1px solid #ccc",
3763
- boxShadow: "0 2px 8px rgba(0,0,0,0.1)"
3764
- },
3765
- children: d("button", {
3766
- onClick: () => Re((_) => !_),
3767
- style: {
3768
- padding: "6px 14px",
3769
- fontSize: 13,
3770
- fontWeight: xe ? 600 : 400,
3771
- backgroundColor: xe ? "#e65100" : "#fff",
3772
- color: xe ? "#fff" : "#666",
3773
- border: "none",
3774
- cursor: "pointer",
3775
- fontFamily: "system-ui, sans-serif"
3776
- },
3777
- children: "Debug"
3778
- })
3779
- })
3780
- ]
3781
- }),
3782
- n && V && d(jn, {
3783
- wasAutoScaled: z,
3784
- onDismiss: () => B(false)
3785
- }),
3786
- n && Q && be && d(Hn, {
3787
- isDoubleShell: T,
3788
- onDismiss: () => ie(false)
3789
- })
3790
- ]
3791
- }),
3792
- W("div", {
3793
- style: {
3794
- padding: "12px 24px",
3795
- backgroundColor: "#fff",
3796
- borderTop: "1px solid #e0e0e0",
3797
- display: "flex",
3798
- alignItems: "center",
3799
- justifyContent: "flex-end",
3800
- gap: 8,
3801
- flexShrink: 0
3802
- },
3803
- children: [
3804
- n && !be && ce.length >= 2 && d("button", {
3805
- onClick: Qt,
3806
- style: {
3807
- padding: "6px 16px",
3808
- borderRadius: 4,
3809
- fontSize: 14,
3810
- fontWeight: 500,
3811
- backgroundColor: "rgb(12, 67, 173)",
3812
- border: "none",
3813
- color: "#fff",
3814
- cursor: "pointer",
3815
- fontFamily: "system-ui, sans-serif",
3816
- letterSpacing: "0.4px",
3817
- lineHeight: "36px"
3818
- },
3819
- children: "Next \xBB"
3820
- }),
3821
- n && !be && ce.length >= 1 && d("button", {
3822
- onClick: Yt,
3823
- style: {
3824
- padding: "6px 16px",
3825
- borderRadius: 4,
3826
- fontSize: 14,
3827
- fontWeight: 500,
3828
- backgroundColor: "#fff",
3829
- border: "1px solid #bdbdbd",
3830
- color: "#333",
3831
- cursor: "pointer",
3832
- fontFamily: "system-ui, sans-serif",
3833
- letterSpacing: "0.4px",
3834
- lineHeight: "36px"
3835
- },
3836
- children: "Reset Points"
3837
- }),
3838
- be && d("button", {
3839
- onClick: qt,
3840
- disabled: se.length === 0,
3841
- style: {
3842
- padding: "6px 16px",
3843
- borderRadius: 4,
3844
- fontSize: 14,
3845
- fontWeight: 500,
3846
- backgroundColor: se.length > 0 ? "rgb(12, 67, 173)" : "#e0e0e0",
3847
- border: "none",
3848
- color: se.length > 0 ? "#fff" : "#9e9e9e",
3849
- cursor: se.length > 0 ? "pointer" : "not-allowed",
3850
- fontFamily: "system-ui, sans-serif",
3851
- letterSpacing: "0.4px",
3852
- lineHeight: "36px"
3853
- },
3854
- children: "Continue to Next Step"
3855
- })
3856
- ]
3857
- })
3858
- ]
3859
- })
3860
- ]
3861
- }),
3862
- e.showInsertMeasurement && Te && (() => {
3863
- const _ = R === "AK" ? "IT/Perineum" : "MPT", K = S, ue = [];
3864
- for (let Z = 2; Z >= 1; Z -= K) ue.push(`${Z}\u2033 above ${_}`);
3865
- ue.push(`At ${_}`);
3866
- for (let Z = K; Z <= 9; Z += K) ue.push(`${Z}\u2033 below ${_}`);
3867
- return d("div", {
3868
- style: {
3869
- position: "fixed",
3870
- inset: 0,
3871
- backgroundColor: "rgba(0,0,0,0.32)",
3872
- display: "flex",
3873
- alignItems: "center",
3874
- justifyContent: "flex-start",
3875
- paddingLeft: 40,
3876
- zIndex: 9999
3877
- },
3878
- children: W("div", {
3879
- style: {
3880
- backgroundColor: "#fff",
3881
- borderRadius: 4,
3882
- width: 620,
3883
- maxHeight: "80vh",
3884
- display: "flex",
3885
- flexDirection: "column",
3886
- boxShadow: "0 11px 15px -7px rgba(0,0,0,0.2), 0 24px 38px 3px rgba(0,0,0,0.14), 0 9px 46px 8px rgba(0,0,0,0.12)",
3887
- fontFamily: "system-ui, sans-serif"
3888
- },
3889
- children: [
3890
- W("div", {
3891
- style: {
3892
- padding: "24px 24px 0"
3893
- },
3894
- children: [
3895
- W("div", {
3896
- style: {
3897
- fontSize: 20,
3898
- fontWeight: 500,
3899
- color: "rgba(0,0,0,0.87)",
3900
- marginBottom: 4
3901
- },
3902
- children: [
3903
- R,
3904
- " Circumferences"
3905
- ]
3906
- }),
3907
- W("div", {
3908
- style: {
3909
- fontSize: 13,
3910
- color: "rgba(0,0,0,0.54)",
3911
- marginBottom: 20
3912
- },
3913
- children: [
3914
- "Enter form measurements (mm). ",
3915
- K,
3916
- "\u2033",
3917
- " spacing."
3918
- ]
3919
- })
3920
- ]
3921
- }),
3922
- d("div", {
3923
- style: {
3924
- padding: "0 24px",
3925
- overflowY: "auto",
3926
- flex: 1
3927
- },
3928
- children: d("div", {
3929
- style: {
3930
- display: "grid",
3931
- gridTemplateColumns: "1fr 1fr",
3932
- gap: "16px 24px"
3933
- },
3934
- children: ue.map((Z, Be) => W("div", {
3935
- children: [
3936
- W("label", {
3937
- style: {
3938
- display: "block",
3939
- fontSize: 13,
3940
- fontWeight: 500,
3941
- color: "rgb(12, 67, 173)",
3942
- marginBottom: 6
3943
- },
3944
- children: [
3945
- Z,
3946
- " (mm):"
3947
- ]
3948
- }),
3949
- d("input", {
3950
- type: "number",
3951
- step: "0.1",
3952
- value: Ae[Z] ?? "",
3953
- onChange: (te) => De((ve) => ({
3954
- ...ve,
3955
- [Z]: te.target.value
3956
- })),
3957
- style: {
3958
- width: "100%",
3959
- padding: "10px 12px",
3960
- fontSize: 15,
3961
- border: "2px solid rgb(12, 67, 173)",
3962
- borderRadius: 4,
3963
- outline: "none",
3964
- boxSizing: "border-box",
3965
- fontFamily: "system-ui, sans-serif"
3966
- }
3967
- })
3968
- ]
3969
- }, Be))
3970
- })
3971
- }),
3972
- W("div", {
3973
- style: {
3974
- display: "flex",
3975
- justifyContent: "flex-end",
3976
- gap: 8,
3977
- padding: "16px 24px",
3978
- borderTop: "1px solid #e0e0e0",
3979
- marginTop: 16
3980
- },
3981
- children: [
3982
- d("button", {
3983
- onClick: () => {
3984
- Me(false), De({});
3985
- },
3986
- style: {
3987
- padding: "6px 16px",
3988
- borderRadius: 4,
3989
- fontSize: 14,
3990
- fontWeight: 500,
3991
- backgroundColor: "#fff",
3992
- border: "1px solid #bdbdbd",
3993
- color: "rgba(0,0,0,0.87)",
3994
- cursor: "pointer",
3995
- fontFamily: "system-ui, sans-serif",
3996
- lineHeight: "36px",
3997
- letterSpacing: "0.4px"
3998
- },
3999
- children: "Cancel"
4000
- }),
4001
- d("button", {
4002
- onClick: () => {
4003
- const Z = ue.map((te) => parseFloat(Ae[te] || "")), Be = Z.filter((te) => !isNaN(te));
4004
- Ee(Be.length > 0 ? Z.map((te) => isNaN(te) ? void 0 : te) : void 0), Me(false);
4005
- },
4006
- style: {
4007
- padding: "6px 16px",
4008
- borderRadius: 4,
4009
- fontSize: 14,
4010
- fontWeight: 500,
4011
- backgroundColor: "rgb(12, 67, 173)",
4012
- border: "none",
4013
- color: "#fff",
4014
- cursor: "pointer",
4015
- fontFamily: "system-ui, sans-serif",
4016
- lineHeight: "36px",
4017
- letterSpacing: "0.4px"
4018
- },
4019
- children: "Save"
4020
- })
4021
- ]
4022
- })
4023
- ]
4024
- })
4025
- });
4026
- })()
4027
- ]
4028
- });
4029
- };
4030
- Nt = function(e) {
4031
- const s = e === "AK" ? 2 : 1, o = [];
4032
- for (let t = 2; t >= 1; t -= s) o.push(`${t}_above`);
4033
- o.push("at_ref");
4034
- for (let t = s; t <= 9; t += s) o.push(`${t}_below`);
4035
- return o;
4036
- };
4037
- dt = function(e, s) {
4038
- const o = Nt(s), t = {};
4039
- for (let l = 0; l < Math.min(e.length, o.length); l++) {
4040
- const a = e[l];
4041
- a != null && !isNaN(a) && (t[o[l]] = a);
4042
- }
4043
- return t;
4044
- };
4045
- ao = function(e, s) {
4046
- if (!e) return;
4047
- const t = Nt(s).map((l) => {
4048
- const a = e[l];
4049
- return a ?? void 0;
4050
- });
4051
- if (!t.every((l) => l == null)) return t;
4052
- };
4053
- bo = ({ request: e, onComplete: s, wasmModule: o }) => {
4054
- const [t, l] = q(null);
4055
- Se(() => {
4056
- if (o !== void 0) return;
4057
- let n = false;
4058
- return import("./galileo_core_geo-DFVJmkI7.js").then(async (i) => {
4059
- await i.default(), n || l(i);
4060
- }).catch(() => {
4061
- }), () => {
4062
- n = true;
4063
- };
4064
- }, [
4065
- o
4066
- ]);
4067
- const a = o !== void 0 ? o : t, c = de(() => ao(e.form_measurements, e.spacing_type), [
4068
- e.form_measurements,
4069
- e.spacing_type
4070
- ]), u = (n) => {
4071
- const i = n.scanMeasurements.map((m) => +(m.modifiedValue ?? m.originalValue).toFixed(1)), r = dt(i, e.spacing_type);
4072
- let f, y;
4073
- if (n.formMeasurements) {
4074
- f = dt(n.formMeasurements, e.spacing_type);
4075
- const m = n.scanMeasurements.map((g, w) => {
4076
- var _a;
4077
- const C = (_a = n.formMeasurements) == null ? void 0 : _a[w];
4078
- return C == null || isNaN(C) ? null : +((g.modifiedValue ?? g.originalValue) - C).toFixed(1);
4079
- });
4080
- y = dt(m, e.spacing_type);
4081
- }
4082
- const p = {
4083
- spacing_type: e.spacing_type,
4084
- source_unit: "mm",
4085
- file_format: n.fileFormat,
4086
- measurement_source: n.formMeasurements ? "form_provided" : "scan_derived",
4087
- is_double_wall: n.isDoubleWall,
4088
- is_unit_converted: false,
4089
- form_measurements: f,
4090
- scan_measurements: r,
4091
- measurement_variance: y,
4092
- scan_url: e.scan_url,
4093
- frontal_height: +n.frontalHeight.toFixed(1),
4094
- transverse_ml: +n.transverseML.toFixed(1),
4095
- transverse_ap: +n.transverseAP.toFixed(1)
4096
- };
4097
- console.log("[GirthManagerWidget] WidgetResponse:", JSON.stringify(p, null, 2)), s == null ? void 0 : s(p);
4098
- };
4099
- return d("div", {
4100
- style: {
4101
- width: "100%",
4102
- height: "100%",
4103
- display: "flex"
4104
- },
4105
- children: d(lo, {
4106
- config: fn,
4107
- spacingType: e.spacing_type,
4108
- scanUrl: e.scan_url,
4109
- formMeasurements: c,
4110
- onComplete: u,
4111
- wasmModule: a
4112
- })
4113
- });
4114
- };
4115
- })();
4116
- export {
4117
- bo as G,
4118
- __tla,
4119
- dt as a,
4120
- ao as c,
4121
- Nt as g
4122
- };