From 88d6c48c1d33674cd78e2cf455a39b9f417a883e Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Wed, 21 May 2025 09:44:49 +0530 Subject: [PATCH 1/3] feat: update PointsCreator to include getPointByUuidFromProduct and enhance point state management --- .../events/points/creator/pointsCreator.tsx | 50 ++++++++++++------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/app/src/modules/simulation/events/points/creator/pointsCreator.tsx b/app/src/modules/simulation/events/points/creator/pointsCreator.tsx index 22ca63d..00e8f32 100644 --- a/app/src/modules/simulation/events/points/creator/pointsCreator.tsx +++ b/app/src/modules/simulation/events/points/creator/pointsCreator.tsx @@ -15,7 +15,7 @@ function PointsCreator() { const { gl, raycaster, scene, pointer, camera } = useThree(); const { subModule } = useSubModuleStore(); const { events, updatePoint, getPointByUuid, getEventByModelUuid } = useEventsStore(); - const { getEventByModelUuid: getEventByModelUuidFromProduct, updatePoint: updatePointFromProduct, getEventByModelUuid: getEventByModelUuidFromProduct2 } = useProductStore(); + const { getEventByModelUuid: getEventByModelUuidFromProduct, updatePoint: updatePointFromProduct, getEventByModelUuid: getEventByModelUuidFromProduct2, getPointByUuid: getPointByUuidFromProduct } = useProductStore(); const { selectedProduct } = useSelectedProduct(); const { activeModule } = useModuleStore(); const transformRef = useRef(null); @@ -76,7 +76,7 @@ function PointsCreator() { }, [selectedEventSphere]); const updatePointToState = (selectedEventSphere: THREE.Mesh) => { - let point = JSON.parse( + let point: PointsScheme = JSON.parse( JSON.stringify( getPointByUuid( selectedEventSphere.userData.modelUuid, @@ -90,28 +90,44 @@ function PointsCreator() { selectedEventSphere.position.y, selectedEventSphere.position.z, ]; + point.rotation = [ + selectedEventSphere.rotation.x, + selectedEventSphere.rotation.y, + selectedEventSphere.rotation.z, + ]; const event = getEventByModelUuidFromProduct(selectedProduct.productId, selectedEventSphere.userData.modelUuid); if (event && selectedProduct.productId !== '') { - const updatedEvent = updatePointFromProduct( - selectedProduct.productId, - selectedEventSphere.userData.modelUuid, - selectedEventSphere.userData.pointUuid, - point - ) - if (updatedEvent) { - updatePoint( + + const updatedPoint = JSON.parse( + JSON.stringify( + getPointByUuidFromProduct(selectedProduct.productId, selectedEventSphere.userData.modelUuid, selectedEventSphere.userData.pointUuid) + ) + ); + if (updatedPoint) { + updatedPoint.position = point.position; + updatedPoint.rotation = point.rotation; + + const updatedEvent = updatePointFromProduct( + selectedProduct.productId, selectedEventSphere.userData.modelUuid, selectedEventSphere.userData.pointUuid, - point + updatedPoint ) - updateBackend( - selectedProduct.productName, - selectedProduct.productId, - organization, - updatedEvent - ); + if (updatedEvent) { + updatePoint( + selectedEventSphere.userData.modelUuid, + selectedEventSphere.userData.pointUuid, + point + ) + updateBackend( + selectedProduct.productName, + selectedProduct.productId, + organization, + updatedEvent + ); + } } } } From 402223feb36d9a1c6bf23d546d30c909dc528e24 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Wed, 21 May 2025 10:05:17 +0530 Subject: [PATCH 2/3] feat: optimize ArrowOnQuadraticBezier to improve curve calculations and simplify subCurve generation --- .../modules/simulation/events/arrows/arrows.tsx | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/app/src/modules/simulation/events/arrows/arrows.tsx b/app/src/modules/simulation/events/arrows/arrows.tsx index fdb0c18..5eb6a9f 100644 --- a/app/src/modules/simulation/events/arrows/arrows.tsx +++ b/app/src/modules/simulation/events/arrows/arrows.tsx @@ -160,29 +160,26 @@ export function ArrowOnQuadraticBezier({ const arrowRadius = 0.01 * scale; const arrowHeadRadius = arrowRadius * 2.5; - const curveLength = useMemo(() => fullCurve.getLength(), [fullCurve]); - const arrowHeadTOffset = useMemo(() => Math.min(arrowHeadLength / curveLength, 0.5), [arrowHeadLength, curveLength]); - - const endT = 1 - arrowHeadTOffset; - const subCurve = useMemo(() => { - const t1 = Math.max(0, endT - segmentSize / 2); - const t2 = Math.min(1, endT + segmentSize / 2); + const centerT = 0.5; + const t1 = Math.max(0, centerT - segmentSize / 2); + const t2 = Math.min(1, centerT + segmentSize / 2); + const divisions = 10; const subPoints = Array.from({ length: divisions + 1 }, (_, i) => { const t = THREE.MathUtils.lerp(t1, t2, i / divisions); return fullCurve.getPoint(t); }); return new THREE.CatmullRomCurve3(subPoints); - }, [fullCurve, endT, segmentSize]); + }, [fullCurve, segmentSize]); const tubeGeometry = useMemo( () => new THREE.TubeGeometry(subCurve, 20, arrowRadius, 8, false), [subCurve, arrowRadius] ); - const arrowPosition = useMemo(() => fullCurve.getPoint(1), [fullCurve]); - const arrowTangent = useMemo(() => fullCurve.getTangent(1).normalize(), [fullCurve]); + const arrowPosition = useMemo(() => subCurve.getPoint(1), [subCurve]); + const arrowTangent = useMemo(() => subCurve.getTangent(1).normalize(), [subCurve]); const arrowRotation = useMemo(() => { return new THREE.Quaternion().setFromUnitVectors(new THREE.Vector3(0, 1, 0), arrowTangent); From 60a277f7f0f28a404b6ee595db56efef6f0793c9 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Wed, 21 May 2025 12:43:25 +0530 Subject: [PATCH 3/3] feat: implement vehicle and machine event managers for monitoring state changes --- .../eventManager/useMachineEventManager.ts | 65 ++++++ .../triggerHandler/useTriggerHandler.ts | 195 ++++++++++++++++-- .../eventManager/useVehicleEventManager.ts | 65 ++++++ 3 files changed, 303 insertions(+), 22 deletions(-) create mode 100644 app/src/modules/simulation/machine/eventManager/useMachineEventManager.ts create mode 100644 app/src/modules/simulation/vehicle/instances/eventManager/useVehicleEventManager.ts diff --git a/app/src/modules/simulation/machine/eventManager/useMachineEventManager.ts b/app/src/modules/simulation/machine/eventManager/useMachineEventManager.ts new file mode 100644 index 0000000..e6edaf3 --- /dev/null +++ b/app/src/modules/simulation/machine/eventManager/useMachineEventManager.ts @@ -0,0 +1,65 @@ +import { useEffect, useRef } from 'react'; +import { useFrame } from '@react-three/fiber'; +import { useMachineStore } from '../../../../store/simulation/useMachineStore'; + +type MachineCallback = { + machineId: string; + callback: () => void; +}; + +export function useMachineEventManager() { + const { getMachineById } = useMachineStore(); + const callbacksRef = useRef([]); + const isMonitoringRef = useRef(false); + + // Add a new machine to monitor + const addMachineToMonitor = (machineId: string, callback: () => void) => { + // Avoid duplicates + if (!callbacksRef.current.some((entry) => entry.machineId === machineId)) { + callbacksRef.current.push({ machineId, callback }); + } + + // Start monitoring if not already running + if (!isMonitoringRef.current) { + isMonitoringRef.current = true; + } + }; + + // Remove a machine from monitoring + const removeMachineFromMonitor = (machineId: string) => { + callbacksRef.current = callbacksRef.current.filter( + (entry) => entry.machineId !== machineId + ); + + // Stop monitoring if no more machines to track + if (callbacksRef.current.length === 0) { + isMonitoringRef.current = false; + } + }; + + // Check machine states every frame + useFrame(() => { + if (!isMonitoringRef.current || callbacksRef.current.length === 0) return; + + callbacksRef.current.forEach(({ machineId, callback }) => { + const machine = getMachineById(machineId); + if (machine && machine.isActive === false && machine.state === 'idle' && !machine.currentAction) { + callback(); + removeMachineFromMonitor(machineId); // Remove after triggering + } + }); + }); + + // Cleanup on unmount + useEffect(() => { + return () => { + callbacksRef.current = []; + isMonitoringRef.current = false; + }; + }, []); + + return { + addMachineToMonitor, + removeMachineFromMonitor, + }; +} \ No newline at end of file diff --git a/app/src/modules/simulation/triggers/triggerHandler/useTriggerHandler.ts b/app/src/modules/simulation/triggers/triggerHandler/useTriggerHandler.ts index 67fecdb..a5d5372 100644 --- a/app/src/modules/simulation/triggers/triggerHandler/useTriggerHandler.ts +++ b/app/src/modules/simulation/triggers/triggerHandler/useTriggerHandler.ts @@ -10,6 +10,8 @@ import { useStorageUnitStore } from '../../../../store/simulation/useStorageUnit import { useArmBotEventManager } from '../../roboticArm/eventManager/useArmBotEventManager'; import { useConveyorStore } from '../../../../store/simulation/useConveyorStore'; import { useConveyorEventManager } from '../../conveyor/eventManager/useConveyorEventManager'; +import { useVehicleEventManager } from '../../vehicle/instances/eventManager/useVehicleEventManager'; +import { useMachineEventManager } from '../../machine/eventManager/useMachineEventManager'; export function useTriggerHandler() { const { handleAction } = useActionHandler(); @@ -19,6 +21,8 @@ export function useTriggerHandler() { const { getConveyorById } = useConveyorStore(); const { addArmBotToMonitor } = useArmBotEventManager(); const { addConveyorToMonitor } = useConveyorEventManager(); + const { addVehicleToMonitor } = useVehicleEventManager(); + const { addMachineToMonitor } = useMachineEventManager(); const { getVehicleById } = useVehicleStore(); const { getMachineById } = useMachineStore(); const { getStorageUnitById } = useStorageUnitStore(); @@ -89,7 +93,7 @@ export function useTriggerHandler() { if (vehicle) { - if (vehicle.isActive === false && vehicle.state === 'idle' && vehicle.currentLoad < vehicle.point.action.loadCapacity) { + if (vehicle.isActive === false && vehicle.state === 'idle' && vehicle.isPicking && vehicle.currentLoad < vehicle.point.action.loadCapacity) { setIsVisible(materialId, false); @@ -98,8 +102,10 @@ export function useTriggerHandler() { } else { - // Event Manager Needed - + // Handle current action using Event Manager + addVehicleToMonitor(vehicle.modelUuid, () => { + handleAction(action, materialId); + }) } } } @@ -140,21 +146,110 @@ export function useTriggerHandler() { if (action) { if (armBot) { + if (action && action.triggers.length > 0 && + action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid && + action.triggers[0]?.triggeredAsset?.triggeredAction?.actionUuid && + action.triggers[0]?.triggeredAsset?.triggeredPoint?.pointUuid) { + const model = getEventByModelUuid(selectedProduct.productId, action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid); - if (armBot.isActive === false && armBot.state === 'idle') { + if (model?.type === 'vehicle') { + const vehicle = getVehicleById(action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid); + if (vehicle) { + if (vehicle.isActive === false && vehicle.state === 'idle' && vehicle.isPicking && vehicle.currentLoad < vehicle.point.action.loadCapacity) { + // Handle current action from vehicle + setIsPaused(materialId, true); + handleAction(action, materialId); - // Handle current action from arm bot - setIsPaused(materialId, true); - handleAction(action, materialId); + } else { + // Handle current action using Event Manager + setIsPaused(materialId, true); + + addVehicleToMonitor(vehicle.modelUuid, + () => { + handleAction(action, materialId); + } + ) + } + } + } else if (model?.type === 'machine') { + const armBot = getArmBotById(trigger.triggeredAsset?.triggeredModel.modelUuid); + if (armBot) { + if (armBot.isActive === false && armBot.state === 'idle') { + const machine = getMachineById(action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid); + if (machine) { + if (machine.isActive === false && machine.state === 'idle' && !machine.currentAction) { + setIsPaused(materialId, true); + handleAction(action, materialId); + } else { + + // Handle current action using Event Manager + setIsPaused(materialId, true); + + addMachineToMonitor(machine.modelUuid, + () => { + handleAction(action, materialId); + } + ) + } + } + } else { + addArmBotToMonitor(armBot.modelUuid, + () => { + const machine = getMachineById(action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid || ''); + if (machine) { + if (machine.isActive === false && machine.state === 'idle' && !machine.currentAction) { + setIsPaused(materialId, true); + handleAction(action, materialId); + } else { + + // Handle current action using Event Manager + setIsPaused(materialId, true); + + addMachineToMonitor(machine.modelUuid, + () => { + handleAction(action, materialId); + } + ) + } + } + } + ); + } + } + } else { + if (armBot.isActive === false && armBot.state === 'idle') { + + // Handle current action from arm bot + setIsPaused(materialId, true); + handleAction(action, materialId); + + } else { + + // Handle current action using Event Manager + setIsPaused(materialId, true); + addArmBotToMonitor(armBot.modelUuid, + () => handleAction(action, materialId) + ); + + } + } } else { + if (armBot.isActive === false && armBot.state === 'idle') { - // Event Manager Needed - setIsPaused(materialId, true); - addArmBotToMonitor(armBot.modelUuid, - () => handleAction(action, materialId) - ); + // Handle current action from arm bot + setIsPaused(materialId, true); + handleAction(action, materialId); + } else { + + // Handle current action using Event Manager + setIsPaused(materialId, true); + addArmBotToMonitor(armBot.modelUuid, + () => handleAction(action, materialId) + ); + + } } } } @@ -334,11 +429,20 @@ export function useTriggerHandler() { if (model?.type === 'transfer') { const conveyor = getConveyorById(action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid || ''); if (conveyor) { - addConveyorToMonitor(conveyor.modelUuid, - () => { + const previousModel = getEventByModelUuid(selectedProduct.productId, material.previous?.modelUuid || ''); + if (previousModel) { + if (previousModel.type === 'transfer' && previousModel.modelUuid === model.modelUuid) { handleAction(action, materialId) + } else { + addConveyorToMonitor(conveyor.modelUuid, + () => { + handleAction(action, materialId) + } + ) } - ) + } else { + handleAction(action, materialId) + } // handleAction(action, materialId) } } else { @@ -347,18 +451,28 @@ export function useTriggerHandler() { } else { - // Event Manager Needed + // Handle current action using Event Manager + addArmBotToMonitor(armBot.modelUuid, () => { const model = getEventByModelUuid(selectedProduct.productId, action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid || ''); if (model?.type === 'transfer') { const conveyor = getConveyorById(action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid || ''); if (conveyor) { - addConveyorToMonitor(conveyor.modelUuid, - () => { + const previousModel = getEventByModelUuid(selectedProduct.productId, material.previous?.modelUuid || ''); + if (previousModel) { + if (previousModel.type === 'transfer' && previousModel.modelUuid === model.modelUuid) { handleAction(action, materialId) + } else { + addConveyorToMonitor(conveyor.modelUuid, + () => { + handleAction(action, materialId) + } + ) } - ) + } else { + handleAction(action, materialId) + } // handleAction(action, materialId) } } else { @@ -432,17 +546,54 @@ export function useTriggerHandler() { if (vehicle) { - if (vehicle.isActive === false && vehicle.state === 'idle' && vehicle.currentLoad < vehicle.point.action.loadCapacity) { + if (vehicle.isActive === false && vehicle.state === 'idle' && vehicle.isPicking && vehicle.currentLoad < vehicle.point.action.loadCapacity) { + + setPreviousLocation(material.materialId, { + modelUuid: material.current.modelUuid, + pointUuid: material.current.pointUuid, + actionUuid: material.current.actionUuid, + }) + + setCurrentLocation(material.materialId, { + modelUuid: action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid || '', + pointUuid: action.triggers[0]?.triggeredAsset?.triggeredPoint?.pointUuid || '', + actionUuid: action.triggers[0]?.triggeredAsset?.triggeredAction?.actionUuid || '', + }); + + setNextLocation(material.materialId, null); setIsVisible(materialId, false); + setIsPaused(materialId, false); // Handle current action from vehicle handleAction(nextAction, materialId); } else { - // Event Manager Needed + // Handle current action using Event Manager + setIsPaused(materialId, true); + addVehicleToMonitor(vehicle.modelUuid, + () => { + setPreviousLocation(material.materialId, { + modelUuid: material.current.modelUuid, + pointUuid: material.current.pointUuid, + actionUuid: material.current.actionUuid, + }) + + setCurrentLocation(material.materialId, { + modelUuid: action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid || '', + pointUuid: action.triggers[0]?.triggeredAsset?.triggeredPoint?.pointUuid || '', + actionUuid: action.triggers[0]?.triggeredAsset?.triggeredAction?.actionUuid || '', + }); + + setNextLocation(material.materialId, null); + + setIsPaused(materialId, false); + setIsVisible(materialId, false); + handleAction(nextAction, materialId); + } + ) } } } @@ -491,7 +642,7 @@ export function useTriggerHandler() { if (vehicle) { - if (vehicle.isActive === false && vehicle.state === 'idle' && vehicle.currentLoad < vehicle.point.action.loadCapacity) { + if (vehicle.isActive === false && vehicle.state === 'idle' && vehicle.isPicking && vehicle.currentLoad < vehicle.point.action.loadCapacity) { setIsVisible(materialId, false); diff --git a/app/src/modules/simulation/vehicle/instances/eventManager/useVehicleEventManager.ts b/app/src/modules/simulation/vehicle/instances/eventManager/useVehicleEventManager.ts new file mode 100644 index 0000000..7cc8c58 --- /dev/null +++ b/app/src/modules/simulation/vehicle/instances/eventManager/useVehicleEventManager.ts @@ -0,0 +1,65 @@ +import { useEffect, useRef } from 'react'; +import { useFrame } from '@react-three/fiber'; +import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore'; + +type VehicleCallback = { + vehicleId: string; + callback: () => void; +}; + +export function useVehicleEventManager() { + const { getVehicleById } = useVehicleStore(); + const callbacksRef = useRef([]); + const isMonitoringRef = useRef(false); + + // Add a new vehicle to monitor + const addVehicleToMonitor = (vehicleId: string, callback: () => void) => { + // Avoid duplicates + if (!callbacksRef.current.some((entry) => entry.vehicleId === vehicleId)) { + callbacksRef.current.push({ vehicleId, callback }); + } + + // Start monitoring if not already running + if (!isMonitoringRef.current) { + isMonitoringRef.current = true; + } + }; + + // Remove a vehicle from monitoring + const removeVehicleFromMonitor = (vehicleId: string) => { + callbacksRef.current = callbacksRef.current.filter( + (entry) => entry.vehicleId !== vehicleId + ); + + // Stop monitoring if no more vehicles to track + if (callbacksRef.current.length === 0) { + isMonitoringRef.current = false; + } + }; + + // Check vehicle states every frame + useFrame(() => { + if (!isMonitoringRef.current || callbacksRef.current.length === 0) return; + + callbacksRef.current.forEach(({ vehicleId, callback }) => { + const vehicle = getVehicleById(vehicleId); + if (vehicle && vehicle.isActive === false && vehicle.state === 'idle' && vehicle.isPicking && vehicle.currentLoad < vehicle.point.action.loadCapacity) { + callback(); + removeVehicleFromMonitor(vehicleId); // Remove after triggering + } + }); + }); + + // Cleanup on unmount + useEffect(() => { + return () => { + callbacksRef.current = []; + isMonitoringRef.current = false; + }; + }, []); + + return { + addVehicleToMonitor, + removeVehicleFromMonitor, + }; +} \ No newline at end of file