Merge remote-tracking branch 'origin/v2' into v2-ui
This commit is contained in:
commit
520cd5f581
|
@ -549,7 +549,7 @@ const ZoneGroup: React.FC = () => {
|
||||||
const midpoint = new THREE.Vector3(
|
const midpoint = new THREE.Vector3(
|
||||||
(point1.x + point2.x) / 2,
|
(point1.x + point2.x) / 2,
|
||||||
CONSTANTS.zoneConfig.height / 2 +
|
CONSTANTS.zoneConfig.height / 2 +
|
||||||
(zone.layer - 1) * CONSTANTS.zoneConfig.height,
|
(zone.layer - 1) * CONSTANTS.zoneConfig.height,
|
||||||
(point1.z + point2.z) / 2
|
(point1.z + point2.z) / 2
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
import { useCallback } from "react";
|
||||||
|
import { useMaterialStore } from "../../../../../store/simulation/useMaterialStore";
|
||||||
|
|
||||||
|
export function useDefaultHandler() {
|
||||||
|
const { getMaterialById } = useMaterialStore();
|
||||||
|
|
||||||
|
const defaultLogStatus = (materialUuid: string, status: string) => {
|
||||||
|
// console.log(`${materialUuid}, ${status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDefault = useCallback((action: ConveyorAction, materialId?: string) => {
|
||||||
|
if (!action || action.actionType !== 'default' || !materialId) return;
|
||||||
|
|
||||||
|
const material = getMaterialById(materialId);
|
||||||
|
if (!material) return;
|
||||||
|
|
||||||
|
defaultLogStatus(material.materialId, `performed Default action`);
|
||||||
|
|
||||||
|
}, [getMaterialById]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
handleDefault,
|
||||||
|
};
|
||||||
|
}
|
|
@ -2,7 +2,7 @@ import { useCallback } from "react";
|
||||||
import { useMaterialStore } from "../../../../../store/simulation/useMaterialStore";
|
import { useMaterialStore } from "../../../../../store/simulation/useMaterialStore";
|
||||||
|
|
||||||
export function useDespawnHandler() {
|
export function useDespawnHandler() {
|
||||||
const { addMaterial, getMaterialById, removeMaterial } = useMaterialStore();
|
const { getMaterialById, removeMaterial } = useMaterialStore();
|
||||||
|
|
||||||
const deSpawnLogStatus = (materialUuid: string, status: string) => {
|
const deSpawnLogStatus = (materialUuid: string, status: string) => {
|
||||||
// console.log(`${materialUuid}, ${status}`);
|
// console.log(`${materialUuid}, ${status}`);
|
||||||
|
@ -18,7 +18,7 @@ export function useDespawnHandler() {
|
||||||
|
|
||||||
deSpawnLogStatus(material.materialId, `Despawned`);
|
deSpawnLogStatus(material.materialId, `Despawned`);
|
||||||
|
|
||||||
}, [addMaterial, getMaterialById, removeMaterial]);
|
}, [getMaterialById, removeMaterial]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
handleDespawn,
|
handleDespawn,
|
||||||
|
|
|
@ -1,17 +1,20 @@
|
||||||
import { useEffect, useCallback } from "react";
|
import { useEffect, useCallback } from "react";
|
||||||
|
import { useDefaultHandler } from "./actionHandler/useDefaultHandler";
|
||||||
import { useSpawnHandler } from "./actionHandler/useSpawnHandler";
|
import { useSpawnHandler } from "./actionHandler/useSpawnHandler";
|
||||||
import { useSwapHandler } from "./actionHandler/useSwapHandler";
|
import { useSwapHandler } from "./actionHandler/useSwapHandler";
|
||||||
import { useDelayHandler } from "./actionHandler/useDelayHandler";
|
import { useDelayHandler } from "./actionHandler/useDelayHandler";
|
||||||
import { useDespawnHandler } from "./actionHandler/useDespawnHandler";
|
import { useDespawnHandler } from "./actionHandler/useDespawnHandler";
|
||||||
|
|
||||||
export function useConveyorActions() {
|
export function useConveyorActions() {
|
||||||
|
const { handleDefault } = useDefaultHandler();
|
||||||
const { handleSpawn, clearCurrentSpawn } = useSpawnHandler();
|
const { handleSpawn, clearCurrentSpawn } = useSpawnHandler();
|
||||||
const { handleSwap } = useSwapHandler();
|
const { handleSwap } = useSwapHandler();
|
||||||
const { handleDespawn } = useDespawnHandler();
|
const { handleDespawn } = useDespawnHandler();
|
||||||
const { handleDelay, cleanupDelay } = useDelayHandler();
|
const { handleDelay, cleanupDelay } = useDelayHandler();
|
||||||
|
|
||||||
const handleDefaultAction = useCallback((action: ConveyorAction) => {
|
const handleDefaultAction = useCallback((action: ConveyorAction, materialId?: string) => {
|
||||||
}, []);
|
handleDefault(action, materialId);
|
||||||
|
}, [handleDefault]);
|
||||||
|
|
||||||
const handleSpawnAction = useCallback((action: ConveyorAction) => {
|
const handleSpawnAction = useCallback((action: ConveyorAction) => {
|
||||||
handleSpawn(action);
|
handleSpawn(action);
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
import { useCallback } from "react";
|
||||||
|
import { useMaterialStore } from "../../../../../store/simulation/useMaterialStore";
|
||||||
|
import { useArmBotStore } from "../../../../../store/simulation/useArmBotStore";
|
||||||
|
import { useProductStore } from "../../../../../store/simulation/useProductStore";
|
||||||
|
import { useSelectedProduct } from "../../../../../store/simulation/useSimulationStore";
|
||||||
|
|
||||||
|
export function usePickAndPlaceHandler() {
|
||||||
|
const { getMaterialById } = useMaterialStore();
|
||||||
|
const { addCurrentAction } = useArmBotStore();
|
||||||
|
const { getModelUuidByActionUuid } = useProductStore();
|
||||||
|
const { selectedProduct } = useSelectedProduct();
|
||||||
|
|
||||||
|
const pickAndPlaceLogStatus = (materialUuid: string, status: string) => {
|
||||||
|
// console.log(`${materialUuid}, ${status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const handlePickAndPlace = useCallback((action: RoboticArmAction, materialId?: string) => {
|
||||||
|
if (!action || action.actionType !== 'pickAndPlace' || !materialId) return;
|
||||||
|
|
||||||
|
const material = getMaterialById(materialId);
|
||||||
|
if (!material) return;
|
||||||
|
|
||||||
|
const modelUuid = getModelUuidByActionUuid(selectedProduct.productId, action.actionUuid);
|
||||||
|
|
||||||
|
if (!modelUuid) return;
|
||||||
|
|
||||||
|
addCurrentAction(
|
||||||
|
modelUuid,
|
||||||
|
action.actionUuid,
|
||||||
|
material.materialType,
|
||||||
|
material.materialId
|
||||||
|
);
|
||||||
|
|
||||||
|
pickAndPlaceLogStatus(material.materialId, `if going to be picked by armBot ${modelUuid}`);
|
||||||
|
|
||||||
|
}, [getMaterialById, getModelUuidByActionUuid, addCurrentAction]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
handlePickAndPlace,
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,20 +1,24 @@
|
||||||
import { useEffect, useCallback } from 'react';
|
import { useEffect, useCallback } from 'react';
|
||||||
|
import { usePickAndPlaceHandler } from './actionHandler/usePickAndPlaceHandler';
|
||||||
|
|
||||||
export function useRoboticArmActions() {
|
export function useRoboticArmActions() {
|
||||||
|
const { handlePickAndPlace } = usePickAndPlaceHandler();
|
||||||
|
|
||||||
const handlePickAndPlace = useCallback((action: RoboticArmAction) => {
|
const handlePickAndPlaceAction = useCallback((action: RoboticArmAction, materialId: string) => {
|
||||||
console.log(`Robotic arm pick and place`);
|
handlePickAndPlace(action, materialId);
|
||||||
}, []);
|
}, [handlePickAndPlace]);
|
||||||
|
|
||||||
|
const handleRoboticArmAction = useCallback((action: RoboticArmAction, materialId: string) => {
|
||||||
|
if (!action) return;
|
||||||
|
|
||||||
const handleRoboticArmAction = useCallback((action: RoboticArmAction) => {
|
|
||||||
switch (action.actionType) {
|
switch (action.actionType) {
|
||||||
case 'pickAndPlace':
|
case 'pickAndPlace':
|
||||||
handlePickAndPlace(action);
|
handlePickAndPlaceAction(action, materialId);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
console.warn(`Unknown robotic arm action type: ${action.actionType}`);
|
console.warn(`Unknown robotic arm action type: ${action.actionType}`);
|
||||||
}
|
}
|
||||||
}, [handlePickAndPlace]);
|
}, [handlePickAndPlaceAction]);
|
||||||
|
|
||||||
const cleanup = useCallback(() => {
|
const cleanup = useCallback(() => {
|
||||||
}, []);
|
}, []);
|
||||||
|
|
|
@ -23,36 +23,26 @@ export function useActionHandler() {
|
||||||
const handleAction = useCallback(
|
const handleAction = useCallback(
|
||||||
(action: Action, materialId?: string) => {
|
(action: Action, materialId?: string) => {
|
||||||
if (!action) return;
|
if (!action) return;
|
||||||
|
try {
|
||||||
try {
|
switch (action.actionType) {
|
||||||
switch (action.actionType) {
|
case 'default': case 'spawn': case 'swap': case 'delay': case 'despawn':
|
||||||
case "default":
|
handleConveyorAction(action as ConveyorAction, materialId as string);
|
||||||
case "spawn":
|
break;
|
||||||
case "swap":
|
case 'travel':
|
||||||
case "delay":
|
handleVehicleAction(action as VehicleAction, materialId as string);
|
||||||
case "despawn":
|
break;
|
||||||
handleConveyorAction(
|
case 'pickAndPlace':
|
||||||
action as ConveyorAction,
|
handleRoboticArmAction(action as RoboticArmAction, materialId as string);
|
||||||
materialId as string
|
break;
|
||||||
);
|
case 'process':
|
||||||
break;
|
handleMachineAction(action as MachineAction);
|
||||||
case "travel":
|
break;
|
||||||
handleVehicleAction(action as VehicleAction);
|
case 'store':
|
||||||
break;
|
handleStorageAction(action as StorageAction);
|
||||||
case "pickAndPlace":
|
break;
|
||||||
handleRoboticArmAction(action as RoboticArmAction);
|
default:
|
||||||
break;
|
console.warn(`Unknown action type: ${(action as Action).actionType}`);
|
||||||
case "process":
|
}
|
||||||
handleMachineAction(action as MachineAction);
|
|
||||||
break;
|
|
||||||
case "store":
|
|
||||||
handleStorageAction(action as StorageAction);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
console.warn(
|
|
||||||
`Unknown action type: ${(action as Action).actionType}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
echo.error("Failed to handle action");
|
echo.error("Failed to handle action");
|
||||||
console.error("Error handling action:", error);
|
console.error("Error handling action:", error);
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
import { useCallback } from "react";
|
||||||
|
import { useMaterialStore } from "../../../../../store/simulation/useMaterialStore";
|
||||||
|
import { useProductStore } from "../../../../../store/simulation/useProductStore";
|
||||||
|
import { useSelectedProduct } from "../../../../../store/simulation/useSimulationStore";
|
||||||
|
import { useVehicleStore } from "../../../../../store/simulation/useVehicleStore";
|
||||||
|
|
||||||
|
export function useTravelHandler() {
|
||||||
|
const { getMaterialById } = useMaterialStore();
|
||||||
|
const { getModelUuidByActionUuid } = useProductStore();
|
||||||
|
const { selectedProduct } = useSelectedProduct();
|
||||||
|
const { incrementVehicleLoad, addCurrentMaterial } = useVehicleStore();
|
||||||
|
|
||||||
|
const travelLogStatus = (materialUuid: string, status: string) => {
|
||||||
|
// console.log(`${materialUuid}, ${status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleTravel = useCallback((action: VehicleAction, materialId?: string) => {
|
||||||
|
if (!action || action.actionType !== 'travel' || !materialId) return;
|
||||||
|
|
||||||
|
const material = getMaterialById(materialId);
|
||||||
|
if (!material) return;
|
||||||
|
|
||||||
|
const modelUuid = getModelUuidByActionUuid(selectedProduct.productId, action.actionUuid);
|
||||||
|
|
||||||
|
if (!modelUuid) return;
|
||||||
|
|
||||||
|
incrementVehicleLoad(modelUuid, 1);
|
||||||
|
addCurrentMaterial(modelUuid, material.materialType, material.materialId);
|
||||||
|
|
||||||
|
travelLogStatus(material.materialId, `is triggering travel from ${modelUuid}`);
|
||||||
|
|
||||||
|
}, [getMaterialById, getModelUuidByActionUuid]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
handleTravel,
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,20 +1,19 @@
|
||||||
import { useEffect, useCallback } from 'react';
|
import { useEffect, useCallback } from 'react';
|
||||||
|
import { useTravelHandler } from './actionHandler/useTravelHandler';
|
||||||
|
|
||||||
export function useVehicleActions() {
|
export function useVehicleActions() {
|
||||||
|
const { handleTravel } = useTravelHandler();
|
||||||
|
|
||||||
const handleTravelAction = useCallback((action: VehicleAction) => {
|
const handleTravelAction = useCallback((action: VehicleAction, materialId: string) => {
|
||||||
if (!action || action.actionType !== 'travel') return;
|
handleTravel(action, materialId);
|
||||||
|
}, [handleTravel]);
|
||||||
|
|
||||||
console.log(`Vehicle travel action ${action.actionUuid}`);
|
const handleVehicleAction = useCallback((action: VehicleAction, materialId: string) => {
|
||||||
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const handleVehicleAction = useCallback((action: VehicleAction) => {
|
|
||||||
if (!action) return;
|
if (!action) return;
|
||||||
|
|
||||||
switch (action.actionType) {
|
switch (action.actionType) {
|
||||||
case 'travel':
|
case 'travel':
|
||||||
handleTravelAction(action);
|
handleTravelAction(action, materialId);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
console.warn(`Unknown vehicle action type: ${action.actionType}`);
|
console.warn(`Unknown vehicle action type: ${action.actionType}`);
|
||||||
|
|
|
@ -85,37 +85,10 @@ function MaterialInstance({ material }: { material: MaterialSchema }) {
|
||||||
|
|
||||||
const callTrigger = () => {
|
const callTrigger = () => {
|
||||||
if (!material.next) return;
|
if (!material.next) return;
|
||||||
const fromModel = getEventByModelUuid(selectedProduct.productId, material.next.modelUuid);
|
const action = getActionByPointUuid(selectedProduct.productId, material.next.pointUuid);
|
||||||
if (!fromModel) return;
|
if (action) {
|
||||||
const fromPoint = getPointByUuid(selectedProduct.productId, fromModel.modelUuid, material.next.pointUuid);
|
triggerPointActions(action, material.materialId);
|
||||||
if (!fromPoint) return;
|
|
||||||
|
|
||||||
if (fromModel.type === 'transfer') {
|
|
||||||
const toModel = getEventByModelUuid(selectedProduct.productId, material.next.modelUuid);
|
|
||||||
if (!toModel) return;
|
|
||||||
if (toModel.type === 'transfer') {
|
|
||||||
const action = getActionByPointUuid(selectedProduct.productId, material.next.pointUuid);
|
|
||||||
if (action) {
|
|
||||||
triggerPointActions(action, material.materialId);
|
|
||||||
}
|
|
||||||
} else if (toModel?.type === 'vehicle') {
|
|
||||||
// Transfer to Vehicle
|
|
||||||
|
|
||||||
} else if (toModel?.type === 'machine') {
|
|
||||||
// Transfer to Machine
|
|
||||||
|
|
||||||
} else if (toModel?.type === 'roboticArm') {
|
|
||||||
// Transfer to Robotic Arm
|
|
||||||
|
|
||||||
} else if (toModel?.type === 'storageUnit') {
|
|
||||||
// Transfer to Storage Unit
|
|
||||||
}
|
|
||||||
} else if (fromModel.type === 'vehicle') {
|
|
||||||
} else if (fromModel.type === 'machine') {
|
|
||||||
} else if (fromModel.type === 'roboticArm') {
|
|
||||||
} else if (fromModel.type === 'storageUnit') {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -50,7 +50,7 @@ function TriggerConnector() {
|
||||||
organization: string,
|
organization: string,
|
||||||
eventData: EventsSchema
|
eventData: EventsSchema
|
||||||
) => {
|
) => {
|
||||||
upsertProductOrEventApi({
|
const data =upsertProductOrEventApi({
|
||||||
productName: productName,
|
productName: productName,
|
||||||
productId: productId,
|
productId: productId,
|
||||||
organization: organization,
|
organization: organization,
|
||||||
|
|
|
@ -4,13 +4,15 @@ import { useProductStore } from '../../../../store/simulation/useProductStore';
|
||||||
import { useSelectedProduct } from '../../../../store/simulation/useSimulationStore';
|
import { useSelectedProduct } from '../../../../store/simulation/useSimulationStore';
|
||||||
import { useMaterialStore } from '../../../../store/simulation/useMaterialStore';
|
import { useMaterialStore } from '../../../../store/simulation/useMaterialStore';
|
||||||
import { useArmBotStore } from '../../../../store/simulation/useArmBotStore';
|
import { useArmBotStore } from '../../../../store/simulation/useArmBotStore';
|
||||||
|
import { useVehicleStore } from '../../../../store/simulation/useVehicleStore';
|
||||||
|
|
||||||
export function useTriggerHandler() {
|
export function useTriggerHandler() {
|
||||||
const { handleAction } = useActionHandler();
|
const { handleAction } = useActionHandler();
|
||||||
const { selectedProduct } = useSelectedProduct();
|
const { selectedProduct } = useSelectedProduct();
|
||||||
const { getEventByTriggerUuid, getEventByModelUuid, getActionByUuid, getModelUuidByActionUuid } = useProductStore();
|
const { getEventByTriggerUuid, getEventByModelUuid, getActionByUuid, getModelUuidByActionUuid } = useProductStore();
|
||||||
const { addCurrentAction, getArmBotById } = useArmBotStore();
|
const { getArmBotById } = useArmBotStore();
|
||||||
const { setCurrentLocation, setNextLocation, getMaterialById, setIsPaused, setEndTime } = useMaterialStore();
|
const { getVehicleById } = useVehicleStore();
|
||||||
|
const { setCurrentLocation, setNextLocation, getMaterialById, setIsPaused, setIsVisible, setEndTime } = useMaterialStore();
|
||||||
|
|
||||||
const handleTrigger = (trigger: TriggerSchema, action: Action, materialId: string) => {
|
const handleTrigger = (trigger: TriggerSchema, action: Action, materialId: string) => {
|
||||||
|
|
||||||
|
@ -42,6 +44,46 @@ export function useTriggerHandler() {
|
||||||
}
|
}
|
||||||
} else if (toEvent?.type === 'vehicle') {
|
} else if (toEvent?.type === 'vehicle') {
|
||||||
// Transfer to Vehicle
|
// Transfer to Vehicle
|
||||||
|
if (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.productId, trigger.triggeredAsset.triggeredAction.actionUuid);
|
||||||
|
const vehicle = getVehicleById(trigger.triggeredAsset?.triggeredModel.modelUuid);
|
||||||
|
|
||||||
|
setCurrentLocation(material.materialId, {
|
||||||
|
modelUuid: material.next.modelUuid,
|
||||||
|
pointUuid: material.next.pointUuid,
|
||||||
|
actionUuid: trigger.triggeredAsset?.triggeredAction?.actionUuid,
|
||||||
|
});
|
||||||
|
|
||||||
|
setNextLocation(material.materialId, null);
|
||||||
|
|
||||||
|
if (action) {
|
||||||
|
|
||||||
|
if (vehicle) {
|
||||||
|
|
||||||
|
if (vehicle.isActive === false && vehicle.state === 'idle' && vehicle.currentLoad < vehicle.point.action.loadCapacity) {
|
||||||
|
|
||||||
|
setIsVisible(materialId, false);
|
||||||
|
|
||||||
|
// Handle current action from vehicle
|
||||||
|
handleAction(action, materialId);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Event Manager Needed
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} else if (toEvent?.type === 'machine') {
|
} else if (toEvent?.type === 'machine') {
|
||||||
// Transfer to Machine
|
// Transfer to Machine
|
||||||
|
@ -51,33 +93,41 @@ export function useTriggerHandler() {
|
||||||
if (trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint && trigger.triggeredAsset.triggeredAction) {
|
if (trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint && trigger.triggeredAsset.triggeredAction) {
|
||||||
const material = getMaterialById(materialId);
|
const material = getMaterialById(materialId);
|
||||||
if (material) {
|
if (material) {
|
||||||
|
|
||||||
|
// Handle current action of the material
|
||||||
|
handleAction(action, materialId);
|
||||||
|
|
||||||
if (material.next) {
|
if (material.next) {
|
||||||
|
const action = getActionByUuid(selectedProduct.productId, trigger.triggeredAsset.triggeredAction.actionUuid);
|
||||||
const armBot = getArmBotById(trigger.triggeredAsset?.triggeredModel.modelUuid);
|
const armBot = getArmBotById(trigger.triggeredAsset?.triggeredModel.modelUuid);
|
||||||
if (armBot) {
|
|
||||||
if (armBot.isActive === false && armBot.state === 'idle') {
|
|
||||||
setCurrentLocation(material.materialId, {
|
|
||||||
modelUuid: material.next.modelUuid,
|
|
||||||
pointUuid: material.next.pointUuid,
|
|
||||||
actionUuid: trigger.triggeredAsset?.triggeredAction?.actionUuid,
|
|
||||||
});
|
|
||||||
|
|
||||||
setNextLocation(material.materialId, null);
|
setCurrentLocation(material.materialId, {
|
||||||
|
modelUuid: material.next.modelUuid,
|
||||||
|
pointUuid: material.next.pointUuid,
|
||||||
|
actionUuid: trigger.triggeredAsset?.triggeredAction?.actionUuid,
|
||||||
|
});
|
||||||
|
|
||||||
setIsPaused(material.materialId, true);
|
setNextLocation(material.materialId, null);
|
||||||
addCurrentAction(
|
|
||||||
trigger.triggeredAsset?.triggeredModel.modelUuid,
|
|
||||||
trigger.triggeredAsset?.triggeredAction?.actionUuid,
|
|
||||||
material.materialType,
|
|
||||||
material.materialId
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
|
|
||||||
// Event Manager Needed
|
if (action) {
|
||||||
|
|
||||||
|
if (armBot) {
|
||||||
|
|
||||||
|
if (armBot.isActive === false && armBot.state === 'idle') {
|
||||||
|
|
||||||
|
setIsPaused(material.materialId, true);
|
||||||
|
|
||||||
|
// Handle current action from arm bot
|
||||||
|
handleAction(action, materialId);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Event Manager Needed
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
handleAction(action, materialId);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (toEvent?.type === 'storageUnit') {
|
} else if (toEvent?.type === 'storageUnit') {
|
||||||
|
@ -149,6 +199,41 @@ export function useTriggerHandler() {
|
||||||
|
|
||||||
} else if (toEvent?.type === 'vehicle') {
|
} else if (toEvent?.type === 'vehicle') {
|
||||||
// Robotic Arm to Vehicle
|
// Robotic Arm to Vehicle
|
||||||
|
if (trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint && trigger.triggeredAsset.triggeredAction) {
|
||||||
|
const material = getMaterialById(materialId);
|
||||||
|
if (material) {
|
||||||
|
const action = getActionByUuid(selectedProduct.productId, trigger.triggeredAsset.triggeredAction.actionUuid);
|
||||||
|
const vehicle = getVehicleById(trigger.triggeredAsset?.triggeredModel.modelUuid);
|
||||||
|
|
||||||
|
setCurrentLocation(material.materialId, {
|
||||||
|
modelUuid: trigger.triggeredAsset.triggeredModel.modelUuid,
|
||||||
|
pointUuid: trigger.triggeredAsset.triggeredPoint.pointUuid,
|
||||||
|
actionUuid: trigger.triggeredAsset?.triggeredAction?.actionUuid,
|
||||||
|
});
|
||||||
|
|
||||||
|
setNextLocation(material.materialId, null);
|
||||||
|
|
||||||
|
if (action) {
|
||||||
|
|
||||||
|
if (vehicle) {
|
||||||
|
|
||||||
|
if (vehicle.isActive === false && vehicle.state === 'idle' && vehicle.currentLoad < vehicle.point.action.loadCapacity) {
|
||||||
|
|
||||||
|
setIsVisible(materialId, false);
|
||||||
|
|
||||||
|
// Handle current action from vehicle
|
||||||
|
handleAction(action, materialId);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Event Manager Needed
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} else if (toEvent?.type === 'machine') {
|
} else if (toEvent?.type === 'machine') {
|
||||||
// Robotic Arm to Machine
|
// Robotic Arm to Machine
|
||||||
|
|
|
@ -1,232 +1,372 @@
|
||||||
import React, { useEffect, useRef, useState } from 'react';
|
import React, { useEffect, useRef, useState } from "react";
|
||||||
import * as Types from "../../../../types/world/worldTypes";
|
import * as Types from "../../../../types/world/worldTypes";
|
||||||
import startPoint from "../../../../assets/gltf-glb/arrow_green.glb";
|
import startPoint from "../../../../assets/gltf-glb/arrow_green.glb";
|
||||||
import * as THREE from "three";
|
|
||||||
import startEnd from "../../../../assets/gltf-glb/arrow_red.glb";
|
import startEnd from "../../../../assets/gltf-glb/arrow_red.glb";
|
||||||
import { useGLTF } from '@react-three/drei';
|
import { useGLTF } from "@react-three/drei";
|
||||||
import { useFrame, useThree } from '@react-three/fiber';
|
import { useFrame, useThree } from "@react-three/fiber";
|
||||||
import { useSelectedEventSphere, useIsDragging, useIsRotating } from '../../../../store/simulation/useSimulationStore';
|
import {
|
||||||
import { useVehicleStore } from '../../../../store/simulation/useVehicleStore';
|
useSelectedEventSphere,
|
||||||
import { useProductStore } from '../../../../store/simulation/useProductStore';
|
useIsDragging,
|
||||||
import { useSelectedProduct } from '../../../../store/simulation/useSimulationStore';
|
useIsRotating,
|
||||||
import { upsertProductOrEventApi } from '../../../../services/simulation/UpsertProductOrEventApi';
|
} from "../../../../store/simulation/useSimulationStore";
|
||||||
|
import { useVehicleStore } from "../../../../store/simulation/useVehicleStore";
|
||||||
|
import { useProductStore } from "../../../../store/simulation/useProductStore";
|
||||||
|
import { useSelectedProduct } from "../../../../store/simulation/useSimulationStore";
|
||||||
|
import { upsertProductOrEventApi } from "../../../../services/simulation/UpsertProductOrEventApi";
|
||||||
|
import { Box3, DoubleSide, Euler, Group, Mesh, Plane, Quaternion, Vector3 } from "three";
|
||||||
|
import { position } from "html2canvas/dist/types/css/property-descriptors/position";
|
||||||
|
|
||||||
const VehicleUI = () => {
|
const VehicleUI = () => {
|
||||||
const { scene: startScene } = useGLTF(startPoint) as any;
|
const { scene: startScene } = useGLTF(startPoint) as any;
|
||||||
const { scene: endScene } = useGLTF(startEnd) as any;
|
const { scene: endScene } = useGLTF(startEnd) as any;
|
||||||
const startMarker = useRef<THREE.Group>(null);
|
const startMarker = useRef<Group>(null);
|
||||||
const endMarker = useRef<THREE.Group>(null);
|
const endMarker = useRef<Group>(null);
|
||||||
const prevMousePos = useRef({ x: 0, y: 0 });
|
const prevMousePos = useRef({ x: 0, y: 0 });
|
||||||
const { selectedEventSphere } = useSelectedEventSphere();
|
const { selectedEventSphere } = useSelectedEventSphere();
|
||||||
const { selectedProduct } = useSelectedProduct();
|
const { selectedProduct } = useSelectedProduct();
|
||||||
const { getVehicleById } = useVehicleStore();
|
const { getVehicleById } = useVehicleStore();
|
||||||
const { updateEvent } = useProductStore();
|
const { updateEvent } = useProductStore();
|
||||||
const [startPosition, setStartPosition] = useState<[number, number, number]>([0, 0, 0]);
|
const [startPosition, setStartPosition] = useState<[number, number, number]>([
|
||||||
const [endPosition, setEndPosition] = useState<[number, number, number]>([0, 0, 0]);
|
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 { raycaster } = useThree();
|
|
||||||
const plane = useRef(new THREE.Plane(new THREE.Vector3(0, 1, 0), 0));
|
|
||||||
const state: Types.ThreeState = useThree();
|
|
||||||
const controls: any = state.controls;
|
|
||||||
|
|
||||||
const email = localStorage.getItem('email')
|
|
||||||
const organization = (email!.split("@")[1]).split(".")[0];
|
|
||||||
|
|
||||||
const updateBackend = (
|
const [endPosition, setEndPosition] = useState<[number, number, number]>([
|
||||||
productName: string,
|
0, 1, 0,
|
||||||
productId: string,
|
]);
|
||||||
organization: string,
|
const [startRotation, setStartRotation] = useState<[number, number, number]>([
|
||||||
eventData: EventsSchema
|
0, 0, 0,
|
||||||
) => {
|
]);
|
||||||
upsertProductOrEventApi({
|
|
||||||
productName: productName,
|
|
||||||
productId: productId,
|
|
||||||
organization: organization,
|
|
||||||
eventDatas: eventData
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
const [endRotation, setEndRotation] = useState<[number, number, number]>([
|
||||||
if (!selectedEventSphere) return;
|
0, 0, 0,
|
||||||
const selectedVehicle = getVehicleById(selectedEventSphere.userData.modelUuid);
|
]);
|
||||||
|
const [steeringRotation, setSteeringRotation] = useState<
|
||||||
|
[number, number, number]
|
||||||
|
>([0, 0, 0]);
|
||||||
|
|
||||||
if (selectedVehicle?.point?.action) {
|
const { isDragging, setIsDragging } = useIsDragging();
|
||||||
const { pickUpPoint, unLoadPoint } = selectedVehicle.point.action;
|
const { isRotating, setIsRotating } = useIsRotating();
|
||||||
|
const { raycaster } = useThree();
|
||||||
|
const [point, setPoint] = useState<
|
||||||
|
[number, number, number]
|
||||||
|
>([0, 0, 0]);
|
||||||
|
const plane = useRef(new Plane(new Vector3(0, 1, 0), 0));
|
||||||
|
const [tubeRotation, setTubeRotation] = useState<boolean>(false);
|
||||||
|
const tubeRef = useRef<Group>(null);
|
||||||
|
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 CIRCLE_RADIUS = 0.8;
|
||||||
|
const email = localStorage.getItem("email");
|
||||||
|
const organization = email!.split("@")[1].split(".")[0];
|
||||||
|
|
||||||
if (pickUpPoint) {
|
const updateBackend = (
|
||||||
setStartPosition([pickUpPoint.position.x, 0, pickUpPoint.position.z]);
|
productName: string,
|
||||||
setStartRotation([pickUpPoint.rotation.x, pickUpPoint.rotation.y, pickUpPoint.rotation.z]);
|
productId: string,
|
||||||
|
organization: string,
|
||||||
|
eventData: EventsSchema
|
||||||
|
) => {
|
||||||
|
upsertProductOrEventApi({
|
||||||
|
productName: productName,
|
||||||
|
productId: productId,
|
||||||
|
organization: organization,
|
||||||
|
eventDatas: eventData,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!selectedEventSphere) return;
|
||||||
|
const selectedVehicle = getVehicleById(
|
||||||
|
selectedEventSphere.userData.modelUuid
|
||||||
|
);
|
||||||
|
|
||||||
|
if (selectedVehicle) {
|
||||||
|
setSelectedVechicleData({ position: selectedVehicle.position, rotation: selectedVehicle.rotation });
|
||||||
|
setPoint(selectedVehicle.point.position)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
if (selectedVehicle?.point?.action) {
|
||||||
|
const { pickUpPoint, unLoadPoint, steeringAngle } = selectedVehicle.point.action;
|
||||||
|
|
||||||
|
if (pickUpPoint && outerGroup.current) {
|
||||||
|
const worldPos = new Vector3(
|
||||||
|
pickUpPoint.position.x,
|
||||||
|
pickUpPoint.position.y,
|
||||||
|
pickUpPoint.position.z
|
||||||
|
);
|
||||||
|
const localPosition = outerGroup.current.worldToLocal(worldPos.clone());
|
||||||
|
|
||||||
|
|
||||||
|
setStartPosition([localPosition.x, selectedVehicle.point.position[1], localPosition.z,
|
||||||
|
]);
|
||||||
|
setStartRotation([pickUpPoint.rotation.x, pickUpPoint.rotation.y, pickUpPoint.rotation.z,])
|
||||||
} else {
|
} else {
|
||||||
const defaultLocal = new THREE.Vector3(0, 0, 1.5);
|
setStartPosition([0, selectedVehicle.point.position[1] + 0.1, 1.5]);
|
||||||
const defaultWorld = selectedEventSphere.localToWorld(defaultLocal);
|
setStartRotation([0, 0, 0]);
|
||||||
setStartPosition([defaultWorld.x, 0, defaultWorld.z]);
|
|
||||||
setStartRotation([0, 0, 0]);
|
|
||||||
}
|
}
|
||||||
|
// end point
|
||||||
|
if (unLoadPoint && outerGroup.current) {
|
||||||
|
const worldPos = new Vector3(unLoadPoint.position.x, unLoadPoint.position.y, unLoadPoint.position.z);
|
||||||
|
const localPosition = outerGroup.current.worldToLocal(worldPos);
|
||||||
|
|
||||||
if (unLoadPoint) {
|
setEndPosition([localPosition.x, selectedVehicle.point.position[1], localPosition.z]);
|
||||||
setEndPosition([unLoadPoint.position.x, 0, unLoadPoint.position.z]);
|
setEndRotation([unLoadPoint.rotation.x, unLoadPoint.rotation.y, unLoadPoint.rotation.z,
|
||||||
setEndRotation([unLoadPoint.rotation.x, unLoadPoint.rotation.y, unLoadPoint.rotation.z]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
const defaultLocal = new THREE.Vector3(0, 0, -1.5);
|
setEndPosition([0, selectedVehicle.point.position[1] + 0.1, -1.5]);
|
||||||
const defaultWorld = selectedEventSphere.localToWorld(defaultLocal);
|
setEndRotation([0, 0, 0]);
|
||||||
setEndPosition([defaultWorld.x, 0, defaultWorld.z]);
|
|
||||||
setEndRotation([0, 0, 0]);
|
|
||||||
}
|
}
|
||||||
}
|
setSteeringRotation([0, steeringAngle, 0])
|
||||||
}, [selectedEventSphere]);
|
}
|
||||||
|
}, 10);
|
||||||
useFrame(() => {
|
|
||||||
if (!isDragging) return;
|
|
||||||
const intersectPoint = new THREE.Vector3();
|
|
||||||
const intersects = raycaster.ray.intersectPlane(plane.current, intersectPoint);
|
|
||||||
|
|
||||||
if (intersects) {
|
|
||||||
if (isDragging === "start") {
|
|
||||||
setStartPosition([intersectPoint.x, 0, intersectPoint.z]);
|
|
||||||
}
|
|
||||||
if (isDragging === "end") {
|
|
||||||
setEndPosition([intersectPoint.x, 0, intersectPoint.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;
|
|
||||||
if (isRotating === 'start') {
|
|
||||||
const y = startRotation[1] + deltaX * rotationSpeed;
|
|
||||||
setStartRotation([0, y, 0]);
|
|
||||||
} else {
|
|
||||||
const y = endRotation[1] + deltaX * rotationSpeed;
|
|
||||||
setEndRotation([0, y, 0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
const handlePointerDown = (e: any, state: "start" | "end", rotation: "start" | "end") => {
|
}, [selectedEventSphere, outerGroup.current]);
|
||||||
|
|
||||||
if (e.object.name === "handle") {
|
const handlePointerDown = (
|
||||||
const normalizedX = (e.clientX / window.innerWidth) * 2 - 1;
|
e: any,
|
||||||
const normalizedY = -(e.clientY / window.innerHeight) * 2 + 1;
|
state: "start" | "end",
|
||||||
prevMousePos.current = { x: normalizedX, y: normalizedY };
|
rotation: "start" | "end"
|
||||||
setIsRotating(rotation);
|
) => {
|
||||||
if (controls) controls.enabled = false;
|
if (e.object.name === "handle") {
|
||||||
setIsDragging(null);
|
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.enabled = false;
|
||||||
|
setIsDragging(null);
|
||||||
|
} else {
|
||||||
|
setIsDragging(state);
|
||||||
|
setIsRotating(null);
|
||||||
|
if (controls) controls.enabled = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} else {
|
const handlePointerUp = () => {
|
||||||
setIsDragging(state);
|
controls.enabled = true;
|
||||||
setIsRotating(null);
|
setIsDragging(null);
|
||||||
if (controls) controls.enabled = false;
|
setIsRotating(null);
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handlePointerUp = () => {
|
if (selectedEventSphere?.userData.modelUuid) {
|
||||||
controls.enabled = true;
|
const updatedVehicle = getVehicleById(
|
||||||
setIsDragging(null);
|
selectedEventSphere.userData.modelUuid
|
||||||
setIsRotating(null);
|
);
|
||||||
|
|
||||||
if (selectedEventSphere?.userData.modelUuid) {
|
let globalStartPosition = null;
|
||||||
const updatedVehicle = getVehicleById(selectedEventSphere.userData.modelUuid);
|
let globalEndPosition = null;
|
||||||
|
|
||||||
if (updatedVehicle) {
|
if (outerGroup.current && startMarker.current && endMarker.current) {
|
||||||
const event = updateEvent(selectedProduct.productId, selectedEventSphere.userData.modelUuid, {
|
const worldPosStart = new Vector3(...startPosition);
|
||||||
point: {
|
globalStartPosition = outerGroup.current.localToWorld(worldPosStart.clone());
|
||||||
...updatedVehicle.point,
|
const worldPosEnd = new Vector3(...endPosition);
|
||||||
action: {
|
globalEndPosition = outerGroup.current.localToWorld(worldPosEnd.clone());
|
||||||
...updatedVehicle.point?.action,
|
}
|
||||||
pickUpPoint: {
|
if (updatedVehicle && globalEndPosition && globalStartPosition) {
|
||||||
position: { x: startPosition[0], y: startPosition[1], z: startPosition[2], },
|
const event = updateEvent(
|
||||||
rotation: { x: 0, y: startRotation[1], z: 0, },
|
selectedProduct.productId,
|
||||||
},
|
selectedEventSphere.userData.modelUuid,
|
||||||
unLoadPoint: {
|
{
|
||||||
position: { x: endPosition[0], y: endPosition[1], z: endPosition[2], },
|
point: {
|
||||||
rotation: { x: 0, y: endRotation[1], z: 0, },
|
...updatedVehicle.point,
|
||||||
},
|
action: {
|
||||||
|
...updatedVehicle.point?.action,
|
||||||
|
pickUpPoint: {
|
||||||
|
position: {
|
||||||
|
x: globalStartPosition.x,
|
||||||
|
y: 0,
|
||||||
|
z: globalStartPosition.z,
|
||||||
|
},
|
||||||
|
rotation: { x: 0, y: startRotation[1], z: 0 },
|
||||||
},
|
},
|
||||||
},
|
unLoadPoint: {
|
||||||
})
|
position: {
|
||||||
|
x: globalEndPosition.x,
|
||||||
|
y: 0,
|
||||||
|
z: globalEndPosition.z,
|
||||||
|
},
|
||||||
|
rotation: { x: 0, y: endRotation[1], z: 0 },
|
||||||
|
},
|
||||||
|
steeringAngle: steeringRotation[1]
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
if (event) {
|
if (event) {
|
||||||
updateBackend(
|
updateBackend(
|
||||||
selectedProduct.productName,
|
selectedProduct.productName,
|
||||||
selectedProduct.productId,
|
selectedProduct.productId,
|
||||||
organization,
|
organization,
|
||||||
event
|
event
|
||||||
);
|
);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useFrame(() => {
|
||||||
const handleGlobalPointerUp = () => {
|
if (!isDragging || !plane.current || !raycaster || !outerGroup.current) return;
|
||||||
setIsDragging(null);
|
const intersectPoint = new Vector3();
|
||||||
setIsRotating(null);
|
const intersects = raycaster.ray.intersectPlane(plane.current, intersectPoint);
|
||||||
if (controls) controls.enabled = true;
|
if (!intersects) return;
|
||||||
handlePointerUp();
|
const localPoint = outerGroup?.current.worldToLocal(intersectPoint.clone());
|
||||||
};
|
if (isDragging === "start") {
|
||||||
|
if (startMarker.current) {
|
||||||
|
|
||||||
if (isDragging || isRotating) {
|
}
|
||||||
window.addEventListener("pointerup", handleGlobalPointerUp);
|
setStartPosition([localPoint.x, point[1], localPoint.z]);
|
||||||
}
|
} else if (isDragging === "end") {
|
||||||
|
setEndPosition([localPoint.x, point[1], localPoint.z]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return () => {
|
useEffect(() => {
|
||||||
window.removeEventListener("pointerup", handleGlobalPointerUp);
|
const handleGlobalPointerUp = () => {
|
||||||
};
|
setIsDragging(null);
|
||||||
}, [isDragging, isRotating, startPosition, startRotation, endPosition, endRotation]);
|
setIsRotating(null);
|
||||||
|
setTubeRotation(false);
|
||||||
|
if (controls) controls.enabled = true;
|
||||||
|
handlePointerUp();
|
||||||
|
|
||||||
return (
|
};
|
||||||
startPosition.length > 0 && endPosition.length > 0 ? (
|
|
||||||
<mesh>
|
if (isDragging || isRotating || tubeRotation) {
|
||||||
<primitive
|
window.addEventListener("pointerup", handleGlobalPointerUp);
|
||||||
name="start"
|
}
|
||||||
object={startScene}
|
|
||||||
ref={startMarker}
|
return () => {
|
||||||
position={startPosition}
|
window.removeEventListener("pointerup", handleGlobalPointerUp);
|
||||||
rotation={startRotation}
|
};
|
||||||
onPointerDown={(e: any) => {
|
}, [
|
||||||
e.stopPropagation();
|
isDragging, isRotating, startPosition, startRotation, endPosition, endRotation, tubeRotation, steeringRotation, outerGroup.current, tubeRef.current
|
||||||
handlePointerDown(e, "start", "start");
|
]);
|
||||||
}}
|
|
||||||
onPointerMissed={() => {
|
|
||||||
controls.enabled = true;
|
const prevSteeringY = useRef(0);
|
||||||
setIsDragging(null);
|
useFrame((state) => {
|
||||||
setIsRotating(null);
|
if (tubeRotation) {
|
||||||
}}
|
const currentPointerX = state.pointer.x;
|
||||||
/>
|
const deltaX = currentPointerX - prevMousePos.current.x;
|
||||||
|
prevMousePos.current.x = currentPointerX;
|
||||||
|
|
||||||
|
const marker = tubeRef.current;
|
||||||
|
if (marker) {
|
||||||
|
const rotationSpeed = 2;
|
||||||
|
marker.rotation.y += deltaX * rotationSpeed;
|
||||||
|
setSteeringRotation([marker.rotation.x, marker.rotation.y, marker.rotation.z]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
prevSteeringY.current = 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
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,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return selectedVehicleData ? (
|
||||||
|
<group position={selectedVehicleData.position} rotation={selectedVehicleData.rotation} ref={outerGroup}>
|
||||||
|
<group
|
||||||
|
position={[0, 0, 0]}
|
||||||
|
ref={tubeRef}
|
||||||
|
rotation={steeringRotation}
|
||||||
|
onPointerDown={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
setTubeRotation(true);
|
||||||
|
prevMousePos.current.x = e.pointer.x;
|
||||||
|
controls.enabled = false;
|
||||||
|
}}
|
||||||
|
onPointerMissed={() => {
|
||||||
|
controls.enabled = true;
|
||||||
|
setTubeRotation(false);
|
||||||
|
}}
|
||||||
|
onPointerUp={() => {
|
||||||
|
controls.enabled = true;
|
||||||
|
setTubeRotation(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
(
|
||||||
|
<mesh
|
||||||
|
position={[0, point[1], 0]}
|
||||||
|
rotation={[-Math.PI / 2, 0, 0]}
|
||||||
|
name="steering"
|
||||||
|
>
|
||||||
|
<ringGeometry args={[CIRCLE_RADIUS, CIRCLE_RADIUS + 0.2, 36]} />
|
||||||
|
<meshBasicMaterial color="yellow" side={DoubleSide} />
|
||||||
|
|
||||||
<primitive
|
|
||||||
name="end"
|
|
||||||
object={endScene}
|
|
||||||
ref={endMarker}
|
|
||||||
position={endPosition}
|
|
||||||
rotation={endRotation}
|
|
||||||
onPointerDown={(e: any) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
handlePointerDown(e, "end", "end");
|
|
||||||
}}
|
|
||||||
onPointerMissed={() => {
|
|
||||||
controls.enabled = true;
|
|
||||||
setIsDragging(null);
|
|
||||||
setIsRotating(null);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</mesh>
|
</mesh>
|
||||||
) : null
|
<mesh position={[0, point[1], CIRCLE_RADIUS + 0.24]} rotation={[Math.PI / 2, 0, 0]}>
|
||||||
);
|
<coneGeometry args={[0.1, 0.3, 12]} />
|
||||||
}
|
<meshBasicMaterial color="yellow" side={DoubleSide} />
|
||||||
|
</mesh>
|
||||||
|
)
|
||||||
|
</group>
|
||||||
|
|
||||||
|
{/* Start Marker */}
|
||||||
|
<primitive
|
||||||
|
name="startMarker"
|
||||||
|
object={startScene}
|
||||||
|
ref={startMarker}
|
||||||
|
position={startPosition}
|
||||||
|
rotation={startRotation}
|
||||||
|
onPointerDown={(e: any) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
handlePointerDown(e, "start", "start");
|
||||||
|
}}
|
||||||
|
onPointerMissed={() => {
|
||||||
|
controls.enabled = true;
|
||||||
|
setIsDragging(null);
|
||||||
|
setIsRotating(null);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* End Marker */}
|
||||||
|
<primitive
|
||||||
|
name="endMarker"
|
||||||
|
object={endScene}
|
||||||
|
ref={endMarker}
|
||||||
|
position={endPosition}
|
||||||
|
rotation={endRotation}
|
||||||
|
onPointerDown={(e: any) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
handlePointerDown(e, "end", "end");
|
||||||
|
}}
|
||||||
|
onPointerMissed={() => {
|
||||||
|
controls.enabled = true;
|
||||||
|
setIsDragging(null);
|
||||||
|
setIsRotating(null);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</group>
|
||||||
|
) : null;
|
||||||
|
};
|
||||||
export default VehicleUI;
|
export default VehicleUI;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -38,10 +38,12 @@ const MaterialAnimator = ({ agvDetail }: MaterialAnimatorProps) => {
|
||||||
<>
|
<>
|
||||||
{hasLoad && (
|
{hasLoad && (
|
||||||
<>
|
<>
|
||||||
<MaterialModel
|
{agvDetail.currentMaterials.length > 0 &&
|
||||||
matRef={meshRef}
|
<MaterialModel
|
||||||
materialType={agvDetail.materialType || 'Default material'}
|
matRef={meshRef}
|
||||||
/>
|
materialType={agvDetail.currentMaterials[0].materialType || 'Default material'}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
|
||||||
<Html
|
<Html
|
||||||
position={htmlPosition}
|
position={htmlPosition}
|
||||||
|
|
|
@ -9,13 +9,14 @@ interface VehicleAnimatorProps {
|
||||||
path: [number, number, number][];
|
path: [number, number, number][];
|
||||||
handleCallBack: () => void;
|
handleCallBack: () => void;
|
||||||
reset: () => void;
|
reset: () => void;
|
||||||
|
startUnloadingProcess: () => void;
|
||||||
currentPhase: string;
|
currentPhase: string;
|
||||||
agvUuid: string;
|
agvUuid: string;
|
||||||
agvDetail: VehicleStatus;
|
agvDetail: VehicleStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetail, reset }: VehicleAnimatorProps) {
|
function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetail, reset, startUnloadingProcess }: VehicleAnimatorProps) {
|
||||||
const { decrementVehicleLoad, getVehicleById } = useVehicleStore();
|
const { getVehicleById } = useVehicleStore();
|
||||||
const { isPaused } = usePauseButtonStore();
|
const { isPaused } = usePauseButtonStore();
|
||||||
const { isPlaying } = usePlayButtonStore();
|
const { isPlaying } = usePlayButtonStore();
|
||||||
const { speed } = useAnimationPlaySpeed();
|
const { speed } = useAnimationPlaySpeed();
|
||||||
|
@ -23,32 +24,25 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai
|
||||||
const progressRef = useRef<number>(0);
|
const progressRef = useRef<number>(0);
|
||||||
const movingForward = useRef<boolean>(true);
|
const movingForward = useRef<boolean>(true);
|
||||||
const completedRef = useRef<boolean>(false);
|
const completedRef = useRef<boolean>(false);
|
||||||
const isPausedRef = useRef<boolean>(false);
|
const [objectRotation, setObjectRotation] = useState<{ x: number; y: number; z: number } | undefined>(agvDetail.point?.action?.pickUpPoint?.rotation || { x: 0, y: 0, z: 0 })
|
||||||
const pauseTimeRef = useRef<number | null>(null);
|
|
||||||
const [progress, setProgress] = useState<number>(0);
|
|
||||||
const [restRotation, setRestingRotation] = useState<boolean>(true);
|
const [restRotation, setRestingRotation] = useState<boolean>(true);
|
||||||
const [currentPath, setCurrentPath] = useState<[number, number, number][]>([]);
|
const [currentPath, setCurrentPath] = useState<[number, number, number][]>([]);
|
||||||
const { scene } = useThree();
|
const { scene } = useThree();
|
||||||
let startTime: number;
|
|
||||||
let fixedInterval: number;
|
|
||||||
let coveredDistance = progressRef.current;
|
|
||||||
let objectRotation = (agvDetail.point?.action?.pickUpPoint?.rotation || { x: 0, y: 0, z: 0 }) as { x: number; y: number; z: number } | undefined;
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (currentPhase === 'stationed-pickup' && path.length > 0) {
|
if (currentPhase === 'stationed-pickup' && path.length > 0) {
|
||||||
setCurrentPath(path);
|
setCurrentPath(path);
|
||||||
objectRotation = agvDetail.point.action?.pickUpPoint?.rotation
|
setObjectRotation(agvDetail.point.action?.pickUpPoint?.rotation)
|
||||||
} else if (currentPhase === 'pickup-drop' && path.length > 0) {
|
} else if (currentPhase === 'pickup-drop' && path.length > 0) {
|
||||||
objectRotation = agvDetail.point.action?.unLoadPoint?.rotation
|
setObjectRotation(agvDetail.point.action?.unLoadPoint?.rotation)
|
||||||
setCurrentPath(path);
|
setCurrentPath(path);
|
||||||
} else if (currentPhase === 'drop-pickup' && path.length > 0) {
|
} else if (currentPhase === 'drop-pickup' && path.length > 0) {
|
||||||
objectRotation = agvDetail.point.action?.pickUpPoint?.rotation
|
setObjectRotation(agvDetail.point.action?.pickUpPoint?.rotation)
|
||||||
setCurrentPath(path);
|
setCurrentPath(path);
|
||||||
}
|
}
|
||||||
}, [currentPhase, path]);
|
}, [currentPhase, path, objectRotation]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setProgress(0);
|
|
||||||
completedRef.current = false;
|
completedRef.current = false;
|
||||||
}, [currentPath]);
|
}, [currentPath]);
|
||||||
|
|
||||||
|
@ -56,17 +50,11 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai
|
||||||
if (isReset || !isPlaying) {
|
if (isReset || !isPlaying) {
|
||||||
reset();
|
reset();
|
||||||
setCurrentPath([]);
|
setCurrentPath([]);
|
||||||
setProgress(0);
|
|
||||||
completedRef.current = false;
|
completedRef.current = false;
|
||||||
movingForward.current = true;
|
movingForward.current = true;
|
||||||
progressRef.current = 0;
|
progressRef.current = 0;
|
||||||
startTime = 0;
|
|
||||||
coveredDistance = 0;
|
|
||||||
setReset(false);
|
setReset(false);
|
||||||
setRestingRotation(true);
|
setRestingRotation(true);
|
||||||
decrementVehicleLoad(agvDetail.modelUuid, 0);
|
|
||||||
isPausedRef.current = false;
|
|
||||||
pauseTimeRef.current = 0;
|
|
||||||
const object = scene.getObjectByProperty('uuid', agvUuid);
|
const object = scene.getObjectByProperty('uuid', agvUuid);
|
||||||
const vehicle = getVehicleById(agvDetail.modelUuid);
|
const vehicle = getVehicleById(agvDetail.modelUuid);
|
||||||
if (object && vehicle) {
|
if (object && vehicle) {
|
||||||
|
@ -76,10 +64,6 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai
|
||||||
}
|
}
|
||||||
}, [isReset, isPlaying])
|
}, [isReset, isPlaying])
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
isPausedRef.current = isPaused;
|
|
||||||
}, [isPaused]);
|
|
||||||
|
|
||||||
useFrame((_, delta) => {
|
useFrame((_, delta) => {
|
||||||
const object = scene.getObjectByProperty('uuid', agvUuid);
|
const object = scene.getObjectByProperty('uuid', agvUuid);
|
||||||
if (!object || currentPath.length < 2) return;
|
if (!object || currentPath.length < 2) return;
|
||||||
|
@ -98,7 +82,7 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai
|
||||||
totalDistance += segmentDistance;
|
totalDistance += segmentDistance;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (index < distances.length && coveredDistance > accumulatedDistance + distances[index]) {
|
while (index < distances.length && progressRef.current > accumulatedDistance + distances[index]) {
|
||||||
accumulatedDistance += distances[index];
|
accumulatedDistance += distances[index];
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
|
@ -124,9 +108,7 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai
|
||||||
|
|
||||||
if (isAligned) {
|
if (isAligned) {
|
||||||
progressRef.current += delta * (speed * agvDetail.speed);
|
progressRef.current += delta * (speed * agvDetail.speed);
|
||||||
coveredDistance = progressRef.current;
|
const t = (progressRef.current - accumulatedDistance) / segmentDistance;
|
||||||
|
|
||||||
const t = (coveredDistance - accumulatedDistance) / segmentDistance;
|
|
||||||
const position = start.clone().lerp(end, t);
|
const position = start.clone().lerp(end, t);
|
||||||
object.position.copy(position);
|
object.position.copy(position);
|
||||||
}
|
}
|
||||||
|
@ -134,17 +116,21 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai
|
||||||
|
|
||||||
if (progressRef.current >= totalDistance) {
|
if (progressRef.current >= totalDistance) {
|
||||||
if (restRotation && objectRotation) {
|
if (restRotation && objectRotation) {
|
||||||
const targetQuaternion = new THREE.Quaternion().setFromEuler(new THREE.Euler(objectRotation.x, objectRotation.y, objectRotation.z));
|
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 * 2);
|
object.quaternion.slerp(targetQuaternion, delta * 2);
|
||||||
const angleDiff = object.quaternion.angleTo(targetQuaternion);
|
if (object.quaternion.angleTo(targetQuaternion) < 0.01) {
|
||||||
if (angleDiff < 0.01) {
|
object.quaternion.copy(targetQuaternion);
|
||||||
object.rotation.set(objectRotation.x, objectRotation.y, objectRotation.z);
|
object.rotation.copy(targetEuler);
|
||||||
setRestingRotation(false);
|
setRestingRotation(false);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (progressRef.current >= totalDistance) {
|
if (progressRef.current >= totalDistance) {
|
||||||
setRestingRotation(true);
|
setRestingRotation(true);
|
||||||
progressRef.current = 0;
|
progressRef.current = 0;
|
||||||
|
@ -152,54 +138,15 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai
|
||||||
setCurrentPath([]);
|
setCurrentPath([]);
|
||||||
handleCallBack();
|
handleCallBack();
|
||||||
if (currentPhase === 'pickup-drop') {
|
if (currentPhase === 'pickup-drop') {
|
||||||
requestAnimationFrame(firstFrame);
|
requestAnimationFrame(startUnloadingProcess);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function firstFrame() {
|
|
||||||
const droppedMaterial = agvDetail.currentLoad;
|
|
||||||
startTime = performance.now();
|
|
||||||
step(droppedMaterial);
|
|
||||||
}
|
|
||||||
|
|
||||||
function step(droppedMaterial: number) {
|
|
||||||
if (isPausedRef.current) {
|
|
||||||
if (!pauseTimeRef.current) {
|
|
||||||
pauseTimeRef.current = performance.now();
|
|
||||||
}
|
|
||||||
requestAnimationFrame(() => step(droppedMaterial));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pauseTimeRef.current) {
|
|
||||||
const pauseDuration = performance.now() - pauseTimeRef.current;
|
|
||||||
startTime += pauseDuration;
|
|
||||||
pauseTimeRef.current = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const elapsedTime = performance.now() - startTime;
|
|
||||||
const unLoadDuration = agvDetail.point.action.unLoadDuration;
|
|
||||||
fixedInterval = ((unLoadDuration / agvDetail.currentLoad) * (1000 / speed));
|
|
||||||
|
|
||||||
if (elapsedTime >= fixedInterval) {
|
|
||||||
let droppedMat = droppedMaterial - 1;
|
|
||||||
decrementVehicleLoad(agvDetail.modelUuid, 1);
|
|
||||||
if (droppedMat > 0) {
|
|
||||||
startTime = performance.now();
|
|
||||||
requestAnimationFrame(() => step(droppedMat));
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
requestAnimationFrame(() => step(droppedMaterial));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{currentPath.length > 0 && (
|
{currentPath.length > 0 && (
|
||||||
<group visible={false}>
|
<group >
|
||||||
<Line points={currentPath} color="blue" lineWidth={3} />
|
<Line points={currentPath} color="blue" lineWidth={3} />
|
||||||
{currentPath.map((point, index) => (
|
{currentPath.map((point, index) => (
|
||||||
<mesh key={index} position={point}>
|
<mesh key={index} position={point}>
|
||||||
|
|
|
@ -3,18 +3,28 @@ import VehicleAnimator from '../animator/vehicleAnimator';
|
||||||
import * as THREE from 'three';
|
import * as THREE from 'three';
|
||||||
import { NavMeshQuery } from '@recast-navigation/core';
|
import { NavMeshQuery } from '@recast-navigation/core';
|
||||||
import { useNavMesh } from '../../../../../store/store';
|
import { useNavMesh } from '../../../../../store/store';
|
||||||
import { usePlayButtonStore } from '../../../../../store/usePlayButtonStore';
|
import { useAnimationPlaySpeed, usePauseButtonStore, usePlayButtonStore } from '../../../../../store/usePlayButtonStore';
|
||||||
import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore';
|
import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore';
|
||||||
|
import { useMaterialStore } from '../../../../../store/simulation/useMaterialStore';
|
||||||
import MaterialAnimator from '../animator/materialAnimator';
|
import MaterialAnimator from '../animator/materialAnimator';
|
||||||
|
|
||||||
function VehicleInstance({ agvDetail }: { agvDetail: VehicleStatus }) {
|
function VehicleInstance({ agvDetail }: { agvDetail: VehicleStatus }) {
|
||||||
const { navMesh } = useNavMesh();
|
const { navMesh } = useNavMesh();
|
||||||
const vehicleRef: any = useRef();
|
|
||||||
const { isPlaying } = usePlayButtonStore();
|
const { isPlaying } = usePlayButtonStore();
|
||||||
const { vehicles, setVehicleActive, setVehicleState, incrementVehicleLoad, setMaterialType } = useVehicleStore();
|
const { removeMaterial } = useMaterialStore();
|
||||||
|
const { vehicles, setVehicleActive, setVehicleState, clearCurrentMaterials, setVehicleLoad, decrementVehicleLoad, removeLastMaterial } = useVehicleStore();
|
||||||
const [currentPhase, setCurrentPhase] = useState<string>('stationed');
|
const [currentPhase, setCurrentPhase] = useState<string>('stationed');
|
||||||
const [path, setPath] = useState<[number, number, number][]>([]);
|
const [path, setPath] = useState<[number, number, number][]>([]);
|
||||||
let isIncrememtable = useRef<boolean>(true);
|
const pauseTimeRef = useRef<number | null>(null);
|
||||||
|
const isPausedRef = useRef<boolean>(false);
|
||||||
|
let startTime: number;
|
||||||
|
let fixedInterval: number;
|
||||||
|
const { speed } = useAnimationPlaySpeed();
|
||||||
|
const { isPaused } = usePauseButtonStore();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
isPausedRef.current = isPaused;
|
||||||
|
}, [isPaused]);
|
||||||
|
|
||||||
const computePath = useCallback(
|
const computePath = useCallback(
|
||||||
(start: any, end: any) => {
|
(start: any, end: any) => {
|
||||||
|
@ -34,7 +44,6 @@ function VehicleInstance({ agvDetail }: { agvDetail: VehicleStatus }) {
|
||||||
|
|
||||||
function vehicleStatus(modelId: string, status: string) {
|
function vehicleStatus(modelId: string, status: string) {
|
||||||
// console.log(`${modelId} , ${status}`);
|
// console.log(`${modelId} , ${status}`);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to reset everything
|
// Function to reset everything
|
||||||
|
@ -42,19 +51,16 @@ function VehicleInstance({ agvDetail }: { agvDetail: VehicleStatus }) {
|
||||||
setCurrentPhase('stationed');
|
setCurrentPhase('stationed');
|
||||||
setVehicleActive(agvDetail.modelUuid, false);
|
setVehicleActive(agvDetail.modelUuid, false);
|
||||||
setVehicleState(agvDetail.modelUuid, 'idle');
|
setVehicleState(agvDetail.modelUuid, 'idle');
|
||||||
|
setVehicleLoad(agvDetail.modelUuid, 0);
|
||||||
setPath([]);
|
setPath([]);
|
||||||
}
|
startTime = 0;
|
||||||
|
isPausedRef.current = false;
|
||||||
const increment = () => {
|
pauseTimeRef.current = 0;
|
||||||
if (isIncrememtable.current) {
|
|
||||||
incrementVehicleLoad(agvDetail.modelUuid, 10);
|
|
||||||
setMaterialType(agvDetail.modelUuid, 'Material 1')
|
|
||||||
isIncrememtable.current = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isPlaying) {
|
if (isPlaying) {
|
||||||
|
if (!agvDetail.point.action.unLoadPoint || !agvDetail.point.action.pickUpPoint) return;
|
||||||
|
|
||||||
if (!agvDetail.isActive && agvDetail.state === 'idle' && currentPhase === 'stationed') {
|
if (!agvDetail.isActive && agvDetail.state === 'idle' && currentPhase === 'stationed') {
|
||||||
const toPickupPath = computePath(
|
const toPickupPath = computePath(
|
||||||
|
@ -68,13 +74,7 @@ function VehicleInstance({ agvDetail }: { agvDetail: VehicleStatus }) {
|
||||||
vehicleStatus(agvDetail.modelUuid, 'Started from station, heading to pickup');
|
vehicleStatus(agvDetail.modelUuid, 'Started from station, heading to pickup');
|
||||||
return;
|
return;
|
||||||
} else if (!agvDetail.isActive && agvDetail.state === 'idle' && currentPhase === 'picking') {
|
} else if (!agvDetail.isActive && agvDetail.state === 'idle' && currentPhase === 'picking') {
|
||||||
|
if (agvDetail.currentLoad === agvDetail.point.action.loadCapacity && agvDetail.currentMaterials.length > 0) {
|
||||||
setTimeout(() => {
|
|
||||||
increment();
|
|
||||||
}, 5000);
|
|
||||||
|
|
||||||
|
|
||||||
if (agvDetail.currentLoad === agvDetail.point.action.loadCapacity && agvDetail.materialType) {
|
|
||||||
if (agvDetail.point.action.pickUpPoint && agvDetail.point.action.unLoadPoint) {
|
if (agvDetail.point.action.pickUpPoint && agvDetail.point.action.unLoadPoint) {
|
||||||
const toDrop = computePath(
|
const toDrop = computePath(
|
||||||
agvDetail.point.action.pickUpPoint.position,
|
agvDetail.point.action.pickUpPoint.position,
|
||||||
|
@ -98,8 +98,6 @@ function VehicleInstance({ agvDetail }: { agvDetail: VehicleStatus }) {
|
||||||
setVehicleState(agvDetail.modelUuid, 'running');
|
setVehicleState(agvDetail.modelUuid, 'running');
|
||||||
setVehicleActive(agvDetail.modelUuid, true);
|
setVehicleActive(agvDetail.modelUuid, true);
|
||||||
vehicleStatus(agvDetail.modelUuid, 'Started from dropping point, heading to pickup point');
|
vehicleStatus(agvDetail.modelUuid, 'Started from dropping point, heading to pickup point');
|
||||||
|
|
||||||
isIncrememtable.current = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -125,11 +123,54 @@ function VehicleInstance({ agvDetail }: { agvDetail: VehicleStatus }) {
|
||||||
setVehicleState(agvDetail.modelUuid, 'idle');
|
setVehicleState(agvDetail.modelUuid, 'idle');
|
||||||
setVehicleActive(agvDetail.modelUuid, false);
|
setVehicleActive(agvDetail.modelUuid, false);
|
||||||
setPath([]);
|
setPath([]);
|
||||||
setMaterialType(agvDetail.modelUuid, null)
|
clearCurrentMaterials(agvDetail.modelUuid)
|
||||||
vehicleStatus(agvDetail.modelUuid, 'Reached pickup point again, cycle complete');
|
vehicleStatus(agvDetail.modelUuid, 'Reached pickup point again, cycle complete');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function startUnloadingProcess() {
|
||||||
|
const droppedMaterial = agvDetail.currentLoad;
|
||||||
|
startTime = performance.now();
|
||||||
|
handleMaterialDrop(droppedMaterial);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleMaterialDrop(droppedMaterial: number) {
|
||||||
|
if (isPausedRef.current) {
|
||||||
|
if (!pauseTimeRef.current) {
|
||||||
|
pauseTimeRef.current = performance.now();
|
||||||
|
}
|
||||||
|
requestAnimationFrame(() => handleMaterialDrop(droppedMaterial));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pauseTimeRef.current) {
|
||||||
|
const pauseDuration = performance.now() - pauseTimeRef.current;
|
||||||
|
startTime += pauseDuration;
|
||||||
|
pauseTimeRef.current = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const elapsedTime = performance.now() - startTime;
|
||||||
|
const unLoadDuration = agvDetail.point.action.unLoadDuration;
|
||||||
|
fixedInterval = ((unLoadDuration / agvDetail.currentLoad) * (1000 / speed));
|
||||||
|
|
||||||
|
if (elapsedTime >= fixedInterval) {
|
||||||
|
let droppedMat = droppedMaterial - 1;
|
||||||
|
decrementVehicleLoad(agvDetail.modelUuid, 1);
|
||||||
|
const materialId = removeLastMaterial(agvDetail.modelUuid);
|
||||||
|
if (materialId) {
|
||||||
|
removeMaterial(materialId);
|
||||||
|
}
|
||||||
|
if (droppedMat > 0) {
|
||||||
|
startTime = performance.now();
|
||||||
|
requestAnimationFrame(() => handleMaterialDrop(droppedMat));
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
requestAnimationFrame(() => handleMaterialDrop(droppedMaterial));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<VehicleAnimator
|
<VehicleAnimator
|
||||||
|
@ -139,6 +180,7 @@ function VehicleInstance({ agvDetail }: { agvDetail: VehicleStatus }) {
|
||||||
agvUuid={agvDetail?.modelUuid}
|
agvUuid={agvDetail?.modelUuid}
|
||||||
agvDetail={agvDetail}
|
agvDetail={agvDetail}
|
||||||
reset={reset}
|
reset={reset}
|
||||||
|
startUnloadingProcess={startUnloadingProcess}
|
||||||
/>
|
/>
|
||||||
<MaterialAnimator agvDetail={agvDetail} />
|
<MaterialAnimator agvDetail={agvDetail} />
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -31,8 +31,8 @@ function Vehicles() {
|
||||||
|
|
||||||
<VehicleInstances />
|
<VehicleInstances />
|
||||||
|
|
||||||
{isVehicleSelected && !isPlaying &&
|
{isVehicleSelected && selectedEventSphere && !isPlaying &&
|
||||||
< VehicleUI />
|
<VehicleUI />
|
||||||
}
|
}
|
||||||
|
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -7,6 +7,7 @@ export default function ZoneAssets() {
|
||||||
const { zoneAssetId, setZoneAssetId } = useZoneAssetId();
|
const { zoneAssetId, setZoneAssetId } = useZoneAssetId();
|
||||||
const { setSelectedFloorItem } = useSelectedFloorItem();
|
const { setSelectedFloorItem } = useSelectedFloorItem();
|
||||||
const { raycaster, controls, scene }: any = useThree();
|
const { raycaster, controls, scene }: any = useThree();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// console.log('zoneAssetId: ', zoneAssetId);
|
// console.log('zoneAssetId: ', zoneAssetId);
|
||||||
if (!zoneAssetId) return
|
if (!zoneAssetId) return
|
||||||
|
@ -70,8 +71,6 @@ export default function ZoneAssets() {
|
||||||
}
|
}
|
||||||
}, [zoneAssetId, scene, controls])
|
}, [zoneAssetId, scene, controls])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -13,8 +13,6 @@ export default function ZoneCentreTarget() {
|
||||||
const { zoneTarget, setZoneTarget } = usezoneTarget();
|
const { zoneTarget, setZoneTarget } = usezoneTarget();
|
||||||
const { Edit, setEdit } = useEditPosition();
|
const { Edit, setEdit } = useEditPosition();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (
|
if (
|
||||||
selectedZone.zoneViewPortTarget &&
|
selectedZone.zoneViewPortTarget &&
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
|
import { create } from "zustand";
|
||||||
import { create } from 'zustand';
|
import { immer } from "zustand/middleware/immer";
|
||||||
import { immer } from 'zustand/middleware/immer';
|
|
||||||
|
|
||||||
interface VehiclesStore {
|
interface VehiclesStore {
|
||||||
vehicles: VehicleStatus[];
|
vehicles: VehicleStatus[];
|
||||||
|
@ -9,7 +8,7 @@ interface VehiclesStore {
|
||||||
removeVehicle: (modelUuid: string) => void;
|
removeVehicle: (modelUuid: string) => void;
|
||||||
updateVehicle: (
|
updateVehicle: (
|
||||||
modelUuid: string,
|
modelUuid: string,
|
||||||
updates: Partial<Omit<VehicleStatus, 'modelUuid' | 'productId'>>
|
updates: Partial<Omit<VehicleStatus, "modelUuid" | "productId">>
|
||||||
) => void;
|
) => void;
|
||||||
clearvehicles: () => void;
|
clearvehicles: () => void;
|
||||||
|
|
||||||
|
@ -17,8 +16,15 @@ interface VehiclesStore {
|
||||||
updateSteeringAngle: (modelUuid: string, steeringAngle: number) => void;
|
updateSteeringAngle: (modelUuid: string, steeringAngle: number) => void;
|
||||||
incrementVehicleLoad: (modelUuid: string, incrementBy: number) => void;
|
incrementVehicleLoad: (modelUuid: string, incrementBy: number) => void;
|
||||||
decrementVehicleLoad: (modelUuid: string, decrementBy: number) => void;
|
decrementVehicleLoad: (modelUuid: string, decrementBy: number) => void;
|
||||||
setVehicleState: (modelUuid: string, newState: VehicleStatus['state']) => void;
|
setVehicleLoad: (modelUuid: string, load: number) => void;
|
||||||
setMaterialType: (modelUuid: string, materialType: string | null) => void;
|
setVehicleState: (
|
||||||
|
modelUuid: string,
|
||||||
|
newState: VehicleStatus["state"]
|
||||||
|
) => void;
|
||||||
|
addCurrentMaterial: (modelUuid: string, materialType: string, materialId: string) => void;
|
||||||
|
setCurrentMaterials: (modelUuid: string, materials: { materialType: string; materialId: string; }[]) => void;
|
||||||
|
removeLastMaterial: (modelUuid: string) => string | undefined;
|
||||||
|
clearCurrentMaterials: (modelUuid: string) => void;
|
||||||
incrementActiveTime: (modelUuid: string, incrementBy: number) => void;
|
incrementActiveTime: (modelUuid: string, incrementBy: number) => void;
|
||||||
incrementIdleTime: (modelUuid: string, incrementBy: number) => void;
|
incrementIdleTime: (modelUuid: string, incrementBy: number) => void;
|
||||||
|
|
||||||
|
@ -34,7 +40,9 @@ export const useVehicleStore = create<VehiclesStore>()(
|
||||||
|
|
||||||
addVehicle: (productId, event) => {
|
addVehicle: (productId, event) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const exists = state.vehicles.some(v => v.modelUuid === event.modelUuid);
|
const exists = state.vehicles.some(
|
||||||
|
(v) => v.modelUuid === event.modelUuid
|
||||||
|
);
|
||||||
if (!exists) {
|
if (!exists) {
|
||||||
state.vehicles.push({
|
state.vehicles.push({
|
||||||
...event,
|
...event,
|
||||||
|
@ -43,7 +51,7 @@ export const useVehicleStore = create<VehiclesStore>()(
|
||||||
idleTime: 0,
|
idleTime: 0,
|
||||||
activeTime: 0,
|
activeTime: 0,
|
||||||
currentLoad: 0,
|
currentLoad: 0,
|
||||||
materialType: null,
|
currentMaterials: [],
|
||||||
distanceTraveled: 0,
|
distanceTraveled: 0,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -52,13 +60,15 @@ export const useVehicleStore = create<VehiclesStore>()(
|
||||||
|
|
||||||
removeVehicle: (modelUuid) => {
|
removeVehicle: (modelUuid) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
state.vehicles = state.vehicles.filter(v => v.modelUuid !== modelUuid);
|
state.vehicles = state.vehicles.filter(
|
||||||
|
(v) => v.modelUuid !== modelUuid
|
||||||
|
);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
updateVehicle: (modelUuid, updates) => {
|
updateVehicle: (modelUuid, updates) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid);
|
const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid);
|
||||||
if (vehicle) {
|
if (vehicle) {
|
||||||
Object.assign(vehicle, updates);
|
Object.assign(vehicle, updates);
|
||||||
}
|
}
|
||||||
|
@ -73,7 +83,7 @@ export const useVehicleStore = create<VehiclesStore>()(
|
||||||
|
|
||||||
setVehicleActive: (modelUuid, isActive) => {
|
setVehicleActive: (modelUuid, isActive) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid);
|
const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid);
|
||||||
if (vehicle) {
|
if (vehicle) {
|
||||||
vehicle.isActive = isActive;
|
vehicle.isActive = isActive;
|
||||||
}
|
}
|
||||||
|
@ -82,7 +92,7 @@ export const useVehicleStore = create<VehiclesStore>()(
|
||||||
|
|
||||||
updateSteeringAngle: (modelUuid, steeringAngle) => {
|
updateSteeringAngle: (modelUuid, steeringAngle) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid);
|
const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid);
|
||||||
if (vehicle) {
|
if (vehicle) {
|
||||||
vehicle.point.action.steeringAngle = steeringAngle;
|
vehicle.point.action.steeringAngle = steeringAngle;
|
||||||
}
|
}
|
||||||
|
@ -91,7 +101,7 @@ export const useVehicleStore = create<VehiclesStore>()(
|
||||||
|
|
||||||
incrementVehicleLoad: (modelUuid, incrementBy) => {
|
incrementVehicleLoad: (modelUuid, incrementBy) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid);
|
const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid);
|
||||||
if (vehicle) {
|
if (vehicle) {
|
||||||
vehicle.currentLoad += incrementBy;
|
vehicle.currentLoad += incrementBy;
|
||||||
}
|
}
|
||||||
|
@ -100,34 +110,77 @@ export const useVehicleStore = create<VehiclesStore>()(
|
||||||
|
|
||||||
decrementVehicleLoad: (modelUuid, decrementBy) => {
|
decrementVehicleLoad: (modelUuid, decrementBy) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid);
|
const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid);
|
||||||
if (vehicle) {
|
if (vehicle) {
|
||||||
vehicle.currentLoad -= decrementBy;
|
vehicle.currentLoad -= decrementBy;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setVehicleLoad: (modelUuid, load) => {
|
||||||
|
set((state) => {
|
||||||
|
const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid);
|
||||||
|
if (vehicle) {
|
||||||
|
vehicle.currentLoad = load;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
setVehicleState: (modelUuid, newState) => {
|
setVehicleState: (modelUuid, newState) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid);
|
const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid);
|
||||||
if (vehicle) {
|
if (vehicle) {
|
||||||
vehicle.state = newState;
|
vehicle.state = newState;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
setMaterialType: (modelUuid, materialType) => {
|
addCurrentMaterial: (modelUuid, materialType, materialId) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid);
|
const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid);
|
||||||
if (vehicle) {
|
if (vehicle) {
|
||||||
vehicle.materialType = materialType;
|
vehicle.currentMaterials.push({ materialType, materialId });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
setCurrentMaterials: (modelUuid, materials) => {
|
||||||
|
set((state) => {
|
||||||
|
const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid);
|
||||||
|
if (vehicle) {
|
||||||
|
vehicle.currentMaterials = materials;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
removeLastMaterial: (modelUuid) => {
|
||||||
|
let materialId: string | undefined;
|
||||||
|
set((state) => {
|
||||||
|
const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid);
|
||||||
|
if (vehicle) {
|
||||||
|
if (vehicle.currentMaterials.length > 0) {
|
||||||
|
const material = vehicle.currentMaterials.pop();
|
||||||
|
if (material) {
|
||||||
|
materialId = material.materialId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return materialId;
|
||||||
|
},
|
||||||
|
|
||||||
|
clearCurrentMaterials: (modelUuid) => {
|
||||||
|
set((state) => {
|
||||||
|
const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid);
|
||||||
|
if (vehicle) {
|
||||||
|
vehicle.currentMaterials = [];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
incrementActiveTime: (modelUuid, incrementBy) => {
|
incrementActiveTime: (modelUuid, incrementBy) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid);
|
const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid);
|
||||||
if (vehicle) {
|
if (vehicle) {
|
||||||
vehicle.activeTime += incrementBy;
|
vehicle.activeTime += incrementBy;
|
||||||
}
|
}
|
||||||
|
@ -136,7 +189,7 @@ export const useVehicleStore = create<VehiclesStore>()(
|
||||||
|
|
||||||
incrementIdleTime: (modelUuid, incrementBy) => {
|
incrementIdleTime: (modelUuid, incrementBy) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid);
|
const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid);
|
||||||
if (vehicle) {
|
if (vehicle) {
|
||||||
vehicle.idleTime += incrementBy;
|
vehicle.idleTime += incrementBy;
|
||||||
}
|
}
|
||||||
|
@ -144,19 +197,19 @@ export const useVehicleStore = create<VehiclesStore>()(
|
||||||
},
|
},
|
||||||
|
|
||||||
getVehicleById: (modelUuid) => {
|
getVehicleById: (modelUuid) => {
|
||||||
return get().vehicles.find(v => v.modelUuid === modelUuid);
|
return get().vehicles.find((v) => v.modelUuid === modelUuid);
|
||||||
},
|
},
|
||||||
|
|
||||||
getVehiclesByProduct: (productId) => {
|
getVehiclesByProduct: (productId) => {
|
||||||
return get().vehicles.filter(v => v.productId === productId);
|
return get().vehicles.filter((v) => v.productId === productId);
|
||||||
},
|
},
|
||||||
|
|
||||||
getVehiclesByState: (state) => {
|
getVehiclesByState: (state) => {
|
||||||
return get().vehicles.filter(v => v.state === state);
|
return get().vehicles.filter((v) => v.state === state);
|
||||||
},
|
},
|
||||||
|
|
||||||
getActiveVehicles: () => {
|
getActiveVehicles: () => {
|
||||||
return get().vehicles.filter(v => v.isActive);
|
return get().vehicles.filter((v) => v.isActive);
|
||||||
}
|
},
|
||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
|
|
|
@ -181,7 +181,7 @@ interface VehicleStatus extends VehicleEventSchema {
|
||||||
idleTime: number;
|
idleTime: number;
|
||||||
activeTime: number;
|
activeTime: number;
|
||||||
currentLoad: number;
|
currentLoad: number;
|
||||||
materialType: string | null;
|
currentMaterials: { materialType: string; materialId: string; }[];
|
||||||
distanceTraveled: number;
|
distanceTraveled: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue