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

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.
@@ -1,2280 +0,0 @@
1
- import { jsxs as W, jsx as d, Fragment as He } from "react/jsx-runtime";
2
- import { createContext as tn, useCallback as Fe, useMemo as de, useState as q, memo as nn, useEffect as 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
- };