import * as THREE from 'three'; import { useThree } from '@react-three/fiber'; import { useEffect, useMemo, useState } from "react"; import { DragControls, Tube } from '@react-three/drei'; import { useToolMode } from '../../../store/builder/store'; import { useBuilderStore } from '../../../store/builder/useBuilderStore'; import { useSceneContext } from '../../scene/sceneContext'; import * as Constants from '../../../types/world/worldConstants'; interface LineProps { points: [Point, Point]; } function Line({ points }: Readonly) { const [isHovered, setIsHovered] = useState(false); const { raycaster, camera, pointer, gl } = useThree(); const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []); const [isDeletable, setIsDeletable] = useState(false); const { toolMode } = useToolMode(); const { wallStore } = useSceneContext(); const { removeWallByPoints, setPosition } = wallStore(); const [dragOffset, setDragOffset] = useState(null); const { hoveredLine, setHoveredLine, hoveredPoint } = useBuilderStore(); const path = useMemo(() => { const [start, end] = points.map(p => new THREE.Vector3(...p.position)); return new THREE.LineCurve3(start, end); }, [points]); const colors = getColor(points[0]); function getColor(point: Point) { if (point.pointType === 'Aisle') { return { defaultLineColor: Constants.lineConfig.aisleColor, defaultDeleteColor: Constants.lineConfig.deleteColor, } } else if (point.pointType === 'Floor') { return { defaultLineColor: Constants.lineConfig.floorColor, defaultDeleteColor: Constants.lineConfig.deleteColor, } } else if (point.pointType === 'Wall') { return { defaultLineColor: Constants.lineConfig.wallColor, defaultDeleteColor: Constants.lineConfig.deleteColor, } } else if (point.pointType === 'Zone') { return { defaultLineColor: Constants.lineConfig.zoneColor, defaultDeleteColor: Constants.lineConfig.deleteColor, } } else { return { defaultLineColor: Constants.lineConfig.defaultColor, defaultDeleteColor: Constants.lineConfig.deleteColor, } } } useEffect(() => { if (toolMode === '2D-Delete') { if (isHovered && !hoveredPoint) { setIsDeletable(true); } else { setIsDeletable(false); } } else { setIsDeletable(false); } }, [isHovered, colors.defaultLineColor, colors.defaultDeleteColor, toolMode, hoveredPoint]); useEffect(() => { if (hoveredLine && (hoveredLine[0].pointUuid !== points[0].pointUuid || hoveredLine[1].pointUuid !== points[1].pointUuid)) { setIsHovered(false); } }, [hoveredLine]) const handlePointClick = (points: [Point, Point]) => { if (toolMode === '2D-Delete') { if (points[0].pointType === 'Wall' && points[1].pointType === 'Wall') { removeWallByPoints(points); setHoveredLine(null); } gl.domElement.style.cursor = 'default'; } } const handleDrag = (points: [Point, Point]) => { if (toolMode === 'move' && isHovered && dragOffset) { raycaster.setFromCamera(pointer, camera); const intersectionPoint = new THREE.Vector3(); const hit = raycaster.ray.intersectPlane(plane, intersectionPoint); if (hit) { gl.domElement.style.cursor = 'move'; const positionWithOffset = new THREE.Vector3().addVectors(hit, dragOffset); const start = new THREE.Vector3(...points[0].position); const end = new THREE.Vector3(...points[1].position); const midPoint = new THREE.Vector3().addVectors(start, end).multiplyScalar(0.5); const delta = new THREE.Vector3().subVectors(positionWithOffset, midPoint); const newStart = new THREE.Vector3().addVectors(start, delta); const newEnd = new THREE.Vector3().addVectors(end, delta); setPosition(points[0].pointUuid, [newStart.x, newStart.y, newStart.z]); setPosition(points[1].pointUuid, [newEnd.x, newEnd.y, newEnd.z]); } } }; const handleDragStart = (points: [Point, Point]) => { raycaster.setFromCamera(pointer, camera); const intersectionPoint = new THREE.Vector3(); const hit = raycaster.ray.intersectPlane(plane, intersectionPoint); if (hit && !hoveredPoint) { const start = new THREE.Vector3(...points[0].position); const end = new THREE.Vector3(...points[1].position); const midPoint = new THREE.Vector3().addVectors(start, end).multiplyScalar(0.5); const offset = new THREE.Vector3().subVectors(midPoint, hit); setDragOffset(offset); } }; const handleDragEnd = (points: [Point, Point]) => { gl.domElement.style.cursor = 'default'; setDragOffset(null); if (toolMode !== 'move') return; if (points[0].pointType === 'Wall' && points[1].pointType === 'Wall') { // console.log('Wall after drag: ', points); } } return ( handleDragStart(points)} onDrag={() => handleDrag(points)} onDragEnd={() => handleDragEnd(points)} > { handlePointClick(points); }} onPointerOver={() => { if (!hoveredLine) { setHoveredLine(points); setIsHovered(true) if (toolMode === 'move' && !hoveredPoint) { gl.domElement.style.cursor = 'pointer'; } } }} onPointerOut={() => { if (hoveredLine) { setHoveredLine(null); gl.domElement.style.cursor = 'default'; } setIsHovered(false) }} > ); } export default Line;