From 7208e2bc56169c0800cac21786031461764a5556 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Sun, 24 May 2026 22:53:23 +0000 Subject: [PATCH] Changes Co-authored-by: Reifonas <211114984+Reifonas@users.noreply.github.com> --- src/components/three/ModelViewer.tsx | 66 ++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/src/components/three/ModelViewer.tsx b/src/components/three/ModelViewer.tsx index 5c30a88..e7a8314 100644 --- a/src/components/three/ModelViewer.tsx +++ b/src/components/three/ModelViewer.tsx @@ -1115,6 +1115,72 @@ function GridCalibrationHandler() { return null; } +/** Applies axis-aligned clipping planes (X / Y / Z) to every mesh inside the + * registered model groups. Listens to the section state in the store; when + * all axes are off, restores empty clipping arrays so meshes render whole. */ +function SectionClippingApplier() { + const enabled = useModelStore((s) => s.sectionEnabled); + const invert = useModelStore((s) => s.sectionInvert); + const level = useModelStore((s) => s.sectionLevel); + + const planes = useMemo(() => ({ + x: new THREE.Plane(new THREE.Vector3(1, 0, 0), 0), + y: new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), + z: new THREE.Plane(new THREE.Vector3(0, 0, 1), 0), + }), []); + + useEffect(() => { + // Configure each plane: keep the half-space on the positive side of the + // normal. Inverting flips the normal direction. + (['x', 'y', 'z'] as const).forEach((axis) => { + const plane = planes[axis]; + const sign = invert[axis] ? -1 : 1; + plane.normal.set( + axis === 'x' ? sign : 0, + axis === 'y' ? sign : 0, + axis === 'z' ? sign : 0, + ); + // For plane equation n·p + d = 0, keeping `n·p >= level*sign_axis` means + // d = -level when normal is +axis, d = +level when normal is -axis. + plane.constant = -sign * level[axis]; + }); + + const active: THREE.Plane[] = []; + if (enabled.x) active.push(planes.x); + if (enabled.y) active.push(planes.y); + if (enabled.z) active.push(planes.z); + + const groups = getAllModelLocalGroups(); + const touched: THREE.Material[] = []; + const apply = (clipping: THREE.Plane[]) => { + for (const g of groups) { + g.traverse((obj) => { + if (!(obj instanceof THREE.Mesh)) return; + const mats = Array.isArray(obj.material) ? obj.material : [obj.material]; + for (const mat of mats) { + if (!mat) continue; + mat.clippingPlanes = clipping; + mat.clipShadows = true; + mat.needsUpdate = true; + touched.push(mat); + } + }); + } + }; + apply(active); + + return () => { + // Cleanup: clear clipping from any material we touched. + for (const mat of touched) { + mat.clippingPlanes = []; + mat.needsUpdate = true; + } + }; + }, [enabled.x, enabled.y, enabled.z, invert.x, invert.y, invert.z, level.x, level.y, level.z, planes]); + + return null; +} + /** Mouse drag handler for desktop "Posicionar" mode: translates/rotates the active model. */ function PositionDragHandler() { const { camera, gl, scene } = useThree();