Merge remote-tracking branch 'origin/main-demo' into feature/predefined-path

This commit is contained in:
2025-08-22 09:12:02 +05:30
98 changed files with 7090 additions and 3036 deletions

View File

@@ -13,30 +13,44 @@ const MaterialAnimator = ({ agvDetail }: { agvDetail: VehicleStatus }) => {
useEffect(() => {
const loadState = agvDetail.currentLoad > 0;
setHasLoad(loadState);
if (!loadState) {
setIsAttached(false);
if (meshRef.current?.parent) {
meshRef.current.parent.remove(meshRef.current);
const agvModel = scene.getObjectByProperty("uuid", agvDetail.modelUuid) as THREE.Object3D;
if (agvModel) {
const material = agvModel.getObjectByName('Sample-Material');
if (material) {
agvModel.remove(material);
}
}
}
}, [agvDetail.currentLoad]);
useFrame(() => {
// if (agvDetail.currentMaterials.length === 0 || agvDetail.currentLoad === 0) {
// const agvModel = scene.getObjectByProperty("uuid", agvDetail.modelUuid) as THREE.Object3D;
// if (agvModel) {
// const material = agvModel.getObjectByName('Sample-Material');
// if (material) {
// agvModel.remove(material);
// }
// }
// }
if (!hasLoad || !meshRef.current || isAttached) return;
const agvModel = scene.getObjectByProperty("uuid", agvDetail.modelUuid) as THREE.Object3D;
if (agvModel && !isAttached) {
if (meshRef.current.parent) {
meshRef.current.parent.remove(meshRef.current);
const material = agvModel.getObjectByName('Sample-Material');
if (material) {
agvModel.remove(material);
}
agvModel.add(meshRef.current);
meshRef.current.position.copy(offset);
meshRef.current.rotation.set(0, 0, 0);
meshRef.current.scale.set(1, 1, 1);
setIsAttached(true);
}
});
@@ -45,6 +59,7 @@ const MaterialAnimator = ({ agvDetail }: { agvDetail: VehicleStatus }) => {
<>
{hasLoad && agvDetail.currentMaterials.length > 0 && (
<MaterialModel
name={'Sample-Material'}
matRef={meshRef}
materialId={agvDetail.currentMaterials[0].materialId || ''}
materialType={agvDetail.currentMaterials[0].materialType || 'Default material'}

View File

@@ -183,7 +183,7 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai
return (
<>
{selectedPath === "auto" &&
<group>
<group visible={false}>
{currentPath.map((pos, i) => {
if (i < currentPath.length - 1) {
return (

View File

@@ -12,24 +12,26 @@ import MaterialAnimator from '../animator/materialAnimator';
import VehicleAnimator from '../animator/vehicleAnimator';
import { useHumanEventManager } from '../../../human/eventManager/useHumanEventManager';
import { useCraneEventManager } from '../../../crane/eventManager/useCraneEventManager';
function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>) {
const { navMesh } = useNavMesh();
const { isPlaying } = usePlayButtonStore();
const { materialStore, armBotStore, conveyorStore, vehicleStore, storageUnitStore, humanStore, productStore, assetStore } = useSceneContext();
const { materialStore, armBotStore, conveyorStore, vehicleStore, storageUnitStore, humanStore, craneStore, productStore, assetStore } = useSceneContext();
const { removeMaterial, setEndTime, setIsVisible } = materialStore();
const { getStorageUnitById } = storageUnitStore();
const { getHumanById, addCurrentAction, addCurrentMaterial, incrementHumanLoad } = humanStore();
const { getCraneById, addCurrentAction: addCraneAction, addCurrentMaterial: addCraneMaterial, incrementCraneLoad } = craneStore();
const { getArmBotById } = armBotStore();
const { getConveyorById } = conveyorStore();
const { triggerPointActions } = useTriggerHandler();
const { setCurrentAnimation, getAssetById } = assetStore();
const { addHumanToMonitor } = useHumanEventManager();
const { addCraneToMonitor } = useCraneEventManager();
const { getActionByUuid, getEventByModelUuid, getTriggerByUuid } = productStore();
const { selectedProductStore } = useProductContext();
const { selectedProduct } = selectedProductStore();
const { vehicles, setVehicleActive, setVehicleState, setVehiclePicking, clearCurrentMaterials, setVehicleLoad, decrementVehicleLoad, removeLastMaterial, getLastMaterial, incrementIdleTime, incrementActiveTime, resetTime } = vehicleStore();
const [currentPhase, setCurrentPhase] = useState<string>('stationed');
const { vehicles, setCurrentPhase, setVehicleActive, setVehicleState, setVehiclePicking, clearCurrentMaterials, setVehicleLoad, decrementVehicleLoad, removeLastMaterial, getLastMaterial, incrementIdleTime, incrementActiveTime, resetTime } = vehicleStore();
const [path, setPath] = useState<[number, number, number][]>([]);
const pauseTimeRef = useRef<number | null>(null);
const idleTimeRef = useRef<number>(0);
@@ -80,7 +82,7 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
// Function to reset everything
function reset() {
setCurrentPhase('stationed');
setCurrentPhase(agvDetail.modelUuid, 'stationed');
setVehicleActive(agvDetail.modelUuid, false);
setVehiclePicking(agvDetail.modelUuid, false);
setVehicleState(agvDetail.modelUuid, 'idle');
@@ -103,20 +105,20 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
if (isPlaying && selectedPath === "auto") {
if (!agvDetail.point.action.unLoadPoint || !agvDetail.point.action.pickUpPoint) return;
if (!agvDetail.isActive && agvDetail.state === 'idle' && currentPhase === 'stationed') {
if (!agvDetail.isActive && agvDetail.state === 'idle' && agvDetail.currentPhase === 'stationed') {
const toPickupPath = computePath(
new THREE.Vector3(agvDetail?.position[0], agvDetail?.position[1], agvDetail?.position[2]),
agvDetail?.point?.action?.pickUpPoint?.position
);
setPath(toPickupPath);
setCurrentPhase('stationed-pickup');
setCurrentPhase(agvDetail.modelUuid, 'stationed-pickup');
setVehicleState(agvDetail.modelUuid, 'running');
setVehiclePicking(agvDetail.modelUuid, false);
setVehicleActive(agvDetail.modelUuid, true);
vehicleStatus(agvDetail.modelUuid, 'Started from station, heading to pickup');
return;
} else if (!agvDetail.isActive && agvDetail.state === 'idle' && currentPhase === 'picking') {
} else if (!agvDetail.isActive && agvDetail.state === 'idle' && agvDetail.currentPhase === 'picking') {
if (agvDetail.currentLoad === agvDetail.point.action.loadCapacity && agvDetail.currentMaterials.length > 0) {
if (agvDetail.point.action.pickUpPoint && agvDetail.point.action.unLoadPoint) {
const toDrop = computePath(
@@ -124,21 +126,21 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
agvDetail.point.action.unLoadPoint.position
);
setPath(toDrop);
setCurrentPhase('pickup-drop');
setCurrentPhase(agvDetail.modelUuid, 'pickup-drop');
setVehicleState(agvDetail.modelUuid, 'running');
setVehiclePicking(agvDetail.modelUuid, false);
setVehicleActive(agvDetail.modelUuid, true);
vehicleStatus(agvDetail.modelUuid, 'Started from pickup point, heading to drop point');
}
}
} else if (!agvDetail.isActive && agvDetail.state === 'idle' && currentPhase === 'dropping' && agvDetail.currentLoad === 0) {
} else if (!agvDetail.isActive && agvDetail.state === 'idle' && agvDetail.currentPhase === 'dropping' && agvDetail.currentLoad === 0) {
if (agvDetail.point.action.pickUpPoint && agvDetail.point.action.unLoadPoint) {
const dropToPickup = computePath(
agvDetail.point.action.unLoadPoint.position,
agvDetail.point.action.pickUpPoint.position
);
setPath(dropToPickup);
setCurrentPhase('drop-pickup');
setCurrentPhase(agvDetail.modelUuid, 'drop-pickup');
setVehicleState(agvDetail.modelUuid, 'running');
setVehiclePicking(agvDetail.modelUuid, false);
setVehicleActive(agvDetail.modelUuid, true);
@@ -149,7 +151,7 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
else {
reset()
}
}, [vehicles, currentPhase, path, isPlaying, selectedPath]);
}, [vehicles, agvDetail.currentPhase, path, isPlaying, selectedPath]);
function animate(currentTime: number) {
if (previousTimeRef.current === null) {
@@ -198,22 +200,22 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
}, [agvDetail, isPlaying]);
function handleCallBack() {
if (currentPhase === 'stationed-pickup') {
setCurrentPhase('picking');
if (agvDetail.currentPhase === 'stationed-pickup') {
setCurrentPhase(agvDetail.modelUuid, 'picking');
setVehicleState(agvDetail.modelUuid, 'idle');
setVehiclePicking(agvDetail.modelUuid, true);
setVehicleActive(agvDetail.modelUuid, false);
vehicleStatus(agvDetail.modelUuid, 'Reached pickup point, waiting for material');
setPath([]);
} else if (currentPhase === 'pickup-drop') {
setCurrentPhase('dropping');
} else if (agvDetail.currentPhase === 'pickup-drop') {
setCurrentPhase(agvDetail.modelUuid, 'dropping');
setVehicleState(agvDetail.modelUuid, 'idle');
setVehiclePicking(agvDetail.modelUuid, false);
setVehicleActive(agvDetail.modelUuid, false);
vehicleStatus(agvDetail.modelUuid, 'Reached drop point');
setPath([]);
} else if (currentPhase === 'drop-pickup') {
setCurrentPhase('picking');
} else if (agvDetail.currentPhase === 'drop-pickup') {
setCurrentPhase(agvDetail.modelUuid, 'picking');
setVehicleState(agvDetail.modelUuid, 'idle');
setVehiclePicking(agvDetail.modelUuid, true);
setVehicleActive(agvDetail.modelUuid, false);
@@ -252,6 +254,12 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
if (action && (triggeredAction?.actionType === 'assembly' || triggeredAction?.actionType === 'worker')) {
handleMaterialDropToHuman(model, triggeredAction);
}
} else if (model.type === 'crane') {
const action = getActionByUuid(selectedProduct.productUuid, agvDetail.point.action.actionUuid);
if (action && (triggeredAction?.actionType === 'pickAndDrop')) {
handleMaterialDropToCrane(model, triggeredAction);
addCraneAction(model.modelUuid, triggeredAction.actionUuid, null, null);
}
}
} else {
const droppedMaterial = agvDetail.currentLoad;
@@ -265,6 +273,64 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
}
}
function handleMaterialDropToCrane(model: CraneEventSchema, action: CraneAction) {
if (model) {
if (action.actionType === 'pickAndDrop') {
addCraneToMonitor(model.modelUuid, () => {
loopMaterialDropToCrane(
agvDetail,
model.modelUuid,
action.actionUuid
);
}, action.actionUuid || '')
}
}
}
function loopMaterialDropToCrane(
vehicle: VehicleStatus,
craneId: string,
craneActionId: string
) {
let currentVehicleLoad = vehicle.currentLoad;
const unloadLoop = () => {
const crane = getCraneById(craneId);
const craneaction = crane?.point.actions.find((action) => action.actionUuid === craneActionId);
if (!crane || crane.currentAction?.actionUuid !== craneaction?.actionUuid) return;
if (crane.isCarrying) {
decrementVehicleLoad(vehicle.modelUuid, 1);
currentVehicleLoad -= 1;
const material = removeLastMaterial(vehicle.modelUuid);
if (material) {
setIsVisible(material.materialId, false);
}
return;
} else if (!crane.isCarrying && !crane.isActive && crane.currentLoad < (craneaction?.maxPickUpCount || 0) && craneaction?.actionType === 'pickAndDrop') {
const material = getLastMaterial(vehicle.modelUuid);
if (material) {
incrementCraneLoad(craneId, 1);
addCraneAction(craneId, craneActionId, material.materialType, material.materialId);
addCraneMaterial(craneId, material.materialType, material.materialId);
}
}
setTimeout(() => {
requestAnimationFrame(unloadLoop);
}, 500)
};
const crane = getCraneById(craneId);
const craneaction = crane?.point.actions.find((action) => action.actionUuid === craneActionId);
if (crane && crane.currentLoad < (craneaction?.maxPickUpCount || 0)) {
setTimeout(() => {
unloadLoop();
}, 500)
}
}
function handleMaterialDropToHuman(model: HumanEventSchema, action: HumanAction) {
if (model) {
@@ -576,7 +642,7 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
<VehicleAnimator
path={path}
handleCallBack={handleCallBack}
currentPhase={currentPhase}
currentPhase={agvDetail.currentPhase}
agvUuid={agvDetail?.modelUuid}
agvDetail={agvDetail}
reset={reset}