Merge remote-tracking branch 'origin/simulation-agv-v2' into v2

This commit is contained in:
2025-05-05 20:08:48 +05:30
6 changed files with 107 additions and 50 deletions

View File

@@ -38,14 +38,6 @@ const SimulationPlayer: React.FC = () => {
const { isReset, setReset } = useResetButtonStore(); const { isReset, setReset } = useResetButtonStore();
const { subModule } = useSubModuleStore(); const { subModule } = useSubModuleStore();
useEffect(() => {
if (isReset) {
setTimeout(()=>{
setReset(false);
},0)
}
}, [isReset])
// Button functions // Button functions
const handleReset = () => { const handleReset = () => {
setReset(true); setReset(true);
@@ -282,10 +274,11 @@ const SimulationPlayer: React.FC = () => {
</div> </div>
{index < intervals.length - 1 && ( {index < intervals.length - 1 && (
<div <div
className={`line ${progress >= ((index + 1) / totalSegments) * 100 className={`line ${
progress >= ((index + 1) / totalSegments) * 100
? "filled" ? "filled"
: "" : ""
}`} }`}
></div> ></div>
)} )}
</React.Fragment> </React.Fragment>

View File

@@ -34,16 +34,12 @@ const MachineAnimator = ({ currentPhase, handleCallBack, processingTime, machine
useEffect(() => { useEffect(() => {
isPlayingRef.current = isPlaying; isPlayingRef.current = isPlaying;
}, [isPlaying]); }, [isPlaying]);
useEffect(() => {
isResetRef.current = isReset;
}, [isReset]);
useEffect(() => { useEffect(() => {
if (isReset || !isPlaying) { if (isReset || !isPlaying) {
reset(); reset();
setReset(false);
startTimeRef.current = 0; startTimeRef.current = 0;
isPausedRef.current = false; isPausedRef.current = false;
pauseTimeRef.current = 0; pauseTimeRef.current = 0;
@@ -53,49 +49,53 @@ const MachineAnimator = ({ currentPhase, handleCallBack, processingTime, machine
} }
}, [isReset, isPlaying]) }, [isReset, isPlaying])
useEffect(() => { useEffect(() => {
if (currentPhase === 'processing' && !animationStarted.current && machineUuid) { if (currentPhase === 'processing' && !animationStarted.current && machineUuid) {
animationStarted.current = true; animationStarted.current = true;
startTimeRef.current = performance.now(); startTimeRef.current = performance.now();
animationFrameId.current = requestAnimationFrame(step); animationFrameId.current = requestAnimationFrame(step);
} }
}, [currentPhase]); }, [currentPhase]);
function step(time: number) { function step(time: number) {
if (!isPausedRef.current || !isResetRef.current) {
if (animationFrameId.current) { if (isPausedRef.current) {
if (!pauseTimeRef.current) {
pauseTimeRef.current = performance.now();
}
animationFrameId.current = requestAnimationFrame(step);
return;
}
if (pauseTimeRef.current) {
const pauseDuration = performance.now() - pauseTimeRef.current;
startTimeRef.current += pauseDuration;
pauseTimeRef.current = null;
}
const elapsed = time - startTimeRef.current;
const processedTime = (processingTime * 1000) / speed;
if (elapsed < processedTime) {
machineStatus(machineUuid, "Machine is currently processing the task");
animationFrameId.current = requestAnimationFrame(step);
} else {
animationStarted.current = false;
if (animationFrameId.current !== null) {
removeCurrentAction(machineUuid);
cancelAnimationFrame(animationFrameId.current); cancelAnimationFrame(animationFrameId.current);
animationFrameId.current = null; animationFrameId.current = null;
}
if (isPausedRef.current) {
if (!pauseTimeRef.current) {
pauseTimeRef.current = performance.now();
}
animationFrameId.current = requestAnimationFrame(step);
return;
}
if (pauseTimeRef.current) {
const pauseDuration = performance.now() - pauseTimeRef.current;
startTimeRef.current += pauseDuration;
pauseTimeRef.current = null;
}
const elapsed = time - startTimeRef.current;
const processedTime = processingTime * 1000;
if (elapsed < processedTime) {
machineStatus(machineUuid, "Machine is currently processing the task");
animationFrameId.current = requestAnimationFrame(step);
} else {
removeCurrentAction(machineUuid);
animationStarted.current = false;
handleCallBack(); handleCallBack();
} }
} }
} }
return null; return null;
} }

View File

@@ -10,10 +10,10 @@ function MachineInstance({ machineDetail }: any) {
const { machines, addCurrentAction, setMachineState, setMachineActive } = useMachineStore(); const { machines, addCurrentAction, setMachineState, setMachineActive } = useMachineStore();
const reset = () => { const reset = () => {
setCurrentPhase("idle");
setMachineState(machineDetail.modelUuid, 'idle'); setMachineState(machineDetail.modelUuid, 'idle');
setMachineActive(machineDetail.modelUuid, false); setMachineActive(machineDetail.modelUuid, false);
isIncrememtable.current = true; isIncrememtable.current = true;
setCurrentPhase("idle");
} }
const increment = () => { const increment = () => {
if (isIncrememtable.current) { if (isIncrememtable.current) {
@@ -31,7 +31,7 @@ function MachineInstance({ machineDetail }: any) {
if (!machineDetail.isActive && machineDetail.state === "idle" && currentPhase == "idle" && !machineDetail.currentAction) { if (!machineDetail.isActive && machineDetail.state === "idle" && currentPhase == "idle" && !machineDetail.currentAction) {
setTimeout(() => { setTimeout(() => {
increment(); increment();
}, 2000); }, 5000);
machineStatus(machineDetail.modelUuid, 'Machine is idle and waiting for next instruction.') machineStatus(machineDetail.modelUuid, 'Machine is idle and waiting for next instruction.')
} else if (!machineDetail.isActive && machineDetail.state === "idle" && currentPhase == "idle" && machineDetail.currentAction) { } else if (!machineDetail.isActive && machineDetail.state === "idle" && currentPhase == "idle" && machineDetail.currentAction) {
setCurrentPhase("processing"); setCurrentPhase("processing");
@@ -39,8 +39,6 @@ function MachineInstance({ machineDetail }: any) {
setMachineActive(machineDetail.modelUuid, true); setMachineActive(machineDetail.modelUuid, true);
machineStatus(machineDetail.modelUuid, "Machine started processing") machineStatus(machineDetail.modelUuid, "Machine started processing")
} }
} else {
reset();
} }
}, [currentPhase, isPlaying, machines]) }, [currentPhase, isPlaying, machines])
@@ -60,6 +58,7 @@ function MachineInstance({ machineDetail }: any) {
return ( return (
<> <>
<MachineAnimator processingTime={machineDetail.point.action.processTime} handleCallBack={handleCallBack} currentPhase={currentPhase} machineUuid={machineDetail.modelUuid} machineStatus={machineStatus} reset={reset} /> <MachineAnimator processingTime={machineDetail.point.action.processTime} handleCallBack={handleCallBack} currentPhase={currentPhase} machineUuid={machineDetail.modelUuid} machineStatus={machineStatus} reset={reset} />
</> </>
) )
} }

View File

@@ -0,0 +1,61 @@
import { useEffect, useRef, useState } from 'react';
import { useThree, useFrame } from '@react-three/fiber';
import * as THREE from 'three';
import { MaterialModel } from '../../../materials/instances/material/materialModel';
import { Html } from '@react-three/drei';
type MaterialAnimatorProps = {
agvDetail: VehicleStatus;
};
const MaterialAnimator = ({ agvDetail }: MaterialAnimatorProps) => {
const meshRef = useRef<any>(null!);
const [hasLoad, setHasLoad] = useState(false);
const { scene } = useThree();
const offset = new THREE.Vector3(0, 0.85, 0);
const [htmlPosition, setHtmlPosition] = useState<[number, number, number]>([0, 0, 0]);
const [htmlRotation, setHtmlRotation] = useState<[number, number, number]>([0, 0, 0]);
useEffect(() => {
setHasLoad(agvDetail.currentLoad > 0);
}, [agvDetail.currentLoad]);
useFrame(() => {
if (!hasLoad || !meshRef.current) return;
const agvModel = scene.getObjectByProperty("uuid", agvDetail.modelUuid) as THREE.Object3D;
if (agvModel) {
const worldPosition = offset.clone().applyMatrix4(agvModel.matrixWorld);
meshRef.current.position.copy(worldPosition);
setHtmlPosition([worldPosition.x, worldPosition.y, worldPosition.z]);
meshRef.current.rotation.copy(agvModel.rotation);
setHtmlRotation([agvModel.rotation.x, agvModel.rotation.y, agvModel.rotation.z]);
}
});
return (
<>
{hasLoad && (
<>
<MaterialModel
matRef={meshRef}
materialType={agvDetail.materialType || 'Default material'}
/>
<Html
position={htmlPosition}
rotation={htmlRotation}
style={{ backgroundColor: "pink", padding: "4px", borderRadius: "4px" }}
>
{agvDetail.currentLoad}
</Html>
</>
)}
</>
);
};
export default MaterialAnimator;

View File

@@ -199,7 +199,7 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai
return ( return (
<> <>
{currentPath.length > 0 && ( {currentPath.length > 0 && (
<> <group visible={false}>
<Line points={currentPath} color="blue" lineWidth={3} /> <Line points={currentPath} color="blue" lineWidth={3} />
{currentPath.map((point, index) => ( {currentPath.map((point, index) => (
<mesh key={index} position={point}> <mesh key={index} position={point}>
@@ -207,7 +207,7 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai
<meshStandardMaterial color="red" /> <meshStandardMaterial color="red" />
</mesh> </mesh>
))} ))}
</> </group>
)} )}
</> </>
); );

View File

@@ -5,11 +5,13 @@ import { NavMeshQuery } from '@recast-navigation/core';
import { useNavMesh } from '../../../../../store/store'; import { useNavMesh } from '../../../../../store/store';
import { usePlayButtonStore } from '../../../../../store/usePlayButtonStore'; import { usePlayButtonStore } from '../../../../../store/usePlayButtonStore';
import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore'; import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore';
import MaterialAnimator from '../animator/materialAnimator';
function VehicleInstance({ agvDetail }: any) { function VehicleInstance({ agvDetail }: any) {
const { navMesh } = useNavMesh(); const { navMesh } = useNavMesh();
const vehicleRef: any = useRef();
const { isPlaying } = usePlayButtonStore(); const { isPlaying } = usePlayButtonStore();
const { vehicles, setVehicleActive, setVehicleState, incrementVehicleLoad } = useVehicleStore(); const { vehicles, setVehicleActive, setVehicleState, incrementVehicleLoad, setMaterialType } = useVehicleStore();
const [currentPhase, setCurrentPhase] = useState<string>('stationed'); const [currentPhase, setCurrentPhase] = useState<string>('stationed');
const [path, setPath] = useState<[number, number, number][]>([]); const [path, setPath] = useState<[number, number, number][]>([]);
let isIncrememtable = useRef<boolean>(true); let isIncrememtable = useRef<boolean>(true);
@@ -44,8 +46,8 @@ function VehicleInstance({ agvDetail }: any) {
const increment = () => { const increment = () => {
if (isIncrememtable.current) { if (isIncrememtable.current) {
incrementVehicleLoad(agvDetail.modelUuid, 10); incrementVehicleLoad(agvDetail.modelUuid, 10);
setMaterialType(agvDetail.modelUuid, 'Material 1')
isIncrememtable.current = false; isIncrememtable.current = false;
} }
} }
@@ -71,7 +73,7 @@ function VehicleInstance({ agvDetail }: any) {
}, 5000); }, 5000);
if (agvDetail.currentLoad === agvDetail.point.action.loadCapacity) { if (agvDetail.currentLoad === agvDetail.point.action.loadCapacity && agvDetail.materialType) {
const toDrop = computePath( const toDrop = computePath(
agvDetail.point.action.pickUpPoint.position, agvDetail.point.action.pickUpPoint.position,
agvDetail.point.action.unLoadPoint.position agvDetail.point.action.unLoadPoint.position
@@ -118,6 +120,7 @@ function VehicleInstance({ agvDetail }: any) {
setVehicleState(agvDetail.modelUuid, 'idle'); setVehicleState(agvDetail.modelUuid, 'idle');
setVehicleActive(agvDetail.modelUuid, false); setVehicleActive(agvDetail.modelUuid, false);
setPath([]); setPath([]);
setMaterialType(agvDetail.modelUuid, null)
vehicleStatus(agvDetail.modelUuid, 'Reached pickup point again, cycle complete'); vehicleStatus(agvDetail.modelUuid, 'Reached pickup point again, cycle complete');
} }
} }
@@ -132,6 +135,7 @@ function VehicleInstance({ agvDetail }: any) {
agvDetail={agvDetail} agvDetail={agvDetail}
reset={reset} reset={reset}
/> />
<MaterialAnimator agvDetail={agvDetail} />
</> </>
); );
} }