vehicle to human completed

This commit is contained in:
2025-07-17 12:54:47 +05:30
parent fe09c3df56
commit 1d6d42b358
13 changed files with 120 additions and 60 deletions

View File

@@ -139,6 +139,11 @@ function AssetsGroup({ plane }: { readonly plane: RefMesh }) {
steeringAngle: 0,
pickUpPoint: null,
unLoadPoint: null,
paths: {
initPickup: [],
pickupDrop: [],
dropPickup: [],
},
triggers: []
}
}

View File

@@ -262,6 +262,11 @@ async function handleModelLoad(
steeringAngle: 0,
pickUpPoint: null,
unLoadPoint: null,
paths: {
initPickup: [],
pickupDrop: [],
dropPickup: [],
},
triggers: [],
},
},

View File

@@ -255,6 +255,8 @@ const CamModelsGroup = () => {
setCams((prev) => dedupeCams([...prev, ...newCams]));
});
}
}).catch(() => {
console.log('Error fetching active users data')
});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

View File

@@ -234,6 +234,11 @@ const CopyPasteControls3D = ({
steeringAngle: 0,
pickUpPoint: null,
unLoadPoint: null,
paths: {
initPickup: [],
pickupDrop: [],
dropPickup: [],
},
triggers: []
}
}

View File

@@ -208,6 +208,11 @@ const DuplicationControls3D = ({
steeringAngle: 0,
pickUpPoint: null,
unLoadPoint: null,
paths: {
initPickup: [],
pickupDrop: [],
dropPickup: [],
},
triggers: []
}
}

View File

@@ -5,8 +5,9 @@ import { useSceneContext } from '../../../scene/sceneContext';
import { useProductContext } from '../../products/productContext';
export function useHumanEventManager() {
const { humanStore, productStore } = useSceneContext();
const { getHumanById, clearLoadCount } = humanStore();
const { humanStore, productStore, assetStore } = useSceneContext();
const { getHumanById, clearLoadCount, setCurrentPhase } = humanStore();
const { getAssetById } = assetStore();
const { getActionByUuid } = productStore();
const { selectedProductStore } = useProductContext();
const { selectedProduct } = selectedProductStore();
@@ -69,9 +70,10 @@ export function useHumanEventManager() {
const { actionType: expectedActionType, actionUuid } = actionQueue[0];
const human = getHumanById(humanId);
const humanAsset = getAssetById(humanId);
const action = getActionByUuid(selectedProduct.productUuid, actionUuid) as HumanAction | undefined;
if (!human || !action || action.actionType !== expectedActionType) return;
if (!humanAsset || !human || !action || action.actionType !== expectedActionType) return;
let conditionMet = false;
@@ -82,23 +84,32 @@ export function useHumanEventManager() {
conditionMet = (
!human.isActive &&
human.state === "idle" &&
humanAsset.animationState?.current === 'idle' &&
human.currentLoad < currentAction.loadCapacity
);
if (human.totalLoadCount >= currentAction.loadCount) {
queue.shift();
actionQueue.shift();
if (queue.length === 0) {
removeHumanFromMonitor(humanId);
}
return;
// if (human.totalLoadCount >= currentAction.loadCount) {
// queue.shift();
// actionQueue.shift();
// if (queue.length === 0) {
// removeHumanFromMonitor(humanId);
// }
// return;
// }
if (conditionMet && actionUuid !== human.currentAction?.actionUuid) {
setCurrentPhase(human.modelUuid, 'init');
}
} else {
conditionMet = (
!human.isActive &&
human.state === "idle" &&
humanAsset.animationState?.current === 'idle' &&
human.currentLoad < action.loadCapacity
);
if (conditionMet && actionUuid !== human.currentAction?.actionUuid) {
setCurrentPhase(human.modelUuid, 'init');
}
}
} else if (expectedActionType === "assembly") {
@@ -106,12 +117,17 @@ export function useHumanEventManager() {
conditionMet = (
!human.isActive &&
human.state === "idle" &&
humanAsset.animationState?.current === 'idle' &&
human.currentLoad < currentAction.loadCapacity
);
if (conditionMet && actionUuid !== human.currentAction?.actionUuid) {
setCurrentPhase(human.modelUuid, 'init');
}
} else {
conditionMet = (
!human.isActive &&
human.state === "idle" &&
humanAsset.animationState?.current === 'idle' &&
human.currentLoad < action.loadCapacity
)
}
@@ -136,7 +152,7 @@ export function useHumanEventManager() {
}
}
});
});
},10);
useEffect(() => {
return () => {

View File

@@ -11,11 +11,10 @@ interface HumanAnimatorProps {
handleCallBack: () => void;
reset: () => void;
startUnloadingProcess: () => void;
currentPhase: string;
human: HumanStatus;
}
function HumanAnimator({ path, handleCallBack, currentPhase, human, reset, startUnloadingProcess }: Readonly<HumanAnimatorProps>) {
function HumanAnimator({ path, handleCallBack, human, reset, startUnloadingProcess }: Readonly<HumanAnimatorProps>) {
const { humanStore, assetStore, productStore } = useSceneContext();
const { getActionByUuid } = productStore();
const { selectedProductStore } = useProductContext();
@@ -38,20 +37,20 @@ function HumanAnimator({ path, handleCallBack, currentPhase, human, reset, start
useEffect(() => {
if (!human.currentAction?.actionUuid) return;
const action = getActionByUuid(selectedProduct.productUuid, human?.currentAction?.actionUuid || '');
if (currentPhase === 'init-pickup' && path.length > 0) {
if (human.currentPhase === 'init-pickup' && path.length > 0) {
setCurrentPath(path);
setObjectRotation((action as HumanAction).pickUpPoint?.rotation ?? null)
} else if (currentPhase === 'init_assembly' && path.length > 0) {
} else if (human.currentPhase === 'init-assembly' && path.length > 0) {
setObjectRotation((action as HumanAction)?.assemblyPoint?.rotation ?? null)
setCurrentPath(path);
} else if (currentPhase === 'pickup-drop' && path.length > 0) {
} else if (human.currentPhase === 'pickup-drop' && path.length > 0) {
setObjectRotation((action as HumanAction)?.dropPoint?.rotation ?? null)
setCurrentPath(path);
} else if (currentPhase === 'drop-pickup' && path.length > 0) {
} else if (human.currentPhase === 'drop-pickup' && path.length > 0) {
setObjectRotation((action as HumanAction)?.pickUpPoint?.rotation ?? null)
setCurrentPath(path);
}
}, [currentPhase, path, objectRotation, selectedProduct, human.currentAction?.actionUuid]);
}, [human.currentPhase, path, objectRotation, selectedProduct, human.currentAction?.actionUuid]);
useEffect(() => {
completedRef.current = false;
@@ -135,13 +134,13 @@ function HumanAnimator({ path, handleCallBack, currentPhase, human, reset, start
const t = (progressRef.current - accumulatedDistance) / segmentDistance;
const position = start.clone().lerp(end, t);
object.position.copy(position);
if (human.currentMaterials.length > 0 && action?.actionType === 'worker' && (currentPhase !== 'init-pickup' && currentPhase !== 'init_assembly')) {
if (human.currentMaterials.length > 0 && action?.actionType === 'worker' && (human.currentPhase !== 'init-pickup' && human.currentPhase !== 'init-assembly' && human.currentPhase !== 'drop-pickup')) {
setCurrentAnimation(human.modelUuid, 'walk_with_box', true, true, true);
} else {
setCurrentAnimation(human.modelUuid, 'walking', true, true, true);
}
} else {
if (human.currentMaterials.length > 0 && action?.actionType === 'worker' && (currentPhase !== 'init-pickup' && currentPhase !== 'init_assembly')) {
if (human.currentMaterials.length > 0 && action?.actionType === 'worker' && (human.currentPhase !== 'init-pickup' && human.currentPhase !== 'init-assembly' && human.currentPhase !== 'drop-pickup')) {
setCurrentAnimation(human.modelUuid, 'idle_with_box', true, true, true);
} else {
setCurrentAnimation(human.modelUuid, 'idle', true, true, true);
@@ -188,7 +187,7 @@ function HumanAnimator({ path, handleCallBack, currentPhase, human, reset, start
movingForward.current = !movingForward.current;
setCurrentPath([]);
handleCallBack();
if (currentPhase === 'pickup-drop') {
if (human.currentPhase === 'pickup-drop') {
requestAnimationFrame(startUnloadingProcess);
}
}

View File

@@ -5,7 +5,7 @@ import { MaterialModel } from '../../../materials/instances/material/materialMod
import { useSceneContext } from '../../../../scene/sceneContext';
import { useProductContext } from '../../../products/productContext';
const MaterialAnimator = ({ human, currentPhase }: { human: HumanStatus, currentPhase: string; }) => {
const MaterialAnimator = ({ human }: { human: HumanStatus; }) => {
const { productStore } = useSceneContext();
const { getActionByUuid } = productStore();
const { selectedProductStore } = useProductContext();
@@ -46,11 +46,11 @@ const MaterialAnimator = ({ human, currentPhase }: { human: HumanStatus, current
meshRef.current.visible = true;
setIsAttached(true);
}
}, [hasLoad, human.modelUuid, scene, currentPhase]);
}, [hasLoad, human.modelUuid, scene, human.currentPhase]);
return (
<>
{hasLoad && (action as HumanAction).actionType === 'worker' && human.currentMaterials.length > 0 && currentPhase !== 'init-pickup' && currentPhase !== 'init_assembly' && (
{hasLoad && (action as HumanAction).actionType === 'worker' && human.currentMaterials.length > 0 && (human.currentPhase !== 'init-pickup' && human.currentPhase !== 'init-assembly' && human.currentPhase !== 'drop-pickup') && (
<MaterialModel
matRef={meshRef}
materialId={human.currentMaterials[0].materialId || ''}

View File

@@ -27,9 +27,8 @@ function HumanInstance({ human }: { human: HumanStatus }) {
const { getActionByUuid, getEventByModelUuid, getTriggerByUuid } = productStore();
const { selectedProductStore } = useProductContext();
const { selectedProduct } = selectedProductStore();
const { setHumanActive, setHumanState, clearCurrentMaterials, setHumanLoad, setHumanScheduled, decrementHumanLoad, removeLastMaterial, incrementIdleTime, incrementActiveTime, resetTime } = humanStore();
const { setHumanActive, setHumanState, clearCurrentMaterials, setHumanLoad, setHumanScheduled, decrementHumanLoad, removeLastMaterial, incrementIdleTime, incrementActiveTime, resetTime, setCurrentPhase } = humanStore();
const [currentPhase, setCurrentPhase] = useState<string>('init');
const [path, setPath] = useState<[number, number, number][]>([]);
const pauseTimeRef = useRef<number | null>(null);
const idleTimeRef = useRef<number>(0);
@@ -84,7 +83,7 @@ function HumanInstance({ human }: { human: HumanStatus }) {
}
function reset() {
setCurrentPhase('init');
setCurrentPhase(human.modelUuid, 'init');
setHumanActive(human.modelUuid, false);
setHumanState(human.modelUuid, 'idle');
setHumanScheduled(human.modelUuid, false);
@@ -124,7 +123,7 @@ function HumanInstance({ human }: { human: HumanStatus }) {
if (!action || !(action as HumanAction).assemblyPoint || (action as HumanAction).actionType === 'worker') return;
if (!human.isActive && human.state === 'idle' && (currentPhase === 'init' || currentPhase === 'picking')) {
if (!human.isActive && human.state === 'idle' && human.currentPhase === 'init') {
const humanMesh = scene.getObjectByProperty('uuid', human.modelUuid);
if (!humanMesh) return;
@@ -139,16 +138,16 @@ function HumanInstance({ human }: { human: HumanStatus }) {
);
setPath(toPickupPath);
setHumanState(human.modelUuid, 'idle');
setCurrentPhase('init_assembly');
setCurrentPhase(human.modelUuid, 'init-assembly');
setHumanActive(human.modelUuid, false);
setCurrentAnimation(human.modelUuid, 'idle', true, true, true);
humanStatus(human.modelUuid, 'Human is waiting for material in assembly');
} else if (!human.isActive && human.state === 'idle' && currentPhase === 'waiting') {
} else if (!human.isActive && human.state === 'idle' && human.currentPhase === 'waiting') {
if (human.currentMaterials.length > 0 && humanAsset && humanAsset.animationState?.current !== 'working_standing') {
setCurrentAnimation(human.modelUuid, 'working_standing', true, true, false);
setHumanState(human.modelUuid, 'running');
setCurrentPhase('assembling');
setCurrentPhase(human.modelUuid, 'assembling');
setHumanActive(human.modelUuid, true);
processStartTimeRef.current = performance.now();
@@ -163,9 +162,9 @@ function HumanInstance({ human }: { human: HumanStatus }) {
}
}
} else if (human.isActive && human.state === 'running' && human.currentMaterials.length > 0 && humanAsset && humanAsset.animationState?.current === 'working_standing' && humanAsset.animationState?.isCompleted) {
if ((action as HumanAction).assemblyPoint && currentPhase === 'assembling') {
if ((action as HumanAction).assemblyPoint && human.currentPhase === 'assembling') {
setHumanState(human.modelUuid, 'idle');
setCurrentPhase('waiting');
setCurrentPhase(human.modelUuid, 'waiting');
setHumanActive(human.modelUuid, false);
setHumanScheduled(human.modelUuid, false);
setCurrentAnimation(human.modelUuid, 'idle', true, true, true);
@@ -183,7 +182,7 @@ function HumanInstance({ human }: { human: HumanStatus }) {
reset()
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [human, currentPhase, path, isPlaying, humanAsset?.animationState?.isCompleted]);
}, [human, human.currentPhase, path, isPlaying, humanAsset?.animationState?.isCompleted]);
const trackAssemblyProcess = useCallback(() => {
const action = getActionByUuid(selectedProduct.productUuid, human?.currentAction?.actionUuid || '');
@@ -235,7 +234,7 @@ function HumanInstance({ human }: { human: HumanStatus }) {
const action = getActionByUuid(selectedProduct.productUuid, human?.currentAction?.actionUuid || '');
if (!action || action.actionType !== 'worker' || !action.pickUpPoint || !action.dropPoint) return;
if (!human.isActive && human.state === 'idle' && (currentPhase === 'init' || currentPhase === 'waiting')) {
if (!human.isActive && human.state === 'idle' && human.currentPhase === 'init') {
const humanMesh = scene.getObjectByProperty('uuid', human.modelUuid);
if (!humanMesh) return;
@@ -249,13 +248,13 @@ function HumanInstance({ human }: { human: HumanStatus }) {
)
);
setPath(toPickupPath);
setCurrentPhase('init-pickup');
setCurrentPhase(human.modelUuid, 'init-pickup');
setHumanState(human.modelUuid, 'running');
setHumanActive(human.modelUuid, true);
setCurrentAnimation(human.modelUuid, 'walking', true, true, true);
humanStatus(human.modelUuid, 'Started from init, heading to pickup');
return;
} else if (!human.isActive && human.state === 'idle' && currentPhase === 'picking') {
} else if (!human.isActive && human.state === 'idle' && human.currentPhase === 'picking') {
if (humanAsset && human.currentLoad === action.loadCapacity && human.currentMaterials.length > 0 && humanAsset.animationState?.current === 'pickup' && humanAsset.animationState?.isCompleted) {
if (action.pickUpPoint && action.dropPoint) {
const toDrop = computePath(
@@ -271,18 +270,18 @@ function HumanInstance({ human }: { human: HumanStatus }) {
)
);
setPath(toDrop);
setCurrentPhase('pickup-drop');
setCurrentPhase(human.modelUuid, 'pickup-drop');
setHumanState(human.modelUuid, 'running');
setCurrentAnimation(human.modelUuid, 'walk_with_box', true, true, true);
humanStatus(human.modelUuid, 'Started from pickup point, heading to drop point');
}
} else if (human.currentLoad === action.loadCapacity && human.currentMaterials.length > 0 && humanAsset?.animationState?.current !== 'pickup') {
} else if (human.currentMaterials.length > 0 && humanAsset?.animationState?.current !== 'pickup') {
if (human.currentMaterials[0]?.materialId) {
setIsVisible(human.currentMaterials[0]?.materialId, false);
}
setCurrentAnimation(human.modelUuid, 'pickup', true, false, false);
}
} else if (!human.isActive && human.state === 'idle' && currentPhase === 'dropping' && human.currentLoad === 0) {
} else if (!human.isActive && human.state === 'idle' && human.currentPhase === 'dropping' && human.currentLoad === 0) {
if (action.pickUpPoint && action.dropPoint) {
const dropToPickup = computePath(
new THREE.Vector3(
@@ -297,7 +296,7 @@ function HumanInstance({ human }: { human: HumanStatus }) {
)
);
setPath(dropToPickup);
setCurrentPhase('drop-pickup');
setCurrentPhase(human.modelUuid, 'drop-pickup');
setHumanState(human.modelUuid, 'running');
setHumanActive(human.modelUuid, true);
setCurrentAnimation(human.modelUuid, 'walking', true, true, true);
@@ -309,32 +308,33 @@ function HumanInstance({ human }: { human: HumanStatus }) {
reset()
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [human, currentPhase, path, isPlaying, humanAsset?.animationState?.isCompleted]);
}, [human, human.currentPhase, path, isPlaying, humanAsset?.animationState?.isCompleted]);
function handleCallBack() {
if (currentPhase === 'init-pickup') {
setCurrentPhase('picking');
if (human.currentPhase === 'init-pickup') {
setCurrentPhase(human.modelUuid, 'picking');
setHumanState(human.modelUuid, 'idle');
setHumanActive(human.modelUuid, false);
setCurrentAnimation(human.modelUuid, 'idle', true, true, true);
humanStatus(human.modelUuid, 'Reached pickup point, waiting for material');
setPath([]);
} if (currentPhase === 'init_assembly') {
setCurrentPhase('waiting');
} if (human.currentPhase === 'init-assembly') {
setCurrentPhase(human.modelUuid, 'waiting');
setHumanState(human.modelUuid, 'idle');
setHumanActive(human.modelUuid, false);
setCurrentAnimation(human.modelUuid, 'idle', true, true, true);
humanStatus(human.modelUuid, 'Reached assembly point, waiting for material');
setPath([]);
} else if (currentPhase === 'pickup-drop') {
setCurrentPhase('dropping');
} else if (human.currentPhase === 'pickup-drop') {
setCurrentPhase(human.modelUuid, 'dropping');
setHumanState(human.modelUuid, 'idle');
setHumanActive(human.modelUuid, false);
setCurrentAnimation(human.modelUuid, 'drop', true, false, false);
humanStatus(human.modelUuid, 'Reached drop point');
setPath([]);
} else if (currentPhase === 'drop-pickup') {
setCurrentPhase('picking');
} else if (human.currentPhase === 'drop-pickup') {
console.log('human: ', human);
setCurrentPhase(human.modelUuid, 'picking');
setHumanState(human.modelUuid, 'idle');
setHumanActive(human.modelUuid, false);
setHumanScheduled(human.modelUuid, false);
@@ -817,13 +817,12 @@ function HumanInstance({ human }: { human: HumanStatus }) {
<HumanAnimator
path={path}
handleCallBack={handleCallBack}
currentPhase={currentPhase}
human={human}
reset={reset}
startUnloadingProcess={startUnloadingProcess}
/>
<MaterialAnimator currentPhase={currentPhase} human={human} />
<MaterialAnimator human={human} />
</>
)
}

View File

@@ -381,7 +381,9 @@ export function useTriggerHandler() {
setIsPaused(materialId, true);
addConveyorToMonitor(conveyor.modelUuid, () => {
handleAction(action, materialId);
addHumanToMonitor(human.modelUuid, () => {
handleAction(action, materialId);
}, action.actionUuid)
}, [materialId])
}
}, action.actionUuid)

View File

@@ -19,7 +19,7 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
const { materialStore, armBotStore, conveyorStore, vehicleStore, storageUnitStore, humanStore, productStore, assetStore } = useSceneContext();
const { removeMaterial, setEndTime, setIsVisible } = materialStore();
const { getStorageUnitById } = storageUnitStore();
const { getHumanById, addCurrentAction } = humanStore();
const { getHumanById, addCurrentAction, addCurrentMaterial, incrementHumanLoad , incrementLoadCount } = humanStore();
const { getArmBotById } = armBotStore();
const { getConveyorById } = conveyorStore();
const { triggerPointActions } = useTriggerHandler();
@@ -295,27 +295,31 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
const humanAction = human?.point.actions.find((action) => action.actionUuid === humanActionId);
if (!human || human.currentAction?.actionUuid !== humanAction?.actionUuid) return;
if (humanAsset && human.currentMaterials.length > 0 && humanAsset.animationState?.current === 'pickup' && humanAsset.animationState?.isCompleted) {
if (!human.isActive && human.currentLoad < (humanAction?.loadCapacity || 0) && humanAsset?.animationState?.current === 'idle' && humanAction?.actionType === 'worker') {
setCurrentAnimation(human.modelUuid, 'pickup', true, false, false);
decrementVehicleLoad(vehicle.modelUuid, 1);
currentVehicleLoad -= 1;
const material = removeLastMaterial(vehicle.modelUuid);
if (material) {
setIsVisible(material.materialId, false);
addCurrentMaterial(humanId, material.materialType, material.materialId);
incrementHumanLoad(humanId, 1);
incrementLoadCount(humanId, 1);
}
} else if (!human.isActive && human.currentLoad < (humanAction?.loadCapacity || 0) && humanAsset?.animationState?.current === 'waiting') {
setCurrentAnimation(human.modelUuid, 'pickup', true, false, false);
return;
}
setTimeout(() => {
requestAnimationFrame(unloadLoop);
}, 150)
}, 500)
};
const human = getHumanById(humanId);
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();
setTimeout(() => {
unloadLoop();
}, 500)
}
}

View File

@@ -12,6 +12,8 @@ interface HumansStore {
) => void;
clearHumans: () => void;
setCurrentPhase: (modelUuid: string, phase: string) => void;
addCurrentAction: (modelUuid: string, actionUuid: string) => void;
removeCurrentAction: (modelUuid: string) => void;
@@ -58,6 +60,7 @@ export const createHumanStore = () => {
state.humans.push({
...event,
productUuid,
currentPhase: 'init',
isActive: false,
isScheduled: false,
idleTime: 0,
@@ -92,6 +95,15 @@ export const createHumanStore = () => {
});
},
setCurrentPhase: (modelUuid, phase) => {
set((state) => {
const human = state.humans.find(h => h.modelUuid === modelUuid);
if (human) {
human.currentPhase = phase;
}
});
},
addCurrentAction: (modelUuid, actionUuid) => {
set((state) => {
const human = state.humans.find(h => h.modelUuid === modelUuid);

View File

@@ -40,6 +40,11 @@ interface VehicleAction {
steeringAngle: number;
pickUpPoint: { position: { x: number; y: number, z: number }, rotation: { x: number; y: number, z: number } } | null;
unLoadPoint: { position: { x: number; y: number, z: number }, rotation: { x: number; y: number, z: number } } | null;
paths: {
initPickup: [number, number, number][],
pickupDrop: [number, number, number][],
dropPickup: [number, number, number][],
}
triggers: TriggerSchema[];
}
@@ -224,6 +229,7 @@ interface StorageUnitStatus extends StorageEventSchema {
interface HumanStatus extends HumanEventSchema {
productUuid: string;
currentPhase: string;
isActive: boolean;
isScheduled: boolean;
idleTime: number;