@solid-labs/fab-one-widget 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/dist/GirthManagerWidget-DizbUvPi.js +2280 -0
  2. package/dist/GirthManagerWidget-DizbUvPi.js.map +1 -0
  3. package/dist/girth-manager-ui/src/GirthManagerCore.d.ts +37 -0
  4. package/dist/girth-manager-ui/src/components/AlignedOrbitControls.d.ts +5 -0
  5. package/dist/girth-manager-ui/src/components/CameraFit.d.ts +11 -0
  6. package/dist/girth-manager-ui/src/components/CircumferenceMeasurements.d.ts +16 -0
  7. package/dist/girth-manager-ui/src/components/CircumferenceSlice.d.ts +16 -0
  8. package/dist/girth-manager-ui/src/components/ClickableMesh.d.ts +8 -0
  9. package/dist/girth-manager-ui/src/components/DebugOverlays.d.ts +31 -0
  10. package/dist/girth-manager-ui/src/components/DebugPanel.d.ts +6 -0
  11. package/dist/girth-manager-ui/src/components/DraggableLineHandle.d.ts +16 -0
  12. package/dist/girth-manager-ui/src/components/ErrorDisplay.d.ts +4 -0
  13. package/dist/girth-manager-ui/src/components/LandmarkMarkers.d.ts +5 -0
  14. package/dist/girth-manager-ui/src/components/LoadingSpinner.d.ts +3 -0
  15. package/dist/girth-manager-ui/src/components/ScaleNotice.d.ts +5 -0
  16. package/dist/girth-manager-ui/src/components/ShellNotice.d.ts +5 -0
  17. package/dist/girth-manager-ui/src/components/Stepper.d.ts +10 -0
  18. package/dist/girth-manager-ui/src/components/TransverseView.d.ts +10 -0
  19. package/dist/girth-manager-ui/src/components/VerticalDimension.d.ts +8 -0
  20. package/dist/girth-manager-ui/src/config.d.ts +29 -0
  21. package/dist/girth-manager-ui/src/hooks/useCachedBVH.d.ts +3 -0
  22. package/dist/girth-manager-ui/src/index.d.ts +38 -0
  23. package/dist/girth-manager-ui/src/processing/alignment.d.ts +4 -0
  24. package/dist/girth-manager-ui/src/processing/constants.d.ts +7 -0
  25. package/dist/girth-manager-ui/src/processing/cut-plane.d.ts +13 -0
  26. package/dist/girth-manager-ui/src/processing/mesh-ops.d.ts +33 -0
  27. package/dist/girth-manager-ui/src/processing/pipeline.d.ts +46 -0
  28. package/dist/girth-manager-ui/src/processing/slice.d.ts +14 -0
  29. package/dist/girth-manager-ui/src/processing/stl-convert.d.ts +2 -0
  30. package/dist/girth-manager-ui/src/processing/types.d.ts +43 -0
  31. package/dist/girth-manager-ui/src/processing/validation.d.ts +6 -0
  32. package/dist/girth-manager-ui/src/processing/vertex-colors.d.ts +8 -0
  33. package/dist/girth-manager-ui/src/processing/wasm-loader.d.ts +23 -0
  34. package/dist/{store.d.ts → girth-manager-ui/src/store.d.ts} +1 -14
  35. package/dist/girth-manager-web-widget/src/GirthManagerWidget.d.ts +13 -0
  36. package/dist/girth-manager-web-widget/src/dev-harness.d.ts +1 -0
  37. package/dist/girth-manager-web-widget/src/index.d.ts +4 -0
  38. package/dist/girth-manager-web-widget/src/types.d.ts +76 -0
  39. package/dist/girth-manager-web-widget/src/web-component.d.ts +34 -0
  40. package/dist/index.js +7 -0
  41. package/dist/index.js.map +1 -0
  42. package/dist/web-component.js +78 -0
  43. package/dist/web-component.js.map +1 -0
  44. package/package.json +36 -26
  45. package/dist/FabOneWidget.d.ts +0 -21
  46. package/dist/fab-one-widget.js +0 -4733
  47. package/dist/index.d.ts +0 -2
  48. package/dist/protosthetics_geo-BcQYS-wX.js +0 -1
  49. package/dist/register.d.ts +0 -2
@@ -0,0 +1,2280 @@
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 Ce, useRef as Ie } from "react";
3
+ import { useFrame as Lt, useThree as on, Canvas as sn } from "@react-three/fiber";
4
+ import { Html as Ke, Line as ge, OrbitControls as Dt } from "@react-three/drei";
5
+ import * as J from "three";
6
+ import { Plane as it, Vector3 as h, Box3 as Tt, Line3 as ht, Quaternion as Oe, Matrix4 as kt } from "three";
7
+ import { create as rn } from "zustand";
8
+ import { OBJLoader as ln } from "three/examples/jsm/loaders/OBJLoader.js";
9
+ import { STLLoader as an } from "three/examples/jsm/loaders/STLLoader.js";
10
+ import { MeshBVH as $e } from "three-mesh-bvh";
11
+ const cn = {
12
+ showDragDrop: true,
13
+ showStartOver: true,
14
+ showInsertMeasurement: true,
15
+ showDebug: true,
16
+ showSpacingToggle: true,
17
+ showAmputationModal: true,
18
+ showNavigation: true,
19
+ showToolbar: true
20
+ }, fn = {
21
+ showDragDrop: false,
22
+ showStartOver: false,
23
+ showInsertMeasurement: false,
24
+ showDebug: false,
25
+ showSpacingToggle: false,
26
+ showAmputationModal: false,
27
+ showNavigation: false,
28
+ showToolbar: false
29
+ }, dn = tn(cn), gt = rn((e, s) => ({
30
+ landmarkPoints: [],
31
+ isAligned: false,
32
+ isCut: false,
33
+ addLandmarkPoint: (n) => e((t) => t.landmarkPoints.length >= 3 ? t : { landmarkPoints: [...t.landmarkPoints, n] }),
34
+ removeLandmarkPoint: (n) => e((t) => ({
35
+ landmarkPoints: t.landmarkPoints.filter((i, a) => a !== n)
36
+ })),
37
+ clearLandmarkPoints: () => e({ landmarkPoints: [], isAligned: false, isCut: false }),
38
+ updateLandmarkPositions: (n) => e((t) => ({
39
+ landmarkPoints: t.landmarkPoints.map((i, a) => ({
40
+ ...i,
41
+ position: n[a] ?? i.position
42
+ }))
43
+ })),
44
+ setAligned: (n) => e({ isAligned: n }),
45
+ setCut: (n) => e({ isCut: n }),
46
+ isSelectionComplete: () => s().landmarkPoints.length === 3
47
+ })), un = 0.45, Ye = 3, ut = 1e-3, We = 25.4, pn = 5, hn = [0.25, -0.25, 0.5, -0.5];
48
+ function gn(e) {
49
+ const s = e.split(`
50
+ `), n = [], t = [];
51
+ let i = false;
52
+ for (const a of s)
53
+ if (a.startsWith("v ")) {
54
+ const c = a.trim().split(/\s+/);
55
+ if (c.length >= 7) {
56
+ n.push(parseFloat(c[1]), parseFloat(c[2]), parseFloat(c[3]));
57
+ let u = parseFloat(c[4]), o = parseFloat(c[5]), l = parseFloat(c[6]);
58
+ (u > 1 || o > 1 || l > 1) && (u /= 255, o /= 255, l /= 255), t.push(u, o, l), i = true;
59
+ } else c.length >= 4 && (n.push(parseFloat(c[1]), parseFloat(c[2]), parseFloat(c[3])), t.push(0, 0, 0));
60
+ }
61
+ return i ? { positions: new Float32Array(n), colors: new Float32Array(t) } : null;
62
+ }
63
+ function mn(e, s, n, t) {
64
+ const i = e.getAttribute("position"), a = i.count, c = new Float32Array(a * 3), u = s.length / 3;
65
+ let o = 1 / 0, l = 1 / 0, r = 1 / 0, f = -1 / 0, y = -1 / 0, p = -1 / 0;
66
+ for (let b = 0; b < u; b++) {
67
+ const w = s[b * 3] * t, C = s[b * 3 + 1] * t, M = s[b * 3 + 2] * t;
68
+ w < o && (o = w), w > f && (f = w), C < l && (l = C), C > y && (y = C), M < r && (r = M), M > p && (p = M);
69
+ }
70
+ const m = Math.min(128, Math.max(16, Math.round(Math.cbrt(u)))), g = (f - o + 1e-6) / m, z = (y - l + 1e-6) / m, v = (p - r + 1e-6) / m, x = /* @__PURE__ */ new Map();
71
+ for (let b = 0; b < u; b++) {
72
+ const w = Math.min(m - 1, Math.floor((s[b * 3] * t - o) / g)), C = Math.min(m - 1, Math.floor((s[b * 3 + 1] * t - l) / z)), M = Math.min(m - 1, Math.floor((s[b * 3 + 2] * t - r) / v)), L = w * m * m + C * m + M;
73
+ let P = x.get(L);
74
+ P || (P = [], x.set(L, P)), P.push(b);
75
+ }
76
+ for (let b = 0; b < a; b++) {
77
+ const w = i.getX(b), C = i.getY(b), M = i.getZ(b), L = Math.min(m - 1, Math.max(0, Math.floor((w - o) / g))), P = Math.min(m - 1, Math.max(0, Math.floor((C - l) / z))), H = Math.min(m - 1, Math.max(0, Math.floor((M - r) / v)));
78
+ let O = 1 / 0, $ = 0;
79
+ for (let R = 0; R <= m && O > 0; R++) {
80
+ for (let Y = -R; Y <= R; Y++)
81
+ for (let N = -R; N <= R; N++)
82
+ for (let ne = -R; ne <= R; ne++) {
83
+ if (R > 0 && Math.abs(Y) < R && Math.abs(N) < R && Math.abs(ne) < R) continue;
84
+ const oe = L + Y, le = P + N, ee = H + ne;
85
+ if (oe < 0 || oe >= m || le < 0 || le >= m || ee < 0 || ee >= m) continue;
86
+ const D = x.get(oe * m * m + le * m + ee);
87
+ if (D)
88
+ for (const S of D) {
89
+ const F = s[S * 3] * t, V = s[S * 3 + 1] * t, B = s[S * 3 + 2] * t, T = (w - F) ** 2 + (C - V) ** 2 + (M - B) ** 2;
90
+ T < O && (O = T, $ = S);
91
+ }
92
+ }
93
+ if (O < 1 / 0) break;
94
+ }
95
+ c[b * 3] = n[$ * 3], c[b * 3 + 1] = n[$ * 3 + 1], c[b * 3 + 2] = n[$ * 3 + 2];
96
+ }
97
+ e.setAttribute("color", new J.Float32BufferAttribute(c, 3));
98
+ }
99
+ const xn = 30, zt = [
100
+ "#4488ff",
101
+ // 0 = largest (outer shell) — blue
102
+ "#ff4444",
103
+ // 1 = second largest (inner shell) — red
104
+ "#44cc44",
105
+ // 2 = third (floor/platform) — green
106
+ "#ffaa00",
107
+ // 3 — orange
108
+ "#cc44ff",
109
+ // 4 — purple
110
+ "#44ffcc"
111
+ // 5 — teal
112
+ ];
113
+ function yn(e, s) {
114
+ const n = e.getVertices(), t = e.getFaces(), i = e.getComponentLabels(), a = /* @__PURE__ */ new Map();
115
+ for (let r = 0; r < i.length; r++) {
116
+ const f = i[r];
117
+ a.has(f) || a.set(f, []), a.get(f).push(r);
118
+ }
119
+ const c = [...a.keys()].sort((r, f) => r - f), u = [], o = [], l = [];
120
+ for (const r of c) {
121
+ const f = a.get(r), y = /* @__PURE__ */ new Map(), p = [], m = [];
122
+ for (const x of f)
123
+ for (let b = 0; b < 3; b++) {
124
+ const w = t[x * 3 + b];
125
+ if (!y.has(w)) {
126
+ const C = p.length / 3;
127
+ p.push(n[w * 3], n[w * 3 + 1], n[w * 3 + 2]), y.set(w, C);
128
+ }
129
+ m.push(y.get(w));
130
+ }
131
+ const g = new J.BufferGeometry();
132
+ g.setAttribute("position", new J.Float32BufferAttribute(p, 3)), g.setIndex(m), g.computeVertexNormals(), u.push(g);
133
+ const v = r === s ? `#${r} inner` : r === 0 ? `#${r} outer` : `#${r} (${f.length} faces)`;
134
+ o.push(v), l.push(zt[r % zt.length]);
135
+ }
136
+ return { geometries: u, labels: o, colors: l, innerIdx: s };
137
+ }
138
+ async function bn(e, s, n) {
139
+ let t = null;
140
+ try {
141
+ const i = gn(e);
142
+ n == null ? void 0 : n("Loading mesh..."), t = new s.WasmMeshSet(), t.loadObjString(e), n == null ? void 0 : n("Detecting units...");
143
+ const a = t.autoScaleToMm(pn);
144
+ n == null ? void 0 : n("Merging close vertices..."), t.applyMergeCloseVertices(1e-4), n == null ? void 0 : n("Analyzing mesh components...");
145
+ let c = false, u = null;
146
+ if (t.getComponentCount() >= 2) {
147
+ n == null ? void 0 : n("Building component debug info...");
148
+ const y = yn(t, null);
149
+ 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);
150
+ } else
151
+ n == null ? void 0 : n("Removing floating artifacts..."), t.splitAndKeepLargest();
152
+ n == null ? void 0 : n("Closing holes..."), t.applyCloseHoles(30), t.applyMergeCloseVertices(1e-4), n == null ? void 0 : n("Extracting geometry...");
153
+ const l = t.getVertices(), r = t.getFaces();
154
+ if (l.length === 0) return null;
155
+ const f = new J.BufferGeometry();
156
+ if (f.setAttribute("position", new J.Float32BufferAttribute(l, 3)), f.setIndex(Array.from(r)), f.computeVertexNormals(), i) {
157
+ const y = a ? 1e3 : 1;
158
+ mn(f, i.positions, i.colors, y);
159
+ }
160
+ return { geometry: f, wasScaled: a, innerShellExtracted: c, componentDebug: u };
161
+ } catch (i) {
162
+ return console.error("WASM processing failed:", i), null;
163
+ } finally {
164
+ if (t) try {
165
+ t.free();
166
+ } catch {
167
+ }
168
+ }
169
+ }
170
+ function wn(e) {
171
+ const n = new ln().parse(e);
172
+ let t = null;
173
+ return n.traverse((i) => {
174
+ i.isMesh && !t && (t = i.geometry);
175
+ }), t;
176
+ }
177
+ async function ft(e) {
178
+ const s = await e.arrayBuffer(), i = new an().parse(s).getAttribute("position");
179
+ if (!i || i.count === 0) throw new Error("Empty STL geometry");
180
+ const a = [];
181
+ for (let c = 0; c < i.count; c++)
182
+ a.push(`v ${i.getX(c)} ${i.getY(c)} ${i.getZ(c)}`);
183
+ for (let c = 0; c < i.count; c += 3)
184
+ a.push(`f ${c + 1} ${c + 2} ${c + 3}`);
185
+ return a.join(`
186
+ `);
187
+ }
188
+ function Bt(e, s) {
189
+ const n = 1 / s;
190
+ return `${Math.round(e.x * n)}_${Math.round(e.y * n)}_${Math.round(e.z * n)}`;
191
+ }
192
+ function Rt(e, s) {
193
+ if (!e.length) return [];
194
+ const n = [];
195
+ for (const t of e)
196
+ (n.length === 0 || n[n.length - 1].distanceTo(t) > s) && n.push(t.clone());
197
+ return n.length > 2 && n[0].distanceTo(n[n.length - 1]) > s && n.push(n[0].clone()), n;
198
+ }
199
+ function je(e) {
200
+ let s = 0;
201
+ for (let n = 0; n < e.length - 1; n++) s += e[n].distanceTo(e[n + 1]);
202
+ return s;
203
+ }
204
+ function Et(e, s = 1e-3, n = false) {
205
+ if (!e.length) return [];
206
+ const t = /* @__PURE__ */ new Map(), i = (l) => {
207
+ const r = Bt(l, s);
208
+ let f = t.get(r);
209
+ return f || (f = l.clone(), t.set(r, f)), f;
210
+ }, a = e.map((l) => ({ a: i(l.a), b: i(l.b) })), c = [];
211
+ for (; a.length; ) {
212
+ const l = a.pop(), r = [l.a, l.b];
213
+ let f = true;
214
+ for (; f; ) {
215
+ f = false;
216
+ for (let p = a.length - 1; p >= 0; p--) {
217
+ const { a: m, b: g } = a[p];
218
+ if (m.equals(r[r.length - 1]))
219
+ r.push(g);
220
+ else if (g.equals(r[r.length - 1]))
221
+ r.push(m);
222
+ else if (m.equals(r[0]))
223
+ r.unshift(g);
224
+ else if (g.equals(r[0]))
225
+ r.unshift(m);
226
+ else continue;
227
+ a.splice(p, 1), f = true;
228
+ }
229
+ }
230
+ const y = Rt(r, s);
231
+ y.length > 1 && c.push(y);
232
+ }
233
+ if (!c.length) return [];
234
+ if (c.sort((l, r) => je(r) - je(l)), !n) return c[0] ?? [];
235
+ const u = je(c[0]), o = c.filter((l) => je(l) >= u * 0.3);
236
+ return o[o.length - 1] ?? c[0];
237
+ }
238
+ function Ct(e, s, n, t = false) {
239
+ const i = new it(new h(0, 1, 0), -n), a = [], c = new Tt();
240
+ c.setFromBufferAttribute(s.getAttribute("position"));
241
+ const u = { linePoints: [], lineLength: 0, rightmostPoint: new h(0, n, 0) };
242
+ if (!i.intersectsBox(c)) return u;
243
+ const o = new ht(), l = new h();
244
+ e.shapecast({
245
+ intersectsBounds: (g) => i.intersectsBox(g),
246
+ intersectsTriangle: (g) => {
247
+ const z = [];
248
+ o.set(g.a, g.b), i.intersectLine(o, l) && z.push(l.clone()), o.set(g.b, g.c), i.intersectLine(o, l) && z.push(l.clone()), o.set(g.c, g.a), i.intersectLine(o, l) && z.push(l.clone()), z.length === 2 && a.push({ a: z[0], b: z[1] });
249
+ }
250
+ });
251
+ const r = Et(a, ut, t), f = je(r);
252
+ if (r.length < 2) return u;
253
+ let y = -1 / 0, p = new h(0, n, 0);
254
+ for (const g of r)
255
+ g.x > y && (y = g.x, p = g.clone());
256
+ const m = r.length > 2 && r[0].distanceTo(r[r.length - 1]) < ut * 10;
257
+ return { linePoints: r, lineLength: f, rightmostPoint: p, isClosed: m };
258
+ }
259
+ function Ze(e, s, n, t = false) {
260
+ const i = Ct(e, s, n, t);
261
+ if (i.isClosed && i.linePoints.length >= 3) return i;
262
+ console.warn(`[slice] y=${n.toFixed(2)} failed (pts=${i.linePoints.length}, closed=${i.isClosed}), retrying...`);
263
+ let a = i;
264
+ for (const c of hn) {
265
+ const u = Ct(e, s, n + c, t);
266
+ if (u.isClosed && u.linePoints.length >= 3)
267
+ 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;
268
+ u.linePoints.length > a.linePoints.length && (a = u);
269
+ }
270
+ return console.warn(`[slice] y=${n.toFixed(2)} all retries exhausted (pts=${a.linePoints.length}, closed=${a.isClosed})`), a;
271
+ }
272
+ function pt(e, s, n, t) {
273
+ const i = new it().setFromNormalAndCoplanarPoint(t.clone().normalize(), n), a = new Tt();
274
+ if (a.setFromBufferAttribute(s.getAttribute("position")), !i.intersectsBox(a)) return 0;
275
+ const c = [], u = new ht(), o = new h();
276
+ e.shapecast({
277
+ intersectsBounds: (r) => i.intersectsBox(r),
278
+ intersectsTriangle: (r) => {
279
+ const f = [];
280
+ u.set(r.a, r.b), i.intersectLine(u, o) && f.push(o.clone()), u.set(r.b, r.c), i.intersectLine(u, o) && f.push(o.clone()), u.set(r.c, r.a), i.intersectLine(u, o) && f.push(o.clone()), f.length === 2 && c.push({ a: f[0], b: f[1] });
281
+ }
282
+ });
283
+ const l = Et(c, ut);
284
+ return je(l);
285
+ }
286
+ function ot(e) {
287
+ return new $e(e, { maxLeafTris: Ye });
288
+ }
289
+ function vt(e, s, n) {
290
+ const t = e instanceof $e ? e : new $e(e, { maxLeafTris: Ye }), i = new it().setFromNormalAndCoplanarPoint(n.clone().normalize(), s), a = [], c = new ht(), u = new h();
291
+ return t.shapecast({
292
+ intersectsBounds: (o) => i.intersectsBox(o),
293
+ intersectsTriangle: (o) => {
294
+ const l = [];
295
+ c.set(o.a, o.b), i.intersectLine(c, u) && l.push(u.clone()), c.set(o.b, o.c), i.intersectLine(c, u) && l.push(u.clone()), c.set(o.c, o.a), i.intersectLine(c, u) && l.push(u.clone()), l.length === 2 && a.push({ a: l[0], b: l[1] });
296
+ }
297
+ }), a;
298
+ }
299
+ function Mt(e, s, n = 1e-3) {
300
+ if (!e.length) return [];
301
+ const t = /* @__PURE__ */ new Map(), i = (l) => {
302
+ const r = Bt(l, n);
303
+ let f = t.get(r);
304
+ return f || (f = l.clone(), t.set(r, f)), f;
305
+ }, a = e.map((l) => ({ a: i(l.a), b: i(l.b) })), c = [];
306
+ for (; a.length; ) {
307
+ const l = a.pop(), r = [l.a, l.b];
308
+ let f = true;
309
+ for (; f; ) {
310
+ f = false;
311
+ for (let p = a.length - 1; p >= 0; p--) {
312
+ const { a: m, b: g } = a[p];
313
+ if (m.equals(r[r.length - 1]))
314
+ r.push(g);
315
+ else if (g.equals(r[r.length - 1]))
316
+ r.push(m);
317
+ else if (m.equals(r[0]))
318
+ r.unshift(g);
319
+ else if (g.equals(r[0]))
320
+ r.unshift(m);
321
+ else continue;
322
+ a.splice(p, 1), f = true;
323
+ }
324
+ }
325
+ const y = Rt(r, n);
326
+ y.length > 1 && c.push(y);
327
+ }
328
+ if (!c.length) return [];
329
+ let u = [], o = 1 / 0;
330
+ for (const l of c) {
331
+ if (l.length < 3 || !(l[0].distanceTo(l[l.length - 1]) < 2)) continue;
332
+ const f = new h();
333
+ for (const p of l) f.add(p);
334
+ f.divideScalar(l.length);
335
+ const y = f.distanceTo(s);
336
+ y < o && (o = y, u = l);
337
+ }
338
+ if (u.length === 0)
339
+ for (const l of c) {
340
+ if (l.length < 3) continue;
341
+ const r = new h();
342
+ for (const y of l) r.add(y);
343
+ r.divideScalar(l.length);
344
+ const f = r.distanceTo(s);
345
+ f < o && (o = f, u = l);
346
+ }
347
+ return u;
348
+ }
349
+ function Sn(e) {
350
+ const s = new h();
351
+ for (const n of e) s.add(n);
352
+ return s.divideScalar(e.length);
353
+ }
354
+ function zn(e, s, n) {
355
+ const t = new $e(e, { maxLeafTris: Ye }), i = new h().subVectors(s, n).normalize(), c = s.distanceTo(n) * 0.05;
356
+ let u = i.clone();
357
+ const o = (v) => {
358
+ const x = [];
359
+ for (let $ = -10; $ <= 0; $++) {
360
+ const R = s.clone().addScaledVector(v, $ * c), Y = vt(t, R, v), N = Mt(Y, R, 1);
361
+ N.length >= 3 && N[0].distanceTo(N[N.length - 1]) < 1 && x.push(Sn(N));
362
+ }
363
+ if (x.length < 3) return null;
364
+ const b = new h();
365
+ for (const $ of x) b.add($);
366
+ b.divideScalar(x.length);
367
+ let w = 0, C = 0, M = 0, L = 0, P = 0, H = 0;
368
+ for (const $ of x) {
369
+ const R = $.x - b.x, Y = $.y - b.y, N = $.z - b.z;
370
+ w += R * R, C += R * Y, M += R * N, L += Y * Y, P += Y * N, H += N * N;
371
+ }
372
+ let O = v.clone();
373
+ for (let $ = 0; $ < 30; $++) {
374
+ const R = w * O.x + C * O.y + M * O.z, Y = C * O.x + L * O.y + P * O.z, N = M * O.x + P * O.y + H * O.z, ne = new h(R, Y, N), oe = ne.length();
375
+ if (oe < 1e-10 || (ne.divideScalar(oe), O.distanceTo(ne) < 1e-8)) break;
376
+ O = ne;
377
+ }
378
+ return O.dot(i) < 0 && O.negate(), O;
379
+ };
380
+ for (let v = 0; v < 3; v++) {
381
+ const x = o(u);
382
+ if (!x) break;
383
+ const b = u.angleTo(x);
384
+ if (u = x, b < 1e-3) break;
385
+ }
386
+ const l = new h();
387
+ Math.abs(u.x) < 0.9 ? l.set(1, 0, 0) : l.set(0, 1, 0), l.crossVectors(u, l).normalize();
388
+ const r = new h().crossVectors(u, l).normalize(), f = (v) => {
389
+ const x = vt(t, s, v), b = Mt(x, s, 1);
390
+ if (b.length < 3) return { circumference: 1 / 0, closed: false };
391
+ const w = b[0].distanceTo(b[b.length - 1]) < 1;
392
+ return { circumference: je(b), closed: w };
393
+ };
394
+ let y = u.clone(), p = 1 / 0;
395
+ for (let v = -3; v <= 3; v += 1)
396
+ for (let x = -3; x <= 3; x += 1) {
397
+ const b = v * Math.PI / 180, w = x * Math.PI / 180, C = u.clone().applyQuaternion(new Oe().setFromAxisAngle(l, b)).applyQuaternion(new Oe().setFromAxisAngle(r, w)).normalize(), M = f(C);
398
+ M.closed && M.circumference < p && (p = M.circumference, y = C);
399
+ }
400
+ const m = y.clone(), g = new h();
401
+ Math.abs(m.x) < 0.9 ? g.set(1, 0, 0) : g.set(0, 1, 0), g.crossVectors(m, g).normalize();
402
+ const z = new h().crossVectors(m, g).normalize();
403
+ for (let v = -5; v <= 5; v += 1)
404
+ for (let x = -5; x <= 5; x += 1) {
405
+ const b = v * 0.1 * Math.PI / 180, w = x * 0.1 * Math.PI / 180, C = m.clone().applyQuaternion(new Oe().setFromAxisAngle(g, b)).applyQuaternion(new Oe().setFromAxisAngle(z, w)).normalize(), M = f(C);
406
+ M.closed && M.circumference < p && (p = M.circumference, y = C);
407
+ }
408
+ return p === 1 / 0 && (p = f(u).circumference, y = u), { normal: y, circumference: p };
409
+ }
410
+ function Cn(e, s, n) {
411
+ const t = e.getAttribute("position"), i = e.getIndex();
412
+ if (!i) return { isDoubleShell: false, sampledFaces: 0, opposingPairs: 0, confidence: 0 };
413
+ const a = i.array, c = t.array, u = new h().subVectors(n, s).normalize(), o = n.distanceTo(s), l = Math.min(o * 0.06, 15), r = new $e(e, { maxLeafTris: Ye });
414
+ let f = new h(1, 0, 0);
415
+ Math.abs(u.dot(f)) > 0.9 && (f = new h(0, 1, 0)), f.sub(u.clone().multiplyScalar(u.dot(f))).normalize();
416
+ const y = new h().crossVectors(u, f).normalize(), p = 12, m = new h();
417
+ let g = 0, z = 0, v = 0;
418
+ for (const w of [0.65, 0.78, 0.9]) {
419
+ const C = new h().lerpVectors(s, n, w);
420
+ let M = 0, L = 0, P = 0, H = 0;
421
+ for (let Y = 0; Y < a.length; Y += 3) {
422
+ const N = a[Y], ne = a[Y + 1], oe = a[Y + 2], le = (c[N * 3] + c[ne * 3] + c[oe * 3]) / 3, ee = (c[N * 3 + 1] + c[ne * 3 + 1] + c[oe * 3 + 1]) / 3, D = (c[N * 3 + 2] + c[ne * 3 + 2] + c[oe * 3 + 2]) / 3, S = le - C.x, F = ee - C.y, V = D - C.z;
423
+ Math.abs(S * u.x + F * u.y + V * u.z) > l || (M += le, L += ee, P += D, H++);
424
+ }
425
+ if (H < 8) continue;
426
+ const O = new h(M / H, L / H, P / H);
427
+ let $ = 0;
428
+ for (let Y = 0; Y < p; Y++) {
429
+ const N = Y / p * Math.PI * 2, ne = new h().addScaledVector(f, Math.cos(N)).addScaledVector(y, Math.sin(N)), oe = new J.Ray(O, ne);
430
+ let le = 0;
431
+ r.shapecast({
432
+ intersectsBounds: (ee) => oe.intersectsBox(ee),
433
+ intersectsTriangle: (ee) => (oe.intersectTriangle(ee.a, ee.b, ee.c, false, m) && le++, false)
434
+ }), $ += le, z++;
435
+ }
436
+ g += $, $ / p > 1.5 && v++;
437
+ }
438
+ if (z === 0) return { isDoubleShell: false, sampledFaces: 0, opposingPairs: 0, confidence: 0 };
439
+ const x = g / z;
440
+ return {
441
+ isDoubleShell: v >= 2,
442
+ sampledFaces: z,
443
+ opposingPairs: g,
444
+ confidence: x
445
+ };
446
+ }
447
+ function vn(e, s, n, t) {
448
+ const i = new h().subVectors(n, s), a = new h().subVectors(t, s), c = new h().subVectors(e, s), u = i.dot(i), o = i.dot(a), l = i.dot(c), r = a.dot(a), f = a.dot(c), y = 1 / (u * r - o * o), p = (r * l - o * f) * y, m = (u * f - o * l) * y;
449
+ return { u: 1 - p - m, v: p, w: m };
450
+ }
451
+ function st(e, s, n, t, i = false) {
452
+ const a = n.clone().normalize(), c = e.getAttribute("position"), u = e.getIndex();
453
+ if (!u) throw new Error("No index buffer");
454
+ const o = new h().subVectors(t, s).dot(a), l = Math.abs(o) < 1e-6 ? 1 : Math.sign(o), r = c.array, f = u.array, y = e.getAttribute("color"), p = y ? y.array : null, m = [], g = [], z = [], v = (D, S, F) => {
455
+ const V = m.length / 3;
456
+ return m.push(D, S, F), V;
457
+ }, x = (D) => new h(r[D * 3], r[D * 3 + 1], r[D * 3 + 2]), b = (D, S) => {
458
+ const F = new h().subVectors(D, s).dot(a), V = new h().subVectors(S, s).dot(a), B = F / (F - V);
459
+ return new h().lerpVectors(D, S, B);
460
+ }, w = /* @__PURE__ */ new Map(), C = /* @__PURE__ */ new Map(), M = /* @__PURE__ */ new Map(), L = (D) => {
461
+ let S = M.get(D);
462
+ return S === void 0 && (S = new h().subVectors(x(D), s).dot(a), M.set(D, S)), S;
463
+ }, P = (D) => {
464
+ if (w.has(D)) return w.get(D);
465
+ const S = x(D), F = v(S.x, S.y, S.z);
466
+ return p && g.push(p[D * 3], p[D * 3 + 1], p[D * 3 + 2]), w.set(D, F), F;
467
+ }, H = (D, S) => {
468
+ const F = D < S ? `${D}_${S}` : `${S}_${D}`;
469
+ if (C.has(F)) return C.get(F);
470
+ const V = b(x(D), x(S)), B = v(V.x, V.y, V.z);
471
+ if (p) {
472
+ const T = L(D), E = L(S), j = T / (T - E);
473
+ g.push(
474
+ p[D * 3] + j * (p[S * 3] - p[D * 3]),
475
+ p[D * 3 + 1] + j * (p[S * 3 + 1] - p[D * 3 + 1]),
476
+ p[D * 3 + 2] + j * (p[S * 3 + 2] - p[D * 3 + 2])
477
+ );
478
+ }
479
+ return C.set(F, B), B;
480
+ }, O = (D) => {
481
+ const S = L(D);
482
+ return Math.sign(S) === l || Math.abs(S) < 1e-6;
483
+ };
484
+ for (let D = 0; D < f.length; D += 3) {
485
+ const S = f[D], F = f[D + 1], V = f[D + 2], B = O(S), T = O(F), E = O(V), j = (B ? 1 : 0) + (T ? 1 : 0) + (E ? 1 : 0);
486
+ if (j !== 0)
487
+ if (j === 3)
488
+ z.push(P(S), P(F), P(V));
489
+ else if (j === 1) {
490
+ let X, Q, ie;
491
+ B ? (X = S, Q = F, ie = V) : T ? (X = F, Q = V, ie = S) : (X = V, Q = S, ie = F), z.push(P(X), H(X, Q), H(X, ie));
492
+ } else {
493
+ let X, Q, ie;
494
+ B ? T ? (X = V, Q = S, ie = F) : (X = F, Q = V, ie = S) : (X = S, Q = F, ie = V);
495
+ const se = P(Q), A = P(ie), I = H(Q, X), k = H(ie, X);
496
+ z.push(se, I, A), z.push(A, I, k);
497
+ }
498
+ }
499
+ const $ = z.length / 3;
500
+ let R;
501
+ if (i)
502
+ R = Array.from({ length: $ }, (D, S) => S);
503
+ else {
504
+ const D = /* @__PURE__ */ new Map();
505
+ for (let T = 0; T < $; T++)
506
+ for (let E = 0; E < 3; E++) {
507
+ const j = z[T * 3 + E];
508
+ D.has(j) || D.set(j, []), D.get(j).push(T);
509
+ }
510
+ const S = /* @__PURE__ */ new Set(), F = [];
511
+ for (let T = 0; T < $; T++) {
512
+ if (S.has(T)) continue;
513
+ const E = [], j = [T];
514
+ for (S.add(T); j.length > 0; ) {
515
+ const X = j.shift();
516
+ E.push(X);
517
+ for (let Q = 0; Q < 3; Q++) {
518
+ const ie = z[X * 3 + Q];
519
+ for (const se of D.get(ie))
520
+ S.has(se) || (S.add(se), j.push(se));
521
+ }
522
+ }
523
+ F.push(E);
524
+ }
525
+ let V = F[0] || [], B = 1 / 0;
526
+ for (const T of F) {
527
+ let E = 1 / 0;
528
+ for (const j of T) {
529
+ for (let X = 0; X < 3; X++) {
530
+ const Q = z[j * 3 + X], ie = m[Q * 3] - t.x, se = m[Q * 3 + 1] - t.y, A = m[Q * 3 + 2] - t.z, I = ie * ie + se * se + A * A;
531
+ I < E && (E = I);
532
+ }
533
+ if (E < B) break;
534
+ }
535
+ E < B && (B = E, V = T);
536
+ }
537
+ R = V;
538
+ }
539
+ const Y = /* @__PURE__ */ new Map(), N = [], ne = [], oe = [];
540
+ let le = 0;
541
+ for (const D of R)
542
+ for (let S = 0; S < 3; S++) {
543
+ const F = z[D * 3 + S];
544
+ Y.has(F) || (N.push(m[F * 3], m[F * 3 + 1], m[F * 3 + 2]), p && ne.push(g[F * 3], g[F * 3 + 1], g[F * 3 + 2]), Y.set(F, le++)), oe.push(Y.get(F));
545
+ }
546
+ const ee = new J.BufferGeometry();
547
+ return ee.setAttribute("position", new J.Float32BufferAttribute(N, 3)), p && ne.length > 0 && ee.setAttribute("color", new J.Float32BufferAttribute(ne, 3)), ee.setIndex(oe), ee.computeVertexNormals(), ee.computeBoundingBox(), ee;
548
+ }
549
+ function rt(e, s, n) {
550
+ const t = e.getAttribute("position"), i = n - s;
551
+ if (i < 1) return null;
552
+ const a = 30, c = i / a, u = [];
553
+ for (let z = 0; z < a; z++) {
554
+ const v = s + z * c, x = s + (z + 1) * c;
555
+ let b = 0, w = 0, C = 0, M = 0;
556
+ for (let L = 0; L < t.count; L++) {
557
+ const P = t.getY(L);
558
+ P >= v && P < x && (b += t.getX(L), w += P, C += t.getZ(L), M++);
559
+ }
560
+ M > 20 && u.push(new h(b / M, w / M, C / M));
561
+ }
562
+ if (u.length < 5) return null;
563
+ const o = new h();
564
+ for (const z of u) o.add(z);
565
+ o.divideScalar(u.length);
566
+ let l = 0, r = 0, f = 0, y = 0, p = 0, m = 0;
567
+ for (const z of u) {
568
+ const v = z.x - o.x, x = z.y - o.y, b = z.z - o.z;
569
+ l += v * v, r += v * x, f += v * b, y += x * x, p += x * b, m += b * b;
570
+ }
571
+ let g = new h(0.01, 1, 0.01).normalize();
572
+ for (let z = 0; z < 30; z++) {
573
+ const v = l * g.x + r * g.y + f * g.z, x = r * g.x + y * g.y + p * g.z, b = f * g.x + p * g.y + m * g.z, w = new h(v, x, b), C = w.length();
574
+ if (C < 1e-10 || (w.divideScalar(C), g.distanceTo(w) < 1e-8)) break;
575
+ g = w;
576
+ }
577
+ return g.y < 0 && g.negate(), g;
578
+ }
579
+ function Wt(e, s, n, t) {
580
+ const i = e.getIndex(), a = i ? i.count / 3 : 0;
581
+ if (a < 10) return { valid: false, reason: `Geometry is empty or degenerate (${a} faces)` };
582
+ const c = s - n;
583
+ if (c < 4) return { valid: false, reason: `Height too small (${c.toFixed(1)}mm < 4mm)` };
584
+ if (c > 1e3) return { valid: false, reason: `Height too large (${c.toFixed(1)}mm > 1000mm)` };
585
+ const u = new $e(e, { maxLeafTris: Ye }), o = Ze(u, e, s);
586
+ if (o.lineLength === 0) return { valid: false, reason: "No circumference at green point \u2014 mesh may be empty at that height" };
587
+ const l = s - t;
588
+ if (l <= n) return { valid: true, reason: "" };
589
+ const r = Ze(u, e, l);
590
+ if (o.lineLength > 0 && r.lineLength > 0) {
591
+ const y = o.lineLength / r.lineLength;
592
+ if (y < 0.5)
593
+ return { valid: false, reason: `First circumference is too small relative to second (ratio ${y.toFixed(2)} < 0.5) \u2014 possible trimmed angle` };
594
+ }
595
+ const f = s - t * 2;
596
+ if (f > n) {
597
+ const y = Ze(u, e, f);
598
+ if (r.lineLength > 0 && y.lineLength > 0) {
599
+ const p = r.lineLength / y.lineLength;
600
+ if (p < 0.5)
601
+ return { valid: false, reason: `Second circumference is too small relative to third (ratio ${p.toFixed(2)} < 0.5) \u2014 possible trimmed angle` };
602
+ }
603
+ }
604
+ return { valid: true, reason: "" };
605
+ }
606
+ const Mn = [
607
+ { nudge: 3, angle: 0, cutOffset: 5 },
608
+ { nudge: 5, angle: Math.PI * 2 / 3, cutOffset: 3 },
609
+ { nudge: 8, angle: Math.PI * 4 / 3, cutOffset: 4 },
610
+ { nudge: -5, angle: 0, cutOffset: 6 }
611
+ ], nt = 5;
612
+ function Vt(e, s, n, t) {
613
+ const i = new Oe().setFromAxisAngle(n, t);
614
+ return e.applyMatrix4(new kt().makeRotationFromQuaternion(i)), s.map((a) => a.clone().applyQuaternion(i));
615
+ }
616
+ function _t(e, s, n) {
617
+ const t = new Oe().setFromAxisAngle(s, n);
618
+ e.applyMatrix4(new kt().makeRotationFromQuaternion(t));
619
+ }
620
+ function An(e, s, n, t, i, a) {
621
+ const c = n.getAttribute("position"), u = n.getIndex();
622
+ if (!u) return s;
623
+ const l = s[1].y + t * We, r = c.array, f = u.array, y = n.getAttribute("color"), p = y ? y.array : null, m = [], g = [], z = [], v = (A, I, k) => {
624
+ const G = m.length / 3;
625
+ return m.push(A, I, k), G;
626
+ }, x = (A) => [r[A * 3], r[A * 3 + 1], r[A * 3 + 2]], b = (A, I) => {
627
+ const k = (l - A[1]) / (I[1] - A[1]);
628
+ return [A[0] + k * (I[0] - A[0]), l, A[2] + k * (I[2] - A[2])];
629
+ }, w = /* @__PURE__ */ new Map(), C = /* @__PURE__ */ new Map(), M = (A) => {
630
+ if (w.has(A)) return w.get(A);
631
+ const [I, k, G] = x(A), U = v(I, k, G);
632
+ return p && g.push(p[A * 3], p[A * 3 + 1], p[A * 3 + 2]), w.set(A, U), U;
633
+ }, L = (A, I) => {
634
+ const k = A < I ? `${A}_${I}` : `${I}_${A}`;
635
+ if (C.has(k)) return C.get(k);
636
+ const G = x(A), U = x(I), [re, Pe, me] = b(G, U), ae = v(re, Pe, me);
637
+ if (p) {
638
+ const xe = (l - G[1]) / (U[1] - G[1]);
639
+ g.push(
640
+ p[A * 3] + xe * (p[I * 3] - p[A * 3]),
641
+ p[A * 3 + 1] + xe * (p[I * 3 + 1] - p[A * 3 + 1]),
642
+ p[A * 3 + 2] + xe * (p[I * 3 + 2] - p[A * 3 + 2])
643
+ );
644
+ }
645
+ return C.set(k, ae), ae;
646
+ };
647
+ for (let A = 0; A < f.length; A += 3) {
648
+ const I = f[A], k = f[A + 1], G = f[A + 2], U = x(I), re = x(k), Pe = x(G), me = U[1] < l, ae = re[1] < l, xe = Pe[1] < l, Re = (me ? 1 : 0) + (ae ? 1 : 0) + (xe ? 1 : 0);
649
+ if (Re !== 0)
650
+ if (Re === 3)
651
+ z.push(M(I), M(k), M(G));
652
+ else if (Re === 1) {
653
+ let pe, we, he;
654
+ me ? (pe = I, we = k, he = G) : ae ? (pe = k, we = G, he = I) : (pe = G, we = I, he = k), z.push(M(pe), L(pe, we), L(pe, he));
655
+ } else {
656
+ let pe, we, he;
657
+ me ? ae ? (pe = G, we = I, he = k) : (pe = k, we = G, he = I) : (pe = I, we = k, he = G);
658
+ const Ge = M(we), fe = M(he), Ne = L(we, pe), Le = L(he, pe);
659
+ z.push(Ge, Ne, fe), z.push(fe, Ne, Le);
660
+ }
661
+ }
662
+ const P = z.length / 3, H = /* @__PURE__ */ new Map();
663
+ for (let A = 0; A < P; A++)
664
+ for (let I = 0; I < 3; I++) {
665
+ const k = z[A * 3 + I];
666
+ H.has(k) || H.set(k, []), H.get(k).push(A);
667
+ }
668
+ const O = /* @__PURE__ */ new Map();
669
+ for (let A = 0; A < P; A++) O.set(A, /* @__PURE__ */ new Set());
670
+ for (const [, A] of H)
671
+ for (const I of A) for (const k of A) I !== k && O.get(I).add(k);
672
+ const $ = /* @__PURE__ */ new Set(), R = [];
673
+ for (let A = 0; A < P; A++) {
674
+ if ($.has(A)) continue;
675
+ const I = [], k = [A];
676
+ for ($.add(A); k.length > 0; ) {
677
+ const G = k.shift();
678
+ I.push(G);
679
+ for (const U of O.get(G))
680
+ $.has(U) || ($.add(U), k.push(U));
681
+ }
682
+ R.push(I);
683
+ }
684
+ const Y = s[0];
685
+ let N = R[0] || [], ne = 1 / 0;
686
+ for (const A of R) {
687
+ let I = 1 / 0;
688
+ for (const k of A) {
689
+ for (let G = 0; G < 3; G++) {
690
+ const U = z[k * 3 + G], re = m[U * 3] - Y.x, Pe = m[U * 3 + 1] - Y.y, me = m[U * 3 + 2] - Y.z, ae = re * re + Pe * Pe + me * me;
691
+ ae < I && (I = ae);
692
+ }
693
+ if (I < ne) break;
694
+ }
695
+ I < ne && (ne = I, N = A);
696
+ }
697
+ const oe = /* @__PURE__ */ new Map(), le = [], ee = [], D = [];
698
+ let S = 0;
699
+ for (const A of N)
700
+ for (let I = 0; I < 3; I++) {
701
+ const k = z[A * 3 + I];
702
+ oe.has(k) || (le.push(m[k * 3], m[k * 3 + 1], m[k * 3 + 2]), p && ee.push(g[k * 3], g[k * 3 + 1], g[k * 3 + 2]), oe.set(k, S++)), D.push(oe.get(k));
703
+ }
704
+ const F = new J.BufferGeometry();
705
+ 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...");
706
+ const V = new h(0, 1, 0);
707
+ let B = [...s];
708
+ const T = (A, I) => {
709
+ B = Vt(F, B, A, I), a && _t(a, A, I);
710
+ };
711
+ for (let A = 0; A < 5; A++) {
712
+ const I = F.getAttribute("position"), k = Math.min(B[0].y, B[1].y), U = Math.max(B[0].y, B[1].y) - k;
713
+ if (U < 1) break;
714
+ const re = 30, Pe = U / re, me = [];
715
+ for (let ye = 0; ye < re; ye++) {
716
+ const Te = k + ye * Pe, Me = k + (ye + 1) * Pe;
717
+ let Ae = 0, De = 0, Se = 0, Ee = 0;
718
+ for (let ke = 0; ke < I.count; ke++) {
719
+ const Ue = I.getY(ke);
720
+ Ue >= Te && Ue < Me && (Ae += I.getX(ke), De += Ue, Se += I.getZ(ke), Ee++);
721
+ }
722
+ Ee > 20 && me.push(new h(Ae / Ee, De / Ee, Se / Ee));
723
+ }
724
+ if (me.length < 5) break;
725
+ const ae = new h();
726
+ for (const ye of me) ae.add(ye);
727
+ ae.divideScalar(me.length);
728
+ let xe = 0, Re = 0, pe = 0, we = 0, he = 0, Ge = 0;
729
+ for (const ye of me) {
730
+ const Te = ye.x - ae.x, Me = ye.y - ae.y, Ae = ye.z - ae.z;
731
+ xe += Te * Te, Re += Te * Me, pe += Te * Ae, we += Me * Me, he += Me * Ae, Ge += Ae * Ae;
732
+ }
733
+ let fe = new h(0.01, 1, 0.01).normalize();
734
+ for (let ye = 0; ye < 30; ye++) {
735
+ 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), Se = De.length();
736
+ if (Se < 1e-10 || (De.divideScalar(Se), fe.distanceTo(De) < 1e-8)) break;
737
+ fe = De;
738
+ }
739
+ fe.y < 0 && fe.negate();
740
+ const Ne = fe.dot(V);
741
+ if (Math.acos(Math.min(1, Math.abs(Ne))) * 180 / Math.PI < 0.1) break;
742
+ const Le = new h().crossVectors(fe, V);
743
+ Le.length() > 1e-4 && (Le.normalize(), T(Le, Math.acos(Math.min(1, Math.max(-1, Ne)))));
744
+ }
745
+ B[0].y > B[1].y && T(new h(1, 0, 0), Math.PI);
746
+ const E = B[0];
747
+ 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));
748
+ const X = B[1].y + 5 * We, Q = st(
749
+ F,
750
+ new h(0, X, 0),
751
+ new h(0, 1, 0),
752
+ B[0]
753
+ );
754
+ e.geometry.dispose(), e.geometry = Q, Q.computeVertexNormals(), Q.computeBoundingBox(), i.updateLandmarkPositions(B.map((A) => ({ x: A.x, y: A.y, z: A.z })));
755
+ const ie = Q.boundingBox, se = new h();
756
+ 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;
757
+ }
758
+ function Fn(e, s, n, t) {
759
+ const i = s.map((m) => new h(m.position.x, m.position.y, m.position.z)), a = i[0], c = i[1];
760
+ t.onStatus("Cutting double shell above green point...");
761
+ const u = c.y + 2 * We, o = new h(c.x, u, c.z), l = e.geometry, r = st(l, o, new h(0, 1, 0), a, true);
762
+ l.dispose(), e.geometry = r, r.computeVertexNormals(), r.computeBoundingBox(), t.onStatus("Setting blue point..."), t.addLandmarkPoint({
763
+ faceIndex: -1,
764
+ vertexIndices: [0, 1, 2],
765
+ position: { x: a.x, y: a.y, z: a.z },
766
+ barycentricCoords: { u: 0.33, v: 0.33, w: 0.34 }
767
+ }), i.push(a.clone()), t.updateLandmarkPositions(i.map((m) => ({ x: m.x, y: m.y, z: m.z }))), t.setAligned(true), t.setCut(true), t.setAdjustedStartY(null), t.setAdjustedEndY(null), t.setOriginalEndY(c.y);
768
+ const f = r.boundingBox, y = new h();
769
+ f.getSize(y), t.setModelSize(Math.max(y.x, y.y, y.z)), t.onStatus("Validating results...");
770
+ const p = Wt(r, c.y, a.y, n);
771
+ p.valid || console.warn(`Double shell validation warning: ${p.reason}`);
772
+ }
773
+ function In(e, s, n, t) {
774
+ var _a, _b;
775
+ const i = e.geometry.clone(), a = s.map((o) => ({ ...o })), c = new h(0, 1, 0);
776
+ if (t.skipDoubleShellDetection)
777
+ console.log("Skipping double-shell detection: inner shell already extracted");
778
+ else {
779
+ const o = new h(s[0].position.x, s[0].position.y, s[0].position.z), l = new h(s[1].position.x, s[1].position.y, s[1].position.z);
780
+ t.onStatus("Detecting shell type...");
781
+ const r = Cn(e.geometry, o, l);
782
+ if (console.log(`Shell detection: ${r.isDoubleShell ? "DOUBLE" : "SINGLE"} shell (${r.opposingPairs} inward/${r.sampledFaces} total faces, confidence ${(r.confidence * 100).toFixed(0)}%)`), r.isDoubleShell) {
783
+ (_a = t.setDoubleShell) == null ? void 0 : _a.call(t, true), Fn(e, a, n, t), t.setClippedReferenceGeometry ? (i.computeVertexNormals(), t.setClippedReferenceGeometry(i)) : i.dispose();
784
+ return;
785
+ }
786
+ (_b = t.setDoubleShell) == null ? void 0 : _b.call(t, false);
787
+ }
788
+ let u = "";
789
+ for (let o = 0; o < nt; o++)
790
+ try {
791
+ o > 0 && (t.onStatus(`Retry ${o}/${nt - 1} \u2014 ${u}`), e.geometry.dispose(), e.geometry = i.clone(), t.removeLandmarkPoint(2), t.setAligned(false), t.setCut(false));
792
+ let l = e.geometry, r = a.map((S) => new h(S.position.x, S.position.y, S.position.z));
793
+ const f = t.setClippedReferenceGeometry ? i.clone() : null;
794
+ let y = 5;
795
+ if (o > 0) {
796
+ const S = Mn[o - 1];
797
+ y = S.cutOffset;
798
+ const F = new h().subVectors(r[1], r[0]).normalize();
799
+ if (S.nudge < 0)
800
+ r[1].addScaledVector(F, S.nudge);
801
+ else {
802
+ const E = new h();
803
+ 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, S.angle), r[1].addScaledVector(E, S.nudge);
804
+ }
805
+ const V = l.getAttribute("position");
806
+ let B = 1 / 0, T = 0;
807
+ for (let E = 0; E < V.count; E++) {
808
+ const j = V.getX(E) - r[1].x, X = V.getY(E) - r[1].y, Q = V.getZ(E) - r[1].z, ie = j * j + X * X + Q * Q;
809
+ ie < B && (B = ie, T = E);
810
+ }
811
+ r[1].set(V.getX(T), V.getY(T), V.getZ(T)), console.log(`Retry ${o}: nudge=${S.nudge}mm angle=${(S.angle * 180 / Math.PI).toFixed(0)}\xB0 cutOffset=${S.cutOffset}" \u2192 green=(${r[1].x.toFixed(1)}, ${r[1].y.toFixed(1)}, ${r[1].z.toFixed(1)})`);
812
+ }
813
+ const p = (S, F) => {
814
+ r = Vt(l, r, S, F), f && _t(f, S, F);
815
+ }, m = r[0], g = r[1], { normal: z } = zn(l, g, m);
816
+ t.onStatus(o > 0 ? `Retry ${o}: Slicing mesh...` : "Slicing mesh at cut plane...");
817
+ const v = new h().subVectors(g, m).normalize(), x = Math.sign(v.dot(z)), b = g.clone().addScaledVector(z, x * y * We), w = st(l, b, z, m);
818
+ l.dispose(), l = w, e.geometry = l, t.onStatus(o > 0 ? `Retry ${o}: Rough alignment...` : "Rough alignment...");
819
+ const C = new h().subVectors(r[1], r[0]).normalize();
820
+ let M = C.dot(c), L = new h().crossVectors(C, c);
821
+ L.length() > 1e-4 && (L.normalize(), p(L, Math.acos(Math.min(1, Math.max(-1, M))))), r[0].y > r[1].y && p(new h(1, 0, 0), Math.PI), l.computeVertexNormals(), t.onStatus(o > 0 ? `Retry ${o}: Translating...` : "Translating to origin...");
822
+ const P = r[0].clone();
823
+ l.translate(-P.x, -P.y, -P.z), f && f.translate(-P.x, -P.y, -P.z), r = r.map((S) => new h(S.x - P.x, S.y - P.y, S.z - P.z)), t.onStatus(o > 0 ? `Retry ${o}: Isolating limb...` : "Isolating limb region...");
824
+ {
825
+ const S = ot(l), F = r[0].y, V = r[1].y, B = new h(0, 1, 0), T = 5;
826
+ l.computeBoundingBox();
827
+ const E = l.boundingBox.max.y, j = [];
828
+ for (let X = F + T; X < E; X += T) {
829
+ const Q = pt(S, l, new h(0, X, 0), B);
830
+ Q > 0 && j.push({ y: X, circ: Q });
831
+ }
832
+ if (j.length > 5) {
833
+ const X = V - F, Q = F + X * 0.3, ie = F + X * 0.7, se = j.filter((A) => A.y >= Q && A.y <= ie);
834
+ if (se.length >= 3) {
835
+ const A = se.map((U) => U.circ).sort((U, re) => U - re), I = A[Math.floor(A.length / 2)], k = 1.6;
836
+ let G = null;
837
+ for (const U of j)
838
+ if (!(U.y < V - T * 2) && U.circ > I * k) {
839
+ G = U.y - T;
840
+ break;
841
+ }
842
+ if (G === null) {
843
+ const U = j.find((re) => Math.abs(re.y - V) < T);
844
+ if (U && U.circ > I * k) {
845
+ for (let re = j.length - 1; re >= 0; re--)
846
+ if (!(j[re].y > V + T) && j[re].circ <= I * k) {
847
+ G = j[re].y + T;
848
+ break;
849
+ }
850
+ }
851
+ }
852
+ if (G !== null && G > F + X * 0.5) {
853
+ console.log(`Limb isolation: cutting at Y=${G.toFixed(1)}mm (baseline circ=${I.toFixed(1)}mm, threshold=${(I * k).toFixed(1)}mm)`);
854
+ const U = st(
855
+ l,
856
+ new h(0, G, 0),
857
+ B,
858
+ r[0]
859
+ // keep side with red point
860
+ );
861
+ l.dispose(), l = U, e.geometry = l, l.computeVertexNormals(), l.computeBoundingBox();
862
+ } else
863
+ console.log(`Limb isolation: no anomaly detected (baseline=${I.toFixed(1)}mm)`);
864
+ }
865
+ }
866
+ }
867
+ t.onStatus(o > 0 ? `Retry ${o}: PCA alignment...` : "Iterative PCA alignment...");
868
+ const H = 10, O = 80, $ = r[0].y, R = r[1].y;
869
+ let Y = R - H;
870
+ for (let S = 0; S < O; S++) {
871
+ const F = Math.min(Y, R), V = Math.max(Y, R), B = rt(l, F, V);
872
+ if (B && (M = B.dot(c), Math.acos(Math.min(1, Math.abs(M))) * 180 / Math.PI > 0.1 && (L = new h().crossVectors(B, c), L.length() > 1e-4))) {
873
+ L.normalize(), p(L, Math.acos(Math.min(1, Math.max(-1, M))));
874
+ const E = r[0].clone();
875
+ l.translate(-E.x, -E.y, -E.z), f && f.translate(-E.x, -E.y, -E.z), r = r.map((j) => new h(j.x - E.x, j.y - E.y, j.z - E.z));
876
+ }
877
+ if (Y -= H, Y <= $) break;
878
+ }
879
+ l.computeVertexNormals(), t.onStatus(o > 0 ? `Retry ${o}: Setting blue point...` : "Setting blue point...");
880
+ const N = new h(r[0].x, r[0].y, r[0].z);
881
+ r.push(N), t.addLandmarkPoint({
882
+ faceIndex: -1,
883
+ vertexIndices: [0, 1, 2],
884
+ position: { x: N.x, y: N.y, z: N.z },
885
+ barycentricCoords: { u: 0.33, v: 0.33, w: 0.34 }
886
+ }), t.onStatus(o > 0 ? `Retry ${o}: Final PCA...` : "Final PCA refinement...");
887
+ for (let S = 0; S < 3; S++) {
888
+ const F = rt(l, 0, r[1].y);
889
+ if (F) {
890
+ if (M = F.dot(c), Math.acos(Math.min(1, Math.abs(M))) * 180 / Math.PI < 0.1) break;
891
+ if (L = new h().crossVectors(F, c), L.length() > 1e-4) {
892
+ L.normalize(), p(L, Math.acos(Math.min(1, Math.max(-1, M))));
893
+ const B = r[0].clone();
894
+ l.translate(-B.x, -B.y, -B.z), f && f.translate(-B.x, -B.y, -B.z), r = r.map((T) => new h(T.x - B.x, T.y - B.y, T.z - B.z));
895
+ }
896
+ }
897
+ }
898
+ if (r[1].y < r[0].y) {
899
+ p(new h(1, 0, 0), Math.PI);
900
+ const S = r[0].clone();
901
+ l.translate(-S.x, -S.y, -S.z), f && f.translate(-S.x, -S.y, -S.z), r = r.map((F) => new h(F.x - S.x, F.y - S.y, F.z - S.z));
902
+ }
903
+ l.computeVertexNormals(), l.computeBoundingBox(), t.onStatus(o > 0 ? `Retry ${o}: Circumference refinement...` : "Circumference refinement...");
904
+ {
905
+ const S = ot(l), F = r[1].y, V = r[0].y, B = [F - We, F - 2 * We, F - 3 * We].filter((T) => T > V + 5);
906
+ if (B.length >= 2) {
907
+ const T = Math.PI / 180, E = (I, k) => {
908
+ const G = new h(0, 1, 0);
909
+ 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));
910
+ let U = 0;
911
+ for (const re of B) U += pt(S, l, new h(0, re, 0), G);
912
+ return U;
913
+ };
914
+ let j = 0, X = 0, Q = E(0, 0);
915
+ for (let I = -3; I <= 3; I += 0.5)
916
+ for (let k = -3; k <= 3; k += 0.5) {
917
+ const G = E(I * T, k * T);
918
+ G > 0 && G < Q && (Q = G, j = I * T, X = k * T);
919
+ }
920
+ const ie = j, se = X;
921
+ for (let I = -5; I <= 5; I++)
922
+ for (let k = -5; k <= 5; k++) {
923
+ const G = ie + I * 0.1 * T, U = se + k * 0.1 * T, re = E(G, U);
924
+ re > 0 && re < Q && (Q = re, j = G, X = U);
925
+ }
926
+ const A = Math.sqrt(j * j + X * X);
927
+ if (A > 0.05 * T) {
928
+ console.log(`Circumference refinement: rotating ${(-j / T).toFixed(2)}\xB0X ${(-X / T).toFixed(2)}\xB0Z`), Math.abs(j) > 0.01 * T && p(new h(1, 0, 0), -j), Math.abs(X) > 0.01 * T && p(new h(0, 0, 1), -X);
929
+ const I = r[0].clone();
930
+ l.translate(-I.x, -I.y, -I.z), f && f.translate(-I.x, -I.y, -I.z), r = r.map((k) => new h(k.x - I.x, k.y - I.y, k.z - I.z)), l.computeVertexNormals();
931
+ } else
932
+ console.log(`Circumference refinement: already optimal (${(A / T).toFixed(3)}\xB0)`);
933
+ }
934
+ }
935
+ const ne = r.map((S) => ({ x: S.x, y: S.y, z: S.z }));
936
+ t.updateLandmarkPositions(ne), t.setAligned(true), t.onStatus(o > 0 ? `Retry ${o}: Cutting mesh...` : 'Cutting mesh 2" above green...'), r = An(e, r, l, 5, t, f), t.onStatus("Validating results...");
937
+ const oe = e.geometry, le = r[1].y, ee = r[0].y, D = Wt(oe, le, ee, n);
938
+ if (D.valid) {
939
+ console.log(`Processing succeeded on attempt ${o + 1}`), f && t.setClippedReferenceGeometry && (f.computeVertexNormals(), t.setClippedReferenceGeometry(f));
940
+ break;
941
+ }
942
+ console.warn(`Attempt ${o + 1} failed validation: ${D.reason}`), u = D.reason, f && f.dispose(), o === 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));
943
+ } catch (l) {
944
+ console.error("Processing failed:", l), t.setError(l instanceof Error ? l.message : "Failed to process mesh.");
945
+ break;
946
+ }
947
+ i.dispose();
948
+ }
949
+ const Pn = ({ message: e, onDismiss: s }) => /* @__PURE__ */ W("div", { style: {
950
+ position: "absolute",
951
+ top: 16,
952
+ right: 16,
953
+ padding: "12px 16px",
954
+ backgroundColor: "rgba(220, 53, 69, 0.95)",
955
+ borderRadius: 8,
956
+ color: "#fff",
957
+ fontSize: 14,
958
+ maxWidth: 300,
959
+ zIndex: 100,
960
+ display: "flex",
961
+ alignItems: "flex-start",
962
+ gap: 12
963
+ }, children: [
964
+ /* @__PURE__ */ W("div", { style: { flex: 1 }, children: [
965
+ /* @__PURE__ */ d("div", { style: { fontWeight: "bold", marginBottom: 4 }, children: "Error" }),
966
+ /* @__PURE__ */ d("div", { style: { fontSize: 12, opacity: 0.9 }, children: e })
967
+ ] }),
968
+ /* @__PURE__ */ d("button", { onClick: s, style: { background: "none", border: "none", color: "#fff", cursor: "pointer", fontSize: 18, padding: 0, lineHeight: 1, opacity: 0.7 }, children: "x" })
969
+ ] }), At = ({ message: e }) => /* @__PURE__ */ W("div", { style: {
970
+ position: "absolute",
971
+ top: 0,
972
+ left: 0,
973
+ right: 0,
974
+ bottom: 0,
975
+ backgroundColor: "rgba(0, 0, 0, 0.7)",
976
+ display: "flex",
977
+ flexDirection: "column",
978
+ alignItems: "center",
979
+ justifyContent: "center",
980
+ zIndex: 100
981
+ }, children: [
982
+ /* @__PURE__ */ d("div", { style: { width: 48, height: 48, border: "4px solid rgba(255, 255, 255, 0.2)", borderTopColor: "#4a90d9", borderRadius: "50%", animation: "spin 1s linear infinite" } }),
983
+ e && /* @__PURE__ */ d("div", { style: { marginTop: 16, color: "#fff", fontSize: 14 }, children: e }),
984
+ /* @__PURE__ */ d("style", { children: "@keyframes spin { to { transform: rotate(360deg); } }" })
985
+ ] }), Ln = ({ mesh: e, maxPoints: s = 2, meshColor: n = "#c8c8c8", meshOpacity: t = 1 }) => {
986
+ const { addLandmarkPoint: i, landmarkPoints: a } = gt(), c = Fe((l) => {
987
+ if (a.length >= s) return;
988
+ l.stopPropagation();
989
+ const r = l.intersections[0], f = r == null ? void 0 : r.faceIndex;
990
+ if (!r || f == null) return;
991
+ const y = e.geometry, p = y.index;
992
+ let m;
993
+ p ? m = [p.getX(f * 3), p.getX(f * 3 + 1), p.getX(f * 3 + 2)] : m = [f * 3, f * 3 + 1, f * 3 + 2];
994
+ const g = y.getAttribute("position"), z = new h().fromBufferAttribute(g, m[0]), v = new h().fromBufferAttribute(g, m[1]), x = new h().fromBufferAttribute(g, m[2]);
995
+ z.applyMatrix4(e.matrixWorld), v.applyMatrix4(e.matrixWorld), x.applyMatrix4(e.matrixWorld);
996
+ const b = r.point, w = vn(b, z, v, x), C = {
997
+ faceIndex: f,
998
+ vertexIndices: m,
999
+ position: { x: b.x, y: b.y, z: b.z },
1000
+ barycentricCoords: w
1001
+ };
1002
+ i(C);
1003
+ }, [e, i, a.length, s]), u = de(() => !!e.geometry.getAttribute("color"), [e]), o = de(() => new J.MeshStandardMaterial({
1004
+ color: u ? "#ffffff" : n,
1005
+ side: J.DoubleSide,
1006
+ roughness: 0.6,
1007
+ metalness: 0.1,
1008
+ transparent: t < 1,
1009
+ opacity: t,
1010
+ vertexColors: u
1011
+ }), [n, t, u]);
1012
+ return /* @__PURE__ */ d(
1013
+ "primitive",
1014
+ {
1015
+ object: e,
1016
+ onClick: c,
1017
+ material: o
1018
+ }
1019
+ );
1020
+ }, Dn = ({ point: e, index: s, markerSize: n, color: t, label: i }) => {
1021
+ const [a, c] = q(false);
1022
+ return /* @__PURE__ */ W(
1023
+ "mesh",
1024
+ {
1025
+ position: [e.position.x, e.position.y, e.position.z],
1026
+ onPointerOver: () => c(true),
1027
+ onPointerOut: () => c(false),
1028
+ children: [
1029
+ /* @__PURE__ */ d("sphereGeometry", { args: [n, 16, 16] }),
1030
+ /* @__PURE__ */ d("meshBasicMaterial", { color: t }),
1031
+ a && /* @__PURE__ */ d(Ke, { center: true, style: { pointerEvents: "none" }, children: /* @__PURE__ */ d("div", { style: {
1032
+ padding: "3px 8px",
1033
+ backgroundColor: "rgba(0, 0, 0, 0.75)",
1034
+ borderRadius: 4,
1035
+ color: "#fff",
1036
+ fontSize: 12,
1037
+ fontFamily: "system-ui, sans-serif",
1038
+ whiteSpace: "nowrap",
1039
+ transform: "translateY(-24px)"
1040
+ }, children: i }) })
1041
+ ]
1042
+ },
1043
+ s
1044
+ );
1045
+ }, Tn = ({ modelSize: e, labels: s }) => {
1046
+ const { landmarkPoints: n } = gt(), t = e * 0.02, i = ["#ff4444", "#44ff44", "#4444ff"], c = s ?? ["Origin", "MPT", "Cut Plane"];
1047
+ return /* @__PURE__ */ d(He, { children: n.map((u, o) => /* @__PURE__ */ d(Dn, { point: u, index: o, markerSize: t, color: i[o], label: c[o] }, o)) });
1048
+ };
1049
+ function kn(e) {
1050
+ return de(() => e ? new $e(e, { maxLeafTris: Ye }) : null, [e]);
1051
+ }
1052
+ const Ft = (e, s) => {
1053
+ const n = Math.abs(e - s);
1054
+ return n < 1 ? "#8BC34A" : n < 5 ? "#FFC107" : "#FF5722";
1055
+ }, It = new J.Color("#8BC34A"), Pt = new J.Color("#FFC107"), Bn = new J.Color("#FF5722"), Rn = (e) => {
1056
+ if (e < 1) return It.clone();
1057
+ if (e < 5) {
1058
+ const n = (e - 1) / 4;
1059
+ return It.clone().lerp(Pt, n);
1060
+ }
1061
+ const s = Math.min((e - 5) / 5, 1);
1062
+ return Pt.clone().lerp(Bn, s);
1063
+ }, En = (e, s) => {
1064
+ const n = e.length, t = new Float32Array(n * 2 * 3), i = new Float32Array(n * 2 * 3), a = [];
1065
+ for (let o = 0; o < n; o++) {
1066
+ const l = e[o], r = s[o], f = l.distanceTo(r), y = Rn(f);
1067
+ if (t[o * 6] = l.x, t[o * 6 + 1] = l.y, t[o * 6 + 2] = l.z, i[o * 6] = y.r, i[o * 6 + 1] = y.g, i[o * 6 + 2] = y.b, t[o * 6 + 3] = r.x, t[o * 6 + 4] = r.y, t[o * 6 + 5] = r.z, i[o * 6 + 3] = y.r, i[o * 6 + 4] = y.g, i[o * 6 + 5] = y.b, o < n - 1) {
1068
+ const p = o * 2, m = p + 1, g = (o + 1) * 2, z = g + 1;
1069
+ a.push(p, m, g, m, z, g);
1070
+ }
1071
+ }
1072
+ const c = new J.BufferGeometry();
1073
+ c.setAttribute("position", new J.Float32BufferAttribute(t, 3)), c.setAttribute("color", new J.Float32BufferAttribute(i, 3)), c.setIndex(a);
1074
+ const u = new J.MeshBasicMaterial({
1075
+ vertexColors: true,
1076
+ transparent: true,
1077
+ opacity: 0.25,
1078
+ side: J.DoubleSide,
1079
+ depthTest: false,
1080
+ depthWrite: false
1081
+ });
1082
+ return new J.Mesh(c, u);
1083
+ }, Wn = ({ bvh: e, geometry: s, yPosition: n, color: t = "#00ff00", labelX: i, onDataChange: a, displayUnit: c = "mm", useInnerSurface: u = false, formValue: o, lineWidth: l = 1.5 }) => {
1084
+ const r = de(() => Ze(e, s, n, u), [e, s, n, u]), { linePoints: f, lineLength: y } = r, p = de(() => {
1085
+ if (o == null || y <= 0 || f.length < 2) return null;
1086
+ const v = o / y, x = f.reduce((w, C) => w + C.x, 0) / f.length, b = f.reduce((w, C) => w + C.z, 0) / f.length;
1087
+ return f.map((w) => new h(
1088
+ x + (w.x - x) * v,
1089
+ w.y,
1090
+ b + (w.z - b) * v
1091
+ ));
1092
+ }, [f, y, o]), m = de(() => !p || f.length < 2 ? null : En(f, p), [f, p]);
1093
+ Ce(() => () => {
1094
+ m && (m.geometry.dispose(), m.material.dispose());
1095
+ }, [m]);
1096
+ const g = Ie(null), z = de(() => {
1097
+ const v = new J.BufferGeometry();
1098
+ v.setAttribute("position", new J.Float32BufferAttribute(new Float32Array(6), 3));
1099
+ const x = new J.LineBasicMaterial({ color: 6710886, depthTest: false, depthWrite: false, transparent: true });
1100
+ return new J.Line(v, x);
1101
+ }, []);
1102
+ return Ce(() => () => {
1103
+ z.geometry.dispose(), z.material.dispose();
1104
+ }, [z]), Ce(() => {
1105
+ y > 0 && (a == null ? void 0 : a({ yPosition: n, originalValue: y, modifiedValue: null }));
1106
+ }, [y, n, a]), Lt(({ camera: v }) => {
1107
+ if (!g.current || f.length < 2) return;
1108
+ const x = new h();
1109
+ v.getWorldDirection(x);
1110
+ const b = new h(x.x, 0, x.z);
1111
+ if (b.lengthSq() < 1e-8) return;
1112
+ b.normalize();
1113
+ const w = new h().crossVectors(b, new h(0, 1, 0)).normalize();
1114
+ let C = -1 / 0, M = f[0];
1115
+ for (const O of f) {
1116
+ const $ = w.x * O.x + w.z * O.z;
1117
+ $ > C && (C = $, M = O);
1118
+ }
1119
+ const L = i * 0.35, P = new h(
1120
+ M.x + w.x * L,
1121
+ n,
1122
+ M.z + w.z * L
1123
+ );
1124
+ g.current.position.copy(P);
1125
+ const H = z.geometry.getAttribute("position");
1126
+ H.setXYZ(0, M.x, M.y, M.z), H.setXYZ(1, P.x, P.y, P.z), H.needsUpdate = true;
1127
+ }), f.length < 2 ? null : /* @__PURE__ */ W("group", { children: [
1128
+ /* @__PURE__ */ d(ge, { points: f, color: t, lineWidth: l, depthTest: false, depthWrite: false, transparent: true }),
1129
+ m && /* @__PURE__ */ d("primitive", { object: m }),
1130
+ p && o != null && /* @__PURE__ */ d(ge, { points: p, color: Ft(y, o), lineWidth: 2.5, dashed: true, dashSize: 2, gapSize: 1.5, depthTest: false, depthWrite: false, transparent: true, opacity: 0.8 }),
1131
+ /* @__PURE__ */ d("primitive", { object: z }),
1132
+ /* @__PURE__ */ d("group", { ref: g, children: /* @__PURE__ */ d(Ke, { zIndexRange: [100, 0], style: { pointerEvents: "none", transform: "translateY(-50%)" }, children: /* @__PURE__ */ W("div", { style: { display: "flex", alignItems: "stretch", gap: 0, marginLeft: 10, pointerEvents: "none", whiteSpace: "nowrap" }, children: [
1133
+ /* @__PURE__ */ W("div", { style: {
1134
+ display: "flex",
1135
+ alignItems: "center",
1136
+ gap: 4,
1137
+ padding: "5px 10px",
1138
+ backgroundColor: "rgba(0, 0, 0, 0.75)",
1139
+ borderRadius: o != null ? "4px 0 0 4px" : 4
1140
+ }, children: [
1141
+ /* @__PURE__ */ d("span", { style: { fontSize: 14, color: "#fff", fontFamily: "monospace", minWidth: 52, textAlign: "right" }, children: c === "inch" ? (y / 25.4).toFixed(2) : y.toFixed(1) }),
1142
+ /* @__PURE__ */ d("span", { style: { fontSize: 11, color: "rgba(255,255,255,0.6)", fontFamily: "monospace" }, children: c === "inch" ? "in" : "mm" })
1143
+ ] }),
1144
+ o != null && y > 0 && (() => {
1145
+ const v = y - o, x = v > 0.5 ? "\u25B2" : v < -0.5 ? "\u25BC" : "", b = Ft(y, o);
1146
+ return /* @__PURE__ */ W("div", { style: {
1147
+ display: "flex",
1148
+ alignItems: "center",
1149
+ gap: 5,
1150
+ padding: "5px 10px",
1151
+ backgroundColor: "rgba(0, 0, 0, 0.55)",
1152
+ borderRadius: "0 4px 4px 0",
1153
+ borderLeft: "1px solid rgba(255,255,255,0.12)"
1154
+ }, children: [
1155
+ x && /* @__PURE__ */ d("span", { style: { fontSize: 10, color: b, lineHeight: 1 }, children: x }),
1156
+ /* @__PURE__ */ W("span", { style: { fontSize: 13, color: b, fontFamily: "monospace", fontWeight: 600 }, children: [
1157
+ v > 0 ? "+" : "",
1158
+ c === "inch" ? (v / 25.4).toFixed(2) : v.toFixed(1)
1159
+ ] }),
1160
+ /* @__PURE__ */ W("span", { style: { fontSize: 11, color: "rgba(255,255,255,0.4)", fontFamily: "monospace" }, children: [
1161
+ "form ",
1162
+ c === "inch" ? (o / 25.4).toFixed(2) : o.toFixed(0)
1163
+ ] })
1164
+ ] });
1165
+ })()
1166
+ ] }) }) })
1167
+ ] });
1168
+ }, Vn = nn(Wn), _n = ({ mesh: e, startY: s, endY: n, spacing: t, modelSize: i, onMeasurementsChange: a, reverseOrder: c = false, displayUnit: u = "mm", useInnerSurface: o = false, formMeasurements: l, originY: r }) => {
1169
+ const f = Ie(/* @__PURE__ */ new Map()), y = e.geometry, p = kn(y), m = de(() => {
1170
+ const x = [];
1171
+ if (c)
1172
+ for (let b = n; b >= s; b -= t) x.push(b);
1173
+ else
1174
+ for (let b = s; b <= n; b += t) x.push(b);
1175
+ return x;
1176
+ }, [s, n, t, c]);
1177
+ Ce(() => {
1178
+ f.current.clear();
1179
+ }, [m]);
1180
+ const g = ["#5B9BD5"], z = i * un, v = Fe((x) => {
1181
+ f.current.set(x.yPosition, x);
1182
+ const b = Array.from(f.current.values()).sort(
1183
+ (w, C) => c ? C.yPosition - w.yPosition : w.yPosition - C.yPosition
1184
+ );
1185
+ a == null ? void 0 : a(b);
1186
+ }, [a, c]);
1187
+ return p ? /* @__PURE__ */ d(He, { children: m.map((x, b) => /* @__PURE__ */ d(Vn, { bvh: p, geometry: y, yPosition: x, color: r != null && Math.abs(x - r) < t * 0.5 ? "#44ff44" : g[b % g.length], labelX: z, onDataChange: v, displayUnit: u, useInnerSurface: o, formValue: l == null ? void 0 : l[b], lineWidth: r != null && Math.abs(x - r) < t * 0.5 ? 4 : 1.5 }, x)) }) : null;
1188
+ }, On = ({ mesh: e, greenY: s, modelSize: n, displayUnit: t = "mm" }) => {
1189
+ var _a;
1190
+ const i = e.geometry;
1191
+ i.computeBoundingBox();
1192
+ const a = ((_a = i.boundingBox) == null ? void 0 : _a.min.y) ?? 0, c = s - a, u = n * 0.4, o = n * 0.03, l = Ie(null);
1193
+ Lt(({ camera: v }) => {
1194
+ if (!l.current) return;
1195
+ const x = new h();
1196
+ v.getWorldDirection(x);
1197
+ const b = new h(x.x, 0, x.z);
1198
+ if (b.lengthSq() < 1e-8) return;
1199
+ b.normalize();
1200
+ const w = new h().crossVectors(new h(0, 1, 0), b).normalize();
1201
+ l.current.position.set(w.x * u, 0, w.z * u);
1202
+ const C = v.position.x - l.current.position.x, M = v.position.z - l.current.position.z;
1203
+ l.current.rotation.y = Math.atan2(C, M);
1204
+ });
1205
+ const r = new h(0, s, 0), f = new h(0, a, 0), y = new h(0, (s + a) / 2, 0), p = new h(-o, s, 0), m = new h(o, s, 0), g = new h(-o, a, 0), z = new h(o, a, 0);
1206
+ return /* @__PURE__ */ W("group", { ref: l, children: [
1207
+ /* @__PURE__ */ d(ge, { points: [r, f], color: "#888888", lineWidth: 1.5, depthTest: false }),
1208
+ /* @__PURE__ */ d(ge, { points: [p, m], color: "#888888", lineWidth: 1.5, depthTest: false }),
1209
+ /* @__PURE__ */ d(ge, { points: [g, z], color: "#888888", lineWidth: 1.5, depthTest: false }),
1210
+ /* @__PURE__ */ d("mesh", { position: y, children: /* @__PURE__ */ d(Ke, { center: true, style: { pointerEvents: "none" }, children: /* @__PURE__ */ W("div", { style: {
1211
+ padding: "4px 8px",
1212
+ backgroundColor: "rgba(0, 0, 0, 0.7)",
1213
+ borderRadius: 4,
1214
+ color: "#fff",
1215
+ fontSize: 16,
1216
+ fontFamily: "monospace",
1217
+ whiteSpace: "nowrap",
1218
+ transform: "rotate(-90deg)",
1219
+ transformOrigin: "center center",
1220
+ pointerEvents: "none"
1221
+ }, children: [
1222
+ t === "inch" ? (c / 25.4).toFixed(2) : c.toFixed(1),
1223
+ " ",
1224
+ t === "inch" ? "in" : "mm"
1225
+ ] }) }) })
1226
+ ] });
1227
+ }, $n = ({ modelSize: e, isAligned: s, isCut: n, mesh: t, viewMode: i, sliceY: a, landmarkCount: c = 0 }) => {
1228
+ const { set: u, size: o, camera: l, invalidate: r } = on(), f = Ie(false), y = Ie(s), p = Ie(n), m = Ie(i), g = Ie(new h()), z = Ie(null), v = Ie(c), x = Fe(() => {
1229
+ if (!t || e <= 0) return;
1230
+ const w = t.geometry;
1231
+ w.computeBoundingBox();
1232
+ const C = w.boundingBox, M = new h();
1233
+ C.getCenter(M);
1234
+ const L = new h();
1235
+ C.getSize(L), g.current.copy(L);
1236
+ const P = o.width / o.height, H = Math.max(L.y, L.x / P) * 1.2, O = H * P, $ = new J.OrthographicCamera(-O / 2, O / 2, H / 2, -H / 2, 0.1, e * 10);
1237
+ $.position.set(0, M.y, e * 2), $.lookAt(0, M.y, 0), u({ camera: $ });
1238
+ }, [t, e, o, u]), b = Fe((w) => {
1239
+ const C = w.position.clone(), M = C.length(), L = Math.atan2(C.x, C.z), P = Math.acos(C.y / M), O = L + 0.02;
1240
+ w.position.set(
1241
+ M * Math.sin(P) * Math.sin(O),
1242
+ M * Math.cos(P),
1243
+ M * Math.sin(P) * Math.cos(O)
1244
+ ), w.lookAt(0, 0, 0), w.updateMatrixWorld(true), r();
1245
+ }, [r]);
1246
+ return Ce(() => {
1247
+ if (e > 0 && !f.current && !s) {
1248
+ f.current = true;
1249
+ const w = new J.PerspectiveCamera(50, o.width / o.height, 0.1, e * 10);
1250
+ w.position.set(e * 0.3, e * 0.2, e * 1.5), w.lookAt(0, 0, 0), u({ camera: w }), requestAnimationFrame(() => b(w));
1251
+ }
1252
+ }, [e, o, u, s, b]), Ce(() => {
1253
+ const w = v.current;
1254
+ v.current = c, w === 0 && c === 1 && !s && requestAnimationFrame(() => b(l));
1255
+ }, [c, s, l, b]), Ce(() => {
1256
+ y.current === s && p.current === n || (y.current = s, p.current = n, s && i === "3D" && x());
1257
+ }, [s, n, i, x]), Ce(() => {
1258
+ if (m.current === i) return;
1259
+ const w = m.current;
1260
+ if (m.current = i, !(!s || !t || e <= 0))
1261
+ if (i === "2D" && a != null) {
1262
+ z.current = l;
1263
+ const C = t.geometry, M = C.getAttribute("position"), L = M.array, P = e * 0.15;
1264
+ let H = 1 / 0, O = -1 / 0, $ = 1 / 0, R = -1 / 0, Y = false;
1265
+ for (let B = 0; B < M.count; B++)
1266
+ if (Math.abs(L[B * 3 + 1] - a) < P) {
1267
+ const T = L[B * 3], E = L[B * 3 + 2];
1268
+ T < H && (H = T), T > O && (O = T), E < $ && ($ = E), E > R && (R = E), Y = true;
1269
+ }
1270
+ if (!Y) {
1271
+ C.computeBoundingBox();
1272
+ const B = C.boundingBox;
1273
+ H = B.min.x, O = B.max.x, $ = B.min.z, R = B.max.z;
1274
+ }
1275
+ const N = (H + O) / 2, ne = ($ + R) / 2, oe = o.width / o.height, le = 1.4, ee = (O - H) * le, D = (R - $) * le;
1276
+ let S, F;
1277
+ ee / D > oe ? (S = ee, F = ee / oe) : (F = D, S = D * oe);
1278
+ const V = new J.OrthographicCamera(-S / 2, S / 2, F / 2, -F / 2, 0.1, e * 10);
1279
+ V.position.set(N, a + e * 2, ne), V.up.set(0, 0, -1), V.lookAt(N, a, ne), u({ camera: V });
1280
+ } else w === "2D" && (z.current ? (u({ camera: z.current }), z.current = null) : x());
1281
+ }, [i, a, s, t, e, o, u, l, x]), Ce(() => {
1282
+ if (!s || !l || !l.isOrthographicCamera) return;
1283
+ const w = l;
1284
+ if (i === "2D") {
1285
+ if (!t || a == null) return;
1286
+ const C = t.geometry, M = C.getAttribute("position"), L = M.array, P = e * 0.15;
1287
+ let H = 1 / 0, O = -1 / 0, $ = 1 / 0, R = -1 / 0, Y = false;
1288
+ for (let S = 0; S < M.count; S++)
1289
+ if (Math.abs(L[S * 3 + 1] - a) < P) {
1290
+ const F = L[S * 3], V = L[S * 3 + 2];
1291
+ F < H && (H = F), F > O && (O = F), V < $ && ($ = V), V > R && (R = V), Y = true;
1292
+ }
1293
+ if (!Y) {
1294
+ C.computeBoundingBox();
1295
+ const S = C.boundingBox;
1296
+ H = S.min.x, O = S.max.x, $ = S.min.z, R = S.max.z;
1297
+ }
1298
+ const N = o.width / o.height, ne = 1.4, oe = (O - H) * ne, le = (R - $) * ne;
1299
+ let ee, D;
1300
+ oe / le > N ? (ee = oe, D = oe / N) : (D = le, ee = le * N), w.left = -ee / 2, w.right = ee / 2, w.top = D / 2, w.bottom = -D / 2;
1301
+ } else {
1302
+ const C = g.current, M = o.width / o.height, L = Math.max(C.y, C.x / M) * 1.2, P = L * M;
1303
+ w.left = -P / 2, w.right = P / 2, w.top = L / 2, w.bottom = -L / 2;
1304
+ }
1305
+ w.updateProjectionMatrix();
1306
+ }, [o.width, o.height, s, l, i, t]), null;
1307
+ }, Nn = ({ mesh: e, isDragging: s }) => {
1308
+ var _a;
1309
+ const n = e.geometry;
1310
+ n.computeBoundingBox();
1311
+ const t = new h();
1312
+ return (_a = n.boundingBox) == null ? void 0 : _a.getCenter(t), /* @__PURE__ */ d(
1313
+ Dt,
1314
+ {
1315
+ enableDamping: false,
1316
+ enablePan: false,
1317
+ minPolarAngle: Math.PI * 0.15,
1318
+ maxPolarAngle: Math.PI * 0.85,
1319
+ minZoom: 0.5,
1320
+ maxZoom: 3,
1321
+ enabled: !s,
1322
+ target: [t.x, t.y, t.z]
1323
+ }
1324
+ );
1325
+ }, jn = ({ wasAutoScaled: e, onDismiss: s }) => /* @__PURE__ */ W("div", { style: {
1326
+ position: "absolute",
1327
+ bottom: 16,
1328
+ left: 16,
1329
+ zIndex: 10,
1330
+ display: "flex",
1331
+ alignItems: "flex-start",
1332
+ gap: 10,
1333
+ padding: "10px 14px",
1334
+ maxWidth: 320,
1335
+ backgroundColor: e ? "rgba(30, 70, 160, 0.92)" : "rgba(40, 40, 40, 0.88)",
1336
+ borderRadius: 8,
1337
+ boxShadow: "0 2px 12px rgba(0,0,0,0.15)",
1338
+ fontFamily: "system-ui, sans-serif"
1339
+ }, children: [
1340
+ /* @__PURE__ */ d("span", { style: { fontSize: 13, color: "#fff", lineHeight: "20px" }, children: e ? "Units detected as meters - converted to mm" : "Units detected as mm" }),
1341
+ /* @__PURE__ */ d("button", { onClick: s, style: {
1342
+ background: "none",
1343
+ border: "none",
1344
+ color: "rgba(255,255,255,0.7)",
1345
+ cursor: "pointer",
1346
+ fontSize: 16,
1347
+ lineHeight: "20px",
1348
+ padding: 0,
1349
+ marginLeft: "auto",
1350
+ flexShrink: 0
1351
+ }, children: "X" })
1352
+ ] }), Hn = ({ isDoubleShell: e, onDismiss: s }) => /* @__PURE__ */ W("div", { style: {
1353
+ position: "absolute",
1354
+ bottom: 68,
1355
+ left: 16,
1356
+ zIndex: 10,
1357
+ display: "flex",
1358
+ alignItems: "flex-start",
1359
+ gap: 10,
1360
+ padding: "10px 14px",
1361
+ maxWidth: 320,
1362
+ backgroundColor: e ? "rgba(130, 80, 20, 0.92)" : "rgba(40, 40, 40, 0.88)",
1363
+ borderRadius: 8,
1364
+ boxShadow: "0 2px 12px rgba(0,0,0,0.15)",
1365
+ fontFamily: "system-ui, sans-serif"
1366
+ }, children: [
1367
+ /* @__PURE__ */ d("span", { style: { fontSize: 13, color: "#fff", lineHeight: "20px" }, children: e ? "Double shell scan detected" : "Single shell scan detected" }),
1368
+ /* @__PURE__ */ d("button", { onClick: s, style: {
1369
+ background: "none",
1370
+ border: "none",
1371
+ color: "rgba(255,255,255,0.7)",
1372
+ cursor: "pointer",
1373
+ fontSize: 16,
1374
+ lineHeight: "20px",
1375
+ padding: 0,
1376
+ marginLeft: "auto",
1377
+ flexShrink: 0
1378
+ }, children: "X" })
1379
+ ] }), Yn = ({ steps: e, currentStep: s, accentColor: n = "rgb(12, 67, 173)" }) => /* @__PURE__ */ d("div", { style: { backgroundColor: "#fff", borderBottom: "1px solid #e0e0e0", display: "flex", alignItems: "center", padding: "24px 24px", flexShrink: 0 }, children: e.map((t, i) => {
1380
+ const a = t.number < s, c = t.number === s;
1381
+ return /* @__PURE__ */ W("div", { style: { display: "contents" }, children: [
1382
+ /* @__PURE__ */ W("div", { style: { display: "flex", alignItems: "center", gap: 8, padding: "0 8px", flexShrink: 0, cursor: "default" }, children: [
1383
+ /* @__PURE__ */ d("div", { style: {
1384
+ width: 24,
1385
+ height: 24,
1386
+ borderRadius: "50%",
1387
+ backgroundColor: a || c ? n : "rgba(0, 0, 0, 0.38)",
1388
+ color: "#fff",
1389
+ display: "flex",
1390
+ alignItems: "center",
1391
+ justifyContent: "center",
1392
+ fontSize: 12,
1393
+ fontFamily: "system-ui, sans-serif",
1394
+ flexShrink: 0
1395
+ }, children: a ? "\u2713" : t.number }),
1396
+ /* @__PURE__ */ d("div", { style: {
1397
+ fontSize: 14,
1398
+ fontWeight: c ? 600 : 400,
1399
+ color: c ? "rgba(0, 0, 0, 0.87)" : "rgba(0, 0, 0, 0.54)",
1400
+ fontFamily: "system-ui, sans-serif",
1401
+ whiteSpace: "nowrap"
1402
+ }, children: t.label })
1403
+ ] }),
1404
+ i < e.length - 1 && /* @__PURE__ */ d("div", { style: { flex: "auto", borderTop: "1px solid #bdbdbd", margin: "0 8px" } })
1405
+ ] }, t.number);
1406
+ }) }), Gn = ({ mesh: e, upperY: s, originY: n, modelSize: t, meshColor: i = "#c8c8c8", displayUnit: a = "mm" }) => {
1407
+ const c = e.geometry, u = de(() => new $e(c, { maxLeafTris: Ye }), [c]), o = de(() => Ze(u, c, n), [u, c, n]), l = de(() => new it(new h(0, -1, 0), s), [s]), { mlLine: r, apLine: f, mlWidth: y, apWidth: p } = de(() => {
1408
+ let z = null, v = null, x = 0, b = 0;
1409
+ if (o.linePoints.length >= 2) {
1410
+ let w = o.linePoints[0], C = o.linePoints[0], M = o.linePoints[0], L = o.linePoints[0];
1411
+ for (const P of o.linePoints)
1412
+ P.x < w.x && (w = P), P.x > C.x && (C = P), P.z < M.z && (M = P), P.z > L.z && (L = P);
1413
+ z = [new h(w.x, n, w.z), new h(C.x, n, C.z)], v = [new h(M.x, n, M.z), new h(L.x, n, L.z)], x = z[0].distanceTo(z[1]), b = v[0].distanceTo(v[1]);
1414
+ }
1415
+ return { mlLine: z, apLine: v, mlWidth: x, apWidth: b };
1416
+ }, [o, n]), m = (z) => a === "inch" ? (z / 25.4).toFixed(2) : z.toFixed(1), g = a === "inch" ? "in" : "mm";
1417
+ return /* @__PURE__ */ W(He, { children: [
1418
+ /* @__PURE__ */ d("mesh", { geometry: e.geometry, children: /* @__PURE__ */ d("meshStandardMaterial", { color: i, side: J.DoubleSide, transparent: true, opacity: 0.15, depthWrite: false, clippingPlanes: [l] }) }),
1419
+ o.linePoints.length >= 2 && /* @__PURE__ */ d(ge, { points: o.linePoints, color: "#00ff00", lineWidth: 3, depthTest: false, depthWrite: false, transparent: true }),
1420
+ r && /* @__PURE__ */ W(He, { children: [
1421
+ /* @__PURE__ */ d(ge, { points: r, color: "#ff8800", lineWidth: 2, depthTest: false, depthWrite: false, transparent: true }),
1422
+ /* @__PURE__ */ d(Ke, { position: [r[0].x, n, r[0].z - t * 0.02], center: true, style: { pointerEvents: "none" }, children: /* @__PURE__ */ d("div", { style: { whiteSpace: "nowrap", padding: "2px 6px", backgroundColor: "rgba(0,0,0,0.75)", borderRadius: 3 }, children: /* @__PURE__ */ W("span", { style: { fontSize: 12, color: "#ff8800", fontFamily: "monospace" }, children: [
1423
+ "ML ",
1424
+ m(y),
1425
+ " ",
1426
+ g
1427
+ ] }) }) })
1428
+ ] }),
1429
+ f && /* @__PURE__ */ W(He, { children: [
1430
+ /* @__PURE__ */ d(ge, { points: f, color: "#ff00ff", lineWidth: 2, depthTest: false, depthWrite: false, transparent: true }),
1431
+ /* @__PURE__ */ d(Ke, { position: [Math.max(f[0].x, f[1].x) + t * 0.02, n, f[0].z > f[1].z ? f[0].z : f[1].z], center: true, style: { pointerEvents: "none" }, children: /* @__PURE__ */ d("div", { style: { whiteSpace: "nowrap", padding: "2px 6px", backgroundColor: "rgba(0,0,0,0.75)", borderRadius: 3 }, children: /* @__PURE__ */ W("span", { style: { fontSize: 12, color: "#ff00ff", fontFamily: "monospace" }, children: [
1432
+ "AP ",
1433
+ m(p),
1434
+ " ",
1435
+ g
1436
+ ] }) }) })
1437
+ ] })
1438
+ ] });
1439
+ }, Xn = {
1440
+ pcaAxes: true,
1441
+ obb: true,
1442
+ obbAxis: true,
1443
+ shellComponents: true,
1444
+ circumferenceScan: false,
1445
+ landmarkAxis: true,
1446
+ iterativePCA: false,
1447
+ fullRegionPCA: true
1448
+ }, Zn = ["#ff4444", "#44cc44", "#4488ff"];
1449
+ function Ot(e) {
1450
+ const s = e.getAttribute("position"), n = s.count, t = new h();
1451
+ for (let g = 0; g < n; g++)
1452
+ t.x += s.getX(g), t.y += s.getY(g), t.z += s.getZ(g);
1453
+ t.divideScalar(n);
1454
+ let i = 0, a = 0, c = 0, u = 0, o = 0, l = 0;
1455
+ for (let g = 0; g < n; g++) {
1456
+ const z = s.getX(g) - t.x, v = s.getY(g) - t.y, x = s.getZ(g) - t.z;
1457
+ i += z * z, a += z * v, c += z * x, u += v * v, o += v * x, l += x * x;
1458
+ }
1459
+ i /= n, a /= n, c /= n, u /= n, o /= n, l /= n;
1460
+ const r = [], f = [], y = [[i, a, c], [a, u, o], [c, o, l]];
1461
+ for (let g = 0; g < 3; g++) {
1462
+ let z = new h(1 + g * 0.1, 1 - g * 0.1, 0.5 + g * 0.3).normalize(), v = 0;
1463
+ for (let x = 0; x < 100; x++) {
1464
+ const b = y[0][0] * z.x + y[0][1] * z.y + y[0][2] * z.z, w = y[1][0] * z.x + y[1][1] * z.y + y[1][2] * z.z, C = y[2][0] * z.x + y[2][1] * z.y + y[2][2] * z.z, M = new h(b, w, C);
1465
+ if (v = M.length(), v < 1e-12) break;
1466
+ if (M.divideScalar(v), z.distanceTo(M) < 1e-10) {
1467
+ z = M;
1468
+ break;
1469
+ }
1470
+ z = M;
1471
+ }
1472
+ r.push(z.clone()), f.push(v);
1473
+ for (let x = 0; x < 3; x++)
1474
+ for (let b = 0; b < 3; b++) {
1475
+ const w = [z.x, z.y, z.z][x], C = [z.x, z.y, z.z][b];
1476
+ y[x][b] -= v * w * C;
1477
+ }
1478
+ }
1479
+ const p = new h();
1480
+ for (let g = 0; g < n; g++)
1481
+ p.x += s.getX(g), p.y += s.getY(g), p.z += s.getZ(g);
1482
+ p.divideScalar(n);
1483
+ const m = [0, 0, 0];
1484
+ for (let g = 0; g < 3; g++) {
1485
+ let z = 1 / 0, v = -1 / 0;
1486
+ const x = r[g];
1487
+ for (let b = 0; b < n; b++) {
1488
+ const w = s.getX(b) - p.x, C = s.getY(b) - p.y, M = s.getZ(b) - p.z, L = w * x.x + C * x.y + M * x.z;
1489
+ L < z && (z = L), L > v && (v = L);
1490
+ }
1491
+ m[g] = (v - z) / 2;
1492
+ }
1493
+ return {
1494
+ axes: r,
1495
+ eigenvalues: f,
1496
+ center: p,
1497
+ halfExtents: m
1498
+ };
1499
+ }
1500
+ function Kn({ pca: e }) {
1501
+ return /* @__PURE__ */ d("group", { children: e.axes.map((s, n) => {
1502
+ const t = e.center.clone().addScaledVector(s, e.halfExtents[n]), i = e.center.clone().addScaledVector(s, -e.halfExtents[n]);
1503
+ return /* @__PURE__ */ d(ge, { points: [i, t], color: Zn[n], lineWidth: 2 }, n);
1504
+ }) });
1505
+ }
1506
+ function Un({ pca: e }) {
1507
+ const s = de(() => {
1508
+ const { center: n, axes: t, halfExtents: i } = e, a = [];
1509
+ for (let u = -1; u <= 1; u += 2)
1510
+ for (let o = -1; o <= 1; o += 2)
1511
+ for (let l = -1; l <= 1; l += 2)
1512
+ a.push(
1513
+ n.clone().addScaledVector(t[0], u * i[0]).addScaledVector(t[1], o * i[1]).addScaledVector(t[2], l * i[2])
1514
+ );
1515
+ return [
1516
+ [0, 1],
1517
+ [2, 3],
1518
+ [4, 5],
1519
+ [6, 7],
1520
+ [0, 2],
1521
+ [1, 3],
1522
+ [4, 6],
1523
+ [5, 7],
1524
+ [0, 4],
1525
+ [1, 5],
1526
+ [2, 6],
1527
+ [3, 7]
1528
+ ].map(([u, o]) => [a[u], a[o]]);
1529
+ }, [e]);
1530
+ return /* @__PURE__ */ d("group", { children: s.map((n, t) => /* @__PURE__ */ d(ge, { points: n, color: "#ffaa00", lineWidth: 1, transparent: true, opacity: 0.5 }, t)) });
1531
+ }
1532
+ function Qn({ redPoint: e, greenPoint: s }) {
1533
+ const n = de(() => new h().subVectors(s, e).normalize(), [e, s]), t = de(() => {
1534
+ const a = n.dot(new h(0, 1, 0));
1535
+ return Math.acos(Math.min(1, Math.abs(a))) * 180 / Math.PI;
1536
+ }, [n]), i = t < 1 ? "#44ff44" : t < 5 ? "#ffcc00" : "#ff4444";
1537
+ return /* @__PURE__ */ W("group", { children: [
1538
+ /* @__PURE__ */ d(ge, { points: [e, s], color: i, lineWidth: 3 }),
1539
+ /* @__PURE__ */ W("mesh", { position: e, children: [
1540
+ /* @__PURE__ */ d("sphereGeometry", { args: [1.5, 8, 8] }),
1541
+ /* @__PURE__ */ d("meshBasicMaterial", { color: "#ff4444" })
1542
+ ] }),
1543
+ /* @__PURE__ */ W("mesh", { position: s, children: [
1544
+ /* @__PURE__ */ d("sphereGeometry", { args: [1.5, 8, 8] }),
1545
+ /* @__PURE__ */ d("meshBasicMaterial", { color: "#44ff44" })
1546
+ ] })
1547
+ ] });
1548
+ }
1549
+ function qn({ geometry: e, redY: s, greenY: n, modelSize: t }) {
1550
+ const a = t * 0.15, c = de(() => {
1551
+ const u = [];
1552
+ let o = n - 10;
1553
+ const l = new h(0, 1, 0);
1554
+ for (; o > s; ) {
1555
+ const r = Math.min(o, n), f = Math.max(o, n), y = rt(e, r, f);
1556
+ if (y) {
1557
+ const p = y.dot(l), m = Math.acos(Math.min(1, Math.abs(p))) * 180 / Math.PI;
1558
+ u.push({ axis: y, regionMin: r, regionMax: f, angleDeg: m });
1559
+ }
1560
+ o -= 10;
1561
+ }
1562
+ return u;
1563
+ }, [e, s, n]);
1564
+ return /* @__PURE__ */ d("group", { children: c.map((u, o) => {
1565
+ const l = (u.regionMin + u.regionMax) / 2, r = new h(0, l, 0), f = r.clone().addScaledVector(u.axis, a), y = r.clone().addScaledVector(u.axis, -a), p = o / Math.max(1, c.length - 1), m = u.angleDeg < 0.5 ? `hsl(${120 - p * 120}, 80%, 60%)` : `hsl(${40 - u.angleDeg * 2}, 90%, 55%)`;
1566
+ return /* @__PURE__ */ W("group", { children: [
1567
+ /* @__PURE__ */ d(ge, { points: [y, f], color: m, lineWidth: 1.5, transparent: true, opacity: 0.7 }),
1568
+ /* @__PURE__ */ d(
1569
+ ge,
1570
+ {
1571
+ points: [new h(-a * 0.3, u.regionMin, 0), new h(a * 0.3, u.regionMin, 0)],
1572
+ color: m,
1573
+ lineWidth: 0.5,
1574
+ transparent: true,
1575
+ opacity: 0.3
1576
+ }
1577
+ )
1578
+ ] }, o);
1579
+ }) });
1580
+ }
1581
+ function Jn({ geometry: e, redY: s, greenY: n, modelSize: t }) {
1582
+ const i = de(() => {
1583
+ const f = rt(e, s, n);
1584
+ if (!f) return null;
1585
+ const y = f.dot(new h(0, 1, 0)), p = Math.acos(Math.min(1, Math.abs(y))) * 180 / Math.PI;
1586
+ return { axis: f, angleDeg: p };
1587
+ }, [e, s, n]);
1588
+ if (!i) return null;
1589
+ const a = (s + n) / 2, c = new h(0, a, 0), u = t * 0.4, o = c.clone().addScaledVector(i.axis, u), l = c.clone().addScaledVector(i.axis, -u), r = i.angleDeg < 0.5 ? "#00ffff" : i.angleDeg < 2 ? "#ffcc00" : "#ff6600";
1590
+ return /* @__PURE__ */ d("group", { children: /* @__PURE__ */ d(ge, { points: [l, o], color: r, lineWidth: 3, dashed: true, dashSize: 3, gapSize: 2 }) });
1591
+ }
1592
+ function eo({ pca: e, modelSize: s }) {
1593
+ const n = e.axes[0], t = s * 0.6, i = e.center.clone().addScaledVector(n, t), a = e.center.clone().addScaledVector(n, -t);
1594
+ return /* @__PURE__ */ d(ge, { points: [a, i], color: "#ff8800", lineWidth: 2, dashed: true, dashSize: 3, gapSize: 2 });
1595
+ }
1596
+ function to({ geometry: e, redY: s, greenY: n, modelSize: t }) {
1597
+ const i = de(() => {
1598
+ const l = ot(e), r = new h(0, 1, 0), f = 5;
1599
+ e.computeBoundingBox();
1600
+ const y = e.boundingBox.max.y, p = [];
1601
+ for (let C = s + f; C < y; C += f) {
1602
+ const M = pt(l, e, new h(0, C, 0), r);
1603
+ M > 0 && p.push({ y: C, circ: M });
1604
+ }
1605
+ if (p.length < 5) return null;
1606
+ const m = n - s, g = s + m * 0.3, z = s + m * 0.7, v = p.filter((C) => C.y >= g && C.y <= z);
1607
+ if (v.length < 3) return null;
1608
+ const x = v.map((C) => C.circ).sort((C, M) => C - M), b = x[Math.floor(x.length / 2)], w = Math.max(...p.map((C) => C.circ));
1609
+ return { circumferences: p, baseline: b, maxCirc: w };
1610
+ }, [e, s, n]);
1611
+ if (!i) return null;
1612
+ const { circumferences: a, baseline: c, maxCirc: u } = i, o = t * 0.3 / u;
1613
+ return /* @__PURE__ */ W("group", { children: [
1614
+ a.map(({ y: l, circ: r }, f) => {
1615
+ const y = r / c, p = y > 1.6 ? "#ff4444" : y > 1.3 ? "#ffcc00" : "#22cc66", m = r * o;
1616
+ return /* @__PURE__ */ d(
1617
+ ge,
1618
+ {
1619
+ points: [new h(-m, l, 0), new h(m, l, 0)],
1620
+ color: p,
1621
+ lineWidth: 1.5,
1622
+ transparent: true,
1623
+ opacity: 0.6
1624
+ },
1625
+ f
1626
+ );
1627
+ }),
1628
+ (() => {
1629
+ const l = c * 1.6 * o, r = a[0].y, f = a[a.length - 1].y;
1630
+ return /* @__PURE__ */ W(He, { children: [
1631
+ /* @__PURE__ */ d(
1632
+ ge,
1633
+ {
1634
+ points: [new h(-l, r, 0), new h(-l, f, 0)],
1635
+ color: "#ff4444",
1636
+ lineWidth: 1,
1637
+ dashed: true,
1638
+ dashSize: 3,
1639
+ gapSize: 2,
1640
+ transparent: true,
1641
+ opacity: 0.4
1642
+ }
1643
+ ),
1644
+ /* @__PURE__ */ d(
1645
+ ge,
1646
+ {
1647
+ points: [new h(l, r, 0), new h(l, f, 0)],
1648
+ color: "#ff4444",
1649
+ lineWidth: 1,
1650
+ dashed: true,
1651
+ dashSize: 3,
1652
+ gapSize: 2,
1653
+ transparent: true,
1654
+ opacity: 0.4
1655
+ }
1656
+ )
1657
+ ] });
1658
+ })()
1659
+ ] });
1660
+ }
1661
+ function no({ componentDebug: e }) {
1662
+ return /* @__PURE__ */ d("group", { children: e.geometries.map((s, n) => {
1663
+ const t = e.colors[n] ?? "#888888", i = n === e.innerIdx;
1664
+ s.computeBoundingBox();
1665
+ const a = new h();
1666
+ return s.boundingBox.getCenter(a), /* @__PURE__ */ W("group", { children: [
1667
+ /* @__PURE__ */ d("mesh", { geometry: s, renderOrder: i ? 2 : 1, children: /* @__PURE__ */ d(
1668
+ "meshStandardMaterial",
1669
+ {
1670
+ color: t,
1671
+ transparent: true,
1672
+ opacity: i ? 0.5 : 0.2,
1673
+ side: J.DoubleSide,
1674
+ depthWrite: false,
1675
+ polygonOffset: true,
1676
+ polygonOffsetFactor: 1,
1677
+ polygonOffsetUnits: 1
1678
+ }
1679
+ ) }),
1680
+ /* @__PURE__ */ d("mesh", { geometry: s, renderOrder: i ? 2 : 1, children: /* @__PURE__ */ d("meshBasicMaterial", { color: t, wireframe: true, transparent: true, opacity: i ? 0.4 : 0.15 }) }),
1681
+ /* @__PURE__ */ d("group", { position: a, children: /* @__PURE__ */ d(Ke, { center: true, style: { pointerEvents: "none" }, children: /* @__PURE__ */ d("div", { style: {
1682
+ padding: "2px 8px",
1683
+ backgroundColor: "rgba(0,0,0,0.8)",
1684
+ borderRadius: 4,
1685
+ border: `1px solid ${t}`,
1686
+ whiteSpace: "nowrap"
1687
+ }, children: /* @__PURE__ */ d("span", { style: { fontSize: 11, color: t, fontFamily: "monospace", fontWeight: i ? 700 : 400 }, children: e.labels[n] }) }) }) })
1688
+ ] }, n);
1689
+ }) });
1690
+ }
1691
+ function oo({ mesh: e, layers: s, landmarkPoints: n, componentDebug: t }) {
1692
+ const i = e.geometry, a = de(() => i.getAttribute("position") ? Ot(i) : null, [i]), c = de(() => !n || n.length < 2 ? null : {
1693
+ red: new h(n[0].position.x, n[0].position.y, n[0].position.z),
1694
+ green: new h(n[1].position.x, n[1].position.y, n[1].position.z)
1695
+ }, [n]);
1696
+ return /* @__PURE__ */ W("group", { children: [
1697
+ s.pcaAxes && a && /* @__PURE__ */ d(Kn, { pca: a }),
1698
+ s.obb && a && /* @__PURE__ */ d(Un, { pca: a }),
1699
+ s.obbAxis && a && /* @__PURE__ */ d(eo, { pca: a, modelSize: a.halfExtents[0] ? Math.max(...a.halfExtents) * 2 : 100 }),
1700
+ s.shellComponents && t && /* @__PURE__ */ d(no, { componentDebug: t }),
1701
+ s.circumferenceScan && c && /* @__PURE__ */ d(
1702
+ to,
1703
+ {
1704
+ geometry: i,
1705
+ redY: c.red.y,
1706
+ greenY: c.green.y,
1707
+ modelSize: (a == null ? void 0 : a.halfExtents[0]) ? Math.max(...a.halfExtents) * 2 : 100
1708
+ }
1709
+ ),
1710
+ s.landmarkAxis && c && /* @__PURE__ */ d(Qn, { redPoint: c.red, greenPoint: c.green }),
1711
+ s.iterativePCA && c && /* @__PURE__ */ d(
1712
+ qn,
1713
+ {
1714
+ geometry: i,
1715
+ redY: c.red.y,
1716
+ greenY: c.green.y,
1717
+ modelSize: (a == null ? void 0 : a.halfExtents[0]) ? Math.max(...a.halfExtents) * 2 : 100
1718
+ }
1719
+ ),
1720
+ s.fullRegionPCA && c && /* @__PURE__ */ d(
1721
+ Jn,
1722
+ {
1723
+ geometry: i,
1724
+ redY: c.red.y,
1725
+ greenY: c.green.y,
1726
+ modelSize: (a == null ? void 0 : a.halfExtents[0]) ? Math.max(...a.halfExtents) * 2 : 100
1727
+ }
1728
+ )
1729
+ ] });
1730
+ }
1731
+ function so({ mesh: e }) {
1732
+ const s = e.geometry, n = de(() => {
1733
+ if (!s.getAttribute("position")) return null;
1734
+ const a = Ot(s), c = a.axes[0], u = a.halfExtents[0] * 1.3;
1735
+ return { axis: c, center: a.center, halfLen: u };
1736
+ }, [s]);
1737
+ if (!n) return null;
1738
+ const t = n.center.clone().addScaledVector(n.axis, n.halfLen), i = n.center.clone().addScaledVector(n.axis, -n.halfLen);
1739
+ return /* @__PURE__ */ d(ge, { points: [i, t], color: "#666", lineWidth: 1, dashed: true, dashSize: 4, gapSize: 3, transparent: true, opacity: 0.4, depthTest: false, renderOrder: 999 });
1740
+ }
1741
+ const $t = [
1742
+ { key: "pcaAxes", label: "PCA Axes (full mesh)", color: "#ff4444", group: "Geometry" },
1743
+ { key: "obb", label: "OBB Wireframe", color: "#ffaa00", group: "Geometry" },
1744
+ { key: "obbAxis", label: "OBB Primary Axis", color: "#ff8800", group: "Geometry" },
1745
+ { key: "shellComponents", label: "Shell Components", color: "#4488ff", group: "Shell Detection" },
1746
+ { key: "circumferenceScan", label: "Circumference Scan (step 4.5)", color: "#22cc66", group: "Isolation" },
1747
+ { key: "landmarkAxis", label: "Landmark Axis (rough align)", color: "#44ff44", group: "Alignment" },
1748
+ { key: "iterativePCA", label: "Iterative PCA (step 5)", color: "#cc66ff", group: "Alignment" },
1749
+ { key: "fullRegionPCA", label: "Full Region PCA (step 7)", color: "#00ffff", group: "Alignment" }
1750
+ ], ro = [...new Set($t.map((e) => e.group))];
1751
+ function io({ layers: e, onToggleLayer: s }) {
1752
+ return /* @__PURE__ */ W("div", { style: {
1753
+ position: "absolute",
1754
+ top: 16,
1755
+ left: 16,
1756
+ zIndex: 20,
1757
+ backgroundColor: "rgba(7, 6, 17, 0.9)",
1758
+ border: "1px solid rgba(255,255,255,0.1)",
1759
+ borderRadius: 6,
1760
+ padding: "10px 12px",
1761
+ fontFamily: "system-ui, sans-serif",
1762
+ fontSize: 12,
1763
+ color: "#ccc",
1764
+ minWidth: 180,
1765
+ backdropFilter: "blur(8px)"
1766
+ }, children: [
1767
+ /* @__PURE__ */ d("div", { style: { fontSize: 10, fontWeight: 600, textTransform: "uppercase", letterSpacing: "0.5px", color: "#888", marginBottom: 8 }, children: "Debug Layers" }),
1768
+ ro.map((n) => /* @__PURE__ */ W("div", { children: [
1769
+ /* @__PURE__ */ d("div", { style: { fontSize: 9, fontWeight: 600, textTransform: "uppercase", letterSpacing: "0.5px", color: "#555", marginTop: 6, marginBottom: 4 }, children: n }),
1770
+ $t.filter((t) => t.group === n).map(({ key: t, label: i, color: a }) => /* @__PURE__ */ W("label", { style: {
1771
+ display: "flex",
1772
+ alignItems: "center",
1773
+ gap: 8,
1774
+ padding: "3px 0",
1775
+ cursor: "pointer",
1776
+ userSelect: "none"
1777
+ }, children: [
1778
+ /* @__PURE__ */ d(
1779
+ "input",
1780
+ {
1781
+ type: "checkbox",
1782
+ checked: e[t],
1783
+ onChange: () => s(t),
1784
+ style: { accentColor: a, width: 14, height: 14, cursor: "pointer" }
1785
+ }
1786
+ ),
1787
+ /* @__PURE__ */ d("span", { style: {
1788
+ width: 8,
1789
+ height: 8,
1790
+ borderRadius: "50%",
1791
+ backgroundColor: a,
1792
+ opacity: e[t] ? 1 : 0.3,
1793
+ flexShrink: 0
1794
+ } }),
1795
+ /* @__PURE__ */ d("span", { style: { opacity: e[t] ? 1 : 0.5 }, children: i })
1796
+ ] }, t))
1797
+ ] }, n))
1798
+ ] });
1799
+ }
1800
+ const lo = ({
1801
+ config: e,
1802
+ spacingType: s,
1803
+ scanUrl: n,
1804
+ formMeasurements: t,
1805
+ onComplete: i,
1806
+ isDebugUser: a = false,
1807
+ onAnalyticsEvent: c,
1808
+ wasmModule: u
1809
+ }) => {
1810
+ const [o, l] = q(null), [r, f] = q(0), [y, p] = q(false), [m, g] = q(false), [z, v] = q(""), [x, b] = q("3D"), [w, C] = q(
1811
+ s === "AK" ? 2 : 1
1812
+ ), [M, L] = q(false), [P, H] = q(null), [O, $] = q(null), [R, Y] = q(s ?? null), [N, ne] = q("mm"), [oe, le] = q(false), [ee, D] = q(""), [S, F] = q(false), [V, B] = q(false), [T, E] = q(false), [j, X] = q(false), [Q, ie] = q(false), [se, A] = q([]), [I, k] = q(null), [G, U] = q(null), [re, Pe] = q(null), [me, ae] = q(null), [xe, Re] = q(false), [pe, we] = q(Xn), [he, Ge] = q(false), [fe, Ne] = q(null), [Le, ye] = q("obj"), [Te, Me] = q(false), [Ae, De] = q({}), [Se, Ee] = q(
1813
+ t
1814
+ ), [ke, Ue] = q(true), [mt] = q("#c8c8c8"), [jt] = q(1), [Xe, Ht] = q(false), lt = Ie(null), {
1815
+ landmarkPoints: ce,
1816
+ clearLandmarkPoints: Yt,
1817
+ addLandmarkPoint: xt,
1818
+ removeLandmarkPoint: yt,
1819
+ updateLandmarkPositions: bt,
1820
+ setAligned: wt,
1821
+ isAligned: be,
1822
+ setCut: St,
1823
+ isCut: Gt
1824
+ } = gt(), at = w * We;
1825
+ Ce(() => {
1826
+ t && Ee(t);
1827
+ }, [t]), Ce(() => {
1828
+ t || (Ee(void 0), De({}));
1829
+ }, [w]);
1830
+ const ct = Ie(false);
1831
+ Ce(() => {
1832
+ if (!be || se.length === 0 || ct.current || !c) return;
1833
+ ct.current = true;
1834
+ const _ = ce.length >= 3 ? Math.abs(ce[2].position.y - ce[1].position.y) : null;
1835
+ c("dimensions_calculated", {
1836
+ spacing_type: R,
1837
+ source_unit: "mm",
1838
+ file_format: Le,
1839
+ measurement_source: "scan_derived",
1840
+ is_double_wall: T,
1841
+ is_unit_converted: false,
1842
+ form_measurements: (Se == null ? void 0 : Se.filter((K) => K != null)) ?? null,
1843
+ scan_measurements: se.map((K) => +(K.modifiedValue ?? K.originalValue).toFixed(1)),
1844
+ measurement_variance: Se ? se.map((K, ue) => {
1845
+ const Z = Se[ue];
1846
+ return Z == null ? null : +((K.modifiedValue ?? K.originalValue) - Z).toFixed(1);
1847
+ }) : null,
1848
+ frontal_height: _ !== null ? +_.toFixed(1) : null
1849
+ });
1850
+ }, [be, se]), Ce(() => {
1851
+ u !== void 0 && (lt.current = u, Ht(true));
1852
+ }, [u]);
1853
+ const Qe = Fe((_, K) => {
1854
+ _.computeBoundingBox();
1855
+ const ue = _.boundingBox, Z = new h();
1856
+ ue.getCenter(Z), _.translate(-Z.x, -Z.y, -Z.z), _.computeBoundingBox();
1857
+ const Be = _.boundingBox, te = new h();
1858
+ Be.getSize(te), f(Math.max(te.x, te.y, te.z));
1859
+ const ve = new J.Mesh(
1860
+ _,
1861
+ new J.MeshStandardMaterial({ color: 8947848, side: J.DoubleSide })
1862
+ );
1863
+ l(ve), F(K), B(true);
1864
+ }, []), qe = Fe(async (_, K) => {
1865
+ ae(null);
1866
+ const ue = K.toLowerCase(), Z = ue.endsWith(".stl");
1867
+ if (!ue.endsWith(".obj") && !Z) {
1868
+ ae("Unsupported file format. Please use OBJ or STL.");
1869
+ return;
1870
+ }
1871
+ ye(Z ? "stl" : "obj"), g(true), v("Processing file...");
1872
+ try {
1873
+ let te;
1874
+ if (Z)
1875
+ if (v("Converting STL..."), _ instanceof ArrayBuffer) {
1876
+ const ze = new Blob([_]), Ve = new File([ze], K);
1877
+ te = await ft(Ve);
1878
+ } else {
1879
+ const ze = new Blob([_]), Ve = new File([ze], K);
1880
+ te = await ft(Ve);
1881
+ }
1882
+ else
1883
+ te = typeof _ == "string" ? _ : new TextDecoder().decode(_);
1884
+ const ve = lt.current ? await bn(te, lt.current, v) : null;
1885
+ if (ve)
1886
+ e.showAmputationModal && !s ? (H(ve), L(true)) : (Qe(ve.geometry, ve.wasScaled), ve.innerShellExtracted && (X(true), E(true)), ve.componentDebug && $(ve.componentDebug));
1887
+ else {
1888
+ v("Using fallback loader...");
1889
+ const ze = wn(te);
1890
+ ze ? e.showAmputationModal && !s ? (H({ geometry: ze, wasScaled: false, innerShellExtracted: false }), L(true)) : Qe(ze, false) : ae("Failed to parse the mesh.");
1891
+ }
1892
+ } catch (te) {
1893
+ ae(te instanceof Error ? te.message : "Failed to process the mesh file.");
1894
+ } finally {
1895
+ g(false), v("");
1896
+ }
1897
+ }, [Xe, e.showAmputationModal, s, Qe]);
1898
+ Ce(() => {
1899
+ if (!n || !Xe) return;
1900
+ (async () => {
1901
+ g(true), v("Downloading scan...");
1902
+ try {
1903
+ const K = await fetch(n);
1904
+ if (!K.ok) throw new Error(`Failed to download scan: ${K.status}`);
1905
+ const Z = new URL(n).pathname.split("/").pop() || "scan.obj";
1906
+ if (Z.toLowerCase().endsWith(".stl")) {
1907
+ const te = await K.arrayBuffer();
1908
+ await qe(te, Z);
1909
+ } else {
1910
+ const te = await K.text();
1911
+ await qe(te, Z);
1912
+ }
1913
+ } catch (K) {
1914
+ ae(K instanceof Error ? K.message : "Failed to load scan from URL."), g(false), v("");
1915
+ }
1916
+ })();
1917
+ }, [n, Xe]);
1918
+ const Xt = Fe((_) => {
1919
+ _.preventDefault(), p(true);
1920
+ }, []), Zt = Fe((_) => {
1921
+ _.preventDefault(), p(false);
1922
+ }, []), Kt = Fe(async (_) => {
1923
+ if (_.preventDefault(), p(false), !Xe) {
1924
+ ae("WASM module is still loading. Please wait.");
1925
+ return;
1926
+ }
1927
+ const K = _.dataTransfer.files[0];
1928
+ if (!K) return;
1929
+ const ue = K.name.toLowerCase();
1930
+ if (!ue.endsWith(".obj") && !ue.endsWith(".stl")) {
1931
+ ae("Please drop an OBJ or STL file.");
1932
+ return;
1933
+ }
1934
+ if (ue.endsWith(".stl")) {
1935
+ ye("stl"), g(true), v("Converting STL...");
1936
+ try {
1937
+ const Z = await ft(K);
1938
+ await qe(Z, K.name);
1939
+ } catch (Z) {
1940
+ ae(Z instanceof Error ? Z.message : "Failed to process STL file."), g(false), v("");
1941
+ }
1942
+ } else {
1943
+ const Z = await K.text();
1944
+ await qe(Z, K.name);
1945
+ }
1946
+ }, [Xe, qe]), Ut = Fe((_) => {
1947
+ Y(_), C(_ === "AK" ? 2 : 1), L(false), P && (Qe(P.geometry, P.wasScaled), P.innerShellExtracted && (X(true), E(true)), P.componentDebug && $(P.componentDebug), H(null)), c == null ? void 0 : c("file_loaded", {
1948
+ spacing_type: _,
1949
+ file_format: Le,
1950
+ is_double_wall: (P == null ? void 0 : P.innerShellExtracted) ?? false
1951
+ });
1952
+ }, [P, Qe, c, Le]), Qt = Fe(() => {
1953
+ !o || ce.length < 2 || (le(true), D("Please wait..."), setTimeout(() => {
1954
+ In(o, ce, at, {
1955
+ onStatus: D,
1956
+ addLandmarkPoint: xt,
1957
+ removeLandmarkPoint: yt,
1958
+ updateLandmarkPositions: bt,
1959
+ setAligned: wt,
1960
+ setCut: St,
1961
+ setModelSize: f,
1962
+ setOriginalEndY: Pe,
1963
+ setAdjustedStartY: k,
1964
+ setAdjustedEndY: U,
1965
+ setError: ae,
1966
+ setDoubleShell: (_) => {
1967
+ E(_), ie(true);
1968
+ },
1969
+ setClippedReferenceGeometry: Ne,
1970
+ skipDoubleShellDetection: j
1971
+ }), ct.current = false, le(false);
1972
+ }, 50));
1973
+ }, [o, ce, bt, wt, xt, yt, St, at, j]), qt = Fe(() => {
1974
+ if (!i || !o || se.length === 0 || !R) return;
1975
+ let _ = 0, K = 0;
1976
+ const ue = ce.length >= 3 ? Math.abs(ce[2].position.y - ce[1].position.y) : 0;
1977
+ if (ce.length >= 2) {
1978
+ const Z = o.geometry, te = ce[1].position.y;
1979
+ try {
1980
+ const ve = ot(Z), ze = Ze(ve, Z, te);
1981
+ if (ze.linePoints.length >= 2) {
1982
+ let Ve = ze.linePoints[0], Je = ze.linePoints[0], et = ze.linePoints[0], tt = ze.linePoints[0];
1983
+ for (const _e of ze.linePoints)
1984
+ _e.x < Ve.x && (Ve = _e), _e.x > Je.x && (Je = _e), _e.z < et.z && (et = _e), _e.z > tt.z && (tt = _e);
1985
+ _ = 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));
1986
+ }
1987
+ } catch {
1988
+ }
1989
+ }
1990
+ i({
1991
+ spacingType: R,
1992
+ sourceUnit: "mm",
1993
+ fileFormat: Le,
1994
+ measurementSource: Se ? "form_provided" : "scan_derived",
1995
+ isDoubleWall: T,
1996
+ isUnitConverted: false,
1997
+ formMeasurements: Se,
1998
+ scanMeasurements: se,
1999
+ frontalHeight: ue,
2000
+ transverseML: _,
2001
+ transverseAP: K,
2002
+ scanUrl: n
2003
+ });
2004
+ }, [i, o, se, R, ce, Le, T, Se, n]), Jt = be ? 4 : o ? ce.length === 0 ? 2 : 3 : 1, en = [
2005
+ { label: "Load File", number: 1 },
2006
+ { label: "Set Origin", number: 2 },
2007
+ { label: R === "AK" ? "Set IT/Perineum" : "Set MPT", number: 3 },
2008
+ { label: "Results", number: 4 }
2009
+ ];
2010
+ return /* @__PURE__ */ W(dn.Provider, { value: e, children: [
2011
+ /* @__PURE__ */ W("div", { style: { flex: 1, display: "flex", flexDirection: "column", backgroundColor: "#F9F9FA", minWidth: 0, position: "relative", height: "100%" }, children: [
2012
+ e.showToolbar && /* @__PURE__ */ d("div", { style: { height: 83, backgroundColor: "#9e9e9e", flexShrink: 0, position: "relative", overflow: "hidden" }, children: /* @__PURE__ */ d("div", { style: { position: "absolute", inset: 0, opacity: 0.1, backgroundImage: "repeating-linear-gradient(45deg, transparent, transparent 10px, #fff 10px, #fff 12px)", pointerEvents: "none" } }) }),
2013
+ /* @__PURE__ */ d(Yn, { steps: en, currentStep: Jt }),
2014
+ /* @__PURE__ */ W("div", { style: { flex: 1, display: "flex", flexDirection: "column", minHeight: 0 }, children: [
2015
+ /* @__PURE__ */ W(
2016
+ "div",
2017
+ {
2018
+ style: { flex: 1, position: "relative", minHeight: 0, overflow: "hidden" },
2019
+ onDragOver: e.showDragDrop ? Xt : void 0,
2020
+ onDragLeave: e.showDragDrop ? Zt : void 0,
2021
+ onDrop: e.showDragDrop ? Kt : void 0,
2022
+ children: [
2023
+ e.showDragDrop && !o && !m && /* @__PURE__ */ d("div", { style: { position: "absolute", inset: 16, border: "3px dashed #ccc", borderRadius: 4, display: "flex", alignItems: "center", justifyContent: "center", pointerEvents: "none" }, children: Xe ? /* @__PURE__ */ d("div", { style: { fontSize: 18, color: "#aaa", fontWeight: 400, fontFamily: "system-ui, sans-serif" }, children: "Drag & Drop Files Here" }) : /* @__PURE__ */ W("div", { style: { textAlign: "center" }, children: [
2024
+ /* @__PURE__ */ d("div", { style: { width: 32, height: 32, border: "3px solid rgba(0,0,0,0.1)", borderTopColor: "#4a90d9", borderRadius: "50%", animation: "spin 1s linear infinite", margin: "0 auto 12px" } }),
2025
+ /* @__PURE__ */ d("div", { style: { fontSize: 16, color: "#999", fontFamily: "system-ui, sans-serif" }, children: "Loading WASM module..." }),
2026
+ /* @__PURE__ */ d("style", { children: "@keyframes spin { to { transform: rotate(360deg); } }" })
2027
+ ] }) }),
2028
+ !e.showDragDrop && !o && !m && !me && /* @__PURE__ */ d("div", { style: { position: "absolute", inset: 0, display: "flex", alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ W("div", { style: { textAlign: "center" }, children: [
2029
+ /* @__PURE__ */ d("div", { style: { width: 32, height: 32, border: "3px solid rgba(0,0,0,0.1)", borderTopColor: "#4a90d9", borderRadius: "50%", animation: "spin 1s linear infinite", margin: "0 auto 12px" } }),
2030
+ /* @__PURE__ */ d("div", { style: { fontSize: 16, color: "#999", fontFamily: "system-ui, sans-serif" }, children: "Loading scan..." }),
2031
+ /* @__PURE__ */ d("style", { children: "@keyframes spin { to { transform: rotate(360deg); } }" })
2032
+ ] }) }),
2033
+ o && !be && ce.length === 0 && /* @__PURE__ */ W("div", { style: { position: "absolute", top: 16, left: "50%", transform: "translateX(-50%)", display: "flex", alignItems: "center", gap: 8, padding: "8px 16px", backgroundColor: "rgba(0, 0, 0, 0.6)", borderRadius: 8, color: "#fff", fontSize: 13, pointerEvents: "none", zIndex: 5, fontFamily: "system-ui, sans-serif" }, children: [
2034
+ /* @__PURE__ */ d("div", { style: { width: 10, height: 10, borderRadius: "50%", backgroundColor: "#ff4444", flexShrink: 0 } }),
2035
+ "Click mesh to set Origin"
2036
+ ] }),
2037
+ o && !be && ce.length === 1 && /* @__PURE__ */ W("div", { style: { position: "absolute", top: 16, left: "50%", transform: "translateX(-50%)", display: "flex", alignItems: "center", gap: 8, padding: "8px 16px", backgroundColor: "rgba(0, 0, 0, 0.6)", borderRadius: 8, color: "#fff", fontSize: 13, pointerEvents: "none", zIndex: 5, fontFamily: "system-ui, sans-serif" }, children: [
2038
+ /* @__PURE__ */ d("div", { style: { width: 10, height: 10, borderRadius: "50%", backgroundColor: "#44ff44", flexShrink: 0 } }),
2039
+ "Click mesh to set ",
2040
+ R === "AK" ? "IT/Perineum" : "MPT"
2041
+ ] }),
2042
+ m && /* @__PURE__ */ d(At, { message: z || "Processing mesh..." }),
2043
+ oe && /* @__PURE__ */ d(At, { message: ee }),
2044
+ me && /* @__PURE__ */ d(Pn, { message: me, onDismiss: () => ae(null) }),
2045
+ e.showAmputationModal && M && /* @__PURE__ */ d("div", { style: { position: "absolute", inset: 0, backgroundColor: "rgba(0,0,0,0.32)", display: "flex", alignItems: "center", justifyContent: "center", zIndex: 20 }, children: /* @__PURE__ */ W("div", { style: { backgroundColor: "#fff", borderRadius: 4, width: 560, 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)", fontFamily: "system-ui, sans-serif" }, children: [
2046
+ /* @__PURE__ */ W("div", { style: { padding: "24px 24px 20px" }, children: [
2047
+ /* @__PURE__ */ d("div", { style: { fontSize: 20, fontWeight: 500, color: "rgba(0,0,0,0.87)", marginBottom: 8 }, children: "Select Spacing Type" }),
2048
+ /* @__PURE__ */ d("div", { style: { fontSize: 14, color: "rgba(0,0,0,0.54)", marginBottom: 24 }, children: "Choose the measurement spacing for this scan" }),
2049
+ /* @__PURE__ */ d("div", { style: { display: "flex", gap: 16 }, children: ["AK", "BK"].map((_) => /* @__PURE__ */ W("label", { onClick: () => Y(_), style: { flex: 1, display: "flex", flexDirection: "column", padding: "20px 24px", border: "2px solid", borderRadius: 4, cursor: "pointer", borderColor: R === _ ? "rgb(12, 67, 173)" : "#e0e0e0", backgroundColor: R === _ ? "rgba(12, 67, 173, 0.04)" : "#fff", transition: "border-color 0.15s, background-color 0.15s" }, children: [
2050
+ /* @__PURE__ */ d("input", { type: "radio", name: "ampType", checked: R === _, onChange: () => Y(_), style: { accentColor: "rgb(12, 67, 173)", marginBottom: 12, width: 18, height: 18 } }),
2051
+ /* @__PURE__ */ d("span", { style: { fontSize: 18, fontWeight: 600, color: "rgba(0,0,0,0.87)", marginBottom: 4 }, children: _ }),
2052
+ /* @__PURE__ */ W("span", { style: { fontSize: 13, color: "rgba(0,0,0,0.54)" }, children: [
2053
+ _ === "AK" ? "2" : "1",
2054
+ "-inch measurement spacing"
2055
+ ] })
2056
+ ] }, _)) })
2057
+ ] }),
2058
+ /* @__PURE__ */ W("div", { style: { display: "flex", justifyContent: "flex-end", gap: 8, padding: "12px 24px 20px", borderTop: "1px solid #e0e0e0" }, children: [
2059
+ /* @__PURE__ */ d("button", { onClick: () => {
2060
+ L(false), H(null);
2061
+ }, style: { padding: "6px 16px", borderRadius: 4, fontSize: 14, fontWeight: 500, backgroundColor: "#fff", border: "1px solid #bdbdbd", color: "rgba(0,0,0,0.87)", cursor: "pointer", fontFamily: "system-ui, sans-serif", lineHeight: "36px", letterSpacing: "0.4px" }, children: "Cancel" }),
2062
+ /* @__PURE__ */ d("button", { onClick: () => R && Ut(R), disabled: !R, style: { padding: "6px 16px", borderRadius: 4, fontSize: 14, fontWeight: 500, backgroundColor: R ? "rgb(12, 67, 173)" : "#e0e0e0", border: "none", color: R ? "#fff" : "#9e9e9e", cursor: R ? "pointer" : "not-allowed", fontFamily: "system-ui, sans-serif", lineHeight: "36px", letterSpacing: "0.4px" }, children: "Next \xBB" })
2063
+ ] })
2064
+ ] }) }),
2065
+ e.showDragDrop && y && /* @__PURE__ */ d("div", { style: { position: "absolute", inset: 0, backgroundColor: "rgba(12, 67, 173, 0.1)", border: "2px dashed rgb(12, 67, 173)", pointerEvents: "none", zIndex: 10 } }),
2066
+ /* @__PURE__ */ W(sn, { camera: { position: [0, 0, 5] }, style: { display: o ? "block" : "none", backgroundColor: xe ? "#070611" : void 0 }, gl: { localClippingEnabled: true }, scene: { background: xe ? new J.Color("#070611") : null }, children: [
2067
+ /* @__PURE__ */ d("ambientLight", { intensity: 0.4 }),
2068
+ /* @__PURE__ */ d("directionalLight", { position: [10, 10, 5], intensity: 1.2 }),
2069
+ /* @__PURE__ */ d("directionalLight", { position: [-5, 5, -5], intensity: 0.4 }),
2070
+ /* @__PURE__ */ d("directionalLight", { position: [0, -10, 0], intensity: 0.2 }),
2071
+ o && x === "3D" && /* @__PURE__ */ d(Ln, { mesh: o, maxPoints: 2, meshColor: mt, meshOpacity: xe ? 0.3 : jt }),
2072
+ he && fe && x === "3D" && /* @__PURE__ */ d("mesh", { geometry: fe, renderOrder: 1, children: /* @__PURE__ */ d("meshStandardMaterial", { color: "#c8c8c8", transparent: true, opacity: 0.35, side: J.DoubleSide, depthWrite: false, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 1 }) }),
2073
+ o && x === "3D" && /* @__PURE__ */ d(Tn, { modelSize: r, labels: ["Origin", R === "AK" ? "IT/Perineum" : "MPT", "Cut Plane"] }),
2074
+ /* @__PURE__ */ d(
2075
+ $n,
2076
+ {
2077
+ modelSize: r,
2078
+ isAligned: be,
2079
+ isCut: Gt,
2080
+ mesh: o,
2081
+ viewMode: x,
2082
+ sliceY: be && ce.length >= 2 ? G ?? re ?? ce[1].position.y : void 0,
2083
+ landmarkCount: ce.length
2084
+ }
2085
+ ),
2086
+ !be && /* @__PURE__ */ d(Dt, { enableDamping: false }),
2087
+ be && se.length > 0 && o && x === "3D" && /* @__PURE__ */ d(Nn, { mesh: o, isDragging: false }),
2088
+ o && be && ce.length >= 3 && (() => {
2089
+ const K = o.geometry.getIndex();
2090
+ if (!K || K.count < 30) return null;
2091
+ const ue = ce[2], Z = ce[1], Be = I ?? ue.position.y, te = G ?? re ?? Z.position.y;
2092
+ return x === "2D" ? /* @__PURE__ */ d(Gn, { mesh: o, upperY: te, originY: Z.position.y, modelSize: r, meshColor: mt, displayUnit: N }) : /* @__PURE__ */ W(He, { children: [
2093
+ /* @__PURE__ */ d(
2094
+ _n,
2095
+ {
2096
+ mesh: o,
2097
+ startY: Be,
2098
+ endY: te,
2099
+ spacing: at,
2100
+ modelSize: r,
2101
+ onMeasurementsChange: A,
2102
+ reverseOrder: true,
2103
+ displayUnit: N,
2104
+ useInnerSurface: T && !j,
2105
+ formMeasurements: ke ? Se : void 0,
2106
+ originY: Z.position.y
2107
+ }
2108
+ ),
2109
+ (!T || j) && /* @__PURE__ */ d(On, { mesh: o, greenY: Z.position.y, modelSize: r, displayUnit: N })
2110
+ ] });
2111
+ })(),
2112
+ o && be && x === "3D" && /* @__PURE__ */ d(so, { mesh: o }),
2113
+ o && e.showDebug && xe && x === "3D" && /* @__PURE__ */ d(oo, { mesh: o, modelSize: r, layers: pe, landmarkPoints: ce, componentDebug: O })
2114
+ ] }),
2115
+ o && (e.showStartOver || e.showInsertMeasurement) && /* @__PURE__ */ W("div", { style: { position: "absolute", top: 16, left: 16, zIndex: 10, display: "flex", gap: 8 }, children: [
2116
+ e.showStartOver && /* @__PURE__ */ d("button", { onClick: () => window.location.reload(), style: { padding: "6px 16px", borderRadius: 4, fontSize: 13, fontWeight: 500, backgroundColor: "#fff", border: "1px solid #bdbdbd", color: "#333", cursor: "pointer", fontFamily: "system-ui, sans-serif", letterSpacing: "0.4px", boxShadow: "0 2px 8px rgba(0,0,0,0.1)" }, children: "Start Over" }),
2117
+ e.showInsertMeasurement && /* @__PURE__ */ d("button", { onClick: () => Me(true), style: { padding: "6px 16px", borderRadius: 4, fontSize: 13, fontWeight: 500, backgroundColor: "rgb(12, 67, 173)", border: "none", color: "#fff", cursor: "pointer", fontFamily: "system-ui, sans-serif", letterSpacing: "0.4px", boxShadow: "0 2px 8px rgba(0,0,0,0.1)" }, children: "Insert Measurement" })
2118
+ ] }),
2119
+ e.showDebug && xe && o && x === "3D" && /* @__PURE__ */ d(io, { layers: pe, onToggleLayer: (_) => we((K) => ({ ...K, [_]: !K[_] })) }),
2120
+ be && se.length > 0 && /* @__PURE__ */ W("div", { style: { position: "absolute", top: 16, right: 16, display: "flex", gap: 8, zIndex: 10 }, children: [
2121
+ /* @__PURE__ */ W("div", { style: { display: "flex", borderRadius: 6, overflow: "hidden", border: "1px solid #ccc", boxShadow: "0 2px 8px rgba(0,0,0,0.1)" }, children: [
2122
+ /* @__PURE__ */ d("button", { onClick: () => b("3D"), style: { padding: "6px 14px", fontSize: 13, fontWeight: x === "3D" ? 600 : 400, backgroundColor: x === "3D" ? "rgb(12, 67, 173)" : "#fff", color: x === "3D" ? "#fff" : "#666", border: "none", cursor: "pointer", fontFamily: "system-ui, sans-serif" }, children: "Frontal" }),
2123
+ /* @__PURE__ */ d("button", { onClick: () => b("2D"), style: { padding: "6px 14px", fontSize: 13, fontWeight: x === "2D" ? 600 : 400, backgroundColor: x === "2D" ? "rgb(12, 67, 173)" : "#fff", color: x === "2D" ? "#fff" : "#666", border: "none", borderLeft: "1px solid #ccc", cursor: "pointer", fontFamily: "system-ui, sans-serif" }, children: "Transverse" })
2124
+ ] }),
2125
+ /* @__PURE__ */ W("div", { style: { display: "flex", borderRadius: 6, overflow: "hidden", border: "1px solid #ccc", boxShadow: "0 2px 8px rgba(0,0,0,0.1)" }, children: [
2126
+ /* @__PURE__ */ d("button", { onClick: () => ne("mm"), style: { padding: "6px 14px", fontSize: 13, fontWeight: N === "mm" ? 600 : 400, backgroundColor: N === "mm" ? "rgb(12, 67, 173)" : "#fff", color: N === "mm" ? "#fff" : "#666", border: "none", cursor: "pointer", fontFamily: "system-ui, sans-serif" }, children: "mm" }),
2127
+ /* @__PURE__ */ d("button", { onClick: () => ne("inch"), style: { padding: "6px 14px", fontSize: 13, fontWeight: N === "inch" ? 600 : 400, backgroundColor: N === "inch" ? "rgb(12, 67, 173)" : "#fff", color: N === "inch" ? "#fff" : "#666", border: "none", borderLeft: "1px solid #ccc", cursor: "pointer", fontFamily: "system-ui, sans-serif" }, children: "in" })
2128
+ ] }),
2129
+ e.showSpacingToggle && x === "3D" && /* @__PURE__ */ W("div", { style: { display: "flex", borderRadius: 6, overflow: "hidden", border: "1px solid #ccc", boxShadow: "0 2px 8px rgba(0,0,0,0.1)" }, children: [
2130
+ /* @__PURE__ */ d("button", { onClick: () => C(1), style: { padding: "6px 14px", fontSize: 13, fontWeight: w === 1 ? 600 : 400, backgroundColor: w === 1 ? "rgb(12, 67, 173)" : "#fff", color: w === 1 ? "#fff" : "#666", border: "none", cursor: "pointer", fontFamily: "system-ui, sans-serif" }, children: '1"' }),
2131
+ /* @__PURE__ */ d("button", { onClick: () => C(2), style: { padding: "6px 14px", fontSize: 13, fontWeight: w === 2 ? 600 : 400, backgroundColor: w === 2 ? "rgb(12, 67, 173)" : "#fff", color: w === 2 ? "#fff" : "#666", border: "none", borderLeft: "1px solid #ccc", cursor: "pointer", fontFamily: "system-ui, sans-serif" }, children: '2"' })
2132
+ ] }),
2133
+ x === "3D" && fe && /* @__PURE__ */ d("div", { style: { display: "flex", borderRadius: 6, overflow: "hidden", border: "1px solid #ccc", boxShadow: "0 2px 8px rgba(0,0,0,0.1)" }, children: /* @__PURE__ */ d("button", { onClick: () => Ge((_) => !_), style: { padding: "6px 14px", fontSize: 13, fontWeight: he ? 600 : 400, backgroundColor: he ? "rgb(12, 67, 173)" : "#fff", color: he ? "#fff" : "#666", border: "none", cursor: "pointer", fontFamily: "system-ui, sans-serif" }, children: "Show Full Scan" }) }),
2134
+ x === "3D" && Se && /* @__PURE__ */ d("div", { style: { display: "flex", borderRadius: 6, overflow: "hidden", border: "1px solid #ccc", boxShadow: "0 2px 8px rgba(0,0,0,0.1)" }, children: /* @__PURE__ */ d("button", { onClick: () => Ue((_) => !_), style: { padding: "6px 14px", fontSize: 13, fontWeight: ke ? 600 : 400, backgroundColor: ke ? "rgb(12, 67, 173)" : "#fff", color: ke ? "#fff" : "#666", border: "none", cursor: "pointer", fontFamily: "system-ui, sans-serif" }, children: "Form Overlay" }) }),
2135
+ e.showDebug && a && /* @__PURE__ */ d("div", { style: { display: "flex", borderRadius: 6, overflow: "hidden", border: "1px solid #ccc", boxShadow: "0 2px 8px rgba(0,0,0,0.1)" }, children: /* @__PURE__ */ d("button", { onClick: () => Re((_) => !_), style: { padding: "6px 14px", fontSize: 13, fontWeight: xe ? 600 : 400, backgroundColor: xe ? "#e65100" : "#fff", color: xe ? "#fff" : "#666", border: "none", cursor: "pointer", fontFamily: "system-ui, sans-serif" }, children: "Debug" }) })
2136
+ ] }),
2137
+ o && V && /* @__PURE__ */ d(jn, { wasAutoScaled: S, onDismiss: () => B(false) }),
2138
+ o && Q && be && /* @__PURE__ */ d(Hn, { isDoubleShell: T, onDismiss: () => ie(false) })
2139
+ ]
2140
+ }
2141
+ ),
2142
+ /* @__PURE__ */ W("div", { style: { padding: "12px 24px", backgroundColor: "#fff", borderTop: "1px solid #e0e0e0", display: "flex", alignItems: "center", justifyContent: "flex-end", gap: 8, flexShrink: 0 }, children: [
2143
+ o && !be && ce.length >= 2 && /* @__PURE__ */ d("button", { onClick: Qt, style: { padding: "6px 16px", borderRadius: 4, fontSize: 14, fontWeight: 500, backgroundColor: "rgb(12, 67, 173)", border: "none", color: "#fff", cursor: "pointer", fontFamily: "system-ui, sans-serif", letterSpacing: "0.4px", lineHeight: "36px" }, children: "Next \xBB" }),
2144
+ o && !be && ce.length >= 1 && /* @__PURE__ */ d("button", { onClick: Yt, style: { padding: "6px 16px", borderRadius: 4, fontSize: 14, fontWeight: 500, backgroundColor: "#fff", border: "1px solid #bdbdbd", color: "#333", cursor: "pointer", fontFamily: "system-ui, sans-serif", letterSpacing: "0.4px", lineHeight: "36px" }, children: "Reset Points" }),
2145
+ be && /* @__PURE__ */ d(
2146
+ "button",
2147
+ {
2148
+ onClick: qt,
2149
+ disabled: se.length === 0,
2150
+ style: { padding: "6px 16px", borderRadius: 4, fontSize: 14, fontWeight: 500, backgroundColor: se.length > 0 ? "rgb(12, 67, 173)" : "#e0e0e0", border: "none", color: se.length > 0 ? "#fff" : "#9e9e9e", cursor: se.length > 0 ? "pointer" : "not-allowed", fontFamily: "system-ui, sans-serif", letterSpacing: "0.4px", lineHeight: "36px" },
2151
+ children: "Continue to Next Step"
2152
+ }
2153
+ )
2154
+ ] })
2155
+ ] })
2156
+ ] }),
2157
+ e.showInsertMeasurement && Te && (() => {
2158
+ const _ = R === "AK" ? "IT/Perineum" : "MPT", K = w, ue = [];
2159
+ for (let Z = 2; Z >= 1; Z -= K) ue.push(`${Z}\u2033 above ${_}`);
2160
+ ue.push(`At ${_}`);
2161
+ for (let Z = K; Z <= 9; Z += K) ue.push(`${Z}\u2033 below ${_}`);
2162
+ return /* @__PURE__ */ d("div", { style: { position: "fixed", inset: 0, backgroundColor: "rgba(0,0,0,0.32)", display: "flex", alignItems: "center", justifyContent: "flex-start", paddingLeft: 40, zIndex: 9999 }, children: /* @__PURE__ */ W("div", { style: { backgroundColor: "#fff", borderRadius: 4, width: 620, maxHeight: "80vh", display: "flex", flexDirection: "column", 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)", fontFamily: "system-ui, sans-serif" }, children: [
2163
+ /* @__PURE__ */ W("div", { style: { padding: "24px 24px 0" }, children: [
2164
+ /* @__PURE__ */ W("div", { style: { fontSize: 20, fontWeight: 500, color: "rgba(0,0,0,0.87)", marginBottom: 4 }, children: [
2165
+ R,
2166
+ " Circumferences"
2167
+ ] }),
2168
+ /* @__PURE__ */ W("div", { style: { fontSize: 13, color: "rgba(0,0,0,0.54)", marginBottom: 20 }, children: [
2169
+ "Enter form measurements (mm). ",
2170
+ K,
2171
+ "\u2033",
2172
+ " spacing."
2173
+ ] })
2174
+ ] }),
2175
+ /* @__PURE__ */ d("div", { style: { padding: "0 24px", overflowY: "auto", flex: 1 }, children: /* @__PURE__ */ d("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: "16px 24px" }, children: ue.map((Z, Be) => /* @__PURE__ */ W("div", { children: [
2176
+ /* @__PURE__ */ W("label", { style: { display: "block", fontSize: 13, fontWeight: 500, color: "rgb(12, 67, 173)", marginBottom: 6 }, children: [
2177
+ Z,
2178
+ " (mm):"
2179
+ ] }),
2180
+ /* @__PURE__ */ d(
2181
+ "input",
2182
+ {
2183
+ type: "number",
2184
+ step: "0.1",
2185
+ value: Ae[Z] ?? "",
2186
+ onChange: (te) => De((ve) => ({ ...ve, [Z]: te.target.value })),
2187
+ style: { width: "100%", padding: "10px 12px", fontSize: 15, border: "2px solid rgb(12, 67, 173)", borderRadius: 4, outline: "none", boxSizing: "border-box", fontFamily: "system-ui, sans-serif" }
2188
+ }
2189
+ )
2190
+ ] }, Be)) }) }),
2191
+ /* @__PURE__ */ W("div", { style: { display: "flex", justifyContent: "flex-end", gap: 8, padding: "16px 24px", borderTop: "1px solid #e0e0e0", marginTop: 16 }, children: [
2192
+ /* @__PURE__ */ d("button", { onClick: () => {
2193
+ Me(false), De({});
2194
+ }, style: { padding: "6px 16px", borderRadius: 4, fontSize: 14, fontWeight: 500, backgroundColor: "#fff", border: "1px solid #bdbdbd", color: "rgba(0,0,0,0.87)", cursor: "pointer", fontFamily: "system-ui, sans-serif", lineHeight: "36px", letterSpacing: "0.4px" }, children: "Cancel" }),
2195
+ /* @__PURE__ */ d("button", { onClick: () => {
2196
+ const Z = ue.map((te) => parseFloat(Ae[te] || "")), Be = Z.filter((te) => !isNaN(te));
2197
+ Ee(Be.length > 0 ? Z.map((te) => isNaN(te) ? void 0 : te) : void 0), Me(false);
2198
+ }, style: { padding: "6px 16px", borderRadius: 4, fontSize: 14, fontWeight: 500, backgroundColor: "rgb(12, 67, 173)", border: "none", color: "#fff", cursor: "pointer", fontFamily: "system-ui, sans-serif", lineHeight: "36px", letterSpacing: "0.4px" }, children: "Save" })
2199
+ ] })
2200
+ ] }) });
2201
+ })()
2202
+ ] });
2203
+ };
2204
+ function Nt(e) {
2205
+ const s = e === "AK" ? 2 : 1, n = [];
2206
+ for (let t = 2; t >= 1; t -= s)
2207
+ n.push(`${t}_above`);
2208
+ n.push("at_ref");
2209
+ for (let t = s; t <= 9; t += s)
2210
+ n.push(`${t}_below`);
2211
+ return n;
2212
+ }
2213
+ function dt(e, s) {
2214
+ const n = Nt(s), t = {};
2215
+ for (let i = 0; i < Math.min(e.length, n.length); i++) {
2216
+ const a = e[i];
2217
+ a != null && !isNaN(a) && (t[n[i]] = a);
2218
+ }
2219
+ return t;
2220
+ }
2221
+ function ao(e, s) {
2222
+ if (!e) return;
2223
+ const t = Nt(s).map((i) => {
2224
+ const a = e[i];
2225
+ return a ?? void 0;
2226
+ });
2227
+ if (!t.every((i) => i == null))
2228
+ return t;
2229
+ }
2230
+ const bo = ({ request: e, onComplete: s, wasmModule: n }) => {
2231
+ const t = de(
2232
+ () => ao(e.form_measurements, e.spacing_type),
2233
+ [e.form_measurements, e.spacing_type]
2234
+ ), i = (a) => {
2235
+ const c = a.scanMeasurements.map((f) => +(f.modifiedValue ?? f.originalValue).toFixed(1)), u = dt(c, e.spacing_type);
2236
+ let o, l;
2237
+ if (a.formMeasurements) {
2238
+ o = dt(a.formMeasurements, e.spacing_type);
2239
+ const f = a.scanMeasurements.map((y, p) => {
2240
+ var _a;
2241
+ const m = (_a = a.formMeasurements) == null ? void 0 : _a[p];
2242
+ return m == null || isNaN(m) ? null : +((y.modifiedValue ?? y.originalValue) - m).toFixed(1);
2243
+ });
2244
+ l = dt(f, e.spacing_type);
2245
+ }
2246
+ const r = {
2247
+ spacing_type: e.spacing_type,
2248
+ source_unit: "mm",
2249
+ file_format: a.fileFormat,
2250
+ measurement_source: a.formMeasurements ? "form_provided" : "scan_derived",
2251
+ is_double_wall: a.isDoubleWall,
2252
+ is_unit_converted: false,
2253
+ form_measurements: o,
2254
+ scan_measurements: u,
2255
+ measurement_variance: l,
2256
+ scan_url: e.scan_url,
2257
+ frontal_height: +a.frontalHeight.toFixed(1),
2258
+ transverse_ml: +a.transverseML.toFixed(1),
2259
+ transverse_ap: +a.transverseAP.toFixed(1)
2260
+ };
2261
+ console.log("[GirthManagerWidget] WidgetResponse:", JSON.stringify(r, null, 2)), s == null ? void 0 : s(r);
2262
+ };
2263
+ return /* @__PURE__ */ d("div", { style: { width: "100%", height: "100%", display: "flex" }, children: /* @__PURE__ */ d(
2264
+ lo,
2265
+ {
2266
+ config: fn,
2267
+ spacingType: e.spacing_type,
2268
+ scanUrl: e.scan_url,
2269
+ formMeasurements: t,
2270
+ onComplete: i,
2271
+ wasmModule: n
2272
+ }
2273
+ ) });
2274
+ };
2275
+ export {
2276
+ bo as G,
2277
+ dt as a,
2278
+ ao as c,
2279
+ Nt as g
2280
+ };