diff --git a/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx b/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx
index d96182b..a1e88cc 100644
--- a/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx
+++ b/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx
@@ -1,7 +1,7 @@
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';
+import { Line, Text } from '@react-three/drei';
import {
useAnimationPlaySpeed,
usePauseButtonStore,
@@ -94,9 +94,9 @@ function RoboticArmAnimator({
}
useEffect(() => {
const points = generateRingPointsWithDegrees(CIRCLE_RADIUS, 64);
-
+
}, [armBot.position]);
-
+
// Function for find nearest Circlepoints Index
const findNearestIndex = (nearestPoint: [number, number, number], points: [number, number, number][], epsilon = 1e-6) => {
for (let i = 0; i < points.length; i++) {
@@ -124,7 +124,6 @@ function RoboticArmAnimator({
// 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];
@@ -137,31 +136,50 @@ function RoboticArmAnimator({
const indexOfNearestStart = findNearestIndex(nearestToStart, circlePoints);
const indexOfNearestEnd = findNearestIndex(nearestToEnd, circlePoints);
- const clockwiseDistance = (indexOfNearestEnd - indexOfNearestStart + 64) % 64;
- const counterClockwiseDistance = (indexOfNearestStart - indexOfNearestEnd + 64) % 64;
- const clockwiseIsShorter = clockwiseDistance <= counterClockwiseDistance;
+ const totalSegments = 64;
+ const clockwiseDistance = (indexOfNearestEnd - indexOfNearestStart + totalSegments) % totalSegments;
+ const counterClockwiseDistance = (indexOfNearestStart - indexOfNearestEnd + totalSegments) % totalSegments;
+
+ // Prepare degrees
+ const degreesList = generateRingPointsWithDegrees(CIRCLE_RADIUS, totalSegments);
+
+ // Helper function to collect points and check forbidden degrees
+ const collectArcPoints = (startIdx: number, endIdx: number, clockwise: boolean) => {
+ const arcPoints: [number, number, number][] = [];
+ let i = startIdx;
+
+ while (i !== (endIdx + (clockwise ? 1 : -1) + totalSegments) % totalSegments) {
+ const { degree, position } = degreesList[i];
+
+ // Skip over
+ arcPoints.push(position);
+ i = (i + (clockwise ? 1 : -1) + totalSegments) % totalSegments;
+ }
+ return arcPoints;
+ };
+
+ const hasForbiddenDegrees = (arc: [number, number, number][]) => {
+ return arc.some(p => {
+ const idx = findNearestIndex(p, circlePoints);
+ const degree = degreesList[idx]?.degree || 0;
+ return degree >= 271 && degree <= 300; // Forbidden range: 271° to 300°
+ });
+ };
+
+
+ // Try both directions
+ const arcClockwise = collectArcPoints(indexOfNearestStart, indexOfNearestEnd, true);
+ const arcCounterClockwise = collectArcPoints(indexOfNearestStart, indexOfNearestEnd, false);
+
+ const clockwiseForbidden = hasForbiddenDegrees(arcClockwise);
+ const counterClockwiseForbidden = hasForbiddenDegrees(arcCounterClockwise);
let arcPoints: [number, number, number][] = [];
- if (clockwiseIsShorter) {
- if (indexOfNearestStart <= indexOfNearestEnd) {
- arcPoints = circlePoints.slice(indexOfNearestStart, indexOfNearestEnd + 1);
- } else {
- arcPoints = [
- ...circlePoints.slice(indexOfNearestStart, 64),
- ...circlePoints.slice(0, indexOfNearestEnd + 1)
- ];
- }
+ if (!clockwiseForbidden && (clockwiseDistance <= counterClockwiseDistance || counterClockwiseForbidden)) {
+ arcPoints = arcClockwise;
} 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]);
- }
- }
+ arcPoints = arcCounterClockwise;
}
const pathVectors = [
@@ -174,9 +192,7 @@ function RoboticArmAnimator({
new THREE.Vector3(end[0], end[1], end[2])
];
-
const pathSegments: [THREE.Vector3, THREE.Vector3][] = [];
-
for (let i = 0; i < pathVectors.length - 1; i++) {
pathSegments.push([pathVectors[i], pathVectors[i + 1]]);
}
@@ -186,16 +202,12 @@ function RoboticArmAnimator({
const totalDistance = segmentDistances.reduce((sum, d) => sum + d, 0);
totalDistanceRef.current = totalDistance;
- const movementSpeed = speed * armBot.speed;
- const totalMoveTime = totalDistance / movementSpeed;
-
- const segmentTimes = segmentDistances.map(distance => (distance / totalDistance) * totalMoveTime);
-
setCustomCurvePoints(pathVectors);
-
}
}, [circlePoints, currentPath]);
+
+
// Frame update for animation
useFrame((state, delta) => {
if (!ikSolver) return;
@@ -266,10 +278,52 @@ function RoboticArmAnimator({
/>
)}
-
-
-
-
+
+ {/* Green ring */}
+
+
+
+
+
+ {/* Markers at 90°, 180°, 270°, 360° */}
+ {[90, 180, 270, 360].map((degree, index) => {
+ const rad = (degree * Math.PI) / 180;
+ const x = CIRCLE_RADIUS * Math.cos(rad);
+ const z = CIRCLE_RADIUS * Math.sin(rad);
+ const y = 0; // same plane as the ring (Y axis)
+
+ return (
+
+
+
+
+ );
+ })}
+
+ {/* Optional: Text Labels */}
+
+ {[90, 180, 270, 360].map((degree, index) => {
+ const rad = (degree * Math.PI) / 180;
+ const x = CIRCLE_RADIUS * Math.cos(rad);
+ const z = CIRCLE_RADIUS * Math.sin(rad);
+ const y = 0.15; // lift the text slightly above the ring
+
+ return (
+
+ {degree}°
+
+ );
+ })}
+
+
+
>
);
}
diff --git a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx
index 21bbc7e..246d3f8 100644
--- a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx
+++ b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx
@@ -164,6 +164,17 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
else if (armBot && !armBot.isActive && armBot.state === "idle" && currentPhase === "dropping" && armBot.currentAction) {
requestAnimationFrame(firstFrame);
}
+ }else{
+ logStatus(armBot.modelUuid, "Simulation Play Exited")
+ setArmBotActive(armBot.modelUuid, false)
+ setArmBotState(armBot.modelUuid, "idle")
+ setCurrentPhase("init");
+ setPath([])
+ isPausedRef.current = false
+ pauseTimeRef.current = null
+ isPausedRef.current = false
+ startTime = 0
+ removeCurrentAction(armBot.modelUuid)
}
}, [currentPhase, armBot, isPlaying, ikSolver])
diff --git a/app/src/modules/simulation/ui/arm/useDraggableGLTF.ts b/app/src/modules/simulation/ui/arm/useDraggableGLTF.ts
index b819852..fdb271c 100644
--- a/app/src/modules/simulation/ui/arm/useDraggableGLTF.ts
+++ b/app/src/modules/simulation/ui/arm/useDraggableGLTF.ts
@@ -139,15 +139,16 @@ export default function useDraggableGLTF(onUpdate: OnUpdateCallback) {
}
// Allow only angles between 90° and 270°
- if (angleDeg < 95 || angleDeg > 270) {
+ if (angleDeg < 0 || angleDeg > 270) {
// Clamp to nearest boundary (90° or 270°)
- const distanceTo90 = Math.abs(angleDeg - 95);
+ const distanceTo90 = Math.abs(angleDeg - 0);
const distanceTo270 = Math.abs(angleDeg - 270);
if (distanceTo90 < distanceTo270) {
- angleDeg = 95;
+ angleDeg = 0;
} else {
- angleDeg = 270;
+ return
+ // angleDeg = 270;
}
// Update angle in radians