import React, { useEffect, useState } from 'react'; import { useSelectedAction, useSelectedEventSphere, useSelectedProduct } from '../../../../store/simulation/useSimulationStore'; import { useGLTF } from '@react-three/drei'; import { useThree } from '@react-three/fiber'; import { useProductStore } from '../../../../store/simulation/useProductStore'; import { useArmBotStore } from '../../../../store/simulation/useArmBotStore'; import PickDropPoints from './PickDropPoints'; import useDraggableGLTF from './useDraggableGLTF'; import * as THREE from 'three'; import armPick from "../../../../assets/gltf-glb/ui/arm_ui_pick.glb"; import armDrop from "../../../../assets/gltf-glb/ui/arm_ui_drop.glb"; import { upsertProductOrEventApi } from '../../../../services/simulation/UpsertProductOrEventApi'; type Positions = { pick: [number, number, number]; drop: [number, number, number]; default: [number, number, number]; }; const ArmBotUI = () => { const { getEventByModelUuid, updateAction, getActionByUuid } = useProductStore(); const { selectedEventSphere } = useSelectedEventSphere(); const { selectedProduct } = useSelectedProduct(); const { scene } = useThree(); const { selectedAction } = useSelectedAction(); const { armBots } = useArmBotStore(); const armUiPick = useGLTF(armPick) as any; const armUiDrop = useGLTF(armDrop) as any; const [startPosition, setStartPosition] = useState<[number, number, number] | null>([0, 0, 0]); const [endPosition, setEndPosition] = useState<[number, number, number] | null>([0, 0, 0]); const [selectedArmBotData, setSelectedArmBotData] = useState(null); 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 }) } // Fetch and setup selected ArmBot data useEffect(() => { if (selectedEventSphere) { const selectedArmBot = getEventByModelUuid(selectedProduct.productId, selectedEventSphere.userData.modelUuid); if (selectedArmBot?.type === "roboticArm" && selectedAction.actionId) { setSelectedArmBotData(selectedArmBot); const defaultPositions = getDefaultPositions(selectedArmBot.modelUuid); const matchingAction = getActionByUuid(selectedProduct.productId, selectedAction.actionId); if (matchingAction && (matchingAction as RoboticArmPointSchema["actions"][0]).process) { const startPoint = (matchingAction as RoboticArmPointSchema["actions"][0]).process.startPoint; const pickPosition = (!startPoint || (Array.isArray(startPoint) && startPoint.every(v => v === 0))) ? defaultPositions.pick : startPoint; const endPoint = (matchingAction as RoboticArmPointSchema["actions"][0]).process.endPoint; const dropPosition = (!endPoint || (Array.isArray(endPoint) && endPoint.every(v => v === 0))) ? defaultPositions.drop : endPoint; setStartPosition(pickPosition); setEndPosition(dropPosition); } } } }, [armBots, selectedEventSphere, selectedProduct, getEventByModelUuid, selectedAction]); function getDefaultPositions(modelUuid: string): Positions { const modelData = getEventByModelUuid(selectedProduct.productId, modelUuid); if (modelData?.type === "roboticArm") { const baseX = modelData.point.position?.[0] || 0; const baseY = modelData.point.position?.[1] || 0;; const baseZ = modelData.point.position?.[2] || 0; return { pick: [baseX, baseY, baseZ + 0.5], drop: [baseX, baseY, baseZ - 0.5], default: [baseX, baseY, baseZ], }; } return { pick: [0.5, 1.5, 0], drop: [-0.5, 1.5, 0], default: [0, 1.5, 0], }; } function getLocalPosition(parentUuid: string, worldPosArray: [number, number, number] | null): [number, number, number] | null { if (worldPosArray) { const worldPos = new THREE.Vector3(...worldPosArray); const parentObject = scene.getObjectByProperty('uuid', parentUuid); if (parentObject) { const localPos = worldPos.clone(); parentObject.worldToLocal(localPos); return [localPos.x, localPos.y, localPos.z]; } } return null; } const updatePointToState = (obj: THREE.Object3D) => { const { modelUuid, actionType, actionUuid } = obj.userData; const newPosition = new THREE.Vector3(); obj.getWorldPosition(newPosition); const worldPositionArray = newPosition.toArray() as [number, number, number]; if (selectedEventSphere) { const selectedArmBot = getEventByModelUuid(selectedProduct.productId, selectedEventSphere.userData.modelUuid); const armBot = selectedArmBot?.modelUuid === modelUuid ? selectedArmBot : null; if (!armBot) return; if (armBot.type === "roboticArm") { armBot?.point?.actions?.map((action) => { if (action.actionUuid === actionUuid) { const updatedProcess = { ...action.process }; if (actionType === "pick") { updatedProcess.startPoint = getLocalPosition(modelUuid, worldPositionArray); setStartPosition(updatedProcess.startPoint) } else if (actionType === "drop") { updatedProcess.endPoint = getLocalPosition(modelUuid, worldPositionArray); setEndPosition(updatedProcess.endPoint) } const event = updateAction(selectedProduct.productId, actionUuid, { actionUuid: action.actionUuid, process: updatedProcess, } ) if (event) { updateBackend( selectedProduct.productName, selectedProduct.productId, organization, event ); } return { ...action, process: updatedProcess, }; } return action; }); } } } const { handlePointerDown } = useDraggableGLTF(updatePointToState); if (!selectedArmBotData || !Array.isArray(selectedArmBotData.point?.actions)) { return null; // avoid rendering if no data yet } return ( <> {selectedArmBotData.point.actions.map((action: any) => { if (action.actionUuid === selectedAction.actionId) { return ( {startPosition && endPosition && ( <> )} ); } else { return null; // important! must return something } })} ); }; export default ArmBotUI;