import * as THREE from 'three'; import * as Constants from '../../../types/world/worldConstants'; import { useRef, useState, useEffect, useMemo } from 'react'; import { useDeletePointOrLine, useToolMode } from '../../../store/builder/store'; import { DragControls } from '@react-three/drei'; import { useAisleStore } from '../../../store/builder/useAisleStore'; import { useThree } from '@react-three/fiber'; import { useBuilderStore } from '../../../store/builder/useBuilderStore'; import { usePointSnapping } from './helpers/usePointSnapping'; import { useAislePointSnapping } from './helpers/useAisleDragSnap'; import { useWallStore } from '../../../store/builder/useWallStore'; function Point({ point }: { readonly point: Point }) { const materialRef = useRef(null); const { raycaster, camera, pointer } = useThree(); const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []); const [isHovered, setIsHovered] = useState(false); const { toolMode } = useToolMode(); const { setPosition: setAislePosition, removePoint: removeAislePoint } = useAisleStore(); const { setPosition: setWallPosition, removePoint: removeWallPoint } = useWallStore(); const { snapPosition } = useAislePointSnapping(point); const { checkSnapForAisle } = usePointSnapping({ uuid: point.pointUuid, pointType: point.pointType, position: point.position }); const { hoveredPoint, setHoveredPoint } = useBuilderStore(); const { deletePointOrLine } = useDeletePointOrLine(); const boxScale: [number, number, number] = Constants.pointConfig.boxScale; const colors = getColor(point); function getColor(point: Point) { if (point.pointType === 'Aisle') { return { defaultInnerColor: Constants.pointConfig.defaultInnerColor, defaultOuterColor: Constants.pointConfig.aisleOuterColor, defaultDeleteColor: Constants.pointConfig.deleteColor, } } else if (point.pointType === 'Floor') { return { defaultInnerColor: Constants.pointConfig.defaultInnerColor, defaultOuterColor: Constants.pointConfig.floorOuterColor, defaultDeleteColor: Constants.pointConfig.deleteColor, } } else if (point.pointType === 'Wall') { return { defaultInnerColor: Constants.pointConfig.defaultInnerColor, defaultOuterColor: Constants.pointConfig.wallOuterColor, defaultDeleteColor: Constants.pointConfig.deleteColor, } } else if (point.pointType === 'Zone') { return { defaultInnerColor: Constants.pointConfig.defaultInnerColor, defaultOuterColor: Constants.pointConfig.zoneOuterColor, defaultDeleteColor: Constants.pointConfig.deleteColor, } } else { return { defaultInnerColor: Constants.pointConfig.defaultInnerColor, defaultOuterColor: Constants.pointConfig.defaultOuterColor, defaultDeleteColor: Constants.pointConfig.deleteColor, } } } useEffect(() => { if (materialRef.current && (toolMode === 'move' || deletePointOrLine)) { let innerColor; let outerColor; if (isHovered) { innerColor = deletePointOrLine ? colors.defaultDeleteColor : colors.defaultOuterColor; outerColor = deletePointOrLine ? colors.defaultDeleteColor : colors.defaultOuterColor; } else { innerColor = colors.defaultInnerColor; outerColor = colors.defaultOuterColor; } materialRef.current.uniforms.uInnerColor.value.set(innerColor); materialRef.current.uniforms.uOuterColor.value.set(outerColor); materialRef.current.uniformsNeedUpdate = true; } else if (materialRef.current && toolMode !== 'move') { materialRef.current.uniforms.uInnerColor.value.set(colors.defaultInnerColor); materialRef.current.uniforms.uOuterColor.value.set(colors.defaultOuterColor); materialRef.current.uniformsNeedUpdate = true; } }, [isHovered, colors.defaultInnerColor, colors.defaultOuterColor, colors.defaultDeleteColor, toolMode, deletePointOrLine]); const uniforms = useMemo(() => ({ uOuterColor: { value: new THREE.Color(colors.defaultOuterColor) }, uInnerColor: { value: new THREE.Color(colors.defaultInnerColor) }, }), [colors.defaultInnerColor, colors.defaultOuterColor]); const handleDrag = (point: Point) => { if (toolMode === 'move' && isHovered) { raycaster.setFromCamera(pointer, camera); const intersectionPoint = new THREE.Vector3(); const position = raycaster.ray.intersectPlane(plane, intersectionPoint); if (point.pointType === 'Aisle') { if (position) { const newPosition: [number, number, number] = [position.x, position.y, position.z]; const aisleSnappedPosition = snapPosition(newPosition); const finalSnappedPosition = checkSnapForAisle(aisleSnappedPosition.position); setAislePosition(point.pointUuid, finalSnappedPosition.position); } } else if (point.pointType === 'Wall') { if (position) { const newPosition: [number, number, number] = [position.x, position.y, position.z]; setWallPosition(point.pointUuid, newPosition); } } } } const handleDragEnd = (point: Point) => { if (deletePointOrLine) return; console.log('point: ', point); } const handlePointClick = (point: Point) => { if (deletePointOrLine) { if (point.pointType === 'Aisle') { const removedAisles = removeAislePoint(point.pointUuid); if (removedAisles.length > 0) { setHoveredPoint(null); } } } } useEffect(() => { if (hoveredPoint && hoveredPoint.pointUuid !== point.pointUuid) { setIsHovered(false); } }, [hoveredPoint]) if (!point) { return null; } return ( { handleDrag(point) }} onDragEnd={() => { handleDragEnd(point) }} > { handlePointClick(point); }} onPointerOver={() => { if (!hoveredPoint) { setHoveredPoint(point); setIsHovered(true) } }} onPointerOut={() => { if (hoveredPoint && hoveredPoint.pointUuid === point.pointUuid) { setHoveredPoint(null); } setIsHovered(false) }} userData={point} > borderThickness && vUv.x < 1.0 - borderThickness && vUv.y > borderThickness && vUv.y < 1.0 - borderThickness) { gl_FragColor = vec4(uInnerColor, 1.0); // Inner square } else { gl_FragColor = vec4(uOuterColor, 1.0); // Border } } ` } /> ); } export default Point;