From 253b3db2ed7c769978acda15cfcce038770f7a91 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Tue, 29 Jul 2025 11:24:46 +0530 Subject: [PATCH] Refactor position handling in CopyPasteControls3D and DuplicationControls3D; update useRetrieveHandler to include machine and human event management; implement event handlers for model interactions in useEventHandlers. --- .../model/eventHandlers/useEventHandlers.ts | 238 ++++++++++++++++++ .../selection3D/copyPasteControls3D.tsx | 2 +- .../selection3D/duplicationControls3D.tsx | 2 +- .../actionHandler/useRetrieveHandler.ts | 97 ++++++- .../machineInstance/machineInstance.tsx | 2 +- .../triggerHandler/useTriggerHandler.ts | 30 ++- 6 files changed, 355 insertions(+), 16 deletions(-) create mode 100644 app/src/modules/builder/asset/models/model/eventHandlers/useEventHandlers.ts diff --git a/app/src/modules/builder/asset/models/model/eventHandlers/useEventHandlers.ts b/app/src/modules/builder/asset/models/model/eventHandlers/useEventHandlers.ts new file mode 100644 index 0000000..d678382 --- /dev/null +++ b/app/src/modules/builder/asset/models/model/eventHandlers/useEventHandlers.ts @@ -0,0 +1,238 @@ +import * as THREE from 'three'; +import { CameraControls } from '@react-three/drei'; +import { ThreeEvent } from '@react-three/fiber'; +import { useCallback } from 'react'; +import { ProductStoreType } from '../../../../../../store/simulation/useProductStore'; +import { EventStoreType } from '../../../../../../store/simulation/useEventsStore'; +import { Socket } from 'socket.io-client'; + +import { useActiveTool, useToolMode } from '../../../../../../store/builder/store'; +import useModuleStore, { useSubModuleStore } from '../../../../../../store/useModuleStore'; +import { useSocketStore } from '../../../../../../store/builder/store'; +import { useSceneContext } from '../../../../../scene/sceneContext'; +import { useProductContext } from '../../../../../simulation/products/productContext'; +import { useVersionContext } from '../../../../version/versionContext'; +import { useParams } from 'react-router-dom'; +import { getUserData } from '../../../../../../functions/getUserData'; + +// import { deleteFloorItem } from '../../../../../../services/factoryBuilder/asset/floorAsset/deleteFloorItemApi'; + +export function useModelEventHandlers({ + controls, + boundingBox, + groupRef, + toggleView, + deletableFloorItem, + setDeletableFloorItem, + setSelectedFloorItem, + gl, + setTop, + setLeft, + getIsEventInProduct, + getEventByModelUuid, + setSelectedAsset, + clearSelectedAsset, + removeAsset, + updateBackend, + leftDrag, + rightDrag +}: { + controls: CameraControls | any, + boundingBox: THREE.Box3 | null, + groupRef: React.RefObject, + toggleView: boolean, + deletableFloorItem: THREE.Object3D | null, + setDeletableFloorItem: (item: THREE.Object3D | null) => void, + setSelectedFloorItem: (item: THREE.Object3D | null) => void, + gl: THREE.WebGLRenderer, + setTop: (top: number) => void, + setLeft: (left: number) => void, + getIsEventInProduct: (productUuid: string, modelUuid: string) => boolean, + getEventByModelUuid: (modelUuid: string) => EventsSchema | undefined, + setSelectedAsset: (EventData: EventsSchema) => void, + clearSelectedAsset: () => void, + removeAsset: (modelUuid: string) => void, + updateBackend: (productName: string, productUuid: string, projectId: string, event: EventsSchema) => void, + leftDrag: React.MutableRefObject, + rightDrag: React.MutableRefObject +}) { + + const { activeTool } = useActiveTool(); + const { activeModule } = useModuleStore(); + const { subModule } = useSubModuleStore(); + const { socket } = useSocketStore(); + const { eventStore, productStore } = useSceneContext(); + const { selectedProductStore } = useProductContext(); + const { selectedProduct } = selectedProductStore(); + const { selectedVersionStore } = useVersionContext(); + const { selectedVersion } = selectedVersionStore(); + const { projectId } = useParams(); + const { userId, organization } = getUserData(); + + const handleDblClick = (asset: Asset) => { + if (asset && activeTool === "cursor" && boundingBox && groupRef.current && activeModule === 'builder') { + const size = boundingBox.getSize(new THREE.Vector3()); + const center = boundingBox.getCenter(new THREE.Vector3()); + + const front = new THREE.Vector3(0, 0, 1); + groupRef.current.localToWorld(front); + front.sub(groupRef.current.position).normalize(); + + const distance = Math.max(size.x, size.y, size.z) * 2; + const newPosition = center.clone().addScaledVector(front, distance); + + (controls as CameraControls).setPosition(newPosition.x, newPosition.y, newPosition.z, true); + (controls as CameraControls).setTarget(center.x, center.y, center.z, true); + (controls as CameraControls).fitToBox(groupRef.current, true, { + cover: true, + paddingTop: 5, + paddingLeft: 5, + paddingBottom: 5, + paddingRight: 5, + }); + + setSelectedFloorItem(groupRef.current); + } + }; + + const handleClick = async (evt: ThreeEvent, asset: Asset) => { + if (leftDrag.current || toggleView) return; + if (activeTool === 'delete' && deletableFloorItem && deletableFloorItem.uuid === asset.modelUuid) { + + //REST + + // const response = await deleteFloorItem(organization, asset.modelUuid, asset.modelName); + + //SOCKET + + const data = { + organization, + modelUuid: asset.modelUuid, + modelName: asset.modelName, + socketId: socket.id, + userId, + versionId: selectedVersion?.versionId || '', + projectId + } + + const response = socket.emit('v1:model-asset:delete', data) + + eventStore.getState().removeEvent(asset.modelUuid); + const updatedEvents = productStore.getState().deleteEvent(asset.modelUuid); + + updatedEvents.forEach((event) => { + updateBackend( + selectedProduct.productName, + selectedProduct.productUuid, + projectId || '', + event + ); + }) + + if (response) { + + removeAsset(asset.modelUuid); + + echo.success("Model Removed!"); + } + + } else if (activeModule === 'simulation' && subModule === "simulations" && activeTool === 'pen') { + if (asset.eventData && asset.eventData.type === 'Conveyor') { + const intersectedPoint = evt.point; + const localPosition = groupRef.current?.worldToLocal(intersectedPoint.clone()); + if (localPosition) { + const conveyorPoint: ConveyorPointSchema = { + uuid: THREE.MathUtils.generateUUID(), + position: [localPosition?.x, localPosition?.y, localPosition?.z], + rotation: [0, 0, 0], + action: { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: `Action 1`, + actionType: 'default', + material: 'Default Material', + delay: 0, + spawnInterval: 5, + spawnCount: 1, + triggers: [] + } + } + + const event = productStore.getState().addPoint(selectedProduct.productUuid, asset.modelUuid, conveyorPoint); + + if (event) { + updateBackend( + selectedProduct.productName, + selectedProduct.productUuid, + projectId || '', + event + ); + } + } + } + + } + }; + + const handlePointerOver = useCallback((asset: Asset) => { + if (activeTool === "delete" && activeModule === 'builder') { + if (deletableFloorItem && deletableFloorItem.uuid === asset.modelUuid) { + return; + } else { + setDeletableFloorItem(groupRef.current); + } + } + }, [activeTool, activeModule, deletableFloorItem]); + + const handlePointerOut = useCallback((evt: ThreeEvent, asset: Asset) => { + if (evt.intersections.length === 0 && activeTool === "delete" && deletableFloorItem && deletableFloorItem.uuid === asset.modelUuid) { + setDeletableFloorItem(null); + } + }, [activeTool, deletableFloorItem]); + + const handleContextMenu = (asset: Asset, evt: ThreeEvent) => { + if (rightDrag.current || toggleView) return; + if (activeTool === "cursor" && subModule === 'simulations') { + if (asset.modelUuid) { + const canvasElement = gl.domElement; + const isInProduct = getIsEventInProduct(selectedProduct.productUuid, asset.modelUuid); + if (isInProduct) { + const event = getEventByModelUuid(asset.modelUuid); + if (event) { + setSelectedAsset(event); + const canvasRect = canvasElement.getBoundingClientRect(); + const relativeX = evt.clientX - canvasRect.left; + const relativeY = evt.clientY - canvasRect.top; + setTop(relativeY); + setLeft(relativeX); + } else { + clearSelectedAsset(); + } + } else { + const event = getEventByModelUuid(asset.modelUuid); + if (event) { + setSelectedAsset(event) + const canvasRect = canvasElement.getBoundingClientRect(); + const relativeX = evt.clientX - canvasRect.left; + const relativeY = evt.clientY - canvasRect.top; + setTop(relativeY); + setLeft(relativeX); + } else { + clearSelectedAsset() + } + } + } else { + clearSelectedAsset() + } + } else { + clearSelectedAsset() + } + } + + return { + handleDblClick, + handleClick, + handlePointerOver, + handlePointerOut, + handleContextMenu + }; +} diff --git a/app/src/modules/scene/controls/selectionControls/selection3D/copyPasteControls3D.tsx b/app/src/modules/scene/controls/selectionControls/selection3D/copyPasteControls3D.tsx index 24a5f58..a147750 100644 --- a/app/src/modules/scene/controls/selectionControls/selection3D/copyPasteControls3D.tsx +++ b/app/src/modules/scene/controls/selectionControls/selection3D/copyPasteControls3D.tsx @@ -213,7 +213,7 @@ const CopyPasteControls3D = ({ modelUuid: pastedAsset.userData.modelUuid, modelName: pastedAsset.userData.modelName, assetId: pastedAsset.userData.assetId, - position: asset.position, + position: [position.x, position.y, position.z], rotation: { x: asset.rotation[0], y: asset.rotation[1], z: asset.rotation[2] }, isLocked: false, isVisible: true, diff --git a/app/src/modules/scene/controls/selectionControls/selection3D/duplicationControls3D.tsx b/app/src/modules/scene/controls/selectionControls/selection3D/duplicationControls3D.tsx index 5ab6b75..55e88fb 100644 --- a/app/src/modules/scene/controls/selectionControls/selection3D/duplicationControls3D.tsx +++ b/app/src/modules/scene/controls/selectionControls/selection3D/duplicationControls3D.tsx @@ -214,7 +214,7 @@ const DuplicationControls3D = ({ modelUuid: duplicatedAsset.userData.modelUuid, modelName: duplicatedAsset.userData.modelName, assetId: duplicatedAsset.userData.assetId, - position: asset.position, + position: [position.x, position.y, position.z], rotation: { x: asset.rotation[0], y: asset.rotation[1], z: asset.rotation[2] }, isLocked: false, isVisible: true, diff --git a/app/src/modules/simulation/actions/storageUnit/actionHandler/useRetrieveHandler.ts b/app/src/modules/simulation/actions/storageUnit/actionHandler/useRetrieveHandler.ts index e951289..0373fd0 100644 --- a/app/src/modules/simulation/actions/storageUnit/actionHandler/useRetrieveHandler.ts +++ b/app/src/modules/simulation/actions/storageUnit/actionHandler/useRetrieveHandler.ts @@ -3,9 +3,10 @@ import { useFrame } from "@react-three/fiber"; import { usePlayButtonStore, usePauseButtonStore, useResetButtonStore, useAnimationPlaySpeed } from "../../../../../store/usePlayButtonStore"; import { useSceneContext } from "../../../../scene/sceneContext"; import { useProductContext } from "../../../products/productContext"; +import { useHumanEventManager } from "../../../human/eventManager/useHumanEventManager"; export function useRetrieveHandler() { - const { materialStore, armBotStore, vehicleStore, storageUnitStore, productStore, humanStore, assetStore } = useSceneContext(); + const { materialStore, armBotStore, machineStore, vehicleStore, storageUnitStore, productStore, humanStore, assetStore } = useSceneContext(); const { selectedProductStore } = useProductContext(); const { addMaterial } = materialStore(); const { getModelUuidByActionUuid, getPointUuidByActionUuid, getEventByModelUuid, getActionByUuid } = productStore(); @@ -15,14 +16,17 @@ export function useRetrieveHandler() { const { getAssetById, setCurrentAnimation } = assetStore(); const { selectedProduct } = selectedProductStore(); const { getArmBotById, addCurrentAction } = armBotStore(); + const { getMachineById } = machineStore(); const { isPlaying } = usePlayButtonStore(); const { speed } = useAnimationPlaySpeed(); const { isPaused } = usePauseButtonStore(); const { isReset } = useResetButtonStore(); + const { addHumanToMonitor } = useHumanEventManager(); const [activeRetrievals, setActiveRetrievals] = useState>(new Map()); const retrievalTimeRef = useRef>(new Map()); const retrievalCountRef = useRef>(new Map()); + const monitoredHumansRef = useRef>(new Set()); const [initialDelayComplete, setInitialDelayComplete] = useState(false); const delayTimerRef = useRef(null); @@ -312,9 +316,94 @@ export function useRetrieveHandler() { } if (human && !human.isScheduled && human.state === 'idle' && human.currentLoad < action.loadCapacity) { - if (humanAsset?.animationState?.current === 'idle') { - setCurrentAnimation(human.modelUuid, 'pickup', true, false, false); - } else if (humanAsset?.animationState?.current === 'pickup' && humanAsset.animationState.isCompleted) { + const triggeredModel = action.triggers[0]?.triggeredAsset?.triggeredModel?.modelUuid + ? getEventByModelUuid(selectedProduct.productUuid, action.triggers[0].triggeredAsset.triggeredModel.modelUuid) + : null; + if (triggeredModel?.type === 'vehicle') { + const model = getVehicleById(triggeredModel.modelUuid); + if (model && !model.isActive && model.state === 'idle' && model.isPicking && model.currentLoad < model.point.action.loadCapacity) { + if (humanAsset?.animationState?.current === 'idle') { + setCurrentAnimation(human.modelUuid, 'pickup', true, false, false); + } else if (humanAsset?.animationState?.current === 'pickup' && humanAsset.animationState.isCompleted) { + const lastMaterial = getLastMaterial(storageUnit.modelUuid); + if (lastMaterial) { + const material = createNewMaterial( + lastMaterial.materialId, + lastMaterial.materialType, + storageUnit.point.action + ); + if (material) { + removeLastMaterial(storageUnit.modelUuid); + updateCurrentLoad(storageUnit.modelUuid, -1); + incrementHumanLoad(human.modelUuid, 1); + addCurrentMaterialToHuman(human.modelUuid, material.materialType, material.materialId); + retrieveLogStatus(material.materialName, `is picked by ${human.modelName}`); + + retrievalCountRef.current.set(actionUuid, currentCount + 1); + } + } + } + return; + } + } else if (triggeredModel?.type === 'roboticArm') { + const armBot = getArmBotById(triggeredModel.modelUuid); + if (armBot && !armBot.isActive && armBot.state === 'idle' && !armBot.currentAction) { + if (humanAsset?.animationState?.current === 'idle') { + setCurrentAnimation(human.modelUuid, 'pickup', true, false, false); + } else if (humanAsset?.animationState?.current === 'pickup' && humanAsset.animationState.isCompleted) { + const lastMaterial = getLastMaterial(storageUnit.modelUuid); + if (lastMaterial) { + const material = createNewMaterial( + lastMaterial.materialId, + lastMaterial.materialType, + storageUnit.point.action + ); + if (material) { + removeLastMaterial(storageUnit.modelUuid); + updateCurrentLoad(storageUnit.modelUuid, -1); + incrementHumanLoad(human.modelUuid, 1); + addCurrentMaterialToHuman(human.modelUuid, material.materialType, material.materialId); + retrieveLogStatus(material.materialName, `is picked by ${human.modelName}`); + + retrievalCountRef.current.set(actionUuid, currentCount + 1); + } + } + } + return; + } + } else if (triggeredModel?.type === 'machine') { + const machine = getMachineById(triggeredModel.modelUuid); + if (machine && !machine.isActive && machine.state === 'idle' && !machine.currentAction) { + if (!monitoredHumansRef.current.has(human.modelUuid)) { + addHumanToMonitor(human.modelUuid, () => { + if (humanAsset?.animationState?.current === 'idle') { + setCurrentAnimation(human.modelUuid, 'pickup', true, false, false); + } + }, action.actionUuid); + } + monitoredHumansRef.current.add(human.modelUuid); + if (humanAsset?.animationState?.current === 'pickup' && humanAsset.animationState.isCompleted) { + const lastMaterial = getLastMaterial(storageUnit.modelUuid); + if (lastMaterial) { + const material = createNewMaterial( + lastMaterial.materialId, + lastMaterial.materialType, + storageUnit.point.action + ); + if (material) { + removeLastMaterial(storageUnit.modelUuid); + updateCurrentLoad(storageUnit.modelUuid, -1); + incrementHumanLoad(human.modelUuid, 1); + addCurrentMaterialToHuman(human.modelUuid, material.materialType, material.materialId); + retrieveLogStatus(material.materialName, `is picked by ${human.modelName}`); + retrievalCountRef.current.set(actionUuid, currentCount + 1); + } + } + monitoredHumansRef.current.delete(human.modelUuid); + } + return; + } + } else if (triggeredModel?.type === 'storageUnit') { const lastMaterial = getLastMaterial(storageUnit.modelUuid); if (lastMaterial) { const material = createNewMaterial( diff --git a/app/src/modules/simulation/machine/instances/machineInstance/machineInstance.tsx b/app/src/modules/simulation/machine/instances/machineInstance/machineInstance.tsx index f45f909..879c985 100644 --- a/app/src/modules/simulation/machine/instances/machineInstance/machineInstance.tsx +++ b/app/src/modules/simulation/machine/instances/machineInstance/machineInstance.tsx @@ -116,7 +116,7 @@ function MachineInstance({ machineDetail }: { readonly machineDetail: MachineSta function handleCallBack() { if (currentPhase == "processing") { setMachineState(machineDetail.modelUuid, 'idle'); - setMachineActive(machineDetail.modelUuid, false); + setMachineActive(machineDetail.modelUuid, true); setCurrentPhase("idle") isIncrememtable.current = true; machineStatus(machineDetail.modelUuid, "Machine has completed the processing") diff --git a/app/src/modules/simulation/triggers/triggerHandler/useTriggerHandler.ts b/app/src/modules/simulation/triggers/triggerHandler/useTriggerHandler.ts index 4dc5ae2..04e7fa7 100644 --- a/app/src/modules/simulation/triggers/triggerHandler/useTriggerHandler.ts +++ b/app/src/modules/simulation/triggers/triggerHandler/useTriggerHandler.ts @@ -23,7 +23,7 @@ export function useTriggerHandler() { const { addHumanToMonitor } = useHumanEventManager(); const { getVehicleById } = vehicleStore(); const { getHumanById, setHumanScheduled } = humanStore(); - const { getMachineById } = machineStore(); + const { getMachineById, setMachineActive } = machineStore(); const { getStorageUnitById } = storageUnitStore(); const { getMaterialById, setCurrentLocation, setNextLocation, setPreviousLocation, setIsPaused, setIsVisible, setEndTime } = materialStore(); @@ -630,21 +630,24 @@ export function useTriggerHandler() { const previousModel = getEventByModelUuid(selectedProduct.productUuid, material.previous?.modelUuid || ''); if (previousModel) { if (previousModel.type === 'transfer' && previousModel.modelUuid === model.modelUuid) { + setMachineActive(trigger.triggerUuid, false); handleAction(action, materialId) } else { addConveyorToMonitor(conveyor.modelUuid, () => { - handleAction(action, materialId) + setMachineActive(trigger.triggerUuid, false); + handleAction(action, materialId); } ) } } else { - handleAction(action, materialId) + setMachineActive(trigger.triggerUuid, false); + handleAction(action, materialId); } - // handleAction(action, materialId) } } else { - handleAction(action, materialId) + setMachineActive(trigger.triggerUuid, false); + handleAction(action, materialId); } } else { @@ -660,21 +663,24 @@ export function useTriggerHandler() { const previousModel = getEventByModelUuid(selectedProduct.productUuid, material.previous?.modelUuid || ''); if (previousModel) { if (previousModel.type === 'transfer' && previousModel.modelUuid === model.modelUuid) { + setMachineActive(trigger.triggerUuid, false); handleAction(action, materialId) } else { addConveyorToMonitor(conveyor.modelUuid, () => { - handleAction(action, materialId) + setMachineActive(trigger.triggerUuid, false); + handleAction(action, materialId); } ) } } else { - handleAction(action, materialId) + setMachineActive(trigger.triggerUuid, false); + handleAction(action, materialId); } - // handleAction(action, materialId) } } else { - handleAction(action, materialId) + setMachineActive(trigger.triggerUuid, false); + handleAction(action, materialId); } } ); @@ -723,15 +729,18 @@ export function useTriggerHandler() { if (previousModel) { if (previousModel.type === 'transfer' && previousModel.modelUuid === model.modelUuid) { setHumanScheduled(human.modelUuid, true); + setMachineActive(trigger.triggerUuid, false); handleAction(action, materialId) } else { setHumanScheduled(human.modelUuid, true); addConveyorToMonitor(conveyor.modelUuid, () => { + setMachineActive(trigger.triggerUuid, false); handleAction(action, materialId) }) } } else { setHumanScheduled(human.modelUuid, true); + setMachineActive(trigger.triggerUuid, false); handleAction(action, materialId) } } @@ -742,6 +751,7 @@ export function useTriggerHandler() { // Handle current action from vehicle setIsPaused(materialId, true); setHumanScheduled(human.modelUuid, true); + setMachineActive(trigger.triggerUuid, false); handleAction(action, materialId); } else { @@ -750,12 +760,14 @@ export function useTriggerHandler() { setHumanScheduled(human.modelUuid, true); addVehicleToMonitor(vehicle.modelUuid, () => { + setMachineActive(trigger.triggerUuid, false); handleAction(action, materialId); }) } } } else { setHumanScheduled(human.modelUuid, true); + setMachineActive(trigger.triggerUuid, false); handleAction(action, materialId) } }, action.actionUuid);