@solid-labs/fab-one-widget 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/GirthManagerWidget-DizbUvPi.js +2280 -0
- package/dist/GirthManagerWidget-DizbUvPi.js.map +1 -0
- package/dist/girth-manager-ui/src/GirthManagerCore.d.ts +37 -0
- package/dist/girth-manager-ui/src/components/AlignedOrbitControls.d.ts +5 -0
- package/dist/girth-manager-ui/src/components/CameraFit.d.ts +11 -0
- package/dist/girth-manager-ui/src/components/CircumferenceMeasurements.d.ts +16 -0
- package/dist/girth-manager-ui/src/components/CircumferenceSlice.d.ts +16 -0
- package/dist/girth-manager-ui/src/components/ClickableMesh.d.ts +8 -0
- package/dist/girth-manager-ui/src/components/DebugOverlays.d.ts +31 -0
- package/dist/girth-manager-ui/src/components/DebugPanel.d.ts +6 -0
- package/dist/girth-manager-ui/src/components/DraggableLineHandle.d.ts +16 -0
- package/dist/girth-manager-ui/src/components/ErrorDisplay.d.ts +4 -0
- package/dist/girth-manager-ui/src/components/LandmarkMarkers.d.ts +5 -0
- package/dist/girth-manager-ui/src/components/LoadingSpinner.d.ts +3 -0
- package/dist/girth-manager-ui/src/components/ScaleNotice.d.ts +5 -0
- package/dist/girth-manager-ui/src/components/ShellNotice.d.ts +5 -0
- package/dist/girth-manager-ui/src/components/Stepper.d.ts +10 -0
- package/dist/girth-manager-ui/src/components/TransverseView.d.ts +10 -0
- package/dist/girth-manager-ui/src/components/VerticalDimension.d.ts +8 -0
- package/dist/girth-manager-ui/src/config.d.ts +29 -0
- package/dist/girth-manager-ui/src/hooks/useCachedBVH.d.ts +3 -0
- package/dist/girth-manager-ui/src/index.d.ts +38 -0
- package/dist/girth-manager-ui/src/processing/alignment.d.ts +4 -0
- package/dist/girth-manager-ui/src/processing/constants.d.ts +7 -0
- package/dist/girth-manager-ui/src/processing/cut-plane.d.ts +13 -0
- package/dist/girth-manager-ui/src/processing/mesh-ops.d.ts +33 -0
- package/dist/girth-manager-ui/src/processing/pipeline.d.ts +46 -0
- package/dist/girth-manager-ui/src/processing/slice.d.ts +14 -0
- package/dist/girth-manager-ui/src/processing/stl-convert.d.ts +2 -0
- package/dist/girth-manager-ui/src/processing/types.d.ts +43 -0
- package/dist/girth-manager-ui/src/processing/validation.d.ts +6 -0
- package/dist/girth-manager-ui/src/processing/vertex-colors.d.ts +8 -0
- package/dist/girth-manager-ui/src/processing/wasm-loader.d.ts +23 -0
- package/dist/{store.d.ts → girth-manager-ui/src/store.d.ts} +1 -14
- package/dist/girth-manager-web-widget/src/GirthManagerWidget.d.ts +13 -0
- package/dist/girth-manager-web-widget/src/dev-harness.d.ts +1 -0
- package/dist/girth-manager-web-widget/src/index.d.ts +4 -0
- package/dist/girth-manager-web-widget/src/types.d.ts +76 -0
- package/dist/girth-manager-web-widget/src/web-component.d.ts +34 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/web-component.js +78 -0
- package/dist/web-component.js.map +1 -0
- package/package.json +36 -26
- package/dist/FabOneWidget.d.ts +0 -21
- package/dist/fab-one-widget.js +0 -4733
- package/dist/index.d.ts +0 -2
- package/dist/protosthetics_geo-BcQYS-wX.js +0 -1
- package/dist/register.d.ts +0 -2
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { type GirthManagerConfig } from "./config";
|
|
2
|
+
import type { MeasurementData, WasmMeshSetType } from "./processing/types";
|
|
3
|
+
export interface GirthManagerResult {
|
|
4
|
+
spacingType: "AK" | "BK";
|
|
5
|
+
sourceUnit: "mm" | "inch";
|
|
6
|
+
fileFormat: "obj" | "stl";
|
|
7
|
+
measurementSource: "scan_derived" | "form_provided";
|
|
8
|
+
isDoubleWall: boolean;
|
|
9
|
+
isUnitConverted: boolean;
|
|
10
|
+
formMeasurements: number[] | undefined;
|
|
11
|
+
scanMeasurements: MeasurementData[];
|
|
12
|
+
frontalHeight: number;
|
|
13
|
+
transverseML: number;
|
|
14
|
+
transverseAP: number;
|
|
15
|
+
scanUrl: string | undefined;
|
|
16
|
+
}
|
|
17
|
+
export interface GirthManagerCoreProps {
|
|
18
|
+
/** Feature config — controls which UI elements are rendered */
|
|
19
|
+
config: GirthManagerConfig;
|
|
20
|
+
/** Pre-set amputation/spacing type (skips the modal when set) */
|
|
21
|
+
spacingType?: "AK" | "BK";
|
|
22
|
+
/** URL to auto-load a scan file from (widget mode) */
|
|
23
|
+
scanUrl?: string;
|
|
24
|
+
/** Form-provided circumference measurements in mm, ordered by slice position (widget mode) */
|
|
25
|
+
formMeasurements?: number[];
|
|
26
|
+
/** Called when "Continue to Next Step" is clicked */
|
|
27
|
+
onComplete?: (result: GirthManagerResult) => void;
|
|
28
|
+
/** Whether current user can access debug features */
|
|
29
|
+
isDebugUser?: boolean;
|
|
30
|
+
/** Called when analytics events should fire (internal app wires this to PostHog) */
|
|
31
|
+
onAnalyticsEvent?: (eventName: string, properties: Record<string, unknown>) => void;
|
|
32
|
+
/** Provide a loaded WASM module. If not provided, the core will attempt to dynamically import 'galileo-core-geo'. */
|
|
33
|
+
wasmModule?: {
|
|
34
|
+
WasmMeshSet: new () => WasmMeshSetType;
|
|
35
|
+
} | null;
|
|
36
|
+
}
|
|
37
|
+
export declare const GirthManagerCore: ({ config, spacingType: presetSpacingType, scanUrl, formMeasurements: presetFormMeasurements, onComplete, isDebugUser, onAnalyticsEvent, wasmModule: externalWasmModule, }: GirthManagerCoreProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as THREE from "three";
|
|
2
|
+
export interface CameraFitProps {
|
|
3
|
+
modelSize: number;
|
|
4
|
+
isAligned: boolean;
|
|
5
|
+
isCut: boolean;
|
|
6
|
+
mesh: THREE.Mesh | null;
|
|
7
|
+
viewMode: "3D" | "2D";
|
|
8
|
+
sliceY?: number;
|
|
9
|
+
landmarkCount?: number;
|
|
10
|
+
}
|
|
11
|
+
export declare const CameraFit: ({ modelSize, isAligned, isCut, mesh, viewMode, sliceY, landmarkCount }: CameraFitProps) => null;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as THREE from "three";
|
|
2
|
+
import type { MeasurementData } from "../processing/types";
|
|
3
|
+
export interface CircumferenceMeasurementsProps {
|
|
4
|
+
mesh: THREE.Mesh;
|
|
5
|
+
startY: number;
|
|
6
|
+
endY: number;
|
|
7
|
+
spacing: number;
|
|
8
|
+
modelSize: number;
|
|
9
|
+
onMeasurementsChange?: (measurements: MeasurementData[]) => void;
|
|
10
|
+
reverseOrder?: boolean;
|
|
11
|
+
displayUnit?: "mm" | "inch";
|
|
12
|
+
useInnerSurface?: boolean;
|
|
13
|
+
formMeasurements?: number[];
|
|
14
|
+
originY?: number;
|
|
15
|
+
}
|
|
16
|
+
export declare const CircumferenceMeasurements: ({ mesh, startY, endY, spacing, modelSize, onMeasurementsChange, reverseOrder, displayUnit, useInnerSurface, formMeasurements, originY }: CircumferenceMeasurementsProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as THREE from "three";
|
|
2
|
+
import { MeshBVH } from "three-mesh-bvh";
|
|
3
|
+
import type { MeasurementData } from "../processing/types";
|
|
4
|
+
export interface CircumferenceSliceProps {
|
|
5
|
+
bvh: MeshBVH;
|
|
6
|
+
geometry: THREE.BufferGeometry;
|
|
7
|
+
yPosition: number;
|
|
8
|
+
color?: string;
|
|
9
|
+
labelX: number;
|
|
10
|
+
onDataChange?: (data: MeasurementData) => void;
|
|
11
|
+
displayUnit?: "mm" | "inch";
|
|
12
|
+
useInnerSurface?: boolean;
|
|
13
|
+
formValue?: number;
|
|
14
|
+
lineWidth?: number;
|
|
15
|
+
}
|
|
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>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import * as THREE from "three";
|
|
2
|
+
export interface ClickableMeshProps {
|
|
3
|
+
mesh: THREE.Mesh;
|
|
4
|
+
maxPoints?: number;
|
|
5
|
+
meshColor?: string;
|
|
6
|
+
meshOpacity?: number;
|
|
7
|
+
}
|
|
8
|
+
export declare const ClickableMesh: ({ mesh, maxPoints, meshColor, meshOpacity }: ClickableMeshProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import * as THREE from "three";
|
|
2
|
+
import type { ComponentDebugInfo } from "../processing/wasm-loader";
|
|
3
|
+
export interface DebugLayerVisibility {
|
|
4
|
+
pcaAxes: boolean;
|
|
5
|
+
obb: boolean;
|
|
6
|
+
obbAxis: boolean;
|
|
7
|
+
shellComponents: boolean;
|
|
8
|
+
circumferenceScan: boolean;
|
|
9
|
+
landmarkAxis: boolean;
|
|
10
|
+
iterativePCA: boolean;
|
|
11
|
+
fullRegionPCA: boolean;
|
|
12
|
+
}
|
|
13
|
+
export declare const DEFAULT_DEBUG_LAYERS: DebugLayerVisibility;
|
|
14
|
+
export interface DebugOverlaysProps {
|
|
15
|
+
mesh: THREE.Mesh;
|
|
16
|
+
modelSize: number;
|
|
17
|
+
layers: DebugLayerVisibility;
|
|
18
|
+
landmarkPoints?: {
|
|
19
|
+
position: {
|
|
20
|
+
x: number;
|
|
21
|
+
y: number;
|
|
22
|
+
z: number;
|
|
23
|
+
};
|
|
24
|
+
}[];
|
|
25
|
+
componentDebug?: ComponentDebugInfo | null;
|
|
26
|
+
}
|
|
27
|
+
export declare function DebugOverlays({ mesh, layers, landmarkPoints, componentDebug }: DebugOverlaysProps): import("react/jsx-runtime").JSX.Element;
|
|
28
|
+
export interface OBBAlignmentLineProps {
|
|
29
|
+
mesh: THREE.Mesh;
|
|
30
|
+
}
|
|
31
|
+
export declare function OBBAlignmentLine({ mesh }: OBBAlignmentLineProps): import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { DebugLayerVisibility } from "./DebugOverlays";
|
|
2
|
+
export interface DebugPanelProps {
|
|
3
|
+
layers: DebugLayerVisibility;
|
|
4
|
+
onToggleLayer: (layer: keyof DebugLayerVisibility) => void;
|
|
5
|
+
}
|
|
6
|
+
export declare function DebugPanel({ layers, onToggleLayer }: DebugPanelProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as THREE from "three";
|
|
2
|
+
export interface DraggableLineHandleProps {
|
|
3
|
+
mesh: THREE.Mesh;
|
|
4
|
+
yPosition: number;
|
|
5
|
+
onYChange: (newY: number) => void;
|
|
6
|
+
minY: number;
|
|
7
|
+
maxY: number;
|
|
8
|
+
modelSize: number;
|
|
9
|
+
color: string;
|
|
10
|
+
hoverColor: string;
|
|
11
|
+
dragColor: string;
|
|
12
|
+
label: string;
|
|
13
|
+
onDragStart?: () => void;
|
|
14
|
+
onDragEnd?: () => void;
|
|
15
|
+
}
|
|
16
|
+
export declare const DraggableLineHandle: ({ mesh, yPosition, onYChange, minY, maxY, modelSize, color, hoverColor, dragColor, label, onDragStart, onDragEnd }: DraggableLineHandleProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface StepperStep {
|
|
2
|
+
label: string;
|
|
3
|
+
number: number;
|
|
4
|
+
}
|
|
5
|
+
export interface StepperProps {
|
|
6
|
+
steps: StepperStep[];
|
|
7
|
+
currentStep: number;
|
|
8
|
+
accentColor?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare const Stepper: ({ steps, currentStep, accentColor }: StepperProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as THREE from "three";
|
|
2
|
+
export interface TransverseViewProps {
|
|
3
|
+
mesh: THREE.Mesh;
|
|
4
|
+
upperY: number;
|
|
5
|
+
originY: number;
|
|
6
|
+
modelSize: number;
|
|
7
|
+
meshColor?: string;
|
|
8
|
+
displayUnit?: "mm" | "inch";
|
|
9
|
+
}
|
|
10
|
+
export declare const TransverseView: ({ mesh, upperY, originY, modelSize, meshColor, displayUnit }: TransverseViewProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import * as THREE from "three";
|
|
2
|
+
export interface VerticalDimensionProps {
|
|
3
|
+
mesh: THREE.Mesh;
|
|
4
|
+
greenY: number;
|
|
5
|
+
modelSize: number;
|
|
6
|
+
displayUnit?: "mm" | "inch";
|
|
7
|
+
}
|
|
8
|
+
export declare const VerticalDimension: ({ mesh, greenY, modelSize, displayUnit }: VerticalDimensionProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration that controls which UI features are visible
|
|
3
|
+
* in GirthManagerCore. The internal app enables all features;
|
|
4
|
+
* the external widget disables chrome, debug, drag-drop, etc.
|
|
5
|
+
*/
|
|
6
|
+
export interface GirthManagerConfig {
|
|
7
|
+
/** Show drag-and-drop file upload zone */
|
|
8
|
+
showDragDrop: boolean;
|
|
9
|
+
/** Show "Start Over" button */
|
|
10
|
+
showStartOver: boolean;
|
|
11
|
+
/** Show "Insert Measurement" button and modal */
|
|
12
|
+
showInsertMeasurement: boolean;
|
|
13
|
+
/** Allow debug mode toggle (requires isDebugUser) */
|
|
14
|
+
showDebug: boolean;
|
|
15
|
+
/** Show 1"/2" measurement spacing toggle */
|
|
16
|
+
showSpacingToggle: boolean;
|
|
17
|
+
/** Show AK/BK amputation type selection modal */
|
|
18
|
+
showAmputationModal: boolean;
|
|
19
|
+
/** Show left navigation sidebar */
|
|
20
|
+
showNavigation: boolean;
|
|
21
|
+
/** Show top toolbar ribbon */
|
|
22
|
+
showToolbar: boolean;
|
|
23
|
+
}
|
|
24
|
+
/** Default config for the internal application (all features enabled) */
|
|
25
|
+
export declare const INTERNAL_CONFIG: GirthManagerConfig;
|
|
26
|
+
/** Config for the external widget (minimal UI) */
|
|
27
|
+
export declare const WIDGET_CONFIG: GirthManagerConfig;
|
|
28
|
+
export declare const GirthManagerConfigContext: import("react").Context<GirthManagerConfig>;
|
|
29
|
+
export declare function useGirthManagerConfig(): GirthManagerConfig;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export { GirthManagerConfigContext, useGirthManagerConfig, INTERNAL_CONFIG, WIDGET_CONFIG } from "./config";
|
|
2
|
+
export type { GirthManagerConfig } from "./config";
|
|
3
|
+
export { GirthManagerCore } from "./GirthManagerCore";
|
|
4
|
+
export type { GirthManagerCoreProps, GirthManagerResult } from "./GirthManagerCore";
|
|
5
|
+
export { useMeasurementStore } from "./store";
|
|
6
|
+
export type { WasmMeshSetType, LandmarkPoint, MeasurementData, SliceResult, Seg } from "./processing/types";
|
|
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
|
+
export { parseObjVertexColors, transferVertexColors } from "./processing/vertex-colors";
|
|
9
|
+
export { computeSliceAtYOnce, computeSliceAtY, buildBVH, calcLineLength, computeCircumferenceAtPlane } from "./processing/slice";
|
|
10
|
+
export { intersectMeshWithPlane, findBestCutPlane } from "./processing/cut-plane";
|
|
11
|
+
export { computeBarycentricCoords, sliceMeshAtPlane } from "./processing/mesh-ops";
|
|
12
|
+
export type { ShellDetectionResult } from "./processing/mesh-ops";
|
|
13
|
+
export { runPCAOnRegion } from "./processing/alignment";
|
|
14
|
+
export { validateProcessingResult } from "./processing/validation";
|
|
15
|
+
export { stlToObjString } from "./processing/stl-convert";
|
|
16
|
+
export { processWithWasm, processWithObjLoader } from "./processing/wasm-loader";
|
|
17
|
+
export type { WasmProcessResult, ComponentDebugInfo } from "./processing/wasm-loader";
|
|
18
|
+
export { runProcessingPipeline, cutMeshAtY } from "./processing/pipeline";
|
|
19
|
+
export type { PipelineCallbacks } from "./processing/pipeline";
|
|
20
|
+
export { ErrorDisplay } from "./components/ErrorDisplay";
|
|
21
|
+
export { LoadingSpinner } from "./components/LoadingSpinner";
|
|
22
|
+
export { ClickableMesh } from "./components/ClickableMesh";
|
|
23
|
+
export { LandmarkMarkers } from "./components/LandmarkMarkers";
|
|
24
|
+
export { CircumferenceSlice } from "./components/CircumferenceSlice";
|
|
25
|
+
export { CircumferenceMeasurements } from "./components/CircumferenceMeasurements";
|
|
26
|
+
export { VerticalDimension } from "./components/VerticalDimension";
|
|
27
|
+
export { DraggableLineHandle } from "./components/DraggableLineHandle";
|
|
28
|
+
export { CameraFit } from "./components/CameraFit";
|
|
29
|
+
export { AlignedOrbitControls } from "./components/AlignedOrbitControls";
|
|
30
|
+
export { ScaleNotice } from "./components/ScaleNotice";
|
|
31
|
+
export { ShellNotice } from "./components/ShellNotice";
|
|
32
|
+
export { Stepper } from "./components/Stepper";
|
|
33
|
+
export type { StepperStep, StepperProps } from "./components/Stepper";
|
|
34
|
+
export { TransverseView } from "./components/TransverseView";
|
|
35
|
+
export { DebugOverlays, DEFAULT_DEBUG_LAYERS, OBBAlignmentLine } from "./components/DebugOverlays";
|
|
36
|
+
export type { DebugLayerVisibility } from "./components/DebugOverlays";
|
|
37
|
+
export { DebugPanel } from "./components/DebugPanel";
|
|
38
|
+
export { useCachedBVH } from "./hooks/useCachedBVH";
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import * as THREE from "three";
|
|
2
|
+
import { Vector3 } from "three";
|
|
3
|
+
/** Run PCA alignment on a region from minY to maxY. Returns the principal axis or null. */
|
|
4
|
+
export declare function runPCAOnRegion(geometry: THREE.BufferGeometry, minY: number, maxY: number): Vector3 | null;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const LABEL_X_OFFSET_RATIO = 0.45;
|
|
2
|
+
export declare const BVH_MAX_LEAF_TRIS = 3;
|
|
3
|
+
export declare const WELD_EPSILON = 0.001;
|
|
4
|
+
export declare const MM_PER_INCH = 25.4;
|
|
5
|
+
export declare const ABOVE_POINT_OFFSET_INCHES = 2;
|
|
6
|
+
export declare const AUTO_SCALE_VOLUME_THRESHOLD = 5;
|
|
7
|
+
export declare const RETRY_OFFSETS: number[];
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as THREE from "three";
|
|
2
|
+
import { Vector3 } from "three";
|
|
3
|
+
import { MeshBVH } from "three-mesh-bvh";
|
|
4
|
+
import type { Seg } from "./types";
|
|
5
|
+
export declare function intersectMeshWithPlane(bvhOrGeometry: MeshBVH | THREE.BufferGeometry, planePoint: Vector3, planeNormal: Vector3): Seg[];
|
|
6
|
+
/** Like stitchOneLoop but picks the loop whose centroid is closest to `nearPoint` */
|
|
7
|
+
export declare function stitchLoopNearPoint(segments: Seg[], nearPoint: Vector3, eps?: number): Vector3[];
|
|
8
|
+
/** Compute the centroid of a closed loop of points */
|
|
9
|
+
export declare function loopCentroid(loop: Vector3[]): Vector3;
|
|
10
|
+
export declare function findBestCutPlane(geometry: THREE.BufferGeometry, greenPoint: Vector3, redPoint: Vector3): {
|
|
11
|
+
normal: Vector3;
|
|
12
|
+
circumference: number;
|
|
13
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import * as THREE from "three";
|
|
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
|
+
/** Compute barycentric coordinates of point p with respect to triangle (a, b, c) */
|
|
26
|
+
export declare function computeBarycentricCoords(p: Vector3, a: Vector3, b: Vector3, c: Vector3): {
|
|
27
|
+
u: number;
|
|
28
|
+
v: number;
|
|
29
|
+
w: number;
|
|
30
|
+
};
|
|
31
|
+
/** Slice mesh at an arbitrary plane. By default keeps only the component closest to `keepPoint`;
|
|
32
|
+
* pass `keepAllComponents = true` to retain all geometry on the kept side (e.g. double-shell). */
|
|
33
|
+
export declare function sliceMeshAtPlane(geometry: THREE.BufferGeometry, planeOrigin: Vector3, planeNormal: Vector3, keepPoint: Vector3, keepAllComponents?: boolean): THREE.BufferGeometry;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import * as THREE from "three";
|
|
2
|
+
import { Vector3 } from "three";
|
|
3
|
+
export interface PipelineCallbacks {
|
|
4
|
+
onStatus: (message: string) => void;
|
|
5
|
+
setDoubleShell?: (isDoubleShell: boolean) => void;
|
|
6
|
+
/** When true, skip double-shell detection (inner shell was already extracted during WASM processing) */
|
|
7
|
+
skipDoubleShellDetection?: boolean;
|
|
8
|
+
addLandmarkPoint: (point: {
|
|
9
|
+
faceIndex: number;
|
|
10
|
+
vertexIndices: [number, number, number];
|
|
11
|
+
position: {
|
|
12
|
+
x: number;
|
|
13
|
+
y: number;
|
|
14
|
+
z: number;
|
|
15
|
+
};
|
|
16
|
+
barycentricCoords: {
|
|
17
|
+
u: number;
|
|
18
|
+
v: number;
|
|
19
|
+
w: number;
|
|
20
|
+
};
|
|
21
|
+
}) => void;
|
|
22
|
+
removeLandmarkPoint: (index: number) => void;
|
|
23
|
+
updateLandmarkPositions: (positions: {
|
|
24
|
+
x: number;
|
|
25
|
+
y: number;
|
|
26
|
+
z: number;
|
|
27
|
+
}[]) => void;
|
|
28
|
+
setAligned: (aligned: boolean) => void;
|
|
29
|
+
setCut: (cut: boolean) => void;
|
|
30
|
+
setModelSize: (size: number) => void;
|
|
31
|
+
setOriginalEndY: (y: number) => void;
|
|
32
|
+
setAdjustedStartY: (y: number | null) => void;
|
|
33
|
+
setAdjustedEndY: (y: number | null) => void;
|
|
34
|
+
setError: (error: string | null) => void;
|
|
35
|
+
setClippedReferenceGeometry?: (geometry: THREE.BufferGeometry | null) => void;
|
|
36
|
+
}
|
|
37
|
+
/** Cut mesh at Y-plane, keep geometry below cutY, keep largest component closest to redPoint */
|
|
38
|
+
export declare function cutMeshAtY(mesh: THREE.Mesh, currentLandmarks: Vector3[], geometry: THREE.BufferGeometry, cutOffsetInches: number, callbacks: PipelineCallbacks, refGeo?: THREE.BufferGeometry | null): Vector3[];
|
|
39
|
+
/** Full processing pipeline: find cut plane, slice, align, PCA, cut, validate with retries */
|
|
40
|
+
export declare function runProcessingPipeline(mesh: THREE.Mesh, landmarkPoints: {
|
|
41
|
+
position: {
|
|
42
|
+
x: number;
|
|
43
|
+
y: number;
|
|
44
|
+
z: number;
|
|
45
|
+
};
|
|
46
|
+
}[], measurementSpacingMm: number, callbacks: PipelineCallbacks): void;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import * as THREE from "three";
|
|
2
|
+
import { Vector3 } from "three";
|
|
3
|
+
import { MeshBVH } from "three-mesh-bvh";
|
|
4
|
+
import type { Seg, SliceResult } from "./types";
|
|
5
|
+
export declare function weldKey(v: Vector3, eps: number): string;
|
|
6
|
+
export declare function cleanLoop(points: Vector3[], eps: number): Vector3[];
|
|
7
|
+
export declare function calcLineLength(points: Vector3[]): number;
|
|
8
|
+
export declare function stitchOneLoop(segments: Seg[], eps?: number, preferInner?: boolean): Vector3[];
|
|
9
|
+
export declare function computeSliceAtYOnce(bvh: MeshBVH, geometry: THREE.BufferGeometry, yPosition: number, useInnerSurface?: boolean): SliceResult;
|
|
10
|
+
export declare function computeSliceAtY(bvh: MeshBVH, geometry: THREE.BufferGeometry, yPosition: number, useInnerSurface?: boolean): SliceResult;
|
|
11
|
+
/** Compute circumference of the slice at an arbitrary plane (any normal). */
|
|
12
|
+
export declare function computeCircumferenceAtPlane(bvh: MeshBVH, geometry: THREE.BufferGeometry, planePoint: Vector3, planeNormal: Vector3): number;
|
|
13
|
+
/** Compute BVH for a geometry (used in useCachedBVH hook and standalone) */
|
|
14
|
+
export declare function buildBVH(geometry: THREE.BufferGeometry): MeshBVH;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { Vector3 } from "three";
|
|
2
|
+
export interface WasmMeshSetType {
|
|
3
|
+
loadObjString(data: string): void;
|
|
4
|
+
applyCloseHoles(maxHoleSize: number): void;
|
|
5
|
+
applyMergeCloseVertices(threshold: number): void;
|
|
6
|
+
splitAndKeepLargest(): void;
|
|
7
|
+
getComponentCount(): number;
|
|
8
|
+
extractInnerShell(maxWallThickness: number): boolean;
|
|
9
|
+
getComponentLabels(): Int32Array;
|
|
10
|
+
getVertices(): Float32Array;
|
|
11
|
+
getFaces(): Int32Array;
|
|
12
|
+
autoScaleToMm(volumeThreshold: number): boolean;
|
|
13
|
+
free(): void;
|
|
14
|
+
}
|
|
15
|
+
export interface LandmarkPoint {
|
|
16
|
+
faceIndex: number;
|
|
17
|
+
vertexIndices: [number, number, number];
|
|
18
|
+
position: {
|
|
19
|
+
x: number;
|
|
20
|
+
y: number;
|
|
21
|
+
z: number;
|
|
22
|
+
};
|
|
23
|
+
barycentricCoords: {
|
|
24
|
+
u: number;
|
|
25
|
+
v: number;
|
|
26
|
+
w: number;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export interface MeasurementData {
|
|
30
|
+
yPosition: number;
|
|
31
|
+
originalValue: number;
|
|
32
|
+
modifiedValue: number | null;
|
|
33
|
+
}
|
|
34
|
+
export interface SliceResult {
|
|
35
|
+
linePoints: Vector3[];
|
|
36
|
+
lineLength: number;
|
|
37
|
+
rightmostPoint: Vector3;
|
|
38
|
+
isClosed?: boolean;
|
|
39
|
+
}
|
|
40
|
+
export type Seg = {
|
|
41
|
+
a: Vector3;
|
|
42
|
+
b: Vector3;
|
|
43
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import * as THREE from "three";
|
|
2
|
+
/** Validate processing results: check geometry is non-empty, height, and circumference ratios */
|
|
3
|
+
export declare function validateProcessingResult(finalGeometry: THREE.BufferGeometry, greenY: number, redY: number, spacing: number): {
|
|
4
|
+
valid: boolean;
|
|
5
|
+
reason: string;
|
|
6
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import * as THREE from "three";
|
|
2
|
+
/** Parse vertex positions and colors from OBJ text. Returns null if no vertex colors found. */
|
|
3
|
+
export declare function parseObjVertexColors(objText: string): {
|
|
4
|
+
positions: Float32Array;
|
|
5
|
+
colors: Float32Array;
|
|
6
|
+
} | null;
|
|
7
|
+
/** Transfer vertex colors from original OBJ data to processed geometry via nearest-vertex matching with spatial grid. */
|
|
8
|
+
export declare function transferVertexColors(geometry: THREE.BufferGeometry, origPositions: Float32Array, origColors: Float32Array, scaleFactor: number): void;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import * as THREE from "three";
|
|
2
|
+
import type { WasmMeshSetType } from "./types";
|
|
3
|
+
/** Per-component debug geometry */
|
|
4
|
+
export interface ComponentDebugInfo {
|
|
5
|
+
geometries: THREE.BufferGeometry[];
|
|
6
|
+
labels: string[];
|
|
7
|
+
colors: string[];
|
|
8
|
+
innerIdx: number | null;
|
|
9
|
+
}
|
|
10
|
+
export interface WasmProcessResult {
|
|
11
|
+
geometry: THREE.BufferGeometry;
|
|
12
|
+
wasScaled: boolean;
|
|
13
|
+
/** True if a double-shell was detected and the inner shell was extracted */
|
|
14
|
+
innerShellExtracted: boolean;
|
|
15
|
+
/** Debug: per-component colored geometries (only populated when componentCount >= 2) */
|
|
16
|
+
componentDebug: ComponentDebugInfo | null;
|
|
17
|
+
}
|
|
18
|
+
/** Process OBJ string through WASM pipeline (merge, clean, close holes, scale) */
|
|
19
|
+
export declare function processWithWasm(objContents: string, wasmModule: {
|
|
20
|
+
WasmMeshSet: new () => WasmMeshSetType;
|
|
21
|
+
}, onStatus?: (message: string) => void): Promise<WasmProcessResult | null>;
|
|
22
|
+
/** Fallback: process OBJ string with Three.js OBJLoader */
|
|
23
|
+
export declare function processWithObjLoader(objContents: string): THREE.BufferGeometry | null;
|
|
@@ -1,17 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
faceIndex: number;
|
|
3
|
-
vertexIndices: [number, number, number];
|
|
4
|
-
position: {
|
|
5
|
-
x: number;
|
|
6
|
-
y: number;
|
|
7
|
-
z: number;
|
|
8
|
-
};
|
|
9
|
-
barycentricCoords: {
|
|
10
|
-
u: number;
|
|
11
|
-
v: number;
|
|
12
|
-
w: number;
|
|
13
|
-
};
|
|
14
|
-
}
|
|
1
|
+
import type { LandmarkPoint } from "./processing/types";
|
|
15
2
|
interface MeasurementStore {
|
|
16
3
|
landmarkPoints: LandmarkPoint[];
|
|
17
4
|
isAligned: boolean;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type WasmMeshSetType } from "@galileo/girth-manager-ui";
|
|
2
|
+
import type { WidgetRequest, WidgetResponse } from "./types";
|
|
3
|
+
export interface GirthManagerWidgetProps {
|
|
4
|
+
/** Widget input configuration */
|
|
5
|
+
request: WidgetRequest;
|
|
6
|
+
/** Called when "Continue to Next Step" is clicked with the full response payload */
|
|
7
|
+
onComplete?: (response: WidgetResponse) => void;
|
|
8
|
+
/** Pre-loaded WASM module. The consuming app must load galileo-core-geo and pass it here. */
|
|
9
|
+
wasmModule?: {
|
|
10
|
+
WasmMeshSet: new () => WasmMeshSetType;
|
|
11
|
+
} | null;
|
|
12
|
+
}
|
|
13
|
+
export declare const GirthManagerWidget: ({ request, onComplete, wasmModule }: GirthManagerWidgetProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { GirthManagerWidget } from "./GirthManagerWidget";
|
|
2
|
+
export type { GirthManagerWidgetProps } from "./GirthManagerWidget";
|
|
3
|
+
export type { WidgetRequest, WidgetResponse, Circumference } from "./types";
|
|
4
|
+
export { getCircumferenceKeys, arrayToCircumference, circumferenceToArray } from "./types";
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Input contract for the Girth Manager widget.
|
|
3
|
+
* Mirrors the schema in docs/widget_interface.ts.
|
|
4
|
+
*/
|
|
5
|
+
export interface WidgetRequest {
|
|
6
|
+
/** Spacing type: above-knee or below-knee */
|
|
7
|
+
spacing_type: "AK" | "BK";
|
|
8
|
+
/** URL to the uploaded 3D scan file */
|
|
9
|
+
scan_url: string;
|
|
10
|
+
/** Optional circumference measurements from the order form (mm). Omit if not provided. */
|
|
11
|
+
form_measurements?: Circumference;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Output contract emitted by the widget when "Continue to Next Step" is clicked.
|
|
15
|
+
* Mirrors the schema in docs/widget_interface.ts.
|
|
16
|
+
*/
|
|
17
|
+
export interface WidgetResponse {
|
|
18
|
+
/** Spacing type: above-knee or below-knee */
|
|
19
|
+
spacing_type: "AK" | "BK";
|
|
20
|
+
/** Unit of all measurements in this response */
|
|
21
|
+
source_unit: "mm" | "inch";
|
|
22
|
+
/** File format of the scan */
|
|
23
|
+
file_format: "obj" | "stl";
|
|
24
|
+
/** Whether measurements were derived from the scan or taken from the order form */
|
|
25
|
+
measurement_source: "scan_derived" | "form_provided";
|
|
26
|
+
/** Whether the spacing uses a double-wall construction */
|
|
27
|
+
is_double_wall: boolean;
|
|
28
|
+
/** Whether measurements were converted from their original unit */
|
|
29
|
+
is_unit_converted: boolean;
|
|
30
|
+
/** Circumference measurements from the order form (mm). Only includes fields the user filled in. Omitted if none were provided. */
|
|
31
|
+
form_measurements?: Circumference;
|
|
32
|
+
/** Circumference measurements derived from the 3D scan (mm) */
|
|
33
|
+
scan_measurements: Circumference;
|
|
34
|
+
/** Difference between form and scan measurements (mm). Only present for positions where both form and scan values exist. Omitted if no form data was provided. */
|
|
35
|
+
measurement_variance?: Circumference;
|
|
36
|
+
/** URL to the uploaded 3D scan file */
|
|
37
|
+
scan_url: string;
|
|
38
|
+
/** Frontal height of the residual limb (mm) */
|
|
39
|
+
frontal_height: number;
|
|
40
|
+
/** Medio-lateral transverse dimension (mm) */
|
|
41
|
+
transverse_ml: number;
|
|
42
|
+
/** Anterior-posterior transverse dimension (mm) */
|
|
43
|
+
transverse_ap: number;
|
|
44
|
+
}
|
|
45
|
+
export interface Circumference {
|
|
46
|
+
/** 2" above the reference landmark (mm) */
|
|
47
|
+
"2_above"?: number | undefined | null;
|
|
48
|
+
/** 1" above the reference landmark (mm) */
|
|
49
|
+
"1_above"?: number | undefined | null;
|
|
50
|
+
/** At the reference landmark (mm) */
|
|
51
|
+
at_ref?: number | undefined | null;
|
|
52
|
+
/** 1" below the reference landmark (mm) */
|
|
53
|
+
"1_below"?: number | undefined | null;
|
|
54
|
+
/** 2" below the reference landmark (mm) */
|
|
55
|
+
"2_below"?: number | undefined | null;
|
|
56
|
+
/** 3" below the reference landmark (mm) */
|
|
57
|
+
"3_below"?: number | undefined | null;
|
|
58
|
+
/** 4" below the reference landmark (mm) */
|
|
59
|
+
"4_below"?: number | undefined | null;
|
|
60
|
+
/** 5" below the reference landmark (mm) */
|
|
61
|
+
"5_below"?: number | undefined | null;
|
|
62
|
+
/** 6" below the reference landmark (mm) */
|
|
63
|
+
"6_below"?: number | undefined | null;
|
|
64
|
+
/** 7" below the reference landmark (mm) */
|
|
65
|
+
"7_below"?: number | undefined | null;
|
|
66
|
+
/** 8" below the reference landmark (mm) */
|
|
67
|
+
"8_below"?: number | undefined | null;
|
|
68
|
+
/** 9" below the reference landmark (mm) */
|
|
69
|
+
"9_below"?: number | undefined | null;
|
|
70
|
+
}
|
|
71
|
+
/** Ordered keys for mapping measurement arrays to Circumference fields */
|
|
72
|
+
export declare function getCircumferenceKeys(spacingType: "AK" | "BK"): (keyof Circumference)[];
|
|
73
|
+
/** Convert a measurement values array to a Circumference object */
|
|
74
|
+
export declare function arrayToCircumference(values: (number | null | undefined)[], spacingType: "AK" | "BK"): Circumference;
|
|
75
|
+
/** Convert a Circumference object to an ordered measurement values array */
|
|
76
|
+
export declare function circumferenceToArray(circ: Circumference | undefined, spacingType: "AK" | "BK"): number[] | undefined;
|