human to conveyor, conveyor to human multiple actions completed

This commit is contained in:
2025-07-17 09:44:08 +05:30
parent e9053ccd1b
commit fe09c3df56
47 changed files with 1155 additions and 1008 deletions

View File

@@ -180,7 +180,6 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai
setCurrentPath(updated);
};
return (
<>
{selectedPath === "auto" &&

View File

@@ -11,16 +11,20 @@ import InteractivePoints from '../animator/interactivePoint';
import MaterialAnimator from '../animator/materialAnimator';
import VehicleAnimator from '../animator/vehicleAnimator';
import { useHumanEventManager } from '../../../human/eventManager/useHumanEventManager';
function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>) {
const { navMesh } = useNavMesh();
const { isPlaying } = usePlayButtonStore();
const { materialStore, armBotStore, conveyorStore, vehicleStore, storageUnitStore, humanStore, productStore } = useSceneContext();
const { removeMaterial, setEndTime } = materialStore();
const { materialStore, armBotStore, conveyorStore, vehicleStore, storageUnitStore, humanStore, productStore, assetStore } = useSceneContext();
const { removeMaterial, setEndTime, setIsVisible } = materialStore();
const { getStorageUnitById } = storageUnitStore();
const { getHumanById } = humanStore();
const { getHumanById, addCurrentAction } = humanStore();
const { getArmBotById } = armBotStore();
const { getConveyorById } = conveyorStore();
const { triggerPointActions } = useTriggerHandler();
const { setCurrentAnimation, getAssetById } = assetStore();
const { addHumanToMonitor } = useHumanEventManager();
const { getActionByUuid, getEventByModelUuid, getTriggerByUuid } = productStore();
const { selectedProductStore } = useProductContext();
const { selectedProduct } = selectedProductStore();
@@ -96,7 +100,7 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
}
useEffect(() => {
if (isPlaying || selectedPath === "auto") {
if (isPlaying && selectedPath === "auto") {
if (!agvDetail.point.action.unLoadPoint || !agvDetail.point.action.pickUpPoint) return;
if (!agvDetail.isActive && agvDetail.state === 'idle' && currentPhase === 'stationed') {
@@ -223,6 +227,7 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
if (agvDetail.point.action.triggers.length > 0) {
const trigger = getTriggerByUuid(selectedProduct.productUuid, agvDetail.point.action.triggers[0]?.triggerUuid);
const model = getEventByModelUuid(selectedProduct.productUuid, trigger?.triggeredAsset?.triggeredModel?.modelUuid || '');
const triggeredAction = getActionByUuid(selectedProduct.productUuid, trigger?.triggeredAsset?.triggeredAction?.actionUuid || '');
if (trigger && model) {
if (model.type === 'transfer') {
@@ -244,8 +249,8 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
}
} else if (model.type === 'human') {
const action = getActionByUuid(selectedProduct.productUuid, agvDetail.point.action.actionUuid);
if (action) {
handleMaterialDropToHuman(model);
if (action && (triggeredAction?.actionType === 'assembly' || triggeredAction?.actionType === 'worker')) {
handleMaterialDropToHuman(model, triggeredAction);
}
}
} else {
@@ -260,75 +265,56 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
}
}
function handleMaterialDropToHuman(model: HumanEventSchema) {
function handleMaterialDropToHuman(model: HumanEventSchema, action: HumanAction) {
if (model) {
if (model.point.action.actionType === 'worker') {
loopMaterialDropToHuman(
agvDetail.modelUuid,
agvDetail.currentLoad,
agvDetail.point.action.unLoadDuration,
model.modelUuid,
model.point.action.loadCapacity,
agvDetail.point.action
);
if (action.actionType === 'worker') {
addHumanToMonitor(model.modelUuid, () => {
loopMaterialDropToHuman(
agvDetail,
model.modelUuid,
agvDetail.point.action,
action.actionUuid
);
}, action.actionUuid || '')
}
}
}
function loopMaterialDropToHuman(
vehicleId: string,
vehicleCurrentLoad: number,
unLoadDuration: number,
vehicle: VehicleStatus,
humanId: string,
storageMaxCapacity: number,
action: VehicleAction
vehicleAction: VehicleAction,
humanActionId: string
) {
startTime = performance.now();
const fixedInterval = ((unLoadDuration / vehicleCurrentLoad) * (1000 / isSpeedRef.current));
let currentVehicleLoad = vehicle.currentLoad;
const unloadLoop = () => {
if (isPausedRef.current) {
pauseTimeRef.current ??= performance.now();
requestAnimationFrame(unloadLoop);
return;
}
if (pauseTimeRef.current) {
const pauseDuration = performance.now() - pauseTimeRef.current;
startTime += pauseDuration;
pauseTimeRef.current = null;
}
const elapsedTime = performance.now() - startTime;
const human = getHumanById(humanId);
const humanAsset = getAssetById(humanId);
const humanAction = human?.point.actions.find((action) => action.actionUuid === humanActionId);
if (elapsedTime >= fixedInterval) {
if (human && agvDetail &&
human.currentLoad < storageMaxCapacity &&
vehicleCurrentLoad > 0) {
if (!human || human.currentAction?.actionUuid !== humanAction?.actionUuid) return;
decrementVehicleLoad(vehicleId, 1);
vehicleCurrentLoad -= 1;
const material = removeLastMaterial(vehicleId);
if (material) {
triggerPointActions(action, material.materialId);
}
if (vehicleCurrentLoad > 0 && human.currentLoad < storageMaxCapacity) {
startTime = performance.now();
requestAnimationFrame(unloadLoop);
}
if (humanAsset && human.currentMaterials.length > 0 && humanAsset.animationState?.current === 'pickup' && humanAsset.animationState?.isCompleted) {
decrementVehicleLoad(vehicle.modelUuid, 1);
currentVehicleLoad -= 1;
const material = removeLastMaterial(vehicle.modelUuid);
if (material) {
setIsVisible(material.materialId, false);
}
} else {
requestAnimationFrame(unloadLoop);
} else if (!human.isActive && human.currentLoad < (humanAction?.loadCapacity || 0) && humanAsset?.animationState?.current === 'waiting') {
setCurrentAnimation(human.modelUuid, 'pickup', true, false, false);
}
setTimeout(() => {
requestAnimationFrame(unloadLoop);
}, 150)
};
const human = getHumanById(humanId);
if (human && vehicleCurrentLoad > 0 && human?.currentLoad < storageMaxCapacity) {
const humanAction = human?.point.actions.find((action) => action.actionUuid === humanActionId);
if (human && human.currentAction?.actionUuid !== humanActionId && human.currentLoad < (humanAction?.loadCapacity || 0)) {
addCurrentAction(humanId, humanActionId);
unloadLoop();
}
}

View File

@@ -1,25 +1,32 @@
import { useRef } from "react";
import { useNavMesh } from "../../../../store/builder/store";
import PolygonGenerator from "./polygonGenerator";
import NavMeshDetails from "./navMeshDetails";
import * as CONSTANTS from "../../../../types/world/worldConstants";
import * as Types from "../../../../types/world/worldTypes";
import { useLoadingProgress, useNavMesh, useTileDistance } from "../../../../store/builder/store";
import useModuleStore from "../../../../store/useModuleStore";
import PolygonGenerator from "./polygonGenerator";
import NavMeshDetails from "./navMeshDetails";
function NavMesh() {
let groupRef = useRef() as Types.RefGroup;
const { setNavMesh } = useNavMesh();
const { loadingProgress } = useLoadingProgress();
const { activeModule } = useModuleStore();
const { planeValue, gridValue } = useTileDistance();
return (
<>
<PolygonGenerator groupRef={groupRef} />
<NavMeshDetails setNavMesh={setNavMesh} groupRef={groupRef} />
{activeModule === 'simulation' && loadingProgress === 0 &&
<>
<PolygonGenerator groupRef={groupRef} />
<NavMeshDetails setNavMesh={setNavMesh} groupRef={groupRef} />
<group ref={groupRef} visible={false} name="Meshes">
<mesh rotation-x={CONSTANTS.planeConfig.rotation} position={CONSTANTS.planeConfig.position3D} receiveShadow>
<planeGeometry args={[300, 300]} />
<meshBasicMaterial color={CONSTANTS.planeConfig.color} />
</mesh>
</group>
<group ref={groupRef} visible={false} name="Meshes">
<mesh rotation-x={CONSTANTS.planeConfig.rotation} position={CONSTANTS.planeConfig.position3D} receiveShadow>
<planeGeometry args={[planeValue.width, planeValue.height]} />
</mesh>
</group>
</>
}
</>
)
}

View File

@@ -1,10 +1,9 @@
import React, { useEffect } from "react";
import React, { useEffect, useMemo } from "react";
import * as THREE from "three";
import { useThree } from "@react-three/fiber";
import { generateSoloNavMesh } from "@recast-navigation/generators";
import { init as initRecastNavigation } from "@recast-navigation/core";
import { DebugDrawer, getPositionsAndIndices } from "@recast-navigation/three";
import { useSceneContext } from "../../../scene/sceneContext";
import { useToggleView } from "../../../../store/builder/store";
interface NavMeshDetailsProps {
@@ -12,45 +11,48 @@ interface NavMeshDetailsProps {
groupRef: React.MutableRefObject<THREE.Group | null>;
}
const NAVMESH_CONFIG = {
// cellSize: 0.2,
// cellHeight: 0.7,
// walkableRadius: 0.5,
cellSize: 0.3,
cellHeight: 0.7,
walkableRadius: 0.7,
};
export default function NavMeshDetails({
setNavMesh,
groupRef,
}: NavMeshDetailsProps) {
const { aisleStore, wallStore } = useSceneContext();
const { aisles } = aisleStore();
const { scene } = useThree();
const { walls } = wallStore();
const { toggleView } = useToggleView();
const meshes = useMemo(() => {
return groupRef.current?.children.filter((child): child is THREE.Mesh =>
child instanceof THREE.Mesh
) || [];
}, [groupRef.current?.children]);
useEffect(() => {
if (toggleView) return;
if (toggleView || meshes.length === 0) return;
const initializeNavigation = async () => {
try {
await initRecastNavigation();
if (!groupRef.current || groupRef.current.children.length === 0) {
return;
}
const meshes = groupRef?.current?.children as THREE.Mesh[];
const [positions, indices] = getPositionsAndIndices(meshes);
// const cellSize = 0.2;
// const cellHeight = 0.7;
// const walkableRadius = 0.5;
const { cellSize, cellHeight, walkableRadius } = NAVMESH_CONFIG;
const cellSize = 0.3;
const cellHeight = 0.7;
const walkableRadius = 0.7;
const { success, navMesh } = generateSoloNavMesh(positions, indices, {
cs: cellSize,
ch: cellHeight,
walkableRadius: Math.round(walkableRadius / cellHeight),
});
if (!success || !navMesh) {
return;
}
if (!success || !navMesh) return;
setNavMesh(navMesh);
@@ -62,12 +64,12 @@ export default function NavMeshDetails({
debugDrawer.drawNavMesh(navMesh);
// scene.add(debugDrawer);
} catch (error) {
echo.error("Failed to initialize navigation")
console.error("Failed to initialize navigation:", error);
}
};
initializeNavigation();
}, [scene, groupRef, aisles, walls, toggleView]);
}, [meshes, setNavMesh, toggleView, scene]);
return null;
}

View File

@@ -76,42 +76,18 @@ export default function PolygonGenerator({
turf.lineString(line.map((p: any) => p?.position))
);
const validLineFeatures = lineFeatures.map(ls => {
const coords = ls.geometry.coordinates.map(coord => coord.join(','));
if (coords.length < 2) return null;
const start = coords[0];
const end = coords[coords.length - 1];
const middle = coords.slice(1, -1);
const seen = new Set<string>([start, end]);
const filteredMiddle: string[] = [];
for (const point of middle) {
if (!seen.has(point)) {
seen.add(point);
filteredMiddle.push(point);
}
let validLineFeatures = lineFeatures.filter((line) => {
const coords = line.geometry.coordinates;
return coords.length >= 2;
}).filter((line) => {
if (line.geometry.coordinates[0].toString() !== line.geometry.coordinates[1].toString()) {
return true;
}
})
const newCoords = [start, ...filteredMiddle, end];
if (validLineFeatures.length < 3) { validLineFeatures = [] }
if (newCoords.length >= 4) {
const resultCoords = newCoords.map(str => str.split(',').map(Number));
return {
...ls,
geometry: {
...ls.geometry,
coordinates: resultCoords,
},
};
}
return null;
}).filter(Boolean);
const polygons = turf.polygonize(turf.featureCollection(validLineFeatures as any) as any);
const polygons = turf.polygonize(turf.featureCollection(validLineFeatures));
renderWallGeometry(wallPoints);