From fe57e6c8739d35b702378a2bd5d6803c2e7f9dae Mon Sep 17 00:00:00 2001 From: Gomathi9520 Date: Tue, 29 Apr 2025 19:01:06 +0530 Subject: [PATCH 1/8] playSpeed,reset,exit added and armbot movemets added --- .../instances/animator/roboticArmAnimator.tsx | 147 +++-- .../armInstance/roboticArmInstance.tsx | 567 +++++++++++++++--- .../instances/ikInstance/ikInstance.tsx | 17 +- .../instances/roboticArmInstances.tsx | 2 +- .../simulation/roboticArm/roboticArm.tsx | 4 +- .../simulation/ui/arm/useDraggableGLTF.ts | 2 +- 6 files changed, 576 insertions(+), 163 deletions(-) diff --git a/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx b/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx index c82b73d..611ded5 100644 --- a/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx +++ b/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx @@ -1,68 +1,117 @@ -import React, { useEffect, useMemo, useRef, useState } from 'react' -import { useArmBotStore } from '../../../../../store/simulation/useArmBotStore'; -import { useFrame, useThree } from '@react-three/fiber'; -import * as THREE from "three" -import { usePlayButtonStore } from '../../../../../store/usePlayButtonStore'; +import React, { useEffect, useRef, useState } from 'react'; +import { useFrame } from '@react-three/fiber'; +import * as THREE from 'three'; +import { + useAnimationPlaySpeed, + usePauseButtonStore, + usePlayButtonStore, + useResetButtonStore +} from '../../../../../store/usePlayButtonStore'; +import { Line } from '@react-three/drei'; -function RoboticArmAnimator({ armUuid, HandleCallback, currentPhase, ikSolver, targetBone, robot, logStatus, groupRef, processes, armBotCurveRef, path }: any) { - const { armBots } = useArmBotStore(); - const { scene } = useThree(); - const restSpeed = 0.1; - const restPosition = new THREE.Vector3(0, 1, -1.6); - const initialCurveRef = useRef(null); - const initialStartPositionRef = useRef(null); - const [initialProgress, setInitialProgress] = useState(0); - const [progress, setProgress] = useState(0); - const [needsInitialMovement, setNeedsInitialMovement] = useState(true); - const [isInitializing, setIsInitializing] = useState(true); - const { isPlaying } = usePlayButtonStore(); - const statusRef = useRef("idle"); - // Create a ref for initialProgress - const initialProgressRef = useRef(0); +function RoboticArmAnimator({ + HandleCallback, + restPosition, + ikSolver, + targetBone, + armBot, + logStatus, + path +}: any) { + const progressRef = useRef(0); + const curveRef = useRef(null); const [currentPath, setCurrentPath] = useState<[number, number, number][]>([]); + const [curvePoints, setCurvePoints] = useState(null); + + // Zustand stores + const { isPlaying } = usePlayButtonStore(); + const { isPaused } = usePauseButtonStore(); + const { isReset } = useResetButtonStore(); // optional use depending on your logic + const { speed } = useAnimationPlaySpeed(); useEffect(() => { - setCurrentPath(path) }, [path]) useEffect(() => { + if (!isPlaying) { + setCurrentPath([]) + curveRef.current = null + } + }, [isPlaying]) - }, [currentPath]) + useEffect(() => { + if (currentPath && currentPath.length === 3) { + const [start, mid, end] = currentPath; + const points = [ + new THREE.Vector3(start[0], start[1], start[2]), + new THREE.Vector3(start[0], mid[1] + 0.5, start[2]), + new THREE.Vector3(mid[0], mid[1] + 0.5, mid[2]), + new THREE.Vector3(mid[0], end[1] + 0.5, mid[2]), + new THREE.Vector3(end[0], end[1], end[2]) + ]; + const generatedCurve = new THREE.CatmullRomCurve3(points, false, 'centripetal', 1).getPoints(100); + // console.log('generatedCurve: ', generatedCurve); + curveRef.current = generatedCurve; + setCurvePoints(generatedCurve); + + } + }, [currentPath]); useFrame((_, delta) => { - if (!ikSolver || !currentPath || currentPath.length === 0) return; + if (ikSolver && curveRef.current && currentPath.length >= 0) { + const bone = ikSolver.mesh.skeleton.bones.find( + (b: any) => b.name === targetBone + ); + if (!bone) return; - const bone = ikSolver.mesh.skeleton.bones.find( - (b: any) => b.name === targetBone - ); - if (!bone) return; + if (isPlaying) { + if (!isPaused) { + const curvePoints = curveRef.current; + const speedAdjustedProgress = progressRef.current + (speed * armBot.speed); + const index = Math.floor(speedAdjustedProgress); + if (index >= curvePoints.length) { + HandleCallback(); + setCurrentPath([]); + curveRef.current = null; + progressRef.current = 0; + } else { + const point = curvePoints[index]; + bone.position.copy(point); + progressRef.current = speedAdjustedProgress; + } + } + } else { + logStatus(armBot.modelUuid, 'Simulation Play Exited'); + // bone.position.copy(restPosition); + } - // Ensure currentPath is a valid array of 3D points, create a CatmullRomCurve3 from it - const curve = new THREE.CatmullRomCurve3( - currentPath.map(point => new THREE.Vector3(point[0], point[1], point[2])) - ); + ikSolver.update(); + } else if (ikSolver && !isPlaying && currentPath.length === 0) { + const bone = ikSolver.mesh.skeleton.bones.find( + (b: any) => b.name === targetBone + ); + bone.position.copy(restPosition); + ikSolver.update(); + }; - - const next = initialProgressRef.current + delta * 0.5; - if (next >= 1) { - // bone.position.copy(restPosition); - HandleCallback(); // Call the callback when the path is completed - initialProgressRef.current = 0; // Set ref to 1 when done - } else { - const point = curve.getPoint(next); // Get the interpolated point from the curve - bone.position.copy(point); // Update the bone position along the curve - initialProgressRef.current = next; // Update progress - } - - ikSolver.update(); }); - - return ( - <> - ) + <> + {/* {currentPath.length > 0 && ( + <> + + {currentPath.map((point, index) => ( + + + + + ))} + + )} */} + + ); } -export default RoboticArmAnimator; \ No newline at end of file +export default RoboticArmAnimator; diff --git a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx index 3fe8af1..5f00a45 100644 --- a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx +++ b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx @@ -1,42 +1,100 @@ import React, { useEffect, useRef, useState } from 'react' import IKInstance from '../ikInstance/ikInstance'; import RoboticArmAnimator from '../animator/roboticArmAnimator'; -import { usePlayButtonStore } from '../../../../../store/usePlayButtonStore'; +import { usePauseButtonStore, usePlayButtonStore, useResetButtonStore } from '../../../../../store/usePlayButtonStore'; import { useArmBotStore } from '../../../../../store/simulation/useArmBotStore'; import armModel from "../../../../../assets/gltf-glb/rigged/ik_arm_4.glb"; import { useThree } from "@react-three/fiber"; import { useFloorItems } from '../../../../../store/store'; import useModuleStore from '../../../../../store/useModuleStore'; -import { Vector3 } from "three"; import * as THREE from "three"; -interface Process { - triggerId: string; - startPoint?: Vector3; - endPoint?: Vector3; - speed: number; -} +function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { -function RoboticArmInstance({ robot }: { robot: ArmBotStatus }) { - - const { isPlaying } = usePlayButtonStore(); const [currentPhase, setCurrentPhase] = useState<(string)>("init"); - const { scene } = useThree(); - const targetBone = "Target"; - const { activeModule } = useModuleStore(); + const [path, setPath] = useState<[number, number, number][]>([]); const [ikSolver, setIkSolver] = useState(null); + const { scene } = useThree(); + const restPosition = new THREE.Vector3(0, 1.75, -1.6); + const targetBone = "Target"; + const groupRef = useRef(null); + const pauseTimeRef = useRef(null); + const isPausedRef = useRef(false); + let startTime: number; + //zustand const { addCurrentAction, setArmBotActive, setArmBotState, removeCurrentAction } = useArmBotStore(); const { floorItems } = useFloorItems(); - const groupRef = useRef(null); - const [processes, setProcesses] = useState([]); - const [armBotCurvePoints, setArmBotCurvePoints] = useState({ start: [], end: [] }) - const restPosition = new THREE.Vector3(0, 1, -1.6); - let armBotCurveRef = useRef(null) - const [path, setPath] = useState<[number, number, number][]>([]); + const { activeModule } = useModuleStore(); + const { isPlaying } = usePlayButtonStore(); + const { isReset, setReset } = useResetButtonStore(); + const { isPaused } = usePauseButtonStore(); + + function firstFrame() { + startTime = performance.now(); + step(); + } + 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 < 1500) { + // 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 + const startPoint = armBot.point.actions[0].process.startPoint; + const endPoint = armBot.point.actions[0].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])) + } + } + 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; + const endPoint = armBot.point.actions[0].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])); + } + } + logStatus(armBot.modelUuid, "Moving armBot from end point to rest position.") + } + + } + useEffect(() => { + isPausedRef.current = isPaused; + }, [isPaused]); useEffect(() => { let armItems = floorItems?.filter((val: any) => - val.modeluuid === "3abf5d46-b59e-4e6b-9c02-a4634b64b82d" + val.modeluuid === armBot.modelUuid ); // Get the first matching item let armItem = armItems?.[0]; @@ -49,13 +107,30 @@ function RoboticArmInstance({ robot }: { robot: ArmBotStatus }) { const targetBones = ikSolver?.mesh.skeleton.bones.find( (b: any) => b.name === targetBone ); - + if (isReset) { + logStatus(armBot.modelUuid, "Simulation Play Reset Successfully") + removeCurrentAction(armBot.modelUuid) + setArmBotActive(armBot.modelUuid, true) + setArmBotState(armBot.modelUuid, "running") + setCurrentPhase("init-to-rest"); + isPausedRef.current=false + pauseTimeRef.current=null + isPausedRef.current=false + startTime=0 + if (targetBones) { + let curve = createCurveBetweenTwoPoints(targetBones.position, restPosition) + if (curve) { + setPath(curve.points.map(point => [point.x, point.y, point.z])); + } + } + setReset(false); + logStatus(armBot.modelUuid, "Moving armBot from initial point to rest position.") + } if (isPlaying) { //Moving armBot from initial point to rest position. - if (!robot?.isActive && robot?.state == "idle" && currentPhase == "init") { - - setArmBotActive(robot.modelUuid, true) - setArmBotState(robot.modelUuid, "running") + if (!armBot?.isActive && armBot?.state == "idle" && currentPhase == "init") { + setArmBotActive(armBot.modelUuid, true) + setArmBotState(armBot.modelUuid, "running") setCurrentPhase("init-to-rest"); if (targetBones) { let curve = createCurveBetweenTwoPoints(targetBones.position, restPosition) @@ -63,21 +138,22 @@ function RoboticArmInstance({ robot }: { robot: ArmBotStatus }) { setPath(curve.points.map(point => [point.x, point.y, point.z])); } } - logStatus(robot.modelUuid, "Moving armBot from initial point to rest position.") + logStatus(armBot.modelUuid, "Moving armBot from initial point to rest position.") } //Waiting for trigger. - else if (robot && !robot.isActive && robot.state === "idle" && currentPhase === "rest" && !robot.currentAction) { - logStatus(robot.modelUuid, "Waiting to trigger CurrentAction") - setTimeout(() => { - addCurrentAction(robot.modelUuid, 'action-003'); + else if (armBot && !armBot.isActive && armBot.state === "idle" && currentPhase === "rest" && !armBot.currentAction) { + logStatus(armBot.modelUuid, "Waiting to trigger CurrentAction") + const timeoutId = setTimeout(() => { + addCurrentAction(armBot.modelUuid, 'action-003'); }, 3000); + return () => clearTimeout(timeoutId); } - else if (robot && !robot.isActive && robot.state === "idle" && currentPhase === "rest" && robot.currentAction) { - if (robot.currentAction) { - setArmBotActive(robot.modelUuid, true); - setArmBotState(robot.modelUuid, "running"); + 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"); - const startPoint = robot.point.actions[0].process.startPoint; + const startPoint = armBot.point.actions[0].process.startPoint; if (startPoint) { let curve = createCurveBetweenTwoPoints(restPosition, new THREE.Vector3(startPoint[0], startPoint[1], startPoint[2])); if (curve) { @@ -85,105 +161,396 @@ function RoboticArmInstance({ robot }: { robot: ArmBotStatus }) { } } } - logStatus(robot.modelUuid, "Moving armBot from rest point to start position.") + logStatus(armBot.modelUuid, "Moving armBot from rest point to start position.") } - else if (robot && !robot.isActive && robot.state === "idle" && currentPhase === "picking" && robot.currentAction) { - setArmBotActive(robot.modelUuid, true); - setArmBotState(robot.modelUuid, "running"); - setCurrentPhase("start-to-end"); - const startPoint = robot.point.actions[0].process.startPoint; - const endPoint = robot.point.actions[0].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) { - setTimeout(() => { - logStatus(robot.modelUuid, "picking the object"); - setPath(curve.points.map(point => [point.x, point.y, point.z])); - }, 1500) - } - } - logStatus(robot.modelUuid, "Moving armBot from start point to end position.") + else if (armBot && !armBot.isActive && armBot.state === "idle" && currentPhase === "picking" && armBot.currentAction) { + requestAnimationFrame(firstFrame); + // setArmBotActive(armBot.modelUuid, true); + // setArmBotState(armBot.modelUuid, "running"); + // setCurrentPhase("start-to-end"); + // const startPoint = armBot.point.actions[0].process.startPoint; + // const endPoint = armBot.point.actions[0].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) { + // setTimeout(() => { + // logStatus(armBot.modelUuid, "picking the object"); + // setPath(curve.points.map(point => [point.x, point.y, point.z])); + // }, 1500) + // } + // } + // logStatus(armBot.modelUuid, "Moving armBot from start point to end position.") } - else if (robot && !robot.isActive && robot.state === "idle" && currentPhase === "dropping" && robot.currentAction) { - setArmBotActive(robot.modelUuid, true); - setArmBotState(robot.modelUuid, "running"); - setCurrentPhase("end-to-rest"); - const endPoint = robot.point.actions[0].process.endPoint; - if (endPoint) { - let curve = createCurveBetweenTwoPoints(new THREE.Vector3(endPoint[0], endPoint[1], endPoint[2]), restPosition - ); - if (curve) { - setTimeout(() => { - logStatus(robot.modelUuid, "dropping the object"); - setPath(curve.points.map(point => [point.x, point.y, point.z])); - }, 1500) - } - } - logStatus(robot.modelUuid, "Moving armBot from end point to rest position.") + else if (armBot && !armBot.isActive && armBot.state === "idle" && currentPhase === "dropping" && armBot.currentAction) { + requestAnimationFrame(firstFrame); + // setArmBotActive(armBot.modelUuid, true); + // setArmBotState(armBot.modelUuid, "running"); + // setCurrentPhase("end-to-rest"); + // const endPoint = armBot.point.actions[0].process.endPoint; + // if (endPoint) { + // let curve = createCurveBetweenTwoPoints(new THREE.Vector3(endPoint[0], endPoint[1], endPoint[2]), restPosition); + // if (curve) { + // setTimeout(() => { + // logStatus(armBot.modelUuid, "dropping the object"); + // setPath(curve.points.map(point => [point.x, point.y, point.z])); + // }, 1500) + // } + // } + // logStatus(armBot.modelUuid, "Moving armBot from end point to rest position.") } + } else { + logStatus(armBot.modelUuid, "Simulation Play Stopped") + setArmBotActive(armBot.modelUuid, false) + setArmBotState(armBot.modelUuid, "idle") + setCurrentPhase("init"); + setPath([]) + removeCurrentAction(armBot.modelUuid) + } - }, [currentPhase, robot, isPlaying, ikSolver]) + }, [currentPhase, armBot, isPlaying, ikSolver, isReset]) function createCurveBetweenTwoPoints(p1: any, p2: any) { const mid = new THREE.Vector3().addVectors(p1, p2).multiplyScalar(0.5); - mid.y += 0.5; - + // mid.y += 0.5; const points = [p1, mid, p2]; return new THREE.CatmullRomCurve3(points); } const HandleCallback = () => { - if (robot.isActive && robot.state == "running" && currentPhase == "init-to-rest") { - logStatus(robot.modelUuid, "Callback triggered: rest"); - setArmBotActive(robot.modelUuid, false) - setArmBotState(robot.modelUuid, "idle") + 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 (robot.isActive && robot.state == "running" && currentPhase == "rest-to-start") { - logStatus(robot.modelUuid, "Callback triggered: pick."); - setArmBotActive(robot.modelUuid, false) - setArmBotState(robot.modelUuid, "idle") + else if (armBot.isActive && armBot.state == "running" && currentPhase == "rest-to-start") { + logStatus(armBot.modelUuid, "Callback triggered: pick."); + setArmBotActive(armBot.modelUuid, false) + setArmBotState(armBot.modelUuid, "idle") setCurrentPhase("picking"); setPath([]) } - else if (robot.isActive && robot.state == "running" && currentPhase == "start-to-end") { - logStatus(robot.modelUuid, "Callback triggered: drop."); - setArmBotActive(robot.modelUuid, false) - setArmBotState(robot.modelUuid, "idle") + else if (armBot.isActive && armBot.state == "running" && currentPhase == "start-to-end") { + logStatus(armBot.modelUuid, "Callback triggered: drop."); + setArmBotActive(armBot.modelUuid, false) + setArmBotState(armBot.modelUuid, "idle") setCurrentPhase("dropping"); setPath([]) } - else if (robot.isActive && robot.state == "running" && currentPhase == "end-to-rest") { - logStatus(robot.modelUuid, "Callback triggered: rest, cycle completed."); - setArmBotActive(robot.modelUuid, false) - setArmBotState(robot.modelUuid, "idle") + 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([]) - removeCurrentAction(robot.modelUuid) + removeCurrentAction(armBot.modelUuid) } } const logStatus = (id: string, status: string) => { - // console.log(id + "," + status); - console.log( status); + // console.log('status: ', status); } return ( <> - - + + ) } -export default RoboticArmInstance; \ No newline at end of file +export default RoboticArmInstance; + + + + + + + + + + + + +// import React, { useEffect, useRef, useState } from 'react'; +// import IKInstance from '../ikInstance/ikInstance'; +// import RoboticArmAnimator from '../animator/roboticArmAnimator'; +// import { usePlayButtonStore, useResetButtonStore } from '../../../../../store/usePlayButtonStore'; +// import { useArmBotStore } from '../../../../../store/simulation/useArmBotStore'; +// import armModel from "../../../../../assets/gltf-glb/rigged/ik_arm_4.glb"; +// import { useThree } from "@react-three/fiber"; +// import { useFloorItems } from '../../../../../store/store'; +// import useModuleStore from '../../../../../store/useModuleStore'; +// import * as THREE from "three"; + +// function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { + +// const [currentPhase, setCurrentPhase] = useState("init"); +// const [path, setPath] = useState<[number, number, number][]>([]); +// const [ikSolver, setIkSolver] = useState(null); +// const { scene } = useThree(); +// const restPosition = new THREE.Vector3(0, 1, -1.6); +// const targetBone = "Target"; +// const groupRef = useRef(null); + +// // Zustand Stores +// const { addCurrentAction, setArmBotActive, setArmBotState, removeCurrentAction } = useArmBotStore(); +// const { floorItems } = useFloorItems(); +// const { activeModule } = useModuleStore(); +// const { isPlaying } = usePlayButtonStore(); +// const { isReset, setReset } = useResetButtonStore(); + +// // Generate path according to constraints +// const generateArmPath = ( +// startPoint: [number, number, number], +// endPoint: [number, number, number], +// restPos: THREE.Vector3 = new THREE.Vector3(0, 1, -1.6) +// ): [number, number, number][] => { +// const path: [number, number, number][] = []; + +// const startVec = new THREE.Vector3(...startPoint); +// const endVec = new THREE.Vector3(...endPoint); + +// // Helper functions +// const addLinePoints = (from: THREE.Vector3, to: THREE.Vector3, segments: number) => { +// for (let i = 0; i <= segments; i++) { +// const t = i / segments; +// const point = new THREE.Vector3().lerpVectors(from, to, t); +// path.push([point.x, point.y, point.z]); +// } +// }; + +// const addCurveFromTo = (from: THREE.Vector3, to: THREE.Vector3, segments: number = 15) => { +// const mid = new THREE.Vector3() +// .addVectors(from, to) +// .multiplyScalar(0.5) +// .setY(Math.max(from.y, to.y) + 0.5); +// const curve = new THREE.CatmullRomCurve3([from, mid, to]); +// const points = curve.getPoints(segments); +// for (const p of points) { +// path.push([p.x, p.y, p.z]); +// } +// }; + +// // Step 1: Move vertically to align Y with start point +// const step1Start = startVec.clone().setY(restPos.y); +// const step1End = startVec.clone(); +// addLinePoints(step1Start, step1End, 10); + +// // Step 2: Move horizontally XZ to reach start point +// const step2Start = step1End.clone(); +// const step2End = startVec.clone(); // ✅ Fixed here +// addLinePoints(step2Start, step2End, 10); +// addLinePoints(step1End, step2End, 10); + +// // Optional Step 3: Move to rest/midpoint if needed +// const distanceToRest = startVec.distanceTo(restPos); +// if (distanceToRest > 1) { +// addCurveFromTo(step2End, restPos, 15); +// } + +// // Step 4: Move up/down to align Y with end point +// const step4Start = endVec.clone().setY(restPos.y); +// const step4End = endVec.clone(); +// addLinePoints(step4Start, step4End, 10); + +// // Step 5: Move horizontally XZ to end point +// addLinePoints(step4End, endVec.clone(), 10); + +// // Step 6: Return to rest or mid-position after dropping +// const finalRestHeight = restPos.clone().setY(endVec.y + 0.5); +// addCurveFromTo(endVec, finalRestHeight, 15); + +// return path; +// }; + +// useEffect(() => { +// let armItems = floorItems?.filter((val: any) => +// val.modeluuid === armBot.modelUuid +// ); +// let armItem = armItems?.[0]; +// if (armItem) { +// const targetMesh = scene?.getObjectByProperty("uuid", armItem.modeluuid); +// if (targetMesh) { +// targetMesh.visible = activeModule !== "simulation"; +// } +// } + +// const targetBones = ikSolver?.mesh.skeleton.bones.find( +// (b: any) => b.name === targetBone +// ); + +// if (isReset) { +// logStatus(armBot.modelUuid, "Simulation Play Reset Successfully"); +// removeCurrentAction(armBot.modelUuid); +// setArmBotActive(armBot.modelUuid, true); +// setArmBotState(armBot.modelUuid, "running"); +// setCurrentPhase("init-to-rest"); + +// if (targetBones) { +// const startPoint = new THREE.Vector3(targetBones.position.x, targetBones.position.y, targetBones.position.z); +// const curve = new THREE.CatmullRomCurve3([ +// startPoint, +// startPoint.clone().setY(restPosition.y + 0.5), +// restPosition.clone(), +// ]); +// setPath(curve.getPoints(30).map(p => [p.x, p.y, p.z])); +// } + +// setReset(false); +// logStatus(armBot.modelUuid, "Moving armBot from initial point to rest position."); +// } + +// if (isPlaying) { +// // Phase 1: Initial -> Rest +// if (!armBot.isActive && armBot.state === "idle" && currentPhase === "init") { +// setArmBotActive(armBot.modelUuid, true); +// setArmBotState(armBot.modelUuid, "running"); +// setCurrentPhase("init-to-rest"); + +// if (targetBones) { +// const startPoint = new THREE.Vector3(targetBones.position.x, targetBones.position.y, targetBones.position.z); +// const curve = new THREE.CatmullRomCurve3([ +// startPoint, +// startPoint.clone().setY(restPosition.y + 0.5), +// restPosition.clone(), +// ]); +// setPath(curve.getPoints(30).map(p => [p.x, p.y, p.z])); +// } + +// logStatus(armBot.modelUuid, "Moving armBot from initial point to rest position."); +// } + +// // Phase 2: Wait for trigger +// else if (!armBot.isActive && armBot.state === "idle" && currentPhase === "rest" && !armBot.currentAction) { +// logStatus(armBot.modelUuid, "Waiting to trigger CurrentAction"); +// const timeoutId = setTimeout(() => { +// addCurrentAction(armBot.modelUuid, 'action-003'); +// }, 3000); +// return () => clearTimeout(timeoutId); +// } + +// // Phase 3: Rest -> Start Point +// else if (!armBot.isActive && armBot.state === "idle" && currentPhase === "rest" && armBot.currentAction) { +// setArmBotActive(armBot.modelUuid, true); +// setArmBotState(armBot.modelUuid, "running"); +// setCurrentPhase("rest-to-start"); + +// const startPoint = armBot.point.actions[0].process.startPoint; +// if (startPoint) { +// const start = new THREE.Vector3(startPoint[0], startPoint[1], startPoint[2]); +// const curve = new THREE.CatmullRomCurve3([restPosition, restPosition.clone().setY(start.y), start]); +// setPath(curve.getPoints(30).map(p => [p.x, p.y, p.z])); +// } + +// logStatus(armBot.modelUuid, "Moving armBot from rest point to start position."); +// } + +// // Phase 4: Start -> End (Pick & Move Object) +// else if (!armBot.isActive && armBot.state === "idle" && currentPhase === "picking" && armBot.currentAction) { +// setArmBotActive(armBot.modelUuid, true); +// setArmBotState(armBot.modelUuid, "running"); +// setCurrentPhase("start-to-end"); + +// const startPoint = armBot.point.actions[0].process.startPoint; +// const endPoint = armBot.point.actions[0].process.endPoint; + +// if (startPoint && endPoint) { +// const path = generateArmPath(startPoint, endPoint, restPosition); +// logStatus(armBot.modelUuid, "Waiting to pick."); +// setTimeout(()=>{ +// setPath(path); +// },3000) +// } + +// logStatus(armBot.modelUuid, "Moving armBot from start point to end position."); +// } + +// // Phase 5: End -> Rest (Drop & Return) +// else if (!armBot.isActive && armBot.state === "idle" && currentPhase === "dropping" && armBot.currentAction) { +// setArmBotActive(armBot.modelUuid, true); +// setArmBotState(armBot.modelUuid, "running"); +// setCurrentPhase("end-to-rest"); + +// const endPoint = armBot.point.actions[0].process.endPoint; +// if (endPoint) { +// const start = new THREE.Vector3(endPoint[0], endPoint[1], endPoint[2]); +// const curve = new THREE.CatmullRomCurve3([start, start.clone().setY(restPosition.y), restPosition]); +// logStatus(armBot.modelUuid, "Waiting to drop."); +// setTimeout(()=>{ +// setPath(curve.getPoints(30).map(p => [p.x, p.y, p.z])); +// },3000) + +// } + +// logStatus(armBot.modelUuid, "Moving armBot from end point to rest position."); +// } +// } else { +// logStatus(armBot.modelUuid, "Simulation Play Stopped"); +// setArmBotActive(armBot.modelUuid, false); +// setArmBotState(armBot.modelUuid, "idle"); +// setCurrentPhase("init"); +// setPath([]); +// removeCurrentAction(armBot.modelUuid); +// } + +// }, [currentPhase, armBot, isPlaying, ikSolver, isReset]); + +// 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, "idle"); +// 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, "idle"); +// 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([]); +// removeCurrentAction(armBot.modelUuid); +// } +// }; + +// const logStatus = (id: string, status: string) => { +// console.log( status); +// // console.log(`status [${id}]: ${status}`); +// }; + +// return ( +// <> +// +// +// +// ); +// } + +// export default RoboticArmInstance; \ No newline at end of file diff --git a/app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx b/app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx index 645cbb5..e49f5bf 100644 --- a/app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx +++ b/app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx @@ -3,20 +3,18 @@ import * as THREE from "three"; import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader"; import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader"; import { clone } from "three/examples/jsm/utils/SkeletonUtils"; -import { useFrame, useLoader, useThree } from "@react-three/fiber"; +import { useLoader, useThree } from "@react-three/fiber"; import { CCDIKSolver, CCDIKHelper, } from "three/examples/jsm/animation/CCDIKSolver"; + type IKInstanceProps = { modelUrl: string; ikSolver: any; setIkSolver: any - robot: any; + armBot: any; groupRef: React.RefObject; - processes: any; - setArmBotCurvePoints: any }; -function IKInstance({ modelUrl, setIkSolver, ikSolver, robot, groupRef, processes, setArmBotCurvePoints }: IKInstanceProps) { - - const { scene } = useThree(); +function IKInstance({ modelUrl, setIkSolver, ikSolver, armBot, groupRef}: IKInstanceProps) { + const {scene}=useThree() const gltf = useLoader(GLTFLoader, modelUrl, (loader) => { const draco = new DRACOLoader(); draco.setDecoderPath("https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/"); @@ -25,6 +23,7 @@ function IKInstance({ modelUrl, setIkSolver, ikSolver, robot, groupRef, processe const cloned = useMemo(() => clone(gltf?.scene), [gltf]); const targetBoneName = "Target"; const skinnedMeshName = "link_0"; + useEffect(() => { if (!gltf) return; const OOI: any = {}; @@ -67,14 +66,14 @@ function IKInstance({ modelUrl, setIkSolver, ikSolver, robot, groupRef, processe const helper = new CCDIKHelper(OOI.Skinned_Mesh, iks, 0.05) - // scene.add(helper) + scene.add(helper) }, [gltf]); return ( <> - + {armBots?.map((robot: ArmBotStatus) => ( - + ))} diff --git a/app/src/modules/simulation/roboticArm/roboticArm.tsx b/app/src/modules/simulation/roboticArm/roboticArm.tsx index 69e6da0..41d10f9 100644 --- a/app/src/modules/simulation/roboticArm/roboticArm.tsx +++ b/app/src/modules/simulation/roboticArm/roboticArm.tsx @@ -6,8 +6,6 @@ import { useFloorItems } from "../../../store/store"; function RoboticArm() { const { armBots, addArmBot, removeArmBot } = useArmBotStore(); const { floorItems } = useFloorItems(); - - const armBotStatusSample: RoboticArmEventSchema[] = [ { state: "idle", @@ -95,7 +93,7 @@ function RoboticArm() { position: [95.94347308985614, 0, 6.742905194869091], rotation: [0, 0, 0], type: "roboticArm", - speed: 1.5, + speed: 0.1, point: { uuid: "point-123", position: [0, 1.5, 0], diff --git a/app/src/modules/simulation/ui/arm/useDraggableGLTF.ts b/app/src/modules/simulation/ui/arm/useDraggableGLTF.ts index b7e9272..d73b4a9 100644 --- a/app/src/modules/simulation/ui/arm/useDraggableGLTF.ts +++ b/app/src/modules/simulation/ui/arm/useDraggableGLTF.ts @@ -80,7 +80,7 @@ export default function useDraggableGLTF(onUpdate: OnUpdateCallback) { // Add offset for dragging intersection.add(offsetRef.current); - console.log('intersection: ', intersection); + // Get the parent's world matrix if exists const parent = activeObjRef.current.parent; From c95f140d30f7874a1c503478af3c8e71b06dd808 Mon Sep 17 00:00:00 2001 From: Gomathi9520 Date: Wed, 30 Apr 2025 10:30:30 +0530 Subject: [PATCH 2/8] path helper added --- .../instances/animator/roboticArmAnimator.tsx | 31 +++++++++++++++++-- .../instances/ikInstance/ikInstance.tsx | 19 +++++++++--- 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx b/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx index 611ded5..6db275f 100644 --- a/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx +++ b/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx @@ -91,7 +91,7 @@ function RoboticArmAnimator({ const bone = ikSolver.mesh.skeleton.bones.find( (b: any) => b.name === targetBone ); - bone.position.copy(restPosition); + // bone.position.copy(restPosition); ikSolver.update(); }; @@ -100,7 +100,7 @@ function RoboticArmAnimator({ return ( <> {/* {currentPath.length > 0 && ( - <> + {currentPath.map((point, index) => ( @@ -108,8 +108,33 @@ function RoboticArmAnimator({ ))} - + )} */} + {curvePoints && ( + + [p.x, p.y, p.z])} + color="green" + lineWidth={5} + dashed={false} + /> + {currentPath.length >= 1 && ( + <> + {/* First point */} + + + + + + {/* Last point */} + + + + + + )} + + )} ); } diff --git a/app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx b/app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx index e49f5bf..d818777 100644 --- a/app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx +++ b/app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx @@ -3,18 +3,19 @@ import * as THREE from "three"; import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader"; import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader"; import { clone } from "three/examples/jsm/utils/SkeletonUtils"; -import { useLoader, useThree } from "@react-three/fiber"; +import { useLoader, useThree } from "@react-three/fiber"; import { CCDIKSolver, CCDIKHelper, } from "three/examples/jsm/animation/CCDIKSolver"; +import { TransformControls } from '@react-three/drei'; type IKInstanceProps = { modelUrl: string; ikSolver: any; setIkSolver: any armBot: any; - groupRef: React.RefObject; + groupRef: any; }; -function IKInstance({ modelUrl, setIkSolver, ikSolver, armBot, groupRef}: IKInstanceProps) { - const {scene}=useThree() +function IKInstance({ modelUrl, setIkSolver, ikSolver, armBot, groupRef }: IKInstanceProps) { + const { scene } = useThree() const gltf = useLoader(GLTFLoader, modelUrl, (loader) => { const draco = new DRACOLoader(); draco.setDecoderPath("https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/"); @@ -23,6 +24,7 @@ function IKInstance({ modelUrl, setIkSolver, ikSolver, armBot, groupRef}: IKInst const cloned = useMemo(() => clone(gltf?.scene), [gltf]); const targetBoneName = "Target"; const skinnedMeshName = "link_0"; + const [selectedArm, setSelectedArm] = useState(); useEffect(() => { if (!gltf) return; @@ -65,6 +67,9 @@ function IKInstance({ modelUrl, setIkSolver, ikSolver, armBot, groupRef}: IKInst setIkSolver(solver); const helper = new CCDIKHelper(OOI.Skinned_Mesh, iks, 0.05) + groupRef.current.add(helper); + console.log('OOI.Target_Bone: ', OOI.Target_Bone); + setSelectedArm(OOI.Target_Bone); scene.add(helper) @@ -73,7 +78,10 @@ function IKInstance({ modelUrl, setIkSolver, ikSolver, armBot, groupRef}: IKInst return ( <> - + { + setSelectedArm(groupRef.current?.getObjectByName(targetBoneName)) + } + }> + {/* {selectedArm && } */} ) } From ff9bb8f5664001d1ea78b26ce654e2e8c350c5a6 Mon Sep 17 00:00:00 2001 From: Gomathi9520 Date: Wed, 30 Apr 2025 15:27:02 +0530 Subject: [PATCH 3/8] circular curve for arm movements added --- .../instances/animator/roboticArmAnimator.tsx | 244 ++++++++++++++---- .../instances/ikInstance/ikInstance.tsx | 11 +- .../simulation/roboticArm/roboticArm.tsx | 20 +- 3 files changed, 201 insertions(+), 74 deletions(-) diff --git a/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx b/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx index 6db275f..d1bf523 100644 --- a/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx +++ b/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx @@ -1,13 +1,13 @@ import React, { useEffect, useRef, useState } from 'react'; import { useFrame } from '@react-three/fiber'; import * as THREE from 'three'; +import { Line } from '@react-three/drei'; import { useAnimationPlaySpeed, usePauseButtonStore, usePlayButtonStore, useResetButtonStore } from '../../../../../store/usePlayButtonStore'; -import { Line } from '@react-three/drei'; function RoboticArmAnimator({ HandleCallback, @@ -22,24 +22,35 @@ function RoboticArmAnimator({ const curveRef = useRef(null); const [currentPath, setCurrentPath] = useState<[number, number, number][]>([]); const [curvePoints, setCurvePoints] = useState(null); + const [circlePoints, setCirclePoints] = useState<[number, number, number][]>([]); + const [nearestStartPoint, setNearestStartPoint] = useState<[number, number, number] | null>(null); + const [nearestEndPoint, setNearestEndPoint] = useState<[number, number, number] | null>(null); + const [customCurvePoints, setCustomCurvePoints] = useState(null); + const stepSegmentsRef = useRef([]); + const [currentStep, setCurrentStep] = useState(0); + const elapsedTimeRef = useRef(0); // Zustand stores const { isPlaying } = usePlayButtonStore(); const { isPaused } = usePauseButtonStore(); - const { isReset } = useResetButtonStore(); // optional use depending on your logic + const { isReset } = useResetButtonStore(); const { speed } = useAnimationPlaySpeed(); + // Update path state whenever `path` prop changes useEffect(() => { - setCurrentPath(path) - }, [path]) + setCurrentPath(path); + }, [path]); + + // Reset logic when `isPlaying` changes useEffect(() => { if (!isPlaying) { - setCurrentPath([]) - curveRef.current = null + setCurrentPath([]); + curveRef.current = null; } - }, [isPlaying]) + }, [isPlaying]); + // Handle path generation (including CatmullRomCurve3) useEffect(() => { if (currentPath && currentPath.length === 3) { const [start, mid, end] = currentPath; @@ -51,18 +62,152 @@ function RoboticArmAnimator({ new THREE.Vector3(end[0], end[1], end[2]) ]; const generatedCurve = new THREE.CatmullRomCurve3(points, false, 'centripetal', 1).getPoints(100); - // console.log('generatedCurve: ', generatedCurve); curveRef.current = generatedCurve; setCurvePoints(generatedCurve); - } }, [currentPath]); + // Handle circle points based on armBot position + useEffect(() => { + const radius = 1.6; // Circle radius + const segments = 64; + const points: [number, number, number][] = []; + + for (let i = 0; i <= segments; i++) { + const theta = (i / segments) * Math.PI * 2; + const x = radius * Math.cos(theta) + armBot.position[0]; + const z = radius * Math.sin(theta) + armBot.position[2]; + const y = armBot.position[1]; + points.push([x, y, z]); + } + + setCirclePoints(points); + }, [armBot.position]); + + // Handle nearest points and final path (including arc points) + useEffect(() => { + if (circlePoints.length > 0 && currentPath.length > 0) { + const startPoint = [currentPath[0][0], currentPath[0][1] + 0.5, currentPath[0][2]] as [number, number, number]; + const endPoint = [currentPath[currentPath.length - 1][0], currentPath[currentPath.length - 1][1] + 0.5, currentPath[currentPath.length - 1][2]] as [number, number, number]; + + const findNearest = (target: [number, number, number]) => { + let nearestPoint = circlePoints[0]; + let minDistance = Infinity; + + for (const point of circlePoints) { + const dx = target[0] - point[0]; + const dy = target[1] - point[1]; + const dz = target[2] - point[2]; + const distance = Math.sqrt(dx * dx + dy * dy + dz * dz); + if (distance < minDistance) { + minDistance = distance; + nearestPoint = point; + } + } + return nearestPoint; + }; + + const nearestToStart = findNearest(startPoint); + const nearestToEnd = findNearest(endPoint); + + setNearestStartPoint(nearestToStart); + setNearestEndPoint(nearestToEnd); + + const radius = 1.6; + const segments = 64; + const center = armBot.position; + + const startAngle = Math.atan2(nearestToStart[2] - center[2], nearestToStart[0] - center[0]); + const endAngle = Math.atan2(nearestToEnd[2] - center[2], nearestToEnd[0] - center[0]); + let deltaAngle = endAngle - startAngle; + + if (deltaAngle > Math.PI) { + deltaAngle -= 2 * Math.PI; + } else if (deltaAngle < -Math.PI) { + deltaAngle += 2 * Math.PI; + } + + const arcPoints: [number, number, number][] = []; + + for (let i = 0; i <= segments; i++) { + const t = i / segments; + const angle = startAngle + deltaAngle * t; + const x = center[0] + radius * Math.cos(angle); + const z = center[2] + radius * Math.sin(angle); + const y = startPoint[1]; + arcPoints.push([x, y, z]); + } + const start = currentPath[0]; + const end = currentPath[currentPath.length - 1]; + + let step1 = [ + [start[0], start[1], start[2]], + [start[0], start[1] + 0.5, start[2]] + ]; + let step2 = [ + [start[0], start[1] + 0.5, start[2]], + [nearestToStart[0], start[1] + 0.5, nearestToStart[2]] + ]; + let step3 = [ + [nearestToStart[0], start[1] + 0.5, nearestToStart[2]], + [end[0], arcPoints[arcPoints.length - 1][1], end[2]] + ] + let step4 = [ + [end[0], arcPoints[arcPoints.length - 1][1], end[2]], + [end[0], end[1] + 0.5, end[2]] + ] + let step5 = [ + [end[0], end[1] + 0.5, end[2]], + [end[0], end[1], end[2]], + ] + + const points = [ + new THREE.Vector3(start[0], start[1], start[2]), + new THREE.Vector3(start[0], start[1] + 0.5, start[2]), + + new THREE.Vector3(start[0], start[1] + 0.5, start[2]), + new THREE.Vector3(nearestToStart[0], start[1] + 0.5, nearestToStart[2]), + + new THREE.Vector3(nearestToStart[0], start[1] + 0.5, nearestToStart[2]), + new THREE.Vector3(end[0], arcPoints[arcPoints.length - 1][1], end[2]), + + new THREE.Vector3(end[0], arcPoints[arcPoints.length - 1][1], end[2]), + new THREE.Vector3(end[0], end[1] + 0.5, end[2]), + + new THREE.Vector3(end[0], end[1] + 0.5, end[2]), + new THREE.Vector3(end[0], end[1], end[2]) + ]; + const steps = [ + [points[0], points[1]], // step1 + [points[2], points[3]], // step2 + [points[4], points[5]], // step3 + [points[6], points[7]], // step4 + [points[8], points[9]] // step5 + ]; + stepSegmentsRef.current = steps; + setCurrentStep(0); + elapsedTimeRef.current = 0; + + const finalPath = [ + new THREE.Vector3(start[0], start[1], start[2]), + new THREE.Vector3(start[0], start[1] + 0.5, start[2]), + new THREE.Vector3(nearestToStart[0], start[1] + 0.5, nearestToStart[2]), + ...arcPoints.map(([x, y, z]) => new THREE.Vector3(x, y, z)), + new THREE.Vector3(end[0], arcPoints[arcPoints.length - 1][1], end[2]), + new THREE.Vector3(end[0], end[1], end[2]) + ]; + + const customCurve = new THREE.CatmullRomCurve3(finalPath, false, 'centripetal', 1); + const customCurveGeneratedPoints = customCurve.getPoints(100); + + setCustomCurvePoints(customCurveGeneratedPoints); + } + }, [circlePoints, currentPath]); + + // Frame update for animation useFrame((_, delta) => { if (ikSolver && curveRef.current && currentPath.length >= 0) { - const bone = ikSolver.mesh.skeleton.bones.find( - (b: any) => b.name === targetBone - ); + const bone = ikSolver.mesh.skeleton.bones.find((b: any) => b.name === targetBone); if (!bone) return; if (isPlaying) { @@ -70,71 +215,62 @@ function RoboticArmAnimator({ const curvePoints = curveRef.current; const speedAdjustedProgress = progressRef.current + (speed * armBot.speed); const index = Math.floor(speedAdjustedProgress); - if (index >= curvePoints.length) { - HandleCallback(); - setCurrentPath([]); - curveRef.current = null; - progressRef.current = 0; - } else { - const point = curvePoints[index]; - bone.position.copy(point); - progressRef.current = speedAdjustedProgress; + + if (curvePoints) { + + if (index >= curvePoints.length) { + HandleCallback(); + setCurrentPath([]); + curveRef.current = null; + progressRef.current = 0; + } else { + const point = curvePoints[index]; + bone.position.copy(point); + progressRef.current = speedAdjustedProgress; + } } + + } else { + logStatus(armBot.modelUuid, 'Simulation Play Exited'); } - } else { - logStatus(armBot.modelUuid, 'Simulation Play Exited'); - // bone.position.copy(restPosition); + + ikSolver.update(); } - - ikSolver.update(); } else if (ikSolver && !isPlaying && currentPath.length === 0) { - const bone = ikSolver.mesh.skeleton.bones.find( - (b: any) => b.name === targetBone - ); - // bone.position.copy(restPosition); + const bone = ikSolver.mesh.skeleton.bones.find((b: any) => b.name === targetBone); + bone.position.copy(restPosition); ikSolver.update(); - }; - + } }); return ( + <> - {/* {currentPath.length > 0 && ( + {customCurvePoints && currentPath && ( - - {currentPath.map((point, index) => ( - - - - - ))} - - )} */} - {curvePoints && ( - - [p.x, p.y, p.z])} - color="green" - lineWidth={5} - dashed={false} - /> + [p.x, p.y, p.z])} color="green" lineWidth={5} dashed={false} /> + {/* */} {currentPath.length >= 1 && ( <> {/* First point */} - + {/* - + */} {/* Last point */} - + {/* - + */} )} )} + + + + ); } diff --git a/app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx b/app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx index d818777..c40bc92 100644 --- a/app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx +++ b/app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx @@ -67,21 +67,20 @@ function IKInstance({ modelUrl, setIkSolver, ikSolver, armBot, groupRef }: IKIns setIkSolver(solver); const helper = new CCDIKHelper(OOI.Skinned_Mesh, iks, 0.05) - groupRef.current.add(helper); - console.log('OOI.Target_Bone: ', OOI.Target_Bone); + // groupRef.current.add(helper); + setSelectedArm(OOI.Target_Bone); - scene.add(helper) + // scene.add(helper) }, [gltf]); return ( <> - { + { setSelectedArm(groupRef.current?.getObjectByName(targetBoneName)) - } - }> + }}> Date: Wed, 30 Apr 2025 16:50:31 +0530 Subject: [PATCH 4/8] arm ui added --- .../simulation/roboticArm/roboticArm.tsx | 18 +- .../modules/simulation/ui/arm/armBotUI.tsx | 155 ++++++++++++++++++ 2 files changed, 171 insertions(+), 2 deletions(-) create mode 100644 app/src/modules/simulation/ui/arm/armBotUI.tsx diff --git a/app/src/modules/simulation/roboticArm/roboticArm.tsx b/app/src/modules/simulation/roboticArm/roboticArm.tsx index 37e350e..5a5bd38 100644 --- a/app/src/modules/simulation/roboticArm/roboticArm.tsx +++ b/app/src/modules/simulation/roboticArm/roboticArm.tsx @@ -2,9 +2,17 @@ import { useEffect } from "react"; import RoboticArmInstances from "./instances/roboticArmInstances"; import { useArmBotStore } from "../../../store/simulation/useArmBotStore"; import { useFloorItems } from "../../../store/store"; +import { useSelectedEventData, useSelectedEventSphere } from "../../../store/simulation/useSimulationStore"; +import { useEventsStore } from "../../../store/simulation/useEventsStore"; +import { usePlayButtonStore } from "../../../store/usePlayButtonStore"; +import ArmBotUI from "../ui/arm/armBotUI"; function RoboticArm() { const { armBots, addArmBot, removeArmBot } = useArmBotStore(); + const { addEvent } = useEventsStore(); + const { selectedEventSphere } = useSelectedEventSphere(); + const { selectedEventData } = useSelectedEventData(); + const { isPlaying } = usePlayButtonStore(); const { floorItems } = useFloorItems(); const armBotStatusSample: RoboticArmEventSchema[] = [ { @@ -156,12 +164,18 @@ function RoboticArm() { }, []); useEffect(() => { - - }, [armBots]); + + console.log('isPlaying: ', isPlaying); + console.log('selectedEventData: ', selectedEventData); + console.log('selectedEventSphere: ', selectedEventSphere); + }, [selectedEventData, selectedEventSphere, isPlaying]); return ( <> + {selectedEventSphere && selectedEventData?.data.type === "roboticArm" && !isPlaying && + < ArmBotUI /> + } ); } diff --git a/app/src/modules/simulation/ui/arm/armBotUI.tsx b/app/src/modules/simulation/ui/arm/armBotUI.tsx new file mode 100644 index 0000000..7e111e3 --- /dev/null +++ b/app/src/modules/simulation/ui/arm/armBotUI.tsx @@ -0,0 +1,155 @@ +import React from 'react' +import PickDropPoints from './PickDropPoints'; +import { useSelectedEventData, useSelectedEventSphere } from '../../../../store/simulation/useSimulationStore'; +import { useArmBotStore } from '../../../../store/simulation/useArmBotStore'; +import useModuleStore from '../../../../store/useModuleStore'; +import { useGLTF } from '@react-three/drei'; +import armPick from "../../../../assets/gltf-glb/arm_ui_pick.glb"; +import armDrop from "../../../../assets/gltf-glb/arm_ui_drop.glb"; +import useDraggableGLTF from './useDraggableGLTF'; +import * as THREE from "three"; +import { useThree } from '@react-three/fiber'; +const ArmBotUI = () => { + console.log("called"); + const { selectedEventSphere } = useSelectedEventSphere(); + const { selectedEventData } = useSelectedEventData(); + const { armBots, updateArmBot } = useArmBotStore(); + const armUiPick = useGLTF(armPick) as any; + const { scene } = useThree(); + const armUiDrop = useGLTF(armDrop) as any; + + const getDefaultPositions = (modelUuid: string) => { + const modelData = getModelByUuid(modelUuid); + if (modelData) { + + const baseX = modelData.position?.[0] || 0; + const baseY = 2.6; + const baseZ = modelData.position?.[2] || 0; + return { + pick: [baseX, baseY, baseZ + 0.4], + drop: [baseX, baseY, baseZ - 1.2], + default: [baseX, baseY, baseZ - 1.5], + }; + } + return { + pick: [0.5, 1.5, 0], + drop: [-0.5, 1.5, 0], + default: [0, 1.5, 0], + }; + }; + const getModelByUuid = (modelUuid: string) => { + try { + const modelsJson = localStorage.getItem("FloorItems"); + if (modelsJson) { + const models = JSON.parse(modelsJson); + return models.find((m: any) => m.modeluuid === modelUuid); + } + const storeModels = (useModuleStore.getState() as any).models || []; + return storeModels.find((m: any) => m.modelUuid === modelUuid); + } catch (error) { } + return null; + }; + const updatePointToState = (obj: THREE.Object3D) => { + const { modelUuid, pointUuid, actionType, actionUuid } = obj.userData; + + const newPosition = new THREE.Vector3(); + obj.getWorldPosition(newPosition); + const worldPositionArray = newPosition.toArray(); + + const armBot = armBots.find((a) => a.modelUuid === modelUuid); + if (!armBot) return; + + const updatedActions = armBot.point.actions.map((action: any) => { + if (action.actionUuid === actionUuid) { + const updatedProcess = { ...action.process }; + + if (actionType === "pick") { + updatedProcess.startPoint = getLocalPosition(modelUuid, worldPositionArray); + } + if (actionType === "drop") { + updatedProcess.endPoint = getLocalPosition(modelUuid, worldPositionArray); + } + return { + ...action, + process: updatedProcess, + }; + } + return action; + }); + + updateArmBot(modelUuid, { + point: { + ...armBot.point, + actions: updatedActions, + }, + }); + }; + function getLocalPosition(parentUuid: string, worldPosArray: [number, number, number] | null): [number, number, number] | null { + if (worldPosArray) { + const worldPos = new THREE.Vector3(...worldPosArray); + const localPos = worldPos.clone(); + + const parentObject = scene.getObjectByProperty('uuid', parentUuid); + if (parentObject) { + parentObject.worldToLocal(localPos); + + return [localPos.x, localPos.y, localPos.z]; + } else { + + } + } + return null; + } + const { handlePointerDown } = useDraggableGLTF(updatePointToState); + + return ( + <> + {armBots.map((event: any) => { + const defaultPositions = getDefaultPositions(event.modelUuid); + const isSelected = + selectedEventSphere?.userData?.modelUuid === event.modelUuid; + + return event.point.actions.map((action: any) => { + if (action.actionType === "pickAndPlace") { + const pickPosition = action.process.startPoint || defaultPositions.pick; + const dropPosition = action.process.endPoint || defaultPositions.drop; + + return ( + + {/* Pick Point */} + + + {/* Drop Point */} + + + ); + } + return null; + }); + })} + + ); + + +} +export default ArmBotUI \ No newline at end of file From d83b934e61554c0dd17c76b060a7d477da1a9476 Mon Sep 17 00:00:00 2001 From: Gomathi9520 Date: Fri, 2 May 2025 17:35:52 +0530 Subject: [PATCH 5/8] armbot circular path updated and ui dynamic updation --- .../IntialLoad/loadInitialFloorItems.ts | 2 +- .../events/points/creator/pointsCreator.tsx | 55 ++- .../instances/animator/roboticArmAnimator.tsx | 316 +++++++---------- .../armInstance/roboticArmInstance.tsx | 312 +---------------- .../instances/ikInstance/ikInstance.tsx | 3 +- .../instances/roboticArmInstances.tsx | 2 - .../simulation/roboticArm/roboticArm.tsx | 42 ++- .../simulation/ui/arm/PickDropPoints.tsx | 20 +- .../modules/simulation/ui/arm/armBotUI.tsx | 328 ++++++++++-------- .../simulation/ui/arm/useDraggableGLTF.ts | 56 +-- 10 files changed, 438 insertions(+), 698 deletions(-) diff --git a/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts b/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts index a351d73..9515188 100644 --- a/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts +++ b/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts @@ -206,7 +206,7 @@ function processLoadedModel( actionType: "travel", unLoadDuration: 5, loadCapacity: 10, - steeringAngle:0, + steeringAngle: 0, pickUpPoint: null, unLoadPoint: null, triggers: [] diff --git a/app/src/modules/simulation/events/points/creator/pointsCreator.tsx b/app/src/modules/simulation/events/points/creator/pointsCreator.tsx index c6ec316..e4eaafb 100644 --- a/app/src/modules/simulation/events/points/creator/pointsCreator.tsx +++ b/app/src/modules/simulation/events/points/creator/pointsCreator.tsx @@ -23,6 +23,9 @@ function PointsCreator() { const eventData = getEventByModelUuid( selectedEventSphere.userData.modelUuid ); + + + if (eventData) { setSelectedEventData(eventData, selectedEventSphere.userData.pointUuid); } else { @@ -80,7 +83,10 @@ function PointsCreator() { {events.map((event, i) => { if (event.type === "transfer") { return ( - + {event.points.map((point, j) => ( { if (selectedEventData?.data.type !== 'vehicle') { - clearSelectedEventSphere(); + // clearSelectedEventSphere(); } setTransformMode(null); }} key={`${i}-${j}`} position={new THREE.Vector3(...point.position)} - // rotation={new THREE.Euler(...point.rotation)} - userData={{ modelUuid: event.modelUuid, pointUuid: point.uuid }} + userData={{ + modelUuid: event.modelUuid, + pointUuid: point.uuid, + }} > @@ -111,7 +119,10 @@ function PointsCreator() { ); } else if (event.type === "vehicle") { return ( - + @@ -137,7 +150,10 @@ function PointsCreator() { ); } else if (event.type === "roboticArm") { return ( - + { - clearSelectedEventSphere(); + // clearSelectedEventSphere(); setTransformMode(null); }} position={new THREE.Vector3(...event.point.position)} - // rotation={new THREE.Euler(...event.point.rotation)} - userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }} + userData={{ + modelUuid: event.modelUuid, + pointUuid: event.point.uuid, + }} > @@ -163,7 +181,10 @@ function PointsCreator() { ); } else if (event.type === "machine") { return ( - + { - clearSelectedEventSphere(); + // clearSelectedEventSphere(); setTransformMode(null); }} position={new THREE.Vector3(...event.point.position)} - // rotation={new THREE.Euler(...event.point.rotation)} - userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }} + userData={{ + modelUuid: event.modelUuid, + pointUuid: event.point.uuid, + }} > @@ -208,4 +231,4 @@ function PointsCreator() { ); } -export default PointsCreator; +export default PointsCreator; \ No newline at end of file diff --git a/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx b/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx index d1bf523..d32a6c3 100644 --- a/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx +++ b/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useRef, useState } from 'react'; +import React, { useEffect, useMemo, useRef, useState } from 'react'; import { useFrame } from '@react-three/fiber'; import * as THREE from 'three'; import { Line } from '@react-three/drei'; @@ -21,14 +21,8 @@ function RoboticArmAnimator({ const progressRef = useRef(0); const curveRef = useRef(null); const [currentPath, setCurrentPath] = useState<[number, number, number][]>([]); - const [curvePoints, setCurvePoints] = useState(null); const [circlePoints, setCirclePoints] = useState<[number, number, number][]>([]); - const [nearestStartPoint, setNearestStartPoint] = useState<[number, number, number] | null>(null); - const [nearestEndPoint, setNearestEndPoint] = useState<[number, number, number] | null>(null); const [customCurvePoints, setCustomCurvePoints] = useState(null); - const stepSegmentsRef = useRef([]); - const [currentStep, setCurrentStep] = useState(0); - const elapsedTimeRef = useRef(0); // Zustand stores const { isPlaying } = usePlayButtonStore(); @@ -41,7 +35,6 @@ function RoboticArmAnimator({ setCurrentPath(path); }, [path]); - // Reset logic when `isPlaying` changes useEffect(() => { if (!isPlaying) { @@ -50,221 +43,172 @@ function RoboticArmAnimator({ } }, [isPlaying]); - // Handle path generation (including CatmullRomCurve3) - useEffect(() => { - if (currentPath && currentPath.length === 3) { - const [start, mid, end] = currentPath; - const points = [ - new THREE.Vector3(start[0], start[1], start[2]), - new THREE.Vector3(start[0], mid[1] + 0.5, start[2]), - new THREE.Vector3(mid[0], mid[1] + 0.5, mid[2]), - new THREE.Vector3(mid[0], end[1] + 0.5, mid[2]), - new THREE.Vector3(end[0], end[1], end[2]) - ]; - const generatedCurve = new THREE.CatmullRomCurve3(points, false, 'centripetal', 1).getPoints(100); - curveRef.current = generatedCurve; - setCurvePoints(generatedCurve); - } - }, [currentPath]); - // Handle circle points based on armBot position useEffect(() => { - const radius = 1.6; // Circle radius - const segments = 64; - const points: [number, number, number][] = []; - - for (let i = 0; i <= segments; i++) { - const theta = (i / segments) * Math.PI * 2; - const x = radius * Math.cos(theta) + armBot.position[0]; - const z = radius * Math.sin(theta) + armBot.position[2]; - const y = armBot.position[1]; - points.push([x, y, z]); - } - + const points = generateRingPoints(1.6, 64) setCirclePoints(points); }, [armBot.position]); + + function generateRingPoints(radius: any, segments: any) { + const points: [number, number, number][] = []; + for (let i = 0; i < segments; i++) { + // Calculate angle for current segment + const angle = (i / segments) * Math.PI * 2; + + // Calculate x and z coordinates (y remains the same for a flat ring) + const x = Math.cos(angle) * radius; + const z = Math.sin(angle) * radius; + + points.push([x, 1.5, z]); + } + return points; + } + + const findNearestIndex = (nearestPoint: [number, number, number], points: [number, number, number][], epsilon = 1e-6) => { + for (let i = 0; i < points.length; i++) { + const [x, y, z] = points[i]; + if ( + Math.abs(x - nearestPoint[0]) < epsilon && + Math.abs(y - nearestPoint[1]) < epsilon && + Math.abs(z - nearestPoint[2]) < epsilon + ) { + return i; // Found the matching index + } + } + return -1; // Not found + }; + + // Handle nearest points and final path (including arc points) useEffect(() => { if (circlePoints.length > 0 && currentPath.length > 0) { - const startPoint = [currentPath[0][0], currentPath[0][1] + 0.5, currentPath[0][2]] as [number, number, number]; - const endPoint = [currentPath[currentPath.length - 1][0], currentPath[currentPath.length - 1][1] + 0.5, currentPath[currentPath.length - 1][2]] as [number, number, number]; - - const findNearest = (target: [number, number, number]) => { - let nearestPoint = circlePoints[0]; - let minDistance = Infinity; - - for (const point of circlePoints) { - const dx = target[0] - point[0]; - const dy = target[1] - point[1]; - const dz = target[2] - point[2]; - const distance = Math.sqrt(dx * dx + dy * dy + dz * dz); - if (distance < minDistance) { - minDistance = distance; - nearestPoint = point; - } - } - return nearestPoint; - }; - - const nearestToStart = findNearest(startPoint); - const nearestToEnd = findNearest(endPoint); - - setNearestStartPoint(nearestToStart); - setNearestEndPoint(nearestToEnd); - - const radius = 1.6; - const segments = 64; - const center = armBot.position; - - const startAngle = Math.atan2(nearestToStart[2] - center[2], nearestToStart[0] - center[0]); - const endAngle = Math.atan2(nearestToEnd[2] - center[2], nearestToEnd[0] - center[0]); - let deltaAngle = endAngle - startAngle; - - if (deltaAngle > Math.PI) { - deltaAngle -= 2 * Math.PI; - } else if (deltaAngle < -Math.PI) { - deltaAngle += 2 * Math.PI; - } - - const arcPoints: [number, number, number][] = []; - - for (let i = 0; i <= segments; i++) { - const t = i / segments; - const angle = startAngle + deltaAngle * t; - const x = center[0] + radius * Math.cos(angle); - const z = center[2] + radius * Math.sin(angle); - const y = startPoint[1]; - arcPoints.push([x, y, z]); - } const start = currentPath[0]; const end = currentPath[currentPath.length - 1]; - let step1 = [ - [start[0], start[1], start[2]], - [start[0], start[1] + 0.5, start[2]] - ]; - let step2 = [ - [start[0], start[1] + 0.5, start[2]], - [nearestToStart[0], start[1] + 0.5, nearestToStart[2]] - ]; - let step3 = [ - [nearestToStart[0], start[1] + 0.5, nearestToStart[2]], - [end[0], arcPoints[arcPoints.length - 1][1], end[2]] - ] - let step4 = [ - [end[0], arcPoints[arcPoints.length - 1][1], end[2]], - [end[0], end[1] + 0.5, end[2]] - ] - let step5 = [ - [end[0], end[1] + 0.5, end[2]], - [end[0], end[1], end[2]], - ] + const raisedStart = [start[0], start[1] + 0.5, start[2]] as [number, number, number]; + const raisedEnd = [end[0], end[1] + 0.5, end[2]] as [number, number, number]; - const points = [ - new THREE.Vector3(start[0], start[1], start[2]), - new THREE.Vector3(start[0], start[1] + 0.5, start[2]), + const findNearest = (target: [number, number, number]) => { + return circlePoints.reduce((nearest, point) => { + const distance = Math.hypot( + target[0] - point[0], + target[1] - point[1], + target[2] - point[2] + ); + const nearestDistance = Math.hypot( + target[0] - nearest[0], + target[1] - nearest[1], + target[2] - nearest[2] + ); + return distance < nearestDistance ? point : nearest; + }, circlePoints[0]); + }; - new THREE.Vector3(start[0], start[1] + 0.5, start[2]), - new THREE.Vector3(nearestToStart[0], start[1] + 0.5, nearestToStart[2]), + const nearestToStart = findNearest(raisedStart); - new THREE.Vector3(nearestToStart[0], start[1] + 0.5, nearestToStart[2]), - new THREE.Vector3(end[0], arcPoints[arcPoints.length - 1][1], end[2]), + const nearestToEnd = findNearest(raisedEnd); - new THREE.Vector3(end[0], arcPoints[arcPoints.length - 1][1], end[2]), - new THREE.Vector3(end[0], end[1] + 0.5, end[2]), + const indexOfNearestStart = findNearestIndex(nearestToStart, circlePoints); - new THREE.Vector3(end[0], end[1] + 0.5, end[2]), - new THREE.Vector3(end[0], end[1], end[2]) - ]; - const steps = [ - [points[0], points[1]], // step1 - [points[2], points[3]], // step2 - [points[4], points[5]], // step3 - [points[6], points[7]], // step4 - [points[8], points[9]] // step5 - ]; - stepSegmentsRef.current = steps; - setCurrentStep(0); - elapsedTimeRef.current = 0; + const indexOfNearestEnd = findNearestIndex(nearestToEnd, circlePoints); - const finalPath = [ - new THREE.Vector3(start[0], start[1], start[2]), - new THREE.Vector3(start[0], start[1] + 0.5, start[2]), - new THREE.Vector3(nearestToStart[0], start[1] + 0.5, nearestToStart[2]), - ...arcPoints.map(([x, y, z]) => new THREE.Vector3(x, y, z)), - new THREE.Vector3(end[0], arcPoints[arcPoints.length - 1][1], end[2]), - new THREE.Vector3(end[0], end[1], end[2]) + // Find clockwise and counter-clockwise distances + const clockwiseDistance = (indexOfNearestEnd - indexOfNearestStart + 64) % 64; + + const counterClockwiseDistance = (indexOfNearestStart - indexOfNearestEnd + 64) % 64; + + const clockwiseIsShorter = clockwiseDistance <= counterClockwiseDistance; + + // Collect arc points between start and end + let arcPoints: [number, number, number][] = []; + + if (clockwiseIsShorter) { + if (indexOfNearestStart <= indexOfNearestEnd) { + arcPoints = circlePoints.slice(indexOfNearestStart, indexOfNearestEnd + 1); + } else { + // Wrap around + arcPoints = [ + ...circlePoints.slice(indexOfNearestStart, 64), + ...circlePoints.slice(0, indexOfNearestEnd + 1) + ]; + } + } else { + if (indexOfNearestStart >= indexOfNearestEnd) { + for (let i = indexOfNearestStart; i !== (indexOfNearestEnd - 1 + 64) % 64; i = (i - 1 + 64) % 64) { + arcPoints.push(circlePoints[i]); + } + } else { + for (let i = indexOfNearestStart; i !== (indexOfNearestEnd - 1 + 64) % 64; i = (i - 1 + 64) % 64) { + arcPoints.push(circlePoints[i]); + } + } + } + + // Continue your custom path logic + const pathVectors = [ + new THREE.Vector3(start[0], start[1], start[2]), // start + new THREE.Vector3(raisedStart[0], raisedStart[1], raisedStart[2]), // lift up + new THREE.Vector3(nearestToStart[0], raisedStart[1], nearestToStart[2]), // move to arc start + ...arcPoints.map(point => new THREE.Vector3(point[0], raisedStart[1], point[2])), + new THREE.Vector3(nearestToEnd[0], raisedEnd[1], nearestToEnd[2]), // move from arc end + new THREE.Vector3(raisedEnd[0], raisedEnd[1], raisedEnd[2]), // lowered end + new THREE.Vector3(end[0], end[1], end[2]) // end ]; - const customCurve = new THREE.CatmullRomCurve3(finalPath, false, 'centripetal', 1); - const customCurveGeneratedPoints = customCurve.getPoints(100); - - setCustomCurvePoints(customCurveGeneratedPoints); + const customCurve = new THREE.CatmullRomCurve3(pathVectors, false, 'centripetal', 1); + const generatedPoints = customCurve.getPoints(100); + setCustomCurvePoints(generatedPoints); } }, [circlePoints, currentPath]); // Frame update for animation useFrame((_, delta) => { - if (ikSolver && curveRef.current && currentPath.length >= 0) { - const bone = ikSolver.mesh.skeleton.bones.find((b: any) => b.name === targetBone); - if (!bone) return; + if (!ikSolver) return; - if (isPlaying) { - if (!isPaused) { - const curvePoints = curveRef.current; - const speedAdjustedProgress = progressRef.current + (speed * armBot.speed); - const index = Math.floor(speedAdjustedProgress); + const bone = ikSolver.mesh.skeleton.bones.find((b: any) => b.name === targetBone); + if (!bone) return; - if (curvePoints) { - - if (index >= curvePoints.length) { - HandleCallback(); - setCurrentPath([]); - curveRef.current = null; - progressRef.current = 0; - } else { - const point = curvePoints[index]; - bone.position.copy(point); - progressRef.current = speedAdjustedProgress; - } - } + if (isPlaying) { + if (!isPaused && customCurvePoints && currentPath.length > 0) { + const curvePoints = customCurvePoints; + const speedAdjustedProgress = progressRef.current + (speed * armBot.speed); + const index = Math.floor(speedAdjustedProgress); + if (index >= curvePoints.length) { + // Reached the end of the curve + HandleCallback(); + setCurrentPath([]); + curveRef.current = null; + progressRef.current = 0; } else { - logStatus(armBot.modelUuid, 'Simulation Play Exited'); + const point = curvePoints[index]; + bone.position.copy(point); + progressRef.current = speedAdjustedProgress; } - - ikSolver.update(); + } else if (isPaused) { + logStatus(armBot.modelUuid, 'Simulation Paused'); } - } else if (ikSolver && !isPlaying && currentPath.length === 0) { - const bone = ikSolver.mesh.skeleton.bones.find((b: any) => b.name === targetBone); + + ikSolver.update(); + } else if (!isPlaying && currentPath.length === 0) { + // Not playing anymore, reset to rest bone.position.copy(restPosition); ikSolver.update(); } }); + return ( - <> - {customCurvePoints && currentPath && ( - - [p.x, p.y, p.z])} color="green" lineWidth={5} dashed={false} /> - {/* */} - {currentPath.length >= 1 && ( - <> - {/* First point */} - {/* - - - */} - - {/* Last point */} - {/* - - - */} - - )} + {customCurvePoints && currentPath && isPlaying && ( + + [p.x, p.y, p.z] as [number, number, number])} + color="green" + lineWidth={5} + dashed={false} + /> )} diff --git a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx index 7660ad1..ff5e7e3 100644 --- a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx +++ b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx @@ -8,6 +8,7 @@ import { useThree } from "@react-three/fiber"; import { useFloorItems } from '../../../../../store/store'; import useModuleStore from '../../../../../store/useModuleStore'; import * as THREE from "three"; +import { useSelectedAction } from '../../../../../store/simulation/useSimulationStore'; function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { @@ -28,6 +29,7 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { const { isPlaying } = usePlayButtonStore(); const { isReset, setReset } = useResetButtonStore(); const { isPaused } = usePauseButtonStore(); + const { selectedAction } = useSelectedAction(); function firstFrame() { startTime = performance.now(); @@ -78,6 +80,7 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { startTime=0; const endPoint = armBot.point.actions[0].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"); @@ -93,21 +96,17 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { }, [isPaused]); useEffect(() => { - let armItems = floorItems?.filter((val: any) => - val.modelUuid === "3abf5d46-b59e-4e6b-9c02-a4634b64b82d" - ); - // Get the first matching item - let armItem = armItems?.[0]; - if (armItem) { - const targetMesh = scene?.getObjectByProperty("uuid", armItem.modelUuid); + const targetMesh = scene?.getObjectByProperty("uuid", armBot.modelUuid); + if (targetMesh) { targetMesh.visible = activeModule !== "simulation" } - } + const targetBones = ikSolver?.mesh.skeleton.bones.find( (b: any) => b.name === targetBone ); if (isReset) { + logStatus(armBot.modelUuid, "Simulation Play Reset Successfully") removeCurrentAction(armBot.modelUuid) setArmBotActive(armBot.modelUuid, true) @@ -127,8 +126,10 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { logStatus(armBot.modelUuid, "Moving armBot from initial point to rest position.") } if (isPlaying) { + //Moving armBot from initial point to rest position. if (!armBot?.isActive && armBot?.state == "idle" && currentPhase == "init") { + setArmBotActive(armBot.modelUuid, true) setArmBotState(armBot.modelUuid, "running") setCurrentPhase("init-to-rest"); @@ -144,12 +145,15 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { else if (armBot && !armBot.isActive && armBot.state === "idle" && currentPhase === "rest" && !armBot.currentAction) { logStatus(armBot.modelUuid, "Waiting to trigger CurrentAction") const timeoutId = setTimeout(() => { - addCurrentAction(armBot.modelUuid, 'action-003'); + let actionId=armBot.point.actions[0].actionUuid + // addCurrentAction(armBot.modelUuid,actionId); + addCurrentAction(armBot.modelUuid, selectedAction?.actionId); }, 3000); return () => clearTimeout(timeoutId); } 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"); @@ -253,7 +257,7 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { } } const logStatus = (id: string, status: string) => { - // console.log('status: ', status); + // } return ( @@ -261,296 +265,8 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { - ) } export default RoboticArmInstance; - - - - - - - - - - - - -// import React, { useEffect, useRef, useState } from 'react'; -// import IKInstance from '../ikInstance/ikInstance'; -// import RoboticArmAnimator from '../animator/roboticArmAnimator'; -// import { usePlayButtonStore, useResetButtonStore } from '../../../../../store/usePlayButtonStore'; -// import { useArmBotStore } from '../../../../../store/simulation/useArmBotStore'; -// import armModel from "../../../../../assets/gltf-glb/rigged/ik_arm_4.glb"; -// import { useThree } from "@react-three/fiber"; -// import { useFloorItems } from '../../../../../store/store'; -// import useModuleStore from '../../../../../store/useModuleStore'; -// import * as THREE from "three"; - -// function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { - -// const [currentPhase, setCurrentPhase] = useState("init"); -// const [path, setPath] = useState<[number, number, number][]>([]); -// const [ikSolver, setIkSolver] = useState(null); -// const { scene } = useThree(); -// const restPosition = new THREE.Vector3(0, 1, -1.6); -// const targetBone = "Target"; -// const groupRef = useRef(null); - -// // Zustand Stores -// const { addCurrentAction, setArmBotActive, setArmBotState, removeCurrentAction } = useArmBotStore(); -// const { floorItems } = useFloorItems(); -// const { activeModule } = useModuleStore(); -// const { isPlaying } = usePlayButtonStore(); -// const { isReset, setReset } = useResetButtonStore(); - -// // Generate path according to constraints -// const generateArmPath = ( -// startPoint: [number, number, number], -// endPoint: [number, number, number], -// restPos: THREE.Vector3 = new THREE.Vector3(0, 1, -1.6) -// ): [number, number, number][] => { -// const path: [number, number, number][] = []; - -// const startVec = new THREE.Vector3(...startPoint); -// const endVec = new THREE.Vector3(...endPoint); - -// // Helper functions -// const addLinePoints = (from: THREE.Vector3, to: THREE.Vector3, segments: number) => { -// for (let i = 0; i <= segments; i++) { -// const t = i / segments; -// const point = new THREE.Vector3().lerpVectors(from, to, t); -// path.push([point.x, point.y, point.z]); -// } -// }; - -// const addCurveFromTo = (from: THREE.Vector3, to: THREE.Vector3, segments: number = 15) => { -// const mid = new THREE.Vector3() -// .addVectors(from, to) -// .multiplyScalar(0.5) -// .setY(Math.max(from.y, to.y) + 0.5); -// const curve = new THREE.CatmullRomCurve3([from, mid, to]); -// const points = curve.getPoints(segments); -// for (const p of points) { -// path.push([p.x, p.y, p.z]); -// } -// }; - -// // Step 1: Move vertically to align Y with start point -// const step1Start = startVec.clone().setY(restPos.y); -// const step1End = startVec.clone(); -// addLinePoints(step1Start, step1End, 10); - -// // Step 2: Move horizontally XZ to reach start point -// const step2Start = step1End.clone(); -// const step2End = startVec.clone(); // ✅ Fixed here -// addLinePoints(step2Start, step2End, 10); -// addLinePoints(step1End, step2End, 10); - -// // Optional Step 3: Move to rest/midpoint if needed -// const distanceToRest = startVec.distanceTo(restPos); -// if (distanceToRest > 1) { -// addCurveFromTo(step2End, restPos, 15); -// } - -// // Step 4: Move up/down to align Y with end point -// const step4Start = endVec.clone().setY(restPos.y); -// const step4End = endVec.clone(); -// addLinePoints(step4Start, step4End, 10); - -// // Step 5: Move horizontally XZ to end point -// addLinePoints(step4End, endVec.clone(), 10); - -// // Step 6: Return to rest or mid-position after dropping -// const finalRestHeight = restPos.clone().setY(endVec.y + 0.5); -// addCurveFromTo(endVec, finalRestHeight, 15); - -// return path; -// }; - -// useEffect(() => { -// let armItems = floorItems?.filter((val: any) => -// val.modeluuid === armBot.modelUuid -// ); -// let armItem = armItems?.[0]; -// if (armItem) { -// const targetMesh = scene?.getObjectByProperty("uuid", armItem.modeluuid); -// if (targetMesh) { -// targetMesh.visible = activeModule !== "simulation"; -// } -// } - -// const targetBones = ikSolver?.mesh.skeleton.bones.find( -// (b: any) => b.name === targetBone -// ); - -// if (isReset) { -// logStatus(armBot.modelUuid, "Simulation Play Reset Successfully"); -// removeCurrentAction(armBot.modelUuid); -// setArmBotActive(armBot.modelUuid, true); -// setArmBotState(armBot.modelUuid, "running"); -// setCurrentPhase("init-to-rest"); - -// if (targetBones) { -// const startPoint = new THREE.Vector3(targetBones.position.x, targetBones.position.y, targetBones.position.z); -// const curve = new THREE.CatmullRomCurve3([ -// startPoint, -// startPoint.clone().setY(restPosition.y + 0.5), -// restPosition.clone(), -// ]); -// setPath(curve.getPoints(30).map(p => [p.x, p.y, p.z])); -// } - -// setReset(false); -// logStatus(armBot.modelUuid, "Moving armBot from initial point to rest position."); -// } - -// if (isPlaying) { -// // Phase 1: Initial -> Rest -// if (!armBot.isActive && armBot.state === "idle" && currentPhase === "init") { -// setArmBotActive(armBot.modelUuid, true); -// setArmBotState(armBot.modelUuid, "running"); -// setCurrentPhase("init-to-rest"); - -// if (targetBones) { -// const startPoint = new THREE.Vector3(targetBones.position.x, targetBones.position.y, targetBones.position.z); -// const curve = new THREE.CatmullRomCurve3([ -// startPoint, -// startPoint.clone().setY(restPosition.y + 0.5), -// restPosition.clone(), -// ]); -// setPath(curve.getPoints(30).map(p => [p.x, p.y, p.z])); -// } - -// logStatus(armBot.modelUuid, "Moving armBot from initial point to rest position."); -// } - -// // Phase 2: Wait for trigger -// else if (!armBot.isActive && armBot.state === "idle" && currentPhase === "rest" && !armBot.currentAction) { -// logStatus(armBot.modelUuid, "Waiting to trigger CurrentAction"); -// const timeoutId = setTimeout(() => { -// addCurrentAction(armBot.modelUuid, 'action-003'); -// }, 3000); -// return () => clearTimeout(timeoutId); -// } - -// // Phase 3: Rest -> Start Point -// else if (!armBot.isActive && armBot.state === "idle" && currentPhase === "rest" && armBot.currentAction) { -// setArmBotActive(armBot.modelUuid, true); -// setArmBotState(armBot.modelUuid, "running"); -// setCurrentPhase("rest-to-start"); - -// const startPoint = armBot.point.actions[0].process.startPoint; -// if (startPoint) { -// const start = new THREE.Vector3(startPoint[0], startPoint[1], startPoint[2]); -// const curve = new THREE.CatmullRomCurve3([restPosition, restPosition.clone().setY(start.y), start]); -// setPath(curve.getPoints(30).map(p => [p.x, p.y, p.z])); -// } - -// logStatus(armBot.modelUuid, "Moving armBot from rest point to start position."); -// } - -// // Phase 4: Start -> End (Pick & Move Object) -// else if (!armBot.isActive && armBot.state === "idle" && currentPhase === "picking" && armBot.currentAction) { -// setArmBotActive(armBot.modelUuid, true); -// setArmBotState(armBot.modelUuid, "running"); -// setCurrentPhase("start-to-end"); - -// const startPoint = armBot.point.actions[0].process.startPoint; -// const endPoint = armBot.point.actions[0].process.endPoint; - -// if (startPoint && endPoint) { -// const path = generateArmPath(startPoint, endPoint, restPosition); -// logStatus(armBot.modelUuid, "Waiting to pick."); -// setTimeout(()=>{ -// setPath(path); -// },3000) -// } - -// logStatus(armBot.modelUuid, "Moving armBot from start point to end position."); -// } - -// // Phase 5: End -> Rest (Drop & Return) -// else if (!armBot.isActive && armBot.state === "idle" && currentPhase === "dropping" && armBot.currentAction) { -// setArmBotActive(armBot.modelUuid, true); -// setArmBotState(armBot.modelUuid, "running"); -// setCurrentPhase("end-to-rest"); - -// const endPoint = armBot.point.actions[0].process.endPoint; -// if (endPoint) { -// const start = new THREE.Vector3(endPoint[0], endPoint[1], endPoint[2]); -// const curve = new THREE.CatmullRomCurve3([start, start.clone().setY(restPosition.y), restPosition]); -// logStatus(armBot.modelUuid, "Waiting to drop."); -// setTimeout(()=>{ -// setPath(curve.getPoints(30).map(p => [p.x, p.y, p.z])); -// },3000) - -// } - -// logStatus(armBot.modelUuid, "Moving armBot from end point to rest position."); -// } -// } else { -// logStatus(armBot.modelUuid, "Simulation Play Stopped"); -// setArmBotActive(armBot.modelUuid, false); -// setArmBotState(armBot.modelUuid, "idle"); -// setCurrentPhase("init"); -// setPath([]); -// removeCurrentAction(armBot.modelUuid); -// } - -// }, [currentPhase, armBot, isPlaying, ikSolver, isReset]); - -// 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, "idle"); -// 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, "idle"); -// 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([]); -// removeCurrentAction(armBot.modelUuid); -// } -// }; - -// const logStatus = (id: string, status: string) => { -// console.log( status); -// // console.log(`status [${id}]: ${status}`); -// }; - -// return ( -// <> -// -// -// -// ); -// } - -// export default RoboticArmInstance; \ No newline at end of file diff --git a/app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx b/app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx index c40bc92..e692ca5 100644 --- a/app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx +++ b/app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx @@ -71,8 +71,7 @@ function IKInstance({ modelUrl, setIkSolver, ikSolver, armBot, groupRef }: IKIns setSelectedArm(OOI.Target_Bone); - // scene.add(helper) - + scene.add(helper) }, [gltf]); diff --git a/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx b/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx index a313278..0acc1d9 100644 --- a/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx +++ b/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx @@ -1,4 +1,3 @@ -import React from 'react' import RoboticArmInstance from './armInstance/roboticArmInstance'; import { useArmBotStore } from '../../../../store/simulation/useArmBotStore'; @@ -10,7 +9,6 @@ function RoboticArmInstances() { {armBots?.map((robot: ArmBotStatus) => ( ))} - ) } diff --git a/app/src/modules/simulation/roboticArm/roboticArm.tsx b/app/src/modules/simulation/roboticArm/roboticArm.tsx index 5a5bd38..e4f2355 100644 --- a/app/src/modules/simulation/roboticArm/roboticArm.tsx +++ b/app/src/modules/simulation/roboticArm/roboticArm.tsx @@ -2,24 +2,26 @@ import { useEffect } from "react"; import RoboticArmInstances from "./instances/roboticArmInstances"; import { useArmBotStore } from "../../../store/simulation/useArmBotStore"; import { useFloorItems } from "../../../store/store"; -import { useSelectedEventData, useSelectedEventSphere } from "../../../store/simulation/useSimulationStore"; -import { useEventsStore } from "../../../store/simulation/useEventsStore"; +import { useSelectedEventData, useSelectedEventSphere, useSelectedProduct } from "../../../store/simulation/useSimulationStore"; +import { useProductStore } from "../../../store/simulation/useProductStore"; import { usePlayButtonStore } from "../../../store/usePlayButtonStore"; import ArmBotUI from "../ui/arm/armBotUI"; function RoboticArm() { const { armBots, addArmBot, removeArmBot } = useArmBotStore(); - const { addEvent } = useEventsStore(); + const { getProductById } = useProductStore(); + const { selectedProduct } = useSelectedProduct(); const { selectedEventSphere } = useSelectedEventSphere(); const { selectedEventData } = useSelectedEventData(); const { isPlaying } = usePlayButtonStore(); const { floorItems } = useFloorItems(); + const armBotStatusSample: RoboticArmEventSchema[] = [ { state: "idle", - modelUuid: "3abf5d46-b59e-4e6b-9c02-a4634b64b82d", + modelUuid: "8790b4d5-fb6e-49e0-8161-04945fe3fdc4", modelName: "ArmBot-X200", - position: [0.20849215906958463, 0, 0.32079278127773675], + position: [4.317833205016363, 0, -3.2829924989068715], rotation: [-1.3768690876192207e-15, 1.4883085074751308, 1.5407776675834467e-15], type: "roboticArm", speed: 1.5, @@ -156,24 +158,36 @@ function RoboticArm() { ]; useEffect(() => { + if (selectedProduct.productId) { + const product = getProductById(selectedProduct.productId); + if (product) { + product.eventDatas.forEach(events => { + if (events.type === 'roboticArm') { + removeArmBot(events.modelUuid); + addArmBot(selectedProduct.productId, events); + } + }); + } + } + }, [selectedProduct]); - removeArmBot(armBotStatusSample[0].modelUuid); - addArmBot('123', armBotStatusSample[0]); - // addArmBot('123', armBotStatusSample[1]); - // addCurrentAction('armbot-xyz-001', 'action-001'); - }, []); + // useEffect(()=>{ + // // removeArmBot("123", armBotStatusSample[0]); + // addArmBot("123", armBotStatusSample[0]); + // },[]) + + useEffect(() => { + + }, [armBots]) useEffect(() => { - console.log('isPlaying: ', isPlaying); - console.log('selectedEventData: ', selectedEventData); - console.log('selectedEventSphere: ', selectedEventSphere); }, [selectedEventData, selectedEventSphere, isPlaying]); return ( <> - {selectedEventSphere && selectedEventData?.data.type === "roboticArm" && !isPlaying && + {selectedEventSphere && selectedEventData?.data.type === "roboticArm" && < ArmBotUI /> } diff --git a/app/src/modules/simulation/ui/arm/PickDropPoints.tsx b/app/src/modules/simulation/ui/arm/PickDropPoints.tsx index 4544a46..831da7f 100644 --- a/app/src/modules/simulation/ui/arm/PickDropPoints.tsx +++ b/app/src/modules/simulation/ui/arm/PickDropPoints.tsx @@ -9,7 +9,7 @@ interface PickDropProps { actionType: "pick" | "drop"; actionUuid: string; gltfScene: THREE.Group; - selectedPoint: THREE.Mesh | null; + handlePointerDown: (e: ThreeEvent) => void; isSelected: boolean; } @@ -21,10 +21,11 @@ const PickDropPoints: React.FC = ({ actionType, actionUuid, gltfScene, - selectedPoint, handlePointerDown, isSelected, }) => { + + const groupRef = useRef(null); return ( @@ -36,15 +37,24 @@ const PickDropPoints: React.FC = ({ : new THREE.Vector3(0, 0, 0) } onPointerDown={(e) => { - e.stopPropagation(); // Important to prevent event bubbling + + e.stopPropagation(); // Prevent event bubbling if (!isSelected) return; handlePointerDown(e); }} userData={{ modelUuid, pointUuid, actionType, actionUuid }} > { + const cloned = gltfScene.clone(); + cloned.traverse((child: any) => { + if (child.isMesh) { + child.userData = { modelUuid, pointUuid, actionType, actionUuid }; + } + }); + return cloned; + })()} + position={[0, 0, 0]} scale={[0.5, 0.5, 0.5]} /> diff --git a/app/src/modules/simulation/ui/arm/armBotUI.tsx b/app/src/modules/simulation/ui/arm/armBotUI.tsx index 7e111e3..d616206 100644 --- a/app/src/modules/simulation/ui/arm/armBotUI.tsx +++ b/app/src/modules/simulation/ui/arm/armBotUI.tsx @@ -1,155 +1,189 @@ -import React from 'react' -import PickDropPoints from './PickDropPoints'; -import { useSelectedEventData, useSelectedEventSphere } from '../../../../store/simulation/useSimulationStore'; +import React, { useCallback, useEffect, useState } from 'react'; +import { useSelectedEventData, useSelectedEventSphere, useSelectedProduct } from '../../../../store/simulation/useSimulationStore'; import { useArmBotStore } from '../../../../store/simulation/useArmBotStore'; -import useModuleStore from '../../../../store/useModuleStore'; import { useGLTF } from '@react-three/drei'; +import { useThree } from '@react-three/fiber'; +import { useProductStore } from '../../../../store/simulation/useProductStore'; +import PickDropPoints from './PickDropPoints'; +import useDraggableGLTF from './useDraggableGLTF'; +import * as THREE from 'three'; + import armPick from "../../../../assets/gltf-glb/arm_ui_pick.glb"; import armDrop from "../../../../assets/gltf-glb/arm_ui_drop.glb"; -import useDraggableGLTF from './useDraggableGLTF'; -import * as THREE from "three"; -import { useThree } from '@react-three/fiber'; +import useModuleStore from '../../../../store/useModuleStore'; + +type Positions = { + pick: [number, number, number]; + drop: [number, number, number]; + default: [number, number, number]; +}; + const ArmBotUI = () => { - console.log("called"); - const { selectedEventSphere } = useSelectedEventSphere(); - const { selectedEventData } = useSelectedEventData(); - const { armBots, updateArmBot } = useArmBotStore(); - const armUiPick = useGLTF(armPick) as any; - const { scene } = useThree(); - const armUiDrop = useGLTF(armDrop) as any; + const { getEventByModelUuid } = useProductStore(); + const { selectedEventData } = useSelectedEventData(); + const { selectedProduct } = useSelectedProduct(); + const { armBots, updateStartPoint, updateEndPoint } = useArmBotStore(); + const { scene } = useThree(); - const getDefaultPositions = (modelUuid: string) => { - const modelData = getModelByUuid(modelUuid); - if (modelData) { - - const baseX = modelData.position?.[0] || 0; - const baseY = 2.6; - const baseZ = modelData.position?.[2] || 0; - return { - pick: [baseX, baseY, baseZ + 0.4], - drop: [baseX, baseY, baseZ - 1.2], - default: [baseX, baseY, baseZ - 1.5], - }; + const armUiPick = useGLTF(armPick) as any; + const armUiDrop = useGLTF(armDrop) as any; + + const [startPosition, setStartPosition] = useState<[number, number, number]>([0, 0, 0]); + const [endPosition, setEndPosition] = useState<[number, number, number]>([0, 0, 0]); + const [selectedArmBotData, setSelectedArmBotData] = useState(null); + + // Fetch and setup selected ArmBot data + useEffect(() => { + if (selectedEventData?.data.type === "roboticArm") { + const selectedArmBot = getEventByModelUuid(selectedProduct.productId, selectedEventData.data.modelUuid); + + if (selectedArmBot) { + if (selectedArmBot.type === "roboticArm") { + + setSelectedArmBotData(selectedArmBot); + + const defaultPositions = getDefaultPositions(selectedArmBot.modelUuid); + + selectedArmBot?.point?.actions?.forEach((action: any) => { + if (action.actionType === "pickAndPlace") { + const startPoint = action.process.startPoint; + const pickPosition = (!startPoint || (Array.isArray(startPoint) && startPoint.every(v => v === 0))) + ? defaultPositions.pick + : startPoint; + const endPoint = action.process.endPoint; + const dropPosition = (!endPoint || (Array.isArray(endPoint) && endPoint.every(v => v === 0))) + ? defaultPositions.drop + : endPoint; + setStartPosition(pickPosition); + setEndPosition(dropPosition) + + } + }); } - return { - pick: [0.5, 1.5, 0], - drop: [-0.5, 1.5, 0], - default: [0, 1.5, 0], - }; - }; - const getModelByUuid = (modelUuid: string) => { - try { - const modelsJson = localStorage.getItem("FloorItems"); - if (modelsJson) { - const models = JSON.parse(modelsJson); - return models.find((m: any) => m.modeluuid === modelUuid); - } - const storeModels = (useModuleStore.getState() as any).models || []; - return storeModels.find((m: any) => m.modelUuid === modelUuid); - } catch (error) { } - return null; - }; - const updatePointToState = (obj: THREE.Object3D) => { - const { modelUuid, pointUuid, actionType, actionUuid } = obj.userData; - - const newPosition = new THREE.Vector3(); - obj.getWorldPosition(newPosition); - const worldPositionArray = newPosition.toArray(); - - const armBot = armBots.find((a) => a.modelUuid === modelUuid); - if (!armBot) return; - - const updatedActions = armBot.point.actions.map((action: any) => { - if (action.actionUuid === actionUuid) { - const updatedProcess = { ...action.process }; - - if (actionType === "pick") { - updatedProcess.startPoint = getLocalPosition(modelUuid, worldPositionArray); - } - if (actionType === "drop") { - updatedProcess.endPoint = getLocalPosition(modelUuid, worldPositionArray); - } - return { - ...action, - process: updatedProcess, - }; - } - return action; - }); - - updateArmBot(modelUuid, { - point: { - ...armBot.point, - actions: updatedActions, - }, - }); - }; - function getLocalPosition(parentUuid: string, worldPosArray: [number, number, number] | null): [number, number, number] | null { - if (worldPosArray) { - const worldPos = new THREE.Vector3(...worldPosArray); - const localPos = worldPos.clone(); - - const parentObject = scene.getObjectByProperty('uuid', parentUuid); - if (parentObject) { - parentObject.worldToLocal(localPos); - - return [localPos.x, localPos.y, localPos.z]; - } else { - - } - } - return null; - } - const { handlePointerDown } = useDraggableGLTF(updatePointToState); - - return ( - <> - {armBots.map((event: any) => { - const defaultPositions = getDefaultPositions(event.modelUuid); - const isSelected = - selectedEventSphere?.userData?.modelUuid === event.modelUuid; - - return event.point.actions.map((action: any) => { - if (action.actionType === "pickAndPlace") { - const pickPosition = action.process.startPoint || defaultPositions.pick; - const dropPosition = action.process.endPoint || defaultPositions.drop; - - return ( - - {/* Pick Point */} - - - {/* Drop Point */} - - - ); - } - return null; - }); - })} - - ); - + } + } + }, [selectedEventData, selectedProduct, getEventByModelUuid]); -} -export default ArmBotUI \ No newline at end of file + 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 (selectedEventData?.data.type === "roboticArm") { + const selectedArmBot = getEventByModelUuid(selectedProduct.productId, selectedEventData.data.modelUuid); + + const armBot = selectedArmBot?.modelUuid === modelUuid ? selectedArmBot : null; + if (!armBot) return; + + if (armBot.type === "roboticArm") { + armBot?.point?.actions?.map((action: any) => { + if (action.actionUuid === actionUuid) { + const updatedProcess = { ...action.process }; + + if (actionType === "pick") { + updatedProcess.startPoint = getLocalPosition(modelUuid, worldPositionArray); + // updatedProcess.startPoint = worldPositionArray + setStartPosition(updatedProcess.startPoint) + + updateStartPoint(modelUuid, actionUuid, updatedProcess.startPoint); + } else if (actionType === "drop") { + updatedProcess.endPoint = getLocalPosition(modelUuid, worldPositionArray); + // updatedProcess.endPoint = worldPositionArray + setEndPosition(updatedProcess.endPoint) + updateEndPoint(modelUuid, actionUuid, updatedProcess.endPoint); + } + return { + ...action, + process: updatedProcess, + }; + } + return action; + }); + + } + } + } + + useEffect(() => { + + +}, [armBots]) + + 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) => ( + + + + + + + ))} + + ); +}; + +export default ArmBotUI; diff --git a/app/src/modules/simulation/ui/arm/useDraggableGLTF.ts b/app/src/modules/simulation/ui/arm/useDraggableGLTF.ts index d73b4a9..01b7932 100644 --- a/app/src/modules/simulation/ui/arm/useDraggableGLTF.ts +++ b/app/src/modules/simulation/ui/arm/useDraggableGLTF.ts @@ -1,11 +1,11 @@ -import { useRef } from "react"; +import { useRef, useState } from "react"; import * as THREE from "three"; import { ThreeEvent, useThree } from "@react-three/fiber"; type OnUpdateCallback = (object: THREE.Object3D) => void; export default function useDraggableGLTF(onUpdate: OnUpdateCallback) { - const { camera, gl, controls, scene } = useThree(); + const { camera, gl, controls } = useThree(); const activeObjRef = useRef(null); const planeRef = useRef( new THREE.Plane(new THREE.Vector3(0, 1, 0), 0) @@ -15,6 +15,7 @@ export default function useDraggableGLTF(onUpdate: OnUpdateCallback) { const raycaster = new THREE.Raycaster(); const pointer = new THREE.Vector2(); + const [objectWorldPos, setObjectWorldPos] = useState(new THREE.Vector3()); const handlePointerDown = (e: ThreeEvent) => { e.stopPropagation(); @@ -33,10 +34,10 @@ export default function useDraggableGLTF(onUpdate: OnUpdateCallback) { activeObjRef.current = obj; initialPositionRef.current.copy(obj.position); + console.log("obj.position: ", obj.position); // Get world position - const objectWorldPos = new THREE.Vector3(); - obj.getWorldPosition(objectWorldPos); + setObjectWorldPos(obj.getWorldPosition(objectWorldPos)); // Set plane at the object's Y level planeRef.current.set(new THREE.Vector3(0, 1, 0), -objectWorldPos.y); @@ -61,52 +62,56 @@ export default function useDraggableGLTF(onUpdate: OnUpdateCallback) { const handlePointerMove = (e: PointerEvent) => { if (!activeObjRef.current) return; - + // Check if Shift key is pressed const isShiftKeyPressed = e.shiftKey; - + // Get the mouse position relative to the canvas const rect = gl.domElement.getBoundingClientRect(); pointer.x = ((e.clientX - rect.left) / rect.width) * 2 - 1; pointer.y = -((e.clientY - rect.top) / rect.height) * 2 + 1; - + // Update raycaster to point to the mouse position raycaster.setFromCamera(pointer, camera); - + // Create a vector to store intersection point const intersection = new THREE.Vector3(); - const intersects = raycaster.ray.intersectPlane(planeRef.current, intersection); + const intersects = raycaster.ray.intersectPlane( + planeRef.current, + intersection + ); if (!intersects) return; - + // Add offset for dragging intersection.add(offsetRef.current); - - + // Get the parent's world matrix if exists const parent = activeObjRef.current.parent; const targetPosition = new THREE.Vector3(); - + + // OnPointerDown + initialPositionRef.current.copy(objectWorldPos); + + // OnPointerMove if (isShiftKeyPressed) { - console.log('isShiftKeyPressed: ', isShiftKeyPressed); - // For Y-axis only movement, maintain original X and Z - console.log('initialPositionRef: ', initialPositionRef); - console.log('intersection.y: ', intersection); - targetPosition.set( - initialPositionRef.current.x, - intersection.y, - initialPositionRef.current.z - ); + const { x: initialX, y: initialY } = initialPositionRef.current; + const { x: objectX, z: objectZ } = objectWorldPos; + + const deltaX = intersection.x - initialX; + + targetPosition.set(objectX, initialY + deltaX, objectZ); } else { // For free movement targetPosition.copy(intersection); } - + // Convert world position to local if object is nested inside a parent if (parent) { parent.worldToLocal(targetPosition); } - + // Update object position + activeObjRef.current.position.copy(targetPosition); }; @@ -126,6 +131,3 @@ export default function useDraggableGLTF(onUpdate: OnUpdateCallback) { return { handlePointerDown }; } - - - From 80e7bf4bf9c701ec83693f9de127b60674b16cfb Mon Sep 17 00:00:00 2001 From: Gomathi9520 Date: Fri, 2 May 2025 18:33:27 +0530 Subject: [PATCH 6/8] armbot position updated --- .../builder/IntialLoad/loadInitialFloorItems.ts | 4 ++-- .../builder/geomentries/assets/assetManager.ts | 3 ++- .../controls/selectionControls/moveControls.tsx | 2 ++ .../controls/selectionControls/rotateControls.tsx | 2 ++ .../instances/armInstance/roboticArmInstance.tsx | 4 ++-- .../modules/simulation/roboticArm/roboticArm.tsx | 13 ++++--------- app/src/modules/simulation/simulation.tsx | 4 ++-- 7 files changed, 16 insertions(+), 16 deletions(-) diff --git a/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts b/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts index ee5c283..9f71945 100644 --- a/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts +++ b/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts @@ -282,8 +282,8 @@ function processLoadedModel( actionName: "Action 1", actionType: "pickAndPlace", process: { - startPoint: [0, 0, 0], - endPoint: [0, 0, 0] + startPoint: null, + endPoint: null }, triggers: [] } diff --git a/app/src/modules/builder/geomentries/assets/assetManager.ts b/app/src/modules/builder/geomentries/assets/assetManager.ts index 5f7798e..b632626 100644 --- a/app/src/modules/builder/geomentries/assets/assetManager.ts +++ b/app/src/modules/builder/geomentries/assets/assetManager.ts @@ -121,7 +121,8 @@ export default async function assetManager( const model = gltf; model.uuid = item.modelUuid; - model.userData = { name: item.modelName, modelId: item.modelfileID, modelUuid: item.modelUuid }; + console.log('item: ', item); + model.userData = { name: item.modelName, modelId: item.modelfileID, modelUuid: item.modelUuid, eventData: item.eventData }; model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap); model.position.set(...item.position); model.rotation.set(item.rotation.x, item.rotation.y, item.rotation.z); diff --git a/app/src/modules/scene/controls/selectionControls/moveControls.tsx b/app/src/modules/scene/controls/selectionControls/moveControls.tsx index cc9ce50..3084952 100644 --- a/app/src/modules/scene/controls/selectionControls/moveControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/moveControls.tsx @@ -222,6 +222,8 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje event ); } + + newFloorItem.eventData = eventData; } } diff --git a/app/src/modules/scene/controls/selectionControls/rotateControls.tsx b/app/src/modules/scene/controls/selectionControls/rotateControls.tsx index 7ea7045..58dab0c 100644 --- a/app/src/modules/scene/controls/selectionControls/rotateControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/rotateControls.tsx @@ -222,6 +222,8 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo event ); } + + newFloorItem.eventData = eventData; } } diff --git a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx index d4b7eaa..4fd5860 100644 --- a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx +++ b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx @@ -146,8 +146,8 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { logStatus(armBot.modelUuid, "Waiting to trigger CurrentAction") const timeoutId = setTimeout(() => { let actionId=armBot.point.actions[0].actionUuid - // addCurrentAction(armBot.modelUuid,actionId); - addCurrentAction(armBot.modelUuid, selectedAction?.actionId); + addCurrentAction(armBot.modelUuid,actionId); + // addCurrentAction(armBot.modelUuid, selectedAction?.actionId); }, 3000); return () => clearTimeout(timeoutId); } diff --git a/app/src/modules/simulation/roboticArm/roboticArm.tsx b/app/src/modules/simulation/roboticArm/roboticArm.tsx index e4f2355..528b0bd 100644 --- a/app/src/modules/simulation/roboticArm/roboticArm.tsx +++ b/app/src/modules/simulation/roboticArm/roboticArm.tsx @@ -8,8 +8,8 @@ import { usePlayButtonStore } from "../../../store/usePlayButtonStore"; import ArmBotUI from "../ui/arm/armBotUI"; function RoboticArm() { - const { armBots, addArmBot, removeArmBot } = useArmBotStore(); - const { getProductById } = useProductStore(); + const { armBots, addArmBot, clearArmBots } = useArmBotStore(); + const { products, getProductById } = useProductStore(); const { selectedProduct } = useSelectedProduct(); const { selectedEventSphere } = useSelectedEventSphere(); const { selectedEventData } = useSelectedEventData(); @@ -161,20 +161,15 @@ function RoboticArm() { if (selectedProduct.productId) { const product = getProductById(selectedProduct.productId); if (product) { + clearArmBots(); product.eventDatas.forEach(events => { if (events.type === 'roboticArm') { - removeArmBot(events.modelUuid); addArmBot(selectedProduct.productId, events); } }); } } - }, [selectedProduct]); - - // useEffect(()=>{ - // // removeArmBot("123", armBotStatusSample[0]); - // addArmBot("123", armBotStatusSample[0]); - // },[]) + }, [selectedProduct, products]); useEffect(() => { diff --git a/app/src/modules/simulation/simulation.tsx b/app/src/modules/simulation/simulation.tsx index 757a9ef..efacd53 100644 --- a/app/src/modules/simulation/simulation.tsx +++ b/app/src/modules/simulation/simulation.tsx @@ -29,14 +29,14 @@ function Simulation() { return ( <> + + {activeModule === 'simulation' && <> - - From 39c86b6fc149d98c5aa1e9a1b26f688323ccac4f Mon Sep 17 00:00:00 2001 From: Gomathi9520 Date: Fri, 2 May 2025 18:34:44 +0530 Subject: [PATCH 7/8] consoles cleared --- .../builder/IntialLoad/loadInitialFloorItems.ts | 8 ++++---- .../builder/geomentries/assets/assetManager.ts | 11 +++++------ app/src/modules/simulation/ui/arm/useDraggableGLTF.ts | 2 +- app/src/modules/simulation/vehicle/vehicles.tsx | 2 +- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts b/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts index 9f71945..0ce28ce 100644 --- a/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts +++ b/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts @@ -72,7 +72,7 @@ async function loadInitialFloorItems( // Check Three.js Cache const cachedModel = THREE.Cache.get(item.modelfileID!); if (cachedModel) { - // console.log(`[Cache] Fetching ${item.modelName}`); + // processLoadedModel(cachedModel.scene.clone(), item, itemsGroup, setFloorItems, addEvent); modelsLoaded++; checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve); @@ -82,7 +82,7 @@ async function loadInitialFloorItems( // Check IndexedDB const indexedDBModel = await retrieveGLTF(item.modelfileID!); if (indexedDBModel) { - // console.log(`[IndexedDB] Fetching ${item.modelName}`); + // const blobUrl = URL.createObjectURL(indexedDBModel); loader.load(blobUrl, (gltf) => { URL.revokeObjectURL(blobUrl); @@ -103,7 +103,7 @@ async function loadInitialFloorItems( } // Fetch from Backend - // console.log(`[Backend] Fetching ${item.modelName}`); + // const modelUrl = `${url_Backend_dwinzo}/api/v2/AssetFile/${item.modelfileID!}`; loader.load(modelUrl, async (gltf) => { const modelBlob = await fetch(modelUrl).then((res) => res.blob()); @@ -121,7 +121,7 @@ async function loadInitialFloorItems( ); }); } else { - // console.log(`Item ${item.modelName} is not near`); + // setFloorItems((prevItems) => [ ...(prevItems || []), { diff --git a/app/src/modules/builder/geomentries/assets/assetManager.ts b/app/src/modules/builder/geomentries/assets/assetManager.ts index b632626..889d905 100644 --- a/app/src/modules/builder/geomentries/assets/assetManager.ts +++ b/app/src/modules/builder/geomentries/assets/assetManager.ts @@ -18,7 +18,7 @@ export default async function assetManager( const taskId = ++currentTaskId; // Increment taskId for each call activePromises.set(taskId, true); // Mark task as active - // console.log("Received message from worker:", data); + // if (data.toRemove.length > 0) { data.toRemove.forEach((uuid: string) => { @@ -58,7 +58,7 @@ export default async function assetManager( // Check Three.js Cache const cachedModel = THREE.Cache.get(item.modelfileID!); if (cachedModel) { - // console.log(`[Cache] Fetching ${item.modelName}`); + // processLoadedModel(cachedModel.scene.clone(), item, itemsGroup, resolve); return; } @@ -66,7 +66,7 @@ export default async function assetManager( // Check IndexedDB const indexedDBModel = await retrieveGLTF(item.modelfileID!); if (indexedDBModel) { - // console.log(`[IndexedDB] Fetching ${item.modelName}`); + // const blobUrl = URL.createObjectURL(indexedDBModel); loader.load( blobUrl, @@ -86,7 +86,7 @@ export default async function assetManager( } // Fetch from Backend - // console.log(`[Backend] Fetching ${item.modelName}`); + // loader.load( modelUrl, async (gltf) => { @@ -114,14 +114,13 @@ export default async function assetManager( const existingModel = itemsGroup?.current?.getObjectByProperty("uuid", item.modelUuid); if (existingModel) { - // console.log(`Model ${item.modelName} already exists in the scene.`); + // resolve(); return; } const model = gltf; model.uuid = item.modelUuid; - console.log('item: ', item); model.userData = { name: item.modelName, modelId: item.modelfileID, modelUuid: item.modelUuid, eventData: item.eventData }; model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap); model.position.set(...item.position); diff --git a/app/src/modules/simulation/ui/arm/useDraggableGLTF.ts b/app/src/modules/simulation/ui/arm/useDraggableGLTF.ts index 01b7932..e450bfd 100644 --- a/app/src/modules/simulation/ui/arm/useDraggableGLTF.ts +++ b/app/src/modules/simulation/ui/arm/useDraggableGLTF.ts @@ -34,7 +34,7 @@ export default function useDraggableGLTF(onUpdate: OnUpdateCallback) { activeObjRef.current = obj; initialPositionRef.current.copy(obj.position); - console.log("obj.position: ", obj.position); + // Get world position setObjectWorldPos(obj.getWorldPosition(objectWorldPos)); diff --git a/app/src/modules/simulation/vehicle/vehicles.tsx b/app/src/modules/simulation/vehicle/vehicles.tsx index 19f049c..3fbc8ef 100644 --- a/app/src/modules/simulation/vehicle/vehicles.tsx +++ b/app/src/modules/simulation/vehicle/vehicles.tsx @@ -29,7 +29,7 @@ function Vehicles() { }, [selectedProduct, products]); useEffect(() => { - // console.log('vehicles: ', vehicles); + // }, [vehicles]) return ( From 0e4005f31e79101d693cc263c521c514880980c2 Mon Sep 17 00:00:00 2001 From: Gomathi9520 Date: Sat, 3 May 2025 10:05:25 +0530 Subject: [PATCH 8/8] multiple action state updated --- .../events/points/creator/pointsCreator.tsx | 3 - .../instances/animator/roboticArmAnimator.tsx | 2 - .../armInstance/roboticArmInstance.tsx | 125 +++++++++--------- .../simulation/roboticArm/roboticArm.tsx | 1 - .../simulation/ui/arm/PickDropPoints.tsx | 3 - .../modules/simulation/ui/arm/armBotUI.tsx | 119 ++++++++--------- 6 files changed, 125 insertions(+), 128 deletions(-) diff --git a/app/src/modules/simulation/events/points/creator/pointsCreator.tsx b/app/src/modules/simulation/events/points/creator/pointsCreator.tsx index 5037f75..0ed7e13 100644 --- a/app/src/modules/simulation/events/points/creator/pointsCreator.tsx +++ b/app/src/modules/simulation/events/points/creator/pointsCreator.tsx @@ -31,8 +31,6 @@ function PointsCreator() { selectedEventSphere.userData.modelUuid ); - - if (eventData) { setSelectedEventData(eventData, selectedEventSphere.userData.pointUuid); } else { @@ -215,7 +213,6 @@ function PointsCreator() { ); }} onPointerMissed={() => { - // clearSelectedEventSphere(); setTransformMode(null); }} position={new THREE.Vector3(...event.point.position)} diff --git a/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx b/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx index d32a6c3..10f90bf 100644 --- a/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx +++ b/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx @@ -55,11 +55,9 @@ function RoboticArmAnimator({ for (let i = 0; i < segments; i++) { // Calculate angle for current segment const angle = (i / segments) * Math.PI * 2; - // Calculate x and z coordinates (y remains the same for a flat ring) const x = Math.cos(angle) * radius; const z = Math.sin(angle) * radius; - points.push([x, 1.5, z]); } return points; diff --git a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx index 4fd5860..9199ede 100644 --- a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx +++ b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx @@ -8,7 +8,9 @@ import { useThree } from "@react-three/fiber"; import { useFloorItems } from '../../../../../store/store'; import useModuleStore from '../../../../../store/useModuleStore'; import * as THREE from "three"; -import { useSelectedAction } from '../../../../../store/simulation/useSimulationStore'; +import { useSelectedAction, useSelectedProduct } from '../../../../../store/simulation/useSimulationStore'; +import { useProductStore } from '../../../../../store/simulation/useProductStore'; + function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { @@ -24,17 +26,19 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { let startTime: number; //zustand const { addCurrentAction, setArmBotActive, setArmBotState, removeCurrentAction } = useArmBotStore(); + const { products, getActionByUuid } = useProductStore(); + const { selectedProduct } = useSelectedProduct(); const { floorItems } = useFloorItems(); const { activeModule } = useModuleStore(); const { isPlaying } = usePlayButtonStore(); const { isReset, setReset } = useResetButtonStore(); const { isPaused } = usePauseButtonStore(); - const { selectedAction } = useSelectedAction(); - + const { selectedAction } = useSelectedAction(); + function firstFrame() { startTime = performance.now(); step(); - } + } function step() { if (isPausedRef.current) { if (!pauseTimeRef.current) { @@ -54,70 +58,70 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { requestAnimationFrame(step); return; } - if(currentPhase==="picking"){ - - setArmBotActive(armBot.modelUuid, true); - setArmBotState(armBot.modelUuid, "running"); - setCurrentPhase("start-to-end"); - startTime=0 - const startPoint = armBot.point.actions[0].process.startPoint; - const endPoint = armBot.point.actions[0].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])) - } + if (currentPhase === "picking") { + + setArmBotActive(armBot.modelUuid, true); + setArmBotState(armBot.modelUuid, "running"); + setCurrentPhase("start-to-end"); + startTime = 0 + const startPoint = armBot.point.actions[0].process.startPoint; + const endPoint = armBot.point.actions[0].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])) } - 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; - const endPoint = armBot.point.actions[0].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])); - } - } - logStatus(armBot.modelUuid, "Moving armBot from end point to rest position.") } - - } - useEffect(() => { + 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; + const endPoint = armBot.point.actions[0].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])); + } + } + logStatus(armBot.modelUuid, "Moving armBot from end point to rest position.") + } + + } + useEffect(() => { isPausedRef.current = isPaused; }, [isPaused]); useEffect(() => { - const targetMesh = scene?.getObjectByProperty("uuid", armBot.modelUuid); - - if (targetMesh) { - targetMesh.visible = activeModule !== "simulation" - } + const targetMesh = scene?.getObjectByProperty("uuid", armBot.modelUuid); + + if (targetMesh) { + targetMesh.visible = activeModule !== "simulation" + } const targetBones = ikSolver?.mesh.skeleton.bones.find( (b: any) => b.name === targetBone ); if (isReset) { - + logStatus(armBot.modelUuid, "Simulation Play Reset Successfully") removeCurrentAction(armBot.modelUuid) setArmBotActive(armBot.modelUuid, true) setArmBotState(armBot.modelUuid, "running") setCurrentPhase("init-to-rest"); - isPausedRef.current=false - pauseTimeRef.current=null - isPausedRef.current=false - startTime=0 + isPausedRef.current = false + pauseTimeRef.current = null + isPausedRef.current = false + startTime = 0 if (targetBones) { - let curve = createCurveBetweenTwoPoints(targetBones.position, restPosition) + let curve = createCurveBetweenTwoPoints(targetBones.position, targetBones.position) if (curve) { setPath(curve.points.map(point => [point.x, point.y, point.z])); } @@ -126,10 +130,10 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { logStatus(armBot.modelUuid, "Moving armBot from initial point to rest position.") } if (isPlaying) { - + //Moving armBot from initial point to rest position. if (!armBot?.isActive && armBot?.state == "idle" && currentPhase == "init") { - + setArmBotActive(armBot.modelUuid, true) setArmBotState(armBot.modelUuid, "running") setCurrentPhase("init-to-rest"); @@ -145,18 +149,19 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { else if (armBot && !armBot.isActive && armBot.state === "idle" && currentPhase === "rest" && !armBot.currentAction) { logStatus(armBot.modelUuid, "Waiting to trigger CurrentAction") const timeoutId = setTimeout(() => { - let actionId=armBot.point.actions[0].actionUuid - addCurrentAction(armBot.modelUuid,actionId); - // addCurrentAction(armBot.modelUuid, selectedAction?.actionId); + addCurrentAction(armBot.modelUuid, selectedAction?.actionId); + console.log('selectedAction?.actionId: ', selectedAction?.actionId); }, 3000); return () => clearTimeout(timeoutId); } 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"); + let actiondata = getActionByUuid(selectedProduct.productId, selectedAction.actionId) + console.log('actiondata: ', actiondata); const startPoint = armBot.point.actions[0].process.startPoint; if (startPoint) { let curve = createCurveBetweenTwoPoints(restPosition, new THREE.Vector3(startPoint[0], startPoint[1], startPoint[2])); @@ -211,7 +216,7 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { setCurrentPhase("init"); setPath([]) removeCurrentAction(armBot.modelUuid) - + } }, [currentPhase, armBot, isPlaying, ikSolver, isReset]) @@ -258,14 +263,14 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { } const logStatus = (id: string, status: string) => { // - + } return ( <> + logStatus={logStatus} path={path} currentPhase={currentPhase} /> ) } diff --git a/app/src/modules/simulation/roboticArm/roboticArm.tsx b/app/src/modules/simulation/roboticArm/roboticArm.tsx index 528b0bd..2cb9ea6 100644 --- a/app/src/modules/simulation/roboticArm/roboticArm.tsx +++ b/app/src/modules/simulation/roboticArm/roboticArm.tsx @@ -172,7 +172,6 @@ function RoboticArm() { }, [selectedProduct, products]); useEffect(() => { - }, [armBots]) useEffect(() => { diff --git a/app/src/modules/simulation/ui/arm/PickDropPoints.tsx b/app/src/modules/simulation/ui/arm/PickDropPoints.tsx index 831da7f..c44eee8 100644 --- a/app/src/modules/simulation/ui/arm/PickDropPoints.tsx +++ b/app/src/modules/simulation/ui/arm/PickDropPoints.tsx @@ -24,10 +24,7 @@ const PickDropPoints: React.FC = ({ handlePointerDown, isSelected, }) => { - - const groupRef = useRef(null); - return ( { const { selectedProduct } = useSelectedProduct(); const { armBots, updateStartPoint, updateEndPoint } = useArmBotStore(); const { scene } = useThree(); + const { selectedAction } = useSelectedAction(); const armUiPick = useGLTF(armPick) as any; const armUiDrop = useGLTF(armDrop) as any; @@ -37,43 +38,40 @@ const ArmBotUI = () => { if (selectedEventData?.data.type === "roboticArm") { const selectedArmBot = getEventByModelUuid(selectedProduct.productId, selectedEventData.data.modelUuid); - if (selectedArmBot) { - if (selectedArmBot.type === "roboticArm") { + if (selectedArmBot?.type === "roboticArm") { + setSelectedArmBotData(selectedArmBot); + const defaultPositions = getDefaultPositions(selectedArmBot.modelUuid); + const matchingAction = armBots?.flatMap((robot: ArmBotStatus) => robot.point.actions) + .find((action) => action.actionUuid === selectedAction.actionId); + if (matchingAction) { + const startPoint = matchingAction.process.startPoint; + const pickPosition = (!startPoint || (Array.isArray(startPoint) && startPoint.every(v => v === 0))) + ? defaultPositions.pick + : startPoint; - setSelectedArmBotData(selectedArmBot); + const endPoint = matchingAction.process.endPoint; + const dropPosition = (!endPoint || (Array.isArray(endPoint) && endPoint.every(v => v === 0))) + ? defaultPositions.drop + : endPoint; - const defaultPositions = getDefaultPositions(selectedArmBot.modelUuid); - - selectedArmBot?.point?.actions?.forEach((action: any) => { - if (action.actionType === "pickAndPlace") { - const startPoint = action.process.startPoint; - const pickPosition = (!startPoint || (Array.isArray(startPoint) && startPoint.every(v => v === 0))) - ? defaultPositions.pick - : startPoint; - const endPoint = action.process.endPoint; - const dropPosition = (!endPoint || (Array.isArray(endPoint) && endPoint.every(v => v === 0))) - ? defaultPositions.drop - : endPoint; - setStartPosition(pickPosition); - setEndPosition(dropPosition) - - } - }); + setStartPosition(pickPosition); + setEndPosition(dropPosition); } } } - }, [selectedEventData, selectedProduct, getEventByModelUuid]); + }, [selectedEventData, 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], + pick: [baseX, baseY, baseZ + 0.5], + drop: [baseX, baseY, baseZ - 0.5], default: [baseX, baseY, baseZ], }; } @@ -118,13 +116,10 @@ const ArmBotUI = () => { if (actionType === "pick") { updatedProcess.startPoint = getLocalPosition(modelUuid, worldPositionArray); - // updatedProcess.startPoint = worldPositionArray setStartPosition(updatedProcess.startPoint) - updateStartPoint(modelUuid, actionUuid, updatedProcess.startPoint); } else if (actionType === "drop") { updatedProcess.endPoint = getLocalPosition(modelUuid, worldPositionArray); - // updatedProcess.endPoint = worldPositionArray setEndPosition(updatedProcess.endPoint) updateEndPoint(modelUuid, actionUuid, updatedProcess.endPoint); } @@ -143,47 +138,53 @@ const ArmBotUI = () => { useEffect(() => { -}, [armBots]) + }, [armBots]) 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) => ( - - - - - - - ))} + {selectedArmBotData.point.actions.map((action: any) => { + if (action.actionUuid === selectedAction.actionId) { + return ( + + + + + + + ); + } else { + return null; // important! must return something + } + })} ); + }; export default ArmBotUI;