@solid-labs/fab-one-widget 0.1.5 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/GirthManagerWidget-C5L2H3Y2.js +4786 -0
- package/dist/GirthManagerWidget-C5L2H3Y2.js.map +1 -0
- package/dist/girth-manager-ui/src/GirthManagerCore.d.ts +11 -5
- package/dist/girth-manager-ui/src/components/CameraFit.d.ts +5 -1
- package/dist/girth-manager-ui/src/components/CircumferenceMeasurements.d.ts +4 -1
- package/dist/girth-manager-ui/src/components/CircumferenceSlice.d.ts +6 -1
- package/dist/girth-manager-ui/src/components/ClickableMesh.d.ts +5 -1
- package/dist/girth-manager-ui/src/components/DebugOverlays.d.ts +14 -2
- package/dist/girth-manager-ui/src/components/DebugPanel.d.ts +2 -1
- package/dist/girth-manager-ui/src/components/ErrorBoundary.d.ts +16 -0
- package/dist/girth-manager-ui/src/components/MeasurementInputForm.d.ts +14 -0
- package/dist/girth-manager-ui/src/components/VerticalDimension.d.ts +3 -1
- package/dist/girth-manager-ui/src/config.d.ts +2 -2
- package/dist/girth-manager-ui/src/index.d.ts +10 -6
- package/dist/girth-manager-ui/src/processing/logger.d.ts +13 -0
- package/dist/girth-manager-ui/src/processing/mesh-ops.d.ts +0 -22
- package/dist/girth-manager-ui/src/processing/pipeline.d.ts +34 -6
- package/dist/girth-manager-ui/src/processing/types.d.ts +112 -12
- package/dist/girth-manager-ui/src/processing/vertex-colors.d.ts +6 -1
- package/dist/girth-manager-ui/src/processing/wasm-loader.d.ts +16 -16
- package/dist/girth-manager-web-widget/src/GirthManagerWidget.d.ts +3 -5
- package/dist/girth-manager-web-widget/src/index.d.ts +1 -1
- package/dist/girth-manager-web-widget/src/types.d.ts +57 -0
- package/dist/girth-manager-web-widget/src/web-component.d.ts +2 -2
- package/dist/html2canvas.esm-Dmi1NfiH.js +4871 -0
- package/dist/html2canvas.esm-Dmi1NfiH.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/web-component.js +2 -2
- package/dist/web-component.js.map +1 -1
- package/package.json +9 -9
- package/dist/GirthManagerWidget-v0RZXFKb.js +0 -4122
- package/dist/GirthManagerWidget-v0RZXFKb.js.map +0 -1
- package/dist/galileo_core_geo-DFVJmkI7.js +0 -298
- package/dist/galileo_core_geo-DFVJmkI7.js.map +0 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type GirthManagerConfig } from "./config";
|
|
2
|
-
import type {
|
|
2
|
+
import type { MeasurementFormData } from "./components/MeasurementInputForm";
|
|
3
|
+
import type { MeasurementData, WasmModule } from "./processing/types";
|
|
3
4
|
export interface GirthManagerResult {
|
|
4
5
|
spacingType: "AK" | "BK";
|
|
5
6
|
sourceUnit: "mm" | "inch";
|
|
@@ -13,6 +14,13 @@ export interface GirthManagerResult {
|
|
|
13
14
|
transverseML: number;
|
|
14
15
|
transverseAP: number;
|
|
15
16
|
scanUrl: string | undefined;
|
|
17
|
+
decision: "use_form_measurements" | "use_scan" | "continue" | "skip";
|
|
18
|
+
skipReason?: string;
|
|
19
|
+
userEnteredMeasurements?: MeasurementFormData;
|
|
20
|
+
screenshots?: {
|
|
21
|
+
frontal_view_png: string;
|
|
22
|
+
side_view_png: string;
|
|
23
|
+
};
|
|
16
24
|
}
|
|
17
25
|
export interface GirthManagerCoreProps {
|
|
18
26
|
/** Feature config — controls which UI elements are rendered */
|
|
@@ -29,9 +37,7 @@ export interface GirthManagerCoreProps {
|
|
|
29
37
|
isDebugUser?: boolean;
|
|
30
38
|
/** Called when analytics events should fire (internal app wires this to PostHog) */
|
|
31
39
|
onAnalyticsEvent?: (eventName: string, properties: Record<string, unknown>) => void;
|
|
32
|
-
/** Provide a loaded WASM module. If not provided,
|
|
33
|
-
wasmModule?:
|
|
34
|
-
WasmMeshSet: new () => WasmMeshSetType;
|
|
35
|
-
} | null;
|
|
40
|
+
/** Provide a loaded WASM module. If not provided, JS fallback is used. */
|
|
41
|
+
wasmModule?: WasmModule | null;
|
|
36
42
|
}
|
|
37
43
|
export declare const GirthManagerCore: ({ config, spacingType: presetSpacingType, scanUrl, formMeasurements: presetFormMeasurements, onComplete, isDebugUser, onAnalyticsEvent, wasmModule: externalWasmModule, }: GirthManagerCoreProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -7,5 +7,9 @@ export interface CameraFitProps {
|
|
|
7
7
|
viewMode: "3D" | "2D";
|
|
8
8
|
sliceY?: number;
|
|
9
9
|
landmarkCount?: number;
|
|
10
|
+
/** Clipped geometry for measurements — camera zooms to this region when aligned */
|
|
11
|
+
measurementGeometry?: THREE.BufferGeometry | null;
|
|
12
|
+
/** Ref populated with a function that resets camera to flat front view */
|
|
13
|
+
resetCameraToFrontRef?: React.MutableRefObject<(() => void) | null>;
|
|
10
14
|
}
|
|
11
|
-
export declare const CameraFit: ({ modelSize, isAligned, isCut, mesh, viewMode, sliceY, landmarkCount }: CameraFitProps) => null;
|
|
15
|
+
export declare const CameraFit: ({ modelSize, isAligned, isCut, mesh, viewMode, sliceY, landmarkCount, measurementGeometry, resetCameraToFrontRef }: CameraFitProps) => null;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as THREE from "three";
|
|
2
2
|
import type { MeasurementData } from "../processing/types";
|
|
3
|
+
import type { WasmSliceData } from "../processing/pipeline";
|
|
3
4
|
export interface CircumferenceMeasurementsProps {
|
|
4
5
|
mesh: THREE.Mesh;
|
|
5
6
|
startY: number;
|
|
@@ -12,5 +13,7 @@ export interface CircumferenceMeasurementsProps {
|
|
|
12
13
|
useInnerSurface?: boolean;
|
|
13
14
|
formMeasurements?: number[];
|
|
14
15
|
originY?: number;
|
|
16
|
+
/** WASM-computed slice data — when provided, uses WASM circumferences + loop points instead of JS BVH */
|
|
17
|
+
wasmSlices?: WasmSliceData | null;
|
|
15
18
|
}
|
|
16
|
-
export declare const CircumferenceMeasurements: ({ mesh, startY, endY, spacing, modelSize, onMeasurementsChange, reverseOrder, displayUnit, useInnerSurface, formMeasurements, originY }: CircumferenceMeasurementsProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
19
|
+
export declare const CircumferenceMeasurements: ({ mesh, startY, endY, spacing, modelSize, onMeasurementsChange, reverseOrder, displayUnit, useInnerSurface, formMeasurements, originY, wasmSlices }: CircumferenceMeasurementsProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as THREE from "three";
|
|
2
|
+
import { Vector3 } from "three";
|
|
2
3
|
import { MeshBVH } from "three-mesh-bvh";
|
|
3
4
|
import type { MeasurementData } from "../processing/types";
|
|
4
5
|
export interface CircumferenceSliceProps {
|
|
@@ -12,5 +13,9 @@ export interface CircumferenceSliceProps {
|
|
|
12
13
|
useInnerSurface?: boolean;
|
|
13
14
|
formValue?: number;
|
|
14
15
|
lineWidth?: number;
|
|
16
|
+
/** WASM-computed loop points for this slice (bypasses JS BVH when provided) */
|
|
17
|
+
wasmLoopPoints?: Vector3[];
|
|
18
|
+
/** WASM-computed circumference for this slice */
|
|
19
|
+
wasmCircumference?: number;
|
|
15
20
|
}
|
|
16
|
-
export declare const CircumferenceSlice: import("react").MemoExoticComponent<({ bvh, geometry, yPosition, color, labelX, onDataChange, displayUnit, useInnerSurface, formValue, lineWidth }: CircumferenceSliceProps) => import("react/jsx-runtime").JSX.Element | null>;
|
|
21
|
+
export declare const CircumferenceSlice: import("react").MemoExoticComponent<({ bvh, geometry, yPosition, color, labelX, onDataChange, displayUnit, useInnerSurface, formValue, lineWidth, wasmLoopPoints, wasmCircumference }: CircumferenceSliceProps) => import("react/jsx-runtime").JSX.Element | null>;
|
|
@@ -4,5 +4,9 @@ export interface ClickableMeshProps {
|
|
|
4
4
|
maxPoints?: number;
|
|
5
5
|
meshColor?: string;
|
|
6
6
|
meshOpacity?: number;
|
|
7
|
+
/** When true, only render/click front faces (prevents clicking from inside the mesh) */
|
|
8
|
+
frontFaceOnly?: boolean;
|
|
9
|
+
/** When true, enables transparency mode optimized for double-shell meshes */
|
|
10
|
+
doubleShellTransparency?: boolean;
|
|
7
11
|
}
|
|
8
|
-
export declare const ClickableMesh: ({ mesh, maxPoints, meshColor, meshOpacity }: ClickableMeshProps) => import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
export declare const ClickableMesh: ({ mesh, maxPoints, meshColor, meshOpacity, frontFaceOnly, doubleShellTransparency }: ClickableMeshProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
import * as THREE from "three";
|
|
2
|
-
|
|
2
|
+
/** Per-component debug geometry (legacy — now passed as null) */
|
|
3
|
+
export interface ComponentDebugInfo {
|
|
4
|
+
geometries: THREE.BufferGeometry[];
|
|
5
|
+
labels: string[];
|
|
6
|
+
colors: string[];
|
|
7
|
+
innerIdx: number | null;
|
|
8
|
+
}
|
|
3
9
|
export interface DebugLayerVisibility {
|
|
4
10
|
pcaAxes: boolean;
|
|
5
11
|
obb: boolean;
|
|
6
12
|
obbAxis: boolean;
|
|
7
13
|
shellComponents: boolean;
|
|
14
|
+
ambientOcclusion: boolean;
|
|
8
15
|
circumferenceScan: boolean;
|
|
9
16
|
landmarkAxis: boolean;
|
|
10
17
|
iterativePCA: boolean;
|
|
@@ -23,8 +30,13 @@ export interface DebugOverlaysProps {
|
|
|
23
30
|
};
|
|
24
31
|
}[];
|
|
25
32
|
componentDebug?: ComponentDebugInfo | null;
|
|
33
|
+
aoData?: Float32Array | null;
|
|
34
|
+
/** The geometry that aoData corresponds to (pre-extraction), since mesh.geometry may change after inner shell extraction */
|
|
35
|
+
aoGeometry?: THREE.BufferGeometry | null;
|
|
36
|
+
/** Clipped geometry used for measurements — rendered as wireframe in debug to show cut region */
|
|
37
|
+
measurementGeometry?: THREE.BufferGeometry | null;
|
|
26
38
|
}
|
|
27
|
-
export declare function DebugOverlays({ mesh, layers, landmarkPoints, componentDebug }: DebugOverlaysProps): import("react/jsx-runtime").JSX.Element;
|
|
39
|
+
export declare function DebugOverlays({ mesh, layers, landmarkPoints, componentDebug, aoData, aoGeometry, measurementGeometry }: DebugOverlaysProps): import("react/jsx-runtime").JSX.Element;
|
|
28
40
|
export interface OBBAlignmentLineProps {
|
|
29
41
|
mesh: THREE.Mesh;
|
|
30
42
|
}
|
|
@@ -2,5 +2,6 @@ import type { DebugLayerVisibility } from "./DebugOverlays";
|
|
|
2
2
|
export interface DebugPanelProps {
|
|
3
3
|
layers: DebugLayerVisibility;
|
|
4
4
|
onToggleLayer: (layer: keyof DebugLayerVisibility) => void;
|
|
5
|
+
isDoubleShell?: boolean;
|
|
5
6
|
}
|
|
6
|
-
export declare function DebugPanel({ layers, onToggleLayer }: DebugPanelProps): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export declare function DebugPanel({ layers, onToggleLayer, isDoubleShell }: DebugPanelProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Component, type ReactNode } from "react";
|
|
2
|
+
interface ErrorBoundaryProps {
|
|
3
|
+
children: ReactNode;
|
|
4
|
+
fallback?: (error: Error, reset: () => void) => ReactNode;
|
|
5
|
+
}
|
|
6
|
+
interface ErrorBoundaryState {
|
|
7
|
+
error: Error | null;
|
|
8
|
+
}
|
|
9
|
+
export declare class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
|
|
10
|
+
state: ErrorBoundaryState;
|
|
11
|
+
static getDerivedStateFromError(error: Error): ErrorBoundaryState;
|
|
12
|
+
componentDidCatch(error: Error, info: React.ErrorInfo): void;
|
|
13
|
+
reset: () => void;
|
|
14
|
+
render(): string | number | bigint | boolean | Iterable<ReactNode> | Promise<string | number | bigint | boolean | import("react").ReactPortal | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | import("react/jsx-runtime").JSX.Element | null | undefined;
|
|
15
|
+
}
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { MeasurementData } from "../processing/types";
|
|
2
|
+
export interface MeasurementFormData {
|
|
3
|
+
circumferences: number[];
|
|
4
|
+
frontalHeight: number;
|
|
5
|
+
}
|
|
6
|
+
export interface MeasurementInputFormProps {
|
|
7
|
+
amputationType: "AK" | "BK";
|
|
8
|
+
spacingInches: 1 | 2;
|
|
9
|
+
scanMeasurements: MeasurementData[];
|
|
10
|
+
scanFrontalHeight: number;
|
|
11
|
+
onSave: (data: MeasurementFormData) => void;
|
|
12
|
+
onSkip: (reason: string) => void;
|
|
13
|
+
}
|
|
14
|
+
export declare const MeasurementInputForm: ({ amputationType, spacingInches, scanMeasurements, scanFrontalHeight, onSave, onSkip, }: MeasurementInputFormProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -4,5 +4,7 @@ export interface VerticalDimensionProps {
|
|
|
4
4
|
greenY: number;
|
|
5
5
|
modelSize: number;
|
|
6
6
|
displayUnit?: "mm" | "inch";
|
|
7
|
+
/** When set, measure to this Y instead of the mesh bounding box bottom (used for double-shell) */
|
|
8
|
+
bottomY?: number;
|
|
7
9
|
}
|
|
8
|
-
export declare const VerticalDimension: ({ mesh, greenY, modelSize, displayUnit }: VerticalDimensionProps) => import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export declare const VerticalDimension: ({ mesh, greenY, modelSize, displayUnit, bottomY }: VerticalDimensionProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -8,8 +8,6 @@ export interface GirthManagerConfig {
|
|
|
8
8
|
showDragDrop: boolean;
|
|
9
9
|
/** Show "Start Over" button */
|
|
10
10
|
showStartOver: boolean;
|
|
11
|
-
/** Show "Insert Measurement" button and modal */
|
|
12
|
-
showInsertMeasurement: boolean;
|
|
13
11
|
/** Allow debug mode toggle (requires isDebugUser) */
|
|
14
12
|
showDebug: boolean;
|
|
15
13
|
/** Show 1"/2" measurement spacing toggle */
|
|
@@ -20,6 +18,8 @@ export interface GirthManagerConfig {
|
|
|
20
18
|
showNavigation: boolean;
|
|
21
19
|
/** Show top toolbar ribbon */
|
|
22
20
|
showToolbar: boolean;
|
|
21
|
+
/** Show manual "Save" screenshot button */
|
|
22
|
+
showSaveButton: boolean;
|
|
23
23
|
}
|
|
24
24
|
/** Default config for the internal application (all features enabled) */
|
|
25
25
|
export declare const INTERNAL_CONFIG: GirthManagerConfig;
|
|
@@ -3,20 +3,22 @@ export type { GirthManagerConfig } from "./config";
|
|
|
3
3
|
export { GirthManagerCore } from "./GirthManagerCore";
|
|
4
4
|
export type { GirthManagerCoreProps, GirthManagerResult } from "./GirthManagerCore";
|
|
5
5
|
export { useMeasurementStore } from "./store";
|
|
6
|
-
export type {
|
|
6
|
+
export type { WasmModule, LandmarkPoint, MeasurementData, SliceResult, Seg } from "./processing/types";
|
|
7
7
|
export { LABEL_X_OFFSET_RATIO, BVH_MAX_LEAF_TRIS, WELD_EPSILON, MM_PER_INCH, ABOVE_POINT_OFFSET_INCHES, AUTO_SCALE_VOLUME_THRESHOLD, RETRY_OFFSETS } from "./processing/constants";
|
|
8
8
|
export { parseObjVertexColors, transferVertexColors } from "./processing/vertex-colors";
|
|
9
9
|
export { computeSliceAtYOnce, computeSliceAtY, buildBVH, calcLineLength, computeCircumferenceAtPlane } from "./processing/slice";
|
|
10
10
|
export { intersectMeshWithPlane, findBestCutPlane } from "./processing/cut-plane";
|
|
11
11
|
export { computeBarycentricCoords, sliceMeshAtPlane } from "./processing/mesh-ops";
|
|
12
|
-
export type { ShellDetectionResult } from "./processing/mesh-ops";
|
|
13
12
|
export { runPCAOnRegion } from "./processing/alignment";
|
|
14
13
|
export { validateProcessingResult } from "./processing/validation";
|
|
14
|
+
export { logger } from "./processing/logger";
|
|
15
|
+
export type { LogLevel } from "./processing/logger";
|
|
15
16
|
export { stlToObjString } from "./processing/stl-convert";
|
|
16
|
-
export { processWithWasm, processWithObjLoader } from "./processing/wasm-loader";
|
|
17
|
-
export type { WasmProcessResult
|
|
18
|
-
export { runProcessingPipeline
|
|
19
|
-
export type { PipelineCallbacks } from "./processing/pipeline";
|
|
17
|
+
export { processWithWasm, processWithObjLoader, extractArrays, buildGeometry } from "./processing/wasm-loader";
|
|
18
|
+
export type { WasmProcessResult } from "./processing/wasm-loader";
|
|
19
|
+
export { runProcessingPipeline } from "./processing/pipeline";
|
|
20
|
+
export type { PipelineCallbacks, WasmSliceData } from "./processing/pipeline";
|
|
21
|
+
export { ErrorBoundary } from "./components/ErrorBoundary";
|
|
20
22
|
export { ErrorDisplay } from "./components/ErrorDisplay";
|
|
21
23
|
export { LoadingSpinner } from "./components/LoadingSpinner";
|
|
22
24
|
export { ClickableMesh } from "./components/ClickableMesh";
|
|
@@ -35,4 +37,6 @@ export { TransverseView } from "./components/TransverseView";
|
|
|
35
37
|
export { DebugOverlays, DEFAULT_DEBUG_LAYERS, OBBAlignmentLine } from "./components/DebugOverlays";
|
|
36
38
|
export type { DebugLayerVisibility } from "./components/DebugOverlays";
|
|
37
39
|
export { DebugPanel } from "./components/DebugPanel";
|
|
40
|
+
export { MeasurementInputForm } from "./components/MeasurementInputForm";
|
|
41
|
+
export type { MeasurementInputFormProps, MeasurementFormData } from "./components/MeasurementInputForm";
|
|
38
42
|
export { useCachedBVH } from "./hooks/useCachedBVH";
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type LogLevel = "debug" | "info" | "warn" | "error";
|
|
2
|
+
declare let onLog: ((level: LogLevel, tag: string, message: string, data?: unknown) => void) | null;
|
|
3
|
+
export declare const logger: {
|
|
4
|
+
/** Set minimum log level. Below this level, messages are silenced. */
|
|
5
|
+
setLevel(level: LogLevel): void;
|
|
6
|
+
/** Set an external log handler (e.g. for sending errors to monitoring). */
|
|
7
|
+
setHandler(handler: typeof onLog): void;
|
|
8
|
+
debug(tag: string, message: string, data?: unknown): void;
|
|
9
|
+
info(tag: string, message: string, data?: unknown): void;
|
|
10
|
+
warn(tag: string, message: string, data?: unknown): void;
|
|
11
|
+
error(tag: string, message: string, data?: unknown): void;
|
|
12
|
+
};
|
|
13
|
+
export {};
|
|
@@ -1,27 +1,5 @@
|
|
|
1
1
|
import * as THREE from "three";
|
|
2
2
|
import { Vector3 } from "three";
|
|
3
|
-
export interface ShellDetectionResult {
|
|
4
|
-
isDoubleShell: boolean;
|
|
5
|
-
sampledFaces: number;
|
|
6
|
-
opposingPairs: number;
|
|
7
|
-
confidence: number;
|
|
8
|
-
}
|
|
9
|
-
/**
|
|
10
|
-
* Detect whether a mesh is single-shell or double-shell (has wall thickness).
|
|
11
|
-
*
|
|
12
|
-
* Method: BVH ray intersection counting.
|
|
13
|
-
* For each of 3 cross-sections perpendicular to the red→green axis, the centroid
|
|
14
|
-
* is computed, then 12 rays are cast radially outward from it. Each ray counts all
|
|
15
|
-
* triangle intersections (both front and back faces via double-sided testing).
|
|
16
|
-
*
|
|
17
|
-
* Single shell → each ray exits through 1 wall → avg hits ≈ 1
|
|
18
|
-
* Double shell → each ray exits through inner wall + outer wall → avg hits ≈ 2
|
|
19
|
-
*
|
|
20
|
-
* This is independent of normal direction and surface texture/roughness.
|
|
21
|
-
* At least 2 of 3 sections must independently show avg hits > 1.5 to classify as
|
|
22
|
-
* double-shell, preventing false positives from irregular endpoints.
|
|
23
|
-
*/
|
|
24
|
-
export declare function detectDoubleShell(geometry: THREE.BufferGeometry, redPoint: Vector3, greenPoint: Vector3): ShellDetectionResult;
|
|
25
3
|
/** Compute barycentric coordinates of point p with respect to triangle (a, b, c) */
|
|
26
4
|
export declare function computeBarycentricCoords(p: Vector3, a: Vector3, b: Vector3, c: Vector3): {
|
|
27
5
|
u: number;
|
|
@@ -1,10 +1,23 @@
|
|
|
1
1
|
import * as THREE from "three";
|
|
2
|
-
import {
|
|
2
|
+
import type { WasmModule } from "./types";
|
|
3
|
+
/** WASM-computed horizontal slice data from batch_cross_sections_y */
|
|
4
|
+
export interface WasmSliceData {
|
|
5
|
+
/** Y positions where slices were computed */
|
|
6
|
+
yValues: number[];
|
|
7
|
+
/** Circumference at each Y (mm) */
|
|
8
|
+
circumferences: number[];
|
|
9
|
+
/** All loop points concatenated [x,y,z,...] */
|
|
10
|
+
allLoopPoints: Float32Array;
|
|
11
|
+
/** Byte offsets into allLoopPoints for each slice */
|
|
12
|
+
offsets: Uint32Array;
|
|
13
|
+
/** MPT Y coordinate */
|
|
14
|
+
mptY: number;
|
|
15
|
+
/** Origin Y coordinate */
|
|
16
|
+
originY: number;
|
|
17
|
+
}
|
|
3
18
|
export interface PipelineCallbacks {
|
|
4
19
|
onStatus: (message: string) => void;
|
|
5
20
|
setDoubleShell?: (isDoubleShell: boolean) => void;
|
|
6
|
-
/** When true, skip double-shell detection (inner shell was already extracted during WASM processing) */
|
|
7
|
-
skipDoubleShellDetection?: boolean;
|
|
8
21
|
addLandmarkPoint: (point: {
|
|
9
22
|
faceIndex: number;
|
|
10
23
|
vertexIndices: [number, number, number];
|
|
@@ -33,10 +46,25 @@ export interface PipelineCallbacks {
|
|
|
33
46
|
setAdjustedEndY: (y: number | null) => void;
|
|
34
47
|
setError: (error: string | null) => void;
|
|
35
48
|
setClippedReferenceGeometry?: (geometry: THREE.BufferGeometry | null) => void;
|
|
49
|
+
setMeasurementGeometry?: (geometry: THREE.BufferGeometry | null) => void;
|
|
50
|
+
setAoData?: (data: Float32Array | null, geometry?: THREE.BufferGeometry) => void;
|
|
51
|
+
setInnerShellExtracted?: (extracted: boolean) => void;
|
|
52
|
+
/** Callback to set WASM-computed slice data (circumferences + loop geometry) */
|
|
53
|
+
setWasmSlices?: (data: WasmSliceData) => void;
|
|
54
|
+
wasmModule?: WasmModule;
|
|
36
55
|
}
|
|
37
|
-
/**
|
|
38
|
-
|
|
39
|
-
|
|
56
|
+
/**
|
|
57
|
+
* Full processing pipeline using WASM.
|
|
58
|
+
*
|
|
59
|
+
* Follows the reference pipeline exactly:
|
|
60
|
+
* 1. detect_shell
|
|
61
|
+
* 2. find_min_cross_section (at MPT)
|
|
62
|
+
* 3. align_to_origin (initial alignment)
|
|
63
|
+
* 4. subdivide_origin_to_plane (generate Y heights)
|
|
64
|
+
* 5. batch_cross_sections_y (at subdivision points → centroids)
|
|
65
|
+
* 6. refine_alignment (PCA on centroids)
|
|
66
|
+
* 7. batch_cross_sections_y (final 1" slicing)
|
|
67
|
+
*/
|
|
40
68
|
export declare function runProcessingPipeline(mesh: THREE.Mesh, landmarkPoints: {
|
|
41
69
|
position: {
|
|
42
70
|
x: number;
|
|
@@ -1,16 +1,116 @@
|
|
|
1
1
|
import type { Vector3 } from "three";
|
|
2
|
-
export interface
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
2
|
+
export interface PreprocessResult {
|
|
3
|
+
positions(): Float32Array;
|
|
4
|
+
indices(): Uint32Array;
|
|
5
|
+
bbox_size(): Float32Array;
|
|
6
|
+
detected_unit(): string;
|
|
7
|
+
unit_converted(): boolean;
|
|
8
|
+
max_dimension(): number;
|
|
9
|
+
weld_stats(): string;
|
|
10
|
+
holes_filled(): number;
|
|
11
|
+
log(): string;
|
|
12
|
+
}
|
|
13
|
+
export interface ShellDetectResult {
|
|
14
|
+
is_double_shell(): boolean;
|
|
15
|
+
thickness(): number;
|
|
16
|
+
ray_count(): number;
|
|
17
|
+
double_hit_count(): number;
|
|
18
|
+
avg_thickness(): number;
|
|
19
|
+
min_thickness(): number;
|
|
20
|
+
max_thickness(): number;
|
|
21
|
+
details(): string;
|
|
22
|
+
hit_ray_lines(): Float32Array;
|
|
23
|
+
miss_ray_lines(): Float32Array;
|
|
24
|
+
hit_points(): Float32Array;
|
|
25
|
+
surface_normal(): Float32Array;
|
|
26
|
+
}
|
|
27
|
+
export interface ExtractInnerShellResult {
|
|
28
|
+
positions(): Float32Array;
|
|
29
|
+
indices(): Uint32Array;
|
|
30
|
+
interior_point(): Float32Array;
|
|
31
|
+
inner_count(): number;
|
|
32
|
+
total_count(): number;
|
|
33
|
+
details(): string;
|
|
34
|
+
}
|
|
35
|
+
export interface AlignResult {
|
|
36
|
+
positions(): Float32Array;
|
|
37
|
+
mpt(): Float32Array;
|
|
38
|
+
origin(): Float32Array;
|
|
39
|
+
transform(): Float32Array;
|
|
40
|
+
details(): string;
|
|
41
|
+
}
|
|
42
|
+
export interface SecondaryPcaResult {
|
|
43
|
+
positions(): Float32Array;
|
|
44
|
+
mpt(): Float32Array;
|
|
45
|
+
origin(): Float32Array;
|
|
46
|
+
transform(): Float32Array;
|
|
47
|
+
details(): string;
|
|
48
|
+
}
|
|
49
|
+
export interface RefineAlignmentResult {
|
|
50
|
+
positions(): Float32Array;
|
|
51
|
+
mpt(): Float32Array;
|
|
52
|
+
origin(): Float32Array;
|
|
53
|
+
rotation(): Float32Array;
|
|
54
|
+
centroid_axis(): Float32Array;
|
|
55
|
+
correction_angle(): number;
|
|
56
|
+
details(): string;
|
|
57
|
+
}
|
|
58
|
+
export interface SubdivideLineResult {
|
|
59
|
+
points(): Float32Array;
|
|
60
|
+
count(): number;
|
|
61
|
+
spacing(): number;
|
|
62
|
+
total_distance(): number;
|
|
63
|
+
}
|
|
64
|
+
export interface CrossSectionResult {
|
|
65
|
+
loop_points(): Float32Array;
|
|
66
|
+
plane_normal(): Float32Array;
|
|
67
|
+
circumference(): number;
|
|
68
|
+
is_closed(): boolean;
|
|
69
|
+
details(): string;
|
|
70
|
+
}
|
|
71
|
+
export interface BatchCrossSectionResult {
|
|
72
|
+
all_loop_points(): Float32Array;
|
|
73
|
+
offsets(): Uint32Array;
|
|
74
|
+
circumferences(): Float32Array;
|
|
75
|
+
count(): number;
|
|
76
|
+
details(): string;
|
|
77
|
+
}
|
|
78
|
+
export interface MeshResult {
|
|
79
|
+
positions(): Float32Array;
|
|
80
|
+
indices(): Uint32Array;
|
|
81
|
+
stats(): string;
|
|
82
|
+
}
|
|
83
|
+
export interface FillHolesResult {
|
|
84
|
+
positions(): Float32Array;
|
|
85
|
+
indices(): Uint32Array;
|
|
86
|
+
holes_filled(): number;
|
|
87
|
+
details(): string;
|
|
88
|
+
}
|
|
89
|
+
/** WASM module — functional API, no persistent state */
|
|
90
|
+
export interface WasmModule {
|
|
91
|
+
bounding_box(positions: Float32Array): Float32Array;
|
|
92
|
+
preprocess_mesh(positions: Float32Array, indices: Uint32Array, meter_threshold: number, weld_tolerance: number, max_hole_perimeter: number): PreprocessResult;
|
|
93
|
+
detect_and_convert_units(positions: Float32Array, meter_threshold: number): {
|
|
94
|
+
positions(): Float32Array;
|
|
95
|
+
detected_unit(): string;
|
|
96
|
+
converted(): boolean;
|
|
97
|
+
max_dimension(): number;
|
|
98
|
+
};
|
|
99
|
+
center_to_origin(positions: Float32Array): Float32Array;
|
|
100
|
+
weld_and_keep_largest(positions: Float32Array, tolerance: number): MeshResult;
|
|
101
|
+
weld_and_keep_largest_indexed(positions: Float32Array, indices: Uint32Array, tolerance: number): MeshResult;
|
|
102
|
+
fill_small_holes(positions: Float32Array, indices: Uint32Array, max_perimeter: number): FillHolesResult;
|
|
103
|
+
align_to_origin(positions: Float32Array, origin_pt: Float32Array, mpt: Float32Array, plane_normal: Float32Array): AlignResult;
|
|
104
|
+
secondary_pca(selected_positions: Float32Array, all_positions: Float32Array, origin_pt: Float32Array, mpt: Float32Array): SecondaryPcaResult;
|
|
105
|
+
refine_alignment(centroids: Float32Array, all_positions: Float32Array, origin_pt: Float32Array, mpt: Float32Array): RefineAlignmentResult;
|
|
106
|
+
subdivide_origin_to_plane(origin_pt: Float32Array, mpt: Float32Array, plane_normal: Float32Array): SubdivideLineResult;
|
|
107
|
+
detect_shell(positions: Float32Array, indices: Uint32Array, mpt: Float32Array, max_thickness: number): ShellDetectResult;
|
|
108
|
+
extract_inner_shell(positions: Float32Array, indices: Uint32Array, mpt: Float32Array, wall_thickness: number, hit_points: Float32Array): ExtractInnerShellResult;
|
|
109
|
+
ray_cast_bvh(positions: Float32Array, ray_origin: Float32Array, ray_dir: Float32Array): Uint32Array;
|
|
110
|
+
find_min_cross_section(positions: Float32Array, indices: Uint32Array, mpt: Float32Array, surface_normal: Float32Array, max_gap: number): CrossSectionResult;
|
|
111
|
+
batch_cross_sections_y(positions: Float32Array, indices: Uint32Array, y_values: Float32Array, max_gap: number): BatchCrossSectionResult;
|
|
112
|
+
batch_cross_sections_y_inner(positions: Float32Array, indices: Uint32Array, y_values: Float32Array, max_gap: number): BatchCrossSectionResult;
|
|
113
|
+
default(): Promise<void>;
|
|
14
114
|
}
|
|
15
115
|
export interface LandmarkPoint {
|
|
16
116
|
faceIndex: number;
|
|
@@ -4,5 +4,10 @@ export declare function parseObjVertexColors(objText: string): {
|
|
|
4
4
|
positions: Float32Array;
|
|
5
5
|
colors: Float32Array;
|
|
6
6
|
} | null;
|
|
7
|
-
/** Transfer vertex colors from original OBJ data to processed geometry via nearest-vertex matching with spatial grid.
|
|
7
|
+
/** Transfer vertex colors from original OBJ data to processed geometry via nearest-vertex matching with spatial grid.
|
|
8
|
+
*
|
|
9
|
+
* After preprocess_mesh, geometry is centered to origin (AABB center subtracted).
|
|
10
|
+
* Original OBJ positions are in their raw coordinate system. We compute the centering
|
|
11
|
+
* offset from the original positions so both spaces align for nearest-neighbor lookup.
|
|
12
|
+
*/
|
|
8
13
|
export declare function transferVertexColors(geometry: THREE.BufferGeometry, origPositions: Float32Array, origColors: Float32Array, scaleFactor: number): void;
|
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
import * as THREE from "three";
|
|
2
|
-
import type {
|
|
3
|
-
/** Per-component debug geometry */
|
|
4
|
-
export interface ComponentDebugInfo {
|
|
5
|
-
geometries: THREE.BufferGeometry[];
|
|
6
|
-
labels: string[];
|
|
7
|
-
colors: string[];
|
|
8
|
-
innerIdx: number | null;
|
|
9
|
-
}
|
|
2
|
+
import type { WasmModule } from "./types";
|
|
10
3
|
export interface WasmProcessResult {
|
|
11
4
|
geometry: THREE.BufferGeometry;
|
|
12
5
|
wasScaled: boolean;
|
|
13
|
-
/** True if
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
|
|
6
|
+
/** True if unit conversion from meters to mm occurred */
|
|
7
|
+
unitConverted: boolean;
|
|
8
|
+
/** Detected unit: "meter" | "mm" | "unknown" */
|
|
9
|
+
detectedUnit: string;
|
|
17
10
|
}
|
|
18
|
-
/**
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
11
|
+
/** Extract positions and indices from a THREE.BufferGeometry */
|
|
12
|
+
declare function extractArrays(geometry: THREE.BufferGeometry): {
|
|
13
|
+
positions: Float32Array;
|
|
14
|
+
indices: Uint32Array;
|
|
15
|
+
};
|
|
16
|
+
/** Build a THREE.BufferGeometry from flat position + index arrays */
|
|
17
|
+
declare function buildGeometry(positions: Float32Array, indices: Uint32Array): THREE.BufferGeometry;
|
|
18
|
+
/** Process OBJ string through WASM pipeline (preprocess_mesh: units + center + weld + fill) */
|
|
19
|
+
export declare function processWithWasm(objContents: string, wasmModule: WasmModule, onStatus?: (message: string) => void): Promise<WasmProcessResult | null>;
|
|
22
20
|
/** Fallback: process OBJ string with Three.js OBJLoader */
|
|
23
21
|
export declare function processWithObjLoader(objContents: string): THREE.BufferGeometry | null;
|
|
22
|
+
/** Helper: extract flat arrays from THREE geometry for passing to WASM functions */
|
|
23
|
+
export { extractArrays, buildGeometry };
|
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type WasmModule } from "@galileo/girth-manager-ui";
|
|
2
2
|
import type { WidgetRequest, WidgetResponse } from "./types";
|
|
3
3
|
export interface GirthManagerWidgetProps {
|
|
4
4
|
/** Widget input configuration */
|
|
5
5
|
request: WidgetRequest;
|
|
6
6
|
/** Called when "Continue to Next Step" is clicked with the full response payload */
|
|
7
7
|
onComplete?: (response: WidgetResponse) => void;
|
|
8
|
-
/** Pre-loaded WASM module. If omitted, the widget auto-loads
|
|
9
|
-
wasmModule?:
|
|
10
|
-
WasmMeshSet: new () => WasmMeshSetType;
|
|
11
|
-
} | null;
|
|
8
|
+
/** Pre-loaded WASM module. If omitted, the widget auto-loads geo-wasm. */
|
|
9
|
+
wasmModule?: WasmModule | null;
|
|
12
10
|
}
|
|
13
11
|
export declare const GirthManagerWidget: ({ request, onComplete, wasmModule: externalWasm }: GirthManagerWidgetProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { GirthManagerWidget } from "./GirthManagerWidget";
|
|
2
2
|
export type { GirthManagerWidgetProps } from "./GirthManagerWidget";
|
|
3
|
-
export type { WidgetRequest, WidgetResponse, Circumference } from "./types";
|
|
3
|
+
export type { WidgetRequest, WidgetResponse, Circumference, SocketScreenshots } from "./types";
|
|
4
4
|
export { getCircumferenceKeys, arrayToCircumference, circumferenceToArray } from "./types";
|
|
@@ -41,6 +41,51 @@ export interface WidgetResponse {
|
|
|
41
41
|
transverse_ml: number;
|
|
42
42
|
/** Anterior-posterior transverse dimension (mm) */
|
|
43
43
|
transverse_ap: number;
|
|
44
|
+
/**
|
|
45
|
+
* User's final decision:
|
|
46
|
+
* - "use_form_measurements": customer chose "Set to Measurements" (use their manually entered values)
|
|
47
|
+
* - "use_scan": customer chose "Go With Scan" (use scan-derived values)
|
|
48
|
+
* - "continue": all measurements were within tolerance (green) — customer confirmed to continue as-is
|
|
49
|
+
* - "skip": customer skipped the scan comparison entirely
|
|
50
|
+
*/
|
|
51
|
+
decision: "use_form_measurements" | "use_scan" | "continue" | "skip";
|
|
52
|
+
/** Reason the user skipped scan comparison (only present when decision is "skip") */
|
|
53
|
+
skip_reason?: string;
|
|
54
|
+
/** User-entered circumference measurements (mm). Only present when user entered measurements. */
|
|
55
|
+
user_measurements?: Circumference;
|
|
56
|
+
/** User-entered frontal height (mm). Only present when user entered measurements. */
|
|
57
|
+
user_frontal_height?: number;
|
|
58
|
+
/**
|
|
59
|
+
* Final resolved circumference measurements (mm) to use for the order form.
|
|
60
|
+
* When decision is "use_form_measurements": contains the user's entered measurements.
|
|
61
|
+
* When decision is "use_scan" or "continue": contains the scan-derived measurements.
|
|
62
|
+
* When decision is "skip": contains the user's entered measurements (form_provided).
|
|
63
|
+
*/
|
|
64
|
+
final_measurements: Circumference;
|
|
65
|
+
/** Final resolved frontal height (mm) to use for the order form, based on the user's decision. */
|
|
66
|
+
final_frontal_height: number;
|
|
67
|
+
/** Final resolved ML transverse dimension (mm) to use for the order form, based on the user's decision. */
|
|
68
|
+
final_transverse_ml: number;
|
|
69
|
+
/** Final resolved AP transverse dimension (mm) to use for the order form, based on the user's decision. */
|
|
70
|
+
final_transverse_ap: number;
|
|
71
|
+
/**
|
|
72
|
+
* PNG screenshots of the final rendered socket with measurement annotations.
|
|
73
|
+
* Includes a frontal view (BK: MPT anchor / AK: IT anchor) and a 90° side view.
|
|
74
|
+
* Both images are base64-encoded data URIs ready for display or upload.
|
|
75
|
+
* Omitted if screenshot capture was not possible (e.g. render not available).
|
|
76
|
+
*/
|
|
77
|
+
screenshots?: SocketScreenshots;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Screenshot outputs of the final socket with measurements overlaid.
|
|
81
|
+
* BK: frontal view anchored at MPT point + 90° side view
|
|
82
|
+
* AK: frontal view anchored at IT point + 90° side view
|
|
83
|
+
*/
|
|
84
|
+
export interface SocketScreenshots {
|
|
85
|
+
/** Frontal view PNG encoded as a base64 data URI (e.g. "data:image/png;base64,...") */
|
|
86
|
+
frontal_view_png: string;
|
|
87
|
+
/** Side view (90° rotation) PNG encoded as a base64 data URI */
|
|
88
|
+
side_view_png: string;
|
|
44
89
|
}
|
|
45
90
|
export interface Circumference {
|
|
46
91
|
/** 2" above the reference landmark (mm) */
|
|
@@ -67,6 +112,18 @@ export interface Circumference {
|
|
|
67
112
|
"8_below"?: number | undefined | null;
|
|
68
113
|
/** 9" below the reference landmark (mm) */
|
|
69
114
|
"9_below"?: number | undefined | null;
|
|
115
|
+
/** 10" below the reference landmark (mm) */
|
|
116
|
+
"10_below"?: number | undefined | null;
|
|
117
|
+
/** 11" below the reference landmark (mm) */
|
|
118
|
+
"11_below"?: number | undefined | null;
|
|
119
|
+
/** 12" below the reference landmark (mm) */
|
|
120
|
+
"12_below"?: number | undefined | null;
|
|
121
|
+
/** 14" below the reference landmark (mm) */
|
|
122
|
+
"14_below"?: number | undefined | null;
|
|
123
|
+
/** 16" below the reference landmark (mm) */
|
|
124
|
+
"16_below"?: number | undefined | null;
|
|
125
|
+
/** 18" below the reference landmark (mm) */
|
|
126
|
+
"18_below"?: number | undefined | null;
|
|
70
127
|
}
|
|
71
128
|
/** Ordered keys for mapping measurement arrays to Circumference fields */
|
|
72
129
|
export declare function getCircumferenceKeys(spacingType: "AK" | "BK"): (keyof Circumference)[];
|
|
@@ -5,7 +5,7 @@ import type { WidgetRequest, WidgetResponse } from "./types";
|
|
|
5
5
|
* Usage in Angular:
|
|
6
6
|
* // In the component class:
|
|
7
7
|
* async ngAfterViewInit() {
|
|
8
|
-
* const wasm = await import('
|
|
8
|
+
* const wasm = await import('geo-wasm');
|
|
9
9
|
* await wasm.default();
|
|
10
10
|
* this.widgetEl.nativeElement.wasmModule = wasm;
|
|
11
11
|
* this.widgetEl.nativeElement.request = { spacing_type: 'BK', scan_url: '...' };
|
|
@@ -21,7 +21,7 @@ declare class GirthManagerWidgetElement extends HTMLElement {
|
|
|
21
21
|
static get observedAttributes(): string[];
|
|
22
22
|
get request(): WidgetRequest | null;
|
|
23
23
|
set request(value: WidgetRequest | string | null);
|
|
24
|
-
/** Set the pre-loaded WASM module (
|
|
24
|
+
/** Set the pre-loaded WASM v2 module (geo-wasm). Must be set before or alongside request. */
|
|
25
25
|
get wasmModule(): unknown;
|
|
26
26
|
set wasmModule(value: unknown);
|
|
27
27
|
connectedCallback(): void;
|