Files
Dwinzo_dev/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx
Jerald-Golden-B f37750023f Refactor FloorItemsGroup to integrate environment data retrieval and improve asset loading progress tracking
Enhance useRetrieveHandler to manage retrieval timing based on animation speed and arm bot state

Update materials component to streamline imports and improve readability

Modify roboticArmInstance to change state handling from 'idle' to 'running' during active phases

Fix useTriggerHandler to ensure actions are handled correctly when material is null

Refactor vehicleInstance to improve material drop handling and integrate conveyor and robotic arm interactions

Add getLastMaterial method to useVehicleStore for better material management in vehicle instances
2025-05-15 14:36:57 +05:30

319 lines
14 KiB
TypeScript

import React, { useEffect, useRef, useState } from 'react'
import * as THREE from "three";
import { useThree } from "@react-three/fiber";
import IKInstance from '../ikInstance/ikInstance';
import RoboticArmAnimator from '../animator/roboticArmAnimator';
import MaterialAnimator from '../animator/materialAnimator';
import armModel from "../../../../../assets/gltf-glb/rigged/ik_arm_1.glb";
import { usePauseButtonStore, usePlayButtonStore, useResetButtonStore } from '../../../../../store/usePlayButtonStore';
import { useMaterialStore } from '../../../../../store/simulation/useMaterialStore';
import { useArmBotStore } from '../../../../../store/simulation/useArmBotStore';
import { useProductStore } from '../../../../../store/simulation/useProductStore';
import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore';
import { useStorageUnitStore } from '../../../../../store/simulation/useStorageUnitStore';
import { useSelectedProduct } from '../../../../../store/simulation/useSimulationStore';
import { useTriggerHandler } from '../../../triggers/triggerHandler/useTriggerHandler';
function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
const [currentPhase, setCurrentPhase] = useState<(string)>("init");
const [path, setPath] = useState<[number, number, number][]>([]);
const [ikSolver, setIkSolver] = useState<any>(null);
const { scene } = useThree();
const restPosition = new THREE.Vector3(0, 1.75, -1.6);
const targetBone = "Target";
const groupRef = useRef<any>(null);
const pauseTimeRef = useRef<number | null>(null);
const isPausedRef = useRef<boolean>(false);
let startTime: number;
const { setArmBotActive, setArmBotState, removeCurrentAction } = useArmBotStore();
const { decrementVehicleLoad, removeLastMaterial } = useVehicleStore();
const { removeLastMaterial: removeLastStorageMaterial, updateCurrentLoad } = useStorageUnitStore();
const { setIsVisible, getMaterialById } = useMaterialStore();
const { selectedProduct } = useSelectedProduct();
const { getActionByUuid, getEventByActionUuid, getEventByModelUuid } = useProductStore();
const { triggerPointActions } = useTriggerHandler();
const { isPlaying } = usePlayButtonStore();
const { isReset } = useResetButtonStore();
const { isPaused } = usePauseButtonStore();
function firstFrame() {
startTime = performance.now();
step();
}
const action = getActionByUuid(selectedProduct.productId, armBot.currentAction?.actionUuid || '');
const handlePickUpTrigger = () => {
if (armBot.currentAction && armBot.currentAction.materialId) {
const material = getMaterialById(armBot.currentAction.materialId);
if (material && material.previous && material.previous.modelUuid) {
const previousModel = getEventByActionUuid(selectedProduct.productId, material.previous.actionUuid);
if (previousModel) {
if (previousModel.type === 'transfer') {
setIsVisible(armBot.currentAction.materialId, false);
} else if (previousModel.type === 'machine') {
// machine specific logic
} else if (previousModel.type === 'vehicle') {
decrementVehicleLoad(previousModel.modelUuid, 1);
removeLastMaterial(previousModel.modelUuid);
} else if (previousModel.type === 'storageUnit') {
// storage unit logic
removeLastStorageMaterial(previousModel.modelUuid);
updateCurrentLoad(previousModel.modelUuid, -1)
}
} else {
setIsVisible(armBot.currentAction.materialId, false);
}
} else {
setIsVisible(armBot.currentAction.materialId, false);
}
}
}
const handleDropTrigger = () => {
if (armBot.currentAction) {
const action = getActionByUuid(selectedProduct.productId, armBot.currentAction.actionUuid);
if (action && action.triggers[0].triggeredAsset?.triggeredModel.modelUuid) {
const model = getEventByModelUuid(selectedProduct.productId, action?.triggers[0].triggeredAsset?.triggeredModel.modelUuid);
if (!model) return;
if (model.type === 'transfer') {
setIsVisible(armBot.currentAction.materialId || '', true);
} else if (model.type === 'machine') {
//
} else if (model.type === 'vehicle') {
//
} else if (model.type === 'storageUnit') {
//
}
}
if (action && armBot.currentAction.materialId) {
triggerPointActions(action, armBot.currentAction.materialId)
removeCurrentAction(armBot.modelUuid)
}
}
}
function step() {
if (isPausedRef.current) {
if (!pauseTimeRef.current) {
pauseTimeRef.current = performance.now();
}
requestAnimationFrame(() => step());
return;
}
if (pauseTimeRef.current) {
const pauseDuration = performance.now() - pauseTimeRef.current;
startTime += pauseDuration;
pauseTimeRef.current = null;
}
const elapsedTime = performance.now() - startTime;
if (elapsedTime < 1000) {
// Wait until 1500ms has passed
requestAnimationFrame(step);
return;
}
if (currentPhase === "picking") {
setArmBotActive(armBot.modelUuid, true);
setArmBotState(armBot.modelUuid, "running");
setCurrentPhase("start-to-end");
startTime = 0
if (!action) return;
const startPoint = (action as RoboticArmAction).process.startPoint;
const endPoint = (action as RoboticArmAction).process.endPoint;
if (startPoint && endPoint) {
let curve = createCurveBetweenTwoPoints(
new THREE.Vector3(startPoint[0], startPoint[1], startPoint[2]),
new THREE.Vector3(endPoint[0], endPoint[1], endPoint[2]));
if (curve) {
logStatus(armBot.modelUuid, "picking the object");
setPath(curve.points.map(point => [point.x, point.y, point.z]))
handlePickUpTrigger();
}
}
logStatus(armBot.modelUuid, "Moving armBot from start point to end position.")
} else if (currentPhase === "dropping") {
setArmBotActive(armBot.modelUuid, true);
setArmBotState(armBot.modelUuid, "running");
setCurrentPhase("end-to-rest");
startTime = 0;
if (!action) return;
const endPoint = (action as RoboticArmAction).process.endPoint;
if (endPoint) {
let curve = createCurveBetweenTwoPoints(new THREE.Vector3(endPoint[0], endPoint[1], endPoint[2]), restPosition);
if (curve) {
logStatus(armBot.modelUuid, "dropping the object");
setPath(curve.points.map(point => [point.x, point.y, point.z]));
handleDropTrigger();
}
}
logStatus(armBot.modelUuid, "Moving armBot from end point to rest position.")
}
}
useEffect(() => {
isPausedRef.current = isPaused;
}, [isPaused]);
useEffect(() => {
if (isReset || !isPlaying) {
logStatus(armBot.modelUuid, "Simulation Play Reset Successfully")
setArmBotActive(armBot.modelUuid, false)
setArmBotState(armBot.modelUuid, "idle")
setCurrentPhase("init");
setPath([])
setIkSolver(null);
removeCurrentAction(armBot.modelUuid)
isPausedRef.current = false
pauseTimeRef.current = null
startTime = 0
const targetBones = ikSolver?.mesh.skeleton.bones.find((b: any) => b.name === targetBone
);
if (targetBones && isPlaying) {
let curve = createCurveBetweenTwoPoints(targetBones.position, restPosition)
if (curve) {
setPath(curve.points.map(point => [point.x, point.y, point.z]));
logStatus(armBot.modelUuid, "Moving armBot from initial point to rest position.")
}
}
}
}, [isReset, isPlaying])
useEffect(() => {
const targetMesh = scene?.getObjectByProperty("uuid", armBot.modelUuid);
if (targetMesh) {
targetMesh.visible = (!isPlaying)
}
const targetBones = ikSolver?.mesh.skeleton.bones.find((b: any) => b.name === targetBone);
if (!isReset && isPlaying) {
//Moving armBot from initial point to rest position.
if (!armBot?.isActive && armBot?.state == "idle" && currentPhase == "init") {
if (targetBones) {
setArmBotActive(armBot.modelUuid, true)
setArmBotState(armBot.modelUuid, "running")
setCurrentPhase("init-to-rest");
let curve = createCurveBetweenTwoPoints(targetBones.position, restPosition)
if (curve) {
setPath(curve.points.map(point => [point.x, point.y, point.z]));
}
}
logStatus(armBot.modelUuid, "Moving armBot from initial point to rest position.")
}
//Waiting for trigger.
else if (armBot && !armBot.isActive && armBot.state === "idle" && currentPhase === "rest" && !armBot.currentAction) {
logStatus(armBot.modelUuid, "Waiting to trigger CurrentAction")
}
//Moving to pickup point
else if (armBot && !armBot.isActive && armBot.state === "idle" && currentPhase === "rest" && armBot.currentAction) {
if (armBot.currentAction) {
setArmBotActive(armBot.modelUuid, true);
setArmBotState(armBot.modelUuid, "running");
setCurrentPhase("rest-to-start");
if (!action) return;
const startPoint = (action as RoboticArmAction).process.startPoint;
if (startPoint) {
let curve = createCurveBetweenTwoPoints(targetBones.position, new THREE.Vector3(startPoint[0], startPoint[1], startPoint[2]));
if (curve) {
setPath(curve.points.map(point => [point.x, point.y, point.z]));
}
}
}
logStatus(armBot.modelUuid, "Moving armBot from rest point to start position.")
}
// Moving to Pick to Drop position
else if (armBot && !armBot.isActive && armBot.state === "running" && currentPhase === "picking" && armBot.currentAction) {
requestAnimationFrame(firstFrame);
}
//Moving to drop point to restPosition
else if (armBot && !armBot.isActive && armBot.state === "running" && currentPhase === "dropping" && armBot.currentAction) {
requestAnimationFrame(firstFrame);
}
} else {
logStatus(armBot.modelUuid, "Simulation Play Exited")
setArmBotActive(armBot.modelUuid, false)
setArmBotState(armBot.modelUuid, "idle")
setCurrentPhase("init");
setIkSolver(null);
setPath([])
isPausedRef.current = false
pauseTimeRef.current = null
isPausedRef.current = false
startTime = 0
removeCurrentAction(armBot.modelUuid)
}
}, [currentPhase, armBot, isPlaying, isReset, ikSolver])
function createCurveBetweenTwoPoints(p1: any, p2: any) {
const mid = new THREE.Vector3().addVectors(p1, p2).multiplyScalar(0.5);
const points = [p1, mid, p2];
return new THREE.CatmullRomCurve3(points);
}
const HandleCallback = () => {
if (armBot.isActive && armBot.state == "running" && currentPhase == "init-to-rest") {
logStatus(armBot.modelUuid, "Callback triggered: rest");
setArmBotActive(armBot.modelUuid, false)
setArmBotState(armBot.modelUuid, "idle")
setCurrentPhase("rest");
setPath([])
}
else if (armBot.isActive && armBot.state == "running" && currentPhase == "rest-to-start") {
logStatus(armBot.modelUuid, "Callback triggered: pick.");
setArmBotActive(armBot.modelUuid, false)
setArmBotState(armBot.modelUuid, "running")
setCurrentPhase("picking");
setPath([])
}
else if (armBot.isActive && armBot.state == "running" && currentPhase == "start-to-end") {
logStatus(armBot.modelUuid, "Callback triggered: drop.");
setArmBotActive(armBot.modelUuid, false)
setArmBotState(armBot.modelUuid, "running")
setCurrentPhase("dropping");
setPath([])
}
else if (armBot.isActive && armBot.state == "running" && currentPhase == "end-to-rest") {
logStatus(armBot.modelUuid, "Callback triggered: rest, cycle completed.");
setArmBotActive(armBot.modelUuid, false)
setArmBotState(armBot.modelUuid, "idle")
setCurrentPhase("rest");
setPath([])
}
}
const logStatus = (id: string, status: string) => {
// console.log('status: ', status);
}
return (
<>
{!isReset && isPlaying && (
<>
<IKInstance modelUrl={armModel} setIkSolver={setIkSolver} ikSolver={ikSolver} armBot={armBot} groupRef={groupRef} />
<RoboticArmAnimator
HandleCallback={HandleCallback}
restPosition={restPosition}
ikSolver={ikSolver}
targetBone={targetBone}
armBot={armBot}
logStatus={logStatus}
path={path}
currentPhase={currentPhase}
/>
</>
)}
<MaterialAnimator ikSolver={ikSolver} armBot={armBot} currentPhase={currentPhase} />
</>
)
}
export default RoboticArmInstance;