forgecad 0.9.15 → 0.9.16
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-CDyGUinA.js → AdminPage-CXvls4-J.js} +1 -1
- package/dist/assets/{BenchmarkPage-DfPMY_-d.js → BenchmarkPage-B27zk8xL.js} +1 -1
- package/dist/assets/{BlogPage-kF0fkdJT.js → BlogPage-CMAVvgQL.js} +1 -1
- package/dist/assets/{DocsPage-B954L3YN.js → DocsPage-knf4I4h7.js} +1 -1
- package/dist/assets/EditorApp-BHMQlJ-D.js +14686 -0
- package/dist/assets/{EditorApp-CuDLxKqL.css → EditorApp-BpjZgzk0.css} +148 -0
- package/dist/assets/{EmbedViewer-C77B-TrF.js → EmbedViewer-D7ZGlFjx.js} +2 -2
- package/dist/assets/{LandingPageProofDriven-Cr6fXMDj.js → LandingPageProofDriven-CnevhTE8.js} +2 -2
- package/dist/assets/{LegalPage-Dzklqmmg.js → LegalPage-BPTUmqeg.js} +1 -1
- package/dist/assets/{PricingPage-zWXkvlwl.js → PricingPage-B0D4goG_.js} +1 -1
- package/dist/assets/{SettingsPage-Bz0of4KQ.js → SettingsPage-CFF-UgjI.js} +1 -1
- package/dist/assets/{app-D3kDkggg.js → app-T0pDcSX4.js} +1184 -218
- package/dist/assets/cli/{render-DSY3mMQa.js → render-C5pcIISc.js} +144 -26
- package/dist/assets/{constructionHistoryWorker-gpDo-uH2.js → constructionHistoryWorker-Ba2Hm58b.js} +1 -0
- package/dist/assets/{evalWorker-CU0Ke6DP.js → evalWorker-vkx310U2.js} +1380 -2173
- package/dist/assets/{inspectWorker-COyp8XXA.js → inspectWorker-BuTJDVX6.js} +252 -30
- package/dist/assets/{targets-B9sGB5nB.js → jointPose-B_Cgedn9.js} +71 -3
- package/dist/assets/{manifold-DNkrUWpA.js → manifold-BWgsjmAM.js} +1 -1
- package/dist/assets/{manifold-C-3h2M7p.js → manifold-D6IFSkhH.js} +2 -2
- package/dist/assets/{manifold-BRI5prcH.js → manifold-rZexZI0G.js} +1 -1
- package/dist/assets/{reportWorker-CdBz5bNg.js → reportWorker-0AGij1Ru.js} +1373 -2166
- package/dist/assets/{scalar-sampling-budget-wJF98aY9.js → scalar-sampling-budget-J5cuzxT1.js} +1494 -2251
- package/dist/assets/{scanProxyWorker-B-9VbLIs.js → scanProxyWorker-Vl4Wxa1y.js} +18 -5
- package/dist/cli/render.html +1 -1
- package/dist/docs/index.html +1 -1
- package/dist/docs-raw/AI/usage.md +2 -0
- package/dist/docs-raw/CLI.md +4 -0
- package/dist/docs-raw/generated/assembly.md +104 -6
- package/dist/docs-raw/generated/concepts.md +14 -4
- package/dist/docs-raw/generated/lib.md +2 -18
- package/dist/docs-raw/generated/output.md +14 -4
- package/dist/docs-raw/generated/runtime-names.md +27 -19
- package/dist/docs-raw/skills/forgecad-make-a-model.md +39 -38
- package/dist/docs-raw/skills/forgecad-project.md +2 -0
- package/dist/docs-raw/welcome.md +2 -0
- package/dist/index.html +1 -1
- package/dist/sitemap.xml +13 -13
- package/dist-cli/{check-compiler-SDX5QIXI.js → check-compiler-SYQ2PWOB.js} +1 -1
- package/dist-cli/{check-query-propagation-EAYEFT77.js → check-query-propagation-HIAGV62W.js} +1 -1
- package/dist-cli/{chunk-N4O47JLF.js → chunk-SPZE3DUY.js} +1591 -2356
- package/dist-cli/forgecad.js +1698 -487
- package/dist-skill/CONTEXT.md +117 -46
- package/dist-skill/docs/CLI.md +4 -0
- package/dist-skill/docs/generated/assembly.md +83 -5
- package/dist-skill/docs/generated/lib.md +2 -18
- package/dist-skill/docs/generated/output.md +14 -4
- package/dist-skill/docs/generated/runtime-names.md +18 -19
- package/dist-skill/library/forgecad-make-a-model/SKILL.md +39 -38
- package/dist-skill/library/forgecad-project/SKILL.md +2 -0
- package/examples/api/helix-basics.forge.js +2 -2
- package/examples/api/route3d-elbow.forge.js +3 -0
- package/examples/api/variable-sweep-test.forge.js +3 -1
- package/package.json +4 -1
- package/dist/assets/EditorApp-Beb-IZ0y.js +0 -14014
- package/examples/api/bolted-service-cover.forge.js +0 -17
- package/examples/api/cable-gland-anchor.forge.js +0 -14
- package/examples/api/captured-cartridge-guide.forge.js +0 -14
- package/examples/api/captured-linear-slide.forge.js +0 -13
- package/examples/api/clevis-pin-joint.forge.js +0 -13
- package/examples/api/datum-enclosure.forge.js +0 -16
- package/examples/api/hose-barb-port.forge.js +0 -14
- package/examples/api/knuckled-hinge-assembly.forge.js +0 -15
- package/examples/api/living-hinge-cover.forge.js +0 -14
- package/examples/api/pcb-terminal-block.forge.js +0 -22
- package/examples/api/pinned-lever-pivot-stack.forge.js +0 -14
- package/examples/api/retained-shaft-knob-stack.forge.js +0 -15
- package/examples/api/routed-tube-clip.forge.js +0 -15
- package/examples/api/seated-bearing-stack.forge.js +0 -30
- package/examples/api/snap-latch-cover.forge.js +0 -14
- package/examples/api/thumb-screw-clamp.forge.js +0 -15
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/EditorApp-
|
|
1
|
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/EditorApp-BpjZgzk0.css","assets/landing-proof-driven-ORyigZ6p.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, z as zipSync, s as strToU8, W as WebGLRenderer, R as Raycaster, O as OrthographicCamera$1, P as PerspectiveCamera$1, S as Scene, a as PCFSoftShadowMap, V as VSMShadowMap, b as PCFShadowMap, B as BasicShadowMap, C as ColorManagement, L as LinearSRGBColorSpace, c as SRGBColorSpace, N as NoToneMapping, A as ACESFilmicToneMapping, d as Layers, e as Color, f as RGBAFormat, U as UnsignedByteType, g as Vector3, h as Vector2, i as Clock, T as THREE, D as DoubleSide, j as REVISION, M as Mesh, I as IcosahedronGeometry, k as ShaderMaterial, l as Spherical, Q as Quaternion, m as MOUSE, n as TOUCH, o as Ray, p as Plane, q as DataTextureLoader, H as HalfFloatType, F as FloatType, r as DataUtils, t as LinearFilter, u as RedFormat, v as InstancedBufferGeometry, w as Float32BufferAttribute, x as InstancedInterleavedBuffer, y as InterleavedBufferAttribute, E as WireframeGeometry, G as Box3, J as Sphere, K as UniformsUtils, X as UniformsLib, Y as Vector4, Z as Line3, $ as Matrix4, a0 as MathUtils, a1 as Uniform, a2 as WebGLRenderTarget, a3 as DepthTexture, a4 as BackSide, a5 as ClampToEdgeWrapping, a6 as PlaneGeometry, a7 as UVMapping, a8 as DataTexture, a9 as Texture, aa as MeshBasicMaterial, ab as IntType, ac as ShortType, ad as ByteType, ae as UnsignedIntType, af as Loader, ag as LoadingManager, ah as LinearMipMapLinearFilter, ai as FileLoader, aj as NoBlending, ak as CubeReflectionMapping, al as EquirectangularReflectionMapping, am as CubeTextureLoader, an as WebGLCubeRenderTarget, ao as ConstraintSketch, ap as setSketchPlacement3D, aq as Sketch, ar as PROFILE_BACKEND_MARKER, as as FrozenShape, at as setShapeCompilePlan, au as hasAnyPorts, av as setShapePortsInternal, aw as markShapePortsUsed, ax as setParamOverrides, ay as resolveForgeRenderStyle, az as DEFAULT_ACTIVE_BACKEND, aA as isConstraintSketch, aB as updateConstraintValue, aC as linearizeMultiObjectSteps, aD as getShapeCompilePlan, aE as SCAN_PROXY_GRANULARITY_DEFAULT, aF as publishSolverWasmRunDebug, aG as resolveForgeQualityPreset, aH as SCAN_PROXY_MATRIX_GRANULARITY_MAX, aI as findJointAnimationClip, aJ as resolveJointAnimation, aK as resolveJointViewValues, aL as resolveImportPath, aM as resolveScanProxyGranularity, aN as BufferGeometry, aO as LineBasicMaterial, aP as Line$1, aQ as LineDashedMaterial, aR as DepthStencilFormat, aS as UnsignedInt248Type, aT as MeshNormalMaterial, aU as NearestFilter, aV as BasicDepthPacking, aW as EventDispatcher$1, aX as NoColorSpace, aY as FrontSide, aZ as Material, a_ as AlwaysDepth, a$ as BufferAttribute, b0 as CanvasTexture, b1 as Object3D, b2 as FogExp2, b3 as Fog, b4 as AmbientLight, b5 as HemisphereLight, b6 as SpotLight, b7 as PointLight, b8 as DirectionalLight, b9 as heatPointsForSide, ba as COMPARISON_COLORS, bb as comparisonHeatDepthTest, bc as comparisonHeatEdgeOpacity, bd as comparisonHeatPatchOpacity, be as shapeToGeometry, bf as buildComparisonHeatPatchGeometry, bg as EdgesGeometry, bh as buildShapeFromCompilePlan, bi as buildVisibleHistoryStacks, bj as sketchToSvg, bk as sketchToDxf, bl as runScript, bm as MeshPhysicalMaterial, bn as LineSegments, bo as findDesignTraceNodeForConstructionStep, bp as formatDesignTraceAnchor, bq as waitForAnimationFrame, br as selectBuildLedgerNodes, bs as worldAuthorPlaneToLocal, bt as scanProxySourceBytes, bu as disposeScanProxyGeometry, bv as scanProxyGeometryFromPayload, bw as AdditiveBlending, bx as geometryWithVisibleVertexColors, by as getRenderStylePreset, bz as SCAN_RENDER_COLORS, bA as NormalBlending, bB as ZEBRA_STRIPE_SOFTNESS, bC as ZEBRA_STRIPE_SCALE, bD as ZEBRA_LIGHT_COLOR, bE as ZEBRA_DARK_COLOR, bF as ZEBRA_ACCENT_COLOR, bG as ZEBRA_STRIPE_FRAGMENT_SHADER, bH as ZEBRA_STRIPE_VERTEX_SHADER, bI as SCAN_PROXY_LAYER_STYLES, bJ as SURFACE_FIELD_FRAGMENT_SHADER, bK as SURFACE_FIELD_VERTEX_SHADER, bL as WORLD_UP, bM as CatmullRomCurve3, bN as TubeGeometry, bO as
|
|
7
|
+
import { _ as __vitePreload, z as zipSync, s as strToU8, W as WebGLRenderer, R as Raycaster, O as OrthographicCamera$1, P as PerspectiveCamera$1, S as Scene, a as PCFSoftShadowMap, V as VSMShadowMap, b as PCFShadowMap, B as BasicShadowMap, C as ColorManagement, L as LinearSRGBColorSpace, c as SRGBColorSpace, N as NoToneMapping, A as ACESFilmicToneMapping, d as Layers, e as Color, f as RGBAFormat, U as UnsignedByteType, g as Vector3, h as Vector2, i as Clock, T as THREE, D as DoubleSide, j as REVISION, M as Mesh, I as IcosahedronGeometry, k as ShaderMaterial, l as Spherical, Q as Quaternion, m as MOUSE, n as TOUCH, o as Ray, p as Plane, q as DataTextureLoader, H as HalfFloatType, F as FloatType, r as DataUtils, t as LinearFilter, u as RedFormat, v as InstancedBufferGeometry, w as Float32BufferAttribute, x as InstancedInterleavedBuffer, y as InterleavedBufferAttribute, E as WireframeGeometry, G as Box3, J as Sphere, K as UniformsUtils, X as UniformsLib, Y as Vector4, Z as Line3, $ as Matrix4, a0 as MathUtils, a1 as Uniform, a2 as WebGLRenderTarget, a3 as DepthTexture, a4 as BackSide, a5 as ClampToEdgeWrapping, a6 as PlaneGeometry, a7 as UVMapping, a8 as DataTexture, a9 as Texture, aa as MeshBasicMaterial, ab as IntType, ac as ShortType, ad as ByteType, ae as UnsignedIntType, af as Loader, ag as LoadingManager, ah as LinearMipMapLinearFilter, ai as FileLoader, aj as NoBlending, ak as CubeReflectionMapping, al as EquirectangularReflectionMapping, am as CubeTextureLoader, an as WebGLCubeRenderTarget, ao as ConstraintSketch, ap as setSketchPlacement3D, aq as Sketch, ar as PROFILE_BACKEND_MARKER, as as FrozenShape, at as setShapeCompilePlan, au as hasAnyPorts, av as setShapePortsInternal, aw as markShapePortsUsed, ax as setParamOverrides, ay as resolveForgeRenderStyle, az as DEFAULT_ACTIVE_BACKEND, aA as isConstraintSketch, aB as updateConstraintValue, aC as linearizeMultiObjectSteps, aD as getShapeCompilePlan, aE as SCAN_PROXY_GRANULARITY_DEFAULT, aF as publishSolverWasmRunDebug, aG as resolveForgeQualityPreset, aH as SCAN_PROXY_MATRIX_GRANULARITY_MAX, aI as findJointAnimationClip, aJ as resolveJointAnimation, aK as resolveJointViewValues, aL as resolveImportPath, aM as resolveScanProxyGranularity, aN as BufferGeometry, aO as LineBasicMaterial, aP as Line$1, aQ as LineDashedMaterial, aR as DepthStencilFormat, aS as UnsignedInt248Type, aT as MeshNormalMaterial, aU as NearestFilter, aV as BasicDepthPacking, aW as EventDispatcher$1, aX as NoColorSpace, aY as FrontSide, aZ as Material, a_ as AlwaysDepth, a$ as BufferAttribute, b0 as CanvasTexture, b1 as Object3D, b2 as FogExp2, b3 as Fog, b4 as AmbientLight, b5 as HemisphereLight, b6 as SpotLight, b7 as PointLight, b8 as DirectionalLight, b9 as heatPointsForSide, ba as COMPARISON_COLORS, bb as comparisonHeatDepthTest, bc as comparisonHeatEdgeOpacity, bd as comparisonHeatPatchOpacity, be as shapeToGeometry, bf as buildComparisonHeatPatchGeometry, bg as EdgesGeometry, bh as buildShapeFromCompilePlan, bi as buildVisibleHistoryStacks, bj as sketchToSvg, bk as sketchToDxf, bl as runScript, bm as MeshPhysicalMaterial, bn as LineSegments, bo as findDesignTraceNodeForConstructionStep, bp as formatDesignTraceAnchor, bq as waitForAnimationFrame, br as selectBuildLedgerNodes, bs as worldAuthorPlaneToLocal, bt as scanProxySourceBytes, bu as disposeScanProxyGeometry, bv as scanProxyGeometryFromPayload, bw as AdditiveBlending, bx as geometryWithVisibleVertexColors, by as getRenderStylePreset, bz as SCAN_RENDER_COLORS, bA as NormalBlending, bB as ZEBRA_STRIPE_SOFTNESS, bC as ZEBRA_STRIPE_SCALE, bD as ZEBRA_LIGHT_COLOR, bE as ZEBRA_DARK_COLOR, bF as ZEBRA_ACCENT_COLOR, bG as ZEBRA_STRIPE_FRAGMENT_SHADER, bH as ZEBRA_STRIPE_VERTEX_SHADER, bI as SCAN_PROXY_LAYER_STYLES, bJ as SURFACE_FIELD_FRAGMENT_SHADER, bK as SURFACE_FIELD_VERTEX_SHADER, bL as WORLD_UP, bM as CatmullRomCurve3, bN as TubeGeometry, bO as THICKNESS_GRADIENT_COLORS, bP as ROUGHNESS_COLORS, bQ as DEFAULT_ROUGHNESS_INSPECTION_OPTIONS, bR as PERFORMANCE_SAMPLE_INTERVAL_SEC, bS as formatPerformanceCount, bT as NON_TEXT_INPUT_TYPES, bU as MeshStandardMaterial, bV as compileSdfNode3, bW as buildSdfRaymarchFragmentShader, bX as SDF_RAYMARCH_PROXY_VERTEX_SHADER, bY as Shape, bZ as ShapeGeometry, b_ as ShaderLib, b$ as CylinderGeometry, c0 as VIEWPORT_CAMERA_STORAGE_KEY, c1 as parseViewportCameraState, c2 as createResolvedExplodeConfig, c3 as explodeBoundsCenter, c4 as explodeMergeBounds, c5 as resolveExplodeDirective, c6 as computeExplodeMotion, c7 as getSketchWorldMatrix, c8 as explodeAdd, c9 as hasExplodeOverride, ca as resolveExplodeLocalFanDirection, cb as explodeMul, cc as explodeLeafFanStage, cd as normalizeCutPlane, ce as toClippingPlane, cf as isObjectExcludedFromCutPlane, cg as getShapePorts, ch as getShapeUsedPorts, ci as DEFAULT_VIEW_CONFIG, cj as SECTION_EXPLORER_PLANE_NAME, ck as ZERO_OFFSET, cl as scanProxyGridForBounds, cm as IDENTITY_MATRIX$2, cn as OBJECT_CONTEXT_MENU_MARGIN, co as OBJECT_CONTEXT_MENU_WIDTH, cp as OBJECT_CONTEXT_MENU_HEIGHT, cq as getKernelFaceNameForTriangle, 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 FOCUS_MODE_DIM_OPACITY, cz as comparisonCandidateContextOpacity, cA as Matrix3, cB as initKernel, cC as initSolverWasm } from "./scalar-sampling-budget-J5cuzxT1.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];
|
|
@@ -39,7 +39,15 @@ async function doFetch(url2, init) {
|
|
|
39
39
|
credentials: "include",
|
|
40
40
|
headers: { ...headers, ...init == null ? void 0 : init.headers }
|
|
41
41
|
});
|
|
42
|
-
const
|
|
42
|
+
const text = await res.text();
|
|
43
|
+
let body = {};
|
|
44
|
+
if (text.trim().length > 0) {
|
|
45
|
+
try {
|
|
46
|
+
body = JSON.parse(text);
|
|
47
|
+
} catch {
|
|
48
|
+
body = { error: text };
|
|
49
|
+
}
|
|
50
|
+
}
|
|
43
51
|
return { res, body };
|
|
44
52
|
}
|
|
45
53
|
async function authFetch(url2, init) {
|
|
@@ -14721,6 +14729,7 @@ const MOUSE_BUTTONS_DRAW = {
|
|
|
14721
14729
|
MIDDLE: MOUSE.PAN,
|
|
14722
14730
|
RIGHT: MOUSE.PAN
|
|
14723
14731
|
};
|
|
14732
|
+
const MOUSE_BUTTONS_VOXEL = MOUSE_BUTTONS_3D;
|
|
14724
14733
|
const dark = {
|
|
14725
14734
|
bg: "#0d1117",
|
|
14726
14735
|
bgPanel: "#161b22",
|
|
@@ -15825,7 +15834,7 @@ const CRASH_COOLDOWN_MS = 2e3;
|
|
|
15825
15834
|
class EvalWorkerClient {
|
|
15826
15835
|
constructor(workerFactory = () => new Worker(new URL(
|
|
15827
15836
|
/* @vite-ignore */
|
|
15828
|
-
"/assets/evalWorker-
|
|
15837
|
+
"/assets/evalWorker-vkx310U2.js",
|
|
15829
15838
|
import.meta.url
|
|
15830
15839
|
), { type: "module" })) {
|
|
15831
15840
|
__publicField(this, "worker", null);
|
|
@@ -17208,6 +17217,13 @@ const DEFAULT_INSPECT_POINT_SAMPLE_COUNT = 2e3;
|
|
|
17208
17217
|
const DEFAULT_COMPARISON_INSPECT_MODE = "difference-only";
|
|
17209
17218
|
const DEFAULT_COMPARISON_CANDIDATE_OPACITY = 0.42;
|
|
17210
17219
|
const DEFAULT_COMPARISON_REFERENCE_OPACITY = 0.2;
|
|
17220
|
+
const THICKNESS_COLOR_RANGE_MIN = 0;
|
|
17221
|
+
const THICKNESS_COLOR_RANGE_MAX = 1e3;
|
|
17222
|
+
const THICKNESS_COLOR_RANGE_MIN_SPAN = 1e-3;
|
|
17223
|
+
const DEFAULT_THICKNESS_COLOR_RANGE = {
|
|
17224
|
+
min: 0,
|
|
17225
|
+
max: 6
|
|
17226
|
+
};
|
|
17211
17227
|
const DEFAULT_MANUAL_SCENE_SETTINGS = {
|
|
17212
17228
|
enabled: false,
|
|
17213
17229
|
backgroundColor: "#f6f7f8",
|
|
@@ -17235,6 +17251,31 @@ const resolveClampedNumber = (value, fallback, min, max2) => {
|
|
|
17235
17251
|
return Math.max(min, Math.min(max2, numeric));
|
|
17236
17252
|
};
|
|
17237
17253
|
const resolveComparisonOpacity = (value, fallback) => resolveClampedNumber(value, fallback, 0, 1);
|
|
17254
|
+
const resolveThicknessColorRange = (value) => {
|
|
17255
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
17256
|
+
return DEFAULT_THICKNESS_COLOR_RANGE;
|
|
17257
|
+
}
|
|
17258
|
+
const raw = value;
|
|
17259
|
+
const min = resolveClampedNumber(
|
|
17260
|
+
raw.min,
|
|
17261
|
+
DEFAULT_THICKNESS_COLOR_RANGE.min,
|
|
17262
|
+
THICKNESS_COLOR_RANGE_MIN,
|
|
17263
|
+
THICKNESS_COLOR_RANGE_MAX
|
|
17264
|
+
);
|
|
17265
|
+
const max2 = resolveClampedNumber(
|
|
17266
|
+
raw.max,
|
|
17267
|
+
DEFAULT_THICKNESS_COLOR_RANGE.max,
|
|
17268
|
+
THICKNESS_COLOR_RANGE_MIN,
|
|
17269
|
+
THICKNESS_COLOR_RANGE_MAX
|
|
17270
|
+
);
|
|
17271
|
+
if (max2 - min >= THICKNESS_COLOR_RANGE_MIN_SPAN) return { min, max: max2 };
|
|
17272
|
+
const defaultSpan = DEFAULT_THICKNESS_COLOR_RANGE.max - DEFAULT_THICKNESS_COLOR_RANGE.min;
|
|
17273
|
+
const expandedMax = Math.min(THICKNESS_COLOR_RANGE_MAX, min + defaultSpan);
|
|
17274
|
+
if (expandedMax - min >= THICKNESS_COLOR_RANGE_MIN_SPAN) return { min, max: expandedMax };
|
|
17275
|
+
const expandedMin = Math.max(THICKNESS_COLOR_RANGE_MIN, max2 - defaultSpan);
|
|
17276
|
+
if (max2 - expandedMin >= THICKNESS_COLOR_RANGE_MIN_SPAN) return { min: expandedMin, max: max2 };
|
|
17277
|
+
return DEFAULT_THICKNESS_COLOR_RANGE;
|
|
17278
|
+
};
|
|
17238
17279
|
const resolveManualSceneSettings = (value) => {
|
|
17239
17280
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
17240
17281
|
return DEFAULT_MANUAL_SCENE_SETTINGS;
|
|
@@ -17411,8 +17452,17 @@ function resolveInitialViewInspectChannel(value) {
|
|
|
17411
17452
|
function resolveInspectDisplayMode(value) {
|
|
17412
17453
|
return typeof value === "string" && INSPECT_DISPLAY_MODES.has(value) ? value : "heatmap";
|
|
17413
17454
|
}
|
|
17455
|
+
function isScalarInspectChannel(channel) {
|
|
17456
|
+
return channel === "thickness" || channel === "roughness";
|
|
17457
|
+
}
|
|
17458
|
+
function shouldUseScanRenderStyle(channel, displayMode) {
|
|
17459
|
+
return isScalarInspectChannel(channel) && displayMode === "scan";
|
|
17460
|
+
}
|
|
17414
17461
|
const initialViewPreferences = readViewPreferences();
|
|
17415
|
-
const
|
|
17462
|
+
const initialInspectChannel = resolveInitialViewInspectChannel(initialViewPreferences.inspectChannel);
|
|
17463
|
+
const initialInspectDisplayMode = resolveInspectDisplayMode(initialViewPreferences.inspectDisplayMode);
|
|
17464
|
+
const initialStoredRenderStyle = resolveForgeRenderStyle(initialViewPreferences.renderStyle);
|
|
17465
|
+
const initialRenderStyle = shouldUseScanRenderStyle(initialInspectChannel, initialInspectDisplayMode) ? "scan" : initialStoredRenderStyle;
|
|
17416
17466
|
const resolveFiniteNumber = (value, fallback) => {
|
|
17417
17467
|
const numeric = typeof value === "number" ? value : Number(value);
|
|
17418
17468
|
return Number.isFinite(numeric) ? numeric : fallback;
|
|
@@ -18254,6 +18304,19 @@ const useForgeStore = create((set, get) => ({
|
|
|
18254
18304
|
});
|
|
18255
18305
|
if (isAssemblyDrivenResult(state2.lastValidResult)) void get().updateAssemblyPose();
|
|
18256
18306
|
},
|
|
18307
|
+
resetJointValues: () => {
|
|
18308
|
+
const state2 = get();
|
|
18309
|
+
const hasPoseState = Object.keys(state2.jointValues).length > 0 || state2.jointAnimationClip !== null || state2.jointAnimationProgress !== 0 || state2.jointAnimationPlaying;
|
|
18310
|
+
if (!hasPoseState) return;
|
|
18311
|
+
const assemblyDriven = isAssemblyDrivenResult(state2.lastValidResult);
|
|
18312
|
+
set({
|
|
18313
|
+
jointValues: {},
|
|
18314
|
+
jointAnimationClip: null,
|
|
18315
|
+
jointAnimationProgress: 0,
|
|
18316
|
+
jointAnimationPlaying: false
|
|
18317
|
+
});
|
|
18318
|
+
if (assemblyDriven) void get().updateAssemblyPose();
|
|
18319
|
+
},
|
|
18257
18320
|
setJointAnimationClip: (name) => {
|
|
18258
18321
|
const assemblyDriven = isAssemblyDrivenResult(get().lastValidResult);
|
|
18259
18322
|
set((state2) => {
|
|
@@ -18347,17 +18410,31 @@ const useForgeStore = create((set, get) => ({
|
|
|
18347
18410
|
writeViewPreferences({ manualScene: DEFAULT_MANUAL_SCENE_SETTINGS });
|
|
18348
18411
|
set({ manualScene: DEFAULT_MANUAL_SCENE_SETTINGS });
|
|
18349
18412
|
},
|
|
18350
|
-
inspectChannel:
|
|
18413
|
+
inspectChannel: initialInspectChannel,
|
|
18351
18414
|
setInspectChannel: (channel) => {
|
|
18352
18415
|
const next = resolveViewInspectChannel(channel);
|
|
18353
|
-
|
|
18354
|
-
|
|
18416
|
+
set((state2) => {
|
|
18417
|
+
const renderStyle = shouldUseScanRenderStyle(next, state2.inspectDisplayMode) ? "scan" : state2.renderStyle;
|
|
18418
|
+
const scanGranularity = resolveViewportScanGranularity(state2.scanGranularity, renderStyle);
|
|
18419
|
+
writeViewPreferences({
|
|
18420
|
+
inspectChannel: next === "collisions" ? "none" : next,
|
|
18421
|
+
...renderStyle !== state2.renderStyle ? { renderStyle, scanGranularity } : {}
|
|
18422
|
+
});
|
|
18423
|
+
return { inspectChannel: next, renderStyle, scanGranularity };
|
|
18424
|
+
});
|
|
18355
18425
|
},
|
|
18356
|
-
inspectDisplayMode:
|
|
18426
|
+
inspectDisplayMode: initialInspectDisplayMode,
|
|
18357
18427
|
setInspectDisplayMode: (mode) => {
|
|
18358
18428
|
const next = resolveInspectDisplayMode(mode);
|
|
18359
|
-
|
|
18360
|
-
|
|
18429
|
+
set((state2) => {
|
|
18430
|
+
const renderStyle = shouldUseScanRenderStyle(state2.inspectChannel, next) ? "scan" : state2.renderStyle;
|
|
18431
|
+
const scanGranularity = resolveViewportScanGranularity(state2.scanGranularity, renderStyle);
|
|
18432
|
+
writeViewPreferences({
|
|
18433
|
+
inspectDisplayMode: next,
|
|
18434
|
+
...renderStyle !== state2.renderStyle ? { renderStyle, scanGranularity } : {}
|
|
18435
|
+
});
|
|
18436
|
+
return { inspectDisplayMode: next, renderStyle, scanGranularity };
|
|
18437
|
+
});
|
|
18361
18438
|
},
|
|
18362
18439
|
scanGranularity: resolveViewportScanGranularity(
|
|
18363
18440
|
initialViewPreferences.scanGranularity ?? SCAN_PROXY_GRANULARITY_DEFAULT,
|
|
@@ -18376,6 +18453,14 @@ const useForgeStore = create((set, get) => ({
|
|
|
18376
18453
|
writeViewPreferences({ inspectPointSampleCount: next });
|
|
18377
18454
|
set({ inspectPointSampleCount: next });
|
|
18378
18455
|
},
|
|
18456
|
+
thicknessColorRange: resolveThicknessColorRange(initialViewPreferences.thicknessColorRange),
|
|
18457
|
+
setThicknessColorRange: (range) => {
|
|
18458
|
+
set((state2) => {
|
|
18459
|
+
const next = resolveThicknessColorRange({ ...state2.thicknessColorRange, ...range });
|
|
18460
|
+
writeViewPreferences({ thicknessColorRange: next });
|
|
18461
|
+
return { thicknessColorRange: next };
|
|
18462
|
+
});
|
|
18463
|
+
},
|
|
18379
18464
|
comparisonInspectMode: resolveComparisonInspectMode(initialViewPreferences.comparisonInspectMode),
|
|
18380
18465
|
setComparisonInspectMode: (mode) => {
|
|
18381
18466
|
const next = resolveComparisonInspectMode(mode);
|
|
@@ -18763,7 +18848,7 @@ const useForgeStore = create((set, get) => ({
|
|
|
18763
18848
|
if (!next) {
|
|
18764
18849
|
return { measureMode: false, measureSelections: [], measurements: [] };
|
|
18765
18850
|
}
|
|
18766
|
-
return { measureMode: true };
|
|
18851
|
+
return { measureMode: true, voxelIntentMode: false };
|
|
18767
18852
|
});
|
|
18768
18853
|
},
|
|
18769
18854
|
measureSelections: [],
|
|
@@ -18797,6 +18882,73 @@ const useForgeStore = create((set, get) => ({
|
|
|
18797
18882
|
writeViewPreferences({ measureSnapPx: value });
|
|
18798
18883
|
set({ measureSnapPx: value });
|
|
18799
18884
|
},
|
|
18885
|
+
voxelIntentMode: false,
|
|
18886
|
+
toggleVoxelIntentMode: () => set((s) => {
|
|
18887
|
+
const next = !s.voxelIntentMode;
|
|
18888
|
+
if (!next) return { voxelIntentMode: false };
|
|
18889
|
+
return {
|
|
18890
|
+
voxelIntentMode: true,
|
|
18891
|
+
measureMode: false,
|
|
18892
|
+
measureSelections: [],
|
|
18893
|
+
measurements: [],
|
|
18894
|
+
constructionGhost: null
|
|
18895
|
+
};
|
|
18896
|
+
}),
|
|
18897
|
+
setVoxelIntentMode: (enabled) => set(
|
|
18898
|
+
() => enabled ? {
|
|
18899
|
+
voxelIntentMode: true,
|
|
18900
|
+
measureMode: false,
|
|
18901
|
+
measureSelections: [],
|
|
18902
|
+
measurements: [],
|
|
18903
|
+
constructionGhost: null
|
|
18904
|
+
} : { voxelIntentMode: false }
|
|
18905
|
+
),
|
|
18906
|
+
voxelIntentTool: "red",
|
|
18907
|
+
setVoxelIntentTool: (tool) => set({ voxelIntentTool: tool }),
|
|
18908
|
+
voxelIntentPlacement: "surface",
|
|
18909
|
+
setVoxelIntentPlacement: (placement) => set({ voxelIntentPlacement: placement }),
|
|
18910
|
+
voxelIntentCellSize: 10,
|
|
18911
|
+
setVoxelIntentCellSize: (cellSize) => set((s) => {
|
|
18912
|
+
if (Object.keys(s.voxelIntentBlocks).length > 0) return {};
|
|
18913
|
+
const nextCellSize = Math.max(1, Math.min(200, Number.isFinite(cellSize) ? Math.round(cellSize) : 10));
|
|
18914
|
+
return { voxelIntentCellSize: nextCellSize };
|
|
18915
|
+
}),
|
|
18916
|
+
voxelIntentCellSizePreviewVisible: false,
|
|
18917
|
+
setVoxelIntentCellSizePreviewVisible: (visible) => set({ voxelIntentCellSizePreviewVisible: visible }),
|
|
18918
|
+
voxelIntentGhostOpacity: 0.24,
|
|
18919
|
+
setVoxelIntentGhostOpacity: (opacity) => set({ voxelIntentGhostOpacity: Math.max(0.05, Math.min(0.75, opacity)) }),
|
|
18920
|
+
voxelIntentContextFile: null,
|
|
18921
|
+
setVoxelIntentContextFile: (filePath) => set((s) => {
|
|
18922
|
+
if (s.voxelIntentContextFile === filePath) return {};
|
|
18923
|
+
return {
|
|
18924
|
+
voxelIntentContextFile: filePath,
|
|
18925
|
+
voxelIntentBlocks: filePath ? s.voxelIntentBlocksByFile[filePath] ?? {} : {}
|
|
18926
|
+
};
|
|
18927
|
+
}),
|
|
18928
|
+
voxelIntentBlocksByFile: {},
|
|
18929
|
+
voxelIntentBlocks: {},
|
|
18930
|
+
setVoxelIntentBlock: (cell, block) => set((s) => {
|
|
18931
|
+
const key = `${cell.x},${cell.y},${cell.z}`;
|
|
18932
|
+
const voxelIntentBlocks = { ...s.voxelIntentBlocks, [key]: block };
|
|
18933
|
+
return {
|
|
18934
|
+
voxelIntentBlocks,
|
|
18935
|
+
voxelIntentBlocksByFile: s.voxelIntentContextFile ? { ...s.voxelIntentBlocksByFile, [s.voxelIntentContextFile]: voxelIntentBlocks } : s.voxelIntentBlocksByFile
|
|
18936
|
+
};
|
|
18937
|
+
}),
|
|
18938
|
+
eraseVoxelIntentBlock: (cell) => set((s) => {
|
|
18939
|
+
const key = `${cell.x},${cell.y},${cell.z}`;
|
|
18940
|
+
if (!(key in s.voxelIntentBlocks)) return {};
|
|
18941
|
+
const next = { ...s.voxelIntentBlocks };
|
|
18942
|
+
delete next[key];
|
|
18943
|
+
return {
|
|
18944
|
+
voxelIntentBlocks: next,
|
|
18945
|
+
voxelIntentBlocksByFile: s.voxelIntentContextFile ? { ...s.voxelIntentBlocksByFile, [s.voxelIntentContextFile]: next } : s.voxelIntentBlocksByFile
|
|
18946
|
+
};
|
|
18947
|
+
}),
|
|
18948
|
+
clearVoxelIntentBlocks: () => set((s) => ({
|
|
18949
|
+
voxelIntentBlocks: {},
|
|
18950
|
+
voxelIntentBlocksByFile: s.voxelIntentContextFile ? { ...s.voxelIntentBlocksByFile, [s.voxelIntentContextFile]: {} } : s.voxelIntentBlocksByFile
|
|
18951
|
+
})),
|
|
18800
18952
|
dimensionsVisible: initialViewPreferences.dimensionsVisible ?? true,
|
|
18801
18953
|
toggleDimensions: () => set((s) => {
|
|
18802
18954
|
const nextDimensionsVisible = !s.dimensionsVisible;
|
|
@@ -26998,12 +27150,15 @@ const COMPARISON_REFERENCE_COLOR = [32, 199, 255];
|
|
|
26998
27150
|
const COMPARISON_CONTEXT_COLOR = [174, 184, 194];
|
|
26999
27151
|
const SCAN_CONTEXT_COLOR = [19, 201, 255];
|
|
27000
27152
|
const SCAN_CONTEXT_EDGE_COLOR = [145, 231, 255];
|
|
27001
|
-
const SCAN_RISK_MID_COLOR = [255, 193, 77];
|
|
27002
|
-
const SCAN_RISK_HOT_COLOR = [255, 138, 31];
|
|
27003
27153
|
const FLOATING_HIGHLIGHT_COLOR = [255, 68, 16];
|
|
27004
27154
|
const FLOATING_CONTEXT_COLOR = [38, 49, 58];
|
|
27005
27155
|
const RIG_SHADOW_COLOR = [6, 10, 18];
|
|
27006
|
-
const RIG_LINK_COLOR = [
|
|
27156
|
+
const RIG_LINK_COLOR = [142, 106, 255];
|
|
27157
|
+
const RIG_KINEMATIC_LINK_COLOR = [255, 226, 106];
|
|
27158
|
+
const RIG_KINEMATIC_EDGE_COLOR = [20, 220, 255];
|
|
27159
|
+
const RIG_FIXED_LINK_COLOR = [240, 253, 255];
|
|
27160
|
+
const RIG_DERIVED_LINK_COLOR = [255, 76, 196];
|
|
27161
|
+
const RIG_CONTROL_LINK_COLOR = [255, 122, 26];
|
|
27007
27162
|
const RIG_PART_LINK_COLOR = [174, 255, 92];
|
|
27008
27163
|
const RIG_HIDDEN_LINK_COLOR = [116, 136, 148];
|
|
27009
27164
|
const COLLISION_PALETTE = [
|
|
@@ -27280,7 +27435,7 @@ function ConstructionGhostOverlay({ matrix }) {
|
|
|
27280
27435
|
class ConstructionHistoryWorkerClient {
|
|
27281
27436
|
constructor(workerFactory = () => new Worker(new URL(
|
|
27282
27437
|
/* @vite-ignore */
|
|
27283
|
-
"/assets/constructionHistoryWorker-
|
|
27438
|
+
"/assets/constructionHistoryWorker-Ba2Hm58b.js",
|
|
27284
27439
|
import.meta.url
|
|
27285
27440
|
), { type: "module" })) {
|
|
27286
27441
|
__publicField(this, "worker", null);
|
|
@@ -29664,7 +29819,7 @@ function generateReportInWorker(options) {
|
|
|
29664
29819
|
return new Promise((resolve2, reject) => {
|
|
29665
29820
|
const worker = new Worker(new URL(
|
|
29666
29821
|
/* @vite-ignore */
|
|
29667
|
-
"/assets/reportWorker-
|
|
29822
|
+
"/assets/reportWorker-0AGij1Ru.js",
|
|
29668
29823
|
import.meta.url
|
|
29669
29824
|
), { type: "module" });
|
|
29670
29825
|
const cleanup = () => {
|
|
@@ -33521,7 +33676,7 @@ function SectionCapPreview({
|
|
|
33521
33676
|
class ScanProxyWorkerClient {
|
|
33522
33677
|
constructor(workerFactory = () => new Worker(new URL(
|
|
33523
33678
|
/* @vite-ignore */
|
|
33524
|
-
"/assets/scanProxyWorker-
|
|
33679
|
+
"/assets/scanProxyWorker-Vl4Wxa1y.js",
|
|
33525
33680
|
import.meta.url
|
|
33526
33681
|
), { type: "module" })) {
|
|
33527
33682
|
__publicField(this, "worker", null);
|
|
@@ -33897,35 +34052,6 @@ function MatrixGlyphVolume({
|
|
|
33897
34052
|
)
|
|
33898
34053
|
] });
|
|
33899
34054
|
}
|
|
33900
|
-
const SCAN_COLD_RGB = normalizedRgb(SCAN_CONTEXT_EDGE_COLOR);
|
|
33901
|
-
const SCAN_MID_RGB = normalizedRgb(SCAN_RISK_MID_COLOR);
|
|
33902
|
-
const SCAN_HOT_RGB = normalizedRgb(SCAN_RISK_HOT_COLOR);
|
|
33903
|
-
function normalizedRgb([r2, g2, b2]) {
|
|
33904
|
-
return [r2 / 255, g2 / 255, b2 / 255];
|
|
33905
|
-
}
|
|
33906
|
-
function clamp01$1(value) {
|
|
33907
|
-
return Math.max(0, Math.min(1, value));
|
|
33908
|
-
}
|
|
33909
|
-
function mix(a2, b2, t2) {
|
|
33910
|
-
return a2 + (b2 - a2) * clamp01$1(t2);
|
|
33911
|
-
}
|
|
33912
|
-
function scanRiskFromColor(r2, g2, b2) {
|
|
33913
|
-
return clamp01$1(r2 * 1.08 + g2 * 0.48 - b2 * 0.62 - 0.38);
|
|
33914
|
-
}
|
|
33915
|
-
function scanColorBuffer(source) {
|
|
33916
|
-
const out = new Float32Array(source.length);
|
|
33917
|
-
for (let index = 0; index < source.length; index += 3) {
|
|
33918
|
-
const risk = scanRiskFromColor(source[index] ?? 0, source[index + 1] ?? 0, source[index + 2] ?? 0);
|
|
33919
|
-
const lowBand = risk < 0.55;
|
|
33920
|
-
const t2 = lowBand ? risk / 0.55 : (risk - 0.55) / 0.45;
|
|
33921
|
-
const from = lowBand ? SCAN_COLD_RGB : SCAN_MID_RGB;
|
|
33922
|
-
const to = lowBand ? SCAN_MID_RGB : SCAN_HOT_RGB;
|
|
33923
|
-
out[index] = mix(from[0], to[0], t2);
|
|
33924
|
-
out[index + 1] = mix(from[1], to[1], t2);
|
|
33925
|
-
out[index + 2] = mix(from[2], to[2], t2);
|
|
33926
|
-
}
|
|
33927
|
-
return out;
|
|
33928
|
-
}
|
|
33929
34055
|
function SurfaceFieldMaterial({
|
|
33930
34056
|
field,
|
|
33931
34057
|
color: color2,
|
|
@@ -33985,17 +34111,104 @@ function ZebraInspectionMaterial({ clippingPlanes }) {
|
|
|
33985
34111
|
}
|
|
33986
34112
|
const EMPTY_CLIPPING_PLANES$1 = [];
|
|
33987
34113
|
const EMPTY_SECTION_PLANES$1 = [];
|
|
34114
|
+
function scanCellKey(ix, iy, iz) {
|
|
34115
|
+
return `${ix}:${iy}:${iz}`;
|
|
34116
|
+
}
|
|
34117
|
+
function buildDirectScanCellColors(pointCloud, grid, matrix) {
|
|
34118
|
+
const accumulators = /* @__PURE__ */ new Map();
|
|
34119
|
+
const point = new Vector3();
|
|
34120
|
+
const [originX, originY, originZ] = grid.origin;
|
|
34121
|
+
const sampleCount = Math.floor(pointCloud.positions.length / 3);
|
|
34122
|
+
for (let sample = 0; sample < sampleCount; sample += 1) {
|
|
34123
|
+
const offset = sample * 3;
|
|
34124
|
+
point.set(pointCloud.positions[offset], pointCloud.positions[offset + 1], pointCloud.positions[offset + 2]).applyMatrix4(matrix);
|
|
34125
|
+
const ix = Math.floor((point.x - originX) / grid.cellSize);
|
|
34126
|
+
const iy = Math.floor((point.y - originY) / grid.cellSize);
|
|
34127
|
+
const iz = Math.floor((point.z - originZ) / grid.cellSize);
|
|
34128
|
+
const key = scanCellKey(ix, iy, iz);
|
|
34129
|
+
const accumulator = accumulators.get(key) ?? { ix, iy, iz, r: 0, g: 0, b: 0, count: 0 };
|
|
34130
|
+
accumulator.r += pointCloud.colors[offset] ?? 0.35;
|
|
34131
|
+
accumulator.g += pointCloud.colors[offset + 1] ?? 0.35;
|
|
34132
|
+
accumulator.b += pointCloud.colors[offset + 2] ?? 0.35;
|
|
34133
|
+
accumulator.count += 1;
|
|
34134
|
+
accumulators.set(key, accumulator);
|
|
34135
|
+
}
|
|
34136
|
+
const directColors = /* @__PURE__ */ new Map();
|
|
34137
|
+
for (const [key, accumulator] of accumulators) {
|
|
34138
|
+
directColors.set(key, {
|
|
34139
|
+
ix: accumulator.ix,
|
|
34140
|
+
iy: accumulator.iy,
|
|
34141
|
+
iz: accumulator.iz,
|
|
34142
|
+
color: [accumulator.r / accumulator.count, accumulator.g / accumulator.count, accumulator.b / accumulator.count]
|
|
34143
|
+
});
|
|
34144
|
+
}
|
|
34145
|
+
return directColors;
|
|
34146
|
+
}
|
|
34147
|
+
function nearestScanCellColor(ix, iy, iz, coloredCells) {
|
|
34148
|
+
let best = coloredCells[0];
|
|
34149
|
+
let bestDistance = Number.POSITIVE_INFINITY;
|
|
34150
|
+
for (const candidate of coloredCells) {
|
|
34151
|
+
const distance = (candidate.ix - ix) ** 2 + (candidate.iy - iy) ** 2 + (candidate.iz - iz) ** 2;
|
|
34152
|
+
if (distance >= bestDistance) continue;
|
|
34153
|
+
best = candidate;
|
|
34154
|
+
bestDistance = distance;
|
|
34155
|
+
}
|
|
34156
|
+
return (best == null ? void 0 : best.color) ?? [0.35, 0.35, 0.35];
|
|
34157
|
+
}
|
|
34158
|
+
function createScanAnalysisColorGeometry(geometry, pointCloud, grid, matrix) {
|
|
34159
|
+
var _a3;
|
|
34160
|
+
if (!geometry) return null;
|
|
34161
|
+
const position = geometry.getAttribute("position");
|
|
34162
|
+
const scanCell = geometry.getAttribute("scanCell");
|
|
34163
|
+
if (!position || !scanCell || position.count !== scanCell.count) return null;
|
|
34164
|
+
const directColors = buildDirectScanCellColors(pointCloud, grid, matrix);
|
|
34165
|
+
const coloredCells = [...directColors.values()];
|
|
34166
|
+
if (coloredCells.length === 0) return null;
|
|
34167
|
+
const resolvedColors = /* @__PURE__ */ new Map();
|
|
34168
|
+
const colors = new Float32Array(position.count * 3);
|
|
34169
|
+
for (let vertex = 0; vertex < position.count; vertex += 1) {
|
|
34170
|
+
const ix = Math.round(scanCell.getX(vertex));
|
|
34171
|
+
const iy = Math.round(scanCell.getY(vertex));
|
|
34172
|
+
const iz = Math.round(scanCell.getZ(vertex));
|
|
34173
|
+
const key = scanCellKey(ix, iy, iz);
|
|
34174
|
+
let color2 = resolvedColors.get(key);
|
|
34175
|
+
if (!color2) {
|
|
34176
|
+
color2 = ((_a3 = directColors.get(key)) == null ? void 0 : _a3.color) ?? nearestScanCellColor(ix, iy, iz, coloredCells);
|
|
34177
|
+
resolvedColors.set(key, color2);
|
|
34178
|
+
}
|
|
34179
|
+
const offset = vertex * 3;
|
|
34180
|
+
colors[offset] = color2[0];
|
|
34181
|
+
colors[offset + 1] = color2[1];
|
|
34182
|
+
colors[offset + 2] = color2[2];
|
|
34183
|
+
}
|
|
34184
|
+
const coloredGeometry = geometry.clone();
|
|
34185
|
+
coloredGeometry.setAttribute("color", new BufferAttribute(colors, 3));
|
|
34186
|
+
return coloredGeometry;
|
|
34187
|
+
}
|
|
33988
34188
|
function ScanProxyLayer({
|
|
33989
34189
|
geometry,
|
|
33990
34190
|
color: color2,
|
|
33991
34191
|
fillOpacity,
|
|
33992
34192
|
wireOpacity,
|
|
33993
34193
|
clippingPlanes,
|
|
33994
|
-
additiveWire
|
|
34194
|
+
additiveWire,
|
|
34195
|
+
analysisGeometry
|
|
33995
34196
|
}) {
|
|
33996
|
-
|
|
34197
|
+
const fillGeometry = analysisGeometry ?? geometry;
|
|
34198
|
+
if (!geometry || !fillGeometry) return null;
|
|
33997
34199
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
33998
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("mesh", { geometry, raycast: () => null, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
34200
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("mesh", { geometry: fillGeometry, raycast: () => null, children: analysisGeometry ? /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
34201
|
+
"meshBasicMaterial",
|
|
34202
|
+
{
|
|
34203
|
+
vertexColors: true,
|
|
34204
|
+
transparent: true,
|
|
34205
|
+
opacity: fillOpacity,
|
|
34206
|
+
side: DoubleSide,
|
|
34207
|
+
depthWrite: false,
|
|
34208
|
+
toneMapped: false,
|
|
34209
|
+
clippingPlanes
|
|
34210
|
+
}
|
|
34211
|
+
) : /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
33999
34212
|
"meshBasicMaterial",
|
|
34000
34213
|
{
|
|
34001
34214
|
color: color2,
|
|
@@ -34029,20 +34242,29 @@ function objectColorScanLayerStyles(color2) {
|
|
|
34029
34242
|
function ScanProxyVolume({
|
|
34030
34243
|
proxy,
|
|
34031
34244
|
clippingPlanes,
|
|
34032
|
-
objectColor
|
|
34245
|
+
objectColor,
|
|
34246
|
+
analysisGeometries
|
|
34033
34247
|
}) {
|
|
34034
34248
|
const layers = objectColor ? objectColorScanLayerStyles(objectColor) : SCAN_PROXY_LAYER_STYLES;
|
|
34035
34249
|
const additiveWire = objectColor === void 0;
|
|
34036
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx("group", { userData: { scanProxyTelemetry: proxy.telemetry }, children: layers.map((layer) =>
|
|
34037
|
-
|
|
34038
|
-
|
|
34039
|
-
|
|
34040
|
-
|
|
34041
|
-
|
|
34042
|
-
|
|
34043
|
-
|
|
34044
|
-
|
|
34045
|
-
|
|
34250
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx("group", { userData: { scanProxyTelemetry: proxy.telemetry }, children: layers.map((layer) => {
|
|
34251
|
+
const analysisGeometry = (analysisGeometries == null ? void 0 : analysisGeometries[layer.material]) ?? null;
|
|
34252
|
+
const fillOpacity = analysisGeometry ? Math.max(layer.fillOpacity, 0.78) : layer.fillOpacity;
|
|
34253
|
+
const wireOpacity = analysisGeometry ? Math.max(layer.wireOpacity, 0.34) : layer.wireOpacity;
|
|
34254
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
34255
|
+
ScanProxyLayer,
|
|
34256
|
+
{
|
|
34257
|
+
geometry: proxy.geometries[layer.material],
|
|
34258
|
+
analysisGeometry,
|
|
34259
|
+
clippingPlanes,
|
|
34260
|
+
additiveWire,
|
|
34261
|
+
...layer,
|
|
34262
|
+
fillOpacity,
|
|
34263
|
+
wireOpacity
|
|
34264
|
+
},
|
|
34265
|
+
layer.material
|
|
34266
|
+
);
|
|
34267
|
+
}) });
|
|
34046
34268
|
}
|
|
34047
34269
|
function ForgeObject({
|
|
34048
34270
|
obj,
|
|
@@ -34100,11 +34322,10 @@ function ForgeObject({
|
|
|
34100
34322
|
const inspectPointGeo = reactExports.useMemo(() => {
|
|
34101
34323
|
if (!inspectPointCloud) return null;
|
|
34102
34324
|
const geometry = new BufferGeometry();
|
|
34103
|
-
const colors = isScalarScan ? scanColorBuffer(inspectPointCloud.colors) : inspectPointCloud.colors;
|
|
34104
34325
|
geometry.setAttribute("position", new BufferAttribute(inspectPointCloud.positions, 3));
|
|
34105
|
-
geometry.setAttribute("color", new BufferAttribute(colors, 3));
|
|
34326
|
+
geometry.setAttribute("color", new BufferAttribute(inspectPointCloud.colors, 3));
|
|
34106
34327
|
return geometry;
|
|
34107
|
-
}, [inspectPointCloud
|
|
34328
|
+
}, [inspectPointCloud]);
|
|
34108
34329
|
const inspectMeshColorGeo = reactExports.useMemo(() => {
|
|
34109
34330
|
if (!solidGeo || !inspectMeshColors) return null;
|
|
34110
34331
|
const position = solidGeo.getAttribute("position");
|
|
@@ -34123,6 +34344,11 @@ function ForgeObject({
|
|
|
34123
34344
|
);
|
|
34124
34345
|
const scanProxyState = useScanProxyWorkerGeometry(solidGeo, wantsScanProxy, scanProxyGrid, matrix);
|
|
34125
34346
|
const scanProxy = scanProxyState.proxy;
|
|
34347
|
+
const scanAnalysisGeometries = reactExports.useMemo(() => {
|
|
34348
|
+
if (!isScalarScan || !scanProxy || !inspectPointCloud) return null;
|
|
34349
|
+
const shell = createScanAnalysisColorGeometry(scanProxy.geometries.shell, inspectPointCloud, scanProxy.grid, matrix);
|
|
34350
|
+
return shell ? { shell } : null;
|
|
34351
|
+
}, [inspectPointCloud, isScalarScan, matrix, scanProxy]);
|
|
34126
34352
|
reactExports.useEffect(() => {
|
|
34127
34353
|
return () => {
|
|
34128
34354
|
solidGeo == null ? void 0 : solidGeo.dispose();
|
|
@@ -34144,16 +34370,13 @@ function ForgeObject({
|
|
|
34144
34370
|
inspectHeatmapField == null ? void 0 : inspectHeatmapField.texture.dispose();
|
|
34145
34371
|
};
|
|
34146
34372
|
}, [inspectHeatmapField]);
|
|
34373
|
+
reactExports.useEffect(() => {
|
|
34374
|
+
return () => {
|
|
34375
|
+
Object.values(scanAnalysisGeometries ?? {}).forEach((geometry) => geometry == null ? void 0 : geometry.dispose());
|
|
34376
|
+
};
|
|
34377
|
+
}, [scanAnalysisGeometries]);
|
|
34147
34378
|
if (!solidGeo || !settings.visible) return null;
|
|
34148
34379
|
const effectiveRenderMode = isInteracting && renderMode === "overlay" ? "solid" : renderMode;
|
|
34149
|
-
const isInspecting = inspectChannel !== "none";
|
|
34150
|
-
const showInspectHeatmap = Boolean(
|
|
34151
|
-
isScalarInspect && !isScalarScan && inspectHeatmapField && (inspectDisplayMode === "heatmap" || inspectDisplayMode === "both")
|
|
34152
|
-
);
|
|
34153
|
-
const showScalarContextMesh = Boolean(isScalarInspect && (isScalarScan || !showInspectHeatmap));
|
|
34154
|
-
const showInspectPoints = Boolean(
|
|
34155
|
-
isScalarInspect && inspectPointGeo && (inspectDisplayMode === "points" || inspectDisplayMode === "both" || isScalarScan)
|
|
34156
|
-
);
|
|
34157
34380
|
const renderStylePreset = getRenderStylePreset(renderStyle);
|
|
34158
34381
|
const materialDefaults = renderStylePreset.material;
|
|
34159
34382
|
const surfaceField = renderStylePreset.surfaceField;
|
|
@@ -34166,6 +34389,7 @@ function ForgeObject({
|
|
|
34166
34389
|
const materialOpacity = Math.min(meshOpacity, styleOpacity);
|
|
34167
34390
|
const transmission = authoredMaterialTransmission ?? transparentDefaults.transmission;
|
|
34168
34391
|
const isTransparent = materialOpacity < 1 || transmission > 0;
|
|
34392
|
+
const isInspecting = inspectChannel !== "none";
|
|
34169
34393
|
const showSolid = isInspecting || effectiveRenderMode !== "wireframe";
|
|
34170
34394
|
const showEdges = !isInspecting && effectiveRenderMode === "overlay" && renderStyle !== "scan" && renderStyle !== "matrix";
|
|
34171
34395
|
const showWire = !isInspecting && effectiveRenderMode === "wireframe";
|
|
@@ -34177,7 +34401,16 @@ function ForgeObject({
|
|
|
34177
34401
|
const showFloatingObject = inspectChannel !== "floating" || hasInspectMeshColors || inspectColor !== "#000000";
|
|
34178
34402
|
const showScanRenderStyle = showSolid && inspectChannel === "none" && renderStyle === "scan";
|
|
34179
34403
|
const showMatrixRenderStyle = showSolid && inspectChannel === "none" && renderStyle === "matrix";
|
|
34180
|
-
const showScalarScanProxy = showSolid && isScalarScan && scanProxy !== null;
|
|
34404
|
+
const showScalarScanProxy = showSolid && isScalarScan && scanProxy !== null && (scanAnalysisGeometries == null ? void 0 : scanAnalysisGeometries.shell) != null;
|
|
34405
|
+
const showInspectHeatmap = Boolean(
|
|
34406
|
+
isScalarInspect && inspectHeatmapField && (!isScalarScan && (inspectDisplayMode === "heatmap" || inspectDisplayMode === "both") || isScalarScan && !showScalarScanProxy)
|
|
34407
|
+
);
|
|
34408
|
+
const showScalarContextMesh = Boolean(
|
|
34409
|
+
isScalarInspect && (!isScalarScan && !showInspectHeatmap || isScalarScan && !showScalarScanProxy && !showInspectHeatmap)
|
|
34410
|
+
);
|
|
34411
|
+
const showInspectPoints = Boolean(
|
|
34412
|
+
isScalarInspect && inspectPointGeo && (inspectDisplayMode === "points" || inspectDisplayMode === "both")
|
|
34413
|
+
);
|
|
34181
34414
|
const showScanFallbackMesh = showScanRenderStyle && scanProxy === null;
|
|
34182
34415
|
const showMatrixFallbackMesh = showMatrixRenderStyle && scanProxy === null;
|
|
34183
34416
|
const showHiddenPickMesh = showScanRenderStyle || showMatrixRenderStyle || showScalarScanProxy;
|
|
@@ -34256,7 +34489,7 @@ function ForgeObject({
|
|
|
34256
34489
|
clippingPlanes: effectiveClippingPlanes
|
|
34257
34490
|
}
|
|
34258
34491
|
) }),
|
|
34259
|
-
showScalarScanProxy && /* @__PURE__ */ jsxRuntimeExports.jsx(ScanProxyVolume, { proxy: scanProxy, clippingPlanes: effectiveClippingPlanes }),
|
|
34492
|
+
showScalarScanProxy && scanProxy && scanAnalysisGeometries && /* @__PURE__ */ jsxRuntimeExports.jsx(ScanProxyVolume, { proxy: scanProxy, clippingPlanes: effectiveClippingPlanes, analysisGeometries: scanAnalysisGeometries }),
|
|
34260
34493
|
showSolid && showScalarContextMesh && !showScalarScanProxy && /* @__PURE__ */ jsxRuntimeExports.jsx("mesh", { geometry: solidGeo, userData: { forgeMesh: true }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
34261
34494
|
"meshBasicMaterial",
|
|
34262
34495
|
{
|
|
@@ -34295,7 +34528,8 @@ function ForgeObject({
|
|
|
34295
34528
|
side: DoubleSide,
|
|
34296
34529
|
toneMapped: false,
|
|
34297
34530
|
clippingPlanes: effectiveClippingPlanes
|
|
34298
|
-
}
|
|
34531
|
+
},
|
|
34532
|
+
inspectHeatmapField.texture.uuid
|
|
34299
34533
|
) }),
|
|
34300
34534
|
showInspectPoints && inspectPointGeo && /* @__PURE__ */ jsxRuntimeExports.jsx("points", { geometry: inspectPointGeo, raycast: () => null, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
34301
34535
|
"pointsMaterial",
|
|
@@ -34782,9 +35016,12 @@ function colorToHex(color2) {
|
|
|
34782
35016
|
return rgbToHex(color2);
|
|
34783
35017
|
}
|
|
34784
35018
|
function fmt(value) {
|
|
34785
|
-
|
|
35019
|
+
if (!Number.isFinite(value)) return "0";
|
|
35020
|
+
if (Number.isInteger(value)) return String(value);
|
|
35021
|
+
const fixed = Math.abs(value) < 10 ? value.toFixed(2) : value.toFixed(1);
|
|
35022
|
+
return fixed.replace(/\.?0+$/, "");
|
|
34786
35023
|
}
|
|
34787
|
-
function inspectionLegendDefinitionFor(channel, displayMode) {
|
|
35024
|
+
function inspectionLegendDefinitionFor(channel, displayMode, legendOptions = {}) {
|
|
34788
35025
|
switch (channel) {
|
|
34789
35026
|
case "mask":
|
|
34790
35027
|
return {
|
|
@@ -34810,8 +35047,11 @@ function inspectionLegendDefinitionFor(channel, displayMode) {
|
|
|
34810
35047
|
case "rig":
|
|
34811
35048
|
return {
|
|
34812
35049
|
title: "Rig Skeleton",
|
|
34813
|
-
summary: "Geometry is ghosted while joint axes,
|
|
35050
|
+
summary: "Geometry is ghosted while joint axes, link pins, and rigid edges stay bright.",
|
|
34814
35051
|
swatches: [
|
|
35052
|
+
{ label: "Link pin", detail: "kinematic node", color: rgbToHex(RIG_KINEMATIC_LINK_COLOR) },
|
|
35053
|
+
{ label: "Fixed link", detail: "anchored node", color: rgbToHex(RIG_FIXED_LINK_COLOR) },
|
|
35054
|
+
{ label: "Rigid edge", detail: "distance member", color: rgbToHex(RIG_KINEMATIC_EDGE_COLOR) },
|
|
34815
35055
|
{ label: "Joint link", detail: "parent-child chain", color: rgbToHex(RIG_LINK_COLOR) },
|
|
34816
35056
|
{ label: "Part link", detail: "joint to moving body", color: rgbToHex(RIG_PART_LINK_COLOR) },
|
|
34817
35057
|
{ label: "Hidden joint", detail: "fixed follower", color: rgbToHex(RIG_HIDDEN_LINK_COLOR) },
|
|
@@ -34869,33 +35109,25 @@ function inspectionLegendDefinitionFor(channel, displayMode) {
|
|
|
34869
35109
|
]
|
|
34870
35110
|
};
|
|
34871
35111
|
case "thickness": {
|
|
34872
|
-
const
|
|
35112
|
+
const colorRange = legendOptions.thicknessColorRange ?? DEFAULT_THICKNESS_COLOR_RANGE;
|
|
35113
|
+
const midpoint = colorRange.min + (colorRange.max - colorRange.min) / 2;
|
|
35114
|
+
const ramp = {
|
|
35115
|
+
colors: THICKNESS_GRADIENT_COLORS.map(colorToHex),
|
|
35116
|
+
leftLabel: `${fmt(colorRange.min)} mm`,
|
|
35117
|
+
centerLabel: `${fmt(midpoint)} mm`,
|
|
35118
|
+
rightLabel: `${fmt(colorRange.max)} mm`
|
|
35119
|
+
};
|
|
34873
35120
|
if (displayMode === "scan") {
|
|
34874
35121
|
return {
|
|
34875
35122
|
title: "Thickness Scan",
|
|
34876
|
-
summary: "
|
|
34877
|
-
|
|
34878
|
-
{ label: "Shell", detail: "context", color: colorToHex(SCAN_CONTEXT_COLOR) },
|
|
34879
|
-
{ label: "Trace", detail: "surface edge", color: colorToHex(SCAN_CONTEXT_EDGE_COLOR) },
|
|
34880
|
-
{ label: "Warn", detail: `<= ${fmt(options.warnThickness)} mm`, color: colorToHex(SCAN_RISK_MID_COLOR) },
|
|
34881
|
-
{ label: "Critical", detail: `<= ${fmt(options.minThickness)} mm`, color: colorToHex(SCAN_RISK_HOT_COLOR) }
|
|
34882
|
-
]
|
|
35123
|
+
summary: "Each scan box uses the same continuous wall-thickness color ramp as the heatmap.",
|
|
35124
|
+
ramp
|
|
34883
35125
|
};
|
|
34884
35126
|
}
|
|
34885
35127
|
return {
|
|
34886
35128
|
title: "Wall Thickness",
|
|
34887
|
-
summary: "
|
|
34888
|
-
ramp
|
|
34889
|
-
colors: [
|
|
34890
|
-
colorToHex(THICKNESS_COLORS.critical),
|
|
34891
|
-
colorToHex(THICKNESS_COLORS.warning),
|
|
34892
|
-
colorToHex(THICKNESS_COLORS.ok),
|
|
34893
|
-
colorToHex(THICKNESS_COLORS.thick)
|
|
34894
|
-
],
|
|
34895
|
-
leftLabel: `<= ${fmt(options.minThickness)} mm`,
|
|
34896
|
-
centerLabel: `${fmt(options.warnThickness)} mm warn`,
|
|
34897
|
-
rightLabel: `>= ${fmt(options.maxThickness)} mm`
|
|
34898
|
-
}
|
|
35129
|
+
summary: "Color maps continuously from thinner to thicker material across the selected range.",
|
|
35130
|
+
ramp
|
|
34899
35131
|
};
|
|
34900
35132
|
}
|
|
34901
35133
|
case "roughness": {
|
|
@@ -34903,12 +35135,20 @@ function inspectionLegendDefinitionFor(channel, displayMode) {
|
|
|
34903
35135
|
if (displayMode === "scan") {
|
|
34904
35136
|
return {
|
|
34905
35137
|
title: "Roughness Scan",
|
|
34906
|
-
summary: "
|
|
35138
|
+
summary: "Each scan box is colored from the same roughness analysis field as the heatmap.",
|
|
34907
35139
|
swatches: [
|
|
34908
|
-
{ label: "
|
|
34909
|
-
{
|
|
34910
|
-
|
|
34911
|
-
|
|
35140
|
+
{ label: "Smooth", detail: `< ${fmt(options.smoothAngleDeg)} deg`, color: colorToHex(ROUGHNESS_COLORS.smooth) },
|
|
35141
|
+
{
|
|
35142
|
+
label: "Moderate",
|
|
35143
|
+
detail: `${fmt(options.smoothAngleDeg)}-${fmt(options.sharpAngleDeg)} deg`,
|
|
35144
|
+
color: colorToHex(ROUGHNESS_COLORS.moderate)
|
|
35145
|
+
},
|
|
35146
|
+
{
|
|
35147
|
+
label: "Sharp",
|
|
35148
|
+
detail: `${fmt(options.sharpAngleDeg)}-${fmt(options.harshAngleDeg)} deg`,
|
|
35149
|
+
color: colorToHex(ROUGHNESS_COLORS.sharp)
|
|
35150
|
+
},
|
|
35151
|
+
{ label: "Harsh", detail: `>= ${fmt(options.harshAngleDeg)} deg`, color: colorToHex(ROUGHNESS_COLORS.harsh) }
|
|
34912
35152
|
]
|
|
34913
35153
|
};
|
|
34914
35154
|
}
|
|
@@ -34968,6 +35208,78 @@ const swatchGridStyle = {
|
|
|
34968
35208
|
gridTemplateColumns: "repeat(2, minmax(0, 1fr))",
|
|
34969
35209
|
gap: 6
|
|
34970
35210
|
};
|
|
35211
|
+
const rangeControlsStyle = {
|
|
35212
|
+
display: "grid",
|
|
35213
|
+
gridTemplateColumns: "repeat(2, minmax(0, 1fr))",
|
|
35214
|
+
gap: 7,
|
|
35215
|
+
marginTop: 7
|
|
35216
|
+
};
|
|
35217
|
+
const rangeLabelStyle = {
|
|
35218
|
+
display: "grid",
|
|
35219
|
+
gap: 3,
|
|
35220
|
+
minWidth: 0,
|
|
35221
|
+
color: "var(--fc-textDim)",
|
|
35222
|
+
fontSize: 10
|
|
35223
|
+
};
|
|
35224
|
+
const rangeInputStyle = {
|
|
35225
|
+
width: "100%",
|
|
35226
|
+
minWidth: 0,
|
|
35227
|
+
boxSizing: "border-box",
|
|
35228
|
+
height: 24,
|
|
35229
|
+
borderRadius: 6,
|
|
35230
|
+
border: "1px solid var(--fc-border)",
|
|
35231
|
+
background: "var(--fc-bg)",
|
|
35232
|
+
color: "var(--fc-text)",
|
|
35233
|
+
font: "inherit",
|
|
35234
|
+
fontSize: 11,
|
|
35235
|
+
padding: "2px 6px",
|
|
35236
|
+
outline: "none"
|
|
35237
|
+
};
|
|
35238
|
+
const dualSliderStyle = {
|
|
35239
|
+
position: "relative",
|
|
35240
|
+
height: 28,
|
|
35241
|
+
marginTop: 9,
|
|
35242
|
+
touchAction: "none"
|
|
35243
|
+
};
|
|
35244
|
+
const sliderTrackStyle = {
|
|
35245
|
+
position: "absolute",
|
|
35246
|
+
left: 0,
|
|
35247
|
+
right: 0,
|
|
35248
|
+
top: 12,
|
|
35249
|
+
height: 5,
|
|
35250
|
+
borderRadius: 999,
|
|
35251
|
+
background: "color-mix(in srgb, var(--fc-border) 76%, transparent)"
|
|
35252
|
+
};
|
|
35253
|
+
const sliderActiveStyle = {
|
|
35254
|
+
position: "absolute",
|
|
35255
|
+
top: 12,
|
|
35256
|
+
height: 5,
|
|
35257
|
+
borderRadius: 999,
|
|
35258
|
+
background: "linear-gradient(90deg, #ff1c1c, #ffde00, #3cdc5a, #4691ff)"
|
|
35259
|
+
};
|
|
35260
|
+
const sliderThumbStyle = {
|
|
35261
|
+
position: "absolute",
|
|
35262
|
+
top: 5,
|
|
35263
|
+
width: 18,
|
|
35264
|
+
height: 18,
|
|
35265
|
+
borderRadius: "50%",
|
|
35266
|
+
border: "2px solid var(--fc-bgPanel)",
|
|
35267
|
+
background: "var(--fc-text)",
|
|
35268
|
+
boxShadow: "0 1px 5px rgba(0, 0, 0, 0.3)",
|
|
35269
|
+
padding: 0,
|
|
35270
|
+
cursor: "grab",
|
|
35271
|
+
touchAction: "none"
|
|
35272
|
+
};
|
|
35273
|
+
const sliderScaleStyle = {
|
|
35274
|
+
display: "grid",
|
|
35275
|
+
gridTemplateColumns: "repeat(3, minmax(0, 1fr))",
|
|
35276
|
+
gap: 6,
|
|
35277
|
+
marginTop: 1,
|
|
35278
|
+
color: "var(--fc-textDim)",
|
|
35279
|
+
fontSize: 9
|
|
35280
|
+
};
|
|
35281
|
+
const SLIDER_STEP = 0.01;
|
|
35282
|
+
const MIN_RANGE_SPAN = 1e-3;
|
|
34971
35283
|
function Ramp({ compact, ramp }) {
|
|
34972
35284
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { minWidth: 0 }, children: [
|
|
34973
35285
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
@@ -35024,15 +35336,272 @@ function Swatch({ item }) {
|
|
|
35024
35336
|
] })
|
|
35025
35337
|
] });
|
|
35026
35338
|
}
|
|
35339
|
+
function parseRangeInput(value, fallback) {
|
|
35340
|
+
const parsed = Number(value);
|
|
35341
|
+
return Number.isFinite(parsed) ? parsed : fallback;
|
|
35342
|
+
}
|
|
35343
|
+
function rangeDraftValue(value) {
|
|
35344
|
+
return Number.isFinite(value) ? String(value) : "";
|
|
35345
|
+
}
|
|
35346
|
+
function rangeKey(range) {
|
|
35347
|
+
return `${range.min}:${range.max}`;
|
|
35348
|
+
}
|
|
35349
|
+
function clamp(value, min, max2) {
|
|
35350
|
+
return Math.max(min, Math.min(max2, value));
|
|
35351
|
+
}
|
|
35352
|
+
function snapSliderValue(value) {
|
|
35353
|
+
return Number((Math.round(value / SLIDER_STEP) * SLIDER_STEP).toFixed(2));
|
|
35354
|
+
}
|
|
35355
|
+
function formatSliderTick(value) {
|
|
35356
|
+
if (!Number.isFinite(value)) return "0";
|
|
35357
|
+
return Number.isInteger(value) ? String(value) : value.toFixed(1).replace(/\.0$/, "");
|
|
35358
|
+
}
|
|
35359
|
+
function sliderMaxFor(range) {
|
|
35360
|
+
const target = Math.max(6, range.max * 1.25, range.min + 1);
|
|
35361
|
+
if (target <= 10) return Math.ceil(target);
|
|
35362
|
+
if (target <= 50) return Math.ceil(target / 5) * 5;
|
|
35363
|
+
if (target <= 100) return Math.ceil(target / 10) * 10;
|
|
35364
|
+
return Math.ceil(target / 50) * 50;
|
|
35365
|
+
}
|
|
35366
|
+
function DualRangeSlider({
|
|
35367
|
+
range,
|
|
35368
|
+
sliderMax,
|
|
35369
|
+
onDraftChange,
|
|
35370
|
+
onCommit
|
|
35371
|
+
}) {
|
|
35372
|
+
const trackRef = reactExports.useRef(null);
|
|
35373
|
+
const minPercent = clamp(range.min, 0, sliderMax) / sliderMax * 100;
|
|
35374
|
+
const maxPercent = clamp(range.max, 0, sliderMax) / sliderMax * 100;
|
|
35375
|
+
const valueFromPointer = (event) => {
|
|
35376
|
+
var _a3;
|
|
35377
|
+
const rect = (_a3 = trackRef.current) == null ? void 0 : _a3.getBoundingClientRect();
|
|
35378
|
+
if (!rect || rect.width <= 0) return null;
|
|
35379
|
+
const ratio = clamp((event.clientX - rect.left) / rect.width, 0, 1);
|
|
35380
|
+
return snapSliderValue(ratio * sliderMax);
|
|
35381
|
+
};
|
|
35382
|
+
const updateThumb = (thumb, value) => {
|
|
35383
|
+
if (thumb === "min") {
|
|
35384
|
+
onDraftChange({ min: clamp(value, 0, range.max - MIN_RANGE_SPAN), max: range.max });
|
|
35385
|
+
} else {
|
|
35386
|
+
onDraftChange({ min: range.min, max: Math.max(range.min + MIN_RANGE_SPAN, clamp(value, MIN_RANGE_SPAN, sliderMax)) });
|
|
35387
|
+
}
|
|
35388
|
+
};
|
|
35389
|
+
const handlePointerMove = (thumb, event) => {
|
|
35390
|
+
if ((event.buttons & 1) !== 1) return;
|
|
35391
|
+
const value = valueFromPointer(event);
|
|
35392
|
+
if (value == null) return;
|
|
35393
|
+
updateThumb(thumb, value);
|
|
35394
|
+
};
|
|
35395
|
+
const handlePointerDown = (thumb, event) => {
|
|
35396
|
+
event.currentTarget.setPointerCapture(event.pointerId);
|
|
35397
|
+
const value = valueFromPointer(event);
|
|
35398
|
+
if (value != null) updateThumb(thumb, value);
|
|
35399
|
+
};
|
|
35400
|
+
const handleKeyDown = (thumb, event) => {
|
|
35401
|
+
let next = null;
|
|
35402
|
+
if (event.key === "ArrowLeft" || event.key === "ArrowDown") next = range[thumb] - SLIDER_STEP;
|
|
35403
|
+
if (event.key === "ArrowRight" || event.key === "ArrowUp") next = range[thumb] + SLIDER_STEP;
|
|
35404
|
+
if (event.key === "Home") next = thumb === "min" ? 0 : range.min + MIN_RANGE_SPAN;
|
|
35405
|
+
if (event.key === "End") next = thumb === "min" ? range.max - MIN_RANGE_SPAN : sliderMax;
|
|
35406
|
+
if (event.key === "Enter") {
|
|
35407
|
+
event.preventDefault();
|
|
35408
|
+
event.currentTarget.blur();
|
|
35409
|
+
return;
|
|
35410
|
+
}
|
|
35411
|
+
if (next == null) return;
|
|
35412
|
+
event.preventDefault();
|
|
35413
|
+
updateThumb(thumb, snapSliderValue(next));
|
|
35414
|
+
};
|
|
35415
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
35416
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { ref: trackRef, style: dualSliderStyle, children: [
|
|
35417
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { style: sliderTrackStyle }),
|
|
35418
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
35419
|
+
"div",
|
|
35420
|
+
{
|
|
35421
|
+
style: {
|
|
35422
|
+
...sliderActiveStyle,
|
|
35423
|
+
left: `${minPercent}%`,
|
|
35424
|
+
width: `${Math.max(0, maxPercent - minPercent)}%`
|
|
35425
|
+
}
|
|
35426
|
+
}
|
|
35427
|
+
),
|
|
35428
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
35429
|
+
"button",
|
|
35430
|
+
{
|
|
35431
|
+
type: "button",
|
|
35432
|
+
role: "slider",
|
|
35433
|
+
"aria-label": "Minimum thickness color",
|
|
35434
|
+
"aria-valuemin": 0,
|
|
35435
|
+
"aria-valuemax": range.max,
|
|
35436
|
+
"aria-valuenow": range.min,
|
|
35437
|
+
onPointerDown: (event) => handlePointerDown("min", event),
|
|
35438
|
+
onPointerMove: (event) => handlePointerMove("min", event),
|
|
35439
|
+
onPointerUp: onCommit,
|
|
35440
|
+
onLostPointerCapture: onCommit,
|
|
35441
|
+
onBlur: onCommit,
|
|
35442
|
+
onKeyDown: (event) => handleKeyDown("min", event),
|
|
35443
|
+
style: {
|
|
35444
|
+
...sliderThumbStyle,
|
|
35445
|
+
left: `${minPercent}%`,
|
|
35446
|
+
transform: "translateX(-50%)",
|
|
35447
|
+
zIndex: range.min >= range.max - SLIDER_STEP ? 3 : 2
|
|
35448
|
+
}
|
|
35449
|
+
}
|
|
35450
|
+
),
|
|
35451
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
35452
|
+
"button",
|
|
35453
|
+
{
|
|
35454
|
+
type: "button",
|
|
35455
|
+
role: "slider",
|
|
35456
|
+
"aria-label": "Maximum thickness color",
|
|
35457
|
+
"aria-valuemin": range.min,
|
|
35458
|
+
"aria-valuemax": sliderMax,
|
|
35459
|
+
"aria-valuenow": range.max,
|
|
35460
|
+
onPointerDown: (event) => handlePointerDown("max", event),
|
|
35461
|
+
onPointerMove: (event) => handlePointerMove("max", event),
|
|
35462
|
+
onPointerUp: onCommit,
|
|
35463
|
+
onLostPointerCapture: onCommit,
|
|
35464
|
+
onBlur: onCommit,
|
|
35465
|
+
onKeyDown: (event) => handleKeyDown("max", event),
|
|
35466
|
+
style: {
|
|
35467
|
+
...sliderThumbStyle,
|
|
35468
|
+
left: `${maxPercent}%`,
|
|
35469
|
+
transform: "translateX(-50%)",
|
|
35470
|
+
zIndex: 2,
|
|
35471
|
+
background: "var(--fc-accent, #4f8cff)"
|
|
35472
|
+
}
|
|
35473
|
+
}
|
|
35474
|
+
)
|
|
35475
|
+
] }),
|
|
35476
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: sliderScaleStyle, children: [
|
|
35477
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "0" }),
|
|
35478
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { textAlign: "center" }, children: formatSliderTick(sliderMax / 2) }),
|
|
35479
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { textAlign: "right" }, children: formatSliderTick(sliderMax) })
|
|
35480
|
+
] })
|
|
35481
|
+
] });
|
|
35482
|
+
}
|
|
35483
|
+
function ThicknessRangeControls({
|
|
35484
|
+
compact,
|
|
35485
|
+
range,
|
|
35486
|
+
onChange
|
|
35487
|
+
}) {
|
|
35488
|
+
const [minDraft, setMinDraft] = reactExports.useState(() => rangeDraftValue(range.min));
|
|
35489
|
+
const [maxDraft, setMaxDraft] = reactExports.useState(() => rangeDraftValue(range.max));
|
|
35490
|
+
const [sliderDraft, setSliderDraft] = reactExports.useState(range);
|
|
35491
|
+
const [sliderMax, setSliderMax] = reactExports.useState(() => sliderMaxFor(range));
|
|
35492
|
+
const sliderDraftRef = reactExports.useRef(range);
|
|
35493
|
+
const committedSliderKeyRef = reactExports.useRef(rangeKey(range));
|
|
35494
|
+
const span = Math.max(1, range.max - range.min);
|
|
35495
|
+
reactExports.useEffect(() => {
|
|
35496
|
+
setMinDraft(rangeDraftValue(range.min));
|
|
35497
|
+
setMaxDraft(rangeDraftValue(range.max));
|
|
35498
|
+
setSliderDraft(range);
|
|
35499
|
+
sliderDraftRef.current = range;
|
|
35500
|
+
committedSliderKeyRef.current = rangeKey(range);
|
|
35501
|
+
}, [range.max, range.min]);
|
|
35502
|
+
const updateSliderDraft = (next) => {
|
|
35503
|
+
sliderDraftRef.current = next;
|
|
35504
|
+
setSliderDraft(next);
|
|
35505
|
+
setMinDraft(rangeDraftValue(next.min));
|
|
35506
|
+
setMaxDraft(rangeDraftValue(next.max));
|
|
35507
|
+
};
|
|
35508
|
+
const commitSliderDraft = () => {
|
|
35509
|
+
const next = sliderDraftRef.current;
|
|
35510
|
+
const nextKey = rangeKey(next);
|
|
35511
|
+
if (nextKey === committedSliderKeyRef.current) return;
|
|
35512
|
+
committedSliderKeyRef.current = nextKey;
|
|
35513
|
+
onChange(next);
|
|
35514
|
+
};
|
|
35515
|
+
const commitMin = () => {
|
|
35516
|
+
const value = minDraft.trim();
|
|
35517
|
+
if (value === "") {
|
|
35518
|
+
setMinDraft(rangeDraftValue(range.min));
|
|
35519
|
+
return;
|
|
35520
|
+
}
|
|
35521
|
+
const min = Math.max(0, parseRangeInput(value, range.min));
|
|
35522
|
+
const max2 = range.max <= min ? min + span : range.max;
|
|
35523
|
+
const next = { min, max: max2 };
|
|
35524
|
+
setSliderMax(sliderMaxFor(next));
|
|
35525
|
+
onChange(next);
|
|
35526
|
+
};
|
|
35527
|
+
const commitMax = () => {
|
|
35528
|
+
const value = maxDraft.trim();
|
|
35529
|
+
if (value === "") {
|
|
35530
|
+
setMaxDraft(rangeDraftValue(range.max));
|
|
35531
|
+
return;
|
|
35532
|
+
}
|
|
35533
|
+
const max2 = Math.max(1e-3, parseRangeInput(value, range.max));
|
|
35534
|
+
const min = range.min >= max2 ? Math.max(0, max2 - span) : range.min;
|
|
35535
|
+
const next = { min, max: max2 };
|
|
35536
|
+
setSliderMax(sliderMaxFor(next));
|
|
35537
|
+
onChange(next);
|
|
35538
|
+
};
|
|
35539
|
+
const handleKeyDown = (event, reset) => {
|
|
35540
|
+
if (event.key === "Enter") {
|
|
35541
|
+
event.preventDefault();
|
|
35542
|
+
event.currentTarget.blur();
|
|
35543
|
+
} else if (event.key === "Escape") {
|
|
35544
|
+
event.preventDefault();
|
|
35545
|
+
reset();
|
|
35546
|
+
event.currentTarget.blur();
|
|
35547
|
+
}
|
|
35548
|
+
};
|
|
35549
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
35550
|
+
"div",
|
|
35551
|
+
{
|
|
35552
|
+
style: {
|
|
35553
|
+
...rangeControlsStyle,
|
|
35554
|
+
gridTemplateColumns: compact ? "minmax(0, 1fr)" : rangeControlsStyle.gridTemplateColumns
|
|
35555
|
+
},
|
|
35556
|
+
children: [
|
|
35557
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { style: { gridColumn: "1 / -1" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(DualRangeSlider, { range: sliderDraft, sliderMax, onDraftChange: updateSliderDraft, onCommit: commitSliderDraft }) }),
|
|
35558
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("label", { style: rangeLabelStyle, children: [
|
|
35559
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Min" }),
|
|
35560
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
35561
|
+
"input",
|
|
35562
|
+
{
|
|
35563
|
+
type: "number",
|
|
35564
|
+
min: 0,
|
|
35565
|
+
step: 0.1,
|
|
35566
|
+
value: minDraft,
|
|
35567
|
+
onChange: (event) => setMinDraft(event.currentTarget.value),
|
|
35568
|
+
onBlur: commitMin,
|
|
35569
|
+
onKeyDown: (event) => handleKeyDown(event, () => setMinDraft(rangeDraftValue(range.min))),
|
|
35570
|
+
style: rangeInputStyle
|
|
35571
|
+
}
|
|
35572
|
+
)
|
|
35573
|
+
] }),
|
|
35574
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("label", { style: rangeLabelStyle, children: [
|
|
35575
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Max" }),
|
|
35576
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
35577
|
+
"input",
|
|
35578
|
+
{
|
|
35579
|
+
type: "number",
|
|
35580
|
+
min: 1e-3,
|
|
35581
|
+
step: 0.1,
|
|
35582
|
+
value: maxDraft,
|
|
35583
|
+
onChange: (event) => setMaxDraft(event.currentTarget.value),
|
|
35584
|
+
onBlur: commitMax,
|
|
35585
|
+
onKeyDown: (event) => handleKeyDown(event, () => setMaxDraft(rangeDraftValue(range.max))),
|
|
35586
|
+
style: rangeInputStyle
|
|
35587
|
+
}
|
|
35588
|
+
)
|
|
35589
|
+
] })
|
|
35590
|
+
]
|
|
35591
|
+
}
|
|
35592
|
+
);
|
|
35593
|
+
}
|
|
35027
35594
|
function InspectionLegend({
|
|
35028
35595
|
channel,
|
|
35029
35596
|
displayMode,
|
|
35030
35597
|
warnings,
|
|
35031
|
-
details
|
|
35598
|
+
details,
|
|
35599
|
+
thicknessColorRange,
|
|
35600
|
+
onThicknessColorRangeChange
|
|
35032
35601
|
}) {
|
|
35033
35602
|
const panelRef = reactExports.useRef(null);
|
|
35034
35603
|
const [compact, setCompact] = reactExports.useState(false);
|
|
35035
|
-
const definition = inspectionLegendDefinitionFor(channel, displayMode);
|
|
35604
|
+
const definition = inspectionLegendDefinitionFor(channel, displayMode, { thicknessColorRange });
|
|
35036
35605
|
reactExports.useEffect(() => {
|
|
35037
35606
|
var _a3;
|
|
35038
35607
|
const parent = (_a3 = panelRef.current) == null ? void 0 : _a3.parentElement;
|
|
@@ -35045,7 +35614,12 @@ function InspectionLegend({
|
|
|
35045
35614
|
}, [channel]);
|
|
35046
35615
|
if (!definition) return null;
|
|
35047
35616
|
const warning = warnings[0];
|
|
35048
|
-
const
|
|
35617
|
+
const showThicknessControls = channel === "thickness" && thicknessColorRange !== void 0 && onThicknessColorRangeChange !== void 0;
|
|
35618
|
+
const effectivePanelStyle = {
|
|
35619
|
+
...panelStyle,
|
|
35620
|
+
...compact ? { padding: "7px 8px" } : {},
|
|
35621
|
+
...showThicknessControls ? { pointerEvents: "auto" } : {}
|
|
35622
|
+
};
|
|
35049
35623
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { ref: panelRef, className: "fc-viewport-floating-panel fc-inspection-legend", style: effectivePanelStyle, children: [
|
|
35050
35624
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: titleStyle, children: [
|
|
35051
35625
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: definition.title }),
|
|
@@ -35053,6 +35627,7 @@ function InspectionLegend({
|
|
|
35053
35627
|
] }),
|
|
35054
35628
|
!compact && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { style: summaryStyle, children: definition.summary }),
|
|
35055
35629
|
definition.ramp && /* @__PURE__ */ jsxRuntimeExports.jsx(Ramp, { compact, ramp: definition.ramp }),
|
|
35630
|
+
showThicknessControls && /* @__PURE__ */ jsxRuntimeExports.jsx(ThicknessRangeControls, { compact, range: thicknessColorRange, onChange: onThicknessColorRangeChange }),
|
|
35056
35631
|
details && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
35057
35632
|
"div",
|
|
35058
35633
|
{
|
|
@@ -36672,6 +37247,12 @@ function computeSceneObjectBounds(obj, objectMatrices) {
|
|
|
36672
37247
|
}
|
|
36673
37248
|
return isFiniteBox3(out) ? out : null;
|
|
36674
37249
|
}
|
|
37250
|
+
if (obj.curve3d) {
|
|
37251
|
+
const b2 = obj.curve3d.bounds;
|
|
37252
|
+
const out = new Box3();
|
|
37253
|
+
if (!expandBoundsByTransformedAabb(out, b2.min, b2.max, matrix)) return null;
|
|
37254
|
+
return isFiniteBox3(out) ? out : null;
|
|
37255
|
+
}
|
|
36675
37256
|
if (obj.toolpath) {
|
|
36676
37257
|
const b2 = obj.toolpath.bounds;
|
|
36677
37258
|
const out = new Box3();
|
|
@@ -40322,8 +40903,8 @@ const computeExplodeTreeOffsets = (root, explodeAmount, explodeConfig) => {
|
|
|
40322
40903
|
};
|
|
40323
40904
|
const EMPTY_RIG_INSPECTION_OVERLAY_STATE = {
|
|
40324
40905
|
joints: [],
|
|
40325
|
-
|
|
40326
|
-
|
|
40906
|
+
edges: [],
|
|
40907
|
+
kinematicLinks: [],
|
|
40327
40908
|
bounds: null
|
|
40328
40909
|
};
|
|
40329
40910
|
function isFiniteVector(value) {
|
|
@@ -40388,18 +40969,20 @@ function buildRigInspectionOverlayState(args) {
|
|
|
40388
40969
|
joints.forEach((joint) => {
|
|
40389
40970
|
byChild.set(joint.joint.child, joint);
|
|
40390
40971
|
});
|
|
40391
|
-
const
|
|
40392
|
-
const
|
|
40972
|
+
const edges = [];
|
|
40973
|
+
const kinematicLinks = [];
|
|
40393
40974
|
if (args.assemblyKinematics) {
|
|
40394
|
-
const
|
|
40975
|
+
const derivedNames = new Set(args.assemblyKinematics.derivedLinks.map((link) => link.name));
|
|
40976
|
+
const controlledNames = new Set(args.assemblyKinematics.angles.filter((angle) => angle.control).map((angle) => angle.c));
|
|
40395
40977
|
const connectedLinkNames = /* @__PURE__ */ new Set();
|
|
40978
|
+
const positions = new Map(args.assemblyKinematics.links.map((link) => [link.name, new Vector3(...link.position)]));
|
|
40396
40979
|
for (const edge of args.assemblyKinematics.edges) {
|
|
40397
40980
|
const start = positions.get(edge.a);
|
|
40398
40981
|
const end = positions.get(edge.b);
|
|
40399
40982
|
if (!start || !end || start.distanceToSquared(end) <= 1e-8) continue;
|
|
40400
40983
|
connectedLinkNames.add(edge.a);
|
|
40401
40984
|
connectedLinkNames.add(edge.b);
|
|
40402
|
-
|
|
40985
|
+
edges.push({
|
|
40403
40986
|
id: `kinematic:${edge.name}`,
|
|
40404
40987
|
kind: "kinematic",
|
|
40405
40988
|
start,
|
|
@@ -40407,22 +40990,36 @@ function buildRigInspectionOverlayState(args) {
|
|
|
40407
40990
|
hidden: false
|
|
40408
40991
|
});
|
|
40409
40992
|
}
|
|
40993
|
+
for (const edge of args.assemblyKinematics.frameEdges ?? []) {
|
|
40994
|
+
const start = new Vector3(...edge.start);
|
|
40995
|
+
const end = new Vector3(...edge.end);
|
|
40996
|
+
if (!isFiniteVector(start) || !isFiniteVector(end) || start.distanceToSquared(end) <= 1e-8) continue;
|
|
40997
|
+
edges.push({
|
|
40998
|
+
id: `frame-edge:${edge.name}`,
|
|
40999
|
+
kind: "kinematic",
|
|
41000
|
+
start,
|
|
41001
|
+
end,
|
|
41002
|
+
hidden: false
|
|
41003
|
+
});
|
|
41004
|
+
}
|
|
40410
41005
|
for (const link of args.assemblyKinematics.links) {
|
|
40411
41006
|
const position = positions.get(link.name);
|
|
40412
41007
|
if (!position || !isFiniteVector(position)) continue;
|
|
40413
|
-
|
|
41008
|
+
kinematicLinks.push({
|
|
40414
41009
|
id: `kinematic-link:${link.name}`,
|
|
40415
41010
|
name: link.name,
|
|
41011
|
+
kind: derivedNames.has(link.name) ? "derived" : link.fixed ? "fixed" : link.gaugeFixed ? "gauge" : "moving",
|
|
40416
41012
|
position,
|
|
40417
|
-
|
|
40418
|
-
connected: connectedLinkNames.has(link.name)
|
|
41013
|
+
controlled: controlledNames.has(link.name),
|
|
41014
|
+
connected: connectedLinkNames.has(link.name),
|
|
41015
|
+
hidden: false
|
|
40419
41016
|
});
|
|
40420
41017
|
}
|
|
40421
41018
|
}
|
|
40422
41019
|
for (const joint of joints) {
|
|
40423
41020
|
const parentJoint = joint.joint.parent ? byChild.get(joint.joint.parent) : null;
|
|
40424
41021
|
if (parentJoint && parentJoint.pivotWorld.distanceToSquared(joint.pivotWorld) > 1e-8) {
|
|
40425
|
-
|
|
41022
|
+
edges.push({
|
|
40426
41023
|
id: `${joint.joint.name}:hierarchy`,
|
|
40427
41024
|
kind: "hierarchy",
|
|
40428
41025
|
start: parentJoint.pivotWorld,
|
|
@@ -40432,7 +41029,7 @@ function buildRigInspectionOverlayState(args) {
|
|
|
40432
41029
|
}
|
|
40433
41030
|
const center = childCenter(args, joint.joint.child);
|
|
40434
41031
|
if (center && center.distanceToSquared(joint.pivotWorld) > 1e-8) {
|
|
40435
|
-
|
|
41032
|
+
edges.push({
|
|
40436
41033
|
id: `${joint.joint.name}:part`,
|
|
40437
41034
|
kind: "part",
|
|
40438
41035
|
start: joint.pivotWorld,
|
|
@@ -40443,12 +41040,12 @@ function buildRigInspectionOverlayState(args) {
|
|
|
40443
41040
|
}
|
|
40444
41041
|
const bounds = new Box3();
|
|
40445
41042
|
let hasBounds = false;
|
|
40446
|
-
for (const
|
|
40447
|
-
if (expandFinitePoint(bounds,
|
|
41043
|
+
for (const link of kinematicLinks) {
|
|
41044
|
+
if (expandFinitePoint(bounds, link.position)) hasBounds = true;
|
|
40448
41045
|
}
|
|
40449
|
-
for (const
|
|
40450
|
-
if (expandFinitePoint(bounds,
|
|
40451
|
-
if (expandFinitePoint(bounds,
|
|
41046
|
+
for (const edge of edges) {
|
|
41047
|
+
if (expandFinitePoint(bounds, edge.start)) hasBounds = true;
|
|
41048
|
+
if (expandFinitePoint(bounds, edge.end)) hasBounds = true;
|
|
40452
41049
|
}
|
|
40453
41050
|
for (const joint of joints) {
|
|
40454
41051
|
if (expandFinitePoint(bounds, joint.pivotWorld)) hasBounds = true;
|
|
@@ -40459,7 +41056,7 @@ function buildRigInspectionOverlayState(args) {
|
|
|
40459
41056
|
if (hasBounds) {
|
|
40460
41057
|
bounds.expandByScalar(Math.max(2, args.axisLength * 0.12));
|
|
40461
41058
|
}
|
|
40462
|
-
return { joints,
|
|
41059
|
+
return { joints, edges, kinematicLinks, bounds: hasBounds ? bounds : null };
|
|
40463
41060
|
}
|
|
40464
41061
|
const EMPTY_PLANE_RECORD = Object.freeze({});
|
|
40465
41062
|
const EMPTY_CLIPPING_RECORD = Object.freeze({});
|
|
@@ -40641,6 +41238,8 @@ function useViewportState() {
|
|
|
40641
41238
|
const inspectDisplayMode = useForgeStore((s) => s.inspectDisplayMode);
|
|
40642
41239
|
const scanGranularity = useForgeStore((s) => s.scanGranularity);
|
|
40643
41240
|
const inspectPointSampleCount = useForgeStore((s) => s.inspectPointSampleCount);
|
|
41241
|
+
const thicknessColorRange = useForgeStore((s) => s.thicknessColorRange);
|
|
41242
|
+
const setThicknessColorRange = useForgeStore((s) => s.setThicknessColorRange);
|
|
40644
41243
|
const comparisonInspectMode = useForgeStore((s) => s.comparisonInspectMode);
|
|
40645
41244
|
const comparisonCandidateOpacity = useForgeStore((s) => s.comparisonCandidateOpacity);
|
|
40646
41245
|
const comparisonReferenceOpacity = useForgeStore((s) => s.comparisonReferenceOpacity);
|
|
@@ -41032,6 +41631,8 @@ function useViewportState() {
|
|
|
41032
41631
|
inspectChannel,
|
|
41033
41632
|
inspectDisplayMode,
|
|
41034
41633
|
inspectPointSampleCount,
|
|
41634
|
+
thicknessColorRange,
|
|
41635
|
+
setThicknessColorRange,
|
|
41035
41636
|
comparisonInspectMode,
|
|
41036
41637
|
comparisonCandidateOpacity,
|
|
41037
41638
|
comparisonReferenceOpacity,
|
|
@@ -42088,12 +42689,12 @@ const HoverTooltipLayer = reactExports.forwardRef(function HoverTooltipLayer2({
|
|
|
42088
42689
|
top: 0,
|
|
42089
42690
|
display: "none",
|
|
42090
42691
|
zIndex: 15,
|
|
42091
|
-
background: "var(--fc-floating-panel-bg, #111111d9)",
|
|
42692
|
+
background: "var(--fc-floating-panel-bg, var(--fc-bgPanel, #111111d9))",
|
|
42092
42693
|
color: "var(--fc-text, #f2f2f2)",
|
|
42093
42694
|
padding: "3px 7px",
|
|
42094
42695
|
borderRadius: "var(--fc-floating-panel-radius, 4px)",
|
|
42095
|
-
border: "1px solid var(--fc-floating-panel-border, #2a2a2a)",
|
|
42096
|
-
boxShadow: "var(--fc-floating-panel-shadow,
|
|
42696
|
+
border: "1px solid var(--fc-floating-panel-border, var(--fc-border, #2a2a2a))",
|
|
42697
|
+
boxShadow: "var(--fc-floating-panel-shadow, 0 8px 20px rgba(0, 0, 0, 0.18))",
|
|
42097
42698
|
fontFamily: "var(--fc-hud-font, inherit)",
|
|
42098
42699
|
fontSize: 11,
|
|
42099
42700
|
fontWeight: 600,
|
|
@@ -42424,10 +43025,12 @@ function RenderLabelsOverlay({ labels }) {
|
|
|
42424
43025
|
if (labels.length === 0) return null;
|
|
42425
43026
|
return /* @__PURE__ */ jsxRuntimeExports.jsx("group", { renderOrder: 12, children: labels.map((label) => /* @__PURE__ */ jsxRuntimeExports.jsx(RenderLabelItem, { label }, label.id)) });
|
|
42426
43027
|
}
|
|
42427
|
-
function
|
|
42428
|
-
const segment = reactExports.useMemo(() => resolveSegmentMeshTransform(
|
|
43028
|
+
function RigEdge({ edge, radius }) {
|
|
43029
|
+
const segment = reactExports.useMemo(() => resolveSegmentMeshTransform(edge.start, edge.end), [edge.end, edge.start]);
|
|
42429
43030
|
if (!segment) return null;
|
|
42430
|
-
const color2 = rgbToHex(
|
|
43031
|
+
const color2 = rgbToHex(
|
|
43032
|
+
edge.hidden ? RIG_HIDDEN_LINK_COLOR : edge.kind === "part" ? RIG_PART_LINK_COLOR : edge.kind === "kinematic" ? RIG_KINEMATIC_EDGE_COLOR : RIG_LINK_COLOR
|
|
43033
|
+
);
|
|
42431
43034
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
42432
43035
|
"mesh",
|
|
42433
43036
|
{
|
|
@@ -42437,16 +43040,35 @@ function RigLink({ link, radius }) {
|
|
|
42437
43040
|
userData: { measureHelper: true },
|
|
42438
43041
|
children: [
|
|
42439
43042
|
/* @__PURE__ */ jsxRuntimeExports.jsx("cylinderGeometry", { args: [radius, radius, segment.length, 16] }),
|
|
42440
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("meshBasicMaterial", { color: color2, depthTest: false, transparent: true, opacity:
|
|
43043
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("meshBasicMaterial", { color: color2, depthTest: false, transparent: true, opacity: edge.hidden ? 0.72 : 0.96, toneMapped: false })
|
|
42441
43044
|
]
|
|
42442
43045
|
}
|
|
42443
43046
|
);
|
|
42444
43047
|
}
|
|
42445
|
-
function
|
|
42446
|
-
|
|
42447
|
-
|
|
42448
|
-
|
|
42449
|
-
|
|
43048
|
+
function colorForKinematicLink(link) {
|
|
43049
|
+
if (link.kind === "fixed" || link.kind === "gauge") return rgbToHex(RIG_FIXED_LINK_COLOR);
|
|
43050
|
+
if (link.kind === "derived") return rgbToHex(RIG_DERIVED_LINK_COLOR);
|
|
43051
|
+
return rgbToHex(link.connected ? RIG_KINEMATIC_LINK_COLOR : RIG_PART_LINK_COLOR);
|
|
43052
|
+
}
|
|
43053
|
+
function RigKinematicLinkPin({ link, radius }) {
|
|
43054
|
+
const color2 = colorForKinematicLink(link);
|
|
43055
|
+
const position = [link.position.x, link.position.y, link.position.z];
|
|
43056
|
+
const markerRadius = link.kind === "derived" || !link.connected ? radius * 0.72 : radius;
|
|
43057
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("group", { position, renderOrder: 94, userData: { measureHelper: true }, children: [
|
|
43058
|
+
link.kind === "fixed" || link.kind === "gauge" ? /* @__PURE__ */ jsxRuntimeExports.jsxs("mesh", { renderOrder: 94, userData: { measureHelper: true }, children: [
|
|
43059
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("boxGeometry", { args: [radius * 1.75, radius * 1.75, radius * 1.05] }),
|
|
43060
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("meshBasicMaterial", { color: color2, depthTest: false, transparent: true, opacity: 0.98, toneMapped: false })
|
|
43061
|
+
] }) : link.kind === "derived" || !link.connected ? /* @__PURE__ */ jsxRuntimeExports.jsxs("mesh", { renderOrder: 94, userData: { measureHelper: true }, children: [
|
|
43062
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("torusGeometry", { args: [markerRadius * 0.82, markerRadius * 0.18, 8, 24] }),
|
|
43063
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("meshBasicMaterial", { color: color2, depthTest: false, transparent: true, opacity: 0.98, toneMapped: false })
|
|
43064
|
+
] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("mesh", { renderOrder: 94, userData: { measureHelper: true }, children: [
|
|
43065
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("sphereGeometry", { args: [markerRadius, 18, 18] }),
|
|
43066
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("meshBasicMaterial", { color: color2, depthTest: false, transparent: true, opacity: 0.98, toneMapped: false })
|
|
43067
|
+
] }),
|
|
43068
|
+
link.controlled && /* @__PURE__ */ jsxRuntimeExports.jsxs("mesh", { renderOrder: 95, userData: { measureHelper: true }, children: [
|
|
43069
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("torusGeometry", { args: [radius * 1.32, radius * 0.12, 8, 28] }),
|
|
43070
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("meshBasicMaterial", { color: rgbToHex(RIG_CONTROL_LINK_COLOR), depthTest: false, transparent: true, opacity: 0.98, toneMapped: false })
|
|
43071
|
+
] })
|
|
42450
43072
|
] });
|
|
42451
43073
|
}
|
|
42452
43074
|
function RigInspectionOverlay({ state: state2, config }) {
|
|
@@ -42462,16 +43084,21 @@ function RigInspectionOverlay({ state: state2, config }) {
|
|
|
42462
43084
|
[config, hiddenColor]
|
|
42463
43085
|
);
|
|
42464
43086
|
const maxAxisLength = reactExports.useMemo(() => state2.joints.reduce((max2, joint) => Math.max(max2, joint.axisLength), 0), [state2.joints]);
|
|
42465
|
-
const
|
|
42466
|
-
|
|
42467
|
-
config.
|
|
42468
|
-
config.
|
|
43087
|
+
const scaleBasis = Math.max(maxAxisLength, config.axisLengthMin);
|
|
43088
|
+
const edgeRadius = MathUtils.clamp(
|
|
43089
|
+
scaleBasis * config.axisLineRadiusScale * 1.15,
|
|
43090
|
+
config.axisLineRadiusMin * 1.15,
|
|
43091
|
+
config.axisLineRadiusMax * 1.75
|
|
42469
43092
|
);
|
|
42470
|
-
const
|
|
42471
|
-
|
|
43093
|
+
const linkPinRadius = MathUtils.clamp(
|
|
43094
|
+
scaleBasis * config.axisDotRadiusScale * 3.2,
|
|
43095
|
+
config.axisDotRadiusMin * 2.2,
|
|
43096
|
+
config.axisLineRadiusMax * 3.2
|
|
43097
|
+
);
|
|
43098
|
+
if (state2.joints.length === 0 && state2.edges.length === 0 && state2.kinematicLinks.length === 0) return null;
|
|
42472
43099
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("group", { children: [
|
|
42473
|
-
state2.
|
|
42474
|
-
state2.
|
|
43100
|
+
state2.edges.map((edge) => /* @__PURE__ */ jsxRuntimeExports.jsx(RigEdge, { edge, radius: edgeRadius }, edge.id)),
|
|
43101
|
+
state2.kinematicLinks.map((link) => /* @__PURE__ */ jsxRuntimeExports.jsx(RigKinematicLinkPin, { link, radius: linkPinRadius }, link.id)),
|
|
42475
43102
|
state2.joints.map((joint) => /* @__PURE__ */ jsxRuntimeExports.jsx(HoveredJointOverlay, { state: joint, config: joint.hidden ? hiddenConfig : config }, joint.joint.name))
|
|
42476
43103
|
] });
|
|
42477
43104
|
}
|
|
@@ -42647,12 +43274,12 @@ function useGeometryComparison(args) {
|
|
|
42647
43274
|
class InspectWorkerClient {
|
|
42648
43275
|
constructor(workerFactory = () => new Worker(new URL(
|
|
42649
43276
|
/* @vite-ignore */
|
|
42650
|
-
"/assets/inspectWorker-
|
|
43277
|
+
"/assets/inspectWorker-BuTJDVX6.js",
|
|
42651
43278
|
import.meta.url
|
|
42652
43279
|
), { type: "module" })) {
|
|
42653
43280
|
__publicField(this, "worker", null);
|
|
42654
43281
|
__publicField(this, "reqId", 0);
|
|
42655
|
-
__publicField(this, "pending",
|
|
43282
|
+
__publicField(this, "pending", /* @__PURE__ */ new Map());
|
|
42656
43283
|
this.workerFactory = workerFactory;
|
|
42657
43284
|
}
|
|
42658
43285
|
getWorker() {
|
|
@@ -42660,9 +43287,9 @@ class InspectWorkerClient {
|
|
|
42660
43287
|
this.worker = this.workerFactory();
|
|
42661
43288
|
this.worker.onmessage = (event) => {
|
|
42662
43289
|
const data = event.data;
|
|
42663
|
-
const pending = this.pending;
|
|
43290
|
+
const pending = this.pending.get(data.payload.reqId);
|
|
42664
43291
|
if (!pending) return;
|
|
42665
|
-
this.pending
|
|
43292
|
+
this.pending.delete(data.payload.reqId);
|
|
42666
43293
|
if (data.type === "inspect-error") {
|
|
42667
43294
|
pending.reject(new Error(data.payload.message));
|
|
42668
43295
|
} else {
|
|
@@ -42670,22 +43297,28 @@ class InspectWorkerClient {
|
|
|
42670
43297
|
}
|
|
42671
43298
|
};
|
|
42672
43299
|
this.worker.onerror = (event) => {
|
|
42673
|
-
var _a3
|
|
43300
|
+
var _a3;
|
|
42674
43301
|
const error = new Error(event.message || "Inspect worker failed unexpectedly.");
|
|
42675
|
-
|
|
42676
|
-
this.pending
|
|
42677
|
-
(
|
|
43302
|
+
this.pending.forEach((pending) => pending.reject(error));
|
|
43303
|
+
this.pending.clear();
|
|
43304
|
+
(_a3 = this.worker) == null ? void 0 : _a3.terminate();
|
|
42678
43305
|
this.worker = null;
|
|
42679
43306
|
};
|
|
42680
43307
|
return this.worker;
|
|
42681
43308
|
}
|
|
42682
43309
|
replaceActiveWorker() {
|
|
42683
|
-
var _a3
|
|
42684
|
-
|
|
42685
|
-
this.pending
|
|
42686
|
-
(
|
|
43310
|
+
var _a3;
|
|
43311
|
+
this.pending.forEach((pending) => pending.reject(new Error("cancelled")));
|
|
43312
|
+
this.pending.clear();
|
|
43313
|
+
(_a3 = this.worker) == null ? void 0 : _a3.terminate();
|
|
42687
43314
|
this.worker = null;
|
|
42688
43315
|
}
|
|
43316
|
+
postRequest(request, transfers = []) {
|
|
43317
|
+
return new Promise((resolve2, reject) => {
|
|
43318
|
+
this.pending.set(request.payload.reqId, { resolve: resolve2, reject });
|
|
43319
|
+
this.getWorker().postMessage(request, transfers);
|
|
43320
|
+
});
|
|
43321
|
+
}
|
|
42689
43322
|
analyze(payload) {
|
|
42690
43323
|
if (this.pending) this.replaceActiveWorker();
|
|
42691
43324
|
const reqId = ++this.reqId;
|
|
@@ -42705,10 +43338,18 @@ class InspectWorkerClient {
|
|
|
42705
43338
|
object.collisionShape.mergeToVert.buffer
|
|
42706
43339
|
] : []
|
|
42707
43340
|
]);
|
|
42708
|
-
return
|
|
42709
|
-
|
|
42710
|
-
|
|
42711
|
-
|
|
43341
|
+
return this.postRequest(request, transfers);
|
|
43342
|
+
}
|
|
43343
|
+
colorizeThickness(payload) {
|
|
43344
|
+
const reqId = ++this.reqId;
|
|
43345
|
+
const request = {
|
|
43346
|
+
type: "colorize-thickness",
|
|
43347
|
+
payload: {
|
|
43348
|
+
reqId,
|
|
43349
|
+
...payload
|
|
43350
|
+
}
|
|
43351
|
+
};
|
|
43352
|
+
return this.postRequest(request);
|
|
42712
43353
|
}
|
|
42713
43354
|
dispose() {
|
|
42714
43355
|
this.replaceActiveWorker();
|
|
@@ -43039,6 +43680,7 @@ function analyzePayloadFor(channel, objects, inspectPointSampleCount, groundZ, w
|
|
|
43039
43680
|
}
|
|
43040
43681
|
function resultToState(channel, result) {
|
|
43041
43682
|
return {
|
|
43683
|
+
analysisId: result.analysisId,
|
|
43042
43684
|
status: "ready",
|
|
43043
43685
|
channel,
|
|
43044
43686
|
objectColors: result.objectColors,
|
|
@@ -43061,7 +43703,8 @@ function resultToState(channel, result) {
|
|
|
43061
43703
|
{
|
|
43062
43704
|
sampleCount: object.sampleCount,
|
|
43063
43705
|
positions: object.positions,
|
|
43064
|
-
colors: object.colors
|
|
43706
|
+
colors: object.colors,
|
|
43707
|
+
values: object.values
|
|
43065
43708
|
}
|
|
43066
43709
|
])
|
|
43067
43710
|
),
|
|
@@ -43069,8 +43712,40 @@ function resultToState(channel, result) {
|
|
|
43069
43712
|
error: null
|
|
43070
43713
|
};
|
|
43071
43714
|
}
|
|
43715
|
+
function applyThicknessColorizeResult(state2, result) {
|
|
43716
|
+
if (state2.channel !== "thickness" || state2.status !== "ready") return state2;
|
|
43717
|
+
if (state2.analysisId !== result.analysisId) return state2;
|
|
43718
|
+
const colorsByObjectId = new Map(result.pointObjects.map((object) => [object.objectId, object.colors]));
|
|
43719
|
+
const pointClouds = Object.fromEntries(
|
|
43720
|
+
Object.entries(state2.pointClouds).map(([objectId, pointCloud]) => [
|
|
43721
|
+
objectId,
|
|
43722
|
+
{
|
|
43723
|
+
...pointCloud,
|
|
43724
|
+
colors: colorsByObjectId.get(objectId) ?? pointCloud.colors
|
|
43725
|
+
}
|
|
43726
|
+
])
|
|
43727
|
+
);
|
|
43728
|
+
return {
|
|
43729
|
+
...state2,
|
|
43730
|
+
pointClouds,
|
|
43731
|
+
heatmapFields: Object.fromEntries(
|
|
43732
|
+
result.heatmapFieldObjects.map((object) => [
|
|
43733
|
+
object.objectId,
|
|
43734
|
+
{
|
|
43735
|
+
data: object.data,
|
|
43736
|
+
boundsMin: object.boundsMin,
|
|
43737
|
+
boundsSize: object.boundsSize,
|
|
43738
|
+
gridSize: object.gridSize
|
|
43739
|
+
}
|
|
43740
|
+
])
|
|
43741
|
+
)
|
|
43742
|
+
};
|
|
43743
|
+
}
|
|
43744
|
+
function thicknessColorRangeKey(range) {
|
|
43745
|
+
return `${range.min}:${range.max}`;
|
|
43746
|
+
}
|
|
43072
43747
|
function useInspectWorkerAnalysis(args) {
|
|
43073
|
-
const [
|
|
43748
|
+
const [rawState, setRawState] = reactExports.useState({
|
|
43074
43749
|
status: "idle",
|
|
43075
43750
|
channel: "none",
|
|
43076
43751
|
objectColors: {},
|
|
@@ -43081,10 +43756,11 @@ function useInspectWorkerAnalysis(args) {
|
|
|
43081
43756
|
warnings: [],
|
|
43082
43757
|
error: null
|
|
43083
43758
|
});
|
|
43759
|
+
const [colorizedState, setColorizedState] = reactExports.useState(null);
|
|
43084
43760
|
reactExports.useEffect(() => {
|
|
43085
43761
|
if (!WORKER_CHANNELS.has(args.inspectChannel)) {
|
|
43086
43762
|
inspectWorkerClient.dispose();
|
|
43087
|
-
|
|
43763
|
+
setRawState({
|
|
43088
43764
|
status: "idle",
|
|
43089
43765
|
channel: args.inspectChannel,
|
|
43090
43766
|
objectColors: {},
|
|
@@ -43099,7 +43775,7 @@ function useInspectWorkerAnalysis(args) {
|
|
|
43099
43775
|
}
|
|
43100
43776
|
let cancelled = false;
|
|
43101
43777
|
const channel = args.inspectChannel;
|
|
43102
|
-
|
|
43778
|
+
setRawState({
|
|
43103
43779
|
status: "loading",
|
|
43104
43780
|
channel: args.inspectChannel,
|
|
43105
43781
|
objectColors: {},
|
|
@@ -43133,12 +43809,13 @@ function useInspectWorkerAnalysis(args) {
|
|
|
43133
43809
|
)
|
|
43134
43810
|
);
|
|
43135
43811
|
if (cancelled) return;
|
|
43136
|
-
|
|
43812
|
+
setRawState(resultToState(args.inspectChannel, result));
|
|
43813
|
+
setColorizedState(null);
|
|
43137
43814
|
} catch (error) {
|
|
43138
43815
|
if (cancelled || error instanceof InspectBuildCancelledError || error instanceof Error && error.message === "cancelled") {
|
|
43139
43816
|
return;
|
|
43140
43817
|
}
|
|
43141
|
-
|
|
43818
|
+
setRawState({
|
|
43142
43819
|
status: "error",
|
|
43143
43820
|
channel: args.inspectChannel,
|
|
43144
43821
|
objectColors: {},
|
|
@@ -43164,7 +43841,179 @@ function useInspectWorkerAnalysis(args) {
|
|
|
43164
43841
|
args.objectMatrices,
|
|
43165
43842
|
args.groundZ
|
|
43166
43843
|
]);
|
|
43167
|
-
|
|
43844
|
+
reactExports.useEffect(() => {
|
|
43845
|
+
if (rawState.status !== "ready" || rawState.channel !== "thickness" || rawState.analysisId === void 0) {
|
|
43846
|
+
setColorizedState(null);
|
|
43847
|
+
return;
|
|
43848
|
+
}
|
|
43849
|
+
let cancelled = false;
|
|
43850
|
+
const analysisId = rawState.analysisId;
|
|
43851
|
+
const rangeKey22 = thicknessColorRangeKey(args.thicknessColorRange);
|
|
43852
|
+
void inspectWorkerClient.colorizeThickness({
|
|
43853
|
+
analysisId,
|
|
43854
|
+
colorMinThickness: args.thicknessColorRange.min,
|
|
43855
|
+
colorMaxThickness: args.thicknessColorRange.max
|
|
43856
|
+
}).then((result) => {
|
|
43857
|
+
if (cancelled) return;
|
|
43858
|
+
setColorizedState({
|
|
43859
|
+
analysisId,
|
|
43860
|
+
rangeKey: rangeKey22,
|
|
43861
|
+
state: applyThicknessColorizeResult(rawState, result)
|
|
43862
|
+
});
|
|
43863
|
+
}).catch((error) => {
|
|
43864
|
+
if (cancelled || error instanceof Error && error.message === "cancelled") return;
|
|
43865
|
+
setColorizedState(null);
|
|
43866
|
+
});
|
|
43867
|
+
return () => {
|
|
43868
|
+
cancelled = true;
|
|
43869
|
+
};
|
|
43870
|
+
}, [args.thicknessColorRange, rawState]);
|
|
43871
|
+
const rangeKey2 = thicknessColorRangeKey(args.thicknessColorRange);
|
|
43872
|
+
if (rawState.status === "ready" && rawState.channel === "thickness" && rawState.analysisId !== void 0 && (colorizedState == null ? void 0 : colorizedState.analysisId) === rawState.analysisId && colorizedState.rangeKey === rangeKey2) {
|
|
43873
|
+
return colorizedState.state;
|
|
43874
|
+
}
|
|
43875
|
+
return rawState;
|
|
43876
|
+
}
|
|
43877
|
+
function voxelCellKey(cell) {
|
|
43878
|
+
return `${cell.x},${cell.y},${cell.z}`;
|
|
43879
|
+
}
|
|
43880
|
+
function resolveVoxelIntentCellSize(cellSize) {
|
|
43881
|
+
return Math.max(1, Number.isFinite(cellSize) ? cellSize : 10);
|
|
43882
|
+
}
|
|
43883
|
+
function voxelCellFromPoint(point, cellSize) {
|
|
43884
|
+
return {
|
|
43885
|
+
x: Math.floor(point.x / cellSize),
|
|
43886
|
+
y: Math.floor(point.y / cellSize),
|
|
43887
|
+
z: Math.floor(point.z / cellSize)
|
|
43888
|
+
};
|
|
43889
|
+
}
|
|
43890
|
+
function dominantAxis(normal) {
|
|
43891
|
+
const ax = Math.abs(normal.x);
|
|
43892
|
+
const ay = Math.abs(normal.y);
|
|
43893
|
+
const az = Math.abs(normal.z);
|
|
43894
|
+
if (ax >= ay && ax >= az) return "x";
|
|
43895
|
+
if (ay >= ax && ay >= az) return "y";
|
|
43896
|
+
return "z";
|
|
43897
|
+
}
|
|
43898
|
+
function anchoredCellIndex(value, cellSize, direction) {
|
|
43899
|
+
const scaled = value / cellSize;
|
|
43900
|
+
const base = Math.floor(scaled);
|
|
43901
|
+
const onBoundary = Math.abs(scaled - Math.round(scaled)) < 1e-7;
|
|
43902
|
+
return onBoundary && direction < 0 ? base - 1 : base;
|
|
43903
|
+
}
|
|
43904
|
+
function voxelCellFromSurfaceAnchor(point, normal, cellSize, side) {
|
|
43905
|
+
const cell = voxelCellFromPoint(point, cellSize);
|
|
43906
|
+
const axis = dominantAxis(normal);
|
|
43907
|
+
const normalValue = normal[axis];
|
|
43908
|
+
const outsideDirection = normalValue < 0 ? -1 : 1;
|
|
43909
|
+
const direction = side === "outside" ? outsideDirection : -outsideDirection;
|
|
43910
|
+
cell[axis] = anchoredCellIndex(point[axis], cellSize, direction);
|
|
43911
|
+
return cell;
|
|
43912
|
+
}
|
|
43913
|
+
function parseVoxelCellKey(key) {
|
|
43914
|
+
const [x, y, z] = key.split(",").map(Number);
|
|
43915
|
+
return { x, y, z };
|
|
43916
|
+
}
|
|
43917
|
+
function addVoxelCells(a2, b2) {
|
|
43918
|
+
return { x: a2.x + b2.x, y: a2.y + b2.y, z: a2.z + b2.z };
|
|
43919
|
+
}
|
|
43920
|
+
function voxelCellCenter(cell, cellSize) {
|
|
43921
|
+
return [(cell.x + 0.5) * cellSize, (cell.y + 0.5) * cellSize, (cell.z + 0.5) * cellSize];
|
|
43922
|
+
}
|
|
43923
|
+
const VOXEL_INTENT_TOOL_COLORS = {
|
|
43924
|
+
red: "#ef4444",
|
|
43925
|
+
green: "#22c55e",
|
|
43926
|
+
blue: "#3b82f6",
|
|
43927
|
+
yellow: "#facc15",
|
|
43928
|
+
white: "#f8fafc",
|
|
43929
|
+
erase: "#a855f7"
|
|
43930
|
+
};
|
|
43931
|
+
const VOXEL_INTENT_TOOL_LABELS = {
|
|
43932
|
+
red: { label: "Red", detail: "mark a red thing to explain in chat" },
|
|
43933
|
+
green: { label: "Green", detail: "mark a green thing to explain in chat" },
|
|
43934
|
+
blue: { label: "Blue", detail: "mark a blue thing to explain in chat" },
|
|
43935
|
+
yellow: { label: "Yellow", detail: "mark a yellow thing to explain in chat" },
|
|
43936
|
+
white: { label: "White", detail: "mark a neutral thing to explain in chat" },
|
|
43937
|
+
erase: { label: "Eraser", detail: "delete the first marker block clicked" }
|
|
43938
|
+
};
|
|
43939
|
+
const VOXEL_INTENT_TOOL_ORDER = ["red", "green", "blue", "yellow", "white", "erase"];
|
|
43940
|
+
const VOXEL_INTENT_PLACEMENT_LABELS = {
|
|
43941
|
+
surface: { label: "Surface", detail: "place outside the clicked face" },
|
|
43942
|
+
inside: { label: "Inside", detail: "place just under the first clicked surface" },
|
|
43943
|
+
through: { label: "Through", detail: "place between the first and second surface hits" },
|
|
43944
|
+
grid: { label: "Grid", detail: "place from the click point in the global grid" }
|
|
43945
|
+
};
|
|
43946
|
+
const VOXEL_INTENT_PLACEMENT_ORDER = ["surface", "inside", "through", "grid"];
|
|
43947
|
+
function directionFromFace(event) {
|
|
43948
|
+
var _a3;
|
|
43949
|
+
const normal = (_a3 = event.face) == null ? void 0 : _a3.normal;
|
|
43950
|
+
if (!normal) return { x: 0, y: 0, z: 1 };
|
|
43951
|
+
const values = [
|
|
43952
|
+
{ axis: "x", value: normal.x },
|
|
43953
|
+
{ axis: "y", value: normal.y },
|
|
43954
|
+
{ axis: "z", value: normal.z }
|
|
43955
|
+
];
|
|
43956
|
+
values.sort((a2, b2) => Math.abs(b2.value) - Math.abs(a2.value));
|
|
43957
|
+
const strongest = values[0];
|
|
43958
|
+
return {
|
|
43959
|
+
x: strongest.axis === "x" ? Math.sign(strongest.value) || 1 : 0,
|
|
43960
|
+
y: strongest.axis === "y" ? Math.sign(strongest.value) || 1 : 0,
|
|
43961
|
+
z: strongest.axis === "z" ? Math.sign(strongest.value) || 1 : 0
|
|
43962
|
+
};
|
|
43963
|
+
}
|
|
43964
|
+
function VoxelIntentCellMesh({
|
|
43965
|
+
cell,
|
|
43966
|
+
color: color2,
|
|
43967
|
+
cellSize,
|
|
43968
|
+
opacity,
|
|
43969
|
+
onClick
|
|
43970
|
+
}) {
|
|
43971
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("mesh", { position: voxelCellCenter(cell, cellSize), onClick, renderOrder: 60, userData: { voxelIntentCell: cell }, children: [
|
|
43972
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("boxGeometry", { args: [cellSize * 0.96, cellSize * 0.96, cellSize * 0.96] }),
|
|
43973
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("meshStandardMaterial", { color: color2, roughness: 0.62, metalness: 0.04, transparent: true, opacity, depthWrite: opacity > 0.55 })
|
|
43974
|
+
] });
|
|
43975
|
+
}
|
|
43976
|
+
function VoxelIntentOverlay() {
|
|
43977
|
+
const tool = useForgeStore((s) => s.voxelIntentTool);
|
|
43978
|
+
const placement = useForgeStore((s) => s.voxelIntentPlacement);
|
|
43979
|
+
const cellSize = useForgeStore((s) => s.voxelIntentCellSize);
|
|
43980
|
+
const blocks = useForgeStore((s) => s.voxelIntentBlocks);
|
|
43981
|
+
const cellSizePreviewVisible = useForgeStore((s) => s.voxelIntentCellSizePreviewVisible);
|
|
43982
|
+
const setBlock = useForgeStore((s) => s.setVoxelIntentBlock);
|
|
43983
|
+
const eraseBlock = useForgeStore((s) => s.eraseVoxelIntentBlock);
|
|
43984
|
+
const resolvedCellSize = resolveVoxelIntentCellSize(cellSize);
|
|
43985
|
+
const blockEntries = reactExports.useMemo(() => Object.entries(blocks).map(([key, block]) => ({ cell: parseVoxelCellKey(key), block })), [blocks]);
|
|
43986
|
+
const occupied = (cell) => voxelCellKey(cell) in blocks;
|
|
43987
|
+
const placeAdjacentTo = (blockCell, event) => {
|
|
43988
|
+
event.stopPropagation();
|
|
43989
|
+
if (tool === "erase") {
|
|
43990
|
+
const clickedCell = event.object.userData.voxelIntentCell ?? blockCell;
|
|
43991
|
+
eraseBlock(clickedCell);
|
|
43992
|
+
return;
|
|
43993
|
+
}
|
|
43994
|
+
const faceCandidate = addVoxelCells(blockCell, directionFromFace(event));
|
|
43995
|
+
if (!occupied(faceCandidate)) {
|
|
43996
|
+
setBlock(faceCandidate, { groupId: tool, placement });
|
|
43997
|
+
return;
|
|
43998
|
+
}
|
|
43999
|
+
};
|
|
44000
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("group", { children: [
|
|
44001
|
+
cellSizePreviewVisible && /* @__PURE__ */ jsxRuntimeExports.jsxs("mesh", { position: voxelCellCenter({ x: 0, y: 0, z: 0 }, resolvedCellSize), renderOrder: 55, raycast: () => null, children: [
|
|
44002
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("boxGeometry", { args: [resolvedCellSize, resolvedCellSize, resolvedCellSize] }),
|
|
44003
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("meshStandardMaterial", { color: "#22d3ee", emissive: "#0891b2", emissiveIntensity: 0.42, roughness: 0.28, metalness: 0.02 })
|
|
44004
|
+
] }),
|
|
44005
|
+
blockEntries.map(({ cell, block }) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
44006
|
+
VoxelIntentCellMesh,
|
|
44007
|
+
{
|
|
44008
|
+
cell,
|
|
44009
|
+
color: VOXEL_INTENT_TOOL_COLORS[block.groupId] ?? VOXEL_INTENT_TOOL_COLORS.white,
|
|
44010
|
+
cellSize: resolvedCellSize,
|
|
44011
|
+
opacity: 0.92,
|
|
44012
|
+
onClick: (event) => placeAdjacentTo(cell, event)
|
|
44013
|
+
},
|
|
44014
|
+
`block:${voxelCellKey(cell)}`
|
|
44015
|
+
))
|
|
44016
|
+
] });
|
|
43168
44017
|
}
|
|
43169
44018
|
function buildManualSceneConfig(base, manualScene, renderStylePreset) {
|
|
43170
44019
|
var _a3, _b2, _c;
|
|
@@ -43480,6 +44329,15 @@ function Viewport() {
|
|
|
43480
44329
|
const buildLedgerEvents = useForgeStore((s) => s.buildLedgerEvents);
|
|
43481
44330
|
const measureSelections = useForgeStore((s) => s.measureSelections);
|
|
43482
44331
|
const meshPreviewFile = useForgeStore((s) => s.meshPreviewFile);
|
|
44332
|
+
const voxelIntentMode = useForgeStore((s) => s.voxelIntentMode);
|
|
44333
|
+
const voxelIntentTool = useForgeStore((s) => s.voxelIntentTool);
|
|
44334
|
+
const voxelIntentPlacement = useForgeStore((s) => s.voxelIntentPlacement);
|
|
44335
|
+
const voxelIntentCellSizeValue = useForgeStore((s) => s.voxelIntentCellSize);
|
|
44336
|
+
const voxelIntentGhostOpacity = useForgeStore((s) => s.voxelIntentGhostOpacity);
|
|
44337
|
+
const voxelIntentBlocks = useForgeStore((s) => s.voxelIntentBlocks);
|
|
44338
|
+
const setVoxelIntentBlock = useForgeStore((s) => s.setVoxelIntentBlock);
|
|
44339
|
+
const eraseVoxelIntentBlock = useForgeStore((s) => s.eraseVoxelIntentBlock);
|
|
44340
|
+
const setVoxelIntentContextFile = useForgeStore((s) => s.setVoxelIntentContextFile);
|
|
43483
44341
|
const isSvgActive = !!activeFile && activeFile.toLowerCase().endsWith(".svg");
|
|
43484
44342
|
const state2 = useViewportState();
|
|
43485
44343
|
const {
|
|
@@ -43494,6 +44352,8 @@ function Viewport() {
|
|
|
43494
44352
|
inspectChannel,
|
|
43495
44353
|
inspectDisplayMode,
|
|
43496
44354
|
inspectPointSampleCount,
|
|
44355
|
+
thicknessColorRange,
|
|
44356
|
+
setThicknessColorRange,
|
|
43497
44357
|
comparisonInspectMode,
|
|
43498
44358
|
comparisonCandidateOpacity,
|
|
43499
44359
|
projectionMode,
|
|
@@ -43566,6 +44426,7 @@ function Viewport() {
|
|
|
43566
44426
|
previewFile,
|
|
43567
44427
|
knownFileNames
|
|
43568
44428
|
} = state2;
|
|
44429
|
+
const voxelContextFile = previewFile ?? ((activeFile == null ? void 0 : activeFile.toLowerCase().endsWith(".forge.js")) ? activeFile : null);
|
|
43569
44430
|
const historyMode = useForgeStore((s) => s.historyMode);
|
|
43570
44431
|
const historyObjectIds = useForgeStore((s) => s.historyObjectIds);
|
|
43571
44432
|
useHistoryPlaybackLoop();
|
|
@@ -43632,6 +44493,7 @@ function Viewport() {
|
|
|
43632
44493
|
const inspectAnalysis = useInspectWorkerAnalysis({
|
|
43633
44494
|
inspectChannel: comparisonInspectActive ? "none" : inspectChannel,
|
|
43634
44495
|
inspectPointSampleCount,
|
|
44496
|
+
thicknessColorRange,
|
|
43635
44497
|
sceneVersion,
|
|
43636
44498
|
objects,
|
|
43637
44499
|
objectSettings,
|
|
@@ -43656,7 +44518,7 @@ function Viewport() {
|
|
|
43656
44518
|
const handlers = useViewportHandlers({
|
|
43657
44519
|
containerRef,
|
|
43658
44520
|
contextMenuRef,
|
|
43659
|
-
measureMode,
|
|
44521
|
+
measureMode: measureMode || voxelIntentMode,
|
|
43660
44522
|
isViewportInteracting,
|
|
43661
44523
|
objectPickSyncEnabled,
|
|
43662
44524
|
hoveredObjectId,
|
|
@@ -43701,6 +44563,100 @@ function Viewport() {
|
|
|
43701
44563
|
handlePerformanceInfoChange,
|
|
43702
44564
|
handleViewPersistenceResolved: handleViewPersistenceResolvedFromHandlers
|
|
43703
44565
|
} = handlers;
|
|
44566
|
+
reactExports.useEffect(() => {
|
|
44567
|
+
setVoxelIntentContextFile(voxelContextFile);
|
|
44568
|
+
}, [setVoxelIntentContextFile, voxelContextFile]);
|
|
44569
|
+
const voxelCellKey2 = (cell) => `${cell.x},${cell.y},${cell.z}`;
|
|
44570
|
+
const addVoxelCells2 = (a2, b2) => ({ x: a2.x + b2.x, y: a2.y + b2.y, z: a2.z + b2.z });
|
|
44571
|
+
const voxelNormalFromBoxHit = (point, bounds) => {
|
|
44572
|
+
const candidates = [
|
|
44573
|
+
{ normal: { x: -1, y: 0, z: 0 }, distance: Math.abs(point.x - bounds.min.x) },
|
|
44574
|
+
{ normal: { x: 1, y: 0, z: 0 }, distance: Math.abs(point.x - bounds.max.x) },
|
|
44575
|
+
{ normal: { x: 0, y: -1, z: 0 }, distance: Math.abs(point.y - bounds.min.y) },
|
|
44576
|
+
{ normal: { x: 0, y: 1, z: 0 }, distance: Math.abs(point.y - bounds.max.y) },
|
|
44577
|
+
{ normal: { x: 0, y: 0, z: -1 }, distance: Math.abs(point.z - bounds.min.z) },
|
|
44578
|
+
{ normal: { x: 0, y: 0, z: 1 }, distance: Math.abs(point.z - bounds.max.z) }
|
|
44579
|
+
];
|
|
44580
|
+
candidates.sort((a2, b2) => a2.distance - b2.distance);
|
|
44581
|
+
return candidates[0].normal;
|
|
44582
|
+
};
|
|
44583
|
+
const voxelBlockHitsOnRay = (ray, cellSize) => {
|
|
44584
|
+
const hits = [];
|
|
44585
|
+
const halfExtent = cellSize * 0.55;
|
|
44586
|
+
const hitPoint = new Vector3();
|
|
44587
|
+
for (const key of Object.keys(voxelIntentBlocks)) {
|
|
44588
|
+
const [x, y, z] = key.split(",").map(Number);
|
|
44589
|
+
const center = new Vector3((x + 0.5) * cellSize, (y + 0.5) * cellSize, (z + 0.5) * cellSize);
|
|
44590
|
+
const bounds = new Box3(
|
|
44591
|
+
new Vector3(center.x - halfExtent, center.y - halfExtent, center.z - halfExtent),
|
|
44592
|
+
new Vector3(center.x + halfExtent, center.y + halfExtent, center.z + halfExtent)
|
|
44593
|
+
);
|
|
44594
|
+
const intersection = ray.intersectBox(bounds, hitPoint);
|
|
44595
|
+
if (!intersection) continue;
|
|
44596
|
+
const alongRay = intersection.clone().sub(ray.origin).dot(ray.direction);
|
|
44597
|
+
hits.push({ cell: { x, y, z }, normal: voxelNormalFromBoxHit(intersection, bounds), alongRay });
|
|
44598
|
+
}
|
|
44599
|
+
hits.sort((a2, b2) => a2.alongRay - b2.alongRay);
|
|
44600
|
+
return hits;
|
|
44601
|
+
};
|
|
44602
|
+
const rayExitPointForObjectClick = (event, cellSize) => {
|
|
44603
|
+
var _a4;
|
|
44604
|
+
const hitObject = event.object;
|
|
44605
|
+
hitObject.updateWorldMatrix(true, false);
|
|
44606
|
+
const raycaster = new Raycaster(event.ray.origin.clone(), event.ray.direction.clone(), 0, 1e5);
|
|
44607
|
+
const hits = raycaster.intersectObject(hitObject, false).sort((a2, b2) => a2.distance - b2.distance);
|
|
44608
|
+
const minGap = Math.max(1e-3, cellSize * 0.08);
|
|
44609
|
+
const distinctHits = [];
|
|
44610
|
+
for (const hit of hits) {
|
|
44611
|
+
if (hit.distance < event.distance - minGap) continue;
|
|
44612
|
+
const previousHit = distinctHits[distinctHits.length - 1];
|
|
44613
|
+
if (!previousHit || Math.abs(hit.distance - previousHit.distance) > minGap) distinctHits.push(hit);
|
|
44614
|
+
}
|
|
44615
|
+
return ((_a4 = distinctHits[1]) == null ? void 0 : _a4.point) ?? null;
|
|
44616
|
+
};
|
|
44617
|
+
const handleVoxelObjectSurfaceClick = (event, matrix) => {
|
|
44618
|
+
var _a4;
|
|
44619
|
+
event.stopPropagation();
|
|
44620
|
+
if ((event.delta ?? 0) > 4) return;
|
|
44621
|
+
const cellSize = resolveVoxelIntentCellSize(voxelIntentCellSizeValue);
|
|
44622
|
+
const markerHits = voxelBlockHitsOnRay(event.ray, cellSize);
|
|
44623
|
+
if (voxelIntentTool === "erase") {
|
|
44624
|
+
const markerHit2 = markerHits[0];
|
|
44625
|
+
if (markerHit2) eraseVoxelIntentBlock(markerHit2.cell);
|
|
44626
|
+
return;
|
|
44627
|
+
}
|
|
44628
|
+
const markerHit = markerHits[0];
|
|
44629
|
+
if (markerHit) {
|
|
44630
|
+
const candidate = addVoxelCells2(markerHit.cell, markerHit.normal);
|
|
44631
|
+
if (!(voxelCellKey2(candidate) in voxelIntentBlocks)) {
|
|
44632
|
+
setVoxelIntentBlock(candidate, { groupId: voxelIntentTool, placement: voxelIntentPlacement });
|
|
44633
|
+
}
|
|
44634
|
+
return;
|
|
44635
|
+
}
|
|
44636
|
+
const worldNormal = ((_a4 = event.face) == null ? void 0 : _a4.normal) ? event.face.normal.clone().applyNormalMatrix(new Matrix3().getNormalMatrix(matrix)).normalize() : new Vector3(0, 0, 1);
|
|
44637
|
+
if (worldNormal.lengthSq() === 0) worldNormal.set(0, 0, 1);
|
|
44638
|
+
if (voxelIntentPlacement === "through") {
|
|
44639
|
+
const exitPoint = rayExitPointForObjectClick(event, cellSize);
|
|
44640
|
+
const cutPoint = exitPoint ? event.point.clone().lerp(exitPoint, 0.5) : event.point.clone().sub(worldNormal.clone().multiplyScalar(cellSize * 0.5));
|
|
44641
|
+
setVoxelIntentBlock(voxelCellFromPoint(cutPoint, cellSize), { groupId: voxelIntentTool, placement: voxelIntentPlacement });
|
|
44642
|
+
return;
|
|
44643
|
+
}
|
|
44644
|
+
if (voxelIntentPlacement === "inside") {
|
|
44645
|
+
setVoxelIntentBlock(voxelCellFromSurfaceAnchor(event.point, worldNormal, cellSize, "inside"), {
|
|
44646
|
+
groupId: voxelIntentTool,
|
|
44647
|
+
placement: voxelIntentPlacement
|
|
44648
|
+
});
|
|
44649
|
+
return;
|
|
44650
|
+
}
|
|
44651
|
+
if (voxelIntentPlacement === "grid") {
|
|
44652
|
+
setVoxelIntentBlock(voxelCellFromPoint(event.point, cellSize), { groupId: voxelIntentTool, placement: voxelIntentPlacement });
|
|
44653
|
+
return;
|
|
44654
|
+
}
|
|
44655
|
+
setVoxelIntentBlock(voxelCellFromSurfaceAnchor(event.point, worldNormal, cellSize, "outside"), {
|
|
44656
|
+
groupId: voxelIntentTool,
|
|
44657
|
+
placement: voxelIntentPlacement
|
|
44658
|
+
});
|
|
44659
|
+
};
|
|
43704
44660
|
const overlayEntries = [];
|
|
43705
44661
|
if (showPerformanceInfo) {
|
|
43706
44662
|
overlayEntries.push({
|
|
@@ -43755,6 +44711,8 @@ function Viewport() {
|
|
|
43755
44711
|
channel: inspectChannel,
|
|
43756
44712
|
displayMode: inspectDisplayMode,
|
|
43757
44713
|
warnings: inspectWarnings,
|
|
44714
|
+
thicknessColorRange,
|
|
44715
|
+
onThicknessColorRangeChange: setThicknessColorRange,
|
|
43758
44716
|
details: comparisonInspectActive ? /* @__PURE__ */ jsxRuntimeExports.jsx(ComparisonLegendDetails, { metrics: comparisonAnalysis.metrics, mode: comparisonInspectMode }) : void 0
|
|
43759
44717
|
}
|
|
43760
44718
|
)
|
|
@@ -43834,7 +44792,7 @@ function Viewport() {
|
|
|
43834
44792
|
{
|
|
43835
44793
|
style: {
|
|
43836
44794
|
background: renderStyle === "classic" ? t2.viewportBg : renderStylePreset.background,
|
|
43837
|
-
cursor: measureMode ? "crosshair" : "default"
|
|
44795
|
+
cursor: measureMode || voxelIntentMode ? "crosshair" : "default"
|
|
43838
44796
|
},
|
|
43839
44797
|
dpr: canvasDpr,
|
|
43840
44798
|
gl: {
|
|
@@ -43921,14 +44879,16 @@ function Viewport() {
|
|
|
43921
44879
|
const settings = objectSettings[obj.id] ?? { visible: true, opacity: 1, color: "#5b9bd5" };
|
|
43922
44880
|
const isDimmedByFocus = focusedObjectIdSet.size > 0 && !focusedObjectIdSet.has(obj.id);
|
|
43923
44881
|
const isDimmedByGhost = constructionGhost !== null && obj.id !== constructionGhost.objectId;
|
|
44882
|
+
const isDimmedByVoxel = voxelIntentMode && !!obj.shape;
|
|
43924
44883
|
const isHiddenByHistory = historyMode && historyObjectIds.includes(obj.id);
|
|
43925
44884
|
if (isHiddenByHistory) return null;
|
|
43926
44885
|
const effectiveSettings = isDimmedByFocus || isDimmedByGhost ? { ...settings, opacity: Math.min(settings.opacity, FOCUS_MODE_DIM_OPACITY) } : settings;
|
|
44886
|
+
const voxelSettings = isDimmedByVoxel ? { ...effectiveSettings, opacity: Math.min(effectiveSettings.opacity, voxelIntentGhostOpacity) } : effectiveSettings;
|
|
43927
44887
|
const comparisonSettings = comparisonInspectActive && obj.shape ? {
|
|
43928
|
-
...
|
|
43929
|
-
opacity: Math.min(
|
|
44888
|
+
...voxelSettings,
|
|
44889
|
+
opacity: Math.min(voxelSettings.opacity, comparisonCandidateContextOpacity(comparisonCandidateOpacity)),
|
|
43930
44890
|
color: "#b9c3cc"
|
|
43931
|
-
} :
|
|
44891
|
+
} : voxelSettings;
|
|
43932
44892
|
const isHovered = hoveredObjectId === obj.id;
|
|
43933
44893
|
const matrix = objectMatrices[obj.id] ?? new Matrix4();
|
|
43934
44894
|
const objectClippingPlanes = objectClippingPlanesById[obj.id] ?? EMPTY_CLIPPING_PLANES;
|
|
@@ -43959,7 +44919,7 @@ function Viewport() {
|
|
|
43959
44919
|
onPointerEnter: (event) => updateHoverLabel(obj, event),
|
|
43960
44920
|
onPointerMove: (event) => updateHoverLabel(obj, event),
|
|
43961
44921
|
onPointerLeave: (event) => clearHoverLabel(obj, event),
|
|
43962
|
-
onClick: (event) => handleObjectClick(obj, event),
|
|
44922
|
+
onClick: (event) => voxelIntentMode ? handleVoxelObjectSurfaceClick(event, matrix) : handleObjectClick(obj, event),
|
|
43963
44923
|
onDoubleClick: (event) => handleObjectDoubleClick(obj, event),
|
|
43964
44924
|
onContextMenu: (event) => handleObjectContextMenu(obj, event)
|
|
43965
44925
|
},
|
|
@@ -44032,6 +44992,7 @@ function Viewport() {
|
|
|
44032
44992
|
}
|
|
44033
44993
|
return null;
|
|
44034
44994
|
}),
|
|
44995
|
+
voxelIntentMode && /* @__PURE__ */ jsxRuntimeExports.jsx(VoxelIntentOverlay, {}),
|
|
44035
44996
|
inspectChannel === "collisions" && /* @__PURE__ */ jsxRuntimeExports.jsx(CollisionInspectionOverlay, { geometries: inspectAnalysis.collisionGeometries }),
|
|
44036
44997
|
rigInspectActive && /* @__PURE__ */ jsxRuntimeExports.jsx(RigInspectionOverlay, { state: rigInspectionOverlay, config: jointOverlayConfig }),
|
|
44037
44998
|
comparisonInspectActive && comparisonAnalysis.referenceResult && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
@@ -44086,7 +45047,7 @@ function Viewport() {
|
|
|
44086
45047
|
}
|
|
44087
45048
|
),
|
|
44088
45049
|
/* @__PURE__ */ jsxRuntimeExports.jsx(ZoomSampler, { onZoomChange: setZoomMmPerPx }),
|
|
44089
|
-
gridEnabled && !isSketchOnly && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
45050
|
+
gridEnabled && !isSketchOnly && !voxelIntentMode && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
44090
45051
|
Grid,
|
|
44091
45052
|
{
|
|
44092
45053
|
args: [500, 500],
|
|
@@ -44111,7 +45072,7 @@ function Viewport() {
|
|
|
44111
45072
|
onPointerEnter: (obj, event) => updateHoverLabel(obj, event),
|
|
44112
45073
|
onPointerMove: (obj, event) => updateHoverLabel(obj, event),
|
|
44113
45074
|
onPointerLeave: (obj, event) => clearHoverLabel(obj, event),
|
|
44114
|
-
onClick: (obj, event) => handleObjectClick(obj, event),
|
|
45075
|
+
onClick: (obj, event) => voxelIntentMode ? handleVoxelObjectSurfaceClick(event, objectMatrices[obj.id] ?? new Matrix4()) : handleObjectClick(obj, event),
|
|
44115
45076
|
onDoubleClick: (obj, event) => handleObjectDoubleClick(obj, event),
|
|
44116
45077
|
onContextMenu: (obj, event) => handleObjectContextMenu(obj, event)
|
|
44117
45078
|
}
|
|
@@ -44146,7 +45107,7 @@ function Viewport() {
|
|
|
44146
45107
|
minPolarAngle: 0,
|
|
44147
45108
|
maxPolarAngle: Math.PI,
|
|
44148
45109
|
enableRotate: !isSketchOnly,
|
|
44149
|
-
mouseButtons: drawModeActive ? MOUSE_BUTTONS_DRAW : isSketchOnly ? MOUSE_BUTTONS_SKETCH : MOUSE_BUTTONS_3D,
|
|
45110
|
+
mouseButtons: voxelIntentMode ? MOUSE_BUTTONS_VOXEL : drawModeActive ? MOUSE_BUTTONS_DRAW : isSketchOnly ? MOUSE_BUTTONS_SKETCH : MOUSE_BUTTONS_3D,
|
|
44150
45111
|
touches: isSketchOnly ? TOUCH_GESTURES_SKETCH : TOUCH_GESTURES_3D
|
|
44151
45112
|
}
|
|
44152
45113
|
),
|
|
@@ -44255,7 +45216,7 @@ function Viewport() {
|
|
|
44255
45216
|
/* @__PURE__ */ jsxRuntimeExports.jsx(ViewportOverlayHost, { entries: overlayEntries }),
|
|
44256
45217
|
viewportDisabledMessage && /* @__PURE__ */ jsxRuntimeExports.jsx(ViewportDisabledOverlay, { title: viewportDisabledMessage.title, body: viewportDisabledMessage.body }),
|
|
44257
45218
|
drawFlagEnabled && /* @__PURE__ */ jsxRuntimeExports.jsx(DrawToolbar, {}),
|
|
44258
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(HoverTooltipLayer, { ref: hoverTooltipRef, enabled: objectPickSyncEnabled && !measureMode }),
|
|
45219
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(HoverTooltipLayer, { ref: hoverTooltipRef, enabled: objectPickSyncEnabled && !measureMode && !voxelIntentMode }),
|
|
44259
45220
|
viewportPortalHost && objectContextMenu && reactDomExports.createPortal(
|
|
44260
45221
|
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
44261
45222
|
"div",
|
|
@@ -44729,7 +45690,7 @@ function Viewport() {
|
|
|
44729
45690
|
}
|
|
44730
45691
|
);
|
|
44731
45692
|
}
|
|
44732
|
-
const EditorApp$1 = reactExports.lazy(() => __vitePreload(() => import("./EditorApp-
|
|
45693
|
+
const EditorApp$1 = reactExports.lazy(() => __vitePreload(() => import("./EditorApp-BHMQlJ-D.js"), true ? __vite__mapDeps([0]) : void 0).then((m2) => ({ default: m2.EditorApp })));
|
|
44733
45694
|
const PENDING_SHARE_COPY_KEY = "fc-pending-share-copy";
|
|
44734
45695
|
function storePendingShareCopy(shareId) {
|
|
44735
45696
|
sessionStorage.setItem(PENDING_SHARE_COPY_KEY, shareId);
|
|
@@ -44995,17 +45956,17 @@ function SeoMetadata() {
|
|
|
44995
45956
|
}, [location.pathname]);
|
|
44996
45957
|
return null;
|
|
44997
45958
|
}
|
|
44998
|
-
reactExports.lazy(() => __vitePreload(() => import("./LandingPageProofDriven-
|
|
44999
|
-
const DocsPage = reactExports.lazy(() => __vitePreload(() => import("./DocsPage-
|
|
45000
|
-
reactExports.lazy(() => __vitePreload(() => import("./BlogPage-
|
|
45001
|
-
reactExports.lazy(() => __vitePreload(() => import("./BenchmarkPage-
|
|
45002
|
-
reactExports.lazy(() => __vitePreload(() => import("./AdminPage-
|
|
45959
|
+
reactExports.lazy(() => __vitePreload(() => import("./LandingPageProofDriven-CnevhTE8.js"), true ? __vite__mapDeps([1]) : void 0).then((m2) => ({ default: m2.LandingPageProofDriven })));
|
|
45960
|
+
const DocsPage = reactExports.lazy(() => __vitePreload(() => import("./DocsPage-knf4I4h7.js"), true ? [] : void 0).then((m2) => ({ default: m2.DocsPage })));
|
|
45961
|
+
reactExports.lazy(() => __vitePreload(() => import("./BlogPage-CMAVvgQL.js"), true ? [] : void 0).then((m2) => ({ default: m2.BlogPage })));
|
|
45962
|
+
reactExports.lazy(() => __vitePreload(() => import("./BenchmarkPage-B27zk8xL.js"), true ? __vite__mapDeps([1,2]) : void 0).then((m2) => ({ default: m2.BenchmarkPage })));
|
|
45963
|
+
reactExports.lazy(() => __vitePreload(() => import("./AdminPage-CXvls4-J.js"), true ? [] : void 0).then((m2) => ({ default: m2.AdminPage })));
|
|
45003
45964
|
reactExports.lazy(() => __vitePreload(() => Promise.resolve().then(() => PublishedModelPage$1), true ? void 0 : void 0).then((m2) => ({ default: m2.PublishedModelPage })));
|
|
45004
|
-
reactExports.lazy(() => __vitePreload(() => import("./SettingsPage-
|
|
45005
|
-
reactExports.lazy(() => __vitePreload(() => import("./PricingPage-
|
|
45006
|
-
reactExports.lazy(() => __vitePreload(() => import("./LegalPage-
|
|
45007
|
-
const EditorApp = reactExports.lazy(() => __vitePreload(() => import("./EditorApp-
|
|
45008
|
-
const EmbedViewer = reactExports.lazy(() => __vitePreload(() => import("./EmbedViewer-
|
|
45965
|
+
reactExports.lazy(() => __vitePreload(() => import("./SettingsPage-CFF-UgjI.js"), true ? [] : void 0).then((m2) => ({ default: m2.SettingsPage })));
|
|
45966
|
+
reactExports.lazy(() => __vitePreload(() => import("./PricingPage-B0D4goG_.js"), true ? __vite__mapDeps([1,3]) : void 0).then((m2) => ({ default: m2.PricingPage })));
|
|
45967
|
+
reactExports.lazy(() => __vitePreload(() => import("./LegalPage-BPTUmqeg.js"), true ? __vite__mapDeps([1,4]) : void 0).then((m2) => ({ default: m2.LegalPage })));
|
|
45968
|
+
const EditorApp = reactExports.lazy(() => __vitePreload(() => import("./EditorApp-BHMQlJ-D.js"), true ? __vite__mapDeps([0]) : void 0).then((m2) => ({ default: m2.EditorApp })));
|
|
45969
|
+
const EmbedViewer = reactExports.lazy(() => __vitePreload(() => import("./EmbedViewer-D7ZGlFjx.js"), true ? [] : void 0).then((m2) => ({ default: m2.EmbedViewer })));
|
|
45009
45970
|
const embedMode = isEmbedMode() && !window.location.pathname.startsWith("/m/");
|
|
45010
45971
|
const EDITABLE_CRASH_FILE = /\.(?:forge\.js|[cm]?[jt]sx?|json|md|txt|svg|dxf)$/i;
|
|
45011
45972
|
function firstMeaningfulLine(text) {
|
|
@@ -45225,7 +46186,7 @@ function App() {
|
|
|
45225
46186
|
applyTheme(localStorage.getItem("fc-theme") || "dark");
|
|
45226
46187
|
clientExports.createRoot(document.getElementById("root")).render(/* @__PURE__ */ jsxRuntimeExports.jsx(App, {}));
|
|
45227
46188
|
export {
|
|
45228
|
-
|
|
46189
|
+
VOXEL_INTENT_PLACEMENT_LABELS as $,
|
|
45229
46190
|
AuthApiError as A,
|
|
45230
46191
|
BrandMark as B,
|
|
45231
46192
|
hasExternalFiles as C,
|
|
@@ -45249,37 +46210,42 @@ export {
|
|
|
45249
46210
|
useJointAnimationValues as U,
|
|
45250
46211
|
INSPECT_POINT_SAMPLE_COUNT_MAX as V,
|
|
45251
46212
|
INSPECT_POINT_SAMPLE_COUNT_MIN as W,
|
|
45252
|
-
|
|
45253
|
-
|
|
45254
|
-
|
|
45255
|
-
|
|
46213
|
+
VOXEL_INTENT_TOOL_ORDER as X,
|
|
46214
|
+
VOXEL_INTENT_TOOL_LABELS as Y,
|
|
46215
|
+
VOXEL_INTENT_TOOL_COLORS as Z,
|
|
46216
|
+
VOXEL_INTENT_PLACEMENT_ORDER as _,
|
|
45256
46217
|
applyTheme as a,
|
|
45257
|
-
|
|
45258
|
-
|
|
45259
|
-
|
|
45260
|
-
|
|
45261
|
-
|
|
45262
|
-
|
|
45263
|
-
|
|
45264
|
-
|
|
45265
|
-
|
|
45266
|
-
|
|
45267
|
-
|
|
45268
|
-
|
|
45269
|
-
|
|
45270
|
-
|
|
45271
|
-
|
|
45272
|
-
|
|
45273
|
-
|
|
45274
|
-
|
|
45275
|
-
|
|
45276
|
-
|
|
45277
|
-
|
|
45278
|
-
|
|
45279
|
-
|
|
45280
|
-
|
|
45281
|
-
|
|
45282
|
-
|
|
46218
|
+
expandBoundsByTransformedAabb as a0,
|
|
46219
|
+
Canvas as a1,
|
|
46220
|
+
PerspectiveCamera as a2,
|
|
46221
|
+
ControlsInteractionBridge as a3,
|
|
46222
|
+
ViewController as a4,
|
|
46223
|
+
SceneConfigurator as a5,
|
|
46224
|
+
LocalEnvironment as a6,
|
|
46225
|
+
ForgeObject as a7,
|
|
46226
|
+
RenderLabelsOverlay as a8,
|
|
46227
|
+
Grid as a9,
|
|
46228
|
+
OrbitControls2 as aa,
|
|
46229
|
+
TOUCH_GESTURES_3D as ab,
|
|
46230
|
+
MOUSE_BUTTONS_3D as ac,
|
|
46231
|
+
ModelJourneyBar as ad,
|
|
46232
|
+
useJointAnimationLoop as ae,
|
|
46233
|
+
computeJointNodeMatrices as af,
|
|
46234
|
+
computeObjectJointMatrices as ag,
|
|
46235
|
+
readLastActiveFileForUser as ah,
|
|
46236
|
+
ToastContainer as ai,
|
|
46237
|
+
isMobile as aj,
|
|
46238
|
+
useFeatureFlag as ak,
|
|
46239
|
+
decodeSharedHash as al,
|
|
46240
|
+
decodeSharedBundle as am,
|
|
46241
|
+
getExternalUrl as an,
|
|
46242
|
+
getGistId as ao,
|
|
46243
|
+
Viewport as ap,
|
|
46244
|
+
shouldBlockBrowserShortcut as aq,
|
|
46245
|
+
useDrawStore as ar,
|
|
46246
|
+
storePendingShareCopy as as,
|
|
46247
|
+
buildShareUrl as at,
|
|
46248
|
+
share as au,
|
|
45283
46249
|
authFetch as b,
|
|
45284
46250
|
authApi as c,
|
|
45285
46251
|
showToast as d,
|