diff --git a/app/src/components/ui/Tools.tsx b/app/src/components/ui/Tools.tsx index 02069d8..3de44bf 100644 --- a/app/src/components/ui/Tools.tsx +++ b/app/src/components/ui/Tools.tsx @@ -438,7 +438,6 @@ const Tools: React.FC = () => { }`} onClick={() => { setIsPlaying(!isPlaying); - setActiveTool("play"); }} > <PlayIcon isActive={activeTool === "play"} /> diff --git a/app/src/components/ui/simulation/simulationPlayer.tsx b/app/src/components/ui/simulation/simulationPlayer.tsx index 85f2c54..d74d9ca 100644 --- a/app/src/components/ui/simulation/simulationPlayer.tsx +++ b/app/src/components/ui/simulation/simulationPlayer.tsx @@ -1,6 +1,7 @@ import React, { useState, useRef, useEffect } from "react"; import { ExitIcon, PlayStopIcon, ResetIcon } from "../../icons/SimulationIcons"; import { usePlayButtonStore } from "../../../store/usePlayButtonStore"; +import { useActiveTool } from "../../../store/store"; const SimulationPlayer: React.FC = () => { const [speed, setSpeed] = useState<number>(1); @@ -8,6 +9,7 @@ const SimulationPlayer: React.FC = () => { const { setIsPlaying } = usePlayButtonStore(); const sliderRef = useRef<HTMLDivElement>(null); const isDragging = useRef(false); + const { setActiveTool } = useActiveTool(); // Button functions const handleReset = () => { @@ -19,6 +21,7 @@ const SimulationPlayer: React.FC = () => { const handleExit = () => { setPlaySimulation(false); setIsPlaying(false); + setActiveTool("cursor") }; // Slider functions starts diff --git a/app/src/modules/builder/agv/agv.tsx b/app/src/modules/builder/agv/agv.tsx index ace2e3e..6218662 100644 --- a/app/src/modules/builder/agv/agv.tsx +++ b/app/src/modules/builder/agv/agv.tsx @@ -19,7 +19,9 @@ const Agv = ({ }) => { const [pathPoints, setPathPoints] = useState< { - uuid: string; + modelUuid: string; + modelSpeed: number; + bufferTime: number; points: { x: number; y: number; z: number }[]; }[] >([]); @@ -32,6 +34,7 @@ const Agv = ({ (val: any) => val.modelName === "agv" ); + console.log("agvModels: ", agvModels); let findMesh = agvModels.filter( (val: any) => val.modeluuid === selectedActionSphere?.path?.modeluuid && @@ -49,8 +52,9 @@ const Agv = ({ "y" in findMesh[0].point.actions.end ? [ { - uuid: findMesh[0].modeluuid, // Ensure it's a number - + modelUuid: findMesh[0].modeluuid, // Ensure it's a number + modelSpeed: findMesh[0].point.speed, + bufferTime: findMesh[0].point.actions.buffer, points: [ { x: findMesh[0].position[0], @@ -72,15 +76,29 @@ const Agv = ({ ] : []; if (result.length > 0) { + // setPathPoints((prev) => [...prev, ...result]); setPathPoints((prev) => { - const existingUUIDs = new Set(prev.map((item) => item.uuid)); - const newItems = result.filter( - (item) => !existingUUIDs.has(item.uuid) + const existingIndex = prev.findIndex( + (item) => item.modelUuid === result[0].modelUuid ); - return [...prev, ...newItems]; + + if (existingIndex !== -1) { + const updatedPathPoints = [...prev]; + updatedPathPoints[existingIndex] = result[0]; + return updatedPathPoints; + } else { + return [...prev, ...result]; + } }); } } + // setPathPoints((prev) => { + // const existingUUIDs = new Set(prev.map((item) => item.uuid)); + // const newItems = result.filter( + // (item) => !existingUUIDs.has(item.uuid) + // ); + // return [...prev, ...newItems]; + // }); }, [simulationPaths, selectedActionSphere]); let groupRef = useRef() as Types.RefGroup; @@ -96,12 +114,40 @@ const Agv = ({ plane={plane} /> {pathPoints.map((pair, i) => ( - <PathNavigator - navMesh={navMesh} - selectedPoints={pair.points} - id={pair.uuid} - key={i} - /> + <> + <PathNavigator + navMesh={navMesh} + selectedPoints={pair.points} + id={pair.modelUuid} + key={i} + speed={pair.modelSpeed} + bufferTime={pair.bufferTime} + /> + {/* {pair.points.length > 2 && ( + <> + <mesh + position={[ + pair.points[1].x, + pair.points[1].y, + pair.points[1].z, + ]} + > + <sphereGeometry args={[0.3, 15, 15]} /> + <meshStandardMaterial color="red" /> + </mesh> + <mesh + position={[ + pair.points[2].x, + pair.points[2].y, + pair.points[2].z, + ]} + > + <sphereGeometry args={[0.3, 15, 15]} /> + <meshStandardMaterial color="red" /> + </mesh> + </> + )} */} + </> ))} <group ref={groupRef} visible={false} name="Meshes"></group> </> diff --git a/app/src/modules/builder/agv/pathNavigator.tsx b/app/src/modules/builder/agv/pathNavigator.tsx index 9da0d59..a83b690 100644 --- a/app/src/modules/builder/agv/pathNavigator.tsx +++ b/app/src/modules/builder/agv/pathNavigator.tsx @@ -3,30 +3,38 @@ import * as THREE from "three"; import { useFrame, useThree } from "@react-three/fiber"; import { NavMeshQuery } from "@recast-navigation/core"; import { Line } from "@react-three/drei"; -import { useTh } from "leva/dist/declarations/src/styles"; import { useActiveTool } from "../../../store/store"; +import { usePlayButtonStore } from "../../../store/usePlayButtonStore"; -// Define interface for props interface PathNavigatorProps { navMesh: any; selectedPoints: any; id: string; + speed: number; + bufferTime: number; } export default function PathNavigator({ navMesh, selectedPoints, id, + speed, + bufferTime, }: PathNavigatorProps) { const [path, setPath] = useState<[number, number, number][]>([]); const progressRef = useRef(0); const distancesRef = useRef<number[]>([]); const totalDistanceRef = useRef(0); const currentSegmentIndex = useRef(0); + const [stop, setStop] = useState<boolean>(true); const { scene } = useThree(); - const { activeTool } = useActiveTool(); + const { isPlaying, setIsPlaying } = usePlayButtonStore(); const [startPoint, setStartPoint] = useState(new THREE.Vector3()); - const meshRef = useRef<THREE.Mesh | null>(null); + const isWaiting = useRef<boolean>(false); // Flag to track waiting state + const delayTime = bufferTime; + + const movingForward = useRef<boolean>(true); // Tracks whether the object is moving forward + // Compute distances and total distance when the path changes useEffect(() => { if (!scene || !id || path.length < 2) return; @@ -39,19 +47,17 @@ export default function PathNavigator({ distances.push(segmentDistance); totalDistance += segmentDistance; } - distancesRef.current = distances; totalDistanceRef.current = totalDistance; - progressRef.current = 0; // Reset progress when the path changes + progressRef.current = 0; }, [path]); + useEffect(() => { if (!navMesh || selectedPoints.length === 0) return; - // Flatten the selectedPoints array into a single list of points const allPoints = selectedPoints.flat(); - - // Compute paths between consecutive points const computedPath: [number, number, number][] = []; + for (let i = 0; i < allPoints.length - 1; i++) { const start = allPoints[i]; setStartPoint( @@ -64,36 +70,35 @@ export default function PathNavigator({ const navMeshQuery = new NavMeshQuery(navMesh); const { path: segmentPath } = navMeshQuery.computePath(start, end); - if (segmentPath && segmentPath.length > 0) { - computedPath.push( - ...segmentPath.map(({ x, y, z }): [number, number, number] => [ - x, - y + 0.1, - z, - ]) - ); + if (!segmentPath || segmentPath.length === 0) { + continue; } + + computedPath.push( + ...segmentPath.map(({ x, y, z }): [number, number, number] => [ + x, + y + 0.1, + z, + ]) + ); } catch (error) {} } - // Set the full computed path - if (computedPath.length > 0) { setPath(computedPath); - currentSegmentIndex.current = 0; // Reset to the first segment + currentSegmentIndex.current = 0; } - }, [selectedPoints, navMesh, path]); - + }, [selectedPoints, navMesh]); useFrame((_, delta) => { if (!scene || !id || path.length < 2) return; - // Find the object in the scene + // Find the object in the scene by its UUID const findObject = scene.getObjectByProperty("uuid", id); - if (activeTool === "play") { - if (!findObject) return; + if (!findObject) return; - const speed = 5; - progressRef.current += delta * speed; + if (isPlaying) { + const fast = speed; + progressRef.current += delta * fast; let coveredDistance = progressRef.current; let accumulatedDistance = 0; @@ -108,9 +113,24 @@ export default function PathNavigator({ index++; } - // If the object has reached the end of the path, stop moving if (index >= distancesRef.current.length) { progressRef.current = totalDistanceRef.current; + + if (!isWaiting.current) { + isWaiting.current = true; // Set waiting flag + + setTimeout(() => { + progressRef.current = 0; // Reset progress + movingForward.current = !movingForward.current; // Toggle direction + + // Reverse the path and distances arrays + path.reverse(); + distancesRef.current.reverse(); + + // Reset the waiting flag + isWaiting.current = false; + }, delayTime * 1000); // Convert seconds to milliseconds + } return; } @@ -119,31 +139,35 @@ export default function PathNavigator({ const end = new THREE.Vector3(...path[index + 1]); const segmentDistance = distancesRef.current[index]; - const t = (coveredDistance - accumulatedDistance) / segmentDistance; + const t = Math.min( + (coveredDistance - accumulatedDistance) / segmentDistance, + 1 + ); // Clamp t to avoid overshooting const position = start.clone().lerp(end, t); findObject.position.copy(position); // Rotate the object to face the direction of movement const direction = new THREE.Vector3().subVectors(end, start).normalize(); - const targetQuaternion = new THREE.Quaternion().setFromUnitVectors( - new THREE.Vector3(0, 0, 1), // Assuming forward direction is (0, 0, 1) - direction - ); - findObject.quaternion.slerp(targetQuaternion, 0.1); // Smoothly interpolate rotation - } else if (activeTool === "cursor") { - findObject?.position.copy(startPoint); + const targetYRotation = Math.atan2(direction.x, direction.z); + findObject.rotation.y += (targetYRotation - findObject.rotation.y) * 0.1; + } else { + findObject.position.copy(startPoint); } }); - + return ( <> - {path.length > 0 && <Line points={path} color="blue" lineWidth={3} />} - {/* {path.length > 0 && ( - <mesh ref={meshRef} position={path.length > 0 ? path[0] : [0, 0.1, 0]}> - <boxGeometry args={[1, 1, 1]} /> - <meshNormalMaterial /> - </mesh> - )} */} + {path.length > 0 && ( + <> + <Line points={path} color="blue" lineWidth={3} /> + {selectedPoints.map((val: any, i: any) => ( + <mesh position={[val[0], val[1] + 1, val[2]]} key={i}> + <sphereGeometry args={[50, 5, 5]} /> + <meshBasicMaterial color={"red"} /> + </mesh> + ))} + </> + )} </> ); }