Merge branch 'dev-simulation/human' into main-dev
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import * as THREE from "three"
|
||||
import * as THREE from "three"
|
||||
import { useEffect } from 'react'
|
||||
import { getFloorAssets } from '../../../services/factoryBuilder/asset/floorAsset/getFloorItemsApi';
|
||||
import { useLoadingProgress, useRenameModeStore, useSelectedFloorItem, useSelectedItem, useSocketStore } from '../../../store/builder/store';
|
||||
@@ -226,7 +226,8 @@ function AssetsGroup({ plane }: { readonly plane: RefMesh }) {
|
||||
modelUuid: item.modelUuid,
|
||||
modelName: item.modelName,
|
||||
position: item.position,
|
||||
rotation: [item.rotation.x, item.rotation.y, item.rotation.z], state: "idle",
|
||||
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
|
||||
state: "idle",
|
||||
type: "storageUnit",
|
||||
point: {
|
||||
uuid: item.eventData.point?.uuid || THREE.MathUtils.generateUUID(),
|
||||
@@ -242,6 +243,30 @@ function AssetsGroup({ plane }: { readonly plane: RefMesh }) {
|
||||
}
|
||||
};
|
||||
addEvent(storageEvent);
|
||||
} else if (item.eventData.type === 'Human') {
|
||||
const humanEvent: HumanEventSchema = {
|
||||
modelUuid: item.modelUuid,
|
||||
modelName: item.modelName,
|
||||
position: item.position,
|
||||
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
|
||||
state: "idle",
|
||||
type: "human",
|
||||
speed: 1,
|
||||
point: {
|
||||
uuid: item.eventData.point?.uuid || THREE.MathUtils.generateUUID(),
|
||||
position: [item.eventData.point?.position[0] || 0, item.eventData.point?.position[1] || 0, item.eventData.point?.position[2] || 0],
|
||||
rotation: [item.eventData.point?.rotation[0] || 0, item.eventData.point?.rotation[1] || 0, item.eventData.point?.rotation[2] || 0],
|
||||
action: {
|
||||
actionUuid: THREE.MathUtils.generateUUID(),
|
||||
actionName: "Action 1",
|
||||
actionType: "worker",
|
||||
loadCapacity: 1,
|
||||
triggers: []
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
addEvent(humanEvent);
|
||||
}
|
||||
} else {
|
||||
assets.push({
|
||||
|
||||
@@ -170,7 +170,7 @@ async function handleModelLoad(
|
||||
|
||||
if (!data || !data.points) return;
|
||||
|
||||
const eventData: any = { type: selectedItem.type, };
|
||||
const eventData: any = { type: selectedItem.type };
|
||||
|
||||
if (selectedItem.type === "Conveyor") {
|
||||
const ConveyorEvent: ConveyorEventSchema = {
|
||||
@@ -368,24 +368,19 @@ async function handleModelLoad(
|
||||
rotation: newFloorItem.rotation,
|
||||
state: "idle",
|
||||
type: "human",
|
||||
speed: 1,
|
||||
point: {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
position: [data.points[0].x, data.points[0].y, data.points[0].z],
|
||||
rotation: [0, 0, 0],
|
||||
actions: [
|
||||
{
|
||||
actionUuid: THREE.MathUtils.generateUUID(),
|
||||
actionName: "Action 1",
|
||||
actionType: "animation",
|
||||
animation: null,
|
||||
loadCapacity: 1,
|
||||
travelPoints: {
|
||||
startPoint: null,
|
||||
endPoint: null,
|
||||
},
|
||||
triggers: []
|
||||
}
|
||||
]
|
||||
action: {
|
||||
actionUuid: THREE.MathUtils.generateUUID(),
|
||||
actionName: "Action 1",
|
||||
actionType: "worker",
|
||||
loadCapacity: 1,
|
||||
triggers: []
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
addEvent(humanEvent);
|
||||
|
||||
@@ -6,7 +6,7 @@ import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
|
||||
import { ThreeEvent, useFrame, useThree } from '@react-three/fiber';
|
||||
import { useActiveTool, useDeletableFloorItem, useLimitDistance, useRenderDistance, useSelectedFloorItem, useSocketStore, useToggleView, useToolMode } from '../../../../../store/builder/store';
|
||||
import { AssetBoundingBox } from '../../functions/assetBoundingBox';
|
||||
import { CameraControls, Html } from '@react-three/drei';
|
||||
import { CameraControls } from '@react-three/drei';
|
||||
import useModuleStore, { useSubModuleStore } from '../../../../../store/useModuleStore';
|
||||
import { useLeftData, useTopData } from '../../../../../store/visualization/useZone3DWidgetStore';
|
||||
import { useSelectedAsset } from '../../../../../store/simulation/useSimulationStore';
|
||||
@@ -15,6 +15,8 @@ import { useParams } from 'react-router-dom';
|
||||
import { getUserData } from '../../../../../functions/getUserData';
|
||||
import { useSceneContext } from '../../../../scene/sceneContext';
|
||||
import { useVersionContext } from '../../../version/versionContext';
|
||||
import { SkeletonUtils } from 'three-stdlib';
|
||||
import { useAnimationPlaySpeed } from '../../../../../store/usePlayButtonStore';
|
||||
|
||||
function Model({ asset }: { readonly asset: Asset }) {
|
||||
const { camera, controls, gl } = useThree();
|
||||
@@ -22,8 +24,9 @@ function Model({ asset }: { readonly asset: Asset }) {
|
||||
const { toggleView } = useToggleView();
|
||||
const { subModule } = useSubModuleStore();
|
||||
const { activeModule } = useModuleStore();
|
||||
const { speed } = useAnimationPlaySpeed();
|
||||
const { assetStore, eventStore, productStore } = useSceneContext();
|
||||
const { assets, removeAsset, setAnimations } = assetStore();
|
||||
const { removeAsset, setAnimations, resetAnimation, setAnimationComplete, setCurrentAnimation: setAnmationAnimation } = assetStore();
|
||||
const { setTop } = useTopData();
|
||||
const { setLeft } = useLeftData();
|
||||
const { getIsEventInProduct } = productStore();
|
||||
@@ -33,7 +36,7 @@ function Model({ asset }: { readonly asset: Asset }) {
|
||||
const { setSelectedAsset, clearSelectedAsset } = useSelectedAsset();
|
||||
const { socket } = useSocketStore();
|
||||
const { deletableFloorItem, setDeletableFloorItem } = useDeletableFloorItem();
|
||||
const { setSelectedFloorItem } = useSelectedFloorItem();
|
||||
const { selectedFloorItem, setSelectedFloorItem } = useSelectedFloorItem();
|
||||
const { limitDistance } = useLimitDistance();
|
||||
const { renderDistance } = useRenderDistance();
|
||||
const [isRendered, setIsRendered] = useState(false);
|
||||
@@ -46,13 +49,18 @@ function Model({ asset }: { readonly asset: Asset }) {
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
const { projectId } = useParams();
|
||||
const { userId, organization } = getUserData();
|
||||
const [animationNames, setAnimationNames] = useState<string[]>([]);
|
||||
const mixerRef = useRef<THREE.AnimationMixer>();
|
||||
const actions = useRef<{ [name: string]: THREE.AnimationAction }>({});
|
||||
const [previousAnimation, setPreviousAnimation] = useState<string | null>(null);
|
||||
const blendFactor = useRef(0);
|
||||
const blendDuration = 0.5;
|
||||
|
||||
useEffect(() => {
|
||||
setDeletableFloorItem(null);
|
||||
}, [activeModule, toolMode])
|
||||
if (selectedFloorItem === null) {
|
||||
resetAnimation(asset.modelUuid);
|
||||
}
|
||||
}, [activeModule, toolMode, selectedFloorItem])
|
||||
|
||||
useEffect(() => {
|
||||
const loader = new GLTFLoader();
|
||||
@@ -62,40 +70,21 @@ function Model({ asset }: { readonly asset: Asset }) {
|
||||
loader.setDRACOLoader(dracoLoader);
|
||||
const loadModel = async () => {
|
||||
try {
|
||||
// Check Cache
|
||||
// const assetId = asset.assetId;
|
||||
// const cachedModel = THREE.Cache.get(assetId);
|
||||
// if (cachedModel) {
|
||||
// setGltfScene(cachedModel.scene.clone());
|
||||
// calculateBoundingBox(cachedModel.scene);
|
||||
// return;
|
||||
// }
|
||||
|
||||
// Check Cache
|
||||
// const assetId = asset.assetId;
|
||||
// console.log('assetId: ', assetId);
|
||||
// const cachedModel = THREE.Cache.get(assetId);
|
||||
// console.log('cachedModel: ', cachedModel);
|
||||
// if (cachedModel) {
|
||||
// setGltfScene(cachedModel.scene.clone());
|
||||
// calculateBoundingBox(cachedModel.scene);
|
||||
// return;
|
||||
// }
|
||||
|
||||
const assetId = asset.assetId;
|
||||
const cachedModel = THREE.Cache.get(assetId);
|
||||
if (cachedModel) {
|
||||
const clonedScene = cachedModel.scene.clone();
|
||||
clonedScene.animations = cachedModel.animations || [];
|
||||
setGltfScene(clonedScene);
|
||||
calculateBoundingBox(clonedScene);
|
||||
if (cachedModel.animations && clonedScene.animations.length > 0) {
|
||||
const animationName = clonedScene.animations.map((clip: any) => clip.name);
|
||||
setAnimationNames(animationName)
|
||||
const clone: any = SkeletonUtils.clone(cachedModel.scene);
|
||||
clone.animations = cachedModel.animations || [];
|
||||
setGltfScene(clone);
|
||||
calculateBoundingBox(clone);
|
||||
if (cachedModel.animations && clone.animations.length > 0) {
|
||||
const animationName = clone.animations.map((clip: any) => clip.name);
|
||||
setAnimations(asset.modelUuid, animationName)
|
||||
mixerRef.current = new THREE.AnimationMixer(clonedScene);
|
||||
mixerRef.current = new THREE.AnimationMixer(clone);
|
||||
|
||||
clonedScene.animations.forEach((animation: any) => {
|
||||
clone.animations.forEach((animation: any) => {
|
||||
const action = mixerRef.current!.clipAction(animation);
|
||||
actions.current[animation.name] = action;
|
||||
});
|
||||
@@ -293,29 +282,50 @@ function Model({ asset }: { readonly asset: Asset }) {
|
||||
clearSelectedAsset()
|
||||
}
|
||||
}
|
||||
|
||||
const handleAnimationComplete = useCallback(() => {
|
||||
if (asset.animationState) {
|
||||
setAnimationComplete(asset.modelUuid, true);
|
||||
}
|
||||
}, [asset.animationState]);
|
||||
|
||||
useFrame((_, delta) => {
|
||||
if (mixerRef.current) {
|
||||
mixerRef.current.update(delta);
|
||||
mixerRef.current.update(delta * speed);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if (!asset.animationState || !mixerRef.current) return;
|
||||
|
||||
if (asset.animationState && asset.animationState.playing) {
|
||||
if (!mixerRef.current) return;
|
||||
const { current, loopAnimation, isPlaying } = asset.animationState;
|
||||
const currentAction = actions.current[current];
|
||||
const previousAction = previousAnimation ? actions.current[previousAnimation] : null;
|
||||
|
||||
Object.values(actions.current).forEach((action) => action.stop());
|
||||
if (isPlaying && currentAction) {
|
||||
blendFactor.current = 0;
|
||||
|
||||
const action = actions.current[asset.animationState.current];
|
||||
if (action && asset.animationState?.playing) {
|
||||
action.reset().setLoop(THREE.LoopOnce, 1).play();
|
||||
currentAction.reset();
|
||||
currentAction.setLoop(loopAnimation ? THREE.LoopRepeat : THREE.LoopOnce, loopAnimation ? Infinity : 1);
|
||||
currentAction.clampWhenFinished = true;
|
||||
|
||||
if (previousAction && previousAction !== currentAction) {
|
||||
previousAction.crossFadeTo(currentAction, blendDuration, false);
|
||||
}
|
||||
|
||||
currentAction.play();
|
||||
mixerRef.current.addEventListener('finished', handleAnimationComplete);
|
||||
setPreviousAnimation(current);
|
||||
} else {
|
||||
Object.values(actions.current).forEach((action) => action.stop());
|
||||
}
|
||||
|
||||
}, [asset.animationState])
|
||||
return () => {
|
||||
if (mixerRef.current) {
|
||||
mixerRef.current.removeEventListener('finished', handleAnimationComplete);
|
||||
}
|
||||
};
|
||||
}, [asset.animationState?.current, asset.animationState?.isPlaying]);
|
||||
|
||||
return (
|
||||
<group
|
||||
|
||||
@@ -332,6 +332,34 @@ const CopyPasteControls = ({
|
||||
position: storageEvent.point.position,
|
||||
rotation: storageEvent.point.rotation
|
||||
};
|
||||
} else if (obj.userData.eventData.type === "Human") {
|
||||
const humanEvent: HumanEventSchema = {
|
||||
modelUuid: newFloorItem.modelUuid,
|
||||
modelName: newFloorItem.modelName,
|
||||
position: newFloorItem.position,
|
||||
rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z],
|
||||
state: "idle",
|
||||
type: "human",
|
||||
speed: 1,
|
||||
point: {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
position: [updatedEventData.point.position[0], updatedEventData.point.position[1], updatedEventData.point.position[2]],
|
||||
rotation: [updatedEventData.point.rotation[0], updatedEventData.point.rotation[1], updatedEventData.point.rotation[2]],
|
||||
action: {
|
||||
actionUuid: THREE.MathUtils.generateUUID(),
|
||||
actionName: "Action 1",
|
||||
actionType: "worker",
|
||||
loadCapacity: 1,
|
||||
triggers: []
|
||||
}
|
||||
}
|
||||
}
|
||||
addEvent(humanEvent);
|
||||
eventData.point = {
|
||||
uuid: humanEvent.point.uuid,
|
||||
position: humanEvent.point.position,
|
||||
rotation: humanEvent.point.rotation
|
||||
};
|
||||
}
|
||||
|
||||
newFloorItem.eventData = eventData;
|
||||
|
||||
@@ -306,6 +306,34 @@ const DuplicationControls = ({
|
||||
position: storageEvent.point.position,
|
||||
rotation: storageEvent.point.rotation
|
||||
};
|
||||
} else if (obj.userData.eventData.type === "Human") {
|
||||
const humanEvent: HumanEventSchema = {
|
||||
modelUuid: newFloorItem.modelUuid,
|
||||
modelName: newFloorItem.modelName,
|
||||
position: newFloorItem.position,
|
||||
rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z],
|
||||
state: "idle",
|
||||
type: "human",
|
||||
speed: 1,
|
||||
point: {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
position: [updatedEventData.point.position[0], updatedEventData.point.position[1], updatedEventData.point.position[2]],
|
||||
rotation: [updatedEventData.point.rotation[0], updatedEventData.point.rotation[1], updatedEventData.point.rotation[2]],
|
||||
action: {
|
||||
actionUuid: THREE.MathUtils.generateUUID(),
|
||||
actionName: "Action 1",
|
||||
actionType: "worker",
|
||||
loadCapacity: 1,
|
||||
triggers: []
|
||||
}
|
||||
}
|
||||
}
|
||||
addEvent(humanEvent);
|
||||
eventData.point = {
|
||||
uuid: humanEvent.point.uuid,
|
||||
position: humanEvent.point.position,
|
||||
rotation: humanEvent.point.rotation
|
||||
};
|
||||
}
|
||||
|
||||
newFloorItem.eventData = eventData;
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import { useCallback } from "react";
|
||||
import { useSceneContext } from "../../../../scene/sceneContext";
|
||||
import { useProductContext } from "../../../products/productContext";
|
||||
|
||||
export function useWorkerHandler() {
|
||||
const { materialStore, humanStore, productStore } = useSceneContext();
|
||||
const { getMaterialById } = materialStore();
|
||||
const { getModelUuidByActionUuid } = productStore();
|
||||
const { selectedProductStore } = useProductContext();
|
||||
const { selectedProduct } = selectedProductStore();
|
||||
const { incrementHumanLoad, addCurrentMaterial } = humanStore();
|
||||
|
||||
const workerLogStatus = (materialUuid: string, status: string) => {
|
||||
echo.info(`${materialUuid}, ${status}`);
|
||||
}
|
||||
|
||||
const handleWorker = useCallback((action: HumanAction, materialId?: string) => {
|
||||
if (!action || action.actionType !== 'worker' || !materialId) return;
|
||||
|
||||
const material = getMaterialById(materialId);
|
||||
if (!material) return;
|
||||
|
||||
const modelUuid = getModelUuidByActionUuid(selectedProduct.productUuid, action.actionUuid);
|
||||
if (!modelUuid) return;
|
||||
|
||||
incrementHumanLoad(modelUuid, 1);
|
||||
addCurrentMaterial(modelUuid, material.materialType, material.materialId);
|
||||
|
||||
workerLogStatus(material.materialName, `performing worker action`);
|
||||
|
||||
}, [getMaterialById]);
|
||||
|
||||
return {
|
||||
handleWorker,
|
||||
};
|
||||
}
|
||||
36
app/src/modules/simulation/actions/human/useHumanActions.ts
Normal file
36
app/src/modules/simulation/actions/human/useHumanActions.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { useEffect, useCallback } from 'react';
|
||||
import { useWorkerHandler } from './actionHandler/useWorkerHandler';
|
||||
|
||||
export function useHumanActions() {
|
||||
const { handleWorker } = useWorkerHandler();
|
||||
|
||||
const handleWorkerAction = useCallback((action: HumanAction, materialId: string) => {
|
||||
handleWorker(action, materialId);
|
||||
}, [handleWorker]);
|
||||
|
||||
const handleHumanAction = useCallback((action: HumanAction, materialId: string) => {
|
||||
if (!action) return;
|
||||
|
||||
switch (action.actionType) {
|
||||
case 'worker':
|
||||
handleWorkerAction(action, materialId);
|
||||
break;
|
||||
default:
|
||||
console.warn(`Unknown Human action type: ${action.actionType}`);
|
||||
}
|
||||
}, [handleWorkerAction]);
|
||||
|
||||
const cleanup = useCallback(() => {
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
cleanup();
|
||||
};
|
||||
}, [cleanup]);
|
||||
|
||||
return {
|
||||
handleHumanAction,
|
||||
cleanup
|
||||
};
|
||||
}
|
||||
@@ -27,7 +27,7 @@ export function useStorageActions() {
|
||||
default:
|
||||
console.warn(`Unknown storage action type: ${action.actionType}`);
|
||||
}
|
||||
}, [handleStoreAction]);
|
||||
}, [handleStoreAction, handleRetrieveAction]);
|
||||
|
||||
const cleanup = useCallback(() => {
|
||||
}, []);
|
||||
|
||||
@@ -7,6 +7,7 @@ import { useMachineActions } from "./machine/useMachineActions";
|
||||
import { useRoboticArmActions } from "./roboticArm/useRoboticArmActions";
|
||||
import { useStorageActions } from "./storageUnit/useStorageUnitActions";
|
||||
import { useVehicleActions } from "./vehicle/useVehicleActions";
|
||||
import { useHumanActions } from "./human/useHumanActions";
|
||||
import { useCallback, useEffect } from "react";
|
||||
|
||||
export function useActionHandler() {
|
||||
@@ -17,6 +18,7 @@ export function useActionHandler() {
|
||||
const { handleRoboticArmAction, cleanup: cleanupRoboticArm } = useRoboticArmActions();
|
||||
const { handleMachineAction, cleanup: cleanupMachine } = useMachineActions();
|
||||
const { handleStorageAction, cleanup: cleanupStorage } = useStorageActions();
|
||||
const { handleHumanAction, cleanup: cleanupHuman } = useHumanActions();
|
||||
|
||||
const handleAction = useCallback((action: Action, materialId?: string) => {
|
||||
if (!action) return;
|
||||
@@ -37,6 +39,9 @@ export function useActionHandler() {
|
||||
case 'store': case 'retrieve':
|
||||
handleStorageAction(action as StorageAction, materialId as string);
|
||||
break;
|
||||
case 'worker':
|
||||
handleHumanAction(action as HumanAction, materialId as string);
|
||||
break;
|
||||
default:
|
||||
console.warn(`Unknown action type: ${(action as Action).actionType}`);
|
||||
}
|
||||
@@ -44,7 +49,7 @@ export function useActionHandler() {
|
||||
echo.error("Failed to handle action");
|
||||
console.error("Error handling action:", error);
|
||||
}
|
||||
}, [handleConveyorAction, handleVehicleAction, handleRoboticArmAction, handleMachineAction, handleStorageAction,]);
|
||||
}, [handleConveyorAction, handleVehicleAction, handleRoboticArmAction, handleMachineAction, handleStorageAction, handleHumanAction]);
|
||||
|
||||
const cleanup = useCallback(() => {
|
||||
cleanupConveyor();
|
||||
@@ -52,7 +57,8 @@ export function useActionHandler() {
|
||||
cleanupRoboticArm();
|
||||
cleanupMachine();
|
||||
cleanupStorage();
|
||||
}, [cleanupConveyor, cleanupVehicle, cleanupRoboticArm, cleanupMachine, cleanupStorage,]);
|
||||
cleanupHuman();
|
||||
}, [cleanupConveyor, cleanupVehicle, cleanupRoboticArm, cleanupMachine, cleanupStorage, cleanupHuman]);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
|
||||
@@ -155,8 +155,8 @@ function TriggerConnector() {
|
||||
// Handle Human point
|
||||
else if (event.type === "human" && 'point' in event) {
|
||||
const point = event.point;
|
||||
point.actions?.forEach(action => {
|
||||
action.triggers?.forEach(trigger => {
|
||||
if (point.action?.triggers) {
|
||||
point.action.triggers.forEach(trigger => {
|
||||
if (trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint) {
|
||||
newConnections.push({
|
||||
id: `${point.uuid}-${trigger.triggeredAsset.triggeredPoint.pointUuid}-${trigger.triggerUuid}`,
|
||||
@@ -166,7 +166,7 @@ function TriggerConnector() {
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { useFrame } from '@react-three/fiber';
|
||||
import { usePauseButtonStore, usePlayButtonStore, useResetButtonStore } from '../../../../store/usePlayButtonStore';
|
||||
import { useSceneContext } from '../../../scene/sceneContext';
|
||||
|
||||
type HumanCallback = {
|
||||
humanId: string;
|
||||
callback: () => void;
|
||||
};
|
||||
|
||||
export function useHumanEventManager() {
|
||||
const { humanStore } = useSceneContext();
|
||||
const { getHumanById } = humanStore();
|
||||
const callbacksRef = useRef<HumanCallback[]>([]);
|
||||
const isMonitoringRef = useRef(false);
|
||||
const { isPlaying } = usePlayButtonStore();
|
||||
const { isPaused } = usePauseButtonStore();
|
||||
const { isReset } = useResetButtonStore();
|
||||
|
||||
useEffect(() => {
|
||||
if (isReset) {
|
||||
callbacksRef.current = [];
|
||||
}
|
||||
}, [isReset])
|
||||
|
||||
// Add a new human to monitor
|
||||
const addHumanToMonitor = (humanId: string, callback: () => void) => {
|
||||
// Avoid duplicates
|
||||
if (!callbacksRef.current.some((entry) => entry.humanId === humanId)) {
|
||||
callbacksRef.current.push({ humanId, callback });
|
||||
}
|
||||
|
||||
// Start monitoring if not already running
|
||||
if (!isMonitoringRef.current) {
|
||||
isMonitoringRef.current = true;
|
||||
}
|
||||
};
|
||||
|
||||
// Remove a human from monitoring
|
||||
const removeHumanFromMonitor = (humanId: string) => {
|
||||
callbacksRef.current = callbacksRef.current.filter(
|
||||
(entry) => entry.humanId !== humanId
|
||||
);
|
||||
|
||||
// Stop monitoring if no more humans to track
|
||||
if (callbacksRef.current.length === 0) {
|
||||
isMonitoringRef.current = false;
|
||||
}
|
||||
};
|
||||
|
||||
// Check human states every frame
|
||||
useFrame(() => {
|
||||
if (!isMonitoringRef.current || callbacksRef.current.length === 0 || !isPlaying || isPaused) return;
|
||||
|
||||
callbacksRef.current.forEach(({ humanId, callback }) => {
|
||||
const human = getHumanById(humanId);
|
||||
if (human && human.isActive === false && human.state === 'idle' && human.isPicking && human.currentLoad < human.point.action.loadCapacity) {
|
||||
callback();
|
||||
removeHumanFromMonitor(humanId); // Remove after triggering
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Cleanup on unmount
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
callbacksRef.current = [];
|
||||
isMonitoringRef.current = false;
|
||||
};
|
||||
}, []);
|
||||
|
||||
return {
|
||||
addHumanToMonitor,
|
||||
removeHumanFromMonitor,
|
||||
};
|
||||
}
|
||||
@@ -1,11 +1,38 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useSelectedAnimation, useSelectedEventSphere } from '../../../store/simulation/useSimulationStore';
|
||||
import { usePlayButtonStore } from '../../../store/usePlayButtonStore';
|
||||
import { useSceneContext } from '../../scene/sceneContext';
|
||||
import HumanInstances from './instances/humanInstances'
|
||||
import HumanUi from './instances/instance/humanUi';
|
||||
|
||||
function Human() {
|
||||
const { humanStore } = useSceneContext();
|
||||
const { getHumanById } = humanStore();
|
||||
const { selectedAnimation } = useSelectedAnimation();
|
||||
const { selectedEventSphere } = useSelectedEventSphere();
|
||||
const { isPlaying } = usePlayButtonStore();
|
||||
const [isVehicleSelected, setIsHumanSelected] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedEventSphere) {
|
||||
const selectedHuman = getHumanById(selectedEventSphere.userData.modelUuid);
|
||||
if (selectedHuman) {
|
||||
setIsHumanSelected(true);
|
||||
} else {
|
||||
setIsHumanSelected(false);
|
||||
}
|
||||
}
|
||||
}, [getHumanById, selectedEventSphere, selectedAnimation])
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
<HumanInstances />
|
||||
|
||||
{isVehicleSelected && selectedEventSphere && !isPlaying &&
|
||||
<HumanUi />
|
||||
}
|
||||
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,191 @@
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { useFrame, useThree } from '@react-three/fiber';
|
||||
import * as THREE from 'three';
|
||||
import { Line } from '@react-three/drei';
|
||||
import { useAnimationPlaySpeed, usePauseButtonStore, usePlayButtonStore, useResetButtonStore } from '../../../../../store/usePlayButtonStore';
|
||||
import { useSceneContext } from '../../../../scene/sceneContext';
|
||||
|
||||
interface HumanAnimatorProps {
|
||||
path: [number, number, number][];
|
||||
handleCallBack: () => void;
|
||||
reset: () => void;
|
||||
startUnloadingProcess: () => void;
|
||||
currentPhase: string;
|
||||
human: HumanStatus;
|
||||
}
|
||||
|
||||
function HumanAnimator({ path, handleCallBack, currentPhase, human, reset, startUnloadingProcess }: Readonly<HumanAnimatorProps>) {
|
||||
const { humanStore, assetStore } = useSceneContext();
|
||||
const { getHumanById } = humanStore();
|
||||
const { setCurrentAnimation } = assetStore();
|
||||
const { isPaused } = usePauseButtonStore();
|
||||
const { isPlaying } = usePlayButtonStore();
|
||||
const { speed } = useAnimationPlaySpeed();
|
||||
const { isReset, setReset } = useResetButtonStore();
|
||||
const progressRef = useRef<number>(0);
|
||||
const movingForward = useRef<boolean>(true);
|
||||
const completedRef = useRef<boolean>(false);
|
||||
const [objectRotation, setObjectRotation] = useState<[number, number, number] | null>(human.point?.action?.pickUpPoint?.rotation || [0, 0, 0])
|
||||
const [restRotation, setRestingRotation] = useState<boolean>(true);
|
||||
const [currentPath, setCurrentPath] = useState<[number, number, number][]>([]);
|
||||
const { scene } = useThree();
|
||||
|
||||
useEffect(() => {
|
||||
if (currentPhase === 'init-pickup' && path.length > 0) {
|
||||
setCurrentPath(path);
|
||||
setObjectRotation(human.point.action.pickUpPoint?.rotation ?? null)
|
||||
} else if (currentPhase === 'pickup-drop' && path.length > 0) {
|
||||
setObjectRotation(human.point.action?.dropPoint?.rotation ?? null)
|
||||
setCurrentPath(path);
|
||||
} else if (currentPhase === 'drop-pickup' && path.length > 0) {
|
||||
setObjectRotation(human.point.action?.pickUpPoint?.rotation ?? null)
|
||||
setCurrentPath(path);
|
||||
}
|
||||
}, [currentPhase, path, objectRotation]);
|
||||
|
||||
useEffect(() => {
|
||||
completedRef.current = false;
|
||||
}, [currentPath]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isReset || !isPlaying) {
|
||||
reset();
|
||||
setCurrentPath([]);
|
||||
completedRef.current = false;
|
||||
movingForward.current = true;
|
||||
progressRef.current = 0;
|
||||
setReset(false);
|
||||
setRestingRotation(true);
|
||||
const object = scene.getObjectByProperty('uuid', human.modelUuid);
|
||||
const humanData = getHumanById(human.modelUuid);
|
||||
if (object && humanData) {
|
||||
object.position.set(humanData.position[0], humanData.position[1], humanData.position[2]);
|
||||
object.rotation.set(humanData.rotation[0], humanData.rotation[1], humanData.rotation[2]);
|
||||
}
|
||||
}
|
||||
}, [isReset, isPlaying])
|
||||
|
||||
const lastTimeRef = useRef(performance.now());
|
||||
|
||||
useFrame(() => {
|
||||
const now = performance.now();
|
||||
const delta = (now - lastTimeRef.current) / 1000;
|
||||
lastTimeRef.current = now;
|
||||
|
||||
const object = scene.getObjectByProperty('uuid', human.modelUuid);
|
||||
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 targetQuaternion = new THREE.Quaternion().setFromRotationMatrix(new THREE.Matrix4().lookAt(start, end, new THREE.Vector3(0, 1, 0)));
|
||||
const y180 = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 1, 0), Math.PI);
|
||||
targetQuaternion.multiply(y180);
|
||||
|
||||
const angle = object.quaternion.angleTo(targetQuaternion);
|
||||
if (angle < 0.01) {
|
||||
object.quaternion.copy(targetQuaternion);
|
||||
} else {
|
||||
object.quaternion.slerp(targetQuaternion, delta * rotationSpeed * speed * human.speed * 5);
|
||||
}
|
||||
|
||||
const isAligned = angle < 0.01;
|
||||
|
||||
if (isAligned) {
|
||||
progressRef.current += delta * (speed * human.speed);
|
||||
const t = (progressRef.current - accumulatedDistance) / segmentDistance;
|
||||
const position = start.clone().lerp(end, t);
|
||||
object.position.copy(position);
|
||||
if (human.currentMaterials.length > 0) {
|
||||
setCurrentAnimation(human.modelUuid, 'walk_with_box', true, true, true);
|
||||
} else {
|
||||
setCurrentAnimation(human.modelUuid, 'walking', true, true, true);
|
||||
}
|
||||
} else {
|
||||
if (human.currentMaterials.length > 0) {
|
||||
setCurrentAnimation(human.modelUuid, 'idle_with_box', true, true, true);
|
||||
} else {
|
||||
setCurrentAnimation(human.modelUuid, 'idle', true, true, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (progressRef.current >= totalDistance) {
|
||||
if (restRotation && objectRotation) {
|
||||
const targetEuler = new THREE.Euler(0, objectRotation[1], 0);
|
||||
|
||||
const baseQuaternion = new THREE.Quaternion().setFromEuler(targetEuler);
|
||||
const y180 = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 1, 0), Math.PI);
|
||||
const targetQuaternion = baseQuaternion.multiply(y180);
|
||||
|
||||
const angle = object.quaternion.angleTo(targetQuaternion);
|
||||
if (angle < 0.01) {
|
||||
object.quaternion.copy(targetQuaternion);
|
||||
setRestingRotation(false);
|
||||
} else {
|
||||
object.quaternion.slerp(targetQuaternion, delta * rotationSpeed * speed * human.speed * 4);
|
||||
}
|
||||
|
||||
if (human.currentMaterials.length > 0) {
|
||||
setCurrentAnimation(human.modelUuid, 'idle_with_box', true, true, true);
|
||||
} else {
|
||||
setCurrentAnimation(human.modelUuid, 'idle', true, true, true);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (progressRef.current >= totalDistance) {
|
||||
setRestingRotation(true);
|
||||
progressRef.current = 0;
|
||||
movingForward.current = !movingForward.current;
|
||||
setCurrentPath([]);
|
||||
handleCallBack();
|
||||
if (currentPhase === 'pickup-drop') {
|
||||
requestAnimationFrame(startUnloadingProcess);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
{currentPath.length > 0 && (
|
||||
// helper
|
||||
<group visible={false}>
|
||||
<Line points={currentPath} color="blue" lineWidth={3} />
|
||||
{currentPath.map((point, index) => (
|
||||
<mesh key={index} position={point}>
|
||||
<sphereGeometry args={[0.1, 16, 16]} />
|
||||
<meshStandardMaterial color="red" />
|
||||
</mesh>
|
||||
))}
|
||||
</group>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default HumanAnimator
|
||||
@@ -0,0 +1,44 @@
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { useThree } from '@react-three/fiber';
|
||||
import * as THREE from 'three';
|
||||
import { MaterialModel } from '../../../materials/instances/material/materialModel';
|
||||
|
||||
const MaterialAnimator = ({ human }: { human: HumanStatus }) => {
|
||||
const meshRef = useRef<any>(null!);
|
||||
const [hasLoad, setHasLoad] = useState(false);
|
||||
const { scene } = useThree();
|
||||
|
||||
useEffect(() => {
|
||||
setHasLoad(human.currentLoad > 0);
|
||||
}, [human.currentLoad]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!hasLoad || !meshRef.current) return;
|
||||
|
||||
const humanModel = scene.getObjectByProperty("uuid", human.modelUuid) as THREE.Object3D;
|
||||
if (!humanModel) return;
|
||||
|
||||
const bone = humanModel.getObjectByName('PlaceObjectRefBone') as THREE.Bone;
|
||||
if (bone) {
|
||||
bone.add(meshRef.current);
|
||||
|
||||
meshRef.current.position.set(0, 0, 0);
|
||||
meshRef.current.rotation.set(0, 0, 0);
|
||||
meshRef.current.scale.set(1, 1, 1);
|
||||
}
|
||||
}, [hasLoad, human.modelUuid]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{hasLoad && human.currentMaterials.length > 0 && (
|
||||
<MaterialModel
|
||||
matRef={meshRef}
|
||||
materialId={human.currentMaterials[0].materialId || ''}
|
||||
materialType={human.currentMaterials[0].materialType || 'Default material'}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default MaterialAnimator;
|
||||
@@ -1,13 +1,686 @@
|
||||
import { useEffect } from 'react'
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import * as THREE from 'three';
|
||||
import { useThree } from '@react-three/fiber';
|
||||
import { NavMeshQuery } from '@recast-navigation/core';
|
||||
import { useNavMesh } from '../../../../../store/builder/store';
|
||||
import { useAnimationPlaySpeed, usePauseButtonStore, usePlayButtonStore } from '../../../../../store/usePlayButtonStore';
|
||||
import { useTriggerHandler } from '../../../triggers/triggerHandler/useTriggerHandler';
|
||||
import { useSceneContext } from '../../../../scene/sceneContext';
|
||||
import { useProductContext } from '../../../products/productContext';
|
||||
|
||||
import HumanAnimator from '../animator/humanAnimator';
|
||||
import MaterialAnimator from '../animator/materialAnimator';
|
||||
|
||||
function HumanInstance({ human }: { human: HumanStatus }) {
|
||||
const { navMesh } = useNavMesh();
|
||||
const { isPlaying } = usePlayButtonStore();
|
||||
const { scene } = useThree();
|
||||
const { assetStore, materialStore, armBotStore, conveyorStore, machineStore, vehicleStore, humanStore, storageUnitStore, productStore } = useSceneContext();
|
||||
const { removeMaterial, setEndTime } = materialStore();
|
||||
const { getStorageUnitById } = storageUnitStore();
|
||||
const { getArmBotById } = armBotStore();
|
||||
const { getConveyorById } = conveyorStore();
|
||||
const { getVehicleById } = vehicleStore();
|
||||
const { getMachineById } = machineStore();
|
||||
const { triggerPointActions } = useTriggerHandler();
|
||||
const { setCurrentAnimation, resetAnimation, getAssetById } = assetStore();
|
||||
const { getActionByUuid, getEventByModelUuid, getTriggerByUuid } = productStore();
|
||||
const { selectedProductStore } = useProductContext();
|
||||
const { selectedProduct } = selectedProductStore();
|
||||
const { setHumanActive, setHumanState, setHumanPicking, clearCurrentMaterials, setHumanLoad, decrementHumanLoad, removeLastMaterial, incrementIdleTime, incrementActiveTime, resetTime } = 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);
|
||||
const activeTimeRef = useRef<number>(0);
|
||||
const isPausedRef = useRef<boolean>(false);
|
||||
const isSpeedRef = useRef<number>(0);
|
||||
const { speed } = useAnimationPlaySpeed();
|
||||
const { isPaused } = usePauseButtonStore();
|
||||
const previousTimeRef = useRef<number | null>(null);
|
||||
const animationFrameIdRef = useRef<number | null>(null);
|
||||
const humanAsset = getAssetById(human.modelUuid);
|
||||
|
||||
useEffect(() => {
|
||||
console.log('human: ', human);
|
||||
}, [human])
|
||||
isPausedRef.current = isPaused;
|
||||
}, [isPaused]);
|
||||
|
||||
useEffect(() => {
|
||||
isSpeedRef.current = speed;
|
||||
}, [speed]);
|
||||
|
||||
const computePath = useCallback(
|
||||
(start: any, end: any) => {
|
||||
try {
|
||||
const navMeshQuery = new NavMeshQuery(navMesh);
|
||||
const { path: segmentPath } = navMeshQuery.computePath(start, end);
|
||||
if (
|
||||
segmentPath.length > 0 &&
|
||||
Math.round(segmentPath[segmentPath.length - 1].x) == Math.round(end.x) &&
|
||||
Math.round(segmentPath[segmentPath.length - 1].z) == Math.round(end.z)
|
||||
) {
|
||||
return segmentPath?.map(({ x, y, z }) => [x, 0, z] as [number, number, number]) || [];
|
||||
} else {
|
||||
console.log("There is no path here...Choose valid path")
|
||||
const { path: segmentPaths } = navMeshQuery.computePath(start, start);
|
||||
return segmentPaths.map(({ x, y, z }) => [x, 0, z] as [number, number, number]) || [];
|
||||
}
|
||||
} catch {
|
||||
console.error("Failed to compute path");
|
||||
return [];
|
||||
}
|
||||
}, [navMesh]);
|
||||
|
||||
function humanStatus(modelId: string, status: string) {
|
||||
// console.log(`${modelId} , ${status}`);
|
||||
}
|
||||
|
||||
function reset() {
|
||||
setCurrentPhase('init');
|
||||
setHumanActive(human.modelUuid, false);
|
||||
setHumanPicking(human.modelUuid, false);
|
||||
setHumanState(human.modelUuid, 'idle');
|
||||
setHumanLoad(human.modelUuid, 0);
|
||||
resetAnimation(human.modelUuid);
|
||||
setPath([]);
|
||||
isPausedRef.current = false;
|
||||
pauseTimeRef.current = 0;
|
||||
resetTime(human.modelUuid)
|
||||
activeTimeRef.current = 0
|
||||
idleTimeRef.current = 0
|
||||
previousTimeRef.current = null
|
||||
if (animationFrameIdRef.current !== null) {
|
||||
cancelAnimationFrame(animationFrameIdRef.current)
|
||||
animationFrameIdRef.current = null
|
||||
}
|
||||
const object = scene.getObjectByProperty('uuid', human.modelUuid);
|
||||
if (object && human) {
|
||||
object.position.set(human.position[0], human.position[1], human.position[2]);
|
||||
object.rotation.set(human.rotation[0], human.rotation[1], human.rotation[2]);
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (isPlaying) {
|
||||
if (!human.point.action.pickUpPoint || !human.point.action.dropPoint) return;
|
||||
|
||||
if (!human.isActive && human.state === 'idle' && currentPhase === 'init') {
|
||||
const toPickupPath = computePath(
|
||||
new THREE.Vector3(human?.position[0], human?.position[1], human?.position[2]),
|
||||
new THREE.Vector3(
|
||||
human?.point?.action?.pickUpPoint?.position?.[0] ?? 0,
|
||||
human?.point?.action?.pickUpPoint?.position?.[1] ?? 0,
|
||||
human?.point?.action?.pickUpPoint?.position?.[2] ?? 0
|
||||
)
|
||||
);
|
||||
setPath(toPickupPath);
|
||||
setCurrentPhase('init-pickup');
|
||||
setHumanState(human.modelUuid, 'running');
|
||||
setHumanPicking(human.modelUuid, false);
|
||||
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') {
|
||||
if (humanAsset && human.currentLoad === human.point.action.loadCapacity && human.currentMaterials.length > 0 && humanAsset.animationState?.current === 'pickup' && humanAsset.animationState?.isCompleted) {
|
||||
if (human.point.action.pickUpPoint && human.point.action.dropPoint) {
|
||||
const toDrop = computePath(
|
||||
new THREE.Vector3(
|
||||
human.point.action.pickUpPoint.position?.[0] ?? 0,
|
||||
human.point.action.pickUpPoint.position?.[1] ?? 0,
|
||||
human.point.action.pickUpPoint.position?.[2] ?? 0
|
||||
),
|
||||
new THREE.Vector3(
|
||||
human.point.action.dropPoint.position?.[0] ?? 0,
|
||||
human.point.action.dropPoint.position?.[1] ?? 0,
|
||||
human.point.action.dropPoint.position?.[2] ?? 0
|
||||
)
|
||||
);
|
||||
setPath(toDrop);
|
||||
setCurrentPhase('pickup-drop');
|
||||
setHumanState(human.modelUuid, 'running');
|
||||
setHumanPicking(human.modelUuid, false);
|
||||
setHumanPicking(human.modelUuid, true);
|
||||
setCurrentAnimation(human.modelUuid, 'walk_with_box', true, true, true);
|
||||
humanStatus(human.modelUuid, 'Started from pickup point, heading to drop point');
|
||||
}
|
||||
} else if (human.currentLoad === human.point.action.loadCapacity && human.currentMaterials.length > 0) {
|
||||
setCurrentAnimation(human.modelUuid, 'pickup', true, false, false);
|
||||
}
|
||||
} else if (!human.isActive && human.state === 'idle' && currentPhase === 'dropping' && human.currentLoad === 0) {
|
||||
if (human.point.action.pickUpPoint && human.point.action.dropPoint) {
|
||||
const dropToPickup = computePath(
|
||||
new THREE.Vector3(
|
||||
human.point.action.dropPoint.position?.[0] ?? 0,
|
||||
human.point.action.dropPoint.position?.[1] ?? 0,
|
||||
human.point.action.dropPoint.position?.[2] ?? 0
|
||||
),
|
||||
new THREE.Vector3(
|
||||
human.point.action.pickUpPoint.position?.[0] ?? 0,
|
||||
human.point.action.pickUpPoint.position?.[1] ?? 0,
|
||||
human.point.action.pickUpPoint.position?.[2] ?? 0
|
||||
)
|
||||
);
|
||||
setPath(dropToPickup);
|
||||
setCurrentPhase('drop-pickup');
|
||||
setHumanState(human.modelUuid, 'running');
|
||||
setHumanPicking(human.modelUuid, false);
|
||||
setHumanActive(human.modelUuid, true);
|
||||
setCurrentAnimation(human.modelUuid, 'walking', true, true, true);
|
||||
humanStatus(human.modelUuid, 'Started from dropping point, heading to pickup point');
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
reset()
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [human, currentPhase, path, isPlaying, humanAsset?.animationState?.isCompleted]);
|
||||
|
||||
function handleCallBack() {
|
||||
if (currentPhase === 'init-pickup') {
|
||||
setCurrentPhase('picking');
|
||||
setHumanState(human.modelUuid, 'idle');
|
||||
setHumanPicking(human.modelUuid, true);
|
||||
setHumanActive(human.modelUuid, false);
|
||||
setCurrentAnimation(human.modelUuid, 'idle', true, true, true);
|
||||
humanStatus(human.modelUuid, 'Reached pickup point, waiting for material');
|
||||
setPath([]);
|
||||
} else if (currentPhase === 'pickup-drop') {
|
||||
setCurrentPhase('dropping');
|
||||
setHumanState(human.modelUuid, 'idle');
|
||||
setHumanPicking(human.modelUuid, false);
|
||||
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');
|
||||
setHumanState(human.modelUuid, 'idle');
|
||||
setHumanPicking(human.modelUuid, true);
|
||||
setHumanActive(human.modelUuid, false);
|
||||
setPath([]);
|
||||
clearCurrentMaterials(human.modelUuid);
|
||||
setCurrentAnimation(human.modelUuid, 'idle', true, true, true);
|
||||
humanStatus(human.modelUuid, 'Reached pickup point again, cycle complete');
|
||||
}
|
||||
}
|
||||
|
||||
function animate(currentTime: number) {
|
||||
if (previousTimeRef.current === null) {
|
||||
previousTimeRef.current = currentTime;
|
||||
}
|
||||
|
||||
const deltaTime = (currentTime - previousTimeRef.current) / 1000;
|
||||
previousTimeRef.current = currentTime;
|
||||
|
||||
if (human.isActive) {
|
||||
if (!isPausedRef.current) {
|
||||
activeTimeRef.current += deltaTime * isSpeedRef.current;
|
||||
}
|
||||
} else {
|
||||
if (!isPausedRef.current) {
|
||||
idleTimeRef.current += deltaTime * isSpeedRef.current;
|
||||
}
|
||||
}
|
||||
animationFrameIdRef.current = requestAnimationFrame(animate);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!isPlaying) return
|
||||
if (!human.isActive) {
|
||||
const roundedActiveTime = Math.round(activeTimeRef.current);
|
||||
incrementActiveTime(human.modelUuid, roundedActiveTime);
|
||||
activeTimeRef.current = 0;
|
||||
} else {
|
||||
const roundedIdleTime = Math.round(idleTimeRef.current);
|
||||
incrementIdleTime(human.modelUuid, roundedIdleTime);
|
||||
idleTimeRef.current = 0;
|
||||
}
|
||||
|
||||
if (animationFrameIdRef.current === null) {
|
||||
animationFrameIdRef.current = requestAnimationFrame(animate);
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (animationFrameIdRef.current !== null) {
|
||||
cancelAnimationFrame(animationFrameIdRef.current);
|
||||
animationFrameIdRef.current = null;
|
||||
}
|
||||
};
|
||||
}, [human, isPlaying]);
|
||||
|
||||
function startUnloadingProcess() {
|
||||
const humanAsset = getAssetById(human.modelUuid);
|
||||
if (humanAsset?.animationState?.current === 'drop' && humanAsset?.animationState?.isCompleted) {
|
||||
if (human.point.action.triggers.length > 0) {
|
||||
const trigger = getTriggerByUuid(selectedProduct.productUuid, human.point.action.triggers[0]?.triggerUuid);
|
||||
const model = getEventByModelUuid(selectedProduct.productUuid, trigger?.triggeredAsset?.triggeredModel?.modelUuid || '');
|
||||
|
||||
if (trigger && model) {
|
||||
if (model.type === 'transfer') {
|
||||
const action = getActionByUuid(selectedProduct.productUuid, human.point.action.actionUuid);
|
||||
if (action) {
|
||||
handleMaterialDropToConveyor(model);
|
||||
}
|
||||
} else if (model.type === 'machine') {
|
||||
const action = getActionByUuid(selectedProduct.productUuid, human.point.action.actionUuid);
|
||||
if (action) {
|
||||
handleMaterialDropToMachine(model);
|
||||
}
|
||||
} else if (model.type === 'roboticArm') {
|
||||
const action = getActionByUuid(selectedProduct.productUuid, human.point.action.actionUuid);
|
||||
if (action) {
|
||||
handleMaterialDropToArmBot(model);
|
||||
}
|
||||
} else if (model.type === 'storageUnit') {
|
||||
const action = getActionByUuid(selectedProduct.productUuid, human.point.action.actionUuid);
|
||||
if (action) {
|
||||
handleMaterialDropToStorageUnit(model);
|
||||
}
|
||||
} else if (model.type === 'vehicle') {
|
||||
const action = getActionByUuid(selectedProduct.productUuid, human.point.action.actionUuid);
|
||||
if (action) {
|
||||
handleMaterialDropToVehicle(model);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const droppedMaterial = human.currentLoad;
|
||||
handleMaterialDropByDefault(droppedMaterial);
|
||||
}
|
||||
} else {
|
||||
const droppedMaterial = human.currentLoad;
|
||||
handleMaterialDropByDefault(droppedMaterial);
|
||||
}
|
||||
} else {
|
||||
requestAnimationFrame(startUnloadingProcess);
|
||||
}
|
||||
}
|
||||
|
||||
function handleMaterialDropToStorageUnit(model: StorageEventSchema) {
|
||||
const humanAsset = getAssetById(human.modelUuid);
|
||||
if (model && humanAsset?.animationState?.current !== 'drop') {
|
||||
setCurrentAnimation(human.modelUuid, 'drop', true, false, false);
|
||||
}
|
||||
|
||||
const checkAnimation = () => {
|
||||
if (humanAsset?.animationState?.isCompleted) {
|
||||
if (model.point.action.actionType === 'store') {
|
||||
loopMaterialDropToStorage(
|
||||
human.modelUuid,
|
||||
human.currentLoad,
|
||||
model.modelUuid,
|
||||
model.point.action.storageCapacity,
|
||||
human.point.action
|
||||
);
|
||||
}
|
||||
} else {
|
||||
requestAnimationFrame(checkAnimation);
|
||||
}
|
||||
};
|
||||
checkAnimation();
|
||||
}
|
||||
|
||||
function loopMaterialDropToStorage(
|
||||
humanId: string,
|
||||
humanCurrentLoad: number,
|
||||
storageUnitId: string,
|
||||
storageMaxCapacity: number,
|
||||
action: HumanAction
|
||||
) {
|
||||
const storageUnit = getStorageUnitById(storageUnitId);
|
||||
const humanAsset = getAssetById(human.modelUuid);
|
||||
|
||||
if (!storageUnit || humanCurrentLoad <= 0 || storageUnit.currentLoad >= storageMaxCapacity) {
|
||||
return;
|
||||
}
|
||||
|
||||
decrementHumanLoad(humanId, 1);
|
||||
humanCurrentLoad -= 1;
|
||||
|
||||
const material = removeLastMaterial(humanId);
|
||||
if (material) {
|
||||
triggerPointActions(action, material.materialId);
|
||||
}
|
||||
|
||||
if (humanCurrentLoad > 0 && storageUnit.currentLoad < storageMaxCapacity) {
|
||||
resetAnimation(human.modelUuid);
|
||||
setCurrentAnimation(human.modelUuid, 'drop', true, false, false);
|
||||
|
||||
const waitForNextDrop = () => {
|
||||
if (humanAsset?.animationState?.current === 'drop' && humanAsset?.animationState?.isCompleted) {
|
||||
loopMaterialDropToStorage(
|
||||
humanId,
|
||||
humanCurrentLoad,
|
||||
storageUnitId,
|
||||
storageMaxCapacity,
|
||||
action
|
||||
);
|
||||
} else {
|
||||
requestAnimationFrame(waitForNextDrop);
|
||||
}
|
||||
};
|
||||
waitForNextDrop();
|
||||
}
|
||||
}
|
||||
|
||||
function handleMaterialDropToConveyor(model: ConveyorEventSchema) {
|
||||
const humanAsset = getAssetById(human.modelUuid);
|
||||
if (humanAsset?.animationState?.current !== 'drop') {
|
||||
setCurrentAnimation(human.modelUuid, 'drop', true, false, false);
|
||||
}
|
||||
|
||||
const checkAnimation = () => {
|
||||
if (humanAsset?.animationState?.isCompleted) {
|
||||
const conveyor = getConveyorById(model.modelUuid);
|
||||
if (conveyor) {
|
||||
loopMaterialDropToConveyor(
|
||||
human.modelUuid,
|
||||
human.currentLoad,
|
||||
conveyor.modelUuid,
|
||||
human.point.action
|
||||
);
|
||||
}
|
||||
} else {
|
||||
requestAnimationFrame(checkAnimation);
|
||||
}
|
||||
};
|
||||
checkAnimation();
|
||||
}
|
||||
|
||||
function loopMaterialDropToConveyor(
|
||||
humanId: string,
|
||||
humanCurrentLoad: number,
|
||||
conveyorId: string,
|
||||
action: HumanAction
|
||||
) {
|
||||
const conveyor = getConveyorById(conveyorId);
|
||||
const humanAsset = getAssetById(human.modelUuid);
|
||||
|
||||
if (!conveyor || humanCurrentLoad <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
decrementHumanLoad(humanId, 1);
|
||||
humanCurrentLoad -= 1;
|
||||
|
||||
const material = removeLastMaterial(humanId);
|
||||
if (material) {
|
||||
triggerPointActions(action, material.materialId);
|
||||
}
|
||||
|
||||
if (humanCurrentLoad > 0) {
|
||||
resetAnimation(human.modelUuid);
|
||||
setCurrentAnimation(human.modelUuid, 'drop', true, false, false);
|
||||
|
||||
const waitForNextDrop = () => {
|
||||
if (humanAsset?.animationState?.isCompleted) {
|
||||
loopMaterialDropToConveyor(
|
||||
humanId,
|
||||
humanCurrentLoad,
|
||||
conveyorId,
|
||||
action
|
||||
);
|
||||
} else {
|
||||
requestAnimationFrame(waitForNextDrop);
|
||||
}
|
||||
};
|
||||
waitForNextDrop();
|
||||
}
|
||||
}
|
||||
|
||||
function handleMaterialDropToArmBot(model: RoboticArmEventSchema) {
|
||||
const humanAsset = getAssetById(human.modelUuid);
|
||||
if (humanAsset?.animationState?.current !== 'drop') {
|
||||
setCurrentAnimation(human.modelUuid, 'drop', true, false, false);
|
||||
}
|
||||
|
||||
const checkAnimation = () => {
|
||||
if (humanAsset?.animationState?.current === 'drop' && humanAsset?.animationState?.isCompleted) {
|
||||
const armBot = getArmBotById(model.modelUuid);
|
||||
if (armBot && armBot.state === 'idle' && !armBot.isActive) {
|
||||
loopMaterialDropToArmBot(
|
||||
human.modelUuid,
|
||||
human.currentLoad,
|
||||
model.modelUuid,
|
||||
human.point.action
|
||||
);
|
||||
}
|
||||
} else {
|
||||
requestAnimationFrame(checkAnimation);
|
||||
}
|
||||
};
|
||||
checkAnimation();
|
||||
}
|
||||
|
||||
function loopMaterialDropToArmBot(
|
||||
humanId: string,
|
||||
humanCurrentLoad: number,
|
||||
armBotId: string,
|
||||
action: HumanAction
|
||||
) {
|
||||
const armBot = getArmBotById(armBotId);
|
||||
const humanAsset = getAssetById(human.modelUuid);
|
||||
|
||||
if (!armBot || armBot.state !== 'idle' || armBot.isActive || humanCurrentLoad <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
decrementHumanLoad(humanId, 1);
|
||||
humanCurrentLoad -= 1;
|
||||
|
||||
const material = removeLastMaterial(humanId);
|
||||
if (material) {
|
||||
triggerPointActions(action, material.materialId);
|
||||
}
|
||||
|
||||
if (humanCurrentLoad > 0) {
|
||||
resetAnimation(human.modelUuid);
|
||||
setCurrentAnimation(human.modelUuid, 'drop', true, false, false);
|
||||
|
||||
const waitForNextTransfer = () => {
|
||||
const currentArmBot = getArmBotById(armBotId);
|
||||
if (currentArmBot && currentArmBot.state === 'idle' && !currentArmBot.isActive) {
|
||||
if (humanAsset?.animationState?.isCompleted) {
|
||||
loopMaterialDropToArmBot(
|
||||
humanId,
|
||||
humanCurrentLoad,
|
||||
armBotId,
|
||||
action
|
||||
);
|
||||
} else {
|
||||
requestAnimationFrame(waitForNextTransfer);
|
||||
}
|
||||
} else {
|
||||
requestAnimationFrame(waitForNextTransfer);
|
||||
}
|
||||
};
|
||||
waitForNextTransfer();
|
||||
}
|
||||
}
|
||||
|
||||
function handleMaterialDropToVehicle(model: VehicleEventSchema) {
|
||||
const humanAsset = getAssetById(human.modelUuid);
|
||||
if (humanAsset?.animationState?.current !== 'drop') {
|
||||
setCurrentAnimation(human.modelUuid, 'drop', true, false, false);
|
||||
}
|
||||
|
||||
const checkAnimation = () => {
|
||||
if (humanAsset?.animationState?.current === 'drop' && humanAsset?.animationState?.isCompleted) {
|
||||
const vehicle = getVehicleById(model.modelUuid);
|
||||
if (vehicle && vehicle.state === 'idle' && !vehicle.isActive) {
|
||||
loopMaterialDropToVehicle(
|
||||
human.modelUuid,
|
||||
human.currentLoad,
|
||||
model.modelUuid,
|
||||
human.point.action
|
||||
);
|
||||
}
|
||||
} else {
|
||||
requestAnimationFrame(checkAnimation);
|
||||
}
|
||||
};
|
||||
checkAnimation();
|
||||
}
|
||||
|
||||
function loopMaterialDropToVehicle(
|
||||
humanId: string,
|
||||
humanCurrentLoad: number,
|
||||
vehicleId: string,
|
||||
action: HumanAction
|
||||
) {
|
||||
const vehicle = getVehicleById(vehicleId);
|
||||
const humanAsset = getAssetById(human.modelUuid);
|
||||
|
||||
if (!vehicle || vehicle.state !== 'idle' || vehicle.isActive || humanCurrentLoad <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
decrementHumanLoad(humanId, 1);
|
||||
humanCurrentLoad -= 1;
|
||||
|
||||
const material = removeLastMaterial(humanId);
|
||||
if (material) {
|
||||
triggerPointActions(action, material.materialId);
|
||||
}
|
||||
|
||||
if (humanCurrentLoad > 0) {
|
||||
resetAnimation(human.modelUuid);
|
||||
setCurrentAnimation(human.modelUuid, 'drop', true, false, false);
|
||||
|
||||
const waitForNextTransfer = () => {
|
||||
const currentVehicle = getVehicleById(vehicleId);
|
||||
if (currentVehicle && currentVehicle.state === 'idle' && !currentVehicle.isActive) {
|
||||
if (humanAsset?.animationState?.isCompleted) {
|
||||
loopMaterialDropToVehicle(
|
||||
humanId,
|
||||
humanCurrentLoad,
|
||||
vehicleId,
|
||||
action
|
||||
);
|
||||
} else {
|
||||
requestAnimationFrame(waitForNextTransfer);
|
||||
}
|
||||
} else {
|
||||
requestAnimationFrame(waitForNextTransfer);
|
||||
}
|
||||
};
|
||||
waitForNextTransfer();
|
||||
}
|
||||
}
|
||||
|
||||
function handleMaterialDropToMachine(model: MachineEventSchema) {
|
||||
const humanAsset = getAssetById(human.modelUuid);
|
||||
if (humanAsset?.animationState?.current !== 'drop') {
|
||||
setCurrentAnimation(human.modelUuid, 'drop', true, false, false);
|
||||
}
|
||||
|
||||
const checkAnimation = () => {
|
||||
if (humanAsset?.animationState?.current === 'drop' && humanAsset?.animationState?.isCompleted) {
|
||||
const machine = getMachineById(model.modelUuid);
|
||||
if (machine && machine.state === 'idle' && !machine.isActive) {
|
||||
loopMaterialDropToMachine(
|
||||
human.modelUuid,
|
||||
human.currentLoad,
|
||||
model.modelUuid,
|
||||
human.point.action
|
||||
);
|
||||
}
|
||||
} else {
|
||||
requestAnimationFrame(checkAnimation);
|
||||
}
|
||||
};
|
||||
checkAnimation();
|
||||
}
|
||||
|
||||
function loopMaterialDropToMachine(
|
||||
humanId: string,
|
||||
humanCurrentLoad: number,
|
||||
machineId: string,
|
||||
action: HumanAction
|
||||
) {
|
||||
const machine = getMachineById(machineId);
|
||||
const humanAsset = getAssetById(human.modelUuid);
|
||||
|
||||
if (!machine || machine.state !== 'idle' || machine.isActive || humanCurrentLoad <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
decrementHumanLoad(humanId, 1);
|
||||
humanCurrentLoad -= 1;
|
||||
|
||||
const material = removeLastMaterial(humanId);
|
||||
if (material) {
|
||||
triggerPointActions(action, material.materialId);
|
||||
}
|
||||
|
||||
if (humanCurrentLoad > 0) {
|
||||
resetAnimation(human.modelUuid);
|
||||
setCurrentAnimation(human.modelUuid, 'drop', true, false, false);
|
||||
|
||||
const waitForNextTransfer = () => {
|
||||
const currentMachine = getMachineById(machineId);
|
||||
if (currentMachine && currentMachine.state === 'idle' && !currentMachine.isActive) {
|
||||
if (humanAsset?.animationState?.isCompleted) {
|
||||
loopMaterialDropToMachine(
|
||||
humanId,
|
||||
humanCurrentLoad,
|
||||
machineId,
|
||||
action
|
||||
);
|
||||
} else {
|
||||
requestAnimationFrame(waitForNextTransfer);
|
||||
}
|
||||
} else {
|
||||
requestAnimationFrame(waitForNextTransfer);
|
||||
}
|
||||
};
|
||||
waitForNextTransfer();
|
||||
}
|
||||
}
|
||||
|
||||
function handleMaterialDropByDefault(droppedMaterial: number) {
|
||||
const humanAsset = getAssetById(human.modelUuid);
|
||||
if (humanAsset?.animationState?.current !== 'drop') {
|
||||
setCurrentAnimation(human.modelUuid, 'drop', true, false, false);
|
||||
}
|
||||
|
||||
if (humanAsset?.animationState?.isCompleted) {
|
||||
const remainingMaterials = droppedMaterial - 1;
|
||||
decrementHumanLoad(human.modelUuid, 1);
|
||||
const material = removeLastMaterial(human.modelUuid);
|
||||
|
||||
if (material) {
|
||||
setEndTime(material.materialId, performance.now());
|
||||
removeMaterial(material.materialId);
|
||||
}
|
||||
|
||||
if (remainingMaterials > 0) {
|
||||
resetAnimation(human.modelUuid);
|
||||
setCurrentAnimation(human.modelUuid, 'drop', true, false, false);
|
||||
|
||||
requestAnimationFrame(() => handleMaterialDropByDefault(remainingMaterials));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
requestAnimationFrame(() => handleMaterialDropByDefault(droppedMaterial));
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
<HumanAnimator
|
||||
path={path}
|
||||
handleCallBack={handleCallBack}
|
||||
currentPhase={currentPhase}
|
||||
human={human}
|
||||
reset={reset}
|
||||
startUnloadingProcess={startUnloadingProcess}
|
||||
/>
|
||||
|
||||
<MaterialAnimator human={human} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
263
app/src/modules/simulation/human/instances/instance/humanUi.tsx
Normal file
263
app/src/modules/simulation/human/instances/instance/humanUi.tsx
Normal file
@@ -0,0 +1,263 @@
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { useGLTF } from '@react-three/drei';
|
||||
import { useFrame, useThree } from '@react-three/fiber';
|
||||
import { useIsDragging, useIsRotating, useSelectedAction, useSelectedEventSphere } from '../../../../../store/simulation/useSimulationStore';
|
||||
import { useProductContext } from '../../../products/productContext';
|
||||
import { useSceneContext } from '../../../../scene/sceneContext';
|
||||
import { Group, Plane, Vector3 } from 'three';
|
||||
import { useVersionContext } from '../../../../builder/version/versionContext';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import startPoint from "../../../../../assets/gltf-glb/ui/arrow_green.glb";
|
||||
import startEnd from "../../../../../assets/gltf-glb/ui/arrow_red.glb";
|
||||
import { upsertProductOrEventApi } from '../../../../../services/simulation/products/UpsertProductOrEventApi';
|
||||
|
||||
function HumanUi() {
|
||||
const { scene: startScene } = useGLTF(startPoint) as any;
|
||||
const { scene: endScene } = useGLTF(startEnd) as any;
|
||||
const startMarker = useRef<Group>(null);
|
||||
const endMarker = useRef<Group>(null);
|
||||
const outerGroup = useRef<Group>(null);
|
||||
const prevMousePos = useRef({ x: 0, y: 0 });
|
||||
const { controls, raycaster } = useThree();
|
||||
const { selectedEventSphere } = useSelectedEventSphere();
|
||||
const { selectedProductStore } = useProductContext();
|
||||
const { humanStore, productStore } = useSceneContext();
|
||||
const { selectedProduct } = selectedProductStore();
|
||||
const { humans, getHumanById } = humanStore();
|
||||
const { updateEvent } = productStore();
|
||||
const [startPosition, setStartPosition] = useState<[number, number, number]>([0, 1, 0]);
|
||||
const [endPosition, setEndPosition] = useState<[number, number, number]>([0, 1, 0]);
|
||||
const [startRotation, setStartRotation] = useState<[number, number, number]>([0, 0, 0]);
|
||||
const [endRotation, setEndRotation] = useState<[number, number, number]>([0, 0, 0]);
|
||||
const { isDragging, setIsDragging } = useIsDragging();
|
||||
const { isRotating, setIsRotating } = useIsRotating();
|
||||
const plane = useRef(new Plane(new Vector3(0, 1, 0), 0));
|
||||
|
||||
const [selectedHumanData, setSelectedHumanData] = useState<{
|
||||
position: [number, number, number];
|
||||
rotation: [number, number, number];
|
||||
}>({ position: [0, 0, 0], rotation: [0, 0, 0] });
|
||||
|
||||
const { selectedAction } = useSelectedAction();
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
const { projectId } = useParams();
|
||||
|
||||
const updateBackend = (
|
||||
productName: string,
|
||||
productUuid: string,
|
||||
projectId: string,
|
||||
eventData: EventsSchema
|
||||
) => {
|
||||
upsertProductOrEventApi({
|
||||
productName: productName,
|
||||
productUuid: productUuid,
|
||||
projectId: projectId,
|
||||
eventDatas: eventData,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!selectedEventSphere) return;
|
||||
|
||||
const selectedHuman = getHumanById(selectedEventSphere.userData.modelUuid);
|
||||
if (!selectedHuman || !selectedHuman.point?.action) return;
|
||||
|
||||
setSelectedHumanData({
|
||||
position: selectedHuman.position,
|
||||
rotation: selectedHuman.rotation,
|
||||
});
|
||||
|
||||
const action = selectedHuman.point.action;
|
||||
|
||||
if (action.pickUpPoint?.position && outerGroup.current) {
|
||||
const worldPos = new Vector3(...action.pickUpPoint.position);
|
||||
const localPosition = outerGroup.current.worldToLocal(worldPos.clone());
|
||||
setStartPosition([localPosition.x, 0.5, localPosition.z]);
|
||||
setStartRotation(action.pickUpPoint.rotation || [0, 0, 0]);
|
||||
}
|
||||
|
||||
if (action.dropPoint?.position && outerGroup.current) {
|
||||
const worldPos = new Vector3(...action.dropPoint.position);
|
||||
const localPosition = outerGroup.current.worldToLocal(worldPos.clone());
|
||||
setEndPosition([localPosition.x, 0.5, localPosition.z]);
|
||||
setEndRotation(action.dropPoint.rotation || [0, 0, 0]);
|
||||
}
|
||||
}, [selectedEventSphere, outerGroup.current, selectedAction, humans]);
|
||||
|
||||
const handlePointerDown = (
|
||||
e: any,
|
||||
state: "start" | "end",
|
||||
rotation: "start" | "end"
|
||||
) => {
|
||||
if (e.object.name === "handle") {
|
||||
const normalizedX = (e.clientX / window.innerWidth) * 2 - 1;
|
||||
const normalizedY = -(e.clientY / window.innerHeight) * 2 + 1;
|
||||
prevMousePos.current = { x: normalizedX, y: normalizedY };
|
||||
setIsRotating(rotation);
|
||||
if (controls) (controls as any).enabled = false;
|
||||
setIsDragging(null);
|
||||
} else {
|
||||
setIsDragging(state);
|
||||
setIsRotating(null);
|
||||
if (controls) (controls as any).enabled = false;
|
||||
}
|
||||
};
|
||||
|
||||
const handlePointerUp = () => {
|
||||
(controls as any).enabled = true;
|
||||
setIsDragging(null);
|
||||
setIsRotating(null);
|
||||
|
||||
if (selectedEventSphere?.userData.modelUuid && selectedAction.actionId) {
|
||||
const selectedHuman = getHumanById(selectedEventSphere.userData.modelUuid);
|
||||
|
||||
if (selectedHuman && outerGroup.current && startMarker.current && endMarker.current) {
|
||||
const worldPosStart = new Vector3(...startPosition);
|
||||
const globalStartPosition = outerGroup.current.localToWorld(worldPosStart.clone());
|
||||
|
||||
const worldPosEnd = new Vector3(...endPosition);
|
||||
const globalEndPosition = outerGroup.current.localToWorld(worldPosEnd.clone());
|
||||
|
||||
const updatedAction = {
|
||||
...selectedHuman.point.action,
|
||||
pickUpPoint: {
|
||||
position: [globalStartPosition.x, globalStartPosition.y, globalStartPosition.z] as [number, number, number],
|
||||
rotation: startRotation
|
||||
},
|
||||
dropPoint: {
|
||||
position: [globalEndPosition.x, globalEndPosition.y, globalEndPosition.z] as [number, number, number],
|
||||
rotation: endRotation
|
||||
}
|
||||
};
|
||||
|
||||
const event = updateEvent(
|
||||
selectedProduct.productUuid,
|
||||
selectedEventSphere.userData.modelUuid,
|
||||
{
|
||||
...selectedHuman,
|
||||
point: {
|
||||
...selectedHuman.point,
|
||||
action: updatedAction
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if (event) {
|
||||
updateBackend(
|
||||
selectedProduct.productName,
|
||||
selectedProduct.productUuid,
|
||||
projectId || '',
|
||||
event
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
useFrame(() => {
|
||||
if (!isDragging || !plane.current || !raycaster || !outerGroup.current) return;
|
||||
const intersectPoint = new Vector3();
|
||||
const intersects = raycaster.ray.intersectPlane(
|
||||
plane.current,
|
||||
intersectPoint
|
||||
);
|
||||
if (!intersects) return;
|
||||
const localPoint = outerGroup?.current.worldToLocal(intersectPoint.clone());
|
||||
if (isDragging === "start") {
|
||||
setStartPosition([localPoint.x, 0.5, localPoint.z]);
|
||||
} else if (isDragging === "end") {
|
||||
setEndPosition([localPoint.x, 0.5, localPoint.z]);
|
||||
}
|
||||
});
|
||||
|
||||
useFrame((state) => {
|
||||
if (!isRotating) return;
|
||||
const currentPointerX = state.pointer.x;
|
||||
const deltaX = currentPointerX - prevMousePos.current.x;
|
||||
prevMousePos.current.x = currentPointerX;
|
||||
const marker =isRotating === "start" ? startMarker.current : endMarker.current;
|
||||
if (marker) {
|
||||
const rotationSpeed = 10;
|
||||
marker.rotation.y += deltaX * rotationSpeed;
|
||||
if (isRotating === "start") {
|
||||
setStartRotation([
|
||||
marker.rotation.x,
|
||||
marker.rotation.y,
|
||||
marker.rotation.z,
|
||||
]);
|
||||
} else {
|
||||
setEndRotation([
|
||||
marker.rotation.x,
|
||||
marker.rotation.y,
|
||||
marker.rotation.z,
|
||||
]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const handleGlobalPointerUp = () => {
|
||||
setIsDragging(null);
|
||||
setIsRotating(null);
|
||||
if (controls) (controls as any).enabled = true;
|
||||
handlePointerUp();
|
||||
};
|
||||
|
||||
if (isDragging || isRotating) {
|
||||
window.addEventListener("pointerup", handleGlobalPointerUp);
|
||||
}
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("pointerup", handleGlobalPointerUp);
|
||||
};
|
||||
}, [isDragging, isRotating, startPosition, startRotation, endPosition, endRotation]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{selectedHumanData && (
|
||||
<group
|
||||
position={selectedHumanData.position}
|
||||
ref={outerGroup}
|
||||
>
|
||||
<primitive
|
||||
name="startMarker"
|
||||
object={startScene}
|
||||
ref={startMarker}
|
||||
position={startPosition}
|
||||
rotation={startRotation}
|
||||
onPointerDown={(e: any) => {
|
||||
e.stopPropagation();
|
||||
handlePointerDown(e, "start", "start");
|
||||
}}
|
||||
onPointerMissed={() => {
|
||||
(controls as any).enabled = true;
|
||||
setIsDragging(null);
|
||||
setIsRotating(null);
|
||||
}}
|
||||
/>
|
||||
|
||||
<primitive
|
||||
name="endMarker"
|
||||
object={endScene}
|
||||
ref={endMarker}
|
||||
position={endPosition}
|
||||
rotation={endRotation}
|
||||
onPointerDown={(e: any) => {
|
||||
e.stopPropagation();
|
||||
handlePointerDown(e, "end", "end");
|
||||
}}
|
||||
onPointerMissed={() => {
|
||||
(controls as any).enabled = true;
|
||||
setIsDragging(null);
|
||||
setIsRotating(null);
|
||||
}}
|
||||
/>
|
||||
</group>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default HumanUi
|
||||
@@ -124,7 +124,8 @@ function determineExecutionMachineSequences(products: productsSchema): EventsSch
|
||||
event.type === 'vehicle' ||
|
||||
event.type === 'machine' ||
|
||||
event.type === 'storageUnit' ||
|
||||
event.type === 'roboticArm'
|
||||
event.type === 'roboticArm' ||
|
||||
event.type === 'human'
|
||||
) {
|
||||
pointToEventMap.set(event.point.uuid, event);
|
||||
allPoints.push(event.point);
|
||||
|
||||
@@ -16,7 +16,8 @@ export async function determineExecutionMachineSequences(products: productsSchem
|
||||
event.type === 'vehicle' ||
|
||||
event.type === 'machine' ||
|
||||
event.type === 'storageUnit' ||
|
||||
event.type === 'roboticArm'
|
||||
event.type === 'roboticArm' ||
|
||||
event.type === 'human'
|
||||
) {
|
||||
pointToEventMap.set(event.point.uuid, event);
|
||||
allPoints.push(event.point);
|
||||
|
||||
@@ -19,7 +19,9 @@ export function determineExecutionOrder(products: productsSchema): PointsScheme[
|
||||
} else if (event.type === 'vehicle' ||
|
||||
event.type === 'machine' ||
|
||||
event.type === 'storageUnit' ||
|
||||
event.type === 'roboticArm') {
|
||||
event.type === 'roboticArm' ||
|
||||
event.type === 'human'
|
||||
) {
|
||||
pointMap.set(event.point.uuid, event.point);
|
||||
allPoints.push(event.point);
|
||||
}
|
||||
|
||||
@@ -16,7 +16,9 @@ export async function determineExecutionSequences(products: productsSchema): Pro
|
||||
} else if (event.type === 'vehicle' ||
|
||||
event.type === 'machine' ||
|
||||
event.type === 'storageUnit' ||
|
||||
event.type === 'roboticArm') {
|
||||
event.type === 'roboticArm' ||
|
||||
event.type === 'human'
|
||||
) {
|
||||
pointMap.set(event.point.uuid, event.point);
|
||||
allPoints.push(event.point);
|
||||
}
|
||||
|
||||
@@ -91,7 +91,8 @@ function determineExecutionMachineSequences(products: productsSchema): EventsSch
|
||||
event.type === 'vehicle' ||
|
||||
event.type === 'machine' ||
|
||||
event.type === 'storageUnit' ||
|
||||
event.type === 'roboticArm'
|
||||
event.type === 'roboticArm' ||
|
||||
event.type === 'human'
|
||||
) {
|
||||
pointToEventMap.set(event.point.uuid, event);
|
||||
allPoints.push(event.point);
|
||||
|
||||
@@ -43,7 +43,7 @@ const VehicleUI = () => {
|
||||
const outerGroup = useRef<Group>(null);
|
||||
const state: Types.ThreeState = useThree();
|
||||
const controls: any = state.controls;
|
||||
const [selectedVehicleData, setSelectedVechicleData] = useState<{ position: [number, number, number]; rotation: [number, number, number]; }>({ position: [0, 0, 0], rotation: [0, 0, 0] });
|
||||
const [selectedVehicleData, setSelectedVehicleData] = useState<{ position: [number, number, number]; rotation: [number, number, number]; }>({ position: [0, 0, 0], rotation: [0, 0, 0] });
|
||||
const CIRCLE_RADIUS = 0.8;
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
@@ -71,7 +71,7 @@ const VehicleUI = () => {
|
||||
);
|
||||
|
||||
if (selectedVehicle) {
|
||||
setSelectedVechicleData({
|
||||
setSelectedVehicleData({
|
||||
position: selectedVehicle.position,
|
||||
rotation: selectedVehicle.rotation,
|
||||
});
|
||||
|
||||
@@ -6,9 +6,10 @@ import { useVehicleEventManager } from '../../vehicle/eventManager/useVehicleEve
|
||||
import { useMachineEventManager } from '../../machine/eventManager/useMachineEventManager';
|
||||
import { useSceneContext } from '../../../scene/sceneContext';
|
||||
import { useProductContext } from '../../products/productContext';
|
||||
import { useHumanEventManager } from '../../human/eventManager/useHumanEventManager';
|
||||
|
||||
export function useTriggerHandler() {
|
||||
const { materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore, productStore } = useSceneContext();
|
||||
const { materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, humanStore, storageUnitStore, productStore } = useSceneContext();
|
||||
const { selectedProductStore } = useProductContext();
|
||||
const { handleAction } = useActionHandler();
|
||||
const { selectedProduct } = selectedProductStore();
|
||||
@@ -19,7 +20,9 @@ export function useTriggerHandler() {
|
||||
const { addConveyorToMonitor } = useConveyorEventManager();
|
||||
const { addVehicleToMonitor } = useVehicleEventManager();
|
||||
const { addMachineToMonitor } = useMachineEventManager();
|
||||
const { addHumanToMonitor } = useHumanEventManager();
|
||||
const { getVehicleById } = vehicleStore();
|
||||
const { getHumanById } = humanStore();
|
||||
const { getMachineById } = machineStore();
|
||||
const { getStorageUnitById } = storageUnitStore();
|
||||
const { getMaterialById, setCurrentLocation, setNextLocation, setPreviousLocation, setIsPaused, setIsVisible, setEndTime } = materialStore();
|
||||
@@ -149,23 +152,51 @@ export function useTriggerHandler() {
|
||||
const model = getEventByModelUuid(selectedProduct.productUuid, action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid);
|
||||
|
||||
if (model?.type === 'vehicle') {
|
||||
const vehicle = getVehicleById(action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid);
|
||||
if (vehicle) {
|
||||
if (vehicle.isActive === false && vehicle.state === 'idle' && vehicle.isPicking && vehicle.currentLoad < vehicle.point.action.loadCapacity) {
|
||||
// Handle current action from vehicle
|
||||
setIsPaused(materialId, true);
|
||||
handleAction(action, materialId);
|
||||
|
||||
} else {
|
||||
|
||||
// Handle current action using Event Manager
|
||||
setIsPaused(materialId, true);
|
||||
|
||||
addVehicleToMonitor(vehicle.modelUuid,
|
||||
() => {
|
||||
const armBot = getArmBotById(trigger.triggeredAsset?.triggeredModel.modelUuid);
|
||||
if (armBot) {
|
||||
if (armBot.isActive === false && armBot.state === 'idle') {
|
||||
const vehicle = getVehicleById(action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid);
|
||||
if (vehicle) {
|
||||
if (vehicle.isActive === false && vehicle.state === 'idle' && vehicle.isPicking && vehicle.currentLoad < vehicle.point.action.loadCapacity) {
|
||||
// Handle current action from vehicle
|
||||
setIsPaused(materialId, true);
|
||||
handleAction(action, materialId);
|
||||
|
||||
} else {
|
||||
|
||||
// Handle current action using Event Manager
|
||||
setIsPaused(materialId, true);
|
||||
|
||||
addVehicleToMonitor(vehicle.modelUuid,
|
||||
() => {
|
||||
handleAction(action, materialId);
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
} else {
|
||||
setIsPaused(materialId, true);
|
||||
addArmBotToMonitor(armBot.modelUuid, () => {
|
||||
const vehicle = getVehicleById(action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid || '');
|
||||
if (vehicle) {
|
||||
if (vehicle.isActive === false && vehicle.state === 'idle' && vehicle.isPicking && vehicle.currentLoad < vehicle.point.action.loadCapacity) {
|
||||
// Handle current action from vehicle
|
||||
setIsPaused(materialId, true);
|
||||
handleAction(action, materialId);
|
||||
|
||||
} else {
|
||||
|
||||
// Handle current action using Event Manager
|
||||
setIsPaused(materialId, true);
|
||||
|
||||
addVehicleToMonitor(vehicle.modelUuid,
|
||||
() => {
|
||||
handleAction(action, materialId);
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
} else if (model?.type === 'machine') {
|
||||
@@ -191,26 +222,25 @@ export function useTriggerHandler() {
|
||||
}
|
||||
} else {
|
||||
setIsPaused(materialId, true);
|
||||
addArmBotToMonitor(armBot.modelUuid,
|
||||
() => {
|
||||
const machine = getMachineById(action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid || '');
|
||||
if (machine) {
|
||||
if (machine.isActive === false && machine.state === 'idle' && !machine.currentAction) {
|
||||
setIsPaused(materialId, true);
|
||||
handleAction(action, materialId);
|
||||
} else {
|
||||
addArmBotToMonitor(armBot.modelUuid, () => {
|
||||
const machine = getMachineById(action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid || '');
|
||||
if (machine) {
|
||||
if (machine.isActive === false && machine.state === 'idle' && !machine.currentAction) {
|
||||
setIsPaused(materialId, true);
|
||||
handleAction(action, materialId);
|
||||
} else {
|
||||
|
||||
// Handle current action using Event Manager
|
||||
setIsPaused(materialId, true);
|
||||
// Handle current action using Event Manager
|
||||
setIsPaused(materialId, true);
|
||||
|
||||
addMachineToMonitor(machine.modelUuid,
|
||||
() => {
|
||||
handleAction(action, materialId);
|
||||
}
|
||||
)
|
||||
}
|
||||
addMachineToMonitor(machine.modelUuid,
|
||||
() => {
|
||||
handleAction(action, materialId);
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -256,6 +286,242 @@ export function useTriggerHandler() {
|
||||
} else if (toEvent?.type === 'storageUnit') {
|
||||
// Transfer to Storage Unit
|
||||
|
||||
} else if (toEvent?.type === 'human') {
|
||||
// Transfer to Human
|
||||
if (materialId && trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint && trigger.triggeredAsset.triggeredAction) {
|
||||
const material = getMaterialById(materialId);
|
||||
if (material) {
|
||||
|
||||
// Handle current action of the material
|
||||
handleAction(action, materialId);
|
||||
|
||||
if (material.next) {
|
||||
const action = getActionByUuid(selectedProduct.productUuid, trigger.triggeredAsset.triggeredAction.actionUuid);
|
||||
const human = getHumanById(trigger.triggeredAsset?.triggeredModel.modelUuid);
|
||||
|
||||
setPreviousLocation(material.materialId, {
|
||||
modelUuid: material.current.modelUuid,
|
||||
pointUuid: material.current.pointUuid,
|
||||
actionUuid: material.current.actionUuid,
|
||||
})
|
||||
|
||||
setCurrentLocation(material.materialId, {
|
||||
modelUuid: material.next.modelUuid,
|
||||
pointUuid: material.next.pointUuid,
|
||||
actionUuid: trigger.triggeredAsset?.triggeredAction?.actionUuid,
|
||||
});
|
||||
|
||||
setNextLocation(material.materialId, null);
|
||||
|
||||
if (action) {
|
||||
|
||||
if (human) {
|
||||
if (action && action.triggers.length > 0 &&
|
||||
action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid &&
|
||||
action.triggers[0]?.triggeredAsset?.triggeredAction?.actionUuid &&
|
||||
action.triggers[0]?.triggeredAsset?.triggeredPoint?.pointUuid) {
|
||||
const model = getEventByModelUuid(selectedProduct.productUuid, action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid);
|
||||
|
||||
if (model?.type === 'vehicle') {
|
||||
const human = getHumanById(trigger.triggeredAsset?.triggeredModel.modelUuid);
|
||||
if (human) {
|
||||
if (human.isActive === false && human.state === 'idle') {
|
||||
const vehicle = getVehicleById(action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid);
|
||||
if (vehicle) {
|
||||
if (vehicle.isActive === false && vehicle.state === 'idle' && vehicle.isPicking && vehicle.currentLoad < vehicle.point.action.loadCapacity) {
|
||||
// Handle current action from vehicle
|
||||
setIsVisible(materialId, false);
|
||||
setIsPaused(materialId, true);
|
||||
handleAction(action, materialId);
|
||||
|
||||
} else {
|
||||
|
||||
// Handle current action using Event Manager
|
||||
setIsPaused(materialId, true);
|
||||
|
||||
addVehicleToMonitor(vehicle.modelUuid,
|
||||
() => {
|
||||
setIsVisible(materialId, false);
|
||||
handleAction(action, materialId);
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
setIsPaused(materialId, true);
|
||||
addHumanToMonitor(human.modelUuid, () => {
|
||||
const vehicle = getVehicleById(action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid || '');
|
||||
if (vehicle) {
|
||||
if (vehicle.isActive === false && vehicle.state === 'idle' && vehicle.isPicking && vehicle.currentLoad < vehicle.point.action.loadCapacity) {
|
||||
// Handle current action from vehicle
|
||||
setIsVisible(materialId, false);
|
||||
setIsPaused(materialId, true);
|
||||
handleAction(action, materialId);
|
||||
|
||||
} else {
|
||||
|
||||
// Handle current action using Event Manager
|
||||
setIsPaused(materialId, true);
|
||||
|
||||
addVehicleToMonitor(vehicle.modelUuid,
|
||||
() => {
|
||||
setIsVisible(materialId, false);
|
||||
handleAction(action, materialId);
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
} else if (model?.type === 'transfer') {
|
||||
const human = getHumanById(trigger.triggeredAsset?.triggeredModel.modelUuid);
|
||||
if (human) {
|
||||
if (human.isActive === false && human.state === 'idle') {
|
||||
const conveyor = getConveyorById(action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid);
|
||||
if (conveyor) {
|
||||
if (!conveyor.isPaused) {
|
||||
// Handle current action from vehicle
|
||||
setIsVisible(materialId, false);
|
||||
setIsPaused(materialId, true);
|
||||
handleAction(action, materialId);
|
||||
|
||||
} else {
|
||||
|
||||
// Handle current action using Event Manager
|
||||
setIsPaused(materialId, true);
|
||||
|
||||
addConveyorToMonitor(conveyor.modelUuid,
|
||||
() => {
|
||||
setIsVisible(materialId, false);
|
||||
handleAction(action, materialId);
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
setIsPaused(materialId, true);
|
||||
addHumanToMonitor(human.modelUuid, () => {
|
||||
const conveyor = getConveyorById(action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid || '');
|
||||
if (conveyor) {
|
||||
if (!conveyor.isPaused) {
|
||||
// Handle current action from vehicle
|
||||
setIsVisible(materialId, false);
|
||||
setIsPaused(materialId, true);
|
||||
handleAction(action, materialId);
|
||||
|
||||
} else {
|
||||
|
||||
// Handle current action using Event Manager
|
||||
setIsPaused(materialId, true);
|
||||
|
||||
addConveyorToMonitor(conveyor.modelUuid,
|
||||
() => {
|
||||
setIsVisible(materialId, false);
|
||||
handleAction(action, materialId);
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
} else if (model?.type === 'machine') {
|
||||
const human = getHumanById(trigger.triggeredAsset?.triggeredModel.modelUuid);
|
||||
if (human) {
|
||||
if (human.isActive === false && human.state === 'idle') {
|
||||
const machine = getMachineById(action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid);
|
||||
if (machine) {
|
||||
if (machine.isActive === false && machine.state === 'idle' && !machine.currentAction) {
|
||||
setIsPaused(materialId, true);
|
||||
setIsVisible(materialId, false);
|
||||
handleAction(action, materialId);
|
||||
} else {
|
||||
|
||||
// Handle current action using Event Manager
|
||||
setIsPaused(materialId, true);
|
||||
|
||||
addMachineToMonitor(machine.modelUuid,
|
||||
() => {
|
||||
setIsVisible(materialId, false);
|
||||
handleAction(action, materialId);
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
setIsPaused(materialId, true);
|
||||
addHumanToMonitor(human.modelUuid, () => {
|
||||
const machine = getMachineById(action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid || '');
|
||||
if (machine) {
|
||||
if (machine.isActive === false && machine.state === 'idle' && !machine.currentAction) {
|
||||
setIsPaused(materialId, true);
|
||||
setIsVisible(materialId, false);
|
||||
handleAction(action, materialId);
|
||||
} else {
|
||||
|
||||
// Handle current action using Event Manager
|
||||
setIsPaused(materialId, true);
|
||||
|
||||
addMachineToMonitor(machine.modelUuid,
|
||||
() => {
|
||||
setIsVisible(materialId, false);
|
||||
handleAction(action, materialId);
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (human.isActive === false && human.state === 'idle') {
|
||||
|
||||
// Handle current action from arm bot
|
||||
setIsPaused(materialId, true);
|
||||
setIsVisible(materialId, false);
|
||||
handleAction(action, materialId);
|
||||
|
||||
} else {
|
||||
|
||||
// Handle current action using Event Manager
|
||||
setIsPaused(materialId, true);
|
||||
addHumanToMonitor(human.modelUuid,
|
||||
() => {
|
||||
setIsVisible(materialId, false);
|
||||
handleAction(action, materialId)
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (human.isActive === false && human.state === 'idle') {
|
||||
|
||||
// Handle current action from arm bot
|
||||
setIsPaused(materialId, true);
|
||||
setIsVisible(materialId, false);
|
||||
handleAction(action, materialId);
|
||||
|
||||
} else {
|
||||
|
||||
// Handle current action using Event Manager
|
||||
setIsPaused(materialId, true);
|
||||
addHumanToMonitor(human.modelUuid,
|
||||
() => {
|
||||
setIsVisible(materialId, false);
|
||||
handleAction(action, materialId)
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (fromEvent?.type === 'vehicle') {
|
||||
if (toEvent?.type === 'transfer') {
|
||||
@@ -322,18 +588,25 @@ export function useTriggerHandler() {
|
||||
|
||||
setNextLocation(material.materialId, null);
|
||||
|
||||
setIsVisible(materialId, false);
|
||||
|
||||
if (action && armBot) {
|
||||
|
||||
if (armBot.isActive === false && armBot.state === 'idle') {
|
||||
|
||||
// Handle current action from arm bot
|
||||
setIsVisible(materialId, false);
|
||||
|
||||
handleAction(action, materialId);
|
||||
|
||||
} else {
|
||||
|
||||
// Event Manager Needed
|
||||
addArmBotToMonitor(armBot.modelUuid,
|
||||
() => {
|
||||
setIsVisible(materialId, false);
|
||||
|
||||
handleAction(action, materialId);
|
||||
}
|
||||
)
|
||||
|
||||
}
|
||||
}
|
||||
@@ -379,6 +652,52 @@ export function useTriggerHandler() {
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (toEvent?.type === 'human') {
|
||||
// Vehicle to Human
|
||||
|
||||
if (materialId && trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint && trigger.triggeredAsset.triggeredAction) {
|
||||
const material = getMaterialById(materialId);
|
||||
if (material) {
|
||||
const action = getActionByUuid(selectedProduct.productUuid, trigger.triggeredAsset.triggeredAction.actionUuid);
|
||||
const human = getHumanById(trigger.triggeredAsset?.triggeredModel.modelUuid);
|
||||
|
||||
setPreviousLocation(material.materialId, {
|
||||
modelUuid: material.current.modelUuid,
|
||||
pointUuid: material.current.pointUuid,
|
||||
actionUuid: material.current.actionUuid,
|
||||
})
|
||||
|
||||
setCurrentLocation(material.materialId, {
|
||||
modelUuid: trigger.triggeredAsset.triggeredModel.modelUuid,
|
||||
pointUuid: trigger.triggeredAsset.triggeredPoint.pointUuid,
|
||||
actionUuid: trigger.triggeredAsset?.triggeredAction?.actionUuid,
|
||||
});
|
||||
|
||||
setNextLocation(material.materialId, null);
|
||||
|
||||
|
||||
if (action && human) {
|
||||
|
||||
if (human.isActive === false && human.state === 'idle') {
|
||||
|
||||
// Handle current action from arm bot
|
||||
setIsVisible(materialId, false);
|
||||
|
||||
handleAction(action, materialId);
|
||||
|
||||
} else {
|
||||
|
||||
addHumanToMonitor(human.modelUuid,
|
||||
() => {
|
||||
setIsVisible(materialId, false);
|
||||
|
||||
handleAction(action, materialId);
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (fromEvent?.type === 'machine') {
|
||||
if (toEvent?.type === 'transfer') {
|
||||
@@ -485,6 +804,135 @@ export function useTriggerHandler() {
|
||||
} else if (toEvent?.type === 'storageUnit') {
|
||||
// Machine to Storage Unit
|
||||
|
||||
} else if (toEvent?.type === 'human') {
|
||||
// Machine to Human
|
||||
if (materialId && trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint && trigger.triggeredAsset.triggeredAction) {
|
||||
const material = getMaterialById(materialId);
|
||||
|
||||
setIsPaused(materialId, true);
|
||||
|
||||
if (material) {
|
||||
const action = getActionByUuid(selectedProduct.productUuid, trigger.triggeredAsset.triggeredAction.actionUuid);
|
||||
const human = getHumanById(trigger.triggeredAsset?.triggeredModel.modelUuid);
|
||||
|
||||
setPreviousLocation(material.materialId, {
|
||||
modelUuid: material.current.modelUuid,
|
||||
pointUuid: material.current.pointUuid,
|
||||
actionUuid: material.current.actionUuid,
|
||||
})
|
||||
|
||||
setCurrentLocation(material.materialId, {
|
||||
modelUuid: material.current.modelUuid,
|
||||
pointUuid: trigger.triggeredAsset.triggeredPoint.pointUuid,
|
||||
actionUuid: trigger.triggeredAsset?.triggeredAction?.actionUuid,
|
||||
});
|
||||
|
||||
setNextLocation(material.materialId, null);
|
||||
|
||||
setIsVisible(materialId, false);
|
||||
|
||||
if (action && human) {
|
||||
|
||||
if (human.isActive === false && human.state === 'idle') {
|
||||
|
||||
// Handle current action from arm bot
|
||||
const model = getEventByModelUuid(selectedProduct.productUuid, action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid || '');
|
||||
if (model?.type === 'transfer') {
|
||||
const conveyor = getConveyorById(action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid || '');
|
||||
if (conveyor) {
|
||||
const previousModel = getEventByModelUuid(selectedProduct.productUuid, material.previous?.modelUuid || '');
|
||||
if (previousModel) {
|
||||
if (previousModel.type === 'transfer' && previousModel.modelUuid === model.modelUuid) {
|
||||
handleAction(action, materialId)
|
||||
} else {
|
||||
addConveyorToMonitor(conveyor.modelUuid,
|
||||
() => {
|
||||
handleAction(action, materialId)
|
||||
}
|
||||
)
|
||||
}
|
||||
} else {
|
||||
handleAction(action, materialId)
|
||||
}
|
||||
// handleAction(action, materialId)
|
||||
}
|
||||
} else if (model?.type === 'vehicle') {
|
||||
const vehicle = getVehicleById(action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid || '');
|
||||
if (vehicle) {
|
||||
if (vehicle.isActive === false && vehicle.state === 'idle' && vehicle.isPicking && vehicle.currentLoad < vehicle.point.action.loadCapacity) {
|
||||
// Handle current action from vehicle
|
||||
setIsPaused(materialId, true);
|
||||
handleAction(action, materialId);
|
||||
|
||||
} else {
|
||||
|
||||
// Handle current action using Event Manager
|
||||
setIsPaused(materialId, true);
|
||||
|
||||
addVehicleToMonitor(vehicle.modelUuid,
|
||||
() => {
|
||||
handleAction(action, materialId);
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
handleAction(action, materialId)
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// Handle current action using Event Manager
|
||||
|
||||
addHumanToMonitor(human.modelUuid, () => {
|
||||
const model = getEventByModelUuid(selectedProduct.productUuid, action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid || '');
|
||||
if (model?.type === 'transfer') {
|
||||
const conveyor = getConveyorById(action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid || '');
|
||||
if (conveyor) {
|
||||
const previousModel = getEventByModelUuid(selectedProduct.productUuid, material.previous?.modelUuid || '');
|
||||
if (previousModel) {
|
||||
if (previousModel.type === 'transfer' && previousModel.modelUuid === model.modelUuid) {
|
||||
handleAction(action, materialId)
|
||||
} else {
|
||||
addConveyorToMonitor(conveyor.modelUuid,
|
||||
() => {
|
||||
handleAction(action, materialId)
|
||||
}
|
||||
)
|
||||
}
|
||||
} else {
|
||||
handleAction(action, materialId)
|
||||
}
|
||||
}
|
||||
} else if (model?.type === 'vehicle') {
|
||||
const vehicle = getVehicleById(action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid || '');
|
||||
if (vehicle) {
|
||||
if (vehicle.isActive === false && vehicle.state === 'idle' && vehicle.isPicking && vehicle.currentLoad < vehicle.point.action.loadCapacity) {
|
||||
// Handle current action from vehicle
|
||||
setIsPaused(materialId, true);
|
||||
handleAction(action, materialId);
|
||||
|
||||
} else {
|
||||
|
||||
// Handle current action using Event Manager
|
||||
setIsPaused(materialId, true);
|
||||
|
||||
addVehicleToMonitor(vehicle.modelUuid,
|
||||
() => {
|
||||
handleAction(action, materialId);
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
handleAction(action, materialId)
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (fromEvent?.type === 'roboticArm') {
|
||||
if (toEvent?.type === 'transfer') {
|
||||
@@ -758,6 +1206,53 @@ export function useTriggerHandler() {
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (toEvent?.type === 'human') {
|
||||
// Robotic Arm to Human
|
||||
if (materialId && trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint && trigger.triggeredAsset.triggeredAction) {
|
||||
const material = getMaterialById(materialId);
|
||||
if (material) {
|
||||
|
||||
setIsPaused(material.materialId, false);
|
||||
|
||||
const action = getActionByUuid(selectedProduct.productUuid, trigger.triggeredAsset.triggeredAction.actionUuid);
|
||||
const human = getHumanById(trigger.triggeredAsset?.triggeredModel.modelUuid);
|
||||
|
||||
setNextLocation(material.materialId, null);
|
||||
|
||||
if (action) {
|
||||
|
||||
if (human) {
|
||||
|
||||
if (human.isActive === false && human.state === 'idle' && human.isPicking && human.currentLoad < human.point.action.loadCapacity) {
|
||||
|
||||
setIsVisible(materialId, false);
|
||||
|
||||
setPreviousLocation(material.materialId, {
|
||||
modelUuid: material.current.modelUuid,
|
||||
pointUuid: material.current.pointUuid,
|
||||
actionUuid: material.current.actionUuid,
|
||||
})
|
||||
|
||||
setCurrentLocation(material.materialId, {
|
||||
modelUuid: trigger.triggeredAsset.triggeredModel.modelUuid,
|
||||
pointUuid: trigger.triggeredAsset.triggeredPoint.pointUuid,
|
||||
actionUuid: trigger.triggeredAsset?.triggeredAction?.actionUuid,
|
||||
});
|
||||
|
||||
// Handle current action from human
|
||||
handleAction(action, materialId);
|
||||
|
||||
} else {
|
||||
|
||||
// Event Manager Needed
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} else if (fromEvent?.type === 'storageUnit') {
|
||||
if (toEvent?.type === 'transfer') {
|
||||
@@ -775,6 +1270,326 @@ export function useTriggerHandler() {
|
||||
} else if (toEvent?.type === 'storageUnit') {
|
||||
// Storage Unit to Storage Unit
|
||||
|
||||
} else if (toEvent?.type === 'human') {
|
||||
// Storage Unit to Human
|
||||
|
||||
}
|
||||
} else if (fromEvent?.type === 'human') {
|
||||
if (toEvent?.type === 'transfer') {
|
||||
// Human to Transfer
|
||||
|
||||
if (materialId && trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint && trigger.triggeredAsset.triggeredAction) {
|
||||
const material = getMaterialById(materialId);
|
||||
if (material) {
|
||||
|
||||
setPreviousLocation(material.materialId, {
|
||||
modelUuid: material.current.modelUuid,
|
||||
pointUuid: material.current.pointUuid,
|
||||
actionUuid: material.current.actionUuid,
|
||||
})
|
||||
|
||||
setCurrentLocation(material.materialId, {
|
||||
modelUuid: trigger.triggeredAsset.triggeredModel.modelUuid,
|
||||
pointUuid: trigger.triggeredAsset.triggeredPoint.pointUuid,
|
||||
actionUuid: trigger.triggeredAsset?.triggeredAction?.actionUuid,
|
||||
});
|
||||
|
||||
const action = getActionByUuid(selectedProduct.productUuid, trigger.triggeredAsset.triggeredAction.actionUuid);
|
||||
|
||||
if (action && action.triggers.length > 0 &&
|
||||
action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid &&
|
||||
action.triggers[0]?.triggeredAsset?.triggeredAction?.actionUuid &&
|
||||
action.triggers[0]?.triggeredAsset?.triggeredPoint?.pointUuid) {
|
||||
const model = getEventByModelUuid(selectedProduct.productUuid, action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid);
|
||||
|
||||
if (model?.type === 'roboticArm') {
|
||||
|
||||
handleAction(action, material.materialId);
|
||||
|
||||
} else if (model?.type === 'vehicle') {
|
||||
const nextAction = getActionByUuid(selectedProduct.productUuid, action.triggers[0]?.triggeredAsset?.triggeredAction.actionUuid);
|
||||
|
||||
if (action) {
|
||||
handleAction(action, material.materialId);
|
||||
|
||||
const vehicle = getVehicleById(action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid);
|
||||
|
||||
setPreviousLocation(material.materialId, {
|
||||
modelUuid: material.current.modelUuid,
|
||||
pointUuid: material.current.pointUuid,
|
||||
actionUuid: material.current.actionUuid,
|
||||
})
|
||||
|
||||
setCurrentLocation(material.materialId, {
|
||||
modelUuid: trigger.triggeredAsset?.triggeredModel.modelUuid,
|
||||
pointUuid: trigger.triggeredAsset?.triggeredPoint?.pointUuid,
|
||||
actionUuid: trigger.triggeredAsset?.triggeredAction?.actionUuid,
|
||||
});
|
||||
|
||||
setNextLocation(material.materialId, null);
|
||||
|
||||
if (nextAction) {
|
||||
|
||||
if (vehicle) {
|
||||
|
||||
if (vehicle.isActive === false && vehicle.state === 'idle' && vehicle.isPicking && vehicle.currentLoad < vehicle.point.action.loadCapacity) {
|
||||
|
||||
setPreviousLocation(material.materialId, {
|
||||
modelUuid: material.current.modelUuid,
|
||||
pointUuid: material.current.pointUuid,
|
||||
actionUuid: material.current.actionUuid,
|
||||
})
|
||||
|
||||
setCurrentLocation(material.materialId, {
|
||||
modelUuid: action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid || '',
|
||||
pointUuid: action.triggers[0]?.triggeredAsset?.triggeredPoint?.pointUuid || '',
|
||||
actionUuid: action.triggers[0]?.triggeredAsset?.triggeredAction?.actionUuid || '',
|
||||
});
|
||||
|
||||
setNextLocation(material.materialId, null);
|
||||
|
||||
setIsVisible(materialId, false);
|
||||
setIsPaused(materialId, false);
|
||||
|
||||
// Handle current action from vehicle
|
||||
handleAction(nextAction, materialId);
|
||||
|
||||
} else {
|
||||
|
||||
// Handle current action using Event Manager
|
||||
setIsPaused(materialId, true);
|
||||
|
||||
addVehicleToMonitor(vehicle.modelUuid,
|
||||
() => {
|
||||
setPreviousLocation(material.materialId, {
|
||||
modelUuid: material.current.modelUuid,
|
||||
pointUuid: material.current.pointUuid,
|
||||
actionUuid: material.current.actionUuid,
|
||||
})
|
||||
|
||||
setCurrentLocation(material.materialId, {
|
||||
modelUuid: action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid || '',
|
||||
pointUuid: action.triggers[0]?.triggeredAsset?.triggeredPoint?.pointUuid || '',
|
||||
actionUuid: action.triggers[0]?.triggeredAsset?.triggeredAction?.actionUuid || '',
|
||||
});
|
||||
|
||||
setNextLocation(material.materialId, null);
|
||||
|
||||
setIsPaused(materialId, false);
|
||||
setIsVisible(materialId, false);
|
||||
handleAction(nextAction, materialId);
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else if (model?.type === 'transfer') {
|
||||
const conveyor = getConveyorById(action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid);
|
||||
if (conveyor) {
|
||||
setNextLocation(material.materialId, {
|
||||
modelUuid: action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid,
|
||||
pointUuid: action.triggers[0]?.triggeredAsset?.triggeredPoint?.pointUuid,
|
||||
})
|
||||
setIsPaused(material.materialId, false);
|
||||
setIsVisible(material.materialId, true);
|
||||
handleAction(action, material.materialId);
|
||||
}
|
||||
} else {
|
||||
setNextLocation(material.materialId, {
|
||||
modelUuid: action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid,
|
||||
pointUuid: action.triggers[0]?.triggeredAsset?.triggeredPoint?.pointUuid,
|
||||
})
|
||||
|
||||
handleAction(action, material.materialId);
|
||||
}
|
||||
} else if (action) {
|
||||
setNextLocation(material.materialId, null)
|
||||
|
||||
handleAction(action, material.materialId);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
} else if (toEvent?.type === 'vehicle') {
|
||||
// Human to Vehicle
|
||||
|
||||
if (materialId && trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint && trigger.triggeredAsset.triggeredAction) {
|
||||
const material = getMaterialById(materialId);
|
||||
if (material) {
|
||||
|
||||
setIsPaused(material.materialId, false);
|
||||
|
||||
const action = getActionByUuid(selectedProduct.productUuid, trigger.triggeredAsset.triggeredAction.actionUuid);
|
||||
const vehicle = getVehicleById(trigger.triggeredAsset?.triggeredModel.modelUuid);
|
||||
|
||||
setNextLocation(material.materialId, null);
|
||||
|
||||
if (action) {
|
||||
|
||||
if (vehicle) {
|
||||
|
||||
if (vehicle.isActive === false && vehicle.state === 'idle' && vehicle.isPicking && vehicle.currentLoad < vehicle.point.action.loadCapacity) {
|
||||
|
||||
setIsVisible(materialId, false);
|
||||
|
||||
setPreviousLocation(material.materialId, {
|
||||
modelUuid: material.current.modelUuid,
|
||||
pointUuid: material.current.pointUuid,
|
||||
actionUuid: material.current.actionUuid,
|
||||
})
|
||||
|
||||
setCurrentLocation(material.materialId, {
|
||||
modelUuid: trigger.triggeredAsset.triggeredModel.modelUuid,
|
||||
pointUuid: trigger.triggeredAsset.triggeredPoint.pointUuid,
|
||||
actionUuid: trigger.triggeredAsset?.triggeredAction?.actionUuid,
|
||||
});
|
||||
|
||||
// Handle current action from vehicle
|
||||
handleAction(action, materialId);
|
||||
|
||||
} else {
|
||||
|
||||
// Event Manager Needed
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
} else if (toEvent?.type === 'machine') {
|
||||
// Human to Machine
|
||||
|
||||
if (materialId && trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint && trigger.triggeredAsset.triggeredAction) {
|
||||
const material = getMaterialById(materialId);
|
||||
if (material) {
|
||||
|
||||
// setIsPaused(material.materialId, false);
|
||||
|
||||
const action = getActionByUuid(selectedProduct.productUuid, trigger.triggeredAsset.triggeredAction.actionUuid);
|
||||
const machine = getMachineById(trigger.triggeredAsset?.triggeredModel.modelUuid);
|
||||
setNextLocation(material.materialId, null);
|
||||
|
||||
if (action) {
|
||||
|
||||
if (machine) {
|
||||
|
||||
if (machine.isActive === false && machine.state === 'idle') {
|
||||
|
||||
setIsVisible(materialId, false);
|
||||
|
||||
setPreviousLocation(material.materialId, {
|
||||
modelUuid: material.current.modelUuid,
|
||||
pointUuid: material.current.pointUuid,
|
||||
actionUuid: material.current.actionUuid,
|
||||
})
|
||||
|
||||
setCurrentLocation(material.materialId, {
|
||||
modelUuid: material.current.modelUuid,
|
||||
pointUuid: trigger.triggeredAsset.triggeredPoint.pointUuid,
|
||||
actionUuid: trigger.triggeredAsset?.triggeredAction?.actionUuid,
|
||||
});
|
||||
|
||||
// Handle current action from machine
|
||||
handleAction(action, materialId);
|
||||
|
||||
} else {
|
||||
|
||||
// Event Manager Needed
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (toEvent?.type === 'roboticArm') {
|
||||
// Human to Robotic Arm
|
||||
|
||||
if (materialId && trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint && trigger.triggeredAsset.triggeredAction) {
|
||||
const material = getMaterialById(materialId);
|
||||
if (material) {
|
||||
const action = getActionByUuid(selectedProduct.productUuid, trigger.triggeredAsset.triggeredAction.actionUuid);
|
||||
const armBot = getArmBotById(trigger.triggeredAsset?.triggeredModel.modelUuid);
|
||||
|
||||
setPreviousLocation(material.materialId, {
|
||||
modelUuid: material.current.modelUuid,
|
||||
pointUuid: material.current.pointUuid,
|
||||
actionUuid: material.current.actionUuid,
|
||||
})
|
||||
|
||||
setCurrentLocation(material.materialId, {
|
||||
modelUuid: trigger.triggeredAsset.triggeredModel.modelUuid,
|
||||
pointUuid: trigger.triggeredAsset.triggeredPoint.pointUuid,
|
||||
actionUuid: trigger.triggeredAsset?.triggeredAction?.actionUuid,
|
||||
});
|
||||
|
||||
setNextLocation(material.materialId, null);
|
||||
|
||||
setIsVisible(materialId, false);
|
||||
|
||||
if (action && armBot) {
|
||||
|
||||
if (armBot.isActive === false && armBot.state === 'idle') {
|
||||
|
||||
// Handle current action from arm bot
|
||||
handleAction(action, materialId);
|
||||
|
||||
} else {
|
||||
|
||||
// Event Manager Needed
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else if (toEvent?.type === 'storageUnit') {
|
||||
// Human to Storage Unit
|
||||
|
||||
if (materialId && trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint && trigger.triggeredAsset.triggeredAction) {
|
||||
const material = getMaterialById(materialId);
|
||||
if (material) {
|
||||
const action = getActionByUuid(selectedProduct.productUuid, trigger.triggeredAsset.triggeredAction.actionUuid);
|
||||
const storageUnit = getStorageUnitById(trigger.triggeredAsset?.triggeredModel.modelUuid);
|
||||
|
||||
setPreviousLocation(material.materialId, {
|
||||
modelUuid: material.current.modelUuid,
|
||||
pointUuid: material.current.pointUuid,
|
||||
actionUuid: material.current.actionUuid,
|
||||
})
|
||||
|
||||
setCurrentLocation(material.materialId, {
|
||||
modelUuid: trigger.triggeredAsset.triggeredModel.modelUuid,
|
||||
pointUuid: trigger.triggeredAsset.triggeredPoint.pointUuid,
|
||||
actionUuid: trigger.triggeredAsset?.triggeredAction?.actionUuid,
|
||||
});
|
||||
|
||||
setNextLocation(material.materialId, null);
|
||||
|
||||
setIsVisible(materialId, false);
|
||||
|
||||
if (action && storageUnit) {
|
||||
|
||||
if (storageUnit.currentLoad < storageUnit.point.action.storageCapacity) {
|
||||
|
||||
// Handle current action from vehicle
|
||||
handleAction(action, materialId);
|
||||
|
||||
} else {
|
||||
|
||||
// Event Manager Needed
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (toEvent?.type === 'human') {
|
||||
// Human to Human
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,12 +3,7 @@ import { useThree, useFrame } from '@react-three/fiber';
|
||||
import * as THREE from 'three';
|
||||
import { MaterialModel } from '../../../materials/instances/material/materialModel';
|
||||
|
||||
type MaterialAnimatorProps = {
|
||||
agvDetail: VehicleStatus;
|
||||
};
|
||||
|
||||
|
||||
const MaterialAnimator = ({ agvDetail }: MaterialAnimatorProps) => {
|
||||
const MaterialAnimator = ({ agvDetail }: { agvDetail: VehicleStatus }) => {
|
||||
const meshRef = useRef<any>(null!);
|
||||
const [hasLoad, setHasLoad] = useState(false);
|
||||
const { scene } = useThree();
|
||||
|
||||
@@ -32,7 +32,6 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai
|
||||
|
||||
useEffect(() => {
|
||||
if (currentPhase === 'stationed-pickup' && path.length > 0) {
|
||||
// console.log('path: ', path);
|
||||
setCurrentPath(path);
|
||||
setObjectRotation(agvDetail.point.action?.pickUpPoint?.rotation)
|
||||
} else if (currentPhase === 'pickup-drop' && path.length > 0) {
|
||||
@@ -66,84 +65,6 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai
|
||||
}
|
||||
}, [isReset, isPlaying])
|
||||
|
||||
// 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(() => {
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import VehicleAnimator from '../animator/vehicleAnimator';
|
||||
import * as THREE from 'three';
|
||||
import { NavMeshQuery } from '@recast-navigation/core';
|
||||
import { useNavMesh } from '../../../../../store/builder/store';
|
||||
import { useAnimationPlaySpeed, usePauseButtonStore, usePlayButtonStore } from '../../../../../store/usePlayButtonStore';
|
||||
import { useTriggerHandler } from '../../../triggers/triggerHandler/useTriggerHandler';
|
||||
import MaterialAnimator from '../animator/materialAnimator';
|
||||
import { useSceneContext } from '../../../../scene/sceneContext';
|
||||
import { useProductContext } from '../../../products/productContext';
|
||||
|
||||
import MaterialAnimator from '../animator/materialAnimator';
|
||||
import VehicleAnimator from '../animator/vehicleAnimator';
|
||||
|
||||
function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>) {
|
||||
const { navMesh } = useNavMesh();
|
||||
const { isPlaying } = usePlayButtonStore();
|
||||
const { materialStore, armBotStore, conveyorStore, vehicleStore, storageUnitStore, productStore } = useSceneContext();
|
||||
const { materialStore, armBotStore, conveyorStore, vehicleStore, storageUnitStore, humanStore, productStore } = useSceneContext();
|
||||
const { removeMaterial, setEndTime } = materialStore();
|
||||
const { getStorageUnitById } = storageUnitStore();
|
||||
const { getHumanById } = humanStore();
|
||||
const { getArmBotById } = armBotStore();
|
||||
const { getConveyorById } = conveyorStore();
|
||||
const { triggerPointActions } = useTriggerHandler();
|
||||
@@ -150,7 +152,6 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [vehicles, currentPhase, path, isPlaying]);
|
||||
|
||||
|
||||
function animate(currentTime: number) {
|
||||
if (previousTimeRef.current === null) {
|
||||
previousTimeRef.current = currentTime;
|
||||
@@ -197,7 +198,6 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
|
||||
};
|
||||
}, [agvDetail, isPlaying]);
|
||||
|
||||
|
||||
function handleCallBack() {
|
||||
if (currentPhase === 'stationed-pickup') {
|
||||
setCurrentPhase('picking');
|
||||
@@ -247,6 +247,11 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
|
||||
if (action) {
|
||||
handleMaterialDropToStorageUnit(model);
|
||||
}
|
||||
} else if (model.type === 'human') {
|
||||
const action = getActionByUuid(selectedProduct.productUuid, agvDetail.point.action.actionUuid);
|
||||
if (action) {
|
||||
handleMaterialDropToHuman(model);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const droppedMaterial = agvDetail.currentLoad;
|
||||
@@ -260,6 +265,79 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
|
||||
}
|
||||
}
|
||||
|
||||
function handleMaterialDropToHuman(model: HumanEventSchema) {
|
||||
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
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function loopMaterialDropToHuman(
|
||||
vehicleId: string,
|
||||
vehicleCurrentLoad: number,
|
||||
unLoadDuration: number,
|
||||
humanId: string,
|
||||
storageMaxCapacity: number,
|
||||
action: VehicleAction
|
||||
) {
|
||||
startTime = performance.now();
|
||||
const fixedInterval = ((unLoadDuration / vehicleCurrentLoad) * (1000 / isSpeedRef.current));
|
||||
|
||||
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);
|
||||
|
||||
if (elapsedTime >= fixedInterval) {
|
||||
if (human && agvDetail &&
|
||||
human.currentLoad < storageMaxCapacity &&
|
||||
vehicleCurrentLoad > 0) {
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
requestAnimationFrame(unloadLoop);
|
||||
}
|
||||
};
|
||||
|
||||
const human = getHumanById(humanId);
|
||||
if (human && vehicleCurrentLoad > 0 && human?.currentLoad < storageMaxCapacity) {
|
||||
unloadLoop();
|
||||
}
|
||||
}
|
||||
|
||||
function handleMaterialDropToStorageUnit(model: StorageEventSchema) {
|
||||
if (model) {
|
||||
if (model.point.action.actionType === 'store') {
|
||||
@@ -527,10 +605,4 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
|
||||
);
|
||||
}
|
||||
|
||||
export default VehicleInstance;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
export default VehicleInstance;
|
||||
Reference in New Issue
Block a user