@solid-labs/fab-one-widget 0.1.6 → 0.1.8

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 (37) hide show
  1. package/dist/GirthManagerWidget-C5L2H3Y2.js +4786 -0
  2. package/dist/GirthManagerWidget-C5L2H3Y2.js.map +1 -0
  3. package/dist/geo_wasm.d.ts +529 -0
  4. package/dist/geo_wasm.js +1686 -0
  5. package/dist/geo_wasm_bg.wasm +0 -0
  6. package/dist/girth-manager-ui/src/GirthManagerCore.d.ts +11 -5
  7. package/dist/girth-manager-ui/src/components/CameraFit.d.ts +5 -1
  8. package/dist/girth-manager-ui/src/components/CircumferenceMeasurements.d.ts +4 -1
  9. package/dist/girth-manager-ui/src/components/CircumferenceSlice.d.ts +6 -1
  10. package/dist/girth-manager-ui/src/components/ClickableMesh.d.ts +5 -1
  11. package/dist/girth-manager-ui/src/components/DebugOverlays.d.ts +14 -2
  12. package/dist/girth-manager-ui/src/components/DebugPanel.d.ts +2 -1
  13. package/dist/girth-manager-ui/src/components/ErrorBoundary.d.ts +16 -0
  14. package/dist/girth-manager-ui/src/components/MeasurementInputForm.d.ts +14 -0
  15. package/dist/girth-manager-ui/src/components/VerticalDimension.d.ts +3 -1
  16. package/dist/girth-manager-ui/src/config.d.ts +2 -2
  17. package/dist/girth-manager-ui/src/index.d.ts +10 -6
  18. package/dist/girth-manager-ui/src/processing/logger.d.ts +13 -0
  19. package/dist/girth-manager-ui/src/processing/mesh-ops.d.ts +0 -22
  20. package/dist/girth-manager-ui/src/processing/pipeline.d.ts +34 -6
  21. package/dist/girth-manager-ui/src/processing/types.d.ts +112 -12
  22. package/dist/girth-manager-ui/src/processing/vertex-colors.d.ts +6 -1
  23. package/dist/girth-manager-ui/src/processing/wasm-loader.d.ts +16 -16
  24. package/dist/girth-manager-web-widget/src/GirthManagerWidget.d.ts +3 -5
  25. package/dist/girth-manager-web-widget/src/index.d.ts +1 -1
  26. package/dist/girth-manager-web-widget/src/types.d.ts +57 -0
  27. package/dist/girth-manager-web-widget/src/web-component.d.ts +2 -2
  28. package/dist/html2canvas.esm-Dmi1NfiH.js +4871 -0
  29. package/dist/html2canvas.esm-Dmi1NfiH.js.map +1 -0
  30. package/dist/index.js +1 -1
  31. package/dist/web-component.js +2 -2
  32. package/dist/web-component.js.map +1 -1
  33. package/package.json +16 -11
  34. package/dist/GirthManagerWidget-Ci-QU3Wh.js +0 -4137
  35. package/dist/GirthManagerWidget-Ci-QU3Wh.js.map +0 -1
  36. package/dist/galileo_core_geo-DFVJmkI7.js +0 -298
  37. package/dist/galileo_core_geo-DFVJmkI7.js.map +0 -1
@@ -1,4137 +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 Pt, 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, jt;
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, r) => ({
32
- landmarkPoints: [],
33
- isAligned: false,
34
- isCut: false,
35
- addLandmarkPoint: (n) => e((t) => t.landmarkPoints.length >= 3 ? t : {
36
- landmarkPoints: [
37
- ...t.landmarkPoints,
38
- n
39
- ]
40
- }),
41
- removeLandmarkPoint: (n) => e((t) => ({
42
- landmarkPoints: t.landmarkPoints.filter((i, a) => a !== n)
43
- })),
44
- clearLandmarkPoints: () => e({
45
- landmarkPoints: [],
46
- isAligned: false,
47
- isCut: false
48
- }),
49
- updateLandmarkPositions: (n) => e((t) => ({
50
- landmarkPoints: t.landmarkPoints.map((i, a) => ({
51
- ...i,
52
- position: n[a] ?? i.position
53
- }))
54
- })),
55
- setAligned: (n) => e({
56
- isAligned: n
57
- }),
58
- setCut: (n) => e({
59
- isCut: n
60
- }),
61
- isSelectionComplete: () => r().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 r = e.split(`
70
- `), n = [], t = [];
71
- let i = false;
72
- for (const a of r) if (a.startsWith("v ")) {
73
- const c = a.trim().split(/\s+/);
74
- if (c.length >= 7) {
75
- n.push(parseFloat(c[1]), parseFloat(c[2]), parseFloat(c[3]));
76
- let u = parseFloat(c[4]), s = parseFloat(c[5]), l = parseFloat(c[6]);
77
- (u > 1 || s > 1 || l > 1) && (u /= 255, s /= 255, l /= 255), t.push(u, s, l), i = true;
78
- } else c.length >= 4 && (n.push(parseFloat(c[1]), parseFloat(c[2]), parseFloat(c[3])), t.push(0, 0, 0));
79
- }
80
- return i ? {
81
- positions: new Float32Array(n),
82
- colors: new Float32Array(t)
83
- } : null;
84
- }
85
- function mn(e, r, n, t) {
86
- const i = e.getAttribute("position"), a = i.count, c = new Float32Array(a * 3), u = r.length / 3;
87
- let s = 1 / 0, l = 1 / 0, o = 1 / 0, f = -1 / 0, y = -1 / 0, p = -1 / 0;
88
- for (let b = 0; b < u; b++) {
89
- const S = r[b * 3] * t, C = r[b * 3 + 1] * t, M = r[b * 3 + 2] * t;
90
- S < s && (s = S), S > f && (f = S), C < l && (l = C), C > y && (y = C), M < o && (o = M), M > p && (p = M);
91
- }
92
- const x = Math.min(128, Math.max(16, Math.round(Math.cbrt(u)))), g = (f - s + 1e-6) / x, w = (y - l + 1e-6) / x, v = (p - o + 1e-6) / x, m = /* @__PURE__ */ new Map();
93
- for (let b = 0; b < u; b++) {
94
- const S = Math.min(x - 1, Math.floor((r[b * 3] * t - s) / g)), C = Math.min(x - 1, Math.floor((r[b * 3 + 1] * t - l) / w)), M = Math.min(x - 1, Math.floor((r[b * 3 + 2] * t - o) / v)), P = S * x * x + C * x + M;
95
- let L = m.get(P);
96
- L || (L = [], m.set(P, L)), L.push(b);
97
- }
98
- for (let b = 0; b < a; b++) {
99
- const S = i.getX(b), C = i.getY(b), M = i.getZ(b), P = Math.min(x - 1, Math.max(0, Math.floor((S - s) / g))), L = Math.min(x - 1, Math.max(0, Math.floor((C - l) / w))), H = Math.min(x - 1, Math.max(0, Math.floor((M - o) / v)));
100
- let O = 1 / 0, $ = 0;
101
- for (let R = 0; R <= x && O > 0; R++) {
102
- for (let Y = -R; Y <= R; Y++) for (let j = -R; j <= R; j++) for (let ne = -R; ne <= R; ne++) {
103
- if (R > 0 && Math.abs(Y) < R && Math.abs(j) < R && Math.abs(ne) < R) continue;
104
- const oe = P + Y, le = L + j, ee = H + ne;
105
- if (oe < 0 || oe >= x || le < 0 || le >= x || ee < 0 || ee >= x) continue;
106
- const D = m.get(oe * x * x + le * x + ee);
107
- if (D) for (const z of D) {
108
- const F = r[z * 3] * t, V = r[z * 3 + 1] * t, B = r[z * 3 + 2] * t, T = (S - F) ** 2 + (C - V) ** 2 + (M - B) ** 2;
109
- T < O && (O = T, $ = z);
110
- }
111
- }
112
- if (O < 1 / 0) break;
113
- }
114
- c[b * 3] = n[$ * 3], c[b * 3 + 1] = n[$ * 3 + 1], c[b * 3 + 2] = n[$ * 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, r) {
127
- const n = e.getVertices(), t = e.getFaces(), i = e.getComponentLabels(), a = /* @__PURE__ */ new Map();
128
- for (let o = 0; o < i.length; o++) {
129
- const f = i[o];
130
- a.has(f) || a.set(f, []), a.get(f).push(o);
131
- }
132
- const c = [
133
- ...a.keys()
134
- ].sort((o, f) => o - f), u = [], s = [], l = [];
135
- for (const o of c) {
136
- const f = a.get(o), y = /* @__PURE__ */ new Map(), p = [], x = [];
137
- for (const m of f) for (let b = 0; b < 3; b++) {
138
- const S = t[m * 3 + b];
139
- if (!y.has(S)) {
140
- const C = p.length / 3;
141
- p.push(n[S * 3], n[S * 3 + 1], n[S * 3 + 2]), y.set(S, C);
142
- }
143
- x.push(y.get(S));
144
- }
145
- const g = new J.BufferGeometry();
146
- g.setAttribute("position", new J.Float32BufferAttribute(p, 3)), g.setIndex(x), g.computeVertexNormals(), u.push(g);
147
- const v = o === r ? `#${o} inner` : o === 0 ? `#${o} outer` : `#${o} (${f.length} faces)`;
148
- s.push(v), l.push(zt[o % zt.length]);
149
- }
150
- return {
151
- geometries: u,
152
- labels: s,
153
- colors: l,
154
- innerIdx: r
155
- };
156
- }
157
- async function bn(e, r, n) {
158
- let t = null;
159
- try {
160
- const i = gn(e);
161
- n == null ? void 0 : n("Loading mesh..."), t = new r.WasmMeshSet(), t.loadObjString(e), n == null ? void 0 : n("Detecting units...");
162
- const a = t.autoScaleToMm(pn);
163
- n == null ? void 0 : n("Merging close vertices..."), t.applyMergeCloseVertices(1e-4), n == null ? void 0 : n("Analyzing mesh components...");
164
- let c = false, u = null;
165
- if (t.getComponentCount() >= 2) {
166
- n == null ? void 0 : n("Building component debug info...");
167
- const y = yn(t, null);
168
- n == null ? void 0 : n("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) : (n == null ? void 0 : n("Removing floating artifacts..."), t.splitAndKeepLargest(), u = y);
169
- } else n == null ? void 0 : n("Removing floating artifacts..."), t.splitAndKeepLargest();
170
- n == null ? void 0 : n("Closing holes..."), t.applyCloseHoles(30), t.applyMergeCloseVertices(1e-4), n == null ? void 0 : n("Extracting geometry...");
171
- const l = t.getVertices(), o = t.getFaces();
172
- if (l.length === 0) return null;
173
- const f = new J.BufferGeometry();
174
- if (f.setAttribute("position", new J.Float32BufferAttribute(l, 3)), f.setIndex(Array.from(o)), f.computeVertexNormals(), i) {
175
- const y = a ? 1e3 : 1;
176
- mn(f, i.positions, i.colors, y);
177
- }
178
- return {
179
- geometry: f,
180
- wasScaled: a,
181
- innerShellExtracted: c,
182
- componentDebug: u
183
- };
184
- } catch (i) {
185
- return console.error("WASM processing failed:", i), null;
186
- } finally {
187
- if (t) try {
188
- t.free();
189
- } catch {
190
- }
191
- }
192
- }
193
- function wn(e) {
194
- const n = new ln().parse(e);
195
- let t = null;
196
- return n.traverse((i) => {
197
- i.isMesh && !t && (t = i.geometry);
198
- }), t;
199
- }
200
- async function ft(e) {
201
- const r = await e.arrayBuffer(), i = new an().parse(r).getAttribute("position");
202
- if (!i || i.count === 0) throw new Error("Empty STL geometry");
203
- const a = [];
204
- for (let c = 0; c < i.count; c++) a.push(`v ${i.getX(c)} ${i.getY(c)} ${i.getZ(c)}`);
205
- for (let c = 0; c < i.count; c += 3) a.push(`f ${c + 1} ${c + 2} ${c + 3}`);
206
- return a.join(`
207
- `);
208
- }
209
- function Bt(e, r) {
210
- const n = 1 / r;
211
- return `${Math.round(e.x * n)}_${Math.round(e.y * n)}_${Math.round(e.z * n)}`;
212
- }
213
- function Rt(e, r) {
214
- if (!e.length) return [];
215
- const n = [];
216
- for (const t of e) (n.length === 0 || n[n.length - 1].distanceTo(t) > r) && n.push(t.clone());
217
- return n.length > 2 && n[0].distanceTo(n[n.length - 1]) > r && n.push(n[0].clone()), n;
218
- }
219
- function Ne(e) {
220
- let r = 0;
221
- for (let n = 0; n < e.length - 1; n++) r += e[n].distanceTo(e[n + 1]);
222
- return r;
223
- }
224
- function Et(e, r = 1e-3, n = false) {
225
- if (!e.length) return [];
226
- const t = /* @__PURE__ */ new Map(), i = (l) => {
227
- const o = Bt(l, r);
228
- let f = t.get(o);
229
- return f || (f = l.clone(), t.set(o, f)), f;
230
- }, a = e.map((l) => ({
231
- a: i(l.a),
232
- b: i(l.b)
233
- })), c = [];
234
- for (; a.length; ) {
235
- const l = a.pop(), o = [
236
- l.a,
237
- l.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: x, b: g } = a[p];
244
- if (x.equals(o[o.length - 1])) o.push(g);
245
- else if (g.equals(o[o.length - 1])) o.push(x);
246
- else if (x.equals(o[0])) o.unshift(g);
247
- else if (g.equals(o[0])) o.unshift(x);
248
- else continue;
249
- a.splice(p, 1), f = true;
250
- }
251
- }
252
- const y = Rt(o, r);
253
- y.length > 1 && c.push(y);
254
- }
255
- if (!c.length) return [];
256
- if (c.sort((l, o) => Ne(o) - Ne(l)), !n) return c[0] ?? [];
257
- const u = Ne(c[0]), s = c.filter((l) => Ne(l) >= u * 0.3);
258
- return s[s.length - 1] ?? c[0];
259
- }
260
- function Ct(e, r, n, t = false) {
261
- const i = new it(new h(0, 1, 0), -n), a = [], c = new Tt();
262
- c.setFromBufferAttribute(r.getAttribute("position"));
263
- const u = {
264
- linePoints: [],
265
- lineLength: 0,
266
- rightmostPoint: new h(0, n, 0)
267
- };
268
- if (!i.intersectsBox(c)) return u;
269
- const s = new ht(), l = new h();
270
- e.shapecast({
271
- intersectsBounds: (g) => i.intersectsBox(g),
272
- intersectsTriangle: (g) => {
273
- const w = [];
274
- s.set(g.a, g.b), i.intersectLine(s, l) && w.push(l.clone()), s.set(g.b, g.c), i.intersectLine(s, l) && w.push(l.clone()), s.set(g.c, g.a), i.intersectLine(s, l) && w.push(l.clone()), w.length === 2 && a.push({
275
- a: w[0],
276
- b: w[1]
277
- });
278
- }
279
- });
280
- const o = Et(a, ut, t), f = Ne(o);
281
- if (o.length < 2) return u;
282
- let y = -1 / 0, p = new h(0, n, 0);
283
- for (const g of o) g.x > y && (y = g.x, p = g.clone());
284
- const x = o.length > 2 && o[0].distanceTo(o[o.length - 1]) < ut * 10;
285
- return {
286
- linePoints: o,
287
- lineLength: f,
288
- rightmostPoint: p,
289
- isClosed: x
290
- };
291
- }
292
- function Ze(e, r, n, t = false) {
293
- const i = Ct(e, r, n, t);
294
- if (i.isClosed && i.linePoints.length >= 3) return i;
295
- console.warn(`[slice] y=${n.toFixed(2)} failed (pts=${i.linePoints.length}, closed=${i.isClosed}), retrying...`);
296
- let a = i;
297
- for (const c of hn) {
298
- const u = Ct(e, r, n + c, t);
299
- if (u.isClosed && u.linePoints.length >= 3) return console.log(`[slice] y=${n.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=${n.toFixed(2)} all retries exhausted (pts=${a.linePoints.length}, closed=${a.isClosed})`), a;
303
- }
304
- function pt(e, r, n, t) {
305
- const i = new it().setFromNormalAndCoplanarPoint(t.clone().normalize(), n), a = new Tt();
306
- if (a.setFromBufferAttribute(r.getAttribute("position")), !i.intersectsBox(a)) return 0;
307
- const c = [], u = new ht(), s = new h();
308
- e.shapecast({
309
- intersectsBounds: (o) => i.intersectsBox(o),
310
- intersectsTriangle: (o) => {
311
- const f = [];
312
- u.set(o.a, o.b), i.intersectLine(u, s) && f.push(s.clone()), u.set(o.b, o.c), i.intersectLine(u, s) && f.push(s.clone()), u.set(o.c, o.a), i.intersectLine(u, s) && f.push(s.clone()), f.length === 2 && c.push({
313
- a: f[0],
314
- b: f[1]
315
- });
316
- }
317
- });
318
- const l = Et(c, ut);
319
- return Ne(l);
320
- }
321
- function ot(e) {
322
- return new $e(e, {
323
- maxLeafTris: Ye
324
- });
325
- }
326
- function vt(e, r, n) {
327
- const t = e instanceof $e ? e : new $e(e, {
328
- maxLeafTris: Ye
329
- }), i = new it().setFromNormalAndCoplanarPoint(n.clone().normalize(), r), a = [], c = new ht(), u = new h();
330
- return t.shapecast({
331
- intersectsBounds: (s) => i.intersectsBox(s),
332
- intersectsTriangle: (s) => {
333
- const l = [];
334
- c.set(s.a, s.b), i.intersectLine(c, u) && l.push(u.clone()), c.set(s.b, s.c), i.intersectLine(c, u) && l.push(u.clone()), c.set(s.c, s.a), i.intersectLine(c, u) && l.push(u.clone()), l.length === 2 && a.push({
335
- a: l[0],
336
- b: l[1]
337
- });
338
- }
339
- }), a;
340
- }
341
- function Mt(e, r, n = 1e-3) {
342
- if (!e.length) return [];
343
- const t = /* @__PURE__ */ new Map(), i = (l) => {
344
- const o = Bt(l, n);
345
- let f = t.get(o);
346
- return f || (f = l.clone(), t.set(o, f)), f;
347
- }, a = e.map((l) => ({
348
- a: i(l.a),
349
- b: i(l.b)
350
- })), c = [];
351
- for (; a.length; ) {
352
- const l = a.pop(), o = [
353
- l.a,
354
- l.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: x, b: g } = a[p];
361
- if (x.equals(o[o.length - 1])) o.push(g);
362
- else if (g.equals(o[o.length - 1])) o.push(x);
363
- else if (x.equals(o[0])) o.unshift(g);
364
- else if (g.equals(o[0])) o.unshift(x);
365
- else continue;
366
- a.splice(p, 1), f = true;
367
- }
368
- }
369
- const y = Rt(o, n);
370
- y.length > 1 && c.push(y);
371
- }
372
- if (!c.length) return [];
373
- let u = [], s = 1 / 0;
374
- for (const l of c) {
375
- if (l.length < 3 || !(l[0].distanceTo(l[l.length - 1]) < 2)) continue;
376
- const f = new h();
377
- for (const p of l) f.add(p);
378
- f.divideScalar(l.length);
379
- const y = f.distanceTo(r);
380
- y < s && (s = y, u = l);
381
- }
382
- if (u.length === 0) for (const l of c) {
383
- if (l.length < 3) continue;
384
- const o = new h();
385
- for (const y of l) o.add(y);
386
- o.divideScalar(l.length);
387
- const f = o.distanceTo(r);
388
- f < s && (s = f, u = l);
389
- }
390
- return u;
391
- }
392
- function Sn(e) {
393
- const r = new h();
394
- for (const n of e) r.add(n);
395
- return r.divideScalar(e.length);
396
- }
397
- function zn(e, r, n) {
398
- const t = new $e(e, {
399
- maxLeafTris: Ye
400
- }), i = new h().subVectors(r, n).normalize(), c = r.distanceTo(n) * 0.05;
401
- let u = i.clone();
402
- const s = (v) => {
403
- const m = [];
404
- for (let $ = -10; $ <= 0; $++) {
405
- const R = r.clone().addScaledVector(v, $ * c), Y = vt(t, R, v), j = Mt(Y, R, 1);
406
- j.length >= 3 && j[0].distanceTo(j[j.length - 1]) < 1 && m.push(Sn(j));
407
- }
408
- if (m.length < 3) return null;
409
- const b = new h();
410
- for (const $ of m) b.add($);
411
- b.divideScalar(m.length);
412
- let S = 0, C = 0, M = 0, P = 0, L = 0, H = 0;
413
- for (const $ of m) {
414
- const R = $.x - b.x, Y = $.y - b.y, j = $.z - b.z;
415
- S += R * R, C += R * Y, M += R * j, P += Y * Y, L += Y * j, H += j * j;
416
- }
417
- let O = v.clone();
418
- for (let $ = 0; $ < 30; $++) {
419
- const R = S * O.x + C * O.y + M * O.z, Y = C * O.x + P * O.y + L * O.z, j = M * O.x + L * O.y + H * O.z, ne = new h(R, Y, j), 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(i) < 0 && O.negate(), O;
424
- };
425
- for (let v = 0; v < 3; v++) {
426
- const m = s(u);
427
- if (!m) break;
428
- const b = u.angleTo(m);
429
- if (u = m, b < 1e-3) break;
430
- }
431
- const l = new h();
432
- Math.abs(u.x) < 0.9 ? l.set(1, 0, 0) : l.set(0, 1, 0), l.crossVectors(u, l).normalize();
433
- const o = new h().crossVectors(u, l).normalize(), f = (v) => {
434
- const m = vt(t, r, v), b = Mt(m, r, 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: Ne(b),
442
- closed: S
443
- };
444
- };
445
- let y = u.clone(), p = 1 / 0;
446
- for (let v = -3; v <= 3; v += 1) for (let m = -3; m <= 3; m += 1) {
447
- const b = v * Math.PI / 180, S = m * Math.PI / 180, C = u.clone().applyQuaternion(new Oe().setFromAxisAngle(l, b)).applyQuaternion(new Oe().setFromAxisAngle(o, S)).normalize(), M = f(C);
448
- M.closed && M.circumference < p && (p = M.circumference, y = C);
449
- }
450
- const x = y.clone(), g = new h();
451
- Math.abs(x.x) < 0.9 ? g.set(1, 0, 0) : g.set(0, 1, 0), g.crossVectors(x, g).normalize();
452
- const w = new h().crossVectors(x, g).normalize();
453
- for (let v = -5; v <= 5; v += 1) for (let m = -5; m <= 5; m += 1) {
454
- const b = v * 0.1 * Math.PI / 180, S = m * 0.1 * Math.PI / 180, C = x.clone().applyQuaternion(new Oe().setFromAxisAngle(g, b)).applyQuaternion(new Oe().setFromAxisAngle(w, S)).normalize(), M = f(C);
455
- M.closed && M.circumference < p && (p = M.circumference, y = C);
456
- }
457
- return p === 1 / 0 && (p = f(u).circumference, y = u), {
458
- normal: y,
459
- circumference: p
460
- };
461
- }
462
- function Cn(e, r, n) {
463
- const t = e.getAttribute("position"), i = e.getIndex();
464
- if (!i) return {
465
- isDoubleShell: false,
466
- sampledFaces: 0,
467
- opposingPairs: 0,
468
- confidence: 0
469
- };
470
- const a = i.array, c = t.array, u = new h().subVectors(n, r).normalize(), s = n.distanceTo(r), l = Math.min(s * 0.06, 15), o = 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, x = new h();
476
- let g = 0, w = 0, v = 0;
477
- for (const S of [
478
- 0.65,
479
- 0.78,
480
- 0.9
481
- ]) {
482
- const C = new h().lerpVectors(r, n, S);
483
- let M = 0, P = 0, L = 0, H = 0;
484
- for (let Y = 0; Y < a.length; Y += 3) {
485
- const j = a[Y], ne = a[Y + 1], oe = a[Y + 2], le = (c[j * 3] + c[ne * 3] + c[oe * 3]) / 3, ee = (c[j * 3 + 1] + c[ne * 3 + 1] + c[oe * 3 + 1]) / 3, D = (c[j * 3 + 2] + c[ne * 3 + 2] + c[oe * 3 + 2]) / 3, z = le - C.x, F = ee - C.y, V = D - C.z;
486
- Math.abs(z * u.x + F * u.y + V * u.z) > l || (M += le, P += ee, L += D, H++);
487
- }
488
- if (H < 8) continue;
489
- const O = new h(M / H, P / H, L / H);
490
- let $ = 0;
491
- for (let Y = 0; Y < p; Y++) {
492
- const j = Y / p * Math.PI * 2, ne = new h().addScaledVector(f, Math.cos(j)).addScaledVector(y, Math.sin(j)), oe = new J.Ray(O, ne);
493
- let le = 0;
494
- o.shapecast({
495
- intersectsBounds: (ee) => oe.intersectsBox(ee),
496
- intersectsTriangle: (ee) => (oe.intersectTriangle(ee.a, ee.b, ee.c, false, x) && le++, false)
497
- }), $ += le, w++;
498
- }
499
- g += $, $ / p > 1.5 && v++;
500
- }
501
- if (w === 0) return {
502
- isDoubleShell: false,
503
- sampledFaces: 0,
504
- opposingPairs: 0,
505
- confidence: 0
506
- };
507
- const m = g / w;
508
- return {
509
- isDoubleShell: v >= 2,
510
- sampledFaces: w,
511
- opposingPairs: g,
512
- confidence: m
513
- };
514
- }
515
- function vn(e, r, n, t) {
516
- const i = new h().subVectors(n, r), a = new h().subVectors(t, r), c = new h().subVectors(e, r), u = i.dot(i), s = i.dot(a), l = i.dot(c), o = a.dot(a), f = a.dot(c), y = 1 / (u * o - s * s), p = (o * l - s * f) * y, x = (u * f - s * l) * y;
517
- return {
518
- u: 1 - p - x,
519
- v: p,
520
- w: x
521
- };
522
- }
523
- function st(e, r, n, t, i = false) {
524
- const a = n.clone().normalize(), c = e.getAttribute("position"), u = e.getIndex();
525
- if (!u) throw new Error("No index buffer");
526
- const s = new h().subVectors(t, r).dot(a), l = Math.abs(s) < 1e-6 ? 1 : Math.sign(s), o = c.array, f = u.array, y = e.getAttribute("color"), p = y ? y.array : null, x = [], g = [], w = [], v = (D, z, F) => {
527
- const V = x.length / 3;
528
- return x.push(D, z, F), V;
529
- }, m = (D) => new h(o[D * 3], o[D * 3 + 1], o[D * 3 + 2]), b = (D, z) => {
530
- const F = new h().subVectors(D, r).dot(a), V = new h().subVectors(z, r).dot(a), B = F / (F - V);
531
- return new h().lerpVectors(D, z, B);
532
- }, S = /* @__PURE__ */ new Map(), C = /* @__PURE__ */ new Map(), M = /* @__PURE__ */ new Map(), P = (D) => {
533
- let z = M.get(D);
534
- return z === void 0 && (z = new h().subVectors(m(D), r).dot(a), M.set(D, z)), z;
535
- }, L = (D) => {
536
- if (S.has(D)) return S.get(D);
537
- const z = m(D), F = v(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 (C.has(F)) return C.get(F);
542
- const V = b(m(D), m(z)), B = v(V.x, V.y, V.z);
543
- if (p) {
544
- const T = P(D), E = P(z), N = T / (T - E);
545
- g.push(p[D * 3] + N * (p[z * 3] - p[D * 3]), p[D * 3 + 1] + N * (p[z * 3 + 1] - p[D * 3 + 1]), p[D * 3 + 2] + N * (p[z * 3 + 2] - p[D * 3 + 2]));
546
- }
547
- return C.set(F, B), B;
548
- }, O = (D) => {
549
- const z = P(D);
550
- return Math.sign(z) === l || 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), N = (B ? 1 : 0) + (T ? 1 : 0) + (E ? 1 : 0);
554
- if (N !== 0) if (N === 3) w.push(L(z), L(F), L(V));
555
- else if (N === 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(L(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 = L(q), A = L(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 (i) 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 N = w[T * 3 + E];
574
- D.has(N) || D.set(N, []), D.get(N).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 = [], N = [
580
- T
581
- ];
582
- for (z.add(T); N.length > 0; ) {
583
- const X = N.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), N.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 N of T) {
596
- for (let X = 0; X < 3; X++) {
597
- const q = w[N * 3 + X], ie = x[q * 3] - t.x, se = x[q * 3 + 1] - t.y, A = x[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(), j = [], 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) || (j.push(x[F * 3], x[F * 3 + 1], x[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(j, 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, r, n) {
616
- const t = e.getAttribute("position"), i = n - r;
617
- if (i < 1) return null;
618
- const a = 30, c = i / a, u = [];
619
- for (let w = 0; w < a; w++) {
620
- const v = r + w * c, m = r + (w + 1) * c;
621
- let b = 0, S = 0, C = 0, M = 0;
622
- for (let P = 0; P < t.count; P++) {
623
- const L = t.getY(P);
624
- L >= v && L < m && (b += t.getX(P), S += L, C += t.getZ(P), M++);
625
- }
626
- M > 20 && u.push(new h(b / M, S / M, C / M));
627
- }
628
- if (u.length < 5) return null;
629
- const s = new h();
630
- for (const w of u) s.add(w);
631
- s.divideScalar(u.length);
632
- let l = 0, o = 0, f = 0, y = 0, p = 0, x = 0;
633
- for (const w of u) {
634
- const v = w.x - s.x, m = w.y - s.y, b = w.z - s.z;
635
- l += v * v, o += v * m, f += v * b, y += m * m, p += m * b, x += b * b;
636
- }
637
- let g = new h(0.01, 1, 0.01).normalize();
638
- for (let w = 0; w < 30; w++) {
639
- const v = l * g.x + o * g.y + f * g.z, m = o * g.x + y * g.y + p * g.z, b = f * g.x + p * g.y + x * g.z, S = new h(v, m, b), C = S.length();
640
- if (C < 1e-10 || (S.divideScalar(C), g.distanceTo(S) < 1e-8)) break;
641
- g = S;
642
- }
643
- return g.y < 0 && g.negate(), g;
644
- }
645
- function Wt(e, r, n, t) {
646
- const i = e.getIndex(), a = i ? i.count / 3 : 0;
647
- if (a < 10) return {
648
- valid: false,
649
- reason: `Geometry is empty or degenerate (${a} faces)`
650
- };
651
- const c = r - n;
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
- }), s = Ze(u, e, r);
663
- if (s.lineLength === 0) return {
664
- valid: false,
665
- reason: "No circumference at green point \u2014 mesh may be empty at that height"
666
- };
667
- const l = r - t;
668
- if (l <= n) return {
669
- valid: true,
670
- reason: ""
671
- };
672
- const o = Ze(u, e, l);
673
- if (s.lineLength > 0 && o.lineLength > 0) {
674
- const y = s.lineLength / o.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 = r - t * 2;
681
- if (f > n) {
682
- const y = Ze(u, e, f);
683
- if (o.lineLength > 0 && y.lineLength > 0) {
684
- const p = o.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, r, n, t) {
719
- const i = new Oe().setFromAxisAngle(n, t);
720
- return e.applyMatrix4(new kt().makeRotationFromQuaternion(i)), r.map((a) => a.clone().applyQuaternion(i));
721
- }
722
- function _t(e, r, n) {
723
- const t = new Oe().setFromAxisAngle(r, n);
724
- e.applyMatrix4(new kt().makeRotationFromQuaternion(t));
725
- }
726
- function An(e, r, n, t, i, a) {
727
- const c = n.getAttribute("position"), u = n.getIndex();
728
- if (!u) return r;
729
- const l = r[1].y + t * We, o = c.array, f = u.array, y = n.getAttribute("color"), p = y ? y.array : null, x = [], g = [], w = [], v = (A, I, k) => {
730
- const G = x.length / 3;
731
- return x.push(A, I, k), G;
732
- }, m = (A) => [
733
- o[A * 3],
734
- o[A * 3 + 1],
735
- o[A * 3 + 2]
736
- ], b = (A, I) => {
737
- const k = (l - A[1]) / (I[1] - A[1]);
738
- return [
739
- A[0] + k * (I[0] - A[0]),
740
- l,
741
- A[2] + k * (I[2] - A[2])
742
- ];
743
- }, S = /* @__PURE__ */ new Map(), C = /* @__PURE__ */ new Map(), M = (A) => {
744
- if (S.has(A)) return S.get(A);
745
- const [I, k, G] = m(A), U = v(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
- }, P = (A, I) => {
748
- const k = A < I ? `${A}_${I}` : `${I}_${A}`;
749
- if (C.has(k)) return C.get(k);
750
- const G = m(A), U = m(I), [re, Le, me] = b(G, U), ae = v(re, Le, me);
751
- if (p) {
752
- const xe = (l - 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 C.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 = m(I), re = m(k), Le = m(G), me = U[1] < l, ae = re[1] < l, xe = Le[1] < l, 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), P(pe, we), P(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), je = P(we, pe), Pe = P(he, pe);
767
- w.push(Ge, je, fe), w.push(fe, je, Pe);
768
- }
769
- }
770
- const L = w.length / 3, H = /* @__PURE__ */ new Map();
771
- for (let A = 0; A < L; 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 < L; 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 < L; 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 = r[0];
792
- let j = 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 = x[U * 3] - Y.x, Le = x[U * 3 + 1] - Y.y, me = x[U * 3 + 2] - Y.z, ae = re * re + Le * Le + me * me;
798
- ae < I && (I = ae);
799
- }
800
- if (I < ne) break;
801
- }
802
- I < ne && (ne = I, j = A);
803
- }
804
- const oe = /* @__PURE__ */ new Map(), le = [], ee = [], D = [];
805
- let z = 0;
806
- for (const A of j) for (let I = 0; I < 3; I++) {
807
- const k = w[A * 3 + I];
808
- oe.has(k) || (le.push(x[k * 3], x[k * 3 + 1], x[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, i.onStatus("Refining alignment...");
812
- const V = new h(0, 1, 0);
813
- let B = [
814
- ...r
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, Le = U / re, me = [];
823
- for (let ye = 0; ye < re; ye++) {
824
- const Te = k + ye * Le, Me = k + (ye + 1) * Le;
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 je = fe.dot(V);
849
- if (Math.acos(Math.min(1, Math.abs(je))) * 180 / Math.PI < 0.1) break;
850
- const Pe = new h().crossVectors(fe, V);
851
- Pe.length() > 1e-4 && (Pe.normalize(), T(Pe, Math.acos(Math.min(1, Math.max(-1, je)))));
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(), i.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), i.setModelSize(Math.max(se.x, se.y, se.z)), i.setCut(true), i.setAdjustedStartY(null), i.setAdjustedEndY(null), i.setOriginalEndY(B[1].y + 2 * We), B;
864
- }
865
- function Fn(e, r, n, t) {
866
- const i = r.map((x) => new h(x.position.x, x.position.y, x.position.z)), a = i[0], c = i[1];
867
- t.onStatus("Cutting double shell above green point...");
868
- const u = c.y + 2 * We, s = new h(c.x, u, c.z), l = e.geometry, o = st(l, s, new h(0, 1, 0), a, true);
869
- l.dispose(), e.geometry = o, o.computeVertexNormals(), o.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
- }), i.push(a.clone()), t.updateLandmarkPositions(i.map((x) => ({
887
- x: x.x,
888
- y: x.y,
889
- z: x.z
890
- }))), t.setAligned(true), t.setCut(true), t.setAdjustedStartY(null), t.setAdjustedEndY(null), t.setOriginalEndY(c.y);
891
- const f = o.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(o, c.y, a.y, n);
894
- p.valid || console.warn(`Double shell validation warning: ${p.reason}`);
895
- }
896
- function In(e, r, n, t) {
897
- var _a, _b;
898
- const i = e.geometry.clone(), a = r.map((s) => ({
899
- ...s
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 s = new h(r[0].position.x, r[0].position.y, r[0].position.z), l = new h(r[1].position.x, r[1].position.y, r[1].position.z);
904
- t.onStatus("Detecting shell type...");
905
- const o = Cn(e.geometry, s, l);
906
- if (console.log(`Shell detection: ${o.isDoubleShell ? "DOUBLE" : "SINGLE"} shell (${o.opposingPairs} inward/${o.sampledFaces} total faces, confidence ${(o.confidence * 100).toFixed(0)}%)`), o.isDoubleShell) {
907
- (_a = t.setDoubleShell) == null ? void 0 : _a.call(t, true), Fn(e, a, n, t), t.setClippedReferenceGeometry ? (i.computeVertexNormals(), t.setClippedReferenceGeometry(i)) : i.dispose();
908
- return;
909
- }
910
- (_b = t.setDoubleShell) == null ? void 0 : _b.call(t, false);
911
- }
912
- let u = "";
913
- for (let s = 0; s < nt; s++) try {
914
- s > 0 && (t.onStatus(`Retry ${s}/${nt - 1} \u2014 ${u}`), e.geometry.dispose(), e.geometry = i.clone(), t.removeLandmarkPoint(2), t.setAligned(false), t.setCut(false));
915
- let l = e.geometry, o = a.map((z) => new h(z.position.x, z.position.y, z.position.z));
916
- const f = t.setClippedReferenceGeometry ? i.clone() : null;
917
- let y = 5;
918
- if (s > 0) {
919
- const z = Mn[s - 1];
920
- y = z.cutOffset;
921
- const F = new h().subVectors(o[1], o[0]).normalize();
922
- if (z.nudge < 0) o[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), o[1].addScaledVector(E, z.nudge);
926
- }
927
- const V = l.getAttribute("position");
928
- let B = 1 / 0, T = 0;
929
- for (let E = 0; E < V.count; E++) {
930
- const N = V.getX(E) - o[1].x, X = V.getY(E) - o[1].y, q = V.getZ(E) - o[1].z, ie = N * N + X * X + q * q;
931
- ie < B && (B = ie, T = E);
932
- }
933
- o[1].set(V.getX(T), V.getY(T), V.getZ(T)), console.log(`Retry ${s}: nudge=${z.nudge}mm angle=${(z.angle * 180 / Math.PI).toFixed(0)}\xB0 cutOffset=${z.cutOffset}" \u2192 green=(${o[1].x.toFixed(1)}, ${o[1].y.toFixed(1)}, ${o[1].z.toFixed(1)})`);
934
- }
935
- const p = (z, F) => {
936
- o = Vt(l, o, z, F), f && _t(f, z, F);
937
- }, x = o[0], g = o[1], { normal: w } = zn(l, g, x);
938
- t.onStatus(s > 0 ? `Retry ${s}: Slicing mesh...` : "Slicing mesh at cut plane...");
939
- const v = new h().subVectors(g, x).normalize(), m = Math.sign(v.dot(w)), b = g.clone().addScaledVector(w, m * y * We), S = st(l, b, w, x);
940
- l.dispose(), l = S, e.geometry = l, t.onStatus(s > 0 ? `Retry ${s}: Rough alignment...` : "Rough alignment...");
941
- const C = new h().subVectors(o[1], o[0]).normalize();
942
- let M = C.dot(c), P = new h().crossVectors(C, c);
943
- P.length() > 1e-4 && (P.normalize(), p(P, Math.acos(Math.min(1, Math.max(-1, M))))), o[0].y > o[1].y && p(new h(1, 0, 0), Math.PI), l.computeVertexNormals(), t.onStatus(s > 0 ? `Retry ${s}: Translating...` : "Translating to origin...");
944
- const L = o[0].clone();
945
- l.translate(-L.x, -L.y, -L.z), f && f.translate(-L.x, -L.y, -L.z), o = o.map((z) => new h(z.x - L.x, z.y - L.y, z.z - L.z)), t.onStatus(s > 0 ? `Retry ${s}: Isolating limb...` : "Isolating limb region...");
946
- {
947
- const z = ot(l), F = o[0].y, V = o[1].y, B = new h(0, 1, 0), T = 5;
948
- l.computeBoundingBox();
949
- const E = l.boundingBox.max.y, N = [];
950
- for (let X = F + T; X < E; X += T) {
951
- const q = pt(z, l, new h(0, X, 0), B);
952
- q > 0 && N.push({
953
- y: X,
954
- circ: q
955
- });
956
- }
957
- if (N.length > 5) {
958
- const X = V - F, q = F + X * 0.3, ie = F + X * 0.7, se = N.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 N) 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 = N.find((re) => Math.abs(re.y - V) < T);
968
- if (U && U.circ > I * k) {
969
- for (let re = N.length - 1; re >= 0; re--) if (!(N[re].y > V + T) && N[re].circ <= I * k) {
970
- G = N[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(l, new h(0, G, 0), B, o[0]);
978
- l.dispose(), l = U, e.geometry = l, l.computeVertexNormals(), l.computeBoundingBox();
979
- } else console.log(`Limb isolation: no anomaly detected (baseline=${I.toFixed(1)}mm)`);
980
- }
981
- }
982
- }
983
- t.onStatus(s > 0 ? `Retry ${s}: PCA alignment...` : "Iterative PCA alignment...");
984
- const H = 10, O = 80, $ = o[0].y, R = o[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(l, F, V);
988
- if (B && (M = B.dot(c), Math.acos(Math.min(1, Math.abs(M))) * 180 / Math.PI > 0.1 && (P = new h().crossVectors(B, c), P.length() > 1e-4))) {
989
- P.normalize(), p(P, Math.acos(Math.min(1, Math.max(-1, M))));
990
- const E = o[0].clone();
991
- l.translate(-E.x, -E.y, -E.z), f && f.translate(-E.x, -E.y, -E.z), o = o.map((N) => new h(N.x - E.x, N.y - E.y, N.z - E.z));
992
- }
993
- if (Y -= H, Y <= $) break;
994
- }
995
- l.computeVertexNormals(), t.onStatus(s > 0 ? `Retry ${s}: Setting blue point...` : "Setting blue point...");
996
- const j = new h(o[0].x, o[0].y, o[0].z);
997
- o.push(j), t.addLandmarkPoint({
998
- faceIndex: -1,
999
- vertexIndices: [
1000
- 0,
1001
- 1,
1002
- 2
1003
- ],
1004
- position: {
1005
- x: j.x,
1006
- y: j.y,
1007
- z: j.z
1008
- },
1009
- barycentricCoords: {
1010
- u: 0.33,
1011
- v: 0.33,
1012
- w: 0.34
1013
- }
1014
- }), t.onStatus(s > 0 ? `Retry ${s}: Final PCA...` : "Final PCA refinement...");
1015
- for (let z = 0; z < 3; z++) {
1016
- const F = rt(l, 0, o[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 (P = new h().crossVectors(F, c), P.length() > 1e-4) {
1020
- P.normalize(), p(P, Math.acos(Math.min(1, Math.max(-1, M))));
1021
- const B = o[0].clone();
1022
- l.translate(-B.x, -B.y, -B.z), f && f.translate(-B.x, -B.y, -B.z), o = o.map((T) => new h(T.x - B.x, T.y - B.y, T.z - B.z));
1023
- }
1024
- }
1025
- }
1026
- if (o[1].y < o[0].y) {
1027
- p(new h(1, 0, 0), Math.PI);
1028
- const z = o[0].clone();
1029
- l.translate(-z.x, -z.y, -z.z), f && f.translate(-z.x, -z.y, -z.z), o = o.map((F) => new h(F.x - z.x, F.y - z.y, F.z - z.z));
1030
- }
1031
- l.computeVertexNormals(), l.computeBoundingBox(), t.onStatus(s > 0 ? `Retry ${s}: Circumference refinement...` : "Circumference refinement...");
1032
- {
1033
- const z = ot(l), F = o[1].y, V = o[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, l, new h(0, re, 0), G);
1044
- return U;
1045
- };
1046
- let N = 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, N = I * T, X = k * T);
1050
- }
1051
- const ie = N, 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, N = G, X = U);
1055
- }
1056
- const A = Math.sqrt(N * N + X * X);
1057
- if (A > 0.05 * T) {
1058
- console.log(`Circumference refinement: rotating ${(-N / T).toFixed(2)}\xB0X ${(-X / T).toFixed(2)}\xB0Z`), Math.abs(N) > 0.01 * T && p(new h(1, 0, 0), -N), Math.abs(X) > 0.01 * T && p(new h(0, 0, 1), -X);
1059
- const I = o[0].clone();
1060
- l.translate(-I.x, -I.y, -I.z), f && f.translate(-I.x, -I.y, -I.z), o = o.map((k) => new h(k.x - I.x, k.y - I.y, k.z - I.z)), l.computeVertexNormals();
1061
- } else console.log(`Circumference refinement: already optimal (${(A / T).toFixed(3)}\xB0)`);
1062
- }
1063
- }
1064
- const ne = o.map((z) => ({
1065
- x: z.x,
1066
- y: z.y,
1067
- z: z.z
1068
- }));
1069
- t.updateLandmarkPositions(ne), t.setAligned(true), t.onStatus(s > 0 ? `Retry ${s}: Cutting mesh...` : 'Cutting mesh 2" above green...'), o = An(e, o, l, 5, t, f), t.onStatus("Validating results...");
1070
- const oe = e.geometry, le = o[1].y, ee = o[0].y, D = Wt(oe, le, ee, n);
1071
- if (D.valid) {
1072
- console.log(`Processing succeeded on attempt ${s + 1}`), f && t.setClippedReferenceGeometry && (f.computeVertexNormals(), t.setClippedReferenceGeometry(f));
1073
- break;
1074
- }
1075
- console.warn(`Attempt ${s + 1} failed validation: ${D.reason}`), u = D.reason, f && f.dispose(), s === nt - 1 && (t.setError(`Processing produced unusual results after ${nt} attempts: ${D.reason}`), e.geometry.dispose(), e.geometry = i.clone(), t.removeLandmarkPoint(2), t.setAligned(false), t.setCut(false));
1076
- } catch (l) {
1077
- console.error("Processing failed:", l), t.setError(l instanceof Error ? l.message : "Failed to process mesh.");
1078
- break;
1079
- }
1080
- i.dispose();
1081
- }
1082
- const Ln = ({ message: e, onDismiss: r }) => 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: r,
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
- }), Pn = ({ mesh: e, maxPoints: r = 2, meshColor: n = "#c8c8c8", meshOpacity: t = 1 }) => {
1173
- const { addLandmarkPoint: i, landmarkPoints: a } = gt(), c = Fe((l) => {
1174
- if (a.length >= r) return;
1175
- l.stopPropagation();
1176
- const o = l.intersections[0], f = o == null ? void 0 : o.faceIndex;
1177
- if (!o || f == null) return;
1178
- const y = e.geometry, p = y.index;
1179
- let x;
1180
- p ? x = [
1181
- p.getX(f * 3),
1182
- p.getX(f * 3 + 1),
1183
- p.getX(f * 3 + 2)
1184
- ] : x = [
1185
- f * 3,
1186
- f * 3 + 1,
1187
- f * 3 + 2
1188
- ];
1189
- const g = y.getAttribute("position"), w = new h().fromBufferAttribute(g, x[0]), v = new h().fromBufferAttribute(g, x[1]), m = new h().fromBufferAttribute(g, x[2]);
1190
- w.applyMatrix4(e.matrixWorld), v.applyMatrix4(e.matrixWorld), m.applyMatrix4(e.matrixWorld);
1191
- const b = o.point, S = vn(b, w, v, m), C = {
1192
- faceIndex: f,
1193
- vertexIndices: x,
1194
- position: {
1195
- x: b.x,
1196
- y: b.y,
1197
- z: b.z
1198
- },
1199
- barycentricCoords: S
1200
- };
1201
- i(C);
1202
- }, [
1203
- e,
1204
- i,
1205
- a.length,
1206
- r
1207
- ]), u = de(() => !!e.geometry.getAttribute("color"), [
1208
- e
1209
- ]), s = de(() => new J.MeshStandardMaterial({
1210
- color: u ? "#ffffff" : n,
1211
- side: J.DoubleSide,
1212
- roughness: 0.6,
1213
- metalness: 0.1,
1214
- transparent: t < 1,
1215
- opacity: t,
1216
- vertexColors: u
1217
- }), [
1218
- n,
1219
- t,
1220
- u
1221
- ]);
1222
- return d("primitive", {
1223
- object: e,
1224
- onClick: c,
1225
- material: s
1226
- });
1227
- }, Dn = ({ point: e, index: r, markerSize: n, color: t, label: i }) => {
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
- n,
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: i
1265
- })
1266
- })
1267
- ]
1268
- }, r);
1269
- }, Tn = ({ modelSize: e, labels: r }) => {
1270
- const { landmarkPoints: n } = gt(), t = e * 0.02, i = [
1271
- "#ff4444",
1272
- "#44ff44",
1273
- "#4444ff"
1274
- ], c = r ?? [
1275
- "Origin",
1276
- "MPT",
1277
- "Cut Plane"
1278
- ];
1279
- return d(He, {
1280
- children: n.map((u, s) => d(Dn, {
1281
- point: u,
1282
- index: s,
1283
- markerSize: t,
1284
- color: i[s],
1285
- label: c[s]
1286
- }, s))
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, r) => {
1297
- const n = Math.abs(e - r);
1298
- return n < 1 ? "#8BC34A" : n < 5 ? "#FFC107" : "#FF5722";
1299
- }, It = new J.Color("#8BC34A"), Lt = new J.Color("#FFC107"), Bn = new J.Color("#FF5722"), Rn = (e) => {
1300
- if (e < 1) return It.clone();
1301
- if (e < 5) {
1302
- const n = (e - 1) / 4;
1303
- return It.clone().lerp(Lt, n);
1304
- }
1305
- const r = Math.min((e - 5) / 5, 1);
1306
- return Lt.clone().lerp(Bn, r);
1307
- }, En = (e, r) => {
1308
- const n = e.length, t = new Float32Array(n * 2 * 3), i = new Float32Array(n * 2 * 3), a = [];
1309
- for (let s = 0; s < n; s++) {
1310
- const l = e[s], o = r[s], f = l.distanceTo(o), y = Rn(f);
1311
- if (t[s * 6] = l.x, t[s * 6 + 1] = l.y, t[s * 6 + 2] = l.z, i[s * 6] = y.r, i[s * 6 + 1] = y.g, i[s * 6 + 2] = y.b, t[s * 6 + 3] = o.x, t[s * 6 + 4] = o.y, t[s * 6 + 5] = o.z, i[s * 6 + 3] = y.r, i[s * 6 + 4] = y.g, i[s * 6 + 5] = y.b, s < n - 1) {
1312
- const p = s * 2, x = p + 1, g = (s + 1) * 2, w = g + 1;
1313
- a.push(p, x, g, x, 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(i, 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: r, yPosition: n, color: t = "#00ff00", labelX: i, onDataChange: a, displayUnit: c = "mm", useInnerSurface: u = false, formValue: s, lineWidth: l = 1.5 }) => {
1328
- const o = de(() => Ze(e, r, n, u), [
1329
- e,
1330
- r,
1331
- n,
1332
- u
1333
- ]), { linePoints: f, lineLength: y } = o, p = de(() => {
1334
- if (s == null || y <= 0 || f.length < 2) return null;
1335
- const v = s / y, m = f.reduce((S, C) => S + C.x, 0) / f.length, b = f.reduce((S, C) => S + C.z, 0) / f.length;
1336
- return f.map((S) => new h(m + (S.x - m) * v, S.y, b + (S.z - b) * v));
1337
- }, [
1338
- f,
1339
- y,
1340
- s
1341
- ]), x = de(() => !p || f.length < 2 ? null : En(f, p), [
1342
- f,
1343
- p
1344
- ]);
1345
- Se(() => () => {
1346
- x && (x.geometry.dispose(), x.material.dispose());
1347
- }, [
1348
- x
1349
- ]);
1350
- const g = Ie(null), w = de(() => {
1351
- const v = new J.BufferGeometry();
1352
- v.setAttribute("position", new J.Float32BufferAttribute(new Float32Array(6), 3));
1353
- const m = new J.LineBasicMaterial({
1354
- color: 6710886,
1355
- depthTest: false,
1356
- depthWrite: false,
1357
- transparent: true
1358
- });
1359
- return new J.Line(v, m);
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: n,
1368
- originalValue: y,
1369
- modifiedValue: null
1370
- }));
1371
- }, [
1372
- y,
1373
- n,
1374
- a
1375
- ]), Pt(({ camera: v }) => {
1376
- if (!g.current || f.length < 2) return;
1377
- const m = new h();
1378
- v.getWorldDirection(m);
1379
- const b = new h(m.x, 0, m.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 C = -1 / 0, M = f[0];
1384
- for (const O of f) {
1385
- const $ = S.x * O.x + S.z * O.z;
1386
- $ > C && (C = $, M = O);
1387
- }
1388
- const P = i * 0.35, L = new h(M.x + S.x * P, n, M.z + S.z * P);
1389
- g.current.position.copy(L);
1390
- const H = w.geometry.getAttribute("position");
1391
- H.setXYZ(0, M.x, M.y, M.z), H.setXYZ(1, L.x, L.y, L.z), H.needsUpdate = true;
1392
- }), f.length < 2 ? null : W("group", {
1393
- children: [
1394
- d(ge, {
1395
- points: f,
1396
- color: t,
1397
- lineWidth: l,
1398
- depthTest: false,
1399
- depthWrite: false,
1400
- transparent: true
1401
- }),
1402
- x && d("primitive", {
1403
- object: x
1404
- }),
1405
- p && s != null && d(ge, {
1406
- points: p,
1407
- color: Ft(y, s),
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: s != 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
- s != null && y > 0 && (() => {
1472
- const v = y - s, m = v > 0.5 ? "\u25B2" : v < -0.5 ? "\u25BC" : "", b = Ft(y, s);
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
- m && d("span", {
1485
- style: {
1486
- fontSize: 10,
1487
- color: b,
1488
- lineHeight: 1
1489
- },
1490
- children: m
1491
- }),
1492
- W("span", {
1493
- style: {
1494
- fontSize: 13,
1495
- color: b,
1496
- fontFamily: "monospace",
1497
- fontWeight: 600
1498
- },
1499
- children: [
1500
- v > 0 ? "+" : "",
1501
- c === "inch" ? (v / 25.4).toFixed(2) : v.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" ? (s / 25.4).toFixed(2) : s.toFixed(0)
1513
- ]
1514
- })
1515
- ]
1516
- });
1517
- })()
1518
- ]
1519
- })
1520
- })
1521
- })
1522
- ]
1523
- });
1524
- }, Vn = nn(Wn), _n = ({ mesh: e, startY: r, endY: n, spacing: t, modelSize: i, onMeasurementsChange: a, reverseOrder: c = false, displayUnit: u = "mm", useInnerSurface: s = false, formMeasurements: l, originY: o }) => {
1525
- const f = Ie(/* @__PURE__ */ new Map()), y = e.geometry, p = kn(y), x = de(() => {
1526
- const m = [];
1527
- if (c) for (let b = n; b >= r; b -= t) m.push(b);
1528
- else for (let b = r; b <= n; b += t) m.push(b);
1529
- return m;
1530
- }, [
1531
- r,
1532
- n,
1533
- t,
1534
- c
1535
- ]);
1536
- Se(() => {
1537
- f.current.clear();
1538
- }, [
1539
- x
1540
- ]);
1541
- const g = [
1542
- "#5B9BD5"
1543
- ], w = i * un, v = Fe((m) => {
1544
- f.current.set(m.yPosition, m);
1545
- const b = Array.from(f.current.values()).sort((S, C) => c ? C.yPosition - S.yPosition : S.yPosition - C.yPosition);
1546
- a == null ? void 0 : a(b);
1547
- }, [
1548
- a,
1549
- c
1550
- ]);
1551
- return p ? d(He, {
1552
- children: x.map((m, b) => d(Vn, {
1553
- bvh: p,
1554
- geometry: y,
1555
- yPosition: m,
1556
- color: o != null && Math.abs(m - o) < t * 0.5 ? "#44ff44" : g[b % g.length],
1557
- labelX: w,
1558
- onDataChange: v,
1559
- displayUnit: u,
1560
- useInnerSurface: s,
1561
- formValue: l == null ? void 0 : l[b],
1562
- lineWidth: o != null && Math.abs(m - o) < t * 0.5 ? 4 : 1.5
1563
- }, m))
1564
- }) : null;
1565
- }, On = ({ mesh: e, greenY: r, modelSize: n, displayUnit: t = "mm" }) => {
1566
- var _a;
1567
- const i = e.geometry;
1568
- i.computeBoundingBox();
1569
- const a = ((_a = i.boundingBox) == null ? void 0 : _a.min.y) ?? 0, c = r - a, u = n * 0.4, s = n * 0.03, l = Ie(null);
1570
- Pt(({ camera: v }) => {
1571
- if (!l.current) return;
1572
- const m = new h();
1573
- v.getWorldDirection(m);
1574
- const b = new h(m.x, 0, m.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
- l.current.position.set(S.x * u, 0, S.z * u);
1579
- const C = v.position.x - l.current.position.x, M = v.position.z - l.current.position.z;
1580
- l.current.rotation.y = Math.atan2(C, M);
1581
- });
1582
- const o = new h(0, r, 0), f = new h(0, a, 0), y = new h(0, (r + a) / 2, 0), p = new h(-s, r, 0), x = new h(s, r, 0), g = new h(-s, a, 0), w = new h(s, a, 0);
1583
- return W("group", {
1584
- ref: l,
1585
- children: [
1586
- d(ge, {
1587
- points: [
1588
- o,
1589
- f
1590
- ],
1591
- color: "#888888",
1592
- lineWidth: 1.5,
1593
- depthTest: false
1594
- }),
1595
- d(ge, {
1596
- points: [
1597
- p,
1598
- x
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: r, isCut: n, mesh: t, viewMode: i, sliceY: a, landmarkCount: c = 0 }) => {
1644
- const { set: u, size: s, camera: l, invalidate: o } = on(), f = Ie(false), y = Ie(r), p = Ie(n), x = Ie(i), g = Ie(new h()), w = Ie(null), v = Ie(c), m = Fe(() => {
1645
- if (!t || e <= 0) return;
1646
- const S = t.geometry;
1647
- S.computeBoundingBox();
1648
- const C = S.boundingBox, M = new h();
1649
- C.getCenter(M);
1650
- const P = new h();
1651
- C.getSize(P), g.current.copy(P);
1652
- const L = s.width / s.height, H = Math.max(P.y, P.x / L) * 1.2, O = H * L, $ = 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
- s,
1660
- u
1661
- ]), b = Fe((S) => {
1662
- const C = S.position.clone(), M = C.length(), P = Math.atan2(C.x, C.z), L = Math.acos(C.y / M), O = P + 0.02;
1663
- S.position.set(M * Math.sin(L) * Math.sin(O), M * Math.cos(L), M * Math.sin(L) * Math.cos(O)), S.lookAt(0, 0, 0), S.updateMatrixWorld(true), o();
1664
- }, [
1665
- o
1666
- ]);
1667
- return Se(() => {
1668
- if (e > 0 && !f.current && !r) {
1669
- f.current = true;
1670
- const S = new J.PerspectiveCamera(50, s.width / s.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
- s,
1678
- u,
1679
- r,
1680
- b
1681
- ]), Se(() => {
1682
- const S = v.current;
1683
- v.current = c, S === 0 && c === 1 && !r && requestAnimationFrame(() => b(l));
1684
- }, [
1685
- c,
1686
- r,
1687
- l,
1688
- b
1689
- ]), Se(() => {
1690
- y.current === r && p.current === n || (y.current = r, p.current = n, r && i === "3D" && m());
1691
- }, [
1692
- r,
1693
- n,
1694
- i,
1695
- m
1696
- ]), Se(() => {
1697
- if (x.current === i) return;
1698
- const S = x.current;
1699
- if (x.current = i, !(!r || !t || e <= 0)) if (i === "2D" && a != null) {
1700
- w.current = l;
1701
- const C = t.geometry, M = C.getAttribute("position"), P = M.array, L = 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(P[B * 3 + 1] - a) < L) {
1704
- const T = P[B * 3], E = P[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
- C.computeBoundingBox();
1709
- const B = C.boundingBox;
1710
- H = B.min.x, O = B.max.x, $ = B.min.z, R = B.max.z;
1711
- }
1712
- const j = (H + O) / 2, ne = ($ + R) / 2, oe = s.width / s.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(j, a + e * 2, ne), V.up.set(0, 0, -1), V.lookAt(j, a, ne), u({
1717
- camera: V
1718
- });
1719
- } else S === "2D" && (w.current ? (u({
1720
- camera: w.current
1721
- }), w.current = null) : m());
1722
- }, [
1723
- i,
1724
- a,
1725
- r,
1726
- t,
1727
- e,
1728
- s,
1729
- u,
1730
- l,
1731
- m
1732
- ]), Se(() => {
1733
- if (!r || !l || !l.isOrthographicCamera) return;
1734
- const S = l;
1735
- if (i === "2D") {
1736
- if (!t || a == null) return;
1737
- const C = t.geometry, M = C.getAttribute("position"), P = M.array, L = 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(P[z * 3 + 1] - a) < L) {
1740
- const F = P[z * 3], V = P[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
- C.computeBoundingBox();
1745
- const z = C.boundingBox;
1746
- H = z.min.x, O = z.max.x, $ = z.min.z, R = z.max.z;
1747
- }
1748
- const j = s.width / s.height, ne = 1.4, oe = (O - H) * ne, le = (R - $) * ne;
1749
- let ee, D;
1750
- oe / le > j ? (ee = oe, D = oe / j) : (D = le, ee = le * j), S.left = -ee / 2, S.right = ee / 2, S.top = D / 2, S.bottom = -D / 2;
1751
- } else {
1752
- const C = g.current, M = s.width / s.height, P = Math.max(C.y, C.x / M) * 1.2, L = P * M;
1753
- S.left = -L / 2, S.right = L / 2, S.top = P / 2, S.bottom = -P / 2;
1754
- }
1755
- S.updateProjectionMatrix();
1756
- }, [
1757
- s.width,
1758
- s.height,
1759
- r,
1760
- l,
1761
- i,
1762
- t
1763
- ]), null;
1764
- }, jn = ({ mesh: e, isDragging: r }) => {
1765
- var _a;
1766
- const n = e.geometry;
1767
- n.computeBoundingBox();
1768
- const t = new h();
1769
- return (_a = n.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: !r,
1777
- target: [
1778
- t.x,
1779
- t.y,
1780
- t.z
1781
- ]
1782
- });
1783
- }, Nn = ({ wasAutoScaled: e, onDismiss: r }) => 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: r,
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: r }) => 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: r,
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: r, accentColor: n = "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, i) => {
1875
- const a = t.number < r, c = t.number === r;
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 ? n : "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
- i < 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: r, originY: n, modelSize: t, meshColor: i = "#c8c8c8", displayUnit: a = "mm" }) => {
1930
- const c = e.geometry, u = de(() => new $e(c, {
1931
- maxLeafTris: Ye
1932
- }), [
1933
- c
1934
- ]), s = de(() => Ze(u, c, n), [
1935
- u,
1936
- c,
1937
- n
1938
- ]), l = de(() => new it(new h(0, -1, 0), r), [
1939
- r
1940
- ]), { mlLine: o, apLine: f, mlWidth: y, apWidth: p } = de(() => {
1941
- let w = null, v = null, m = 0, b = 0;
1942
- if (s.linePoints.length >= 2) {
1943
- let S = s.linePoints[0], C = s.linePoints[0], M = s.linePoints[0], P = s.linePoints[0];
1944
- for (const L of s.linePoints) L.x < S.x && (S = L), L.x > C.x && (C = L), L.z < M.z && (M = L), L.z > P.z && (P = L);
1945
- w = [
1946
- new h(S.x, n, S.z),
1947
- new h(C.x, n, C.z)
1948
- ], v = [
1949
- new h(M.x, n, M.z),
1950
- new h(P.x, n, P.z)
1951
- ], m = w[0].distanceTo(w[1]), b = v[0].distanceTo(v[1]);
1952
- }
1953
- return {
1954
- mlLine: w,
1955
- apLine: v,
1956
- mlWidth: m,
1957
- apWidth: b
1958
- };
1959
- }, [
1960
- s,
1961
- n
1962
- ]), x = (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: i,
1969
- side: J.DoubleSide,
1970
- transparent: true,
1971
- opacity: 0.15,
1972
- depthWrite: false,
1973
- clippingPlanes: [
1974
- l
1975
- ]
1976
- })
1977
- }),
1978
- s.linePoints.length >= 2 && d(ge, {
1979
- points: s.linePoints,
1980
- color: "#00ff00",
1981
- lineWidth: 3,
1982
- depthTest: false,
1983
- depthWrite: false,
1984
- transparent: true
1985
- }),
1986
- o && W(He, {
1987
- children: [
1988
- d(ge, {
1989
- points: o,
1990
- color: "#ff8800",
1991
- lineWidth: 2,
1992
- depthTest: false,
1993
- depthWrite: false,
1994
- transparent: true
1995
- }),
1996
- d(Ke, {
1997
- position: [
1998
- o[0].x,
1999
- n,
2000
- o[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
- x(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
- n,
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
- x(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 r = e.getAttribute("position"), n = r.count, t = new h();
2092
- for (let g = 0; g < n; g++) t.x += r.getX(g), t.y += r.getY(g), t.z += r.getZ(g);
2093
- t.divideScalar(n);
2094
- let i = 0, a = 0, c = 0, u = 0, s = 0, l = 0;
2095
- for (let g = 0; g < n; g++) {
2096
- const w = r.getX(g) - t.x, v = r.getY(g) - t.y, m = r.getZ(g) - t.z;
2097
- i += w * w, a += w * v, c += w * m, u += v * v, s += v * m, l += m * m;
2098
- }
2099
- i /= n, a /= n, c /= n, u /= n, s /= n, l /= n;
2100
- const o = [], f = [], y = [
2101
- [
2102
- i,
2103
- a,
2104
- c
2105
- ],
2106
- [
2107
- a,
2108
- u,
2109
- s
2110
- ],
2111
- [
2112
- c,
2113
- s,
2114
- l
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(), v = 0;
2119
- for (let m = 0; m < 100; m++) {
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, C = y[2][0] * w.x + y[2][1] * w.y + y[2][2] * w.z, M = new h(b, S, C);
2121
- if (v = M.length(), v < 1e-12) break;
2122
- if (M.divideScalar(v), w.distanceTo(M) < 1e-10) {
2123
- w = M;
2124
- break;
2125
- }
2126
- w = M;
2127
- }
2128
- o.push(w.clone()), f.push(v);
2129
- for (let m = 0; m < 3; m++) for (let b = 0; b < 3; b++) {
2130
- const S = [
2131
- w.x,
2132
- w.y,
2133
- w.z
2134
- ][m], C = [
2135
- w.x,
2136
- w.y,
2137
- w.z
2138
- ][b];
2139
- y[m][b] -= v * S * C;
2140
- }
2141
- }
2142
- const p = new h();
2143
- for (let g = 0; g < n; g++) p.x += r.getX(g), p.y += r.getY(g), p.z += r.getZ(g);
2144
- p.divideScalar(n);
2145
- const x = [
2146
- 0,
2147
- 0,
2148
- 0
2149
- ];
2150
- for (let g = 0; g < 3; g++) {
2151
- let w = 1 / 0, v = -1 / 0;
2152
- const m = o[g];
2153
- for (let b = 0; b < n; b++) {
2154
- const S = r.getX(b) - p.x, C = r.getY(b) - p.y, M = r.getZ(b) - p.z, P = S * m.x + C * m.y + M * m.z;
2155
- P < w && (w = P), P > v && (v = P);
2156
- }
2157
- x[g] = (v - w) / 2;
2158
- }
2159
- return {
2160
- axes: o,
2161
- eigenvalues: f,
2162
- center: p,
2163
- halfExtents: x
2164
- };
2165
- }
2166
- function Kn({ pca: e }) {
2167
- return d("group", {
2168
- children: e.axes.map((r, n) => {
2169
- const t = e.center.clone().addScaledVector(r, e.halfExtents[n]), i = e.center.clone().addScaledVector(r, -e.halfExtents[n]);
2170
- return d(ge, {
2171
- points: [
2172
- i,
2173
- t
2174
- ],
2175
- color: Zn[n],
2176
- lineWidth: 2
2177
- }, n);
2178
- })
2179
- });
2180
- }
2181
- function Un({ pca: e }) {
2182
- const r = de(() => {
2183
- const { center: n, axes: t, halfExtents: i } = e, a = [];
2184
- for (let u = -1; u <= 1; u += 2) for (let s = -1; s <= 1; s += 2) for (let l = -1; l <= 1; l += 2) a.push(n.clone().addScaledVector(t[0], u * i[0]).addScaledVector(t[1], s * i[1]).addScaledVector(t[2], l * i[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, s]) => [
2235
- a[u],
2236
- a[s]
2237
- ]);
2238
- }, [
2239
- e
2240
- ]);
2241
- return d("group", {
2242
- children: r.map((n, t) => d(ge, {
2243
- points: n,
2244
- color: "#ffaa00",
2245
- lineWidth: 1,
2246
- transparent: true,
2247
- opacity: 0.5
2248
- }, t))
2249
- });
2250
- }
2251
- function Qn({ redPoint: e, greenPoint: r }) {
2252
- const n = de(() => new h().subVectors(r, e).normalize(), [
2253
- e,
2254
- r
2255
- ]), t = de(() => {
2256
- const a = n.dot(new h(0, 1, 0));
2257
- return Math.acos(Math.min(1, Math.abs(a))) * 180 / Math.PI;
2258
- }, [
2259
- n
2260
- ]), i = t < 1 ? "#44ff44" : t < 5 ? "#ffcc00" : "#ff4444";
2261
- return W("group", {
2262
- children: [
2263
- d(ge, {
2264
- points: [
2265
- e,
2266
- r
2267
- ],
2268
- color: i,
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: r,
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: r, greenY: n, modelSize: t }) {
2305
- const a = t * 0.15, c = de(() => {
2306
- const u = [];
2307
- let s = n - 10;
2308
- const l = new h(0, 1, 0);
2309
- for (; s > r; ) {
2310
- const o = Math.min(s, n), f = Math.max(s, n), y = rt(e, o, f);
2311
- if (y) {
2312
- const p = y.dot(l), x = Math.acos(Math.min(1, Math.abs(p))) * 180 / Math.PI;
2313
- u.push({
2314
- axis: y,
2315
- regionMin: o,
2316
- regionMax: f,
2317
- angleDeg: x
2318
- });
2319
- }
2320
- s -= 10;
2321
- }
2322
- return u;
2323
- }, [
2324
- e,
2325
- r,
2326
- n
2327
- ]);
2328
- return d("group", {
2329
- children: c.map((u, s) => {
2330
- const l = (u.regionMin + u.regionMax) / 2, o = new h(0, l, 0), f = o.clone().addScaledVector(u.axis, a), y = o.clone().addScaledVector(u.axis, -a), p = s / Math.max(1, c.length - 1), x = 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: x,
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: x,
2349
- lineWidth: 0.5,
2350
- transparent: true,
2351
- opacity: 0.3
2352
- })
2353
- ]
2354
- }, s);
2355
- })
2356
- });
2357
- }
2358
- function Jn({ geometry: e, redY: r, greenY: n, modelSize: t }) {
2359
- const i = de(() => {
2360
- const f = rt(e, r, n);
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
- r,
2370
- n
2371
- ]);
2372
- if (!i) return null;
2373
- const a = (r + n) / 2, c = new h(0, a, 0), u = t * 0.4, s = c.clone().addScaledVector(i.axis, u), l = c.clone().addScaledVector(i.axis, -u), o = i.angleDeg < 0.5 ? "#00ffff" : i.angleDeg < 2 ? "#ffcc00" : "#ff6600";
2374
- return d("group", {
2375
- children: d(ge, {
2376
- points: [
2377
- l,
2378
- s
2379
- ],
2380
- color: o,
2381
- lineWidth: 3,
2382
- dashed: true,
2383
- dashSize: 3,
2384
- gapSize: 2
2385
- })
2386
- });
2387
- }
2388
- function eo({ pca: e, modelSize: r }) {
2389
- const n = e.axes[0], t = r * 0.6, i = e.center.clone().addScaledVector(n, t), a = e.center.clone().addScaledVector(n, -t);
2390
- return d(ge, {
2391
- points: [
2392
- a,
2393
- i
2394
- ],
2395
- color: "#ff8800",
2396
- lineWidth: 2,
2397
- dashed: true,
2398
- dashSize: 3,
2399
- gapSize: 2
2400
- });
2401
- }
2402
- function to({ geometry: e, redY: r, greenY: n, modelSize: t }) {
2403
- const i = de(() => {
2404
- const l = ot(e), o = new h(0, 1, 0), f = 5;
2405
- e.computeBoundingBox();
2406
- const y = e.boundingBox.max.y, p = [];
2407
- for (let C = r + f; C < y; C += f) {
2408
- const M = pt(l, e, new h(0, C, 0), o);
2409
- M > 0 && p.push({
2410
- y: C,
2411
- circ: M
2412
- });
2413
- }
2414
- if (p.length < 5) return null;
2415
- const x = n - r, g = r + x * 0.3, w = r + x * 0.7, v = p.filter((C) => C.y >= g && C.y <= w);
2416
- if (v.length < 3) return null;
2417
- const m = v.map((C) => C.circ).sort((C, M) => C - M), b = m[Math.floor(m.length / 2)], S = Math.max(...p.map((C) => C.circ));
2418
- return {
2419
- circumferences: p,
2420
- baseline: b,
2421
- maxCirc: S
2422
- };
2423
- }, [
2424
- e,
2425
- r,
2426
- n
2427
- ]);
2428
- if (!i) return null;
2429
- const { circumferences: a, baseline: c, maxCirc: u } = i, s = t * 0.3 / u;
2430
- return W("group", {
2431
- children: [
2432
- a.map(({ y: l, circ: o }, f) => {
2433
- const y = o / c, p = y > 1.6 ? "#ff4444" : y > 1.3 ? "#ffcc00" : "#22cc66", x = o * s;
2434
- return d(ge, {
2435
- points: [
2436
- new h(-x, l, 0),
2437
- new h(x, l, 0)
2438
- ],
2439
- color: p,
2440
- lineWidth: 1.5,
2441
- transparent: true,
2442
- opacity: 0.6
2443
- }, f);
2444
- }),
2445
- (() => {
2446
- const l = c * 1.6 * s, o = a[0].y, f = a[a.length - 1].y;
2447
- return W(He, {
2448
- children: [
2449
- d(ge, {
2450
- points: [
2451
- new h(-l, o, 0),
2452
- new h(-l, 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(l, o, 0),
2465
- new h(l, 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((r, n) => {
2484
- const t = e.colors[n] ?? "#888888", i = n === e.innerIdx;
2485
- r.computeBoundingBox();
2486
- const a = new h();
2487
- return r.boundingBox.getCenter(a), W("group", {
2488
- children: [
2489
- d("mesh", {
2490
- geometry: r,
2491
- renderOrder: i ? 2 : 1,
2492
- children: d("meshStandardMaterial", {
2493
- color: t,
2494
- transparent: true,
2495
- opacity: i ? 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: r,
2505
- renderOrder: i ? 2 : 1,
2506
- children: d("meshBasicMaterial", {
2507
- color: t,
2508
- wireframe: true,
2509
- transparent: true,
2510
- opacity: i ? 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: i ? 700 : 400
2534
- },
2535
- children: e.labels[n]
2536
- })
2537
- })
2538
- })
2539
- })
2540
- ]
2541
- }, n);
2542
- })
2543
- });
2544
- }
2545
- function oo({ mesh: e, layers: r, landmarkPoints: n, componentDebug: t }) {
2546
- const i = e.geometry, a = de(() => i.getAttribute("position") ? Ot(i) : null, [
2547
- i
2548
- ]), c = de(() => !n || n.length < 2 ? null : {
2549
- red: new h(n[0].position.x, n[0].position.y, n[0].position.z),
2550
- green: new h(n[1].position.x, n[1].position.y, n[1].position.z)
2551
- }, [
2552
- n
2553
- ]);
2554
- return W("group", {
2555
- children: [
2556
- r.pcaAxes && a && d(Kn, {
2557
- pca: a
2558
- }),
2559
- r.obb && a && d(Un, {
2560
- pca: a
2561
- }),
2562
- r.obbAxis && a && d(eo, {
2563
- pca: a,
2564
- modelSize: a.halfExtents[0] ? Math.max(...a.halfExtents) * 2 : 100
2565
- }),
2566
- r.shellComponents && t && d(no, {
2567
- componentDebug: t
2568
- }),
2569
- r.circumferenceScan && c && d(to, {
2570
- geometry: i,
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
- r.landmarkAxis && c && d(Qn, {
2576
- redPoint: c.red,
2577
- greenPoint: c.green
2578
- }),
2579
- r.iterativePCA && c && d(qn, {
2580
- geometry: i,
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
- r.fullRegionPCA && c && d(Jn, {
2586
- geometry: i,
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 r = e.geometry, n = de(() => {
2596
- if (!r.getAttribute("position")) return null;
2597
- const a = Ot(r), 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
- r
2605
- ]);
2606
- if (!n) return null;
2607
- const t = n.center.clone().addScaledVector(n.axis, n.halfLen), i = n.center.clone().addScaledVector(n.axis, -n.halfLen);
2608
- return d(ge, {
2609
- points: [
2610
- i,
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: r }) {
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((n) => 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: n
2718
- }),
2719
- $t.filter((t) => t.group === n).map(({ key: t, label: i, 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: () => r(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: i
2755
- })
2756
- ]
2757
- }, t))
2758
- ]
2759
- }, n))
2760
- ]
2761
- });
2762
- }
2763
- const lo = ({ config: e, spacingType: r, scanUrl: n, formMeasurements: t, onComplete: i, isDebugUser: a = false, onAnalyticsEvent: c, wasmModule: u }) => {
2764
- const [s, l] = Q(null), [o, f] = Q(0), [y, p] = Q(false), [x, g] = Q(false), [w, v] = Q(""), [m, b] = Q("3D"), [S, C] = Q(r === "AK" ? 2 : 1), [M, P] = Q(false), [L, H] = Q(null), [O, $] = Q(null), [R, Y] = Q(r ?? null), [j, ne] = Q("mm"), [oe, le] = Q(false), [ee, D] = Q(""), [z, F] = Q(false), [V, B] = Q(false), [T, E] = Q(false), [N, X] = Q(false), [q, ie] = Q(false), [se, A] = Q([]), [I, k] = Q(null), [G, U] = Q(null), [re, Le] = Q(null), [me, ae] = Q(null), [xe, Re] = Q(false), [pe, we] = Q(Xn), [he, Ge] = Q(false), [fe, je] = Q(null), [Pe, ye] = Q("obj"), [Te, Me] = Q(false), [Ae, De] = Q({}), [ze, Ee] = Q(t), [ke, Ue] = Q(true), [mt] = Q("#c8c8c8"), [Nt] = 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: Pe,
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
- l(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), v("Processing file...");
2821
- try {
2822
- let te;
2823
- if (Z) if (v("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, v) : null;
2840
- if (ve) e.showAmputationModal && !r ? (H(ve), P(true)) : (Qe(ve.geometry, ve.wasScaled), ve.innerShellExtracted && (X(true), E(true)), ve.componentDebug && $(ve.componentDebug));
2841
- else {
2842
- v("Using fallback loader...");
2843
- const Ce = wn(te);
2844
- Ce ? e.showAmputationModal && !r ? (H({
2845
- geometry: Ce,
2846
- wasScaled: false,
2847
- innerShellExtracted: false
2848
- }), P(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), v("");
2854
- }
2855
- }, [
2856
- Xe,
2857
- e.showAmputationModal,
2858
- r,
2859
- Qe
2860
- ]);
2861
- Se(() => {
2862
- if (!n || !Xe) return;
2863
- (async () => {
2864
- g(true), v("Downloading scan...");
2865
- try {
2866
- const K = await fetch(n);
2867
- if (!K.ok) throw new Error(`Failed to download scan: ${K.status}`);
2868
- const Z = new URL(n).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), v("");
2878
- }
2879
- })();
2880
- }, [
2881
- n,
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), v("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), v("");
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(_), C(_ === "AK" ? 2 : 1), P(false), L && (Qe(L.geometry, L.wasScaled), L.innerShellExtracted && (X(true), E(true)), L.componentDebug && $(L.componentDebug), H(null)), c == null ? void 0 : c("file_loaded", {
2917
- spacing_type: _,
2918
- file_format: Pe,
2919
- is_double_wall: (L == null ? void 0 : L.innerShellExtracted) ?? false
2920
- });
2921
- }, [
2922
- L,
2923
- Qe,
2924
- c,
2925
- Pe
2926
- ]), Qt = Fe(() => {
2927
- !s || ce.length < 2 || (le(true), D("Please wait..."), setTimeout(() => {
2928
- In(s, 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: Le,
2937
- setAdjustedStartY: k,
2938
- setAdjustedEndY: U,
2939
- setError: ae,
2940
- setDoubleShell: (_) => {
2941
- E(_), ie(true);
2942
- },
2943
- setClippedReferenceGeometry: je,
2944
- skipDoubleShellDetection: N
2945
- }), ct.current = false, le(false);
2946
- }, 50));
2947
- }, [
2948
- s,
2949
- ce,
2950
- bt,
2951
- wt,
2952
- xt,
2953
- yt,
2954
- St,
2955
- at,
2956
- N
2957
- ]), qt = Fe(() => {
2958
- if (!i || !s || 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 = s.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
- i({
2974
- spacingType: R,
2975
- sourceUnit: "mm",
2976
- fileFormat: Pe,
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: n
2986
- });
2987
- }, [
2988
- i,
2989
- s,
2990
- se,
2991
- R,
2992
- ce,
2993
- Pe,
2994
- T,
2995
- ze,
2996
- n
2997
- ]), Jt = be ? 4 : s ? 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 && !s && !x && 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 && !s && !x && !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
- s && !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
- s && !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
- x && d(At, {
3221
- message: w || "Processing mesh..."
3222
- }),
3223
- oe && d(At, {
3224
- message: ee
3225
- }),
3226
- me && d(Ln, {
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
- P(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: s ? "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
- s && m === "3D" && d(Pn, {
3438
- mesh: s,
3439
- maxPoints: 2,
3440
- meshColor: mt,
3441
- meshOpacity: xe ? 0.3 : Nt
3442
- }),
3443
- he && fe && m === "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
- s && m === "3D" && d(Tn, {
3458
- modelSize: o,
3459
- labels: [
3460
- "Origin",
3461
- R === "AK" ? "IT/Perineum" : "MPT",
3462
- "Cut Plane"
3463
- ]
3464
- }),
3465
- d($n, {
3466
- modelSize: o,
3467
- isAligned: be,
3468
- isCut: Gt,
3469
- mesh: s,
3470
- viewMode: m,
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 && s && m === "3D" && d(jn, {
3478
- mesh: s,
3479
- isDragging: false
3480
- }),
3481
- s && be && ce.length >= 3 && (() => {
3482
- const K = s.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 m === "2D" ? d(Gn, {
3486
- mesh: s,
3487
- upperY: te,
3488
- originY: Z.position.y,
3489
- modelSize: o,
3490
- meshColor: mt,
3491
- displayUnit: j
3492
- }) : W(He, {
3493
- children: [
3494
- d(_n, {
3495
- mesh: s,
3496
- startY: Be,
3497
- endY: te,
3498
- spacing: at,
3499
- modelSize: o,
3500
- onMeasurementsChange: A,
3501
- reverseOrder: true,
3502
- displayUnit: j,
3503
- useInnerSurface: T && !N,
3504
- formMeasurements: ke ? ze : void 0,
3505
- originY: Z.position.y
3506
- }),
3507
- (!T || N) && d(On, {
3508
- mesh: s,
3509
- greenY: Z.position.y,
3510
- modelSize: o,
3511
- displayUnit: j
3512
- })
3513
- ]
3514
- });
3515
- })(),
3516
- s && be && m === "3D" && d(so, {
3517
- mesh: s
3518
- }),
3519
- s && e.showDebug && xe && m === "3D" && d(oo, {
3520
- mesh: s,
3521
- modelSize: o,
3522
- layers: pe,
3523
- landmarkPoints: ce,
3524
- componentDebug: O
3525
- })
3526
- ]
3527
- }),
3528
- s && (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 && s && m === "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: m === "3D" ? 600 : 400,
3606
- backgroundColor: m === "3D" ? "rgb(12, 67, 173)" : "#fff",
3607
- color: m === "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: m === "2D" ? 600 : 400,
3620
- backgroundColor: m === "2D" ? "rgb(12, 67, 173)" : "#fff",
3621
- color: m === "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: j === "mm" ? 600 : 400,
3646
- backgroundColor: j === "mm" ? "rgb(12, 67, 173)" : "#fff",
3647
- color: j === "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: j === "inch" ? 600 : 400,
3660
- backgroundColor: j === "inch" ? "rgb(12, 67, 173)" : "#fff",
3661
- color: j === "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 && m === "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: () => C(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: () => C(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
- m === "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
- m === "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
- s && V && d(Nn, {
3783
- wasAutoScaled: z,
3784
- onDismiss: () => B(false)
3785
- }),
3786
- s && 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
- s && !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
- s && !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
- jt = function(e) {
4031
- const r = e === "AK" ? 2 : 1, n = [];
4032
- for (let t = 2; t >= 1; t -= r) n.push(`${t}_above`);
4033
- n.push("at_ref");
4034
- for (let t = r; t <= 9; t += r) n.push(`${t}_below`);
4035
- return n;
4036
- };
4037
- dt = function(e, r) {
4038
- const n = jt(r), t = {};
4039
- for (let i = 0; i < Math.min(e.length, n.length); i++) {
4040
- const a = e[i];
4041
- a != null && !isNaN(a) && (t[n[i]] = a);
4042
- }
4043
- return t;
4044
- };
4045
- ao = function(e, r) {
4046
- if (!e) return;
4047
- const t = jt(r).map((i) => {
4048
- const a = e[i];
4049
- return a ?? void 0;
4050
- });
4051
- if (!t.every((i) => i == null)) return t;
4052
- };
4053
- bo = ({ request: e, onComplete: r, wasmModule: n }) => {
4054
- const [t, i] = Q(null), [a, c] = Q(n !== void 0);
4055
- Se(() => {
4056
- if (n !== void 0) {
4057
- c(true);
4058
- return;
4059
- }
4060
- let o = false;
4061
- return import("./galileo_core_geo-DFVJmkI7.js").then(async (f) => {
4062
- await f.default(), o || (i(f), c(true));
4063
- }).catch(() => {
4064
- o || c(true);
4065
- }), () => {
4066
- o = true;
4067
- };
4068
- }, [
4069
- n
4070
- ]);
4071
- const u = n !== void 0 ? n : t, s = de(() => ao(e.form_measurements, e.spacing_type), [
4072
- e.form_measurements,
4073
- e.spacing_type
4074
- ]), l = (o) => {
4075
- const f = o.scanMeasurements.map((w) => +(w.modifiedValue ?? w.originalValue).toFixed(1)), y = dt(f, e.spacing_type);
4076
- let p, x;
4077
- if (o.formMeasurements) {
4078
- p = dt(o.formMeasurements, e.spacing_type);
4079
- const w = o.scanMeasurements.map((v, m) => {
4080
- var _a;
4081
- const b = (_a = o.formMeasurements) == null ? void 0 : _a[m];
4082
- return b == null || isNaN(b) ? null : +((v.modifiedValue ?? v.originalValue) - b).toFixed(1);
4083
- });
4084
- x = dt(w, e.spacing_type);
4085
- }
4086
- const g = {
4087
- spacing_type: e.spacing_type,
4088
- source_unit: "mm",
4089
- file_format: o.fileFormat,
4090
- measurement_source: o.formMeasurements ? "form_provided" : "scan_derived",
4091
- is_double_wall: o.isDoubleWall,
4092
- is_unit_converted: false,
4093
- form_measurements: p,
4094
- scan_measurements: y,
4095
- measurement_variance: x,
4096
- scan_url: e.scan_url,
4097
- frontal_height: +o.frontalHeight.toFixed(1),
4098
- transverse_ml: +o.transverseML.toFixed(1),
4099
- transverse_ap: +o.transverseAP.toFixed(1)
4100
- };
4101
- console.log("[GirthManagerWidget] WidgetResponse:", JSON.stringify(g, null, 2)), r == null ? void 0 : r(g);
4102
- };
4103
- return a ? d("div", {
4104
- style: {
4105
- width: "100%",
4106
- height: "100%",
4107
- display: "flex"
4108
- },
4109
- children: d(lo, {
4110
- config: fn,
4111
- spacingType: e.spacing_type,
4112
- scanUrl: e.scan_url,
4113
- formMeasurements: s,
4114
- onComplete: l,
4115
- wasmModule: u
4116
- })
4117
- }) : d("div", {
4118
- style: {
4119
- width: "100%",
4120
- height: "100%",
4121
- display: "flex",
4122
- alignItems: "center",
4123
- justifyContent: "center"
4124
- },
4125
- children: d("span", {
4126
- children: "Initializing..."
4127
- })
4128
- });
4129
- };
4130
- })();
4131
- export {
4132
- bo as G,
4133
- __tla,
4134
- dt as a,
4135
- ao as c,
4136
- jt as g
4137
- };