From fe57e6c8739d35b702378a2bd5d6803c2e7f9dae Mon Sep 17 00:00:00 2001 From: Gomathi9520 Date: Tue, 29 Apr 2025 19:01:06 +0530 Subject: [PATCH 01/19] 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 02/19] 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 03/19] 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 04/19] 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 2ff2f850f3cd2f0bab4713f7fd96f28255750c38 Mon Sep 17 00:00:00 2001 From: Poovizhi99 Date: Fri, 2 May 2025 11:56:04 +0530 Subject: [PATCH 05/19] feat: handle snap function added --- app/src/utils/handleSnap.ts | 65 +++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 app/src/utils/handleSnap.ts diff --git a/app/src/utils/handleSnap.ts b/app/src/utils/handleSnap.ts new file mode 100644 index 0000000..35a0f96 --- /dev/null +++ b/app/src/utils/handleSnap.ts @@ -0,0 +1,65 @@ +import { useEffect } from "react"; +import { detectModifierKeys } from "./shortcutkeys/detectModifierKeys"; + +// Define the props expected by the component +type SnapControlsProps = { + x_point: number; // X-coordinate value to snap + z_point: number; // Z-coordinate value to snap +}; + +const SnapControls: React.FC = ({ x_point, z_point }) => { + useEffect(() => { + // Handler function for keypress events + const handleKeyPress = (event: KeyboardEvent) => { + // Detect which modifier keys (Ctrl, Shift, etc.) are currently pressed + const keyCombination = detectModifierKeys(event); + + // Define the snapping distances + const CTRL_DISTANCE = 1; // Coarse snapping when Ctrl is pressed + const SHIFT_DISTANCE = 0.01; // Fine snapping when Shift is pressed + + // Prevent default behavior to avoid unintended side effects + event.preventDefault(); + + // Create new coordinates to apply snapping to + let newX = x_point; + let newZ = z_point; + + // Check for modifier key combinations and apply appropriate snapping logic + if (keyCombination) { + if (keyCombination === "Ctrl") { + // Snap to nearest integer unit + newX = Math.round(x_point / CTRL_DISTANCE) * CTRL_DISTANCE; + newZ = Math.round(z_point / CTRL_DISTANCE) * CTRL_DISTANCE; + return { newX, newZ }; + } + + if (keyCombination === "Ctrl+Shift") { + // Snap to nearest small unit (0.01) + newX = Math.round(x_point / SHIFT_DISTANCE) * SHIFT_DISTANCE; + newZ = Math.round(z_point / SHIFT_DISTANCE) * SHIFT_DISTANCE; + return { newX, newZ }; + } + + if (keyCombination === "Shift") { + // Incorrect snapping logic — rounding the point and multiplying by small value + newX = Math.round(x_point) * SHIFT_DISTANCE; + newZ = Math.round(z_point) * SHIFT_DISTANCE; + return { newX, newZ }; + } + } + }; + + // Attach keydown event listener when the component mounts + window.addEventListener("keydown", handleKeyPress); + + // Clean up the event listener when the component unmounts + return () => { + window.removeEventListener("keydown", handleKeyPress); + }; + }, []); // Empty dependency array means this effect runs once on mount + + return null; // This component doesn’t render anything +}; + +export default SnapControls; From ef2baacf558cd822e6a53dc3fe88b5fcdc3bd06e Mon Sep 17 00:00:00 2001 From: Poovizhi99 Date: Fri, 2 May 2025 14:04:52 +0530 Subject: [PATCH 06/19] added snap function for ctrl and ctrl+shift key --- .../selectionControls/moveControls.tsx | 47 ++++++++--- app/src/utils/handleSnap.ts | 79 +++++-------------- 2 files changed, 56 insertions(+), 70 deletions(-) diff --git a/app/src/modules/scene/controls/selectionControls/moveControls.tsx b/app/src/modules/scene/controls/selectionControls/moveControls.tsx index cc9ce50..f29396d 100644 --- a/app/src/modules/scene/controls/selectionControls/moveControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/moveControls.tsx @@ -1,7 +1,7 @@ import * as THREE from "three"; -import { useEffect, useMemo, useRef } from "react"; +import { useEffect, useMemo, useRef, useState } from "react"; import { useFrame, useThree } from "@react-three/fiber"; -import { useFloorItems, useSelectedAssets, useSocketStore, useToggleView } from "../../../../store/store"; +import { useFloorItems, useSelectedAssets, useSocketStore, useStartSimulation, useToggleView } from "../../../../store/store"; // import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi'; import { toast } from "react-toastify"; import * as Types from "../../../../types/world/worldTypes"; @@ -10,6 +10,7 @@ import { useEventsStore } from "../../../../store/simulation/useEventsStore"; import { useProductStore } from "../../../../store/simulation/useProductStore"; import { useSelectedProduct } from "../../../../store/simulation/useSimulationStore"; import { upsertProductOrEventApi } from "../../../../services/simulation/UpsertProductOrEventApi"; +import { snapControls } from "../../../../utils/handleSnap"; function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObjects, setCopiedObjects, pastedObjects, setpastedObjects, duplicatedObjects, setDuplicatedObjects, selectionGroup, rotatedObjects, setRotatedObjects, boundingBoxRef }: any) { const { camera, controls, gl, scene, pointer, raycaster } = useThree(); @@ -21,6 +22,7 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje const { floorItems, setFloorItems } = useFloorItems(); const { socket } = useSocketStore(); const itemsData = useRef([]); + const [keyEvent, setKeyEvent] = useState<"Ctrl" | "Shift" | "Ctrl+Shift" | "">("") const email = localStorage.getItem('email') const organization = (email!.split("@")[1]).split(".")[0]; @@ -54,6 +56,15 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje const onPointerMove = () => { isMoving = true; }; + const onKeyUp = (event: KeyboardEvent) => { + // When any modifier is released, reset snap + const isModifierKey = + event.key === "Control" || event.key === "Shift"; + + if (isModifierKey) { + setKeyEvent(""); + } + }; const onPointerUp = (event: PointerEvent) => { if (!isMoving && movedObjects.length > 0 && event.button === 0) { @@ -75,18 +86,28 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje setMovedObjects([]); itemsData.current = []; } + setKeyEvent("") }; const onKeyDown = (event: KeyboardEvent) => { const keyCombination = detectModifierKeys(event); if (pastedObjects.length > 0 || duplicatedObjects.length > 0 || rotatedObjects.length > 0) return; + + if (keyCombination === "Ctrl" || keyCombination === "Ctrl+Shift" || keyCombination === "Shift") { + // update state here + setKeyEvent(keyCombination) + } else { + setKeyEvent("") + } + if (keyCombination === "G") { if (selectedAssets.length > 0) { moveAssets(); itemsData.current = floorItems.filter((item: { modelUuid: string }) => selectedAssets.some((asset: any) => asset.uuid === item.modelUuid)); } } + if (keyCombination === "ESCAPE") { event.preventDefault(); @@ -109,6 +130,7 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje canvasElement.addEventListener("pointermove", onPointerMove); canvasElement.addEventListener("pointerup", onPointerUp); canvasElement.addEventListener("keydown", onKeyDown); + canvasElement?.addEventListener("keyup", onKeyUp); } return () => { @@ -116,12 +138,11 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje canvasElement.removeEventListener("pointermove", onPointerMove); canvasElement.removeEventListener("pointerup", onPointerUp); canvasElement.removeEventListener("keydown", onKeyDown); + canvasElement?.removeEventListener("keyup", onKeyUp); }; - }, [camera, controls, scene, toggleView, selectedAssets, socket, floorItems, pastedObjects, duplicatedObjects, movedObjects, rotatedObjects]); + }, [camera, controls, scene, toggleView, selectedAssets, socket, floorItems, pastedObjects, duplicatedObjects, movedObjects, rotatedObjects, keyEvent]); - const gridSize = 0.25; - const moveSpeed = 0.25; - const isGridSnap = false; + let moveSpeed = keyEvent === "Ctrl" || "Ctrl+Shift" ? 1 : 0.25; useFrame(() => { if (movedObjects.length > 0) { @@ -132,10 +153,17 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje if (point) { let targetX = point.x; let targetZ = point.z; + if (keyEvent === "Ctrl") { + targetX = snapControls(targetX, "Ctrl"); + targetZ = snapControls(targetZ, "Ctrl"); + } else if (keyEvent === "Ctrl+Shift") { + targetX = snapControls(targetX, "Ctrl+Shift"); + targetZ = snapControls(targetZ, "Ctrl+Shift"); + } else if (keyEvent === "Shift") { + targetX = snapControls(targetX, "Shift"); + targetZ = snapControls(targetZ, "Shift"); + } else { - if (isGridSnap) { - targetX = Math.round(point.x / gridSize) * gridSize; - targetZ = Math.round(point.z / gridSize) * gridSize; } const position = new THREE.Vector3(); @@ -278,6 +306,7 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje setMovedObjects([]); setRotatedObjects([]); setSelectedAssets([]); + setKeyEvent("") } return null; diff --git a/app/src/utils/handleSnap.ts b/app/src/utils/handleSnap.ts index 35a0f96..bd6a74d 100644 --- a/app/src/utils/handleSnap.ts +++ b/app/src/utils/handleSnap.ts @@ -1,65 +1,22 @@ -import { useEffect } from "react"; -import { detectModifierKeys } from "./shortcutkeys/detectModifierKeys"; +export function snapControls(value: number, event: string): number { + const CTRL_DISTANCE = 1; // Snap to whole numbers when Ctrl is pressed + const SHIFT_DISTANCE = 0.01; // Snap to half-step increments when Shift is pressed + const CTRL_SHIFT_DISTANCE = 0.1; // Snap to fine increments when both Ctrl and Shift are pressed -// Define the props expected by the component -type SnapControlsProps = { - x_point: number; // X-coordinate value to snap - z_point: number; // Z-coordinate value to snap -}; + switch (event) { + case "Ctrl": + return Math.round(value / CTRL_DISTANCE) * CTRL_DISTANCE; -const SnapControls: React.FC = ({ x_point, z_point }) => { - useEffect(() => { - // Handler function for keypress events - const handleKeyPress = (event: KeyboardEvent) => { - // Detect which modifier keys (Ctrl, Shift, etc.) are currently pressed - const keyCombination = detectModifierKeys(event); + case "Shift": + return Math.round(value / SHIFT_DISTANCE) * SHIFT_DISTANCE; - // Define the snapping distances - const CTRL_DISTANCE = 1; // Coarse snapping when Ctrl is pressed - const SHIFT_DISTANCE = 0.01; // Fine snapping when Shift is pressed + case "Ctrl+Shift": + const base = Math.floor(value / CTRL_DISTANCE) * CTRL_DISTANCE; + const offset = + Math.round((value - base) / CTRL_SHIFT_DISTANCE) * CTRL_SHIFT_DISTANCE; + return base + offset; - // Prevent default behavior to avoid unintended side effects - event.preventDefault(); - - // Create new coordinates to apply snapping to - let newX = x_point; - let newZ = z_point; - - // Check for modifier key combinations and apply appropriate snapping logic - if (keyCombination) { - if (keyCombination === "Ctrl") { - // Snap to nearest integer unit - newX = Math.round(x_point / CTRL_DISTANCE) * CTRL_DISTANCE; - newZ = Math.round(z_point / CTRL_DISTANCE) * CTRL_DISTANCE; - return { newX, newZ }; - } - - if (keyCombination === "Ctrl+Shift") { - // Snap to nearest small unit (0.01) - newX = Math.round(x_point / SHIFT_DISTANCE) * SHIFT_DISTANCE; - newZ = Math.round(z_point / SHIFT_DISTANCE) * SHIFT_DISTANCE; - return { newX, newZ }; - } - - if (keyCombination === "Shift") { - // Incorrect snapping logic — rounding the point and multiplying by small value - newX = Math.round(x_point) * SHIFT_DISTANCE; - newZ = Math.round(z_point) * SHIFT_DISTANCE; - return { newX, newZ }; - } - } - }; - - // Attach keydown event listener when the component mounts - window.addEventListener("keydown", handleKeyPress); - - // Clean up the event listener when the component unmounts - return () => { - window.removeEventListener("keydown", handleKeyPress); - }; - }, []); // Empty dependency array means this effect runs once on mount - - return null; // This component doesn’t render anything -}; - -export default SnapControls; + default: + return value; // No snapping if no modifier key is pressed + } +} From d83b934e61554c0dd17c76b060a7d477da1a9476 Mon Sep 17 00:00:00 2001 From: Gomathi9520 Date: Fri, 2 May 2025 17:35:52 +0530 Subject: [PATCH 07/19] 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 08/19] 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 09/19] 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 ad63a8d72b67f51ff7ffca73fccbeb6ea4a2c1a3 Mon Sep 17 00:00:00 2001 From: Poovizhi99 Date: Fri, 2 May 2025 18:40:22 +0530 Subject: [PATCH 10/19] added actions for machines --- .../instances/animator/machineAnimator.tsx | 102 ++++++++++++++++++ .../machineInstance/machineInstance.tsx | 61 ++++++++++- .../machine/instances/machineInstances.tsx | 7 +- .../modules/simulation/machine/machine.tsx | 8 +- .../instances/roboticArmInstances.tsx | 2 +- .../instances/animator/vehicleAnimator.tsx | 4 +- .../vehicle/instances/vehicleInstances.tsx | 6 +- 7 files changed, 179 insertions(+), 11 deletions(-) create mode 100644 app/src/modules/simulation/machine/instances/animator/machineAnimator.tsx diff --git a/app/src/modules/simulation/machine/instances/animator/machineAnimator.tsx b/app/src/modules/simulation/machine/instances/animator/machineAnimator.tsx new file mode 100644 index 0000000..6ef2b0e --- /dev/null +++ b/app/src/modules/simulation/machine/instances/animator/machineAnimator.tsx @@ -0,0 +1,102 @@ +import { useFrame } from '@react-three/fiber'; +import React, { useEffect, useRef } from 'react'; +import { useMachineStore } from '../../../../../store/simulation/useMachineStore'; +import { useAnimationPlaySpeed, usePauseButtonStore, usePlayButtonStore, useResetButtonStore } from '../../../../../store/usePlayButtonStore'; + + +interface MachineAnimatorProps { + currentPhase: string; + handleCallBack: () => void; + reset: () => void; + machineStatus: (modelId: string, status: string) => void; + processingTime: number; + machineUuid: string +} + +const MachineAnimator = ({ currentPhase, handleCallBack, processingTime, machineUuid, machineStatus, reset }: MachineAnimatorProps) => { + const animationStarted = useRef(false); + const isPausedRef = useRef(false); + const startTimeRef = useRef(0); + const animationFrameId = useRef(null); + const pauseTimeRef = useRef(null); + const { isPaused } = usePauseButtonStore(); + const { removeCurrentAction } = useMachineStore(); + const { isReset, setReset } = useResetButtonStore(); + const { isPlaying } = usePlayButtonStore(); + const { speed } = useAnimationPlaySpeed(); + const isPlayingRef = useRef(false); + const isResetRef = useRef(false) + + + useEffect(() => { + isPausedRef.current = isPaused; + }, [isPaused]); + useEffect(() => { + isPlayingRef.current = isPlaying; + }, [isPlaying]); + useEffect(() => { + isResetRef.current = isReset; + }, [isReset]); + + + useEffect(() => { + + if (isReset || !isPlaying) { + reset(); + setReset(false); + startTimeRef.current = 0; + isPausedRef.current = false; + pauseTimeRef.current = 0; + animationFrameId.current = null; + animationStarted.current = false; + removeCurrentAction(machineUuid) + } + }, [isReset, isPlaying]) + + useEffect(() => { + if (currentPhase === 'processing' && !animationStarted.current && machineUuid) { + animationStarted.current = true; + startTimeRef.current = performance.now(); + animationFrameId.current = requestAnimationFrame(step); + } + }, [currentPhase]); + + function step(time: number) { + if (!isPausedRef.current || !isResetRef.current) { + if (animationFrameId.current) { + cancelAnimationFrame(animationFrameId.current); + animationFrameId.current = null; + } + if (isPausedRef.current) { + if (!pauseTimeRef.current) { + pauseTimeRef.current = performance.now(); + } + animationFrameId.current = requestAnimationFrame(step); + return; + } + + if (pauseTimeRef.current) { + const pauseDuration = performance.now() - pauseTimeRef.current; + startTimeRef.current += pauseDuration; + pauseTimeRef.current = null; + } + + const elapsed = time - startTimeRef.current; + const processedTime = processingTime * 1000; + if (elapsed < processedTime) { + machineStatus(machineUuid, "Machine is currently processing the task"); + animationFrameId.current = requestAnimationFrame(step); + } else { + removeCurrentAction(machineUuid); + animationStarted.current = false; + handleCallBack(); + + } + } + } + + + return null; +} + +export default MachineAnimator; diff --git a/app/src/modules/simulation/machine/instances/machineInstance/machineInstance.tsx b/app/src/modules/simulation/machine/instances/machineInstance/machineInstance.tsx index edb825f..714bcdb 100644 --- a/app/src/modules/simulation/machine/instances/machineInstance/machineInstance.tsx +++ b/app/src/modules/simulation/machine/instances/machineInstance/machineInstance.tsx @@ -1,8 +1,65 @@ -import React from 'react' +import React, { useEffect, useRef, useState } from 'react' +import { useMachineStore } from '../../../../../store/simulation/useMachineStore'; +import { usePlayButtonStore } from '../../../../../store/usePlayButtonStore'; +import MachineAnimator from '../animator/machineAnimator'; + +function MachineInstance({ machineDetail }: any) { + const [currentPhase, setCurrentPhase] = useState('idle'); + let isIncrememtable = useRef(true); + const { isPlaying } = usePlayButtonStore(); + const { machines, addCurrentAction, setMachineState, setMachineActive } = useMachineStore(); + + const reset = () => { + setMachineState(machineDetail.modelUuid, 'idle'); + setMachineActive(machineDetail.modelUuid, false); + isIncrememtable.current = true; + setCurrentPhase("idle"); + } + const increment = () => { + if (isIncrememtable.current) { + addCurrentAction(machineDetail.modelUuid, "machine-action-2468-1357-8024") + isIncrememtable.current = false; + } + } + function machineStatus(modelId: string, status: string) { + // console.log(`${modelId} , ${status}`); + + } + + useEffect(() => { + if (isPlaying) { + if (!machineDetail.isActive && machineDetail.state === "idle" && currentPhase == "idle" && !machineDetail.currentAction) { + setTimeout(() => { + increment(); + }, 2000); + machineStatus(machineDetail.modelUuid, 'Machine is idle and waiting for next instruction.') + } else if (!machineDetail.isActive && machineDetail.state === "idle" && currentPhase == "idle" && machineDetail.currentAction) { + setCurrentPhase("processing"); + setMachineState(machineDetail.modelUuid, 'running'); + setMachineActive(machineDetail.modelUuid, true); + machineStatus(machineDetail.modelUuid, "Machine started processing") + } + } else { + reset(); + } + }, [currentPhase, isPlaying, machines]) + + function handleCallBack() { + if (currentPhase == "processing") { + setMachineState(machineDetail.modelUuid, 'idle'); + setMachineActive(machineDetail.modelUuid, false); + setCurrentPhase("idle") + isIncrememtable.current = true; + machineStatus(machineDetail.modelUuid, "Machine has completed the processing") + } + } + // console.log('currentPhase: ', currentPhase); + + -function MachineInstance() { return ( <> + ) } diff --git a/app/src/modules/simulation/machine/instances/machineInstances.tsx b/app/src/modules/simulation/machine/instances/machineInstances.tsx index b0c2c9f..8536cac 100644 --- a/app/src/modules/simulation/machine/instances/machineInstances.tsx +++ b/app/src/modules/simulation/machine/instances/machineInstances.tsx @@ -1,11 +1,14 @@ import React from 'react' import MachineInstance from './machineInstance/machineInstance' +import { useMachineStore } from '../../../../store/simulation/useMachineStore'; function MachineInstances() { + const { machines } = useMachineStore(); return ( <> - - + {machines.map((val: MachineStatus) => ( + + ))} ) diff --git a/app/src/modules/simulation/machine/machine.tsx b/app/src/modules/simulation/machine/machine.tsx index e9d2dea..3d24f61 100644 --- a/app/src/modules/simulation/machine/machine.tsx +++ b/app/src/modules/simulation/machine/machine.tsx @@ -4,7 +4,7 @@ import { useMachineStore } from '../../../store/simulation/useMachineStore' import { useSelectedProduct } from '../../../store/simulation/useSimulationStore'; function Machine() { - const { addMachine, addCurrentAction, removeMachine } = useMachineStore(); + const { addMachine, addCurrentAction, removeMachine, machines } = useMachineStore(); const { selectedProduct } = useSelectedProduct(); const machineSample: MachineEventSchema[] = [ @@ -38,6 +38,12 @@ function Machine() { // addCurrentAction(machineSample[0].modelUuid, machineSample[0].point.action.actionUuid); }, []) + + useEffect(() => { + + // console.log('machines: ', machines); + }, [machines]) + return ( <> diff --git a/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx b/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx index 1089fa5..d247b35 100644 --- a/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx +++ b/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx @@ -7,7 +7,7 @@ function RoboticArmInstances() { return ( <> - {armBots?.map((robot: ArmBotStatus) => ( + {armBots.map((robot: ArmBotStatus) => ( ))} diff --git a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx index 421dea8..8e522ff 100644 --- a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx +++ b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx @@ -25,9 +25,9 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai const completedRef = useRef(false); const isPausedRef = useRef(false); const pauseTimeRef = useRef(null); + const [progress, setProgress] = useState(0); const [restRotation, setRestingRotation] = useState(true); const [currentPath, setCurrentPath] = useState<[number, number, number][]>([]); - const [progress, setProgress] = useState(0); const { scene } = useThree(); let startTime: number; let fixedInterval: number; @@ -66,6 +66,8 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai setReset(false); setRestingRotation(true); decrementVehicleLoad(agvDetail.modelUuid, 0); + isPausedRef.current = false; + pauseTimeRef.current = 0; const object = scene.getObjectByProperty('uuid', agvUuid); if (object) { object.position.set(agvDetail.position[0], agvDetail.position[1], agvDetail.position[2]); diff --git a/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx b/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx index 91111cf..fcc840d 100644 --- a/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx +++ b/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx @@ -9,10 +9,8 @@ function VehicleInstances() { return ( <> - {vehicles.map((val: any, i: any) => - - - + {vehicles.map((val: VehicleStatus) => + )} From 0e4005f31e79101d693cc263c521c514880980c2 Mon Sep 17 00:00:00 2001 From: Gomathi9520 Date: Sat, 3 May 2025 10:05:25 +0530 Subject: [PATCH 11/19] 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; From 94c306c81365a31b63d9ebdb533d028a386e7c98 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Sat, 3 May 2025 10:09:39 +0530 Subject: [PATCH 12/19] Refactor Trigger component usage in mechanics files: pass selectedPointData and type props for Machine, RoboticArm, StorageUnit, and Vehicle to enhance functionality and maintain consistency. --- .../mechanics/machineMechanics.tsx | 2 +- .../mechanics/roboticArmMechanics.tsx | 2 +- .../mechanics/storageMechanics.tsx | 2 +- .../mechanics/vehicleMechanics.tsx | 2 +- .../eventProperties/trigger/Trigger.tsx | 273 +++++++++++++++--- .../IntialLoad/loadInitialFloorItems.ts | 1 - .../geomentries/assets/addAssetModel.ts | 2 +- .../triggers/connector/triggerConnector.tsx | 8 +- .../services/simulation/renameProductApi.ts | 26 ++ app/src/store/simulation/useProductStore.ts | 7 +- app/src/types/simulationTypes.d.ts | 2 +- 11 files changed, 275 insertions(+), 52 deletions(-) create mode 100644 app/src/services/simulation/renameProductApi.ts diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx index 3e11e54..be50990 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx @@ -137,7 +137,7 @@ function MachineMechanics() {
- +
)} diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx index df5c358..3e8aa67 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx @@ -280,7 +280,7 @@ function RoboticArmMechanics() { />
- +
)} diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx index 3273ce4..34e35ae 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx @@ -146,7 +146,7 @@ function StorageMechanics() {
- +
)} diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx index 7839168..0f52437 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx @@ -235,7 +235,7 @@ function VehicleMechanics() {
- +
diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/trigger/Trigger.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/trigger/Trigger.tsx index 86e4e7b..f48f875 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/trigger/Trigger.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/trigger/Trigger.tsx @@ -1,4 +1,5 @@ -import React, { useEffect, useRef, useState } from "react"; +import React, { useEffect, useMemo, useRef, useState } from "react"; +import * as THREE from "three"; import { AddIcon, RemoveIcon, @@ -9,6 +10,7 @@ import RenameInput from "../../../../../ui/inputs/RenameInput"; import { handleResize } from "../../../../../../functions/handleResizePannel"; import { useProductStore } from "../../../../../../store/simulation/useProductStore"; import { useSelectedProduct } from "../../../../../../store/simulation/useSimulationStore"; +import { upsertProductOrEventApi } from "../../../../../../services/simulation/UpsertProductOrEventApi"; type TriggerProps = { selectedPointData?: PointsScheme | undefined; @@ -18,35 +20,215 @@ type TriggerProps = { const Trigger = ({ selectedPointData, type }: TriggerProps) => { const [currentAction, setCurrentAction] = useState(); const { selectedProduct } = useSelectedProduct(); - const { getActionByUuid } = useProductStore(); + const { getActionByUuid, addTrigger, removeTrigger, updateTrigger, renameTrigger, getProductById } = useProductStore(); const [triggers, setTriggers] = useState([]); const [selectedTrigger, setSelectedTrigger] = useState(); - const [activeOption, setActiveOption] = useState("onComplete"); + const [activeOption, setActiveOption] = useState<"onComplete" | "onStart" | "onStop" | "delay" | "onError">("onComplete"); const triggersContainerRef = useRef(null); + const email = localStorage.getItem('email') + const organization = (email!.split("@")[1]).split(".")[0]; + useEffect(() => { - if (!selectedPointData) return; + if (!selectedPointData || !selectedProduct) return; + + let actionUuid: string | undefined; + if (type === 'Conveyor' || type === 'Vehicle' || type === 'Machine' || type === 'StorageUnit') { - setCurrentAction((selectedPointData as ConveyorPointSchema).action.actionUuid); + actionUuid = (selectedPointData as ConveyorPointSchema | VehiclePointSchema | MachinePointSchema | StoragePointSchema).action?.actionUuid; + } else if (type === 'RoboticArm') { + actionUuid = (selectedPointData as RoboticArmPointSchema).actions[0]?.actionUuid; } - }, [selectedPointData]); + + setCurrentAction(actionUuid); + }, [selectedPointData, selectedProduct, type]); + + + const updateBackend = ( + productName: string, + productId: string, + organization: string, + eventData: EventsSchema + ) => { + upsertProductOrEventApi({ + productName: productName, + productId: productId, + organization: organization, + eventDatas: eventData + }) + } useEffect(() => { if (!currentAction || !selectedProduct) return; const action = getActionByUuid(selectedProduct.productId, currentAction); - setTriggers(action?.triggers || []); - setSelectedTrigger(action?.triggers[0] || undefined); + const actionTriggers = action?.triggers || []; + setTriggers(actionTriggers); + setSelectedTrigger(actionTriggers[0]); }, [currentAction, selectedProduct]); - const addTrigger = (): void => { + const handleAddTrigger = () => { + if (!selectedProduct || !currentAction) return; + + const newTrigger: TriggerSchema = { + triggerUuid: THREE.MathUtils.generateUUID(), + triggerName: `New Trigger ${triggers.length + 1}`, + triggerType: activeOption, + delay: 0, + triggeredAsset: null + }; + + addTrigger(selectedProduct.productId, currentAction, newTrigger); + setSelectedTrigger(newTrigger); }; - const removeTrigger = (triggerUuid: string): void => { + const handleRemoveTrigger = (triggerUuid: string) => { + if (!selectedProduct) return; + removeTrigger(selectedProduct.productId, triggerUuid); + if (selectedTrigger?.triggerUuid === triggerUuid) { + const remainingTriggers = triggers.filter(t => t.triggerUuid !== triggerUuid); + setSelectedTrigger(remainingTriggers[0]); + } + }; + + const handleTriggerRename = (triggerUuid: string, newName: string) => { + if (!selectedProduct) return; + renameTrigger(selectedProduct.productId, triggerUuid, newName); + }; + + const handleTriggerTypeChange = (option: string) => { + if (!selectedTrigger || !selectedProduct) return; + + const validTypes: Array = ["onComplete", "onStart", "onStop", "delay", "onError"]; + if (!validTypes.includes(option as TriggerSchema['triggerType'])) return; + + setActiveOption(option as TriggerSchema['triggerType']); + updateTrigger(selectedProduct.productId, selectedTrigger.triggerUuid, { + triggerType: option as TriggerSchema['triggerType'] + }); }; const triggeredModel = selectedTrigger?.triggeredAsset?.triggeredModel || { modelName: "Select Model", modelUuid: "" }; const triggeredPoint = selectedTrigger?.triggeredAsset?.triggeredPoint || { pointName: "Select Point", pointUuid: "" }; const triggeredAction = selectedTrigger?.triggeredAsset?.triggeredAction || { actionName: "Select Action", actionUuid: "" }; + console.log('selectedTrigger: ', selectedTrigger); + console.log('triggeredAction: ', triggeredAction); + + const modelOptions = getProductById(selectedProduct.productId)?.eventDatas || []; + + const pointOptions: PointsScheme[] = useMemo(() => { + if (!triggeredModel.modelUuid) return []; + + const model = modelOptions.find(m => m.modelUuid === triggeredModel.modelUuid); + if (!model) return []; + + if ('points' in model) { + return (model as ConveyorEventSchema).points; + } else if ('point' in model) { + return [(model as VehicleEventSchema | RoboticArmEventSchema | MachineEventSchema | StorageEventSchema).point]; + } + return []; + }, [triggeredModel.modelUuid, modelOptions]); + + const actionOptions: any = useMemo(() => { + if (!triggeredPoint.pointUuid) return []; + const point = pointOptions.find((p) => p.uuid === triggeredPoint.pointUuid); + if (!point) return []; + + if ('action' in point) { + const typedPoint = point as ConveyorPointSchema | VehiclePointSchema | MachinePointSchema | StoragePointSchema; + return typedPoint.action ? [typedPoint.action] : []; + } else if ('actions' in point) { + const typedPoint = point as RoboticArmPointSchema; + return typedPoint.actions; + } + return []; + }, [triggeredPoint.pointUuid, pointOptions]); + + const handleModelSelect = (option: string, triggerUuid: string) => { + if (!selectedProduct) return; + + const selectedModel = modelOptions.find(m => m.modelName === option); + if (!selectedModel) return; + + const event = updateTrigger(selectedProduct.productId, triggerUuid, { + triggeredAsset: { + triggeredModel: { + modelName: selectedModel.modelName, + modelUuid: selectedModel.modelUuid + }, + triggeredPoint: null, + triggeredAction: null + } + }); + + if (event) { + updateBackend( + selectedProduct.productName, + selectedProduct.productId, + organization, + event + ); + } + }; + + const handlePointSelect = (option: string, triggerUuid: string) => { + if (!selectedProduct || !selectedTrigger) return; + + const pointUuid = pointOptions.find(p => `Point ${p.uuid.slice(0, 5)}` === option)?.uuid; + + if (!pointUuid) return; + + if (selectedTrigger.triggeredAsset?.triggeredModel) { + const event = updateTrigger(selectedProduct.productId, triggerUuid, { + triggeredAsset: { + ...selectedTrigger.triggeredAsset, + triggeredPoint: { + pointName: option, + pointUuid: pointUuid + }, + triggeredAction: null + } + }); + + if (event) { + updateBackend( + selectedProduct.productName, + selectedProduct.productId, + organization, + event + ); + } + } + }; + + const handleActionSelect = (option: string, triggerUuid: string) => { + if (!selectedProduct || !selectedTrigger) return; + + const selectedAction = actionOptions.find((a: any) => a.actionName === option); + + if (!selectedAction) return; + + if (selectedTrigger.triggeredAsset?.triggeredPoint) { + const event = updateTrigger(selectedProduct.productId, triggerUuid, { + triggeredAsset: { + ...selectedTrigger.triggeredAsset, + triggeredAction: { + actionName: option, + actionUuid: selectedAction.actionUuid + } + } + }); + + if (event) { + updateBackend( + selectedProduct.productName, + selectedProduct.productId, + organization, + event + ); + } + } + }; return (
@@ -54,8 +236,9 @@ const Trigger = ({ selectedPointData, type }: TriggerProps) => {
Trigger
@@ -73,13 +256,19 @@ const Trigger = ({ selectedPointData, type }: TriggerProps) => { className={`list-item ${selectedTrigger?.triggerUuid === trigger.triggerUuid ? "active" : ""}`} onClick={() => setSelectedTrigger(trigger)} > - {triggers.length > 1 && ( @@ -95,35 +284,39 @@ const Trigger = ({ selectedPointData, type }: TriggerProps) => {
-
-
{selectedTrigger?.triggerName}
- setActiveOption(option)} - /> -
+ + {selectedTrigger && ( +
+
{selectedTrigger.triggerName}
{ }} - /> - { }} - /> - { }} + label="Trigger Type" + defaultOption={selectedTrigger.triggerType} + options={["onComplete", "onStart", "onStop", "delay", "onError"]} + onSelect={handleTriggerTypeChange} /> + +
+ (option.modelName))]} + onSelect={(option) => { handleModelSelect(option, selectedTrigger.triggerUuid) }} + /> + (`Point ${option.uuid.slice(0, 5)}`))]} + onSelect={(option) => { handlePointSelect(option, selectedTrigger.triggerUuid) }} + /> + (option.actionName))]} + onSelect={(option) => { handleActionSelect(option, selectedTrigger.triggerUuid) }} + /> +
-
+ )}
); diff --git a/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts b/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts index ee5c283..6ab7230 100644 --- a/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts +++ b/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts @@ -8,7 +8,6 @@ import * as Types from "../../../types/world/worldTypes"; import { initializeDB, retrieveGLTF, storeGLTF } from '../../../utils/indexDB/idbUtils'; import { getCamera } from '../../../services/factoryBuilder/camera/getCameraApi'; import { getFloorAssets } from '../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi'; -import PointsCalculator from '../../simulation/events/points/functions/pointsCalculator'; async function loadInitialFloorItems( itemsGroup: Types.RefGroup, diff --git a/app/src/modules/builder/geomentries/assets/addAssetModel.ts b/app/src/modules/builder/geomentries/assets/addAssetModel.ts index 64656a0..6e978dc 100644 --- a/app/src/modules/builder/geomentries/assets/addAssetModel.ts +++ b/app/src/modules/builder/geomentries/assets/addAssetModel.ts @@ -235,7 +235,7 @@ async function handleModelLoad( const nextPoint = ConveyorEvent.points[i + 1]; if (currentPoint.action.triggers.length > 0) { - currentPoint.action.triggers[0].triggeredAsset!.triggeredPoint.pointUuid = nextPoint.uuid; + currentPoint.action.triggers[0].triggeredAsset!.triggeredPoint!.pointUuid = nextPoint.uuid; currentPoint.action.triggers[0].triggeredAsset!.triggeredAction!.actionUuid = nextPoint.action.actionUuid; } } diff --git a/app/src/modules/simulation/triggers/connector/triggerConnector.tsx b/app/src/modules/simulation/triggers/connector/triggerConnector.tsx index dcb46f4..f9fc30f 100644 --- a/app/src/modules/simulation/triggers/connector/triggerConnector.tsx +++ b/app/src/modules/simulation/triggers/connector/triggerConnector.tsx @@ -68,7 +68,7 @@ function TriggerConnector() { event.points.forEach(point => { if (point.action?.triggers) { point.action.triggers.forEach(trigger => { - if (trigger.triggeredAsset) { + if (trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint) { newConnections.push({ id: `${point.uuid}-${trigger.triggeredAsset.triggeredPoint.pointUuid}-${trigger.triggerUuid}`, startPointUuid: point.uuid, @@ -85,7 +85,7 @@ function TriggerConnector() { const point = event.point; if (point.action?.triggers) { point.action.triggers.forEach(trigger => { - if (trigger.triggeredAsset) { + if (trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint) { newConnections.push({ id: `${point.uuid}-${trigger.triggeredAsset.triggeredPoint.pointUuid}-${trigger.triggerUuid}`, startPointUuid: point.uuid, @@ -101,7 +101,7 @@ function TriggerConnector() { const point = event.point; point.actions?.forEach(action => { action.triggers?.forEach(trigger => { - if (trigger.triggeredAsset) { + if (trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint) { newConnections.push({ id: `${point.uuid}-${trigger.triggeredAsset.triggeredPoint.pointUuid}-${trigger.triggerUuid}`, startPointUuid: point.uuid, @@ -117,7 +117,7 @@ function TriggerConnector() { const point = event.point; if (point.action?.triggers) { point.action.triggers.forEach(trigger => { - if (trigger.triggeredAsset) { + if (trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint) { newConnections.push({ id: `${point.uuid}-${trigger.triggeredAsset.triggeredPoint.pointUuid}-${trigger.triggerUuid}`, startPointUuid: point.uuid, diff --git a/app/src/services/simulation/renameProductApi.ts b/app/src/services/simulation/renameProductApi.ts new file mode 100644 index 0000000..afa493c --- /dev/null +++ b/app/src/services/simulation/renameProductApi.ts @@ -0,0 +1,26 @@ +let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; + +export const renameProductApi = async (body: { productName: string, productId: string, organization: string }) => { + try { + const response = await fetch(`${url_Backend_dwinzo}/api/v2/productRename`, { + method: "PATCH", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(body), + }); + + if (!response.ok) { + throw new Error("Failed to rename product"); + } + + const result = await response.json(); + return result; + } catch (error) { + if (error instanceof Error) { + throw new Error(error.message); + } else { + throw new Error("An unknown error occurred"); + } + } +}; diff --git a/app/src/store/simulation/useProductStore.ts b/app/src/store/simulation/useProductStore.ts index b7448f2..8b83cdd 100644 --- a/app/src/store/simulation/useProductStore.ts +++ b/app/src/store/simulation/useProductStore.ts @@ -51,7 +51,7 @@ type ProductsStore = { productId: string, triggerUuid: string, updates: Partial - ) => void; + ) => EventsSchema | undefined; // Renaming functions renameProduct: (productId: string, newName: string) => void; @@ -392,6 +392,7 @@ export const useProductStore = create()( }, updateTrigger: (productId, triggerUuid, updates) => { + let updatedEvent: EventsSchema | undefined; set((state) => { const product = state.products.find(p => p.productId === productId); if (product) { @@ -402,6 +403,7 @@ export const useProductStore = create()( const trigger = point.action.triggers.find(t => t.triggerUuid === triggerUuid); if (trigger) { Object.assign(trigger, updates); + updatedEvent = JSON.parse(JSON.stringify(event)); return; } } @@ -412,6 +414,7 @@ export const useProductStore = create()( const trigger = point.action.triggers.find((t: any) => t.triggerUuid === triggerUuid); if (trigger) { Object.assign(trigger, updates); + updatedEvent = JSON.parse(JSON.stringify(event)); return; } } else if ('actions' in point) { @@ -420,6 +423,7 @@ export const useProductStore = create()( const trigger = action.triggers.find((t: any) => t.triggerUuid === triggerUuid); if (trigger) { Object.assign(trigger, updates); + updatedEvent = JSON.parse(JSON.stringify(event)); return; } } @@ -429,6 +433,7 @@ export const useProductStore = create()( } } }); + return updatedEvent; }, // Renaming functions diff --git a/app/src/types/simulationTypes.d.ts b/app/src/types/simulationTypes.d.ts index c7ccd8b..11d5156 100644 --- a/app/src/types/simulationTypes.d.ts +++ b/app/src/types/simulationTypes.d.ts @@ -13,7 +13,7 @@ interface TriggerSchema { delay: number; triggeredAsset: { triggeredModel: { modelName: string, modelUuid: string }; - triggeredPoint: { pointName: string, pointUuid: string }; + triggeredPoint: { pointName: string, pointUuid: string } | null; triggeredAction: { actionName: string, actionUuid: string } | null; } | null; } From d29c4ce48a43ded8615ec7debe174f4691151afd Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Sat, 3 May 2025 10:28:59 +0530 Subject: [PATCH 13/19] Refactor Trigger component: remove console logs and clean up unused code in Trigger and RoboticArm components; update ArmBotUI to improve state management and backend integration; fix typo in useProductStore comments. --- .../eventProperties/trigger/Trigger.tsx | 2 - .../simulation/roboticArm/roboticArm.tsx | 143 ------- .../modules/simulation/ui/arm/armBotUI.tsx | 352 ++++++++++-------- app/src/store/simulation/useProductStore.ts | 2 +- 4 files changed, 193 insertions(+), 306 deletions(-) diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/trigger/Trigger.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/trigger/Trigger.tsx index f48f875..306865f 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/trigger/Trigger.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/trigger/Trigger.tsx @@ -110,8 +110,6 @@ const Trigger = ({ selectedPointData, type }: TriggerProps) => { const triggeredModel = selectedTrigger?.triggeredAsset?.triggeredModel || { modelName: "Select Model", modelUuid: "" }; const triggeredPoint = selectedTrigger?.triggeredAsset?.triggeredPoint || { pointName: "Select Point", pointUuid: "" }; const triggeredAction = selectedTrigger?.triggeredAsset?.triggeredAction || { actionName: "Select Action", actionUuid: "" }; - console.log('selectedTrigger: ', selectedTrigger); - console.log('triggeredAction: ', triggeredAction); const modelOptions = getProductById(selectedProduct.productId)?.eventDatas || []; diff --git a/app/src/modules/simulation/roboticArm/roboticArm.tsx b/app/src/modules/simulation/roboticArm/roboticArm.tsx index 2cb9ea6..446d1b0 100644 --- a/app/src/modules/simulation/roboticArm/roboticArm.tsx +++ b/app/src/modules/simulation/roboticArm/roboticArm.tsx @@ -1,7 +1,6 @@ import { useEffect } from "react"; import RoboticArmInstances from "./instances/roboticArmInstances"; import { useArmBotStore } from "../../../store/simulation/useArmBotStore"; -import { useFloorItems } from "../../../store/store"; import { useSelectedEventData, useSelectedEventSphere, useSelectedProduct } from "../../../store/simulation/useSimulationStore"; import { useProductStore } from "../../../store/simulation/useProductStore"; import { usePlayButtonStore } from "../../../store/usePlayButtonStore"; @@ -14,148 +13,6 @@ function RoboticArm() { const { selectedEventSphere } = useSelectedEventSphere(); const { selectedEventData } = useSelectedEventData(); const { isPlaying } = usePlayButtonStore(); - const { floorItems } = useFloorItems(); - - const armBotStatusSample: RoboticArmEventSchema[] = [ - { - state: "idle", - modelUuid: "8790b4d5-fb6e-49e0-8161-04945fe3fdc4", - modelName: "ArmBot-X200", - position: [4.317833205016363, 0, -3.2829924989068715], - rotation: [-1.3768690876192207e-15, 1.4883085074751308, 1.5407776675834467e-15], - type: "roboticArm", - speed: 1.5, - point: { - uuid: "point-123", - position: [0, 2.6, 0], - rotation: [0, 0, 0], - actions: [ - { - actionUuid: "action-003", - actionName: "Pick Component", - actionType: "pickAndPlace", - process: { - startPoint: [-1, 2, 1], - endPoint: [-2, 1, -1], - // startPoint: [-2, 1, -1], - // endPoint: [-1, 2, 1], - }, - triggers: [ - { - triggerUuid: "trigger-001", - triggerName: "Start Trigger", - triggerType: "onStart", - delay: 0, - triggeredAsset: { - triggeredModel: { - modelName: "Conveyor A1", - modelUuid: "conveyor-01", - }, - triggeredPoint: { - pointName: "Start Point", - pointUuid: "conveyor-01-point-001", - }, - triggeredAction: { - actionName: "Move Forward", - actionUuid: "conveyor-action-01", - }, - }, - }, - { - triggerUuid: "trigger-002", - triggerName: "Complete Trigger", - triggerType: "onComplete", - delay: 0, - triggeredAsset: { - triggeredModel: { - modelName: "StaticMachine B2", - modelUuid: "machine-02", - }, - triggeredPoint: { - pointName: "Receive Point", - pointUuid: "machine-02-point-001", - }, - triggeredAction: { - actionName: "Process Part", - actionUuid: "machine-action-01", - }, - }, - }, - ], - }, - ], - }, - }, - { - state: "idle", - modelUuid: "armbot-xyz-002", - modelName: "ArmBot-X200", - position: [95.94347308985614, 0, 6.742905194869091], - rotation: [0, 0, 0], - type: "roboticArm", - speed: 0.1, - point: { - uuid: "point-123", - position: [0, 1.5, 0], - rotation: [0, 0, 0], - actions: [ - { - actionUuid: "action-001", - actionName: "Pick Component", - actionType: "pickAndPlace", - process: { - // startPoint: [2.52543010919071, 0, 8.433681161200905], - // endPoint: [95.3438373267953, 0, 9.0279187421610025], - startPoint: null, - endPoint: null, - }, - triggers: [ - { - triggerUuid: "trigger-001", - triggerName: "Start Trigger", - triggerType: "onStart", - delay: 0, - triggeredAsset: { - triggeredModel: { - modelName: "Conveyor A1", - modelUuid: "conveyor-01", - }, - triggeredPoint: { - pointName: "Start Point", - pointUuid: "conveyor-01-point-001", - }, - triggeredAction: { - actionName: "Move Forward", - actionUuid: "conveyor-action-01", - }, - }, - }, - { - triggerUuid: "trigger-002", - triggerName: "Complete Trigger", - triggerType: "onComplete", - delay: 0, - triggeredAsset: { - triggeredModel: { - modelName: "StaticMachine B2", - modelUuid: "machine-02", - }, - triggeredPoint: { - pointName: "Receive Point", - pointUuid: "machine-02-point-001", - }, - triggeredAction: { - actionName: "Process Part", - actionUuid: "machine-action-01", - }, - }, - }, - ], - }, - ], - }, - }, - ]; useEffect(() => { if (selectedProduct.productId) { diff --git a/app/src/modules/simulation/ui/arm/armBotUI.tsx b/app/src/modules/simulation/ui/arm/armBotUI.tsx index 8a2d18f..01e631e 100644 --- a/app/src/modules/simulation/ui/arm/armBotUI.tsx +++ b/app/src/modules/simulation/ui/arm/armBotUI.tsx @@ -1,5 +1,5 @@ -import React, { useCallback, useEffect, useState } from 'react'; -import { useSelectedAction, useSelectedEventData, useSelectedEventSphere, useSelectedProduct } from '../../../../store/simulation/useSimulationStore'; +import React, { useEffect, useState } from 'react'; +import { useSelectedAction, useSelectedEventData, useSelectedProduct } from '../../../../store/simulation/useSimulationStore'; import { useArmBotStore } from '../../../../store/simulation/useArmBotStore'; import { useGLTF } from '@react-three/drei'; import { useThree } from '@react-three/fiber'; @@ -10,180 +10,212 @@ 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 useModuleStore from '../../../../store/useModuleStore'; +import { upsertProductOrEventApi } from '../../../../services/simulation/UpsertProductOrEventApi'; type Positions = { - pick: [number, number, number]; - drop: [number, number, number]; - default: [number, number, number]; + pick: [number, number, number]; + drop: [number, number, number]; + default: [number, number, number]; }; const ArmBotUI = () => { - const { getEventByModelUuid } = useProductStore(); - const { selectedEventData } = useSelectedEventData(); - const { selectedProduct } = useSelectedProduct(); - const { armBots, updateStartPoint, updateEndPoint } = useArmBotStore(); - const { scene } = useThree(); - const { selectedAction } = useSelectedAction(); + const { getEventByModelUuid, updateAction } = useProductStore(); + const { selectedEventData } = useSelectedEventData(); + const { selectedProduct } = useSelectedProduct(); + const { armBots } = useArmBotStore(); + const { scene } = useThree(); + const { selectedAction } = useSelectedAction(); - const armUiPick = useGLTF(armPick) as any; - const armUiDrop = useGLTF(armDrop) as any; + 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); + const [startPosition, setStartPosition] = useState<[number, number, number] | null>([0, 0, 0]); + const [endPosition, setEndPosition] = useState<[number, number, number] | null>([0, 0, 0]); + const [selectedArmBotData, setSelectedArmBotData] = useState(null); - // Fetch and setup selected ArmBot data - useEffect(() => { - if (selectedEventData?.data.type === "roboticArm") { - const selectedArmBot = getEventByModelUuid(selectedProduct.productId, selectedEventData.data.modelUuid); + const email = localStorage.getItem('email') + const organization = (email!.split("@")[1]).split(".")[0]; - 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; - - const endPoint = matchingAction.process.endPoint; - const dropPosition = (!endPoint || (Array.isArray(endPoint) && endPoint.every(v => v === 0))) - ? defaultPositions.drop - : endPoint; - - setStartPosition(pickPosition); - setEndPosition(dropPosition); - } - } - } - }, [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], - default: [baseX, baseY, baseZ], - }; + const updateBackend = ( + productName: string, + productId: string, + organization: string, + eventData: EventsSchema + ) => { + upsertProductOrEventApi({ + productName: productName, + productId: productId, + organization: organization, + eventDatas: eventData + }) } - return { - pick: [0.5, 1.5, 0], - drop: [-0.5, 1.5, 0], - default: [0, 1.5, 0], - }; - } + // Fetch and setup selected ArmBot data + useEffect(() => { + if (selectedEventData?.data.type === "roboticArm") { + const selectedArmBot = getEventByModelUuid(selectedProduct.productId, selectedEventData.data.modelUuid); - 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 (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; - if (parentObject) { - const localPos = worldPos.clone(); - parentObject.worldToLocal(localPos); - return [localPos.x, localPos.y, localPos.z]; - } - } - return null; - } + const endPoint = matchingAction.process.endPoint; + const dropPosition = (!endPoint || (Array.isArray(endPoint) && endPoint.every(v => v === 0))) + ? defaultPositions.drop + : endPoint; - 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); - setStartPosition(updatedProcess.startPoint) - updateStartPoint(modelUuid, actionUuid, updatedProcess.startPoint); - } else if (actionType === "drop") { - updatedProcess.endPoint = getLocalPosition(modelUuid, worldPositionArray); - setEndPosition(updatedProcess.endPoint) - updateEndPoint(modelUuid, actionUuid, updatedProcess.endPoint); + setStartPosition(pickPosition); + setEndPosition(dropPosition); + } } - 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) => { - if (action.actionUuid === selectedAction.actionId) { - return ( - - - - - - - ); - } else { - return null; // important! must return something } - })} - - ); + }, [selectedEventData, selectedProduct, getEventByModelUuid, selectedAction, armBots]); + + + 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) => { + if (action.actionUuid === actionUuid) { + const updatedProcess = { ...action.process }; + + if (actionType === "pick") { + updatedProcess.startPoint = getLocalPosition(modelUuid, worldPositionArray); + setStartPosition(updatedProcess.startPoint) + + } else if (actionType === "drop") { + updatedProcess.endPoint = getLocalPosition(modelUuid, worldPositionArray); + setEndPosition(updatedProcess.endPoint) + } + + const event = updateAction(selectedProduct.productId, + actionUuid, + { + actionUuid: action.actionUuid, + process: updatedProcess, + } + ) + + if (event) { + updateBackend( + selectedProduct.productName, + selectedProduct.productId, + organization, + event + ); + } + return { + ...action, + process: updatedProcess, + }; + } + return action; + }); + + } + } + } + + const { handlePointerDown } = useDraggableGLTF(updatePointToState); + + if (!selectedArmBotData || !Array.isArray(selectedArmBotData.point?.actions)) { + return null; // avoid rendering if no data yet + } + return ( + <> + {selectedArmBotData.point.actions.map((action: any) => { + if (action.actionUuid === selectedAction.actionId) { + return ( + + + {startPosition && endPosition && ( + <> + + + + )} + + + ); + } else { + return null; // important! must return something + } + })} + + ); }; diff --git a/app/src/store/simulation/useProductStore.ts b/app/src/store/simulation/useProductStore.ts index 8b83cdd..3fbaa76 100644 --- a/app/src/store/simulation/useProductStore.ts +++ b/app/src/store/simulation/useProductStore.ts @@ -40,7 +40,7 @@ type ProductsStore = { updates: Partial ) => EventsSchema | undefined; - // Trigger-level actions + // Trigger-level actionss addTrigger: ( productId: string, actionUuid: string, From 03fcc6223890786f255a9a3db6a734333c7b1284 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Sat, 3 May 2025 10:39:12 +0530 Subject: [PATCH 14/19] Refactor ArmBotUI: enhance action retrieval by using getActionByUuid; streamline state updates by removing unnecessary dependencies in useEffect. --- app/src/modules/simulation/ui/arm/armBotUI.tsx | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/app/src/modules/simulation/ui/arm/armBotUI.tsx b/app/src/modules/simulation/ui/arm/armBotUI.tsx index 01e631e..2d83147 100644 --- a/app/src/modules/simulation/ui/arm/armBotUI.tsx +++ b/app/src/modules/simulation/ui/arm/armBotUI.tsx @@ -19,7 +19,7 @@ type Positions = { }; const ArmBotUI = () => { - const { getEventByModelUuid, updateAction } = useProductStore(); + const { getEventByModelUuid, updateAction, getActionByUuid } = useProductStore(); const { selectedEventData } = useSelectedEventData(); const { selectedProduct } = useSelectedProduct(); const { armBots } = useArmBotStore(); @@ -58,15 +58,14 @@ const ArmBotUI = () => { 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); + const matchingAction = getActionByUuid(selectedProduct.productId, selectedAction.actionId); if (matchingAction) { - const startPoint = matchingAction.process.startPoint; + const startPoint = (matchingAction as RoboticArmPointSchema["actions"][0]).process.startPoint; const pickPosition = (!startPoint || (Array.isArray(startPoint) && startPoint.every(v => v === 0))) ? defaultPositions.pick : startPoint; - const endPoint = matchingAction.process.endPoint; + const endPoint = (matchingAction as RoboticArmPointSchema["actions"][0]).process.endPoint; const dropPosition = (!endPoint || (Array.isArray(endPoint) && endPoint.every(v => v === 0))) ? defaultPositions.drop : endPoint; @@ -76,7 +75,7 @@ const ArmBotUI = () => { } } } - }, [selectedEventData, selectedProduct, getEventByModelUuid, selectedAction, armBots]); + }, [selectedEventData, selectedProduct, getEventByModelUuid, selectedAction]); function getDefaultPositions(modelUuid: string): Positions { From 846350728f23874a456ef8e5683b2fd4f20577da Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Sat, 3 May 2025 10:39:43 +0530 Subject: [PATCH 15/19] Remove unused armBots reference from ArmBotUI component --- app/src/modules/simulation/ui/arm/armBotUI.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/modules/simulation/ui/arm/armBotUI.tsx b/app/src/modules/simulation/ui/arm/armBotUI.tsx index 2d83147..cc926aa 100644 --- a/app/src/modules/simulation/ui/arm/armBotUI.tsx +++ b/app/src/modules/simulation/ui/arm/armBotUI.tsx @@ -22,7 +22,6 @@ const ArmBotUI = () => { const { getEventByModelUuid, updateAction, getActionByUuid } = useProductStore(); const { selectedEventData } = useSelectedEventData(); const { selectedProduct } = useSelectedProduct(); - const { armBots } = useArmBotStore(); const { scene } = useThree(); const { selectedAction } = useSelectedAction(); From 1bfa004dc66e925c51af3c008486b91de95f9e2c Mon Sep 17 00:00:00 2001 From: Vishnu Date: Sat, 3 May 2025 10:41:34 +0530 Subject: [PATCH 16/19] Enhance UI components: add active state to ZoneItem, refactor EditWidgetOption and RealTimeVisualization styles, and implement RenameTooltip for dynamic renaming functionality. --- .../components/ui/features/RenameTooltip.tsx | 52 +++++++++++++++++++ app/src/components/ui/list/List.tsx | 3 +- .../components/ui/menu/EditWidgetOption.tsx | 10 ++-- .../instances/ikInstance/ikInstance.tsx | 5 +- .../visualization/RealTimeVisulization.tsx | 2 +- app/src/styles/components/lists.scss | 12 +---- app/src/styles/pages/realTimeViz.scss | 5 +- app/src/styles/pages/userAuth.scss | 10 ++-- 8 files changed, 70 insertions(+), 29 deletions(-) create mode 100644 app/src/components/ui/features/RenameTooltip.tsx diff --git a/app/src/components/ui/features/RenameTooltip.tsx b/app/src/components/ui/features/RenameTooltip.tsx new file mode 100644 index 0000000..ae64bf0 --- /dev/null +++ b/app/src/components/ui/features/RenameTooltip.tsx @@ -0,0 +1,52 @@ +import React, { useState } from "react"; +import { RenameIcon } from "../../icons/ContextMenuIcons"; +import { + useLeftData, + useTopData, +} from "../../../store/visualization/useZone3DWidgetStore"; + +type RenameTooltipProps = { + name: string; + onSubmit: (newName: string) => void; +}; + +const RenameTooltip: React.FC = ({ name, onSubmit }) => { + const [value, setValue] = useState(name); + + const { top } = useTopData(); + const { left } = useLeftData(); + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + onSubmit(value.trim()); + }; + + return ( +
+
+
+ +
+
Name
+
+
+ setValue(e.target.value)} + autoFocus + /> +
+
+ ); +}; + +export default RenameTooltip; diff --git a/app/src/components/ui/list/List.tsx b/app/src/components/ui/list/List.tsx index eebcaa7..b5403e1 100644 --- a/app/src/components/ui/list/List.tsx +++ b/app/src/components/ui/list/List.tsx @@ -27,6 +27,7 @@ interface ZoneItem { id: string; name: string; assets?: Asset[]; + active?: boolean; } interface ListProps { @@ -157,7 +158,7 @@ const List: React.FC = ({ items = [], remove }) => { {items?.map((item) => (
  • -
    +
    - {openObjects && - events.map((event, index) => )} -
    - -
    -
    - Need to Compare Layout? -
    -
    - Click 'Compare' to review and analyze the layout - differences between them. -
    -
    - -
    -
    -
    - - {selectedAsset && ( - - { - if (option === "Add to Product") { - handleAddEventToProduct({ - event: getEventByModelUuid(selectedAsset.modelUuid), - addEvent, - selectedProduct, - clearSelectedAsset - }); - } else { - handleRemoveEventFromProduct(); - } - }} + return ( +
    +
    Simulations
    +
    +
    +
    +
    Products
    + +
    +
    +
    + {products.map((product, index) => ( +
    + {/* eslint-disable-next-line */} +
    + setSelectedProduct(product.productId, product.productName) + } + > + - - )} + + handleRenameProduct(product.productId, newName) + } + /> +
    + {products.length > 1 && ( + + )} +
    + ))} +
    + +
    - ) + +
    + + {openObjects && + events.map((event, index) => ( + + ))} +
    + +
    +
    + Need to Compare Layout? +
    +
    + Click 'Compare' to review and analyze the layout + differences between them. +
    +
    + +
    +
    +
    + + {selectedAsset && ( + + { + if (option === "Add to Product") { + handleAddEventToProduct({ + event: getEventByModelUuid(selectedAsset.modelUuid), + addEvent, + selectedProduct, + clearSelectedAsset, + }); + } else { + handleRemoveEventFromProduct(); + } + }} + /> + + )} +
    + ); }; export default Simulations; diff --git a/app/src/components/ui/features/RenameTooltip.tsx b/app/src/components/ui/features/RenameTooltip.tsx index ae64bf0..180ba85 100644 --- a/app/src/components/ui/features/RenameTooltip.tsx +++ b/app/src/components/ui/features/RenameTooltip.tsx @@ -25,10 +25,8 @@ const RenameTooltip: React.FC = ({ name, onSubmit }) => {
    diff --git a/app/src/components/ui/menu/EditWidgetOption.tsx b/app/src/components/ui/menu/EditWidgetOption.tsx index 035b26b..558957b 100644 --- a/app/src/components/ui/menu/EditWidgetOption.tsx +++ b/app/src/components/ui/menu/EditWidgetOption.tsx @@ -1,4 +1,4 @@ -import React, { useEffect } from "react"; +import React from "react"; import { useLeftData, useTopData, @@ -28,13 +28,13 @@ const EditWidgetOption: React.FC = ({ >
    {options.map((option, index) => ( -
    onClick(option)} > {option} -
    + ))}
    diff --git a/app/src/components/ui/simulation/simulationPlayer.tsx b/app/src/components/ui/simulation/simulationPlayer.tsx index e569250..2b8dcff 100644 --- a/app/src/components/ui/simulation/simulationPlayer.tsx +++ b/app/src/components/ui/simulation/simulationPlayer.tsx @@ -64,8 +64,6 @@ const SimulationPlayer: React.FC = () => { const handleMouseDown = () => { isDragging.current = true; - document.addEventListener("mousemove", handleMouseMove); - document.addEventListener("mouseup", handleMouseUp); }; const handleMouseMove = (e: MouseEvent) => { @@ -80,11 +78,11 @@ const SimulationPlayer: React.FC = () => { const handleMouseUp = () => { isDragging.current = false; - document.removeEventListener("mousemove", handleMouseMove); - document.removeEventListener("mouseup", handleMouseUp); }; useEffect(() => { + document.addEventListener("mousemove", handleMouseMove); + document.addEventListener("mouseup", handleMouseUp); return () => { document.removeEventListener("mousemove", handleMouseMove); document.removeEventListener("mouseup", handleMouseUp); @@ -109,24 +107,6 @@ const SimulationPlayer: React.FC = () => { { name: "process 9", completed: 90 }, // 90% completed { name: "process 10", completed: 30 }, // 30% completed ]; - // Move getRandomColor out of render - const getRandomColor = () => { - const letters = "0123456789ABCDEF"; - let color = "#"; - for (let i = 0; i < 6; i++) { - color += letters[Math.floor(Math.random() * 16)]; - } - return color; - }; - - // Store colors for each process item - const [_, setProcessColors] = useState([]); - - // Generate colors on mount or when process changes - useEffect(() => { - const generatedColors = process.map(() => getRandomColor()); - setProcessColors(generatedColors); - }, []); const intervals = [10, 20, 30, 40, 50, 60]; // in minutes const totalSegments = intervals.length; @@ -218,7 +198,7 @@ const SimulationPlayer: React.FC = () => {
    )} - {subModule === "simulations" && ( + {subModule !== "analysis" && (
    {playSimulation @@ -281,7 +261,7 @@ const SimulationPlayer: React.FC = () => { const segmentProgress = (index / totalSegments) * 100; const isFilled = progress >= segmentProgress; return ( - +
    {label} mins
    { className="process-wrapper" style={{ padding: expand ? "0px" : "5px 35px" }} > + {/* eslint-disable-next-line */}
    { > {process.map((item, index) => (
    (null); - const [currentPath, setCurrentPath] = useState<[number, number, number][]>([]); - const [circlePoints, setCirclePoints] = useState<[number, number, number][]>([]); - const [customCurvePoints, setCustomCurvePoints] = useState(null); + const progressRef = useRef(0); + const curveRef = useRef(null); + const [currentPath, setCurrentPath] = useState<[number, number, number][]>( + [] + ); + const [circlePoints, setCirclePoints] = useState<[number, number, number][]>( + [] + ); + const [customCurvePoints, setCustomCurvePoints] = useState< + THREE.Vector3[] | null + >(null); - // Zustand stores - const { isPlaying } = usePlayButtonStore(); - const { isPaused } = usePauseButtonStore(); - const { isReset } = useResetButtonStore(); - const { speed } = useAnimationPlaySpeed(); + // Zustand stores + const { isPlaying } = usePlayButtonStore(); + const { isPaused } = usePauseButtonStore(); + const { isReset } = useResetButtonStore(); + const { speed } = useAnimationPlaySpeed(); - // Update path state whenever `path` prop changes - useEffect(() => { - setCurrentPath(path); - }, [path]); + // Update path state whenever `path` prop changes + useEffect(() => { + setCurrentPath(path); + }, [path]); - // Reset logic when `isPlaying` changes - useEffect(() => { - if (!isPlaying) { - setCurrentPath([]); - curveRef.current = null; - } - }, [isPlaying]); - - // Handle circle points based on armBot position - useEffect(() => { - 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; + // Reset logic when `isPlaying` changes + useEffect(() => { + if (!isPlaying) { + setCurrentPath([]); + curveRef.current = null; } + }, [isPlaying]); - 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 - } + // Handle circle points based on armBot position + useEffect(() => { + 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 start = currentPath[0]; + const end = currentPath[currentPath.length - 1]; + + 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 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]); + }; + + const nearestToStart = findNearest(raisedStart); + + const nearestToEnd = findNearest(raisedEnd); + + const indexOfNearestStart = findNearestIndex( + nearestToStart, + circlePoints + ); + + const indexOfNearestEnd = findNearestIndex(nearestToEnd, circlePoints); + + // 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), + ]; } - return -1; // Not found - }; - - - // Handle nearest points and final path (including arc points) - useEffect(() => { - if (circlePoints.length > 0 && currentPath.length > 0) { - const start = currentPath[0]; - const end = currentPath[currentPath.length - 1]; - - 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 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]); - }; - - const nearestToStart = findNearest(raisedStart); - - const nearestToEnd = findNearest(raisedEnd); - - const indexOfNearestStart = findNearestIndex(nearestToStart, circlePoints); - - const indexOfNearestEnd = findNearestIndex(nearestToEnd, circlePoints); - - // 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(pathVectors, false, 'centripetal', 1); - const generatedPoints = customCurve.getPoints(100); - setCustomCurvePoints(generatedPoints); + } else if (indexOfNearestStart >= indexOfNearestEnd) { + for ( + let i = indexOfNearestStart; + i !== (indexOfNearestEnd - 1 + 64) % 64; + i = (i - 1 + 64) % 64 + ) { + arcPoints.push(circlePoints[i]); } - }, [circlePoints, currentPath]); + } - // Frame update for animation - useFrame((_, delta) => { - if (!ikSolver) return; + // 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 bone = ikSolver.mesh.skeleton.bones.find((b: any) => b.name === targetBone); - if (!bone) return; + const customCurve = new THREE.CatmullRomCurve3( + pathVectors, + false, + "centripetal", + 1 + ); + const generatedPoints = customCurve.getPoints(100); + setCustomCurvePoints(generatedPoints); + } + }, [circlePoints, currentPath]); - if (isPlaying) { - if (!isPaused && customCurvePoints && currentPath.length > 0) { - const curvePoints = customCurvePoints; - const speedAdjustedProgress = progressRef.current + (speed * armBot.speed); - const index = Math.floor(speedAdjustedProgress); + // Frame update for animation + useFrame((_, delta) => { + if (!ikSolver) return; - if (index >= curvePoints.length) { - // Reached the end of the curve - HandleCallback(); - setCurrentPath([]); - curveRef.current = null; - progressRef.current = 0; - } else { - const point = curvePoints[index]; - bone.position.copy(point); - progressRef.current = speedAdjustedProgress; - } - } else if (isPaused) { - logStatus(armBot.modelUuid, 'Simulation Paused'); - } - - ikSolver.update(); - } else if (!isPlaying && currentPath.length === 0) { - // Not playing anymore, reset to rest - bone.position.copy(restPosition); - ikSolver.update(); - } - }); - - - return ( - <> - {customCurvePoints && currentPath && isPlaying && ( - - [p.x, p.y, p.z] as [number, number, number])} - color="green" - lineWidth={5} - dashed={false} - /> - - )} - - - - - + const bone = ikSolver.mesh.skeleton.bones.find( + (b: any) => b.name === targetBone ); + if (!bone) return; + + 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 { + const point = curvePoints[index]; + bone.position.copy(point); + progressRef.current = speedAdjustedProgress; + } + } else if (isPaused) { + logStatus(armBot.modelUuid, "Simulation Paused"); + } + + ikSolver.update(); + } else if (!isPlaying && currentPath.length === 0) { + // Not playing anymore, reset to rest + bone.position.copy(restPosition); + ikSolver.update(); + } + }); + + return ( + <> + {customCurvePoints && currentPath && isPlaying && ( + + [p.x, p.y, p.z] as [number, number, number] + )} + color="green" + lineWidth={5} + dashed={false} + /> + + )} + + + + + + ); } export default RoboticArmAnimator; From b4e3d3ef7361981b503726f793cb5a09a17bee7b Mon Sep 17 00:00:00 2001 From: Vishnu Date: Sat, 3 May 2025 11:17:20 +0530 Subject: [PATCH 19/19] Refactor styles: update backdrop-filter values for improved UI consistency; clean up code formatting in various components. --- app/src/styles/components/form.scss | 26 ++++++ .../components/simulation/simulation.scss | 89 ++++++++----------- app/src/styles/components/tools.scss | 33 ++++--- app/src/styles/layout/sidebar.scss | 10 +-- 4 files changed, 86 insertions(+), 72 deletions(-) diff --git a/app/src/styles/components/form.scss b/app/src/styles/components/form.scss index e69de29..67accd2 100644 --- a/app/src/styles/components/form.scss +++ b/app/src/styles/components/form.scss @@ -0,0 +1,26 @@ +@use "../abstracts/variables" as *; +@use "../abstracts/mixins" as *; + +.rename-tool-tip { + position: absolute; + background: var(--background-color); + padding: 10px 16px; + width: 260px; + border-radius: #{$border-radius-large}; + outline: 1px solid var(--border-color); + z-index: 100; + .header { + @include flex-center; + gap: 8px; + .icon { + @include flex-center; + } + .name { + color: var(--text-color); + } + input { + width: 100%; + margin-top: 6px; + } + } +} diff --git a/app/src/styles/components/simulation/simulation.scss b/app/src/styles/components/simulation/simulation.scss index 88f85dc..9b6c93d 100644 --- a/app/src/styles/components/simulation/simulation.scss +++ b/app/src/styles/components/simulation/simulation.scss @@ -3,7 +3,7 @@ .simulation-player-wrapper { position: fixed; - bottom: 12px; + bottom: 32px; left: 50%; z-index: 2; transform: translate(-50%, 0); @@ -35,11 +35,11 @@ @include flex-space-between; gap: 12px; justify-content: space-between; - .header{ + .header { @include flex-center; gap: 6px; padding: 0 8px; - svg{ + svg { scale: 1.3; } } @@ -299,6 +299,37 @@ } } } + + .open { + .start-displayer, + .end-displayer { + display: none; + } + + .timmer { + display: none; + } + .progresser-wrapper { + padding-top: 4px; + } + + .time-displayer { + height: 0; + opacity: 0; + pointer-events: none; + display: none; + } + + .processDisplayer { + padding: 0 8px; + background: transparent; + + .process-player { + width: 0; + display: none !important; + } + } + } } .processDisplayer { @@ -314,22 +345,6 @@ font-size: var(--font-size-tiny); } - .timmer { - width: auto; - position: absolute; - bottom: 0; - font-size: var(--font-size-tiny); - } - - .start-displayer { - left: 8px; - } - - .end-displayer { - width: auto; - right: 8px; - } - .start-displayer { bottom: 4px; left: 16px; @@ -351,12 +366,12 @@ border-width: 1px; background: var(--background-color-accent, #6f42c1); } - .process-wrapper{ + .process-wrapper { .process-container { position: relative; display: flex; width: 100%; - + .process { height: 5px; border-radius: 4px; @@ -368,35 +383,3 @@ } } } - -.simulation-player-container.open { - - .start-displayer, - .end-displayer { - display: none; - } - - .timmer { - display: none; - } - .progresser-wrapper { - padding-top: 4px; - } - - .time-displayer { - height: 0; - opacity: 0; - pointer-events: none; - display: none; - } - - .processDisplayer { - padding: 0 8px; - background: transparent; - - .process-player { - width: 0; - display: none !important; - } - } -} diff --git a/app/src/styles/components/tools.scss b/app/src/styles/components/tools.scss index 29d37b4..902e0fb 100644 --- a/app/src/styles/components/tools.scss +++ b/app/src/styles/components/tools.scss @@ -14,7 +14,7 @@ width: fit-content; transition: width 0.2s; background: var(--background-color); - backdrop-filter: blur(8px); + backdrop-filter: blur(20px); z-index: 2; outline: 1px solid var(--border-color); outline-offset: -1px; @@ -31,6 +31,7 @@ .activeDropicon { @include flex-center; gap: 2px; + // stylelint-disable-next-line interpolate-size: allow-keywords; width: 0; opacity: 0; @@ -44,9 +45,11 @@ border-radius: #{$border-radius-medium}; &:hover { - background: color-mix(in srgb, - var(--highlight-accent-color) 60%, - transparent); + background: color-mix( + in srgb, + var(--highlight-accent-color) 60%, + transparent + ); } } @@ -70,9 +73,11 @@ position: relative; &:hover { - background: color-mix(in srgb, - var(--highlight-accent-color) 60%, - transparent); + background: color-mix( + in srgb, + var(--highlight-accent-color) 60%, + transparent + ); } .drop-down-container { @@ -179,11 +184,11 @@ font-weight: 500; background: var(--accent-color); color: var(--highlight-accent-color); - &::after{ + &::after { animation: pulse 1s ease-out infinite; } } - &::after{ + &::after { content: ""; position: absolute; height: 100%; @@ -195,14 +200,14 @@ } @keyframes pulse { - 0%{ + 0% { opacity: 0; - scale: .5; + scale: 0.5; } - 50%{ + 50% { opacity: 1; } - 100%{ + 100% { opacity: 0; scale: 2; } @@ -218,4 +223,4 @@ width: fit-content; opacity: 1; } -} \ No newline at end of file +} diff --git a/app/src/styles/layout/sidebar.scss b/app/src/styles/layout/sidebar.scss index f8c022f..01256a4 100644 --- a/app/src/styles/layout/sidebar.scss +++ b/app/src/styles/layout/sidebar.scss @@ -7,7 +7,7 @@ top: 32px; left: 8px; background: var(--background-color); - backdrop-filter: blur(15px); + backdrop-filter: blur(20px); border-radius: #{$border-radius-extra-large}; outline: 1px solid var(--border-color); box-shadow: #{$box-shadow-medium}; @@ -250,7 +250,7 @@ top: 32px; right: 8px; background: var(--background-color); - backdrop-filter: blur(15px); + backdrop-filter: blur(20px); border-radius: #{$border-radius-extra-large}; outline: 1px solid var(--border-color); box-shadow: #{$box-shadow-medium}; @@ -363,7 +363,7 @@ height: 34px; width: 34px; border-radius: #{$border-radius-circle}; - background: var(--background-color-secondary); + background: var(--background-color-solid-gradient); backdrop-filter: blur(12px); outline: 1px solid var(--border-color); outline-offset: -1px; @@ -416,7 +416,7 @@ outline: none; path { stroke: var(--text-button-color); - strokeWidth: 1.3; + stroke-width: 1.3; } } } @@ -682,7 +682,7 @@ path { stroke: var(--accent-color); - strokeWidth: 1.5px; + stroke-width: 1.5px; } &:hover {