diff --git a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx index a3af481..9d51a8d 100644 --- a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx +++ b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx @@ -64,7 +64,91 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai } }, [isReset, isPlaying]) - useFrame((_, delta) => { + // useFrame((_, delta) => { + // const object = scene.getObjectByProperty('uuid', agvUuid); + // if (!object || currentPath.length < 2) return; + // if (isPaused) return; + + // let totalDistance = 0; + // const distances = []; + // let accumulatedDistance = 0; + // let index = 0; + // const rotationSpeed = 1; + + // for (let i = 0; i < currentPath.length - 1; i++) { + // const start = new THREE.Vector3(...currentPath[i]); + // const end = new THREE.Vector3(...currentPath[i + 1]); + // const segmentDistance = start.distanceTo(end); + // distances.push(segmentDistance); + // totalDistance += segmentDistance; + // } + + // while (index < distances.length && progressRef.current > accumulatedDistance + distances[index]) { + // accumulatedDistance += distances[index]; + // index++; + // } + + // if (index < distances.length) { + // const start = new THREE.Vector3(...currentPath[index]); + // const end = new THREE.Vector3(...currentPath[index + 1]); + // const segmentDistance = distances[index]; + + // const currentDirection = new THREE.Vector3().subVectors(end, start).normalize(); + // const targetAngle = Math.atan2(currentDirection.x, currentDirection.z); + + // const currentAngle = object.rotation.y; + + // let angleDifference = targetAngle - currentAngle; + // if (angleDifference > Math.PI) angleDifference -= 2 * Math.PI; + // if (angleDifference < -Math.PI) angleDifference += 2 * Math.PI; + + // const maxRotationStep = (rotationSpeed * speed * agvDetail.speed) * delta; + // object.rotation.y += Math.sign(angleDifference) * Math.min(Math.abs(angleDifference), maxRotationStep); + // const isAligned = Math.abs(angleDifference) < 0.01; + + // if (isAligned) { + // progressRef.current += delta * (speed * agvDetail.speed); + // const t = (progressRef.current - accumulatedDistance) / segmentDistance; + // const position = start.clone().lerp(end, t); + // object.position.copy(position); + // } + // } + + // if (progressRef.current >= totalDistance) { + // if (restRotation && objectRotation) { + // const targetEuler = new THREE.Euler( + // objectRotation.x, + // objectRotation.y - (agvDetail.point.action.steeringAngle), + // objectRotation.z + // ); + // const targetQuaternion = new THREE.Quaternion().setFromEuler(targetEuler); + // object.quaternion.slerp(targetQuaternion, delta * (rotationSpeed * speed * agvDetail.speed)); + // if (object.quaternion.angleTo(targetQuaternion) < 0.01) { + // object.quaternion.copy(targetQuaternion); + // object.rotation.copy(targetEuler); + // setRestingRotation(false); + // } + // return; + // } + // } + // if (progressRef.current >= totalDistance) { + // setRestingRotation(true); + // progressRef.current = 0; + // movingForward.current = !movingForward.current; + // setCurrentPath([]); + // handleCallBack(); + // if (currentPhase === 'pickup-drop') { + // requestAnimationFrame(startUnloadingProcess); + // } + // } + // }); + const lastTimeRef = useRef(performance.now()); + + useFrame(() => { + const now = performance.now(); + const delta = (now - lastTimeRef.current) / 1000; + lastTimeRef.current = now; + const object = scene.getObjectByProperty('uuid', agvUuid); if (!object || currentPath.length < 2) return; if (isPaused) return; @@ -95,7 +179,6 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai const currentDirection = new THREE.Vector3().subVectors(end, start).normalize(); const targetAngle = Math.atan2(currentDirection.x, currentDirection.z); - const currentAngle = object.rotation.y; let angleDifference = targetAngle - currentAngle; @@ -118,7 +201,7 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai if (restRotation && objectRotation) { const targetEuler = new THREE.Euler( objectRotation.x, - objectRotation.y - (agvDetail.point.action.steeringAngle), + objectRotation.y - agvDetail.point.action.steeringAngle, objectRotation.z ); const targetQuaternion = new THREE.Quaternion().setFromEuler(targetEuler); @@ -131,6 +214,7 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai return; } } + if (progressRef.current >= totalDistance) { setRestingRotation(true); progressRef.current = 0; diff --git a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx index f4e7e61..3b6568d 100644 --- a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx +++ b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx @@ -20,16 +20,20 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>) const { triggerPointActions } = useTriggerHandler(); const { getActionByUuid, getEventByModelUuid, getTriggerByUuid } = useProductStore(); const { selectedProduct } = useSelectedProduct(); - const { vehicles, setVehicleActive, setVehicleState, setVehiclePicking, clearCurrentMaterials, setVehicleLoad, decrementVehicleLoad, removeLastMaterial } = useVehicleStore(); + const { vehicles, setVehicleActive, setVehicleState, setVehiclePicking, clearCurrentMaterials, setVehicleLoad, decrementVehicleLoad, removeLastMaterial, incrementIdleTime, incrementActiveTime } = useVehicleStore(); + const [currentPhase, setCurrentPhase] = useState('stationed'); const [path, setPath] = useState<[number, number, number][]>([]); const pauseTimeRef = useRef(null); + const idleTimeRef = useRef(0); + const activeTimeRef = useRef(0); const isPausedRef = useRef(false); let startTime: number; let fixedInterval: number; const { speed } = useAnimationPlaySpeed(); const { isPaused } = usePauseButtonStore(); + useEffect(() => { isPausedRef.current = isPaused; }, [isPaused]); @@ -117,6 +121,157 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>) } // eslint-disable-next-line react-hooks/exhaustive-deps }, [vehicles, currentPhase, path, isPlaying]); + const previousTimeRef = useRef(null); // Tracks the last frame time + const isActiveRef = useRef(agvDetail.isActive); // Tracks the previous isActive state + const animationFrameIdRef = useRef(null); // Tracks the animation frame ID + + // // Animate function (moved outside useEffect) + // function animate(currentTime: number) { + // if (previousTimeRef.current === null) { + // // Initialize previousTime on the first frame + // previousTimeRef.current = currentTime; + // } + + // const deltaTime = (currentTime - previousTimeRef.current) / 1000; // Time difference in seconds + // previousTimeRef.current = currentTime; + + // if (idleTimeRef.current == 0) { + // activeTimeRef.current += deltaTime * speed; // Scale active time by speed + // const roundedActiveTime = Math.round(activeTimeRef.current); // Round to nearest integer + // console.log('Active Time:', roundedActiveTime, 'seconds'); + // incrementActiveTime(agvDetail.modelUuid, roundedActiveTime); + // incrementIdleTime(agvDetail.modelUuid, 0); + // } else if (activeTimeRef.current = 0) { + // idleTimeRef.current += deltaTime * speed; // Scale idle time by speed + // const roundedIdleTime = Math.round(idleTimeRef.current); // Round to nearest integer + // console.log('Idle Time:', roundedIdleTime, 'seconds'); + // incrementIdleTime(agvDetail.modelUuid, roundedIdleTime); + // incrementActiveTime(agvDetail.modelUuid, 0); + // } + + // // Request the next animation frame + // animationFrameIdRef.current = requestAnimationFrame(animate); + // } + + // useEffect(() => { + + // // Reset timers when transitioning between states + // if (!agvDetail.isActive) { + // activeTimeRef.current = 0; + // } else { + // idleTimeRef.current = 0; + // } + + // if (animationFrameIdRef.current === null) { + // animationFrameIdRef.current = requestAnimationFrame(animate); + // } + // console.log("veh", vehicles); + // // Cleanup function to stop the animation loop + // return () => { + // if (animationFrameIdRef.current !== null) { + // cancelAnimationFrame(animationFrameIdRef.current); + // animationFrameIdRef.current = null; // Reset the animation frame ID + // } + // }; + // }, [agvDetail.isActive]); + // Animate function (moved outside useEffect) + function animate(currentTime: number) { + if (previousTimeRef.current === null) { + // Initialize previousTime on the first frame + previousTimeRef.current = currentTime; + } + + const deltaTime = (currentTime - previousTimeRef.current) / 1000; // Time difference in seconds + previousTimeRef.current = currentTime; + + if (agvDetail.isActive) { + // AGV is active: Increment active time + activeTimeRef.current += deltaTime * speed; // Scale active time by speed + const roundedActiveTime = Math.round(activeTimeRef.current); // Round to nearest integer + + } else { + + idleTimeRef.current += deltaTime * speed; // Scale idle time by speed + const roundedIdleTime = Math.round(idleTimeRef.current); // Round to nearest integer + + } + + // Request the next animation frame + animationFrameIdRef.current = requestAnimationFrame(animate); + } + + useEffect(() => { + // Start or stop the animation based on the isActive state + + if (!agvDetail.isActive) { + // Transitioning to idle: Reset idle time + const roundedIdleTime = Math.round(idleTimeRef.current); // Get the final rounded idle time + console.log('Final Idle Time:', roundedIdleTime, 'seconds'); + incrementIdleTime(agvDetail.modelUuid, roundedIdleTime); + activeTimeRef.current = 0; + } else { + // Transitioning to active: Finalize idle time and pass it to incrementIdleTime + const roundedActiveTime = Math.round(activeTimeRef.current); // Round to nearest integer + console.log('Active Time:', roundedActiveTime, 'seconds'); + incrementActiveTime(agvDetail.modelUuid, roundedActiveTime); + idleTimeRef.current = 0; // Reset idle time + } + + + + // Start the animation loop if not already running + if (animationFrameIdRef.current === null) { + animationFrameIdRef.current = requestAnimationFrame(animate); + } + + // Cleanup function to stop the animation loop + return () => { + if (animationFrameIdRef.current !== null) { + cancelAnimationFrame(animationFrameIdRef.current); + animationFrameIdRef.current = null; // Reset the animation frame ID + } + }; + }, [agvDetail.isActive]); + // let position = 0; + // let previousTime: number; + + // function animate(currentTime: number) { + // previousTime = performance.now(); + + // const deltaTime = (currentTime - previousTime) / 1000; + // previousTime = currentTime; + + // position += speed * deltaTime; + // console.log('deltaTime: ', deltaTime); + // console.log('position: ', position); + // if (idleTimeRef.current === 0) { + // activeTimeRef.current = position; + // console.log('position: active', position); + // console.log(' activeTimeRef.current: ', activeTimeRef.current); + // incrementActiveTime(agvDetail.modelUuid, position) + // incrementIdleTime(agvDetail.modelUuid, idleTimeRef.current) + // } + // else if (activeTimeRef.current === 0) { + // idleTimeRef.current = position; + // console.log('position:idle ', position); + // console.log(' idleTimeRef.current: ', idleTimeRef.current); + // incrementActiveTime(agvDetail.modelUuid, activeTimeRef.current) + // incrementIdleTime(agvDetail.modelUuid, position) + // } + // } + + // useEffect(() => { + // if (agvDetail.isActive) { + // idleTimeRef.current = 0; + // activeTimeRef.current = performance.now(); + // requestAnimationFrame(animate); + // } else { + // activeTimeRef.current = 0; + // idleTimeRef.current = performance.now(); + // requestAnimationFrame(animate); + // } + // console.log('vehicles: ', vehicles); + // }, [agvDetail.isActive]); function handleCallBack() { if (currentPhase === 'stationed-pickup') {