diff --git a/app/src/modules/builder/groups/zoneGroup.tsx b/app/src/modules/builder/groups/zoneGroup.tsx index 3bd9b8d..b0c8124 100644 --- a/app/src/modules/builder/groups/zoneGroup.tsx +++ b/app/src/modules/builder/groups/zoneGroup.tsx @@ -549,7 +549,7 @@ const ZoneGroup: React.FC = () => { const midpoint = new THREE.Vector3( (point1.x + point2.x) / 2, CONSTANTS.zoneConfig.height / 2 + - (zone.layer - 1) * CONSTANTS.zoneConfig.height, + (zone.layer - 1) * CONSTANTS.zoneConfig.height, (point1.z + point2.z) / 2 ); diff --git a/app/src/modules/simulation/actions/conveyor/actionHandler/useDefaultHandler.ts b/app/src/modules/simulation/actions/conveyor/actionHandler/useDefaultHandler.ts index e69de29..ab0a284 100644 --- a/app/src/modules/simulation/actions/conveyor/actionHandler/useDefaultHandler.ts +++ b/app/src/modules/simulation/actions/conveyor/actionHandler/useDefaultHandler.ts @@ -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, + }; +} \ No newline at end of file diff --git a/app/src/modules/simulation/actions/conveyor/actionHandler/useDespawnHandler.ts b/app/src/modules/simulation/actions/conveyor/actionHandler/useDespawnHandler.ts index 464629c..d72419a 100644 --- a/app/src/modules/simulation/actions/conveyor/actionHandler/useDespawnHandler.ts +++ b/app/src/modules/simulation/actions/conveyor/actionHandler/useDespawnHandler.ts @@ -2,7 +2,7 @@ import { useCallback } from "react"; import { useMaterialStore } from "../../../../../store/simulation/useMaterialStore"; export function useDespawnHandler() { - const { addMaterial, getMaterialById, removeMaterial } = useMaterialStore(); + const { getMaterialById, removeMaterial } = useMaterialStore(); const deSpawnLogStatus = (materialUuid: string, status: string) => { // console.log(`${materialUuid}, ${status}`); @@ -18,7 +18,7 @@ export function useDespawnHandler() { deSpawnLogStatus(material.materialId, `Despawned`); - }, [addMaterial, getMaterialById, removeMaterial]); + }, [getMaterialById, removeMaterial]); return { handleDespawn, diff --git a/app/src/modules/simulation/actions/conveyor/useConveyorActions.ts b/app/src/modules/simulation/actions/conveyor/useConveyorActions.ts index 43e3dc1..1772444 100644 --- a/app/src/modules/simulation/actions/conveyor/useConveyorActions.ts +++ b/app/src/modules/simulation/actions/conveyor/useConveyorActions.ts @@ -1,17 +1,20 @@ import { useEffect, useCallback } from "react"; +import { useDefaultHandler } from "./actionHandler/useDefaultHandler"; import { useSpawnHandler } from "./actionHandler/useSpawnHandler"; import { useSwapHandler } from "./actionHandler/useSwapHandler"; import { useDelayHandler } from "./actionHandler/useDelayHandler"; import { useDespawnHandler } from "./actionHandler/useDespawnHandler"; export function useConveyorActions() { + const { handleDefault } = useDefaultHandler(); const { handleSpawn, clearCurrentSpawn } = useSpawnHandler(); const { handleSwap } = useSwapHandler(); const { handleDespawn } = useDespawnHandler(); 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) => { handleSpawn(action); diff --git a/app/src/modules/simulation/actions/roboticArm/actionHandler/usePickAndPlaceHandler.ts b/app/src/modules/simulation/actions/roboticArm/actionHandler/usePickAndPlaceHandler.ts new file mode 100644 index 0000000..2f44cfe --- /dev/null +++ b/app/src/modules/simulation/actions/roboticArm/actionHandler/usePickAndPlaceHandler.ts @@ -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, + }; +} \ No newline at end of file diff --git a/app/src/modules/simulation/actions/roboticArm/useRoboticArmActions.ts b/app/src/modules/simulation/actions/roboticArm/useRoboticArmActions.ts index 37990db..90251d2 100644 --- a/app/src/modules/simulation/actions/roboticArm/useRoboticArmActions.ts +++ b/app/src/modules/simulation/actions/roboticArm/useRoboticArmActions.ts @@ -1,20 +1,24 @@ import { useEffect, useCallback } from 'react'; +import { usePickAndPlaceHandler } from './actionHandler/usePickAndPlaceHandler'; export function useRoboticArmActions() { + const { handlePickAndPlace } = usePickAndPlaceHandler(); - const handlePickAndPlace = useCallback((action: RoboticArmAction) => { - console.log(`Robotic arm pick and place`); - }, []); + const handlePickAndPlaceAction = useCallback((action: RoboticArmAction, materialId: string) => { + handlePickAndPlace(action, materialId); + }, [handlePickAndPlace]); + + const handleRoboticArmAction = useCallback((action: RoboticArmAction, materialId: string) => { + if (!action) return; - const handleRoboticArmAction = useCallback((action: RoboticArmAction) => { switch (action.actionType) { case 'pickAndPlace': - handlePickAndPlace(action); + handlePickAndPlaceAction(action, materialId); break; default: console.warn(`Unknown robotic arm action type: ${action.actionType}`); } - }, [handlePickAndPlace]); + }, [handlePickAndPlaceAction]); const cleanup = useCallback(() => { }, []); diff --git a/app/src/modules/simulation/actions/useActionHandler.ts b/app/src/modules/simulation/actions/useActionHandler.ts index e713ed4..4041ab5 100644 --- a/app/src/modules/simulation/actions/useActionHandler.ts +++ b/app/src/modules/simulation/actions/useActionHandler.ts @@ -23,36 +23,26 @@ export function useActionHandler() { const handleAction = useCallback( (action: Action, materialId?: string) => { if (!action) return; - - try { - switch (action.actionType) { - case "default": - case "spawn": - case "swap": - case "delay": - case "despawn": - handleConveyorAction( - action as ConveyorAction, - materialId as string - ); - break; - case "travel": - handleVehicleAction(action as VehicleAction); - break; - case "pickAndPlace": - handleRoboticArmAction(action as RoboticArmAction); - break; - case "process": - handleMachineAction(action as MachineAction); - break; - case "store": - handleStorageAction(action as StorageAction); - break; - default: - console.warn( - `Unknown action type: ${(action as Action).actionType}` - ); - } + try { + switch (action.actionType) { + case 'default': case 'spawn': case 'swap': case 'delay': case 'despawn': + handleConveyorAction(action as ConveyorAction, materialId as string); + break; + case 'travel': + handleVehicleAction(action as VehicleAction, materialId as string); + break; + case 'pickAndPlace': + handleRoboticArmAction(action as RoboticArmAction, materialId as string); + break; + 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) { echo.error("Failed to handle action"); console.error("Error handling action:", error); diff --git a/app/src/modules/simulation/actions/vehicle/actionHandler/useTravelHandler.ts b/app/src/modules/simulation/actions/vehicle/actionHandler/useTravelHandler.ts new file mode 100644 index 0000000..c77b518 --- /dev/null +++ b/app/src/modules/simulation/actions/vehicle/actionHandler/useTravelHandler.ts @@ -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, + }; +} \ No newline at end of file diff --git a/app/src/modules/simulation/actions/vehicle/useVehicleActions.ts b/app/src/modules/simulation/actions/vehicle/useVehicleActions.ts index 313fb5d..a54672b 100644 --- a/app/src/modules/simulation/actions/vehicle/useVehicleActions.ts +++ b/app/src/modules/simulation/actions/vehicle/useVehicleActions.ts @@ -1,20 +1,19 @@ import { useEffect, useCallback } from 'react'; +import { useTravelHandler } from './actionHandler/useTravelHandler'; export function useVehicleActions() { + const { handleTravel } = useTravelHandler(); - const handleTravelAction = useCallback((action: VehicleAction) => { - if (!action || action.actionType !== 'travel') return; + const handleTravelAction = useCallback((action: VehicleAction, materialId: string) => { + handleTravel(action, materialId); + }, [handleTravel]); - console.log(`Vehicle travel action ${action.actionUuid}`); - - }, []); - - const handleVehicleAction = useCallback((action: VehicleAction) => { + const handleVehicleAction = useCallback((action: VehicleAction, materialId: string) => { if (!action) return; switch (action.actionType) { case 'travel': - handleTravelAction(action); + handleTravelAction(action, materialId); break; default: console.warn(`Unknown vehicle action type: ${action.actionType}`); diff --git a/app/src/modules/simulation/materials/instances/instance/materialInstance.tsx b/app/src/modules/simulation/materials/instances/instance/materialInstance.tsx index a26109c..74bd61f 100644 --- a/app/src/modules/simulation/materials/instances/instance/materialInstance.tsx +++ b/app/src/modules/simulation/materials/instances/instance/materialInstance.tsx @@ -85,37 +85,10 @@ function MaterialInstance({ material }: { material: MaterialSchema }) { const callTrigger = () => { if (!material.next) return; - const fromModel = getEventByModelUuid(selectedProduct.productId, material.next.modelUuid); - if (!fromModel) return; - const fromPoint = getPointByUuid(selectedProduct.productId, fromModel.modelUuid, material.next.pointUuid); - 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') { + const action = getActionByPointUuid(selectedProduct.productId, material.next.pointUuid); + if (action) { + triggerPointActions(action, material.materialId); } - } return ( diff --git a/app/src/modules/simulation/triggers/connector/triggerConnector.tsx b/app/src/modules/simulation/triggers/connector/triggerConnector.tsx index 6afcc69..a56436f 100644 --- a/app/src/modules/simulation/triggers/connector/triggerConnector.tsx +++ b/app/src/modules/simulation/triggers/connector/triggerConnector.tsx @@ -50,7 +50,7 @@ function TriggerConnector() { organization: string, eventData: EventsSchema ) => { - upsertProductOrEventApi({ + const data =upsertProductOrEventApi({ productName: productName, productId: productId, organization: organization, diff --git a/app/src/modules/simulation/triggers/triggerHandler/useTriggerHandler.ts b/app/src/modules/simulation/triggers/triggerHandler/useTriggerHandler.ts index c33e2ec..19652b8 100644 --- a/app/src/modules/simulation/triggers/triggerHandler/useTriggerHandler.ts +++ b/app/src/modules/simulation/triggers/triggerHandler/useTriggerHandler.ts @@ -4,13 +4,15 @@ import { useProductStore } from '../../../../store/simulation/useProductStore'; import { useSelectedProduct } from '../../../../store/simulation/useSimulationStore'; import { useMaterialStore } from '../../../../store/simulation/useMaterialStore'; import { useArmBotStore } from '../../../../store/simulation/useArmBotStore'; +import { useVehicleStore } from '../../../../store/simulation/useVehicleStore'; export function useTriggerHandler() { const { handleAction } = useActionHandler(); const { selectedProduct } = useSelectedProduct(); const { getEventByTriggerUuid, getEventByModelUuid, getActionByUuid, getModelUuidByActionUuid } = useProductStore(); - const { addCurrentAction, getArmBotById } = useArmBotStore(); - const { setCurrentLocation, setNextLocation, getMaterialById, setIsPaused, setEndTime } = useMaterialStore(); + const { getArmBotById } = useArmBotStore(); + const { getVehicleById } = useVehicleStore(); + const { setCurrentLocation, setNextLocation, getMaterialById, setIsPaused, setIsVisible, setEndTime } = useMaterialStore(); const handleTrigger = (trigger: TriggerSchema, action: Action, materialId: string) => { @@ -42,6 +44,46 @@ export function useTriggerHandler() { } } else if (toEvent?.type === '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') { // Transfer to Machine @@ -51,33 +93,41 @@ export function useTriggerHandler() { 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 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); - addCurrentAction( - trigger.triggeredAsset?.triggeredModel.modelUuid, - trigger.triggeredAsset?.triggeredAction?.actionUuid, - material.materialType, - material.materialId - ); - } else { + setNextLocation(material.materialId, null); - // 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') { @@ -149,6 +199,41 @@ export function useTriggerHandler() { } else if (toEvent?.type === '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') { // Robotic Arm to Machine diff --git a/app/src/modules/simulation/ui/vehicle/vehicleUI.tsx b/app/src/modules/simulation/ui/vehicle/vehicleUI.tsx index 2a124cd..33ab372 100644 --- a/app/src/modules/simulation/ui/vehicle/vehicleUI.tsx +++ b/app/src/modules/simulation/ui/vehicle/vehicleUI.tsx @@ -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 startPoint from "../../../../assets/gltf-glb/arrow_green.glb"; -import * as THREE from "three"; import startEnd from "../../../../assets/gltf-glb/arrow_red.glb"; -import { useGLTF } from '@react-three/drei'; -import { useFrame, useThree } from '@react-three/fiber'; -import { useSelectedEventSphere, useIsDragging, useIsRotating } 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 { useGLTF } from "@react-three/drei"; +import { useFrame, useThree } from "@react-three/fiber"; +import { + useSelectedEventSphere, + useIsDragging, + useIsRotating, +} 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 { scene: startScene } = useGLTF(startPoint) as any; - const { scene: endScene } = useGLTF(startEnd) as any; - const startMarker = useRef(null); - const endMarker = useRef(null); - const prevMousePos = useRef({ x: 0, y: 0 }); - const { selectedEventSphere } = useSelectedEventSphere(); - const { selectedProduct } = useSelectedProduct(); - const { getVehicleById } = useVehicleStore(); - const { updateEvent } = useProductStore(); - const [startPosition, setStartPosition] = useState<[number, number, number]>([0, 0, 0]); - const [endPosition, setEndPosition] = useState<[number, number, number]>([0, 0, 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 { scene: startScene } = useGLTF(startPoint) as any; + const { scene: endScene } = useGLTF(startEnd) as any; + const startMarker = useRef(null); + const endMarker = useRef(null); + const prevMousePos = useRef({ x: 0, y: 0 }); + const { selectedEventSphere } = useSelectedEventSphere(); + const { selectedProduct } = useSelectedProduct(); + const { getVehicleById } = useVehicleStore(); + const { updateEvent } = useProductStore(); + const [startPosition, setStartPosition] = useState<[number, number, number]>([ + 0, 1, 0, + ]); - const email = localStorage.getItem('email') - const organization = (email!.split("@")[1]).split(".")[0]; - const updateBackend = ( - productName: string, - productId: string, - organization: string, - eventData: EventsSchema - ) => { - upsertProductOrEventApi({ - productName: productName, - productId: productId, - organization: organization, - eventDatas: eventData - }) - } + const [endPosition, setEndPosition] = useState<[number, number, number]>([ + 0, 1, 0, + ]); + const [startRotation, setStartRotation] = useState<[number, number, number]>([ + 0, 0, 0, + ]); - useEffect(() => { - if (!selectedEventSphere) return; - const selectedVehicle = getVehicleById(selectedEventSphere.userData.modelUuid); + const [endRotation, setEndRotation] = useState<[number, number, number]>([ + 0, 0, 0, + ]); + const [steeringRotation, setSteeringRotation] = useState< + [number, number, number] + >([0, 0, 0]); - if (selectedVehicle?.point?.action) { - const { pickUpPoint, unLoadPoint } = selectedVehicle.point.action; + const { isDragging, setIsDragging } = useIsDragging(); + 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(false); + const tubeRef = useRef(null); + const outerGroup = useRef(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) { - setStartPosition([pickUpPoint.position.x, 0, pickUpPoint.position.z]); - setStartRotation([pickUpPoint.rotation.x, pickUpPoint.rotation.y, pickUpPoint.rotation.z]); + const updateBackend = ( + productName: string, + 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 { - const defaultLocal = new THREE.Vector3(0, 0, 1.5); - const defaultWorld = selectedEventSphere.localToWorld(defaultLocal); - setStartPosition([defaultWorld.x, 0, defaultWorld.z]); - setStartRotation([0, 0, 0]); + setStartPosition([0, selectedVehicle.point.position[1] + 0.1, 1.5]); + 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([unLoadPoint.position.x, 0, unLoadPoint.position.z]); - setEndRotation([unLoadPoint.rotation.x, unLoadPoint.rotation.y, unLoadPoint.rotation.z]); + setEndPosition([localPosition.x, selectedVehicle.point.position[1], localPosition.z]); + setEndRotation([unLoadPoint.rotation.x, unLoadPoint.rotation.y, unLoadPoint.rotation.z, + ]); } else { - const defaultLocal = new THREE.Vector3(0, 0, -1.5); - const defaultWorld = selectedEventSphere.localToWorld(defaultLocal); - setEndPosition([defaultWorld.x, 0, defaultWorld.z]); - setEndRotation([0, 0, 0]); + setEndPosition([0, selectedVehicle.point.position[1] + 0.1, -1.5]); + setEndRotation([0, 0, 0]); } - } - }, [selectedEventSphere]); - - 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]); - } - } - }); + setSteeringRotation([0, steeringAngle, 0]) + } + }, 10); - const handlePointerDown = (e: any, state: "start" | "end", rotation: "start" | "end") => { + }, [selectedEventSphere, outerGroup.current]); - 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.enabled = false; - setIsDragging(null); + 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.enabled = false; + setIsDragging(null); + } else { + setIsDragging(state); + setIsRotating(null); + if (controls) controls.enabled = false; + } + }; - } else { - setIsDragging(state); - setIsRotating(null); - if (controls) controls.enabled = false; - } - }; + const handlePointerUp = () => { + controls.enabled = true; + setIsDragging(null); + setIsRotating(null); - const handlePointerUp = () => { - controls.enabled = true; - setIsDragging(null); - setIsRotating(null); + if (selectedEventSphere?.userData.modelUuid) { + const updatedVehicle = getVehicleById( + selectedEventSphere.userData.modelUuid + ); - if (selectedEventSphere?.userData.modelUuid) { - const updatedVehicle = getVehicleById(selectedEventSphere.userData.modelUuid); + let globalStartPosition = null; + let globalEndPosition = null; - if (updatedVehicle) { - const event = updateEvent(selectedProduct.productId, selectedEventSphere.userData.modelUuid, { - point: { - ...updatedVehicle.point, - action: { - ...updatedVehicle.point?.action, - pickUpPoint: { - position: { x: startPosition[0], y: startPosition[1], z: startPosition[2], }, - rotation: { x: 0, y: startRotation[1], z: 0, }, - }, - unLoadPoint: { - position: { x: endPosition[0], y: endPosition[1], z: endPosition[2], }, - rotation: { x: 0, y: endRotation[1], z: 0, }, - }, + if (outerGroup.current && startMarker.current && endMarker.current) { + const worldPosStart = new Vector3(...startPosition); + globalStartPosition = outerGroup.current.localToWorld(worldPosStart.clone()); + const worldPosEnd = new Vector3(...endPosition); + globalEndPosition = outerGroup.current.localToWorld(worldPosEnd.clone()); + } + if (updatedVehicle && globalEndPosition && globalStartPosition) { + const event = updateEvent( + selectedProduct.productId, + selectedEventSphere.userData.modelUuid, + { + point: { + ...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) { - updateBackend( - selectedProduct.productName, - selectedProduct.productId, - organization, - event - ); - } + if (event) { + updateBackend( + selectedProduct.productName, + selectedProduct.productId, + organization, + event + ); } - } - }; + } + } + }; - useEffect(() => { - const handleGlobalPointerUp = () => { - setIsDragging(null); - setIsRotating(null); - if (controls) controls.enabled = true; - handlePointerUp(); - }; + 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") { + 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 () => { - window.removeEventListener("pointerup", handleGlobalPointerUp); - }; - }, [isDragging, isRotating, startPosition, startRotation, endPosition, endRotation]); + useEffect(() => { + const handleGlobalPointerUp = () => { + setIsDragging(null); + setIsRotating(null); + setTubeRotation(false); + if (controls) controls.enabled = true; + handlePointerUp(); - return ( - startPosition.length > 0 && endPosition.length > 0 ? ( - - { - e.stopPropagation(); - handlePointerDown(e, "start", "start"); - }} - onPointerMissed={() => { - controls.enabled = true; - setIsDragging(null); - setIsRotating(null); - }} - /> + }; + + if (isDragging || isRotating || tubeRotation) { + window.addEventListener("pointerup", handleGlobalPointerUp); + } + + return () => { + window.removeEventListener("pointerup", handleGlobalPointerUp); + }; + }, [ + isDragging, isRotating, startPosition, startRotation, endPosition, endRotation, tubeRotation, steeringRotation, outerGroup.current, tubeRef.current + ]); + + + const prevSteeringY = useRef(0); + useFrame((state) => { + 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 ? ( + + { + 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); + }} + > + ( + + + - { - e.stopPropagation(); - handlePointerDown(e, "end", "end"); - }} - onPointerMissed={() => { - controls.enabled = true; - setIsDragging(null); - setIsRotating(null); - }} - /> - ) : null - ); -} + + + + + ) + + + {/* Start Marker */} + { + e.stopPropagation(); + handlePointerDown(e, "start", "start"); + }} + onPointerMissed={() => { + controls.enabled = true; + setIsDragging(null); + setIsRotating(null); + }} + /> + + {/* End Marker */} + { + e.stopPropagation(); + handlePointerDown(e, "end", "end"); + }} + onPointerMissed={() => { + controls.enabled = true; + setIsDragging(null); + setIsRotating(null); + }} + /> + + ) : null; +}; export default VehicleUI; diff --git a/app/src/modules/simulation/vehicle/instances/animator/materialAnimator.tsx b/app/src/modules/simulation/vehicle/instances/animator/materialAnimator.tsx index 4b9eb1c..1fd3716 100644 --- a/app/src/modules/simulation/vehicle/instances/animator/materialAnimator.tsx +++ b/app/src/modules/simulation/vehicle/instances/animator/materialAnimator.tsx @@ -38,10 +38,12 @@ const MaterialAnimator = ({ agvDetail }: MaterialAnimatorProps) => { <> {hasLoad && ( <> - + {agvDetail.currentMaterials.length > 0 && + + } void; reset: () => void; + startUnloadingProcess: () => void; currentPhase: string; agvUuid: string; agvDetail: VehicleStatus; } -function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetail, reset }: VehicleAnimatorProps) { - const { decrementVehicleLoad, getVehicleById } = useVehicleStore(); +function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetail, reset, startUnloadingProcess }: VehicleAnimatorProps) { + const { getVehicleById } = useVehicleStore(); const { isPaused } = usePauseButtonStore(); const { isPlaying } = usePlayButtonStore(); const { speed } = useAnimationPlaySpeed(); @@ -23,32 +24,25 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai const progressRef = useRef(0); const movingForward = useRef(true); const completedRef = useRef(false); - const isPausedRef = useRef(false); - const pauseTimeRef = useRef(null); - const [progress, setProgress] = useState(0); + const [objectRotation, setObjectRotation] = useState<{ x: number; y: number; z: number } | undefined>(agvDetail.point?.action?.pickUpPoint?.rotation || { x: 0, y: 0, z: 0 }) const [restRotation, setRestingRotation] = useState(true); const [currentPath, setCurrentPath] = useState<[number, number, number][]>([]); 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(() => { if (currentPhase === 'stationed-pickup' && path.length > 0) { setCurrentPath(path); - objectRotation = agvDetail.point.action?.pickUpPoint?.rotation + setObjectRotation(agvDetail.point.action?.pickUpPoint?.rotation) } else if (currentPhase === 'pickup-drop' && path.length > 0) { - objectRotation = agvDetail.point.action?.unLoadPoint?.rotation + setObjectRotation(agvDetail.point.action?.unLoadPoint?.rotation) setCurrentPath(path); } else if (currentPhase === 'drop-pickup' && path.length > 0) { - objectRotation = agvDetail.point.action?.pickUpPoint?.rotation + setObjectRotation(agvDetail.point.action?.pickUpPoint?.rotation) setCurrentPath(path); } - }, [currentPhase, path]); + }, [currentPhase, path, objectRotation]); useEffect(() => { - setProgress(0); completedRef.current = false; }, [currentPath]); @@ -56,17 +50,11 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai if (isReset || !isPlaying) { reset(); setCurrentPath([]); - setProgress(0); completedRef.current = false; movingForward.current = true; progressRef.current = 0; - startTime = 0; - coveredDistance = 0; setReset(false); setRestingRotation(true); - decrementVehicleLoad(agvDetail.modelUuid, 0); - isPausedRef.current = false; - pauseTimeRef.current = 0; const object = scene.getObjectByProperty('uuid', agvUuid); const vehicle = getVehicleById(agvDetail.modelUuid); if (object && vehicle) { @@ -76,10 +64,6 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai } }, [isReset, isPlaying]) - useEffect(() => { - isPausedRef.current = isPaused; - }, [isPaused]); - useFrame((_, delta) => { const object = scene.getObjectByProperty('uuid', agvUuid); if (!object || currentPath.length < 2) return; @@ -98,7 +82,7 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai totalDistance += segmentDistance; } - while (index < distances.length && coveredDistance > accumulatedDistance + distances[index]) { + while (index < distances.length && progressRef.current > accumulatedDistance + distances[index]) { accumulatedDistance += distances[index]; index++; } @@ -124,9 +108,7 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai if (isAligned) { progressRef.current += delta * (speed * agvDetail.speed); - coveredDistance = progressRef.current; - - const t = (coveredDistance - accumulatedDistance) / segmentDistance; + const t = (progressRef.current - accumulatedDistance) / segmentDistance; const position = start.clone().lerp(end, t); object.position.copy(position); } @@ -134,17 +116,21 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai if (progressRef.current >= totalDistance) { 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); - const angleDiff = object.quaternion.angleTo(targetQuaternion); - if (angleDiff < 0.01) { - object.rotation.set(objectRotation.x, objectRotation.y, objectRotation.z); + 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; @@ -152,54 +138,15 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai setCurrentPath([]); handleCallBack(); 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 ( <> {currentPath.length > 0 && ( - + {currentPath.map((point, index) => ( diff --git a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx index abf7336..6607ba6 100644 --- a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx +++ b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx @@ -3,18 +3,28 @@ import VehicleAnimator from '../animator/vehicleAnimator'; import * as THREE from 'three'; import { NavMeshQuery } from '@recast-navigation/core'; import { useNavMesh } from '../../../../../store/store'; -import { usePlayButtonStore } from '../../../../../store/usePlayButtonStore'; +import { useAnimationPlaySpeed, usePauseButtonStore, usePlayButtonStore } from '../../../../../store/usePlayButtonStore'; import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore'; +import { useMaterialStore } from '../../../../../store/simulation/useMaterialStore'; import MaterialAnimator from '../animator/materialAnimator'; function VehicleInstance({ agvDetail }: { agvDetail: VehicleStatus }) { const { navMesh } = useNavMesh(); - const vehicleRef: any = useRef(); 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('stationed'); const [path, setPath] = useState<[number, number, number][]>([]); - let isIncrememtable = useRef(true); + const pauseTimeRef = useRef(null); + const isPausedRef = useRef(false); + let startTime: number; + let fixedInterval: number; + const { speed } = useAnimationPlaySpeed(); + const { isPaused } = usePauseButtonStore(); + + useEffect(() => { + isPausedRef.current = isPaused; + }, [isPaused]); const computePath = useCallback( (start: any, end: any) => { @@ -34,7 +44,6 @@ function VehicleInstance({ agvDetail }: { agvDetail: VehicleStatus }) { function vehicleStatus(modelId: string, status: string) { // console.log(`${modelId} , ${status}`); - } // Function to reset everything @@ -42,19 +51,16 @@ function VehicleInstance({ agvDetail }: { agvDetail: VehicleStatus }) { setCurrentPhase('stationed'); setVehicleActive(agvDetail.modelUuid, false); setVehicleState(agvDetail.modelUuid, 'idle'); + setVehicleLoad(agvDetail.modelUuid, 0); setPath([]); - } - - const increment = () => { - if (isIncrememtable.current) { - incrementVehicleLoad(agvDetail.modelUuid, 10); - setMaterialType(agvDetail.modelUuid, 'Material 1') - isIncrememtable.current = false; - } + startTime = 0; + isPausedRef.current = false; + pauseTimeRef.current = 0; } useEffect(() => { if (isPlaying) { + if (!agvDetail.point.action.unLoadPoint || !agvDetail.point.action.pickUpPoint) return; if (!agvDetail.isActive && agvDetail.state === 'idle' && currentPhase === 'stationed') { const toPickupPath = computePath( @@ -68,13 +74,7 @@ function VehicleInstance({ agvDetail }: { agvDetail: VehicleStatus }) { vehicleStatus(agvDetail.modelUuid, 'Started from station, heading to pickup'); return; } else if (!agvDetail.isActive && agvDetail.state === 'idle' && currentPhase === 'picking') { - - setTimeout(() => { - increment(); - }, 5000); - - - if (agvDetail.currentLoad === agvDetail.point.action.loadCapacity && agvDetail.materialType) { + if (agvDetail.currentLoad === agvDetail.point.action.loadCapacity && agvDetail.currentMaterials.length > 0) { if (agvDetail.point.action.pickUpPoint && agvDetail.point.action.unLoadPoint) { const toDrop = computePath( agvDetail.point.action.pickUpPoint.position, @@ -98,8 +98,6 @@ function VehicleInstance({ agvDetail }: { agvDetail: VehicleStatus }) { setVehicleState(agvDetail.modelUuid, 'running'); setVehicleActive(agvDetail.modelUuid, true); vehicleStatus(agvDetail.modelUuid, 'Started from dropping point, heading to pickup point'); - - isIncrememtable.current = true; } } } else { @@ -125,11 +123,54 @@ function VehicleInstance({ agvDetail }: { agvDetail: VehicleStatus }) { setVehicleState(agvDetail.modelUuid, 'idle'); setVehicleActive(agvDetail.modelUuid, false); setPath([]); - setMaterialType(agvDetail.modelUuid, null) + clearCurrentMaterials(agvDetail.modelUuid) 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 ( <> diff --git a/app/src/modules/simulation/vehicle/vehicles.tsx b/app/src/modules/simulation/vehicle/vehicles.tsx index 0b5a5a5..2b92403 100644 --- a/app/src/modules/simulation/vehicle/vehicles.tsx +++ b/app/src/modules/simulation/vehicle/vehicles.tsx @@ -31,12 +31,12 @@ function Vehicles() { - {isVehicleSelected && !isPlaying && - < VehicleUI /> + {isVehicleSelected && selectedEventSphere && !isPlaying && + } ); } -export default Vehicles; \ No newline at end of file +export default Vehicles; diff --git a/app/src/modules/visualization/zone/zoneAssets.tsx b/app/src/modules/visualization/zone/zoneAssets.tsx index af8b849..309fed4 100644 --- a/app/src/modules/visualization/zone/zoneAssets.tsx +++ b/app/src/modules/visualization/zone/zoneAssets.tsx @@ -7,6 +7,7 @@ export default function ZoneAssets() { const { zoneAssetId, setZoneAssetId } = useZoneAssetId(); const { setSelectedFloorItem } = useSelectedFloorItem(); const { raycaster, controls, scene }: any = useThree(); + useEffect(() => { // console.log('zoneAssetId: ', zoneAssetId); if (!zoneAssetId) return @@ -70,8 +71,6 @@ export default function ZoneAssets() { } }, [zoneAssetId, scene, controls]) - - return ( <> diff --git a/app/src/modules/visualization/zone/zoneCameraTarget.tsx b/app/src/modules/visualization/zone/zoneCameraTarget.tsx index d1587de..c3116ef 100644 --- a/app/src/modules/visualization/zone/zoneCameraTarget.tsx +++ b/app/src/modules/visualization/zone/zoneCameraTarget.tsx @@ -13,8 +13,6 @@ export default function ZoneCentreTarget() { const { zoneTarget, setZoneTarget } = usezoneTarget(); const { Edit, setEdit } = useEditPosition(); - - useEffect(() => { if ( selectedZone.zoneViewPortTarget && diff --git a/app/src/store/simulation/useVehicleStore.ts b/app/src/store/simulation/useVehicleStore.ts index 63ca0d0..7a393de 100644 --- a/app/src/store/simulation/useVehicleStore.ts +++ b/app/src/store/simulation/useVehicleStore.ts @@ -1,6 +1,5 @@ - -import { create } from 'zustand'; -import { immer } from 'zustand/middleware/immer'; +import { create } from "zustand"; +import { immer } from "zustand/middleware/immer"; interface VehiclesStore { vehicles: VehicleStatus[]; @@ -9,7 +8,7 @@ interface VehiclesStore { removeVehicle: (modelUuid: string) => void; updateVehicle: ( modelUuid: string, - updates: Partial> + updates: Partial> ) => void; clearvehicles: () => void; @@ -17,8 +16,15 @@ interface VehiclesStore { updateSteeringAngle: (modelUuid: string, steeringAngle: number) => void; incrementVehicleLoad: (modelUuid: string, incrementBy: number) => void; decrementVehicleLoad: (modelUuid: string, decrementBy: number) => void; - setVehicleState: (modelUuid: string, newState: VehicleStatus['state']) => void; - setMaterialType: (modelUuid: string, materialType: string | null) => void; + setVehicleLoad: (modelUuid: string, load: number) => 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; incrementIdleTime: (modelUuid: string, incrementBy: number) => void; @@ -34,7 +40,9 @@ export const useVehicleStore = create()( addVehicle: (productId, event) => { set((state) => { - const exists = state.vehicles.some(v => v.modelUuid === event.modelUuid); + const exists = state.vehicles.some( + (v) => v.modelUuid === event.modelUuid + ); if (!exists) { state.vehicles.push({ ...event, @@ -43,7 +51,7 @@ export const useVehicleStore = create()( idleTime: 0, activeTime: 0, currentLoad: 0, - materialType: null, + currentMaterials: [], distanceTraveled: 0, }); } @@ -52,13 +60,15 @@ export const useVehicleStore = create()( removeVehicle: (modelUuid) => { set((state) => { - state.vehicles = state.vehicles.filter(v => v.modelUuid !== modelUuid); + state.vehicles = state.vehicles.filter( + (v) => v.modelUuid !== modelUuid + ); }); }, updateVehicle: (modelUuid, updates) => { set((state) => { - const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid); + const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid); if (vehicle) { Object.assign(vehicle, updates); } @@ -73,7 +83,7 @@ export const useVehicleStore = create()( setVehicleActive: (modelUuid, isActive) => { set((state) => { - const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid); + const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid); if (vehicle) { vehicle.isActive = isActive; } @@ -82,7 +92,7 @@ export const useVehicleStore = create()( updateSteeringAngle: (modelUuid, steeringAngle) => { set((state) => { - const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid); + const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid); if (vehicle) { vehicle.point.action.steeringAngle = steeringAngle; } @@ -91,7 +101,7 @@ export const useVehicleStore = create()( incrementVehicleLoad: (modelUuid, incrementBy) => { set((state) => { - const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid); + const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid); if (vehicle) { vehicle.currentLoad += incrementBy; } @@ -100,34 +110,77 @@ export const useVehicleStore = create()( decrementVehicleLoad: (modelUuid, decrementBy) => { set((state) => { - const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid); + const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid); if (vehicle) { 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) => { set((state) => { - const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid); + const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid); if (vehicle) { vehicle.state = newState; } }); }, - setMaterialType: (modelUuid, materialType) => { + addCurrentMaterial: (modelUuid, materialType, materialId) => { set((state) => { - const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid); + const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid); 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) => { set((state) => { - const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid); + const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid); if (vehicle) { vehicle.activeTime += incrementBy; } @@ -136,7 +189,7 @@ export const useVehicleStore = create()( incrementIdleTime: (modelUuid, incrementBy) => { set((state) => { - const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid); + const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid); if (vehicle) { vehicle.idleTime += incrementBy; } @@ -144,19 +197,19 @@ export const useVehicleStore = create()( }, getVehicleById: (modelUuid) => { - return get().vehicles.find(v => v.modelUuid === modelUuid); + return get().vehicles.find((v) => v.modelUuid === modelUuid); }, getVehiclesByProduct: (productId) => { - return get().vehicles.filter(v => v.productId === productId); + return get().vehicles.filter((v) => v.productId === productId); }, getVehiclesByState: (state) => { - return get().vehicles.filter(v => v.state === state); + return get().vehicles.filter((v) => v.state === state); }, getActiveVehicles: () => { - return get().vehicles.filter(v => v.isActive); - } + return get().vehicles.filter((v) => v.isActive); + }, })) ); diff --git a/app/src/types/simulationTypes.d.ts b/app/src/types/simulationTypes.d.ts index 04b742d..8a9f01d 100644 --- a/app/src/types/simulationTypes.d.ts +++ b/app/src/types/simulationTypes.d.ts @@ -181,7 +181,7 @@ interface VehicleStatus extends VehicleEventSchema { idleTime: number; activeTime: number; currentLoad: number; - materialType: string | null; + currentMaterials: { materialType: string; materialId: string; }[]; distanceTraveled: number; }