import { useEffect, useMemo, useRef, useState } from 'react'; import * as THREE from 'three'; import { useFrame, useThree } from '@react-three/fiber'; import { useActiveLayer, useToolMode, useToggleView } from '../../../../store/builder/store'; import * as Constants from '../../../../types/world/worldConstants'; import { Extrude } from '@react-three/drei'; interface ReferenceAisleProps { tempPoints: Point[]; aisleType: AisleTypes; aisleWidth: number; aisleColor: AisleColors; } function ReferenceAisle({ tempPoints, aisleType, aisleWidth, aisleColor }: Readonly) { const { pointer, raycaster, camera } = useThree(); const { toolMode } = useToolMode(); const { toggleView } = useToggleView(); const { activeLayer } = useActiveLayer(); const plane = new THREE.Plane(new THREE.Vector3(0, 1, 0), 0); const [tempAisle, setTempAisle] = useState(null); const mousePosRef = useRef(new THREE.Vector3()); useFrame(() => { if (toolMode === "Aisle" && toggleView && tempPoints.length === 1) { raycaster.setFromCamera(pointer, camera); const intersectionPoint = new THREE.Vector3(); raycaster.ray.intersectPlane(plane, intersectionPoint); if (intersectionPoint) { mousePosRef.current.copy(intersectionPoint); setTempAisle({ uuid: 'temp-aisle', points: [ tempPoints[0], { uuid: 'temp-point', position: [mousePosRef.current.x, mousePosRef.current.y, mousePosRef.current.z], layer: activeLayer } ], type: { typeName: 'Aisle', aisleType: aisleType, aisleColor: aisleColor, aisleWidth: aisleWidth } }); } } else if (tempAisle !== null) { setTempAisle(null); } }); useEffect(() => { setTempAisle(null); }, [toolMode, toggleView, tempPoints.length, aisleType, aisleWidth, aisleColor]); if (!tempAisle) return null; const renderAisle = () => { switch (aisleType) { case 'solid-aisle': return ; case 'dashed-aisle': return ; case 'dotted-aisle': return ; default: return null; } }; return ( {renderAisle()} ); } export default ReferenceAisle; function SolidAisle({ aisle }: { readonly aisle: Aisle }) { const shape = useMemo(() => { if (aisle.points.length < 2) return null; const start = new THREE.Vector3(...aisle.points[0].position); const end = new THREE.Vector3(...aisle.points[1].position); const width = aisle.type.aisleWidth || 0.1; const direction = new THREE.Vector3().subVectors(end, start).normalize(); const perp = new THREE.Vector3(-direction.z, 0, direction.x).normalize(); const leftStart = new THREE.Vector3().copy(start).addScaledVector(perp, width / 2); const rightStart = new THREE.Vector3().copy(start).addScaledVector(perp, -width / 2); const leftEnd = new THREE.Vector3().copy(end).addScaledVector(perp, width / 2); const rightEnd = new THREE.Vector3().copy(end).addScaledVector(perp, -width / 2); const shape = new THREE.Shape(); shape.moveTo(leftStart.x, leftStart.z); shape.lineTo(leftEnd.x, leftEnd.z); shape.lineTo(rightEnd.x, rightEnd.z); shape.lineTo(rightStart.x, rightStart.z); shape.closePath(); return shape; }, [aisle]); if (!shape) return null; return ( ); } function DashedAisle({ aisle }: { readonly aisle: Aisle }) { const shapes = useMemo(() => { if (aisle.points.length < 2) return []; const start = new THREE.Vector3(...aisle.points[0].position); const end = new THREE.Vector3(...aisle.points[1].position); const width = aisle.type.aisleWidth || 0.1; const dashLength = 0.5; const gapLength = 0.3; const direction = new THREE.Vector3().subVectors(end, start).normalize(); const perp = new THREE.Vector3(-direction.z, 0, direction.x).normalize(); const totalLength = new THREE.Vector3().subVectors(end, start).length(); const segmentCount = Math.floor(totalLength / (dashLength + gapLength)); const shapes = []; const directionNormalized = new THREE.Vector3().subVectors(end, start).normalize(); for (let i = 0; i < segmentCount; i++) { const segmentStart = new THREE.Vector3().copy(start).addScaledVector(directionNormalized, i * (dashLength + gapLength)); const segmentEnd = new THREE.Vector3().copy(segmentStart).addScaledVector(directionNormalized, dashLength); const leftStart = new THREE.Vector3().copy(segmentStart).addScaledVector(perp, width / 2); const rightStart = new THREE.Vector3().copy(segmentStart).addScaledVector(perp, -width / 2); const leftEnd = new THREE.Vector3().copy(segmentEnd).addScaledVector(perp, width / 2); const rightEnd = new THREE.Vector3().copy(segmentEnd).addScaledVector(perp, -width / 2); const shape = new THREE.Shape(); shape.moveTo(leftStart.x, leftStart.z); shape.lineTo(leftEnd.x, leftEnd.z); shape.lineTo(rightEnd.x, rightEnd.z); shape.lineTo(rightStart.x, rightStart.z); shape.closePath(); shapes.push(shape); } return shapes; }, [aisle]); if (shapes.length === 0) return null; return ( {shapes.map((shape, index) => ( ))} ); } function DottedAisle({ aisle }: { readonly aisle: Aisle }) { const shapes = useMemo(() => { if (aisle.points.length < 2) return []; const start = new THREE.Vector3(...aisle.points[0].position); const end = new THREE.Vector3(...aisle.points[1].position); const width = aisle.type.aisleWidth || 0.1; const dotSpacing = 0.5; const dotRadius = width * 0.4; const totalLength = new THREE.Vector3().subVectors(end, start).length(); const dotCount = Math.floor(totalLength / dotSpacing); const shapes = []; const directionNormalized = new THREE.Vector3().subVectors(end, start).normalize(); for (let i = 0; i < dotCount; i++) { const dotCenter = new THREE.Vector3().copy(start).addScaledVector(directionNormalized, i * dotSpacing + dotSpacing / 2); const shape = new THREE.Shape(); shape.absarc(dotCenter.x, dotCenter.z, dotRadius, 0, Math.PI * 2, false); shapes.push(shape); } return shapes; }, [aisle]); if (shapes.length === 0) return null; return ( {shapes.map((shape, index) => ( ))} ); }