forgecad 0.10.4 → 0.10.5
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/assets/{AdminPage-B3L3W1Uo.js → AdminPage-raksfnNA.js} +1 -1
- package/dist/assets/{BenchmarkPage-DXKVXMrJ.js → BenchmarkPage-DP3RxhPs.js} +2 -2
- package/dist/assets/{BlogPage-B7BWxOCg.js → BlogPage-D7Dos-vl.js} +1 -1
- package/dist/assets/{DocsPage-BPGGwht1.js → DocsPage-DO1kvBns.js} +7 -1
- package/dist/assets/{EditorApp-BWUGCdD5.js → EditorApp-DQJmcmRT.js} +9 -8
- package/dist/assets/{EmbedViewer-DygByZS2.js → EmbedViewer-DFDUhOma.js} +2 -2
- package/dist/assets/{LandingPageProofDriven-BoVE7JGY.js → LandingPageProofDriven-DbE_tp8-.js} +2 -2
- package/dist/assets/{LegalPage-Din8wv8d.js → LegalPage-CominSso.js} +2 -2
- package/dist/assets/{PricingPage-C2PMzmDc.js → PricingPage-CcVIN9yj.js} +2 -2
- package/dist/assets/{SettingsPage-BlJDCRe8.js → SettingsPage-DLWcP289.js} +1 -1
- package/dist/assets/{app-BsRYSfxY.js → app-xW3hOdq9.js} +1135 -320
- package/dist/assets/{backendInit-6C0DLgH0.js → backendInit-mDHk97u7.js} +6630 -2493
- package/dist/assets/cli/{render-XXol_ET7.js → render--SIU27W_.js} +1263 -112
- package/dist/assets/{constructionHistoryWorker-cTHWRJEi.js → constructionHistoryWorker-uEe_Q7Kg.js} +1861 -610
- package/dist/assets/{evalWorker-BssDYW9u.js → evalWorker-BqyDHDcI.js} +6254 -2177
- package/dist/assets/{forgecad_geometry-CZ_IfuvA.js → forgecad_geometry-D8rWX7nQ.js} +1 -1
- package/dist/assets/{forgecad_geometry_bg-C3rQHfwg.wasm → forgecad_geometry_bg-ObqfqjJT.wasm} +0 -0
- package/dist/assets/{inspectWorker-ymhBV4Ll.js → inspectWorker-UXMxlcR8.js} +2738 -742
- package/dist/assets/{jointPose-B0blBj9A.js → jointPose-bYMlwU3v.js} +1 -1
- package/dist/assets/{landing-proof-driven-Cpf-MIbI.css → landing-proof-driven-_u4v_xQb.css} +2 -2
- package/dist/assets/{manifold-B_7QXpGB.js → manifold-BR7UYI4P.js} +1 -1
- package/dist/assets/{manifold-CYlIm-M6.js → manifold-CyOV5B9S.js} +2 -2
- package/dist/assets/{manifold-CNShmpEJ.js → manifold-D4d5NQst.js} +1 -1
- package/dist/assets/{reportWorker-Cb5eyM7D.js → reportWorker-DsaICZsn.js} +6010 -2032
- package/dist/cli/render.html +1 -1
- package/dist/docs/index.html +2 -2
- package/dist/docs-raw/CLI.md +4 -2
- package/dist/docs-raw/generated/assembly.md +76 -3
- package/dist/docs-raw/generated/concepts.md +31 -4
- package/dist/docs-raw/generated/core.md +159 -21
- package/dist/docs-raw/generated/curves.md +344 -6
- package/dist/docs-raw/generated/runtime-names.md +12 -12
- package/dist/docs-raw/generated/sketch.md +16 -3
- package/dist/docs-raw/guides/inspection-bundles.md +4 -2
- package/dist/docs-raw/guides/structural-fea.md +224 -0
- package/dist/docs-raw/skills/forgecad.md +1 -0
- package/dist/index.html +1 -1
- package/dist/sitemap.xml +15 -15
- package/dist-cli/{check-compiler-4RPB6SB5.js → check-compiler-7YAHVXYM.js} +1 -1
- package/dist-cli/{check-query-propagation-KN3DFQTX.js → check-query-propagation-ZRR6IOJW.js} +1 -1
- package/dist-cli/{chunk-UHBRMYA6.js → chunk-VNM67DIV.js} +6489 -2333
- package/dist-cli/forgecad.js +5258 -717
- package/dist-cli/forgecad_geometry_bg.wasm +0 -0
- package/dist-skill/CONTEXT.md +827 -45
- package/dist-skill/SKILL.md +1 -0
- package/dist-skill/docs/CLI.md +4 -2
- package/dist-skill/docs/generated/assembly.md +73 -3
- package/dist-skill/docs/generated/core.md +159 -21
- package/dist-skill/docs/generated/curves.md +343 -6
- package/dist-skill/docs/generated/runtime-names.md +12 -12
- package/dist-skill/docs/generated/sketch.md +16 -3
- package/dist-skill/docs/guides/inspection-bundles.md +4 -2
- package/dist-skill/docs/guides/structural-fea.md +224 -0
- package/dist-skill/website/skills/forgecad.md +1 -0
- package/examples/analysis/structural-stress-fea.forge.js +19 -0
- package/examples/api/blend-full-round.forge.js +37 -0
- package/examples/api/blend-variable-radius.forge.js +51 -0
- package/examples/api/curve-project-and-intersect.forge.js +59 -0
- package/examples/api/extrude-up-to-face.forge.js +47 -0
- package/examples/api/spoon-full-tang-handle.forge.js +148 -0
- package/examples/api/surface-boundarynet-dished-bowl.forge.js +63 -0
- package/examples/api/surface-fill-interior-constraints.forge.js +59 -0
- package/package.json +4 -1
- /package/dist/assets/{landing-proof-driven-BxZZh5r5.js → landing-proof-driven-DNPRKL_p.js} +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/EditorApp-C5f24ZN9.css","assets/landing-proof-driven-
|
|
1
|
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/EditorApp-C5f24ZN9.css","assets/landing-proof-driven-_u4v_xQb.css","assets/BenchmarkPage-BAbsyMaF.css","assets/PricingPage-BPF6HKyO.css","assets/LegalPage-BRlScr9A.css"])))=>i.map(i=>d[i]);
|
|
2
2
|
var __defProp = Object.defineProperty;
|
|
3
3
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
4
4
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
5
5
|
var _a2;
|
|
6
6
|
import { c as create, j as jsxRuntimeExports, r as reactExports, a as createWithEqualityFn, R as React, T as Tb, s as schedulerExports, b as clientExports, d as reactDomExports, u as useParams, e as useSearchParams, f as useNavigate, L as Link, g as useLocation, B as BrowserRouter, h as Routes, i as Route, N as Navigate } from "./vendor-react-6j1Kke-Y.js";
|
|
7
|
-
import { _ as __vitePreload, S as SDF_PROGRAM_OP, z as zipSync, s as strToU8, W as WebGLRenderer, R as Raycaster, O as OrthographicCamera$1, P as PerspectiveCamera$1, a as Scene, b as PCFSoftShadowMap, V as VSMShadowMap, c as PCFShadowMap, B as BasicShadowMap, C as ColorManagement, L as LinearSRGBColorSpace, d as SRGBColorSpace, N as NoToneMapping, A as ACESFilmicToneMapping, e as Layers, f as Color, g as RGBAFormat, U as UnsignedByteType, h as Vector3, i as Vector2, j as Clock, T as THREE, D as DoubleSide, k as REVISION, M as Mesh, I as IcosahedronGeometry, l as ShaderMaterial, m as Spherical, Q as Quaternion, n as MOUSE, o as TOUCH, p as Ray, q as Plane, r as DataTextureLoader, H as HalfFloatType, F as FloatType, t as DataUtils, u as LinearFilter, v as RedFormat, w as InstancedBufferGeometry, x as Float32BufferAttribute, y as InstancedInterleavedBuffer, E as InterleavedBufferAttribute, G as WireframeGeometry, J as Box3, K as Sphere, X as UniformsUtils, Y as UniformsLib, Z as Vector4, $ as Line3, a0 as Matrix4, a1 as MathUtils, a2 as Uniform, a3 as WebGLRenderTarget, a4 as DepthTexture, a5 as BackSide, a6 as ClampToEdgeWrapping, a7 as PlaneGeometry, a8 as UVMapping, a9 as DataTexture, aa as Texture, ab as MeshBasicMaterial, ac as IntType, ad as ShortType, ae as ByteType, af as UnsignedIntType, ag as Loader, ah as LoadingManager, ai as LinearMipMapLinearFilter, aj as FileLoader, ak as NoBlending, al as CubeReflectionMapping, am as EquirectangularReflectionMapping, an as CubeTextureLoader, ao as WebGLCubeRenderTarget, ap as ConstraintSketch, aq as setSketchPlacement3D, ar as Sketch, as as PROFILE_BACKEND_MARKER, at as FrozenShape, au as setShapeCompilePlan, av as hasAnyPorts, aw as setShapePortsInternal, ax as markShapePortsUsed, ay as writeViewPreferences, az as setParamOverrides, aA as readViewPreferences, aB as resolveForgeRenderStyle, aC as isConstraintSketch, aD as updateConstraintValue, aE as linearizeMultiObjectSteps, aF as getShapeCompilePlan, aG as resolveCameraControlMode, aH as resolveComparisonOpacity, aI as resolveComparisonInspectMode, aJ as resolveBooleanPref, aK as resolveInspectQuantizeBands, aL as resolveInspectIsolineSpacing, aM as resolveInspectColormap, aN as resolveThicknessColorRange, aO as resolveInspectPointSampleCount, aP as SCAN_PROXY_GRANULARITY_DEFAULT, aQ as DEFAULT_MANUAL_SCENE_SETTINGS, aR as resolveManualSceneSettings, aS as publishSolverWasmRunDebug, aT as resolveForgeQualityPreset, aU as DEFAULT_INSPECT_ISOLINES_ENABLED, aV as SCAN_PROXY_MATRIX_GRANULARITY_MAX, aW as findJointAnimationClip, aX as resolveJointAnimation, aY as resolveJointViewValues, aZ as resolveImportPath, a_ as DEFAULT_INSPECT_CRITICAL_LINE_ENABLED, a$ as resolveScanProxyGranularity, b0 as DEFAULT_COMPARISON_REFERENCE_OPACITY, b1 as DEFAULT_COMPARISON_CANDIDATE_OPACITY, b2 as BufferGeometry, b3 as LineBasicMaterial, b4 as Line$1, b5 as LineDashedMaterial, b6 as CanvasTexture, b7 as Object3D, b8 as FogExp2, b9 as Fog, ba as AmbientLight, bb as HemisphereLight, bc as SpotLight, bd as PointLight, be as DirectionalLight, bf as BufferAttribute, bg as heatPointsForSide, bh as COMPARISON_COLORS, bi as comparisonHeatDepthTest, bj as comparisonHeatEdgeOpacity, bk as comparisonHeatPatchOpacity, bl as shapeToGeometry, bm as buildComparisonHeatPatchGeometry, bn as EdgesGeometry, bo as buildShapeFromCompilePlan, bp as VIEWPORT_CAMERA_STORAGE_KEY, bq as parseViewportCameraState, br as getKernelFaceNameForTriangle, bs as OBJECT_CONTEXT_MENU_MARGIN, bt as buildVisibleHistoryStacks, bu as sketchToSvg, bv as sketchToDxf, bw as runScript, bx as MeshPhysicalMaterial, by as LineSegments, bz as findDesignTraceNodeForConstructionStep, bA as formatDesignTraceAnchor, bB as waitForAnimationFrame, bC as selectBuildLedgerNodes, bD as
|
|
7
|
+
import { _ as __vitePreload, S as SDF_PROGRAM_OP, z as zipSync, s as strToU8, W as WebGLRenderer, R as Raycaster, O as OrthographicCamera$1, P as PerspectiveCamera$1, a as Scene, b as PCFSoftShadowMap, V as VSMShadowMap, c as PCFShadowMap, B as BasicShadowMap, C as ColorManagement, L as LinearSRGBColorSpace, d as SRGBColorSpace, N as NoToneMapping, A as ACESFilmicToneMapping, e as Layers, f as Color, g as RGBAFormat, U as UnsignedByteType, h as Vector3, i as Vector2, j as Clock, T as THREE, D as DoubleSide, k as REVISION, M as Mesh, I as IcosahedronGeometry, l as ShaderMaterial, m as Spherical, Q as Quaternion, n as MOUSE, o as TOUCH, p as Ray, q as Plane, r as DataTextureLoader, H as HalfFloatType, F as FloatType, t as DataUtils, u as LinearFilter, v as RedFormat, w as InstancedBufferGeometry, x as Float32BufferAttribute, y as InstancedInterleavedBuffer, E as InterleavedBufferAttribute, G as WireframeGeometry, J as Box3, K as Sphere, X as UniformsUtils, Y as UniformsLib, Z as Vector4, $ as Line3, a0 as Matrix4, a1 as MathUtils, a2 as Uniform, a3 as WebGLRenderTarget, a4 as DepthTexture, a5 as BackSide, a6 as ClampToEdgeWrapping, a7 as PlaneGeometry, a8 as UVMapping, a9 as DataTexture, aa as Texture, ab as MeshBasicMaterial, ac as IntType, ad as ShortType, ae as ByteType, af as UnsignedIntType, ag as Loader, ah as LoadingManager, ai as LinearMipMapLinearFilter, aj as FileLoader, ak as NoBlending, al as CubeReflectionMapping, am as EquirectangularReflectionMapping, an as CubeTextureLoader, ao as WebGLCubeRenderTarget, ap as ConstraintSketch, aq as setSketchPlacement3D, ar as Sketch, as as PROFILE_BACKEND_MARKER, at as FrozenShape, au as setShapeCompilePlan, av as hasAnyPorts, aw as setShapePortsInternal, ax as markShapePortsUsed, ay as writeViewPreferences, az as setParamOverrides, aA as readViewPreferences, aB as resolveForgeRenderStyle, aC as isConstraintSketch, aD as updateConstraintValue, aE as linearizeMultiObjectSteps, aF as getShapeCompilePlan, aG as resolveCameraControlMode, aH as resolveComparisonOpacity, aI as resolveComparisonInspectMode, aJ as resolveBooleanPref, aK as resolveInspectQuantizeBands, aL as resolveInspectIsolineSpacing, aM as resolveInspectColormap, aN as resolveThicknessColorRange, aO as resolveInspectPointSampleCount, aP as SCAN_PROXY_GRANULARITY_DEFAULT, aQ as DEFAULT_MANUAL_SCENE_SETTINGS, aR as resolveManualSceneSettings, aS as publishSolverWasmRunDebug, aT as resolveForgeQualityPreset, aU as DEFAULT_INSPECT_ISOLINES_ENABLED, aV as SCAN_PROXY_MATRIX_GRANULARITY_MAX, aW as findJointAnimationClip, aX as resolveJointAnimation, aY as resolveJointViewValues, aZ as resolveImportPath, a_ as DEFAULT_INSPECT_CRITICAL_LINE_ENABLED, a$ as resolveScanProxyGranularity, b0 as DEFAULT_COMPARISON_REFERENCE_OPACITY, b1 as DEFAULT_COMPARISON_CANDIDATE_OPACITY, b2 as BufferGeometry, b3 as LineBasicMaterial, b4 as Line$1, b5 as LineDashedMaterial, b6 as CanvasTexture, b7 as Object3D, b8 as FogExp2, b9 as Fog, ba as AmbientLight, bb as HemisphereLight, bc as SpotLight, bd as PointLight, be as DirectionalLight, bf as BufferAttribute, bg as heatPointsForSide, bh as COMPARISON_COLORS, bi as comparisonHeatDepthTest, bj as comparisonHeatEdgeOpacity, bk as comparisonHeatPatchOpacity, bl as shapeToGeometry, bm as buildComparisonHeatPatchGeometry, bn as EdgesGeometry, bo as buildShapeFromCompilePlan, bp as VIEWPORT_CAMERA_STORAGE_KEY, bq as parseViewportCameraState, br as getKernelFaceNameForTriangle, bs as OBJECT_CONTEXT_MENU_MARGIN, bt as buildVisibleHistoryStacks, bu as sketchToSvg, bv as sketchToDxf, bw as runScript, bx as MeshPhysicalMaterial, by as LineSegments, bz as findDesignTraceNodeForConstructionStep, bA as formatDesignTraceAnchor, bB as waitForAnimationFrame, bC as selectBuildLedgerNodes, bD as UNIDENTIFIED_FACE_NAME, bE as getBakedEdges, bF as worldAuthorPlaneToLocal, bG as compileSdfProgramEvaluator3, bH as SDF_LINEAR_OUTPUT_COLOR_GLSL, bI as GLSL3, bJ as BoxGeometry, bK as Data3DTexture, bL as buildSdfRaymarchFragmentShader, bM as SDF_RAYMARCH_PROXY_VERTEX_SHADER, bN as scanProxySourceBytes, bO as disposeScanProxyGeometry, bP as scanProxyGeometryFromPayload, bQ as AdditiveBlending, bR as geometryWithVisibleVertexColors, bS as MeshBVH, bT as makeColorScaleTexture, bU as colorScaleLUT, bV as makeScalarValueTexture, bW as makeInspectScalarUniforms, bX as updateInspectScalarUniforms, bY as descriptorToThreeTexture, bZ as applyProjectedTexture, b_ as getRenderStylePreset, b$ as SCAN_RENDER_COLORS, c0 as NormalBlending, c1 as acceleratedRaycast, c2 as INSPECT_SCALAR_FRAGMENT_SHADER, c3 as INSPECT_SCALAR_VERTEX_SHADER, c4 as scanMaterialShellColor, c5 as ZEBRA_STRIPE_SOFTNESS, c6 as ZEBRA_STRIPE_SCALE, c7 as ZEBRA_LIGHT_COLOR, c8 as ZEBRA_DARK_COLOR, c9 as ZEBRA_ACCENT_COLOR, ca as ZEBRA_STRIPE_FRAGMENT_SHADER, cb as ZEBRA_STRIPE_VERTEX_SHADER, cc as SCAN_PROXY_LAYER_STYLES, cd as scanMaterialLayerStyles, ce as SURFACE_FIELD_FRAGMENT_SHADER, cf as SURFACE_FIELD_VERTEX_SHADER, cg as WORLD_UP$1, ch as CatmullRomCurve3, ci as TubeGeometry, cj as DEFAULT_THICKNESS_COLOR_RANGE, ck as DEFAULT_COLORMAP, cl as colorScaleHexStops, cm as PERFORMANCE_SAMPLE_INTERVAL_SEC, cn as formatPerformanceCount, co as NON_TEXT_INPUT_TYPES, cp as MeshStandardMaterial, cq as Shape, cr as ShapeGeometry, cs as ShaderLib, ct as CylinderGeometry, cu as createResolvedExplodeConfig, cv as explodeBoundsCenter, cw as explodeMergeBounds, cx as resolveExplodeDirective, cy as computeExplodeMotion, cz as getSketchWorldMatrix, cA as explodeAdd, cB as hasExplodeOverride, cC as resolveExplodeLocalFanDirection, cD as explodeMul, cE as explodeLeafFanStage, cF as normalizeCutPlane, cG as toClippingPlane, cH as isObjectExcludedFromCutPlane, cI as getShapePorts, cJ as getShapeUsedPorts, cK as DEFAULT_VIEW_CONFIG, cL as SECTION_EXPLORER_PLANE_NAME, cM as ZERO_OFFSET, cN as scanProxyGridForBounds, cO as IDENTITY_MATRIX$2, cP as OBJECT_CONTEXT_MENU_WIDTH, cQ as OBJECT_CONTEXT_MENU_HEIGHT, cR as triangleSoupFromMeshes, cS as compareTriangleSoups, cT as buildGeometryComparisonPointCloud, cU as aabbOverlaps, cV as aabbOverlapVolume, cW as DEFAULT_COLLISION_INSPECTION_OPTIONS, cX as resolveScalarSceneSampleBudget, cY as INSPECT_POINT_SAMPLE_COUNT_MIN, cZ as FOCUS_MODE_DIM_OPACITY, c_ as DEFAULT_THICKNESS_INSPECTION_OPTIONS, c$ as comparisonCandidateContextOpacity, d0 as Matrix3, d1 as initBackendForEvaluation } from "./backendInit-mDHk97u7.js";
|
|
8
8
|
function getCsrfToken() {
|
|
9
9
|
const match = document.cookie.match(/(?:^|;\s*)fc-csrf-token=([^;]+)/);
|
|
10
10
|
return match == null ? void 0 : match[1];
|
|
@@ -1551,7 +1551,7 @@ const is = {
|
|
|
1551
1551
|
return true;
|
|
1552
1552
|
}
|
|
1553
1553
|
};
|
|
1554
|
-
function buildGraph(object) {
|
|
1554
|
+
function buildGraph$1(object) {
|
|
1555
1555
|
const data = {
|
|
1556
1556
|
nodes: {},
|
|
1557
1557
|
materials: {},
|
|
@@ -2359,7 +2359,7 @@ function loadingFn(extensions, onProgress) {
|
|
|
2359
2359
|
}
|
|
2360
2360
|
if (extensions) extensions(loader);
|
|
2361
2361
|
return Promise.all(input.map((input2) => new Promise((res, reject) => loader.load(input2, (data) => {
|
|
2362
|
-
if (isObject3D(data == null ? void 0 : data.scene)) Object.assign(data, buildGraph(data.scene));
|
|
2362
|
+
if (isObject3D(data == null ? void 0 : data.scene)) Object.assign(data, buildGraph$1(data.scene));
|
|
2363
2363
|
res(data);
|
|
2364
2364
|
}, onProgress, (error) => reject(new Error(`Could not load ${input2}: ${error == null ? void 0 : error.message}`))))));
|
|
2365
2365
|
};
|
|
@@ -15976,7 +15976,7 @@ const CRASH_COOLDOWN_MS = 2e3;
|
|
|
15976
15976
|
class EvalWorkerClient {
|
|
15977
15977
|
constructor(workerFactory = () => new Worker(new URL(
|
|
15978
15978
|
/* @vite-ignore */
|
|
15979
|
-
"/assets/evalWorker-
|
|
15979
|
+
"/assets/evalWorker-BqyDHDcI.js",
|
|
15980
15980
|
import.meta.url
|
|
15981
15981
|
), { type: "module" })) {
|
|
15982
15982
|
__publicField(this, "worker", null);
|
|
@@ -17636,6 +17636,7 @@ const VIEW_INSPECT_CHANNELS = /* @__PURE__ */ new Set([
|
|
|
17636
17636
|
"distance",
|
|
17637
17637
|
"collisions",
|
|
17638
17638
|
"thickness",
|
|
17639
|
+
"throughThickness",
|
|
17639
17640
|
"roughness"
|
|
17640
17641
|
]);
|
|
17641
17642
|
const INSPECT_DISPLAY_MODES = /* @__PURE__ */ new Set(["heatmap", "points", "both", "scan"]);
|
|
@@ -17658,7 +17659,7 @@ function resolveInspectDisplayMode(value) {
|
|
|
17658
17659
|
return typeof value === "string" && INSPECT_DISPLAY_MODES.has(value) ? value : "heatmap";
|
|
17659
17660
|
}
|
|
17660
17661
|
function isScalarInspectChannel(channel) {
|
|
17661
|
-
return channel === "thickness" || channel === "roughness";
|
|
17662
|
+
return channel === "thickness" || channel === "throughThickness" || channel === "roughness";
|
|
17662
17663
|
}
|
|
17663
17664
|
function shouldUseScanRenderStyle(channel, displayMode) {
|
|
17664
17665
|
return isScalarInspectChannel(channel) && displayMode === "scan";
|
|
@@ -18978,7 +18979,17 @@ const useForgeStore = create((set, get) => ({
|
|
|
18978
18979
|
};
|
|
18979
18980
|
}),
|
|
18980
18981
|
selectedObjectId: null,
|
|
18981
|
-
selectObject: (id) => set(
|
|
18982
|
+
selectObject: (id) => set((state2) => ({
|
|
18983
|
+
selectedObjectId: id,
|
|
18984
|
+
constructionGhost: null,
|
|
18985
|
+
selectedConstraintId: null,
|
|
18986
|
+
// Face selection is a sub-selection of an object; drop it when the active
|
|
18987
|
+
// object changes (the click handler re-populates it for the new object).
|
|
18988
|
+
selectedFace: state2.selectedFace && state2.selectedFace.objectId === id ? state2.selectedFace : null,
|
|
18989
|
+
// Edge/vertex sub-selections are likewise scoped to the active object.
|
|
18990
|
+
selectedEdge: state2.selectedEdge && state2.selectedEdge.objectId === id ? state2.selectedEdge : null,
|
|
18991
|
+
selectedVertex: state2.selectedVertex && state2.selectedVertex.objectId === id ? state2.selectedVertex : null
|
|
18992
|
+
})),
|
|
18982
18993
|
constructionGhost: null,
|
|
18983
18994
|
setConstructionGhost: (ghost) => set({ constructionGhost: ghost }),
|
|
18984
18995
|
// ── Construction history replay ──
|
|
@@ -19177,6 +19188,30 @@ const useForgeStore = create((set, get) => ({
|
|
|
19177
19188
|
setHoveredSurfaceIndex: (index) => set((state2) => state2.hoveredSurfaceIndex === index ? state2 : { hoveredSurfaceIndex: index }),
|
|
19178
19189
|
selectedSurfaceIndex: null,
|
|
19179
19190
|
setSelectedSurfaceIndex: (index) => set((state2) => state2.selectedSurfaceIndex === index ? { selectedSurfaceIndex: null } : { selectedSurfaceIndex: index }),
|
|
19191
|
+
selectedFace: null,
|
|
19192
|
+
setSelectedFace: (face) => set((state2) => {
|
|
19193
|
+
const prev = state2.selectedFace;
|
|
19194
|
+
if (face && prev && prev.objectId === face.objectId && prev.carrierName !== null && prev.carrierName === face.carrierName) {
|
|
19195
|
+
return { selectedFace: null };
|
|
19196
|
+
}
|
|
19197
|
+
return { selectedFace: face };
|
|
19198
|
+
}),
|
|
19199
|
+
selectedEdge: null,
|
|
19200
|
+
setSelectedEdge: (edge) => set((state2) => {
|
|
19201
|
+
const prev = state2.selectedEdge;
|
|
19202
|
+
if (edge && prev && prev.objectId === edge.objectId && prev.faceA === edge.faceA && prev.faceB === edge.faceB) {
|
|
19203
|
+
return { selectedEdge: null };
|
|
19204
|
+
}
|
|
19205
|
+
return { selectedEdge: edge };
|
|
19206
|
+
}),
|
|
19207
|
+
selectedVertex: null,
|
|
19208
|
+
setSelectedVertex: (vertex) => set((state2) => {
|
|
19209
|
+
const prev = state2.selectedVertex;
|
|
19210
|
+
if (vertex && prev && prev.objectId === vertex.objectId && prev.point[0] === vertex.point[0] && prev.point[1] === vertex.point[1] && prev.point[2] === vertex.point[2]) {
|
|
19211
|
+
return { selectedVertex: null };
|
|
19212
|
+
}
|
|
19213
|
+
return { selectedVertex: vertex };
|
|
19214
|
+
}),
|
|
19180
19215
|
selectedSketchEntityId: null,
|
|
19181
19216
|
setSelectedSketchEntityId: (id) => set((state2) => state2.selectedSketchEntityId === id ? { selectedSketchEntityId: null } : { selectedSketchEntityId: id }),
|
|
19182
19217
|
hoveredJointName: null,
|
|
@@ -19214,6 +19249,13 @@ const useForgeStore = create((set, get) => ({
|
|
|
19214
19249
|
});
|
|
19215
19250
|
},
|
|
19216
19251
|
clearMeasureSelections: () => set({ measureSelections: [] }),
|
|
19252
|
+
replaceLastMeasureSelection: (entity) => {
|
|
19253
|
+
set((s) => {
|
|
19254
|
+
const sels = s.measureSelections;
|
|
19255
|
+
if (sels.length === 0) return { measureSelections: [entity] };
|
|
19256
|
+
return { measureSelections: [...sels.slice(0, -1), entity] };
|
|
19257
|
+
});
|
|
19258
|
+
},
|
|
19217
19259
|
measurements: [],
|
|
19218
19260
|
addMeasurePoint: (pt2) => {
|
|
19219
19261
|
const measurements = get().measurements;
|
|
@@ -23499,7 +23541,7 @@ function moveOrbitTargetToPoint(camera, controls, target) {
|
|
|
23499
23541
|
}
|
|
23500
23542
|
const MIDDLE_BUTTON = 1;
|
|
23501
23543
|
const DOUBLE_CLICK_MAX_MS = 500;
|
|
23502
|
-
const CLICK_DRAG_TOLERANCE_PX = 5;
|
|
23544
|
+
const CLICK_DRAG_TOLERANCE_PX$1 = 5;
|
|
23503
23545
|
const DOUBLE_CLICK_DISTANCE_TOLERANCE_PX = 8;
|
|
23504
23546
|
function distanceSq(a2, b2) {
|
|
23505
23547
|
return (a2.clientX - b2.clientX) ** 2 + (a2.clientY - b2.clientY) ** 2;
|
|
@@ -23535,7 +23577,7 @@ function OrbitTargetPicker({ active, controlsRef }) {
|
|
|
23535
23577
|
previousClickRef.current = null;
|
|
23536
23578
|
if (!active) return;
|
|
23537
23579
|
const element = gl.domElement;
|
|
23538
|
-
const dragToleranceSq = CLICK_DRAG_TOLERANCE_PX ** 2;
|
|
23580
|
+
const dragToleranceSq = CLICK_DRAG_TOLERANCE_PX$1 ** 2;
|
|
23539
23581
|
const doubleDistanceToleranceSq = DOUBLE_CLICK_DISTANCE_TOLERANCE_PX ** 2;
|
|
23540
23582
|
const onPointerDown = (event) => {
|
|
23541
23583
|
if (event.button !== MIDDLE_BUTTON) return;
|
|
@@ -23700,7 +23742,7 @@ function OrbitTargetPulseLayer() {
|
|
|
23700
23742
|
class ConstructionHistoryWorkerClient {
|
|
23701
23743
|
constructor(workerFactory = () => new Worker(new URL(
|
|
23702
23744
|
/* @vite-ignore */
|
|
23703
|
-
"/assets/constructionHistoryWorker-
|
|
23745
|
+
"/assets/constructionHistoryWorker-uEe_Q7Kg.js",
|
|
23704
23746
|
import.meta.url
|
|
23705
23747
|
), { type: "module" })) {
|
|
23706
23748
|
__publicField(this, "worker", null);
|
|
@@ -26212,7 +26254,7 @@ function generateReportInWorker(options) {
|
|
|
26212
26254
|
return new Promise((resolve2, reject) => {
|
|
26213
26255
|
const worker = new Worker(new URL(
|
|
26214
26256
|
/* @vite-ignore */
|
|
26215
|
-
"/assets/reportWorker-
|
|
26257
|
+
"/assets/reportWorker-DsaICZsn.js",
|
|
26216
26258
|
import.meta.url
|
|
26217
26259
|
), { type: "module" });
|
|
26218
26260
|
const cleanup = () => {
|
|
@@ -29980,6 +30022,185 @@ function LedgerMetric({ label, value }) {
|
|
|
29980
30022
|
}
|
|
29981
30023
|
);
|
|
29982
30024
|
}
|
|
30025
|
+
const QUANT = 1e4;
|
|
30026
|
+
const q = (v) => Math.round(v * QUANT);
|
|
30027
|
+
const vertKey = (pos, i) => `${q(pos.getX(i))},${q(pos.getY(i))},${q(pos.getZ(i))}`;
|
|
30028
|
+
const edgeKey = (a2, b2) => a2 < b2 ? `${a2}|${b2}` : `${b2}|${a2}`;
|
|
30029
|
+
function buildEdgeAdjacency(positions, triCount) {
|
|
30030
|
+
const edgeToTris = /* @__PURE__ */ new Map();
|
|
30031
|
+
for (let t2 = 0; t2 < triCount; t2++) {
|
|
30032
|
+
const base = t2 * 3;
|
|
30033
|
+
const v0 = vertKey(positions, base);
|
|
30034
|
+
const v12 = vertKey(positions, base + 1);
|
|
30035
|
+
const v22 = vertKey(positions, base + 2);
|
|
30036
|
+
for (const ek of [edgeKey(v0, v12), edgeKey(v12, v22), edgeKey(v22, v0)]) {
|
|
30037
|
+
let list = edgeToTris.get(ek);
|
|
30038
|
+
if (!list) {
|
|
30039
|
+
list = [];
|
|
30040
|
+
edgeToTris.set(ek, list);
|
|
30041
|
+
}
|
|
30042
|
+
list.push(t2);
|
|
30043
|
+
}
|
|
30044
|
+
}
|
|
30045
|
+
return edgeToTris;
|
|
30046
|
+
}
|
|
30047
|
+
function floodComponent(positions, edgeToTris, startTriIndex, accept) {
|
|
30048
|
+
const visited = /* @__PURE__ */ new Set();
|
|
30049
|
+
const queue = [startTriIndex];
|
|
30050
|
+
visited.add(startTriIndex);
|
|
30051
|
+
while (queue.length > 0) {
|
|
30052
|
+
const t2 = queue.pop();
|
|
30053
|
+
const base = t2 * 3;
|
|
30054
|
+
const v0 = vertKey(positions, base);
|
|
30055
|
+
const v12 = vertKey(positions, base + 1);
|
|
30056
|
+
const v22 = vertKey(positions, base + 2);
|
|
30057
|
+
for (const ek of [edgeKey(v0, v12), edgeKey(v12, v22), edgeKey(v22, v0)]) {
|
|
30058
|
+
const neighbors = edgeToTris.get(ek);
|
|
30059
|
+
if (!neighbors) continue;
|
|
30060
|
+
for (const n of neighbors) {
|
|
30061
|
+
if (visited.has(n)) continue;
|
|
30062
|
+
if (!accept(n)) continue;
|
|
30063
|
+
visited.add(n);
|
|
30064
|
+
queue.push(n);
|
|
30065
|
+
}
|
|
30066
|
+
}
|
|
30067
|
+
}
|
|
30068
|
+
return Array.from(visited);
|
|
30069
|
+
}
|
|
30070
|
+
function summarizeRegion(positions, normals, indices) {
|
|
30071
|
+
let totalArea = 0;
|
|
30072
|
+
const centroid = new Vector3();
|
|
30073
|
+
const weightedNormal = new Vector3();
|
|
30074
|
+
const tmpA = new Vector3();
|
|
30075
|
+
const tmpB = new Vector3();
|
|
30076
|
+
const tmpC = new Vector3();
|
|
30077
|
+
for (const t2 of indices) {
|
|
30078
|
+
const base = t2 * 3;
|
|
30079
|
+
tmpA.set(positions.getX(base), positions.getY(base), positions.getZ(base));
|
|
30080
|
+
tmpB.set(positions.getX(base + 1), positions.getY(base + 1), positions.getZ(base + 1));
|
|
30081
|
+
tmpC.set(positions.getX(base + 2), positions.getY(base + 2), positions.getZ(base + 2));
|
|
30082
|
+
const ab = tmpB.clone().sub(tmpA);
|
|
30083
|
+
const ac = tmpC.clone().sub(tmpA);
|
|
30084
|
+
const cross = ab.cross(ac);
|
|
30085
|
+
const triArea = cross.length() * 0.5;
|
|
30086
|
+
totalArea += triArea;
|
|
30087
|
+
const triCenter = tmpA.clone().add(tmpB).add(tmpC).multiplyScalar(1 / 3);
|
|
30088
|
+
centroid.add(triCenter.multiplyScalar(triArea));
|
|
30089
|
+
if (cross.lengthSq() > 0) weightedNormal.add(cross.multiplyScalar(0.5));
|
|
30090
|
+
}
|
|
30091
|
+
if (totalArea > 0) centroid.multiplyScalar(1 / totalArea);
|
|
30092
|
+
let normal;
|
|
30093
|
+
if (weightedNormal.lengthSq() > 1e-12) {
|
|
30094
|
+
normal = weightedNormal.normalize();
|
|
30095
|
+
} else if (normals) {
|
|
30096
|
+
const si = indices[0] * 3;
|
|
30097
|
+
normal = new Vector3(normals.getX(si), normals.getY(si), normals.getZ(si)).normalize();
|
|
30098
|
+
} else {
|
|
30099
|
+
normal = new Vector3(0, 0, 1);
|
|
30100
|
+
}
|
|
30101
|
+
return { normal, center: centroid, area: totalArea };
|
|
30102
|
+
}
|
|
30103
|
+
function getFaceRegion(geometry, startTriIndex, options = {}) {
|
|
30104
|
+
const positions = geometry.getAttribute("position");
|
|
30105
|
+
const normals = geometry.getAttribute("normal") ?? null;
|
|
30106
|
+
const triCount = positions.count / 3;
|
|
30107
|
+
const edgeToTris = buildEdgeAdjacency(positions, triCount);
|
|
30108
|
+
const userData = geometry.userData;
|
|
30109
|
+
const faceIds = userData.forgeTriangleFaceIds;
|
|
30110
|
+
const faceIdNames = userData.forgeFaceIdNames;
|
|
30111
|
+
if (faceIds && faceIdNames && startTriIndex < faceIds.length) {
|
|
30112
|
+
const hitFaceId = faceIds[startTriIndex];
|
|
30113
|
+
if (hitFaceId >= 0) {
|
|
30114
|
+
const indices2 = floodComponent(positions, edgeToTris, startTriIndex, (n) => faceIds[n] === hitFaceId);
|
|
30115
|
+
const summary2 = summarizeRegion(positions, normals, indices2);
|
|
30116
|
+
const rawName = faceIdNames[hitFaceId] ?? null;
|
|
30117
|
+
const carrierName = rawName && rawName !== UNIDENTIFIED_FACE_NAME ? rawName : null;
|
|
30118
|
+
return { triangleIndices: indices2, ...summary2, carrierName };
|
|
30119
|
+
}
|
|
30120
|
+
}
|
|
30121
|
+
const normalTolerance = options.normalTolerance ?? 0.9995;
|
|
30122
|
+
const si = startTriIndex * 3;
|
|
30123
|
+
const startNormal = normals ? new Vector3(normals.getX(si), normals.getY(si), normals.getZ(si)) : new Vector3(0, 0, 1);
|
|
30124
|
+
const indices = floodComponent(positions, edgeToTris, startTriIndex, (n) => {
|
|
30125
|
+
if (!normals) return false;
|
|
30126
|
+
const ni = n * 3;
|
|
30127
|
+
const nNormal = new Vector3(normals.getX(ni), normals.getY(ni), normals.getZ(ni));
|
|
30128
|
+
return startNormal.dot(nNormal) >= normalTolerance;
|
|
30129
|
+
});
|
|
30130
|
+
const summary = summarizeRegion(positions, normals, indices);
|
|
30131
|
+
return { triangleIndices: indices, normal: startNormal.clone().normalize(), center: summary.center, area: summary.area, carrierName: null };
|
|
30132
|
+
}
|
|
30133
|
+
function buildFaceHighlightGeometry(sourceGeometry, triangleIndices) {
|
|
30134
|
+
const srcPos = sourceGeometry.getAttribute("position");
|
|
30135
|
+
const count = triangleIndices.length * 9;
|
|
30136
|
+
const positions = new Float32Array(count);
|
|
30137
|
+
for (let i = 0; i < triangleIndices.length; i++) {
|
|
30138
|
+
const base = triangleIndices[i] * 3;
|
|
30139
|
+
const out = i * 9;
|
|
30140
|
+
for (let v = 0; v < 3; v++) {
|
|
30141
|
+
positions[out + v * 3] = srcPos.getX(base + v);
|
|
30142
|
+
positions[out + v * 3 + 1] = srcPos.getY(base + v);
|
|
30143
|
+
positions[out + v * 3 + 2] = srcPos.getZ(base + v);
|
|
30144
|
+
}
|
|
30145
|
+
}
|
|
30146
|
+
const geo = new BufferGeometry();
|
|
30147
|
+
geo.setAttribute("position", new BufferAttribute(positions, 3));
|
|
30148
|
+
return geo;
|
|
30149
|
+
}
|
|
30150
|
+
function closestOnSegment(p2, a2, b2, out) {
|
|
30151
|
+
const abx = b2.x - a2.x;
|
|
30152
|
+
const aby = b2.y - a2.y;
|
|
30153
|
+
const abz = b2.z - a2.z;
|
|
30154
|
+
const abLenSq = abx * abx + aby * aby + abz * abz;
|
|
30155
|
+
let t2 = abLenSq > 0 ? ((p2.x - a2.x) * abx + (p2.y - a2.y) * aby + (p2.z - a2.z) * abz) / abLenSq : 0;
|
|
30156
|
+
if (t2 < 0) t2 = 0;
|
|
30157
|
+
else if (t2 > 1) t2 = 1;
|
|
30158
|
+
out.set(a2.x + abx * t2, a2.y + aby * t2, a2.z + abz * t2);
|
|
30159
|
+
return out.distanceToSquared(p2);
|
|
30160
|
+
}
|
|
30161
|
+
function getNearestEdge(geometry, localPoint, maxDistance) {
|
|
30162
|
+
const edges = getBakedEdges(geometry);
|
|
30163
|
+
if (edges.length === 0) return null;
|
|
30164
|
+
const maxSq = maxDistance * maxDistance;
|
|
30165
|
+
let best = null;
|
|
30166
|
+
let bestSq = maxSq;
|
|
30167
|
+
const a2 = new Vector3();
|
|
30168
|
+
const b2 = new Vector3();
|
|
30169
|
+
const closest = new Vector3();
|
|
30170
|
+
for (const edge of edges) {
|
|
30171
|
+
const pts = edge.points;
|
|
30172
|
+
for (let i = 0; i + 5 < pts.length; i += 3) {
|
|
30173
|
+
a2.set(pts[i], pts[i + 1], pts[i + 2]);
|
|
30174
|
+
b2.set(pts[i + 3], pts[i + 4], pts[i + 5]);
|
|
30175
|
+
const dSq = closestOnSegment(localPoint, a2, b2, closest);
|
|
30176
|
+
if (dSq < bestSq) {
|
|
30177
|
+
bestSq = dSq;
|
|
30178
|
+
best = { edge, point: closest.clone(), distance: Math.sqrt(dSq) };
|
|
30179
|
+
}
|
|
30180
|
+
}
|
|
30181
|
+
}
|
|
30182
|
+
return best;
|
|
30183
|
+
}
|
|
30184
|
+
function getNearestVertex(geometry, localPoint, maxDistance) {
|
|
30185
|
+
const edges = getBakedEdges(geometry);
|
|
30186
|
+
if (edges.length === 0) return null;
|
|
30187
|
+
const maxSq = maxDistance * maxDistance;
|
|
30188
|
+
let best = null;
|
|
30189
|
+
let bestSq = maxSq;
|
|
30190
|
+
const v = new Vector3();
|
|
30191
|
+
for (const edge of edges) {
|
|
30192
|
+
const pts = edge.points;
|
|
30193
|
+
for (let i = 0; i + 2 < pts.length; i += 3) {
|
|
30194
|
+
v.set(pts[i], pts[i + 1], pts[i + 2]);
|
|
30195
|
+
const dSq = v.distanceToSquared(localPoint);
|
|
30196
|
+
if (dSq < bestSq) {
|
|
30197
|
+
bestSq = dSq;
|
|
30198
|
+
best = { point: v.clone(), distance: Math.sqrt(dSq) };
|
|
30199
|
+
}
|
|
30200
|
+
}
|
|
30201
|
+
}
|
|
30202
|
+
return best;
|
|
30203
|
+
}
|
|
29983
30204
|
const PREVIEW_RENDER_ORDER_STEP = 1;
|
|
29984
30205
|
const HATCH_DIRECTION_A = new Vector2(Math.cos(MathUtils.degToRad(35)), Math.sin(MathUtils.degToRad(35)));
|
|
29985
30206
|
const HATCH_DIRECTION_B = new Vector2(Math.cos(MathUtils.degToRad(125)), Math.sin(MathUtils.degToRad(125)));
|
|
@@ -31315,6 +31536,9 @@ function ZebraInspectionMaterial({ clippingPlanes }) {
|
|
|
31315
31536
|
}
|
|
31316
31537
|
const EMPTY_CLIPPING_PLANES$1 = [];
|
|
31317
31538
|
const EMPTY_SECTION_PLANES$1 = [];
|
|
31539
|
+
const SELECTED_FACE_HIGHLIGHT_COLOR = "#ffa040";
|
|
31540
|
+
const SELECTED_EDGE_HIGHLIGHT_COLOR = "#3fd8ff";
|
|
31541
|
+
const SELECTED_VERTEX_HIGHLIGHT_COLOR = "#ffffff";
|
|
31318
31542
|
function scanCellKey(ix, iy, iz) {
|
|
31319
31543
|
return `${ix}:${iy}:${iz}`;
|
|
31320
31544
|
}
|
|
@@ -31505,6 +31729,9 @@ function ForgeObject({
|
|
|
31505
31729
|
sectionPlanes,
|
|
31506
31730
|
sectionPreviewRenderOrderBase,
|
|
31507
31731
|
debugHighlightColor,
|
|
31732
|
+
selectedFaceTriangleIndices,
|
|
31733
|
+
selectedEdgePoints,
|
|
31734
|
+
selectedVertexPoint,
|
|
31508
31735
|
onPointerEnter,
|
|
31509
31736
|
onPointerMove,
|
|
31510
31737
|
onPointerLeave,
|
|
@@ -31546,7 +31773,7 @@ function ForgeObject({
|
|
|
31546
31773
|
};
|
|
31547
31774
|
}
|
|
31548
31775
|
}, [obj.shape, wantsDirectSdf]);
|
|
31549
|
-
const isScalarInspect = inspectChannel === "thickness" || inspectChannel === "roughness";
|
|
31776
|
+
const isScalarInspect = inspectChannel === "thickness" || inspectChannel === "throughThickness" || inspectChannel === "roughness";
|
|
31550
31777
|
const isScalarScan = isScalarInspect && inspectDisplayMode === "scan";
|
|
31551
31778
|
const inspectPointGeo = reactExports.useMemo(() => {
|
|
31552
31779
|
if (!inspectPointCloud) return null;
|
|
@@ -31577,6 +31804,7 @@ function ForgeObject({
|
|
|
31577
31804
|
geometry.setAttribute("position", new BufferAttribute(inspectScalarSurface.positions, 3));
|
|
31578
31805
|
geometry.setAttribute("normal", new BufferAttribute(inspectScalarSurface.normals, 3));
|
|
31579
31806
|
geometry.setAttribute("aValue", new BufferAttribute(inspectScalarSurface.aValue, 1));
|
|
31807
|
+
geometry.setAttribute("uv", new BufferAttribute(inspectScalarSurface.uvs ?? new Float32Array(vertexCount * 2), 2));
|
|
31580
31808
|
geometry.setIndex(new BufferAttribute(inspectScalarSurface.index, 1));
|
|
31581
31809
|
try {
|
|
31582
31810
|
geometry.boundsTree = MeshBVH.deserialize(
|
|
@@ -31597,14 +31825,24 @@ function ForgeObject({
|
|
|
31597
31825
|
if (!inspectScalarSurface || !effectiveColorScale) return null;
|
|
31598
31826
|
return makeColorScaleTexture(colorScaleLUT(effectiveColorScale.colormap));
|
|
31599
31827
|
}, [inspectScalarSurface, effectiveColorScale == null ? void 0 : effectiveColorScale.colormap]);
|
|
31828
|
+
const inspectScalarValueTexture = reactExports.useMemo(() => {
|
|
31829
|
+
if (!(inspectScalarSurface == null ? void 0 : inspectScalarSurface.textureValues) || !inspectScalarSurface.textureWidth || !inspectScalarSurface.textureHeight) return null;
|
|
31830
|
+
return makeScalarValueTexture(
|
|
31831
|
+
inspectScalarSurface.textureValues,
|
|
31832
|
+
inspectScalarSurface.textureWidth,
|
|
31833
|
+
inspectScalarSurface.textureHeight
|
|
31834
|
+
);
|
|
31835
|
+
}, [inspectScalarSurface]);
|
|
31600
31836
|
const inspectScalarMaterialRef = reactExports.useRef(null);
|
|
31601
31837
|
const invalidate2 = useThree((s) => s.invalidate);
|
|
31602
31838
|
const inspectScalarUniforms = reactExports.useMemo(() => {
|
|
31603
31839
|
if (!inspectColormapTexture || !effectiveColorScale) return null;
|
|
31604
31840
|
return makeInspectScalarUniforms({
|
|
31605
31841
|
colorScale: inspectColormapTexture,
|
|
31842
|
+
scalarTexture: inspectScalarValueTexture,
|
|
31606
31843
|
domainMin: effectiveColorScale.domainMin,
|
|
31607
31844
|
domainMax: effectiveColorScale.domainMax,
|
|
31845
|
+
colorScaleReversed: effectiveColorScale.reversed === true,
|
|
31608
31846
|
quantizeBands: (inspectScalarParams == null ? void 0 : inspectScalarParams.quantizeBands) ?? 0,
|
|
31609
31847
|
isoEnabled: (inspectScalarParams == null ? void 0 : inspectScalarParams.isolinesEnabled) ?? false,
|
|
31610
31848
|
isoSpacing: (inspectScalarParams == null ? void 0 : inspectScalarParams.isolineSpacing) ?? 0,
|
|
@@ -31612,7 +31850,7 @@ function ForgeObject({
|
|
|
31612
31850
|
criticalThreshold: (inspectScalarParams == null ? void 0 : inspectScalarParams.criticalThreshold) ?? 0,
|
|
31613
31851
|
shadingEnabled: (inspectScalarParams == null ? void 0 : inspectScalarParams.shadingEnabled) ?? true
|
|
31614
31852
|
});
|
|
31615
|
-
}, [inspectColormapTexture]);
|
|
31853
|
+
}, [inspectColormapTexture, inspectScalarValueTexture]);
|
|
31616
31854
|
const wantsScanProxy = Boolean(
|
|
31617
31855
|
settings.visible && (inspectChannel === "none" && (renderStyle === "scan" || renderStyle === "matrix") || isScalarScan)
|
|
31618
31856
|
);
|
|
@@ -31623,6 +31861,40 @@ function ForgeObject({
|
|
|
31623
31861
|
const shell = createScanAnalysisColorGeometry(scanProxy.geometries.shell, inspectPointCloud, scanProxy.grid, matrix);
|
|
31624
31862
|
return shell ? { shell } : null;
|
|
31625
31863
|
}, [inspectPointCloud, isScalarScan, matrix, scanProxy]);
|
|
31864
|
+
const selectedFaceHighlightGeo = reactExports.useMemo(() => {
|
|
31865
|
+
if (!solidGeo || !selectedFaceTriangleIndices || selectedFaceTriangleIndices.length === 0) return null;
|
|
31866
|
+
return buildFaceHighlightGeometry(solidGeo, selectedFaceTriangleIndices);
|
|
31867
|
+
}, [solidGeo, selectedFaceTriangleIndices]);
|
|
31868
|
+
reactExports.useEffect(() => {
|
|
31869
|
+
return () => {
|
|
31870
|
+
selectedFaceHighlightGeo == null ? void 0 : selectedFaceHighlightGeo.dispose();
|
|
31871
|
+
};
|
|
31872
|
+
}, [selectedFaceHighlightGeo]);
|
|
31873
|
+
const selectedEdgeGeo = reactExports.useMemo(() => {
|
|
31874
|
+
if (!selectedEdgePoints || selectedEdgePoints.length < 6) return null;
|
|
31875
|
+
const segCount = selectedEdgePoints.length / 3 - 1;
|
|
31876
|
+
const positions = new Float32Array(segCount * 6);
|
|
31877
|
+
for (let i = 0; i < segCount; i++) {
|
|
31878
|
+
const a2 = i * 3;
|
|
31879
|
+
positions.set(selectedEdgePoints.slice(a2, a2 + 3), i * 6);
|
|
31880
|
+
positions.set(selectedEdgePoints.slice(a2 + 3, a2 + 6), i * 6 + 3);
|
|
31881
|
+
}
|
|
31882
|
+
const geo = new BufferGeometry();
|
|
31883
|
+
geo.setAttribute("position", new BufferAttribute(positions, 3));
|
|
31884
|
+
return geo;
|
|
31885
|
+
}, [selectedEdgePoints]);
|
|
31886
|
+
reactExports.useEffect(() => {
|
|
31887
|
+
return () => {
|
|
31888
|
+
selectedEdgeGeo == null ? void 0 : selectedEdgeGeo.dispose();
|
|
31889
|
+
};
|
|
31890
|
+
}, [selectedEdgeGeo]);
|
|
31891
|
+
const selectedVertexMarkerRadius = reactExports.useMemo(() => {
|
|
31892
|
+
var _a4;
|
|
31893
|
+
if (!selectedVertexPoint || !solidGeo) return 0;
|
|
31894
|
+
if (!solidGeo.boundingSphere) solidGeo.computeBoundingSphere();
|
|
31895
|
+
const r2 = ((_a4 = solidGeo.boundingSphere) == null ? void 0 : _a4.radius) ?? 1;
|
|
31896
|
+
return r2 * 0.02;
|
|
31897
|
+
}, [selectedVertexPoint, solidGeo]);
|
|
31626
31898
|
reactExports.useEffect(() => {
|
|
31627
31899
|
return () => {
|
|
31628
31900
|
solidGeo == null ? void 0 : solidGeo.dispose();
|
|
@@ -31649,11 +31921,17 @@ function ForgeObject({
|
|
|
31649
31921
|
inspectColormapTexture == null ? void 0 : inspectColormapTexture.dispose();
|
|
31650
31922
|
};
|
|
31651
31923
|
}, [inspectColormapTexture]);
|
|
31924
|
+
reactExports.useEffect(() => {
|
|
31925
|
+
return () => {
|
|
31926
|
+
inspectScalarValueTexture == null ? void 0 : inspectScalarValueTexture.dispose();
|
|
31927
|
+
};
|
|
31928
|
+
}, [inspectScalarValueTexture]);
|
|
31652
31929
|
reactExports.useEffect(() => {
|
|
31653
31930
|
if (!inspectScalarUniforms || !effectiveColorScale || !inspectScalarParams) return;
|
|
31654
31931
|
updateInspectScalarUniforms(inspectScalarUniforms, {
|
|
31655
31932
|
domainMin: effectiveColorScale.domainMin,
|
|
31656
31933
|
domainMax: effectiveColorScale.domainMax,
|
|
31934
|
+
colorScaleReversed: effectiveColorScale.reversed === true,
|
|
31657
31935
|
quantizeBands: inspectScalarParams.quantizeBands,
|
|
31658
31936
|
isoEnabled: inspectScalarParams.isolinesEnabled,
|
|
31659
31937
|
isoSpacing: inspectScalarParams.isolineSpacing,
|
|
@@ -32057,7 +32335,25 @@ function ForgeObject({
|
|
|
32057
32335
|
polygonOffsetUnits: -1
|
|
32058
32336
|
}
|
|
32059
32337
|
) }),
|
|
32060
|
-
debugHighlightColor && edgesGeo && /* @__PURE__ */ jsxRuntimeExports.jsx("lineSegments", { geometry: edgesGeo, raycast: () => null, children: /* @__PURE__ */ jsxRuntimeExports.jsx("lineBasicMaterial", { color: debugHighlightColor, linewidth: 2, depthTest: false }) })
|
|
32338
|
+
debugHighlightColor && edgesGeo && /* @__PURE__ */ jsxRuntimeExports.jsx("lineSegments", { geometry: edgesGeo, raycast: () => null, children: /* @__PURE__ */ jsxRuntimeExports.jsx("lineBasicMaterial", { color: debugHighlightColor, linewidth: 2, depthTest: false }) }),
|
|
32339
|
+
selectedFaceHighlightGeo && /* @__PURE__ */ jsxRuntimeExports.jsx("mesh", { geometry: selectedFaceHighlightGeo, raycast: () => null, renderOrder: 11, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
32340
|
+
"meshBasicMaterial",
|
|
32341
|
+
{
|
|
32342
|
+
color: SELECTED_FACE_HIGHLIGHT_COLOR,
|
|
32343
|
+
transparent: true,
|
|
32344
|
+
opacity: 0.45,
|
|
32345
|
+
side: DoubleSide,
|
|
32346
|
+
depthTest: false,
|
|
32347
|
+
polygonOffset: true,
|
|
32348
|
+
polygonOffsetFactor: -2,
|
|
32349
|
+
polygonOffsetUnits: -2
|
|
32350
|
+
}
|
|
32351
|
+
) }),
|
|
32352
|
+
selectedEdgeGeo && /* @__PURE__ */ jsxRuntimeExports.jsx("lineSegments", { geometry: selectedEdgeGeo, raycast: () => null, renderOrder: 12, children: /* @__PURE__ */ jsxRuntimeExports.jsx("lineBasicMaterial", { color: SELECTED_EDGE_HIGHLIGHT_COLOR, linewidth: 2, depthTest: false, toneMapped: false }) }),
|
|
32353
|
+
selectedVertexPoint && selectedVertexMarkerRadius > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("mesh", { position: selectedVertexPoint, raycast: () => null, renderOrder: 13, children: [
|
|
32354
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("sphereGeometry", { args: [selectedVertexMarkerRadius, 12, 12] }),
|
|
32355
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("meshBasicMaterial", { color: SELECTED_VERTEX_HIGHLIGHT_COLOR, depthTest: false, toneMapped: false })
|
|
32356
|
+
] })
|
|
32061
32357
|
]
|
|
32062
32358
|
}
|
|
32063
32359
|
);
|
|
@@ -32344,7 +32640,7 @@ function HoveredJointOverlay({ state: state2, config }) {
|
|
|
32344
32640
|
] });
|
|
32345
32641
|
}
|
|
32346
32642
|
function scalarRamp(options, domainMin, domainMax, unit) {
|
|
32347
|
-
var _a3;
|
|
32643
|
+
var _a3, _b2;
|
|
32348
32644
|
const colormap = ((_a3 = options.colorScale) == null ? void 0 : _a3.colormap) ?? DEFAULT_COLORMAP;
|
|
32349
32645
|
const midpoint = domainMin + (domainMax - domainMin) / 2;
|
|
32350
32646
|
const unitSuffix = unit ? ` ${unit}` : "";
|
|
@@ -32352,7 +32648,7 @@ function scalarRamp(options, domainMin, domainMax, unit) {
|
|
|
32352
32648
|
const critical = options.criticalValue;
|
|
32353
32649
|
const criticalTick = critical != null && Number.isFinite(critical) && span > 0 ? { position: Math.max(0, Math.min(1, (critical - domainMin) / span)), label: `${fmt(critical)}${unitSuffix}` } : void 0;
|
|
32354
32650
|
return {
|
|
32355
|
-
colors: colorScaleHexStops(colormap),
|
|
32651
|
+
colors: colorScaleHexStops(colormap, 8, ((_b2 = options.colorScale) == null ? void 0 : _b2.reversed) === true),
|
|
32356
32652
|
leftLabel: `${fmt(domainMin)}${unitSuffix}`,
|
|
32357
32653
|
centerLabel: `${fmt(midpoint)}${unitSuffix}`,
|
|
32358
32654
|
rightLabel: `${fmt(domainMax)}${unitSuffix}`,
|
|
@@ -32366,7 +32662,7 @@ function fmt(value) {
|
|
|
32366
32662
|
return fixed.replace(/\.?0+$/, "");
|
|
32367
32663
|
}
|
|
32368
32664
|
function inspectionLegendDefinitionFor(channel, displayMode, legendOptions = {}) {
|
|
32369
|
-
var _a3, _b2, _c, _d;
|
|
32665
|
+
var _a3, _b2, _c, _d, _e, _f;
|
|
32370
32666
|
switch (channel) {
|
|
32371
32667
|
case "mask":
|
|
32372
32668
|
return {
|
|
@@ -32468,13 +32764,32 @@ function inspectionLegendDefinitionFor(channel, displayMode, legendOptions = {})
|
|
|
32468
32764
|
}
|
|
32469
32765
|
return {
|
|
32470
32766
|
title: "Wall Thickness",
|
|
32471
|
-
summary: "
|
|
32767
|
+
summary: "Warm colors mark thinner material; cool colors mark thicker material.",
|
|
32768
|
+
ramp
|
|
32769
|
+
};
|
|
32770
|
+
}
|
|
32771
|
+
case "throughThickness": {
|
|
32772
|
+
const colorRange = legendOptions.thicknessColorRange ?? DEFAULT_THICKNESS_COLOR_RANGE;
|
|
32773
|
+
const domainMin = ((_c = legendOptions.colorScale) == null ? void 0 : _c.domainMin) ?? colorRange.min;
|
|
32774
|
+
const domainMax = ((_d = legendOptions.colorScale) == null ? void 0 : _d.domainMax) ?? colorRange.max;
|
|
32775
|
+
const unit = legendOptions.unitLabel ?? "mm";
|
|
32776
|
+
const ramp = scalarRamp(legendOptions, domainMin, domainMax, unit);
|
|
32777
|
+
if (displayMode === "scan") {
|
|
32778
|
+
return {
|
|
32779
|
+
title: "Minimum Solid Span Scan",
|
|
32780
|
+
summary: "Each scan box uses the same minimum solid span ramp as the heatmap.",
|
|
32781
|
+
ramp
|
|
32782
|
+
};
|
|
32783
|
+
}
|
|
32784
|
+
return {
|
|
32785
|
+
title: "Minimum Solid Span",
|
|
32786
|
+
summary: "Warm colors mark short through-material spans; cool colors mark more surrounding material.",
|
|
32472
32787
|
ramp
|
|
32473
32788
|
};
|
|
32474
32789
|
}
|
|
32475
32790
|
case "roughness": {
|
|
32476
|
-
const domainMin = ((
|
|
32477
|
-
const domainMax = ((
|
|
32791
|
+
const domainMin = ((_e = legendOptions.colorScale) == null ? void 0 : _e.domainMin) ?? 0;
|
|
32792
|
+
const domainMax = ((_f = legendOptions.colorScale) == null ? void 0 : _f.domainMax) ?? 1;
|
|
32478
32793
|
const unit = legendOptions.unitLabel ?? "deg";
|
|
32479
32794
|
const ramp = scalarRamp(legendOptions, domainMin, domainMax, unit);
|
|
32480
32795
|
if (displayMode === "scan") {
|
|
@@ -32960,7 +33275,7 @@ function InspectionLegend({
|
|
|
32960
33275
|
criticalValue
|
|
32961
33276
|
});
|
|
32962
33277
|
const swatches = liveSwatches && liveSwatches.length > 0 ? liveSwatches : definition == null ? void 0 : definition.swatches;
|
|
32963
|
-
const sliderGradient = colorScaleHexStops((colorScale == null ? void 0 : colorScale.colormap) ?? "viridis");
|
|
33278
|
+
const sliderGradient = colorScaleHexStops((colorScale == null ? void 0 : colorScale.colormap) ?? "viridis", 8, (colorScale == null ? void 0 : colorScale.reversed) === true);
|
|
32964
33279
|
reactExports.useEffect(() => {
|
|
32965
33280
|
var _a3;
|
|
32966
33281
|
const parent = (_a3 = panelRef.current) == null ? void 0 : _a3.parentElement;
|
|
@@ -32973,7 +33288,7 @@ function InspectionLegend({
|
|
|
32973
33288
|
}, [channel]);
|
|
32974
33289
|
if (!definition) return null;
|
|
32975
33290
|
const warning = warnings[0];
|
|
32976
|
-
const showThicknessControls = channel === "thickness" && thicknessColorRange !== void 0 && onThicknessColorRangeChange !== void 0;
|
|
33291
|
+
const showThicknessControls = (channel === "thickness" || channel === "throughThickness") && thicknessColorRange !== void 0 && onThicknessColorRangeChange !== void 0;
|
|
32977
33292
|
const swatchCount = (swatches == null ? void 0 : swatches.length) ?? 0;
|
|
32978
33293
|
const hasScrollableSwatches = swatchCount > 10;
|
|
32979
33294
|
const effectivePanelStyle = {
|
|
@@ -33066,212 +33381,263 @@ function LabeledAxes({ size = 50 }) {
|
|
|
33066
33381
|
/* @__PURE__ */ jsxRuntimeExports.jsx(Html, { position: [0, 0, size + 3], center: true, style: labelStyle("#4488ff"), children: "Z" })
|
|
33067
33382
|
] });
|
|
33068
33383
|
}
|
|
33069
|
-
const
|
|
33070
|
-
|
|
33071
|
-
|
|
33072
|
-
|
|
33073
|
-
|
|
33074
|
-
|
|
33075
|
-
|
|
33076
|
-
selection: "#ffa040",
|
|
33077
|
-
// both selections — warm amber
|
|
33078
|
-
line: "#ffa040",
|
|
33079
|
-
panelLabel: "#888",
|
|
33080
|
-
panelValue: "#ffd060"
|
|
33081
|
-
};
|
|
33082
|
-
const QUANT = 1e4;
|
|
33083
|
-
const q = (v) => Math.round(v * QUANT);
|
|
33084
|
-
const vertKey = (pos, i) => `${q(pos.getX(i))},${q(pos.getY(i))},${q(pos.getZ(i))}`;
|
|
33085
|
-
const edgeKey = (a2, b2) => a2 < b2 ? `${a2}|${b2}` : `${b2}|${a2}`;
|
|
33086
|
-
function floodFillFace(geometry, startTriIndex, normalTolerance = 0.9995) {
|
|
33384
|
+
const SHARP_DOT = 0.9995;
|
|
33385
|
+
const CORNER_TURN_DEG = 35;
|
|
33386
|
+
const LEN_RATIO_SPLIT = 4;
|
|
33387
|
+
const CONTINUITY_LIMIT_DEG = 60;
|
|
33388
|
+
const CORNER_TURN_COS = Math.cos(CORNER_TURN_DEG * Math.PI / 180);
|
|
33389
|
+
const CONTINUITY_LIMIT_COS = Math.cos(CONTINUITY_LIMIT_DEG * Math.PI / 180);
|
|
33390
|
+
function extractFeatureEdges(geometry) {
|
|
33087
33391
|
const positions = geometry.getAttribute("position");
|
|
33088
33392
|
const normals = geometry.getAttribute("normal");
|
|
33393
|
+
if (!positions) return [];
|
|
33089
33394
|
const triCount = positions.count / 3;
|
|
33090
|
-
const
|
|
33091
|
-
const startNormal = new Vector3(normals.getX(si), normals.getY(si), normals.getZ(si));
|
|
33092
|
-
const edgeToTris = /* @__PURE__ */ new Map();
|
|
33395
|
+
const data = /* @__PURE__ */ new Map();
|
|
33093
33396
|
for (let t2 = 0; t2 < triCount; t2++) {
|
|
33094
33397
|
const base = t2 * 3;
|
|
33095
|
-
const
|
|
33096
|
-
|
|
33097
|
-
|
|
33098
|
-
|
|
33099
|
-
|
|
33100
|
-
|
|
33101
|
-
|
|
33102
|
-
|
|
33103
|
-
|
|
33104
|
-
|
|
33105
|
-
|
|
33106
|
-
|
|
33107
|
-
|
|
33108
|
-
const queue = [startTriIndex];
|
|
33109
|
-
visited.add(startTriIndex);
|
|
33110
|
-
while (queue.length > 0) {
|
|
33111
|
-
const t2 = queue.pop();
|
|
33112
|
-
const base = t2 * 3;
|
|
33113
|
-
const v0 = vertKey(positions, base);
|
|
33114
|
-
const v12 = vertKey(positions, base + 1);
|
|
33115
|
-
const v22 = vertKey(positions, base + 2);
|
|
33116
|
-
for (const ek of [edgeKey(v0, v12), edgeKey(v12, v22), edgeKey(v22, v0)]) {
|
|
33117
|
-
const neighbors = edgeToTris.get(ek);
|
|
33118
|
-
if (!neighbors) continue;
|
|
33119
|
-
for (const n of neighbors) {
|
|
33120
|
-
if (visited.has(n)) continue;
|
|
33121
|
-
const ni = n * 3;
|
|
33122
|
-
const nNormal = new Vector3(normals.getX(ni), normals.getY(ni), normals.getZ(ni));
|
|
33123
|
-
if (startNormal.dot(nNormal) >= normalTolerance) {
|
|
33124
|
-
visited.add(n);
|
|
33125
|
-
queue.push(n);
|
|
33126
|
-
}
|
|
33398
|
+
const tn = normals ? new Vector3(normals.getX(base), normals.getY(base), normals.getZ(base)) : new Vector3(0, 0, 1);
|
|
33399
|
+
for (let e2 = 0; e2 < 3; e2++) {
|
|
33400
|
+
const i0 = base + e2;
|
|
33401
|
+
const i1 = base + (e2 + 1) % 3;
|
|
33402
|
+
const ek = edgeKey(vertKey(positions, i0), vertKey(positions, i1));
|
|
33403
|
+
let d = data.get(ek);
|
|
33404
|
+
if (!d) {
|
|
33405
|
+
d = {
|
|
33406
|
+
a: new Vector3().fromBufferAttribute(positions, i0),
|
|
33407
|
+
b: new Vector3().fromBufferAttribute(positions, i1),
|
|
33408
|
+
normals: []
|
|
33409
|
+
};
|
|
33410
|
+
data.set(ek, d);
|
|
33127
33411
|
}
|
|
33412
|
+
d.normals.push(tn);
|
|
33128
33413
|
}
|
|
33129
33414
|
}
|
|
33130
|
-
const
|
|
33131
|
-
|
|
33132
|
-
|
|
33133
|
-
|
|
33134
|
-
|
|
33135
|
-
const tmpC = new Vector3();
|
|
33136
|
-
for (const t2 of indices) {
|
|
33137
|
-
const base = t2 * 3;
|
|
33138
|
-
tmpA.set(positions.getX(base), positions.getY(base), positions.getZ(base));
|
|
33139
|
-
tmpB.set(positions.getX(base + 1), positions.getY(base + 1), positions.getZ(base + 1));
|
|
33140
|
-
tmpC.set(positions.getX(base + 2), positions.getY(base + 2), positions.getZ(base + 2));
|
|
33141
|
-
const ab = tmpB.clone().sub(tmpA);
|
|
33142
|
-
const ac = tmpC.clone().sub(tmpA);
|
|
33143
|
-
const triArea = ab.cross(ac).length() * 0.5;
|
|
33144
|
-
totalArea += triArea;
|
|
33145
|
-
const triCenter = tmpA.clone().add(tmpB).add(tmpC).multiplyScalar(1 / 3);
|
|
33146
|
-
centroid.add(triCenter.multiplyScalar(triArea));
|
|
33415
|
+
const out = [];
|
|
33416
|
+
for (const d of data.values()) {
|
|
33417
|
+
const sharp = d.normals.length === 2 && d.normals[0].dot(d.normals[1]) < SHARP_DOT;
|
|
33418
|
+
const boundary = d.normals.length === 1;
|
|
33419
|
+
if (sharp || boundary) out.push({ a: d.a, b: d.b });
|
|
33147
33420
|
}
|
|
33148
|
-
|
|
33149
|
-
return { triangleIndices: indices, normal: startNormal.clone(), center: centroid, area: totalArea };
|
|
33421
|
+
return out;
|
|
33150
33422
|
}
|
|
33151
|
-
function
|
|
33152
|
-
const
|
|
33153
|
-
const
|
|
33154
|
-
const
|
|
33155
|
-
for (
|
|
33156
|
-
const
|
|
33157
|
-
const
|
|
33158
|
-
|
|
33159
|
-
|
|
33160
|
-
|
|
33161
|
-
|
|
33423
|
+
function buildGraph(edges) {
|
|
33424
|
+
const point = /* @__PURE__ */ new Map();
|
|
33425
|
+
const adj = /* @__PURE__ */ new Map();
|
|
33426
|
+
const key = (p2) => `${q(p2.x)},${q(p2.y)},${q(p2.z)}`;
|
|
33427
|
+
for (const { a: a2, b: b2 } of edges) {
|
|
33428
|
+
const ka = key(a2);
|
|
33429
|
+
const kb = key(b2);
|
|
33430
|
+
if (ka === kb) continue;
|
|
33431
|
+
point.set(ka, a2);
|
|
33432
|
+
point.set(kb, b2);
|
|
33433
|
+
(adj.get(ka) ?? adj.set(ka, /* @__PURE__ */ new Set()).get(ka)).add(kb);
|
|
33434
|
+
(adj.get(kb) ?? adj.set(kb, /* @__PURE__ */ new Set()).get(kb)).add(ka);
|
|
33435
|
+
}
|
|
33436
|
+
return { point, adj: new Map(Array.from(adj, ([k2, v]) => [k2, Array.from(v)])) };
|
|
33437
|
+
}
|
|
33438
|
+
function nearestSegment(graph, localPoint) {
|
|
33439
|
+
let best = null;
|
|
33440
|
+
let bestSq = Infinity;
|
|
33441
|
+
const closest = new Vector3();
|
|
33442
|
+
const seen = /* @__PURE__ */ new Set();
|
|
33443
|
+
for (const [u, neighbors] of graph.adj) {
|
|
33444
|
+
const a2 = graph.point.get(u);
|
|
33445
|
+
for (const v of neighbors) {
|
|
33446
|
+
const ek = edgeKey(u, v);
|
|
33447
|
+
if (seen.has(ek)) continue;
|
|
33448
|
+
seen.add(ek);
|
|
33449
|
+
const b2 = graph.point.get(v);
|
|
33450
|
+
const dSq = closestOnSegment(localPoint, a2, b2, closest);
|
|
33451
|
+
if (dSq < bestSq) {
|
|
33452
|
+
bestSq = dSq;
|
|
33453
|
+
best = { u, v };
|
|
33454
|
+
}
|
|
33162
33455
|
}
|
|
33163
33456
|
}
|
|
33164
|
-
|
|
33165
|
-
geo.setAttribute("position", new BufferAttribute(positions, 3));
|
|
33166
|
-
return geo;
|
|
33457
|
+
return best;
|
|
33167
33458
|
}
|
|
33168
|
-
function
|
|
33169
|
-
const
|
|
33170
|
-
const
|
|
33171
|
-
|
|
33172
|
-
|
|
33173
|
-
for (let
|
|
33174
|
-
const
|
|
33175
|
-
const
|
|
33176
|
-
|
|
33177
|
-
|
|
33178
|
-
|
|
33179
|
-
|
|
33180
|
-
|
|
33181
|
-
|
|
33182
|
-
|
|
33183
|
-
|
|
33184
|
-
|
|
33185
|
-
|
|
33186
|
-
|
|
33187
|
-
|
|
33188
|
-
|
|
33189
|
-
|
|
33190
|
-
|
|
33191
|
-
|
|
33192
|
-
|
|
33193
|
-
|
|
33194
|
-
|
|
33195
|
-
|
|
33196
|
-
|
|
33197
|
-
|
|
33198
|
-
|
|
33199
|
-
|
|
33200
|
-
|
|
33201
|
-
|
|
33202
|
-
|
|
33203
|
-
|
|
33204
|
-
|
|
33205
|
-
|
|
33206
|
-
const denom = ab.lengthSq();
|
|
33207
|
-
if (denom === 0) continue;
|
|
33208
|
-
const t2 = MathUtils.clamp(localHit.clone().sub(edge.a).dot(ab) / denom, 0, 1);
|
|
33209
|
-
const closest = edge.a.clone().add(ab.multiplyScalar(t2));
|
|
33210
|
-
const dist = closest.distanceTo(localHit);
|
|
33211
|
-
if (dist < closestDist) {
|
|
33212
|
-
closestDist = dist;
|
|
33213
|
-
closestEdge = edge;
|
|
33214
|
-
}
|
|
33215
|
-
}
|
|
33216
|
-
if (!closestEdge) return null;
|
|
33217
|
-
const dir = closestEdge.b.clone().sub(closestEdge.a).normalize();
|
|
33218
|
-
const vertToEdges = /* @__PURE__ */ new Map();
|
|
33219
|
-
for (const edge of sharpEdges) {
|
|
33220
|
-
const vk0 = `${q(edge.a.x)},${q(edge.a.y)},${q(edge.a.z)}`;
|
|
33221
|
-
const vk1 = `${q(edge.b.x)},${q(edge.b.y)},${q(edge.b.z)}`;
|
|
33222
|
-
for (const vk of [vk0, vk1]) {
|
|
33223
|
-
let list = vertToEdges.get(vk);
|
|
33224
|
-
if (!list) {
|
|
33225
|
-
list = [];
|
|
33226
|
-
vertToEdges.set(vk, list);
|
|
33227
|
-
}
|
|
33228
|
-
list.push(edge);
|
|
33459
|
+
function walk(graph, fromKey, curKey, mode, stopAtKey) {
|
|
33460
|
+
const out = [];
|
|
33461
|
+
const visited = /* @__PURE__ */ new Set([fromKey, curKey]);
|
|
33462
|
+
let prev = fromKey;
|
|
33463
|
+
let cur = curKey;
|
|
33464
|
+
for (let guard = 0; guard < 1e5; guard++) {
|
|
33465
|
+
const prevP = graph.point.get(prev);
|
|
33466
|
+
const curP = graph.point.get(cur);
|
|
33467
|
+
const dIn = curP.clone().sub(prevP);
|
|
33468
|
+
const lenIn = dIn.length();
|
|
33469
|
+
if (lenIn === 0) break;
|
|
33470
|
+
dIn.multiplyScalar(1 / lenIn);
|
|
33471
|
+
let bestKey = null;
|
|
33472
|
+
let bestDot = -Infinity;
|
|
33473
|
+
let bestLen = 0;
|
|
33474
|
+
for (const w of graph.adj.get(cur) ?? []) {
|
|
33475
|
+
if (w === prev) continue;
|
|
33476
|
+
const wp = graph.point.get(w);
|
|
33477
|
+
const dOut = wp.clone().sub(curP);
|
|
33478
|
+
const lenOut = dOut.length();
|
|
33479
|
+
if (lenOut === 0) continue;
|
|
33480
|
+
const dot = dIn.dot(dOut) / lenOut;
|
|
33481
|
+
if (dot > bestDot) {
|
|
33482
|
+
bestDot = dot;
|
|
33483
|
+
bestKey = w;
|
|
33484
|
+
bestLen = lenOut;
|
|
33485
|
+
}
|
|
33486
|
+
}
|
|
33487
|
+
if (!bestKey) break;
|
|
33488
|
+
if (bestDot < CONTINUITY_LIMIT_COS) break;
|
|
33489
|
+
if (mode === "single") {
|
|
33490
|
+
if (bestDot < CORNER_TURN_COS) break;
|
|
33491
|
+
const ratio = bestLen >= lenIn ? bestLen / lenIn : lenIn / bestLen;
|
|
33492
|
+
if (ratio > LEN_RATIO_SPLIT) break;
|
|
33493
|
+
}
|
|
33494
|
+
if (bestKey === stopAtKey) {
|
|
33495
|
+
out.push(bestKey);
|
|
33496
|
+
break;
|
|
33229
33497
|
}
|
|
33498
|
+
if (visited.has(bestKey)) break;
|
|
33499
|
+
visited.add(bestKey);
|
|
33500
|
+
out.push(bestKey);
|
|
33501
|
+
prev = cur;
|
|
33502
|
+
cur = bestKey;
|
|
33230
33503
|
}
|
|
33231
|
-
|
|
33232
|
-
|
|
33233
|
-
|
|
33234
|
-
const
|
|
33235
|
-
|
|
33236
|
-
|
|
33237
|
-
|
|
33238
|
-
|
|
33239
|
-
|
|
33240
|
-
const
|
|
33241
|
-
|
|
33242
|
-
|
|
33243
|
-
|
|
33244
|
-
|
|
33245
|
-
|
|
33246
|
-
|
|
33247
|
-
|
|
33248
|
-
|
|
33249
|
-
|
|
33250
|
-
|
|
33251
|
-
|
|
33252
|
-
|
|
33504
|
+
return out;
|
|
33505
|
+
}
|
|
33506
|
+
function chainFromSeed(graph, seed, mode) {
|
|
33507
|
+
const forward = walk(graph, seed.u, seed.v, mode, seed.u);
|
|
33508
|
+
const closed = forward.length > 0 && forward[forward.length - 1] === seed.u;
|
|
33509
|
+
let keys;
|
|
33510
|
+
if (closed) {
|
|
33511
|
+
keys = [seed.u, seed.v, ...forward];
|
|
33512
|
+
} else {
|
|
33513
|
+
const backward = walk(graph, seed.v, seed.u, mode, seed.v);
|
|
33514
|
+
keys = [...backward.slice().reverse(), seed.u, seed.v, ...forward];
|
|
33515
|
+
}
|
|
33516
|
+
return keys.map((k2) => graph.point.get(k2).clone());
|
|
33517
|
+
}
|
|
33518
|
+
function getNearestEdgeChain(geometry, localPoint) {
|
|
33519
|
+
const graph = buildGraph(extractFeatureEdges(geometry));
|
|
33520
|
+
const seed = nearestSegment(graph, localPoint);
|
|
33521
|
+
if (!seed) return null;
|
|
33522
|
+
return chainFromSeed(graph, seed, "single");
|
|
33523
|
+
}
|
|
33524
|
+
function getWholeEdgePath(geometry, localPoint) {
|
|
33525
|
+
const graph = buildGraph(extractFeatureEdges(geometry));
|
|
33526
|
+
const seed = nearestSegment(graph, localPoint);
|
|
33527
|
+
if (!seed) return null;
|
|
33528
|
+
return chainFromSeed(graph, seed, "whole");
|
|
33529
|
+
}
|
|
33530
|
+
function circleMeasurement(curve) {
|
|
33531
|
+
if (!curve || curve.kind !== "circle") return null;
|
|
33532
|
+
const radius = curve.radius;
|
|
33533
|
+
return {
|
|
33534
|
+
radius,
|
|
33535
|
+
diameter: radius * 2,
|
|
33536
|
+
circumference: 2 * Math.PI * radius,
|
|
33537
|
+
center: [curve.center[0], curve.center[1], curve.center[2]],
|
|
33538
|
+
axis: [curve.axis[0], curve.axis[1], curve.axis[2]]
|
|
33539
|
+
};
|
|
33540
|
+
}
|
|
33541
|
+
function worldScale(m2) {
|
|
33542
|
+
const s = new Vector3();
|
|
33543
|
+
m2.decompose(new Vector3(), new Quaternion(), s);
|
|
33544
|
+
return (Math.abs(s.x) + Math.abs(s.y) + Math.abs(s.z)) / 3;
|
|
33545
|
+
}
|
|
33546
|
+
function applyPoint(p2, m2) {
|
|
33547
|
+
const v = new Vector3(p2[0], p2[1], p2[2]).applyMatrix4(m2);
|
|
33548
|
+
return [v.x, v.y, v.z];
|
|
33549
|
+
}
|
|
33550
|
+
function edgeEntityFromBakedEdge(edge, meshMatrixWorld, meshUuid) {
|
|
33551
|
+
const scale = worldScale(meshMatrixWorld);
|
|
33552
|
+
const pts = edge.points;
|
|
33553
|
+
const n = pts.length / 3;
|
|
33554
|
+
const firstLocal = [pts[0], pts[1], pts[2]];
|
|
33555
|
+
const lastLocal = n > 0 ? [pts[(n - 1) * 3], pts[(n - 1) * 3 + 1], pts[(n - 1) * 3 + 2]] : firstLocal;
|
|
33556
|
+
const start = applyPoint(firstLocal, meshMatrixWorld);
|
|
33557
|
+
const end = applyPoint(lastLocal, meshMatrixWorld);
|
|
33558
|
+
const polyline = edge.curve.kind === "line" ? void 0 : Array.from({ length: n }, (_, i) => applyPoint([pts[i * 3], pts[i * 3 + 1], pts[i * 3 + 2]], meshMatrixWorld));
|
|
33559
|
+
if (edge.curve.kind === "line") {
|
|
33560
|
+
const s = new Vector3(...edge.curve.start).applyMatrix4(meshMatrixWorld);
|
|
33561
|
+
const e2 = new Vector3(...edge.curve.end).applyMatrix4(meshMatrixWorld);
|
|
33562
|
+
const dir2 = e2.clone().sub(s);
|
|
33563
|
+
const length = dir2.length();
|
|
33564
|
+
const direction2 = length > 0 ? dir2.normalize() : new Vector3(1, 0, 0);
|
|
33565
|
+
return {
|
|
33566
|
+
kind: "edge",
|
|
33567
|
+
start: [s.x, s.y, s.z],
|
|
33568
|
+
end: [e2.x, e2.y, e2.z],
|
|
33569
|
+
length,
|
|
33570
|
+
direction: [direction2.x, direction2.y, direction2.z],
|
|
33571
|
+
meshUuid,
|
|
33572
|
+
curve: { kind: "line", start: [s.x, s.y, s.z], end: [e2.x, e2.y, e2.z], faceName: edge.curve.faceName }
|
|
33573
|
+
};
|
|
33253
33574
|
}
|
|
33254
|
-
|
|
33255
|
-
|
|
33256
|
-
|
|
33257
|
-
|
|
33258
|
-
|
|
33259
|
-
|
|
33260
|
-
|
|
33261
|
-
|
|
33262
|
-
|
|
33263
|
-
|
|
33264
|
-
|
|
33265
|
-
|
|
33266
|
-
|
|
33267
|
-
|
|
33268
|
-
}
|
|
33575
|
+
if (edge.curve.kind === "circle") {
|
|
33576
|
+
const center = new Vector3(...edge.curve.center).applyMatrix4(meshMatrixWorld);
|
|
33577
|
+
const axis = new Vector3(...edge.curve.axis).transformDirection(meshMatrixWorld).normalize();
|
|
33578
|
+
const radius = edge.curve.radius * scale;
|
|
33579
|
+
return {
|
|
33580
|
+
kind: "edge",
|
|
33581
|
+
start,
|
|
33582
|
+
end,
|
|
33583
|
+
length: 2 * Math.PI * radius,
|
|
33584
|
+
// circumference
|
|
33585
|
+
direction: [axis.x, axis.y, axis.z],
|
|
33586
|
+
meshUuid,
|
|
33587
|
+
curve: { kind: "circle", center: [center.x, center.y, center.z], axis: [axis.x, axis.y, axis.z], radius, faceName: edge.curve.faceName },
|
|
33588
|
+
polyline
|
|
33589
|
+
};
|
|
33269
33590
|
}
|
|
33591
|
+
const dir = new Vector3(end[0] - start[0], end[1] - start[1], end[2] - start[2]);
|
|
33592
|
+
const direction = dir.lengthSq() > 0 ? dir.normalize() : new Vector3(1, 0, 0);
|
|
33270
33593
|
return {
|
|
33271
|
-
|
|
33272
|
-
|
|
33273
|
-
|
|
33594
|
+
kind: "edge",
|
|
33595
|
+
start,
|
|
33596
|
+
end,
|
|
33597
|
+
length: edge.length * scale,
|
|
33598
|
+
direction: [direction.x, direction.y, direction.z],
|
|
33599
|
+
meshUuid,
|
|
33600
|
+
curve: { kind: "unidentified" },
|
|
33601
|
+
polyline
|
|
33602
|
+
};
|
|
33603
|
+
}
|
|
33604
|
+
const MEASURE_COLORS = {
|
|
33605
|
+
face: "#60b8ff",
|
|
33606
|
+
// hover face — gentle blue
|
|
33607
|
+
edge: "#ffffff",
|
|
33608
|
+
// hover edge — white
|
|
33609
|
+
vertex: "#ffffff",
|
|
33610
|
+
// hover vertex — white
|
|
33611
|
+
selection: "#ffa040",
|
|
33612
|
+
// both selections — warm amber
|
|
33613
|
+
line: "#ffa040",
|
|
33614
|
+
panelLabel: "#888",
|
|
33615
|
+
panelValue: "#ffd060"
|
|
33616
|
+
};
|
|
33617
|
+
function edgeEntityFromLocalPolyline(localPts, meshMatrixWorld, meshUuid) {
|
|
33618
|
+
const world = localPts.map((p2) => p2.clone().applyMatrix4(meshMatrixWorld));
|
|
33619
|
+
const start = world[0];
|
|
33620
|
+
const end = world[world.length - 1];
|
|
33621
|
+
let length = 0;
|
|
33622
|
+
const segments = [];
|
|
33623
|
+
for (let i = 1; i < world.length; i++) {
|
|
33624
|
+
length += world[i].distanceTo(world[i - 1]);
|
|
33625
|
+
segments.push([world[i - 1], world[i]]);
|
|
33626
|
+
}
|
|
33627
|
+
const dirVec = end.clone().sub(start);
|
|
33628
|
+
const direction = dirVec.lengthSq() > 0 ? dirVec.normalize() : new Vector3(1, 0, 0);
|
|
33629
|
+
const isLine = world.length <= 2;
|
|
33630
|
+
const entity = {
|
|
33631
|
+
kind: "edge",
|
|
33632
|
+
start: [start.x, start.y, start.z],
|
|
33633
|
+
end: [end.x, end.y, end.z],
|
|
33634
|
+
length,
|
|
33635
|
+
direction: [direction.x, direction.y, direction.z],
|
|
33636
|
+
meshUuid,
|
|
33637
|
+
curve: isLine ? { kind: "line", start: [start.x, start.y, start.z], end: [end.x, end.y, end.z] } : { kind: "unidentified" },
|
|
33638
|
+
polyline: isLine ? void 0 : world.map((p2) => [p2.x, p2.y, p2.z])
|
|
33274
33639
|
};
|
|
33640
|
+
return { entity, preview: { kind: "edge", edgeSegments: segments, meshUuid } };
|
|
33275
33641
|
}
|
|
33276
33642
|
function computeMeasureResult(a2, b2) {
|
|
33277
33643
|
const v32 = (xyz) => new Vector3(...xyz);
|
|
@@ -33413,9 +33779,11 @@ function MeasureTool() {
|
|
|
33413
33779
|
const measureMode = useForgeStore((s) => s.measureMode);
|
|
33414
33780
|
const measureSelections = useForgeStore((s) => s.measureSelections);
|
|
33415
33781
|
const addMeasureSelection = useForgeStore((s) => s.addMeasureSelection);
|
|
33782
|
+
const replaceLastMeasureSelection = useForgeStore((s) => s.replaceLastMeasureSelection);
|
|
33416
33783
|
const { camera, raycaster, scene, gl } = useThree();
|
|
33417
33784
|
const [hover, setHover] = reactExports.useState(null);
|
|
33418
33785
|
const pointerDownRef = reactExports.useRef(null);
|
|
33786
|
+
const lastSelectUpRef = reactExports.useRef(null);
|
|
33419
33787
|
const [selectionVisuals, setSelectionVisuals] = reactExports.useState({ geos: [], matrices: [], edgeSegments: [], vertexPositions: [] });
|
|
33420
33788
|
reactExports.useEffect(() => {
|
|
33421
33789
|
const geos = [];
|
|
@@ -33443,7 +33811,15 @@ function MeasureTool() {
|
|
|
33443
33811
|
} else if (sel.kind === "edge") {
|
|
33444
33812
|
geos.push(null);
|
|
33445
33813
|
matrices.push(null);
|
|
33446
|
-
|
|
33814
|
+
if (sel.polyline && sel.polyline.length >= 2) {
|
|
33815
|
+
const segs = [];
|
|
33816
|
+
for (let i = 1; i < sel.polyline.length; i++) {
|
|
33817
|
+
segs.push([new Vector3(...sel.polyline[i - 1]), new Vector3(...sel.polyline[i])]);
|
|
33818
|
+
}
|
|
33819
|
+
edgeSegs.push(segs);
|
|
33820
|
+
} else {
|
|
33821
|
+
edgeSegs.push([[new Vector3(...sel.start), new Vector3(...sel.end)]]);
|
|
33822
|
+
}
|
|
33447
33823
|
vertexPos.push(null);
|
|
33448
33824
|
} else {
|
|
33449
33825
|
geos.push(null);
|
|
@@ -33491,7 +33867,7 @@ function MeasureTool() {
|
|
|
33491
33867
|
[gl.domElement]
|
|
33492
33868
|
);
|
|
33493
33869
|
const detectEntity = reactExports.useCallback(
|
|
33494
|
-
(event) => {
|
|
33870
|
+
(event, wholePath = false) => {
|
|
33495
33871
|
if (!measureMode) return null;
|
|
33496
33872
|
const pointer = getPointerNDC(event);
|
|
33497
33873
|
raycaster.setFromCamera(new Vector2(pointer.x, pointer.y), camera);
|
|
@@ -33521,58 +33897,89 @@ function MeasureTool() {
|
|
|
33521
33897
|
const vA = new Vector3().fromBufferAttribute(positions, ia).applyMatrix4(mesh.matrixWorld);
|
|
33522
33898
|
const vB = new Vector3().fromBufferAttribute(positions, ib).applyMatrix4(mesh.matrixWorld);
|
|
33523
33899
|
const vC = new Vector3().fromBufferAttribute(positions, ic).applyMatrix4(mesh.matrixWorld);
|
|
33524
|
-
|
|
33525
|
-
|
|
33526
|
-
|
|
33527
|
-
|
|
33528
|
-
|
|
33529
|
-
|
|
33530
|
-
|
|
33531
|
-
|
|
33532
|
-
|
|
33533
|
-
|
|
33534
|
-
|
|
33535
|
-
|
|
33536
|
-
|
|
33537
|
-
|
|
33538
|
-
|
|
33539
|
-
|
|
33540
|
-
|
|
33541
|
-
|
|
33542
|
-
|
|
33543
|
-
|
|
33544
|
-
|
|
33545
|
-
|
|
33546
|
-
|
|
33547
|
-
|
|
33548
|
-
|
|
33549
|
-
|
|
33550
|
-
|
|
33551
|
-
|
|
33552
|
-
|
|
33553
|
-
|
|
33554
|
-
|
|
33555
|
-
|
|
33556
|
-
|
|
33557
|
-
|
|
33900
|
+
const invWorld = new Matrix4().copy(mesh.matrixWorld).invert();
|
|
33901
|
+
const localHit = hit.point.clone().applyMatrix4(invWorld);
|
|
33902
|
+
const bakedEdges = getBakedEdges(geometry);
|
|
33903
|
+
if (bakedEdges.length > 0) {
|
|
33904
|
+
if (!wholePath) {
|
|
33905
|
+
let cornerWorld = null;
|
|
33906
|
+
let cornerDist = SNAP_PX;
|
|
33907
|
+
for (const e2 of bakedEdges) {
|
|
33908
|
+
if (e2.curve.kind !== "line") continue;
|
|
33909
|
+
for (const pt2 of [e2.curve.start, e2.curve.end]) {
|
|
33910
|
+
const w = new Vector3(pt2[0], pt2[1], pt2[2]).applyMatrix4(mesh.matrixWorld);
|
|
33911
|
+
const s = worldToScreen2D(w);
|
|
33912
|
+
const d = Math.hypot(screenX - s.x, screenY - s.y);
|
|
33913
|
+
if (d < cornerDist) {
|
|
33914
|
+
cornerDist = d;
|
|
33915
|
+
cornerWorld = w;
|
|
33916
|
+
}
|
|
33917
|
+
}
|
|
33918
|
+
}
|
|
33919
|
+
if (cornerWorld) {
|
|
33920
|
+
const entity2 = {
|
|
33921
|
+
kind: "vertex",
|
|
33922
|
+
position: [cornerWorld.x, cornerWorld.y, cornerWorld.z],
|
|
33923
|
+
meshUuid: mesh.uuid
|
|
33924
|
+
};
|
|
33925
|
+
return { entity: entity2, preview: { kind: "vertex", vertexPosition: cornerWorld.clone() } };
|
|
33926
|
+
}
|
|
33927
|
+
}
|
|
33928
|
+
const carrierEdge = getNearestEdge(geometry, localHit, Number.POSITIVE_INFINITY);
|
|
33929
|
+
if (carrierEdge && (!wholePath || carrierEdge.edge.curve.kind === "circle")) {
|
|
33930
|
+
const worldPt = carrierEdge.point.clone().applyMatrix4(mesh.matrixWorld);
|
|
33931
|
+
const sp = worldToScreen2D(worldPt);
|
|
33932
|
+
if (Math.hypot(screenX - sp.x, screenY - sp.y) < SNAP_PX * 1.5) {
|
|
33933
|
+
const entity2 = edgeEntityFromBakedEdge(carrierEdge.edge, mesh.matrixWorld, mesh.uuid);
|
|
33934
|
+
const segs = [];
|
|
33935
|
+
const p2 = carrierEdge.edge.points;
|
|
33936
|
+
for (let i = 0; i + 5 < p2.length; i += 3) {
|
|
33937
|
+
segs.push([
|
|
33938
|
+
new Vector3(p2[i], p2[i + 1], p2[i + 2]).applyMatrix4(mesh.matrixWorld),
|
|
33939
|
+
new Vector3(p2[i + 3], p2[i + 4], p2[i + 5]).applyMatrix4(mesh.matrixWorld)
|
|
33940
|
+
]);
|
|
33941
|
+
}
|
|
33942
|
+
return { entity: entity2, preview: { kind: "edge", edgeSegments: segs, meshUuid: mesh.uuid } };
|
|
33943
|
+
}
|
|
33944
|
+
}
|
|
33945
|
+
} else if (!wholePath) {
|
|
33946
|
+
let closestVertexDist = Infinity;
|
|
33947
|
+
let closestVertex = null;
|
|
33948
|
+
for (const v of [vA, vB, vC]) {
|
|
33949
|
+
const s = worldToScreen2D(v);
|
|
33950
|
+
const d = Math.hypot(screenX - s.x, screenY - s.y);
|
|
33951
|
+
if (d < closestVertexDist && d < SNAP_PX) {
|
|
33952
|
+
closestVertexDist = d;
|
|
33953
|
+
closestVertex = v;
|
|
33954
|
+
}
|
|
33955
|
+
}
|
|
33956
|
+
if (closestVertex) {
|
|
33558
33957
|
const entity2 = {
|
|
33559
|
-
kind: "
|
|
33560
|
-
|
|
33561
|
-
end: [edgeResult.end.x, edgeResult.end.y, edgeResult.end.z],
|
|
33562
|
-
length: edgeResult.start.distanceTo(edgeResult.end),
|
|
33563
|
-
direction: [dir.x, dir.y, dir.z],
|
|
33958
|
+
kind: "vertex",
|
|
33959
|
+
position: [closestVertex.x, closestVertex.y, closestVertex.z],
|
|
33564
33960
|
meshUuid: mesh.uuid
|
|
33565
33961
|
};
|
|
33566
|
-
|
|
33567
|
-
|
|
33568
|
-
|
|
33569
|
-
|
|
33570
|
-
|
|
33571
|
-
|
|
33572
|
-
|
|
33962
|
+
return { entity: entity2, preview: { kind: "vertex", vertexPosition: closestVertex.clone() } };
|
|
33963
|
+
}
|
|
33964
|
+
}
|
|
33965
|
+
const chain = wholePath ? getWholeEdgePath(geometry, localHit) : getNearestEdgeChain(geometry, localHit);
|
|
33966
|
+
if (chain && chain.length >= 2) {
|
|
33967
|
+
const closest = new Vector3();
|
|
33968
|
+
const tmp = new Vector3();
|
|
33969
|
+
let nearestSq = Infinity;
|
|
33970
|
+
for (let i = 1; i < chain.length; i++) {
|
|
33971
|
+
const dSq = closestOnSegment(localHit, chain[i - 1], chain[i], tmp);
|
|
33972
|
+
if (dSq < nearestSq) {
|
|
33973
|
+
nearestSq = dSq;
|
|
33974
|
+
closest.copy(tmp);
|
|
33975
|
+
}
|
|
33976
|
+
}
|
|
33977
|
+
const screenPt = worldToScreen2D(closest.clone().applyMatrix4(mesh.matrixWorld));
|
|
33978
|
+
if (Math.hypot(screenX - screenPt.x, screenY - screenPt.y) < SNAP_PX * 1.5) {
|
|
33979
|
+
return edgeEntityFromLocalPolyline(chain, mesh.matrixWorld, mesh.uuid);
|
|
33573
33980
|
}
|
|
33574
33981
|
}
|
|
33575
|
-
const ffResult =
|
|
33982
|
+
const ffResult = getFaceRegion(geometry, faceIndex);
|
|
33576
33983
|
const worldNormal = ffResult.normal.clone().transformDirection(mesh.matrixWorld).normalize();
|
|
33577
33984
|
const worldCenter = ffResult.center.clone().applyMatrix4(mesh.matrixWorld);
|
|
33578
33985
|
const highlightGeo = buildFaceHighlightGeometry(geometry, ffResult.triangleIndices);
|
|
@@ -33636,17 +34043,31 @@ function MeasureTool() {
|
|
|
33636
34043
|
const down = pointerDownRef.current;
|
|
33637
34044
|
pointerDownRef.current = null;
|
|
33638
34045
|
if (!down || down.moved) return;
|
|
34046
|
+
const clearHover = () => setHover((prev) => {
|
|
34047
|
+
var _a4;
|
|
34048
|
+
(_a4 = prev == null ? void 0 : prev.faceHighlightGeo) == null ? void 0 : _a4.dispose();
|
|
34049
|
+
return null;
|
|
34050
|
+
});
|
|
34051
|
+
const now = performance.now();
|
|
34052
|
+
const last2 = lastSelectUpRef.current;
|
|
34053
|
+
const isDouble = !!last2 && last2.added && now - last2.t < 300 && Math.hypot(event.clientX - last2.x, event.clientY - last2.y) < 6;
|
|
34054
|
+
if (isDouble) {
|
|
34055
|
+
const whole = detectEntity(event, true);
|
|
34056
|
+
if (whole) {
|
|
34057
|
+
replaceLastMeasureSelection(whole.entity);
|
|
34058
|
+
clearHover();
|
|
34059
|
+
}
|
|
34060
|
+
lastSelectUpRef.current = null;
|
|
34061
|
+
return;
|
|
34062
|
+
}
|
|
33639
34063
|
const result = detectEntity(event);
|
|
33640
34064
|
if (result) {
|
|
33641
34065
|
addMeasureSelection(result.entity);
|
|
33642
|
-
|
|
33643
|
-
var _a4;
|
|
33644
|
-
(_a4 = prev == null ? void 0 : prev.faceHighlightGeo) == null ? void 0 : _a4.dispose();
|
|
33645
|
-
return null;
|
|
33646
|
-
});
|
|
34066
|
+
clearHover();
|
|
33647
34067
|
}
|
|
34068
|
+
lastSelectUpRef.current = { t: now, x: event.clientX, y: event.clientY, added: !!result };
|
|
33648
34069
|
},
|
|
33649
|
-
[addMeasureSelection, detectEntity, measureMode]
|
|
34070
|
+
[addMeasureSelection, detectEntity, measureMode, replaceLastMeasureSelection]
|
|
33650
34071
|
);
|
|
33651
34072
|
reactExports.useEffect(() => {
|
|
33652
34073
|
if (!measureMode) {
|
|
@@ -33859,15 +34280,31 @@ function MeasureInfoPanel() {
|
|
|
33859
34280
|
] });
|
|
33860
34281
|
}
|
|
33861
34282
|
if (sel.kind === "edge") {
|
|
34283
|
+
const circle = circleMeasurement(sel.curve);
|
|
33862
34284
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "fc-viewport-floating-panel fc-measure-info-panel", style: PANEL_STYLE, children: [
|
|
33863
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { style: { fontWeight: 600, marginBottom: 6, color: MEASURE_COLORS.selection }, children: "Edge" }),
|
|
33864
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
33865
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
33866
|
-
|
|
33867
|
-
|
|
33868
|
-
|
|
33869
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
33870
|
-
|
|
34285
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { style: { fontWeight: 600, marginBottom: 6, color: MEASURE_COLORS.selection }, children: circle ? "Circular Edge" : "Edge" }),
|
|
34286
|
+
circle ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
34287
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: ROW_STYLE, children: [
|
|
34288
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: MEASURE_COLORS.panelLabel }, children: "Radius" }),
|
|
34289
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: MEASURE_COLORS.panelValue, fontWeight: 600, fontSize: 14 }, children: formatLength(circle.radius, lengthUnit) })
|
|
34290
|
+
] }),
|
|
34291
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: ROW_STYLE, children: [
|
|
34292
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: MEASURE_COLORS.panelLabel }, children: "Diameter" }),
|
|
34293
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: MEASURE_COLORS.panelValue, fontWeight: 600, fontSize: 14 }, children: formatLength(circle.diameter, lengthUnit) })
|
|
34294
|
+
] }),
|
|
34295
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: ROW_STYLE, children: [
|
|
34296
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: MEASURE_COLORS.panelLabel }, children: "Circumference" }),
|
|
34297
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: MEASURE_COLORS.panelValue }, children: formatLength(circle.circumference, lengthUnit) })
|
|
34298
|
+
] })
|
|
34299
|
+
] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
34300
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: ROW_STYLE, children: [
|
|
34301
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: MEASURE_COLORS.panelLabel }, children: "Length" }),
|
|
34302
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: MEASURE_COLORS.panelValue }, children: formatLength(sel.length, lengthUnit) })
|
|
34303
|
+
] }),
|
|
34304
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: ROW_STYLE, children: [
|
|
34305
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: MEASURE_COLORS.panelLabel }, children: "Direction" }),
|
|
34306
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: fmtNormal(sel.direction) })
|
|
34307
|
+
] })
|
|
33871
34308
|
] }),
|
|
33872
34309
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { style: { marginTop: 6, fontSize: 10, color: MEASURE_COLORS.panelLabel }, children: "Click another entity to measure" })
|
|
33873
34310
|
] });
|
|
@@ -38530,7 +38967,7 @@ const computeExplodeTreeOffsets = (root, explodeAmount, explodeConfig) => {
|
|
|
38530
38967
|
if (Math.abs(config.amount) <= 1e-8) return {};
|
|
38531
38968
|
const rootCenter = explodeBoundsCenter(root.bounds) ?? [0, 0, 0];
|
|
38532
38969
|
const offsets = {};
|
|
38533
|
-
const
|
|
38970
|
+
const walk2 = (node, depth, inherited, parentCenter, parentDirection) => {
|
|
38534
38971
|
const center = explodeBoundsCenter(node.bounds) ?? parentCenter;
|
|
38535
38972
|
const directive = resolveExplodeDirective([node.path.join("/")], node.label, void 0, config);
|
|
38536
38973
|
const motion = depth > 1 && node.children.length === 0 && !hasExplodeOverride(directive) ? (() => {
|
|
@@ -38554,9 +38991,9 @@ const computeExplodeTreeOffsets = (root, explodeAmount, explodeConfig) => {
|
|
|
38554
38991
|
node.objectIds.forEach((objectId) => {
|
|
38555
38992
|
offsets[objectId] = total;
|
|
38556
38993
|
});
|
|
38557
|
-
node.children.forEach((child) =>
|
|
38994
|
+
node.children.forEach((child) => walk2(child, depth + 1, total, center, motion.branchDirection));
|
|
38558
38995
|
};
|
|
38559
|
-
root.children.forEach((child) =>
|
|
38996
|
+
root.children.forEach((child) => walk2(child, 1, [0, 0, 0], rootCenter, void 0));
|
|
38560
38997
|
return offsets;
|
|
38561
38998
|
};
|
|
38562
38999
|
const EMPTY_RIG_INSPECTION_OVERLAY_STATE = {
|
|
@@ -39474,6 +39911,48 @@ function shouldRequestInitialFit({
|
|
|
39474
39911
|
if (initialFitRequested && previousPreviewFile === previewFile) return false;
|
|
39475
39912
|
return true;
|
|
39476
39913
|
}
|
|
39914
|
+
const SUBFEATURE_SNAP_PX = 14;
|
|
39915
|
+
const CLICK_DRAG_TOLERANCE_PX = 4;
|
|
39916
|
+
function worldToScreenPx(pt2, camera, rect) {
|
|
39917
|
+
const p2 = pt2.clone().project(camera);
|
|
39918
|
+
return {
|
|
39919
|
+
x: (p2.x * 0.5 + 0.5) * rect.width + rect.left,
|
|
39920
|
+
y: (-p2.y * 0.5 + 0.5) * rect.height + rect.top
|
|
39921
|
+
};
|
|
39922
|
+
}
|
|
39923
|
+
function drillIntoSubFeature(mesh, worldHit, camera, rect, clientX, clientY, objectId, store) {
|
|
39924
|
+
const geometry = mesh.geometry;
|
|
39925
|
+
const inv = new Matrix4().copy(mesh.matrixWorld).invert();
|
|
39926
|
+
const localHit = worldHit.clone().applyMatrix4(inv);
|
|
39927
|
+
const vtx = getNearestVertex(geometry, localHit, Number.POSITIVE_INFINITY);
|
|
39928
|
+
if (vtx) {
|
|
39929
|
+
const worldPt = vtx.point.clone().applyMatrix4(mesh.matrixWorld);
|
|
39930
|
+
const s = worldToScreenPx(worldPt, camera, rect);
|
|
39931
|
+
if (Math.hypot(clientX - s.x, clientY - s.y) <= SUBFEATURE_SNAP_PX) {
|
|
39932
|
+
store.setSelectedEdge(null);
|
|
39933
|
+
store.setSelectedVertex({ objectId, point: [vtx.point.x, vtx.point.y, vtx.point.z] });
|
|
39934
|
+
return true;
|
|
39935
|
+
}
|
|
39936
|
+
}
|
|
39937
|
+
const edge = getNearestEdge(geometry, localHit, Number.POSITIVE_INFINITY);
|
|
39938
|
+
if (edge) {
|
|
39939
|
+
const worldPt = edge.point.clone().applyMatrix4(mesh.matrixWorld);
|
|
39940
|
+
const s = worldToScreenPx(worldPt, camera, rect);
|
|
39941
|
+
if (Math.hypot(clientX - s.x, clientY - s.y) <= SUBFEATURE_SNAP_PX) {
|
|
39942
|
+
store.setSelectedVertex(null);
|
|
39943
|
+
store.setSelectedEdge({
|
|
39944
|
+
objectId,
|
|
39945
|
+
faceA: edge.edge.faceA,
|
|
39946
|
+
faceB: edge.edge.faceB,
|
|
39947
|
+
curve: edge.edge.curve,
|
|
39948
|
+
length: edge.edge.length,
|
|
39949
|
+
points: edge.edge.points
|
|
39950
|
+
});
|
|
39951
|
+
return true;
|
|
39952
|
+
}
|
|
39953
|
+
}
|
|
39954
|
+
return false;
|
|
39955
|
+
}
|
|
39477
39956
|
function useViewportHandlers({
|
|
39478
39957
|
containerRef,
|
|
39479
39958
|
contextMenuRef,
|
|
@@ -39505,6 +39984,14 @@ function useViewportHandlers({
|
|
|
39505
39984
|
const [faceInfoData, setFaceInfoData] = reactExports.useState(null);
|
|
39506
39985
|
const [faceInfoLoading, setFaceInfoLoading] = reactExports.useState(false);
|
|
39507
39986
|
const [sketchEntityInfo, setSketchEntityInfo] = reactExports.useState(null);
|
|
39987
|
+
const pointerDownPosRef = reactExports.useRef(null);
|
|
39988
|
+
reactExports.useEffect(() => {
|
|
39989
|
+
const onDown = (e2) => {
|
|
39990
|
+
pointerDownPosRef.current = { x: e2.clientX, y: e2.clientY };
|
|
39991
|
+
};
|
|
39992
|
+
window.addEventListener("pointerdown", onDown, { capture: true });
|
|
39993
|
+
return () => window.removeEventListener("pointerdown", onDown, { capture: true });
|
|
39994
|
+
}, []);
|
|
39508
39995
|
const closeObjectContextMenu = reactExports.useCallback(() => {
|
|
39509
39996
|
setObjectContextMenu(null);
|
|
39510
39997
|
}, []);
|
|
@@ -39565,6 +40052,20 @@ function useViewportHandlers({
|
|
|
39565
40052
|
closeObjectContextMenu();
|
|
39566
40053
|
return;
|
|
39567
40054
|
}
|
|
40055
|
+
const store = useForgeStore.getState();
|
|
40056
|
+
if (store.selectedVertex) {
|
|
40057
|
+
store.setSelectedVertex(null);
|
|
40058
|
+
return;
|
|
40059
|
+
}
|
|
40060
|
+
if (store.selectedEdge) {
|
|
40061
|
+
store.setSelectedEdge(null);
|
|
40062
|
+
return;
|
|
40063
|
+
}
|
|
40064
|
+
if (store.selectedFace) {
|
|
40065
|
+
store.setSelectedFace(null);
|
|
40066
|
+
setFaceInfoPanel(null);
|
|
40067
|
+
return;
|
|
40068
|
+
}
|
|
39568
40069
|
if (faceInfoPanel) {
|
|
39569
40070
|
setFaceInfoPanel(null);
|
|
39570
40071
|
return;
|
|
@@ -39573,7 +40074,6 @@ function useViewportHandlers({
|
|
|
39573
40074
|
setSketchEntityInfo(null);
|
|
39574
40075
|
return;
|
|
39575
40076
|
}
|
|
39576
|
-
const store = useForgeStore.getState();
|
|
39577
40077
|
if (store.measureMode) {
|
|
39578
40078
|
if (store.measureSelections.length > 0) {
|
|
39579
40079
|
store.clearMeasureSelections();
|
|
@@ -39586,8 +40086,13 @@ function useViewportHandlers({
|
|
|
39586
40086
|
store.setConstructionGhost(null);
|
|
39587
40087
|
return;
|
|
39588
40088
|
}
|
|
39589
|
-
if (store.focusedObjectIds.length
|
|
39590
|
-
|
|
40089
|
+
if (store.focusedObjectIds.length > 0) {
|
|
40090
|
+
clearFocusedObject();
|
|
40091
|
+
return;
|
|
40092
|
+
}
|
|
40093
|
+
if (store.selectedObjectId) {
|
|
40094
|
+
store.selectObject(null);
|
|
40095
|
+
}
|
|
39591
40096
|
};
|
|
39592
40097
|
window.addEventListener("keydown", handleEscape);
|
|
39593
40098
|
return () => window.removeEventListener("keydown", handleEscape);
|
|
@@ -39681,11 +40186,42 @@ function useViewportHandlers({
|
|
|
39681
40186
|
);
|
|
39682
40187
|
const handleObjectClick = reactExports.useCallback(
|
|
39683
40188
|
(obj, event) => {
|
|
40189
|
+
var _a3;
|
|
39684
40190
|
if (!objectPickSyncEnabled || measureMode || isViewportInteracting) return;
|
|
40191
|
+
const down = pointerDownPosRef.current;
|
|
40192
|
+
if (down && Math.hypot(event.clientX - down.x, event.clientY - down.y) > CLICK_DRAG_TOLERANCE_PX) return;
|
|
39685
40193
|
event.stopPropagation();
|
|
39686
|
-
|
|
40194
|
+
const store = useForgeStore.getState();
|
|
40195
|
+
const alreadySelected = store.selectedObjectId === obj.id;
|
|
40196
|
+
if (!alreadySelected) {
|
|
40197
|
+
selectObject(obj.id);
|
|
40198
|
+
setFaceInfoPanel(null);
|
|
40199
|
+
return;
|
|
40200
|
+
}
|
|
40201
|
+
const rectForPick = (_a3 = containerRef.current) == null ? void 0 : _a3.getBoundingClientRect();
|
|
40202
|
+
if (event.object instanceof Mesh && rectForPick && event.point && drillIntoSubFeature(event.object, event.point, event.camera, rectForPick, event.clientX, event.clientY, obj.id, store)) {
|
|
40203
|
+
store.setSelectedFace(null);
|
|
40204
|
+
setFaceInfoPanel(null);
|
|
40205
|
+
return;
|
|
40206
|
+
}
|
|
40207
|
+
const triangleIndex = event.faceIndex ?? (event.face ? Math.floor(event.face.a / 3) : null);
|
|
40208
|
+
if (event.object instanceof Mesh && triangleIndex !== null && triangleIndex >= 0) {
|
|
40209
|
+
store.setSelectedEdge(null);
|
|
40210
|
+
store.setSelectedVertex(null);
|
|
40211
|
+
const region = getFaceRegion(event.object.geometry, triangleIndex);
|
|
40212
|
+
const worldNormal = region.normal.clone().transformDirection(event.object.matrixWorld).normalize();
|
|
40213
|
+
const worldCenter = region.center.clone().applyMatrix4(event.object.matrixWorld);
|
|
40214
|
+
store.setSelectedFace({
|
|
40215
|
+
objectId: obj.id,
|
|
40216
|
+
carrierName: region.carrierName,
|
|
40217
|
+
triangleIndices: region.triangleIndices,
|
|
40218
|
+
meshUuid: event.object.uuid,
|
|
40219
|
+
normal: [worldNormal.x, worldNormal.y, worldNormal.z],
|
|
40220
|
+
center: [worldCenter.x, worldCenter.y, worldCenter.z]
|
|
40221
|
+
});
|
|
40222
|
+
}
|
|
39687
40223
|
},
|
|
39688
|
-
[isViewportInteracting, measureMode, objectPickSyncEnabled, selectObject]
|
|
40224
|
+
[containerRef, isViewportInteracting, measureMode, objectPickSyncEnabled, selectObject, setFaceInfoPanel]
|
|
39689
40225
|
);
|
|
39690
40226
|
const handleObjectDoubleClick = reactExports.useCallback(
|
|
39691
40227
|
(obj, event) => {
|
|
@@ -39693,8 +40229,13 @@ function useViewportHandlers({
|
|
|
39693
40229
|
event.stopPropagation();
|
|
39694
40230
|
const additive = event.shiftKey || event.metaKey || event.ctrlKey;
|
|
39695
40231
|
focusObject(obj.id, { additive });
|
|
40232
|
+
const store = useForgeStore.getState();
|
|
40233
|
+
store.setSelectedFace(null);
|
|
40234
|
+
store.setSelectedEdge(null);
|
|
40235
|
+
store.setSelectedVertex(null);
|
|
40236
|
+
setFaceInfoPanel(null);
|
|
39696
40237
|
},
|
|
39697
|
-
[focusObject, isViewportInteracting, measureMode]
|
|
40238
|
+
[focusObject, isViewportInteracting, measureMode, setFaceInfoPanel]
|
|
39698
40239
|
);
|
|
39699
40240
|
const handleObjectContextMenu = reactExports.useCallback(
|
|
39700
40241
|
(obj, event) => {
|
|
@@ -40965,7 +41506,7 @@ function useGeometryComparison(args) {
|
|
|
40965
41506
|
}, [args.activeBackend, args.candidate, args.enabled, args.files, args.previewFile, args.quality]);
|
|
40966
41507
|
return state2;
|
|
40967
41508
|
}
|
|
40968
|
-
const PARALLEL_CHANNELS = /* @__PURE__ */ new Set(["thickness", "roughness"]);
|
|
41509
|
+
const PARALLEL_CHANNELS = /* @__PURE__ */ new Set(["thickness", "throughThickness", "roughness"]);
|
|
40969
41510
|
const MAX_INSPECT_WORKERS = Math.max(
|
|
40970
41511
|
1,
|
|
40971
41512
|
Math.min((typeof navigator !== "undefined" && navigator.hardwareConcurrency ? navigator.hardwareConcurrency : 4) - 1, 8)
|
|
@@ -41021,7 +41562,7 @@ function mergeResults(results, channel, analysisId) {
|
|
|
41021
41562
|
class InspectWorkerClient {
|
|
41022
41563
|
constructor(workerFactory = () => new Worker(new URL(
|
|
41023
41564
|
/* @vite-ignore */
|
|
41024
|
-
"/assets/inspectWorker-
|
|
41565
|
+
"/assets/inspectWorker-UXMxlcR8.js",
|
|
41025
41566
|
import.meta.url
|
|
41026
41567
|
), { type: "module" })) {
|
|
41027
41568
|
__publicField(this, "reqId", 0);
|
|
@@ -41075,8 +41616,16 @@ class InspectWorkerClient {
|
|
|
41075
41616
|
}
|
|
41076
41617
|
}
|
|
41077
41618
|
const inspectWorkerClient = new InspectWorkerClient();
|
|
41078
|
-
const WORKER_CHANNELS = /* @__PURE__ */ new Set([
|
|
41079
|
-
|
|
41619
|
+
const WORKER_CHANNELS = /* @__PURE__ */ new Set([
|
|
41620
|
+
"thickness",
|
|
41621
|
+
"throughThickness",
|
|
41622
|
+
"roughness",
|
|
41623
|
+
"connectivity",
|
|
41624
|
+
"floating",
|
|
41625
|
+
"distance",
|
|
41626
|
+
"collisions"
|
|
41627
|
+
]);
|
|
41628
|
+
const SCALAR_WORKER_CHANNELS = /* @__PURE__ */ new Set(["thickness", "throughThickness", "roughness"]);
|
|
41080
41629
|
const MESH_COMPONENT_WORKER_CHANNELS = /* @__PURE__ */ new Set(["connectivity", "floating", "distance"]);
|
|
41081
41630
|
const IDENTITY_MATRIX_ELEMENTS = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
|
|
41082
41631
|
const INSPECT_BUILD_YIELD_INTERVAL_MS = 8;
|
|
@@ -41386,6 +41935,15 @@ function analyzePayloadFor(channel, objects, inspectPointSampleCount, groundZ, w
|
|
|
41386
41935
|
}
|
|
41387
41936
|
};
|
|
41388
41937
|
}
|
|
41938
|
+
if (channel === "throughThickness") {
|
|
41939
|
+
return {
|
|
41940
|
+
channel,
|
|
41941
|
+
objects,
|
|
41942
|
+
throughThickness: {
|
|
41943
|
+
maxSamplesPerObject
|
|
41944
|
+
}
|
|
41945
|
+
};
|
|
41946
|
+
}
|
|
41389
41947
|
if (channel === "roughness") {
|
|
41390
41948
|
return {
|
|
41391
41949
|
channel,
|
|
@@ -41413,6 +41971,10 @@ function resultToState(channel, result) {
|
|
|
41413
41971
|
normals: object.normals,
|
|
41414
41972
|
index: object.index,
|
|
41415
41973
|
aValue: object.aValue,
|
|
41974
|
+
uvs: object.uvs,
|
|
41975
|
+
textureValues: object.textureValues,
|
|
41976
|
+
textureWidth: object.textureWidth,
|
|
41977
|
+
textureHeight: object.textureHeight,
|
|
41416
41978
|
valueMin: object.valueMin,
|
|
41417
41979
|
valueMax: object.valueMax,
|
|
41418
41980
|
capped: object.capped,
|
|
@@ -41743,6 +42305,24 @@ function panelNumber(value) {
|
|
|
41743
42305
|
function vec3Label(value) {
|
|
41744
42306
|
return `[${value.map(panelNumber).join(", ")}]`;
|
|
41745
42307
|
}
|
|
42308
|
+
function localPointToWorld(point, matrix) {
|
|
42309
|
+
const v = new Vector3(point[0], point[1], point[2]).applyMatrix4(matrix);
|
|
42310
|
+
return [v.x, v.y, v.z];
|
|
42311
|
+
}
|
|
42312
|
+
function localDirToWorld(dir, matrix) {
|
|
42313
|
+
const normal = new Matrix3().getNormalMatrix(matrix);
|
|
42314
|
+
const v = new Vector3(dir[0], dir[1], dir[2]).applyMatrix3(normal).normalize();
|
|
42315
|
+
return [v.x, v.y, v.z];
|
|
42316
|
+
}
|
|
42317
|
+
function worldScaleFactor(matrix) {
|
|
42318
|
+
const det = matrix.determinant();
|
|
42319
|
+
const scale = Math.cbrt(Math.abs(det));
|
|
42320
|
+
return Number.isFinite(scale) && scale > 0 ? scale : 1;
|
|
42321
|
+
}
|
|
42322
|
+
function copyNumberToClipboard(value) {
|
|
42323
|
+
var _a3;
|
|
42324
|
+
void ((_a3 = navigator.clipboard) == null ? void 0 : _a3.writeText(panelNumber(value)));
|
|
42325
|
+
}
|
|
41746
42326
|
function edgeCurveLabel(edge) {
|
|
41747
42327
|
var _a3;
|
|
41748
42328
|
switch ((_a3 = edge.curve) == null ? void 0 : _a3.kind) {
|
|
@@ -41778,6 +42358,8 @@ function inspectChannelLabel(channel) {
|
|
|
41778
42358
|
return "Comparison";
|
|
41779
42359
|
case "thickness":
|
|
41780
42360
|
return "Thickness";
|
|
42361
|
+
case "throughThickness":
|
|
42362
|
+
return "Minimum Solid Span";
|
|
41781
42363
|
case "roughness":
|
|
41782
42364
|
return "Roughness";
|
|
41783
42365
|
default:
|
|
@@ -41993,6 +42575,11 @@ function Viewport() {
|
|
|
41993
42575
|
const runQuality = useForgeStore((s) => s.runQuality);
|
|
41994
42576
|
const buildLedgerEvents = useForgeStore((s) => s.buildLedgerEvents);
|
|
41995
42577
|
const measureSelections = useForgeStore((s) => s.measureSelections);
|
|
42578
|
+
const selectedFace = useForgeStore((s) => s.selectedFace);
|
|
42579
|
+
const selectedEdge = useForgeStore((s) => s.selectedEdge);
|
|
42580
|
+
const selectedVertex = useForgeStore((s) => s.selectedVertex);
|
|
42581
|
+
const setSelectedEdge = useForgeStore((s) => s.setSelectedEdge);
|
|
42582
|
+
const setSelectedVertex = useForgeStore((s) => s.setSelectedVertex);
|
|
41996
42583
|
const meshPreviewFile = useForgeStore((s) => s.meshPreviewFile);
|
|
41997
42584
|
const voxelIntentMode = useForgeStore((s) => s.voxelIntentMode);
|
|
41998
42585
|
const voxelIntentTool = useForgeStore((s) => s.voxelIntentTool);
|
|
@@ -42176,15 +42763,35 @@ function Viewport() {
|
|
|
42176
42763
|
groundZ: inspectGroundZ
|
|
42177
42764
|
});
|
|
42178
42765
|
const scalarChannelInfo = reactExports.useMemo(() => {
|
|
42179
|
-
if (inspectChannel === "thickness") {
|
|
42766
|
+
if (inspectChannel === "thickness" || inspectChannel === "throughThickness") {
|
|
42180
42767
|
return { unitLabel: "mm", criticalThreshold: DEFAULT_THICKNESS_INSPECTION_OPTIONS.minThickness };
|
|
42181
42768
|
}
|
|
42182
42769
|
if (inspectChannel === "roughness") return { unitLabel: "deg", criticalThreshold: null };
|
|
42183
42770
|
return null;
|
|
42184
42771
|
}, [inspectChannel]);
|
|
42772
|
+
const measuredThicknessMax = reactExports.useMemo(() => {
|
|
42773
|
+
if (inspectChannel !== "thickness" && inspectChannel !== "throughThickness") return null;
|
|
42774
|
+
let max2 = -Infinity;
|
|
42775
|
+
for (const surface of Object.values(inspectAnalysis.scalarSurfaces)) {
|
|
42776
|
+
if (Number.isFinite(surface.valueMax)) max2 = Math.max(max2, surface.valueMax);
|
|
42777
|
+
}
|
|
42778
|
+
return Number.isFinite(max2) ? max2 : null;
|
|
42779
|
+
}, [inspectAnalysis.scalarSurfaces, inspectChannel]);
|
|
42780
|
+
const effectiveThicknessColorRange = reactExports.useMemo(() => {
|
|
42781
|
+
const isDefaultRange = thicknessColorRange.min === DEFAULT_THICKNESS_COLOR_RANGE.min && thicknessColorRange.max === DEFAULT_THICKNESS_COLOR_RANGE.max;
|
|
42782
|
+
if (isDefaultRange && measuredThicknessMax != null && measuredThicknessMax > thicknessColorRange.max) {
|
|
42783
|
+
return { min: thicknessColorRange.min, max: measuredThicknessMax };
|
|
42784
|
+
}
|
|
42785
|
+
return thicknessColorRange;
|
|
42786
|
+
}, [measuredThicknessMax, thicknessColorRange]);
|
|
42185
42787
|
const inspectColorScale = reactExports.useMemo(
|
|
42186
|
-
() => ({
|
|
42187
|
-
|
|
42788
|
+
() => ({
|
|
42789
|
+
colormap: inspectColormap,
|
|
42790
|
+
domainMin: effectiveThicknessColorRange.min,
|
|
42791
|
+
domainMax: effectiveThicknessColorRange.max,
|
|
42792
|
+
...(inspectChannel === "thickness" || inspectChannel === "throughThickness") && inspectColormap !== "thickness-classic" ? { reversed: true } : {}
|
|
42793
|
+
}),
|
|
42794
|
+
[effectiveThicknessColorRange.max, effectiveThicknessColorRange.min, inspectChannel, inspectColormap]
|
|
42188
42795
|
);
|
|
42189
42796
|
const inspectScalarParams = reactExports.useMemo(() => {
|
|
42190
42797
|
if (!scalarChannelInfo) return void 0;
|
|
@@ -42195,11 +42802,12 @@ function Viewport() {
|
|
|
42195
42802
|
isolineSpacing: inspectIsolineSpacing,
|
|
42196
42803
|
criticalEnabled: inspectCriticalLineEnabled,
|
|
42197
42804
|
criticalThreshold: scalarChannelInfo.criticalThreshold,
|
|
42198
|
-
shadingEnabled:
|
|
42805
|
+
shadingEnabled: inspectChannel !== "thickness" && inspectChannel !== "throughThickness"
|
|
42199
42806
|
};
|
|
42200
42807
|
}, [
|
|
42201
42808
|
scalarChannelInfo,
|
|
42202
42809
|
inspectColorScale,
|
|
42810
|
+
inspectChannel,
|
|
42203
42811
|
inspectQuantizeBands,
|
|
42204
42812
|
inspectIsolinesEnabled,
|
|
42205
42813
|
inspectIsolineSpacing,
|
|
@@ -42440,7 +43048,7 @@ function Viewport() {
|
|
|
42440
43048
|
displayMode: inspectDisplayMode,
|
|
42441
43049
|
warnings: inspectWarnings,
|
|
42442
43050
|
swatches: inspectLegendSwatches,
|
|
42443
|
-
thicknessColorRange,
|
|
43051
|
+
thicknessColorRange: effectiveThicknessColorRange,
|
|
42444
43052
|
onThicknessColorRangeChange: setThicknessColorRange,
|
|
42445
43053
|
colorScale: scalarChannelInfo ? inspectColorScale : void 0,
|
|
42446
43054
|
unitLabel: scalarChannelInfo == null ? void 0 : scalarChannelInfo.unitLabel,
|
|
@@ -42674,6 +43282,9 @@ function Viewport() {
|
|
|
42674
43282
|
sectionPlanes: objectSectionPlanesById[obj.id] ?? EMPTY_SECTION_PLANES,
|
|
42675
43283
|
sectionPreviewRenderOrderBase: 2e3 + objIndex * 64,
|
|
42676
43284
|
debugHighlightColor: shapeHl == null ? void 0 : shapeHl.color,
|
|
43285
|
+
selectedFaceTriangleIndices: (selectedFace == null ? void 0 : selectedFace.objectId) === obj.id ? selectedFace.triangleIndices : null,
|
|
43286
|
+
selectedEdgePoints: (selectedEdge == null ? void 0 : selectedEdge.objectId) === obj.id ? selectedEdge.points : null,
|
|
43287
|
+
selectedVertexPoint: (selectedVertex == null ? void 0 : selectedVertex.objectId) === obj.id ? selectedVertex.point : null,
|
|
42677
43288
|
onPointerEnter: (event) => updateHoverLabel(obj, event),
|
|
42678
43289
|
onPointerMove: (event) => updateHoverLabel(obj, event),
|
|
42679
43290
|
onPointerLeave: (event) => clearHoverLabel(obj, event),
|
|
@@ -43129,6 +43740,7 @@ function Viewport() {
|
|
|
43129
43740
|
),
|
|
43130
43741
|
viewportPortalHost && faceInfoPanel && reactDomExports.createPortal(
|
|
43131
43742
|
(() => {
|
|
43743
|
+
var _a4;
|
|
43132
43744
|
const obj = objects.find((o2) => o2.id === faceInfoPanel.objectId);
|
|
43133
43745
|
if (!obj) return null;
|
|
43134
43746
|
const activeFaceName = faceInfoPanel.faceName;
|
|
@@ -43139,8 +43751,8 @@ function Viewport() {
|
|
|
43139
43751
|
const history = activeFaceName ? (faceInfoData == null ? void 0 : faceInfoData.faceHistories[activeFaceName]) ?? null : null;
|
|
43140
43752
|
const faceNames = (faceInfoData == null ? void 0 : faceInfoData.faceNames) ?? [];
|
|
43141
43753
|
const activeEdges = activeFaceName && faceInfoData ? (faceInfoData.edgeNames ?? []).map((name) => {
|
|
43142
|
-
var
|
|
43143
|
-
return (
|
|
43754
|
+
var _a5;
|
|
43755
|
+
return (_a5 = faceInfoData.edges) == null ? void 0 : _a5[name];
|
|
43144
43756
|
}).filter((edge) => Boolean(edge) && edgeBelongsToFace(edge, activeFaceName)) : [];
|
|
43145
43757
|
const visibleEdges = activeEdges.slice(0, 12);
|
|
43146
43758
|
const viewportMaxRight = Math.min(viewportScreenRight, viewportWindowWidth);
|
|
@@ -43171,23 +43783,47 @@ function Viewport() {
|
|
|
43171
43783
|
children: [
|
|
43172
43784
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 4 }, children: [
|
|
43173
43785
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { fontWeight: 600, fontSize: 13 }, children: "Surface History" }),
|
|
43174
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
43175
|
-
|
|
43176
|
-
|
|
43177
|
-
|
|
43178
|
-
|
|
43179
|
-
|
|
43180
|
-
|
|
43181
|
-
|
|
43182
|
-
|
|
43183
|
-
|
|
43184
|
-
|
|
43185
|
-
|
|
43186
|
-
|
|
43187
|
-
|
|
43188
|
-
|
|
43189
|
-
|
|
43190
|
-
|
|
43786
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [
|
|
43787
|
+
activeFaceName && activeFace && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
43788
|
+
"button",
|
|
43789
|
+
{
|
|
43790
|
+
type: "button",
|
|
43791
|
+
title: `Copy face("${activeFaceName}") selector to clipboard`,
|
|
43792
|
+
onClick: () => {
|
|
43793
|
+
var _a5;
|
|
43794
|
+
void ((_a5 = navigator.clipboard) == null ? void 0 : _a5.writeText(`face(${JSON.stringify(activeFaceName)})`));
|
|
43795
|
+
},
|
|
43796
|
+
style: {
|
|
43797
|
+
border: "1px solid var(--fc-border)",
|
|
43798
|
+
background: "transparent",
|
|
43799
|
+
color: "var(--fc-textMuted)",
|
|
43800
|
+
cursor: "pointer",
|
|
43801
|
+
fontSize: 11,
|
|
43802
|
+
lineHeight: 1,
|
|
43803
|
+
borderRadius: 4,
|
|
43804
|
+
padding: "3px 6px"
|
|
43805
|
+
},
|
|
43806
|
+
children: "Copy selector"
|
|
43807
|
+
}
|
|
43808
|
+
),
|
|
43809
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
43810
|
+
"button",
|
|
43811
|
+
{
|
|
43812
|
+
type: "button",
|
|
43813
|
+
onClick: () => setFaceInfoPanel(null),
|
|
43814
|
+
style: {
|
|
43815
|
+
border: "none",
|
|
43816
|
+
background: "transparent",
|
|
43817
|
+
color: "var(--fc-textMuted)",
|
|
43818
|
+
cursor: "pointer",
|
|
43819
|
+
fontSize: 16,
|
|
43820
|
+
lineHeight: 1,
|
|
43821
|
+
padding: 0
|
|
43822
|
+
},
|
|
43823
|
+
children: "×"
|
|
43824
|
+
}
|
|
43825
|
+
)
|
|
43826
|
+
] })
|
|
43191
43827
|
] }),
|
|
43192
43828
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
43193
43829
|
"div",
|
|
@@ -43274,6 +43910,33 @@ function Viewport() {
|
|
|
43274
43910
|
]
|
|
43275
43911
|
}
|
|
43276
43912
|
),
|
|
43913
|
+
((_a4 = history == null ? void 0 : history.origin) == null ? void 0 : _a4.sourceSpan) && /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
43914
|
+
"div",
|
|
43915
|
+
{
|
|
43916
|
+
style: {
|
|
43917
|
+
marginBottom: 10,
|
|
43918
|
+
padding: 8,
|
|
43919
|
+
border: "1px solid var(--fc-border)",
|
|
43920
|
+
borderRadius: 6,
|
|
43921
|
+
background: "color-mix(in srgb, var(--fc-bgInput) 70%, transparent)"
|
|
43922
|
+
},
|
|
43923
|
+
children: [
|
|
43924
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { style: { fontSize: 11, fontWeight: 600, marginBottom: 3 }, children: "Source" }),
|
|
43925
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
43926
|
+
"div",
|
|
43927
|
+
{
|
|
43928
|
+
style: {
|
|
43929
|
+
fontSize: 10,
|
|
43930
|
+
color: "var(--fc-textMuted)",
|
|
43931
|
+
fontFamily: "monospace",
|
|
43932
|
+
wordBreak: "break-all"
|
|
43933
|
+
},
|
|
43934
|
+
children: `${history.origin.sourceSpan.fileName}:${history.origin.sourceSpan.line}:${history.origin.sourceSpan.column}`
|
|
43935
|
+
}
|
|
43936
|
+
)
|
|
43937
|
+
]
|
|
43938
|
+
}
|
|
43939
|
+
),
|
|
43277
43940
|
history && history.timeline.length > 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: history.timeline.map((entry, i) => {
|
|
43278
43941
|
const isFirst = i === 0;
|
|
43279
43942
|
const isLast = i === history.timeline.length - 1;
|
|
@@ -43489,12 +44152,164 @@ function Viewport() {
|
|
|
43489
44152
|
]
|
|
43490
44153
|
}
|
|
43491
44154
|
);
|
|
44155
|
+
})(),
|
|
44156
|
+
(selectedEdge || selectedVertex) && (() => {
|
|
44157
|
+
const objectId = (selectedEdge == null ? void 0 : selectedEdge.objectId) ?? (selectedVertex == null ? void 0 : selectedVertex.objectId) ?? "";
|
|
44158
|
+
const obj = objects.find((o2) => o2.id === objectId);
|
|
44159
|
+
const matrix = objectMatrices[objectId] ?? new Matrix4();
|
|
44160
|
+
const scale = worldScaleFactor(matrix);
|
|
44161
|
+
let title = "";
|
|
44162
|
+
const rows = [];
|
|
44163
|
+
let note = null;
|
|
44164
|
+
if (selectedVertex) {
|
|
44165
|
+
title = "Vertex";
|
|
44166
|
+
const world = localPointToWorld(selectedVertex.point, matrix);
|
|
44167
|
+
rows.push(["Coordinate", formatCoord(world, lengthUnit)]);
|
|
44168
|
+
rows.push(["X", formatLength(world[0], lengthUnit, 3), world[0]]);
|
|
44169
|
+
rows.push(["Y", formatLength(world[1], lengthUnit, 3), world[1]]);
|
|
44170
|
+
rows.push(["Z", formatLength(world[2], lengthUnit, 3), world[2]]);
|
|
44171
|
+
} else if (selectedEdge) {
|
|
44172
|
+
const { curve } = selectedEdge;
|
|
44173
|
+
if (curve.kind === "circle") {
|
|
44174
|
+
title = "Edge — Circle";
|
|
44175
|
+
const radius = curve.radius * scale;
|
|
44176
|
+
const center = localPointToWorld(curve.center, matrix);
|
|
44177
|
+
const axis = localDirToWorld(curve.axis, matrix);
|
|
44178
|
+
rows.push(["Radius", formatLength(radius, lengthUnit, 3), radius]);
|
|
44179
|
+
rows.push(["Diameter", formatLength(radius * 2, lengthUnit, 3), radius * 2]);
|
|
44180
|
+
rows.push(["Center", formatCoord(center, lengthUnit)]);
|
|
44181
|
+
rows.push(["Axis", vec3Label(axis)]);
|
|
44182
|
+
} else if (curve.kind === "line") {
|
|
44183
|
+
title = "Edge — Line";
|
|
44184
|
+
const start = localPointToWorld(curve.start, matrix);
|
|
44185
|
+
const end = localPointToWorld(curve.end, matrix);
|
|
44186
|
+
const dir = new Vector3(end[0] - start[0], end[1] - start[1], end[2] - start[2]).normalize();
|
|
44187
|
+
const length = selectedEdge.length * scale;
|
|
44188
|
+
rows.push(["Length", formatLength(length, lengthUnit, 3), length]);
|
|
44189
|
+
rows.push(["Direction", vec3Label([dir.x, dir.y, dir.z])]);
|
|
44190
|
+
rows.push(["Start", formatCoord(start, lengthUnit)]);
|
|
44191
|
+
rows.push(["End", formatCoord(end, lengthUnit)]);
|
|
44192
|
+
} else {
|
|
44193
|
+
title = "Edge — Non-analytic";
|
|
44194
|
+
const length = selectedEdge.length * scale;
|
|
44195
|
+
rows.push(["Length", formatLength(length, lengthUnit, 3), length]);
|
|
44196
|
+
note = "Non-analytic edge: length only (polyline). No analytic radius/axis.";
|
|
44197
|
+
}
|
|
44198
|
+
}
|
|
44199
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
44200
|
+
"div",
|
|
44201
|
+
{
|
|
44202
|
+
className: "fc-viewport-floating-panel fc-edge-info-panel",
|
|
44203
|
+
style: {
|
|
44204
|
+
position: "absolute",
|
|
44205
|
+
left: 16,
|
|
44206
|
+
bottom: 16,
|
|
44207
|
+
width: 248,
|
|
44208
|
+
background: "var(--fc-floating-panel-bg, var(--fc-bgPanel))",
|
|
44209
|
+
border: "1px solid var(--fc-floating-panel-border, var(--fc-border))",
|
|
44210
|
+
borderRadius: "var(--fc-floating-panel-radius, 8px)",
|
|
44211
|
+
boxShadow: "var(--fc-floating-panel-shadow, 0 12px 28px rgba(0, 0, 0, 0.28))",
|
|
44212
|
+
padding: 12,
|
|
44213
|
+
zIndex: 20,
|
|
44214
|
+
fontSize: 12,
|
|
44215
|
+
color: "var(--fc-text)"
|
|
44216
|
+
},
|
|
44217
|
+
onPointerDown: (e2) => e2.stopPropagation(),
|
|
44218
|
+
onContextMenu: (e2) => e2.preventDefault(),
|
|
44219
|
+
children: [
|
|
44220
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 8 }, children: [
|
|
44221
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { fontWeight: 600, fontSize: 13 }, children: title }),
|
|
44222
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
44223
|
+
"button",
|
|
44224
|
+
{
|
|
44225
|
+
type: "button",
|
|
44226
|
+
onClick: () => {
|
|
44227
|
+
setSelectedEdge(null);
|
|
44228
|
+
setSelectedVertex(null);
|
|
44229
|
+
},
|
|
44230
|
+
style: {
|
|
44231
|
+
border: "none",
|
|
44232
|
+
background: "transparent",
|
|
44233
|
+
color: "var(--fc-textMuted)",
|
|
44234
|
+
cursor: "pointer",
|
|
44235
|
+
fontSize: 16,
|
|
44236
|
+
lineHeight: 1,
|
|
44237
|
+
padding: 0
|
|
44238
|
+
},
|
|
44239
|
+
children: "×"
|
|
44240
|
+
}
|
|
44241
|
+
)
|
|
44242
|
+
] }),
|
|
44243
|
+
obj && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
44244
|
+
"div",
|
|
44245
|
+
{
|
|
44246
|
+
style: {
|
|
44247
|
+
fontSize: 11,
|
|
44248
|
+
color: "var(--fc-textMuted)",
|
|
44249
|
+
marginBottom: 8,
|
|
44250
|
+
overflow: "hidden",
|
|
44251
|
+
textOverflow: "ellipsis",
|
|
44252
|
+
whiteSpace: "nowrap"
|
|
44253
|
+
},
|
|
44254
|
+
children: obj.treePath && obj.treePath.length > 0 ? obj.treePath.join(" / ") : obj.name
|
|
44255
|
+
}
|
|
44256
|
+
),
|
|
44257
|
+
rows.map(([label, value, raw]) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
44258
|
+
"div",
|
|
44259
|
+
{
|
|
44260
|
+
style: { display: "flex", justifyContent: "space-between", alignItems: "baseline", gap: 8, marginBottom: 5 },
|
|
44261
|
+
children: [
|
|
44262
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: "var(--fc-textMuted)", fontSize: 11 }, children: label }),
|
|
44263
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { style: { display: "flex", alignItems: "baseline", gap: 6, minWidth: 0 }, children: [
|
|
44264
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { fontFamily: "monospace", fontSize: 11, textAlign: "right", wordBreak: "break-word" }, children: value }),
|
|
44265
|
+
raw !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
44266
|
+
"button",
|
|
44267
|
+
{
|
|
44268
|
+
type: "button",
|
|
44269
|
+
title: `Copy ${label.toLowerCase()} value (${panelNumber(raw)} mm) to clipboard`,
|
|
44270
|
+
onClick: () => copyNumberToClipboard(raw),
|
|
44271
|
+
style: {
|
|
44272
|
+
flexShrink: 0,
|
|
44273
|
+
border: "1px solid var(--fc-border)",
|
|
44274
|
+
background: "transparent",
|
|
44275
|
+
color: "var(--fc-textMuted)",
|
|
44276
|
+
cursor: "pointer",
|
|
44277
|
+
fontSize: 9,
|
|
44278
|
+
lineHeight: 1,
|
|
44279
|
+
borderRadius: 3,
|
|
44280
|
+
padding: "2px 4px"
|
|
44281
|
+
},
|
|
44282
|
+
children: "Copy"
|
|
44283
|
+
}
|
|
44284
|
+
)
|
|
44285
|
+
] })
|
|
44286
|
+
]
|
|
44287
|
+
},
|
|
44288
|
+
label
|
|
44289
|
+
)),
|
|
44290
|
+
note && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
44291
|
+
"div",
|
|
44292
|
+
{
|
|
44293
|
+
style: {
|
|
44294
|
+
marginTop: 6,
|
|
44295
|
+
paddingTop: 6,
|
|
44296
|
+
borderTop: "1px solid var(--fc-border)",
|
|
44297
|
+
fontSize: 10,
|
|
44298
|
+
color: "var(--fc-textMuted)",
|
|
44299
|
+
lineHeight: 1.35
|
|
44300
|
+
},
|
|
44301
|
+
children: note
|
|
44302
|
+
}
|
|
44303
|
+
)
|
|
44304
|
+
]
|
|
44305
|
+
}
|
|
44306
|
+
);
|
|
43492
44307
|
})()
|
|
43493
44308
|
]
|
|
43494
44309
|
}
|
|
43495
44310
|
);
|
|
43496
44311
|
}
|
|
43497
|
-
const EditorApp$1 = reactExports.lazy(() => __vitePreload(() => import("./EditorApp-
|
|
44312
|
+
const EditorApp$1 = reactExports.lazy(() => __vitePreload(() => import("./EditorApp-DQJmcmRT.js"), true ? __vite__mapDeps([0]) : void 0).then((m2) => ({ default: m2.EditorApp })));
|
|
43498
44313
|
const PENDING_SHARE_COPY_KEY = "fc-pending-share-copy";
|
|
43499
44314
|
function storePendingShareCopy(shareId) {
|
|
43500
44315
|
sessionStorage.setItem(PENDING_SHARE_COPY_KEY, shareId);
|
|
@@ -43760,17 +44575,17 @@ function SeoMetadata() {
|
|
|
43760
44575
|
}, [location.pathname]);
|
|
43761
44576
|
return null;
|
|
43762
44577
|
}
|
|
43763
|
-
reactExports.lazy(() => __vitePreload(() => import("./LandingPageProofDriven-
|
|
43764
|
-
const DocsPage = reactExports.lazy(() => __vitePreload(() => import("./DocsPage-
|
|
43765
|
-
reactExports.lazy(() => __vitePreload(() => import("./BlogPage-
|
|
43766
|
-
reactExports.lazy(() => __vitePreload(() => import("./BenchmarkPage-
|
|
43767
|
-
reactExports.lazy(() => __vitePreload(() => import("./AdminPage-
|
|
44578
|
+
reactExports.lazy(() => __vitePreload(() => import("./LandingPageProofDriven-DbE_tp8-.js"), true ? __vite__mapDeps([1]) : void 0).then((m2) => ({ default: m2.LandingPageProofDriven })));
|
|
44579
|
+
const DocsPage = reactExports.lazy(() => __vitePreload(() => import("./DocsPage-DO1kvBns.js"), true ? [] : void 0).then((m2) => ({ default: m2.DocsPage })));
|
|
44580
|
+
reactExports.lazy(() => __vitePreload(() => import("./BlogPage-D7Dos-vl.js"), true ? [] : void 0).then((m2) => ({ default: m2.BlogPage })));
|
|
44581
|
+
reactExports.lazy(() => __vitePreload(() => import("./BenchmarkPage-DP3RxhPs.js"), true ? __vite__mapDeps([1,2]) : void 0).then((m2) => ({ default: m2.BenchmarkPage })));
|
|
44582
|
+
reactExports.lazy(() => __vitePreload(() => import("./AdminPage-raksfnNA.js"), true ? [] : void 0).then((m2) => ({ default: m2.AdminPage })));
|
|
43768
44583
|
reactExports.lazy(() => __vitePreload(() => Promise.resolve().then(() => PublishedModelPage$1), true ? void 0 : void 0).then((m2) => ({ default: m2.PublishedModelPage })));
|
|
43769
|
-
reactExports.lazy(() => __vitePreload(() => import("./SettingsPage-
|
|
43770
|
-
reactExports.lazy(() => __vitePreload(() => import("./PricingPage-
|
|
43771
|
-
reactExports.lazy(() => __vitePreload(() => import("./LegalPage-
|
|
43772
|
-
const EditorApp = reactExports.lazy(() => __vitePreload(() => import("./EditorApp-
|
|
43773
|
-
const EmbedViewer = reactExports.lazy(() => __vitePreload(() => import("./EmbedViewer-
|
|
44584
|
+
reactExports.lazy(() => __vitePreload(() => import("./SettingsPage-DLWcP289.js"), true ? [] : void 0).then((m2) => ({ default: m2.SettingsPage })));
|
|
44585
|
+
reactExports.lazy(() => __vitePreload(() => import("./PricingPage-CcVIN9yj.js"), true ? __vite__mapDeps([1,3]) : void 0).then((m2) => ({ default: m2.PricingPage })));
|
|
44586
|
+
reactExports.lazy(() => __vitePreload(() => import("./LegalPage-CominSso.js"), true ? __vite__mapDeps([1,4]) : void 0).then((m2) => ({ default: m2.LegalPage })));
|
|
44587
|
+
const EditorApp = reactExports.lazy(() => __vitePreload(() => import("./EditorApp-DQJmcmRT.js"), true ? __vite__mapDeps([0]) : void 0).then((m2) => ({ default: m2.EditorApp })));
|
|
44588
|
+
const EmbedViewer = reactExports.lazy(() => __vitePreload(() => import("./EmbedViewer-DFDUhOma.js"), true ? [] : void 0).then((m2) => ({ default: m2.EmbedViewer })));
|
|
43774
44589
|
const embedMode = isEmbedMode() && !window.location.pathname.startsWith("/m/");
|
|
43775
44590
|
const EDITABLE_CRASH_FILE = /\.(?:forge\.js|[cm]?[jt]sx?|json|md|txt|svg|dxf)$/i;
|
|
43776
44591
|
function firstMeaningfulLine(text) {
|