Implement AGV, Conveyor, and Robotic Arm simulations with MQTT integration and Developed ArmAnimator for controlling robotic arm animations with pathfinding.
This commit is contained in:
parent
60c0bef5f9
commit
3d9f625e3d
|
@ -1,8 +1,9 @@
|
||||||
import { useFrame, useThree } from '@react-three/fiber';
|
import { useFrame, useThree } from '@react-three/fiber';
|
||||||
import React, { useEffect, useRef, useState } from 'react';
|
import React, { useEffect, useRef, useState } from 'react';
|
||||||
import * as THREE from 'three';
|
import * as THREE from 'three';
|
||||||
import useModuleStore from '../../store/useModuleStore';
|
import useModuleStore from '../../../../store/useModuleStore';
|
||||||
import { MaterialModel } from '../simulation/materials/instances/material/materialModel';
|
import { MaterialModel } from '../../../simulation/materials/instances/material/materialModel';
|
||||||
|
|
||||||
|
|
||||||
type AgvSimulationProps = {
|
type AgvSimulationProps = {
|
||||||
data: any;
|
data: any;
|
|
@ -1,7 +1,8 @@
|
||||||
import { useFrame, useThree } from '@react-three/fiber';
|
import { useFrame, useThree } from '@react-three/fiber';
|
||||||
import React, { useEffect, useRef, useState } from 'react'
|
import React, { useEffect, useRef, useState } from 'react'
|
||||||
import * as THREE from "three";
|
import * as THREE from "three";
|
||||||
import { useAnimationPlaySpeed } from '../../store/usePlayButtonStore';
|
import { useAnimationPlaySpeed } from '../../../../store/usePlayButtonStore';
|
||||||
|
|
||||||
|
|
||||||
type PointWithDegree = {
|
type PointWithDegree = {
|
||||||
position: [number, number, number];
|
position: [number, number, number];
|
|
@ -1,9 +1,11 @@
|
||||||
import React, { useEffect, useRef, useState } from 'react';
|
import React, { useEffect, useRef, useState } from 'react';
|
||||||
import * as THREE from 'three';
|
import * as THREE from 'three';
|
||||||
import useMqttConnectionStore from '../../store/iiot/iiotmqttConnectionStore';
|
|
||||||
import { useFrame, useThree } from '@react-three/fiber';
|
import { useFrame, useThree } from '@react-three/fiber';
|
||||||
import useModuleStore from '../../store/useModuleStore';
|
import useMqttConnectionStore from '../../../../store/iiot/iiotmqttConnectionStore';
|
||||||
import { MaterialModel } from '../simulation/materials/instances/material/materialModel';
|
import useModuleStore from '../../../../store/useModuleStore';
|
||||||
|
import { MaterialModel } from '../../../simulation/materials/instances/material/materialModel';
|
||||||
|
|
||||||
|
|
||||||
type ConveyorSimulationProps = {
|
type ConveyorSimulationProps = {
|
||||||
data: any;
|
data: any;
|
|
@ -1,6 +1,7 @@
|
||||||
import { useFrame, useThree } from '@react-three/fiber';
|
import { useFrame, useThree } from '@react-three/fiber';
|
||||||
import React, { useEffect, useRef, useState } from 'react';
|
import React, { useEffect, useRef, useState } from 'react';
|
||||||
import useModuleStore from '../../store/useModuleStore';
|
import useModuleStore from '../../../../store/useModuleStore';
|
||||||
|
|
||||||
|
|
||||||
type MachineSimulationProps = {
|
type MachineSimulationProps = {
|
||||||
data: any;
|
data: any;
|
|
@ -1,12 +1,11 @@
|
||||||
import React, { useEffect, useRef, useState } from "react";
|
import React, { useEffect, useRef, useState } from "react";
|
||||||
import useModuleStore from "../../store/useModuleStore";
|
|
||||||
import { useThree } from "@react-three/fiber";
|
import { useThree } from "@react-three/fiber";
|
||||||
import IIotIkSolver from "./IIotIkSolver";
|
import armModel from "../../../../../assets/gltf-glb/rigged/ik_arm_1.glb";
|
||||||
import armModel from "../../assets/gltf-glb/rigged/ik_arm_1.glb";
|
|
||||||
import * as THREE from "three";
|
import * as THREE from "three";
|
||||||
import ArmAnimator from "./ArmAnimator";
|
import useModuleStore from "../../../../../store/useModuleStore";
|
||||||
import { useFloorItems } from "../../store/builder/store";
|
import IIotIkSolver from "./IIotIkSolver";
|
||||||
import { MaterialModel } from "../simulation/materials/instances/material/materialModel";
|
import ArmAnimator from "../ArmAnimator";
|
||||||
|
|
||||||
|
|
||||||
type ArmBotSimulationProps = {
|
type ArmBotSimulationProps = {
|
||||||
data: any;
|
data: any;
|
|
@ -1,6 +1,7 @@
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import useMqttConnectionStore from '../../store/iiot/iiotmqttConnectionStore';
|
|
||||||
import { IClientSubscribeOptions } from 'mqtt';
|
import { IClientSubscribeOptions } from 'mqtt';
|
||||||
|
import useMqttConnectionStore from '../../../../store/iiot/iiotmqttConnectionStore';
|
||||||
|
|
||||||
|
|
||||||
interface MqttListenerProps {
|
interface MqttListenerProps {
|
||||||
|
@ -20,27 +21,27 @@ const MqttListener: React.FC<MqttListenerProps> = ({ setData }) => {
|
||||||
const topic4 = 'agv0001/0001/status'
|
const topic4 = 'agv0001/0001/status'
|
||||||
const topic5 = 'arm0001/0001/status'
|
const topic5 = 'arm0001/0001/status'
|
||||||
|
|
||||||
client.subscribe(topic1, {} as IClientSubscribeOptions, (err) => {
|
client.subscribe(topic1, {} as IClientSubscribeOptions, (err:any) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.error('Subscription error:', err);
|
console.error('Subscription error:', err);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
client.subscribe(topic2, {} as IClientSubscribeOptions, (err) => {
|
client.subscribe(topic2, {} as IClientSubscribeOptions, (err:any) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.error('Subscription error:', err);
|
console.error('Subscription error:', err);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
client.subscribe(topic3, {} as IClientSubscribeOptions, (err) => {
|
client.subscribe(topic3, {} as IClientSubscribeOptions, (err:any) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.error('Subscription error:', err);
|
console.error('Subscription error:', err);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
client.subscribe(topic4, {} as IClientSubscribeOptions, (err) => {
|
client.subscribe(topic4, {} as IClientSubscribeOptions, (err:any) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.error('Subscription error:', err);
|
console.error('Subscription error:', err);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
client.subscribe(topic5, {} as IClientSubscribeOptions, (err) => {
|
client.subscribe(topic5, {} as IClientSubscribeOptions, (err:any) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.error('Subscription error:', err);
|
console.error('Subscription error:', err);
|
||||||
}
|
}
|
|
@ -1,12 +1,13 @@
|
||||||
|
|
||||||
//singleConveyor
|
//singleConveyor
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import MqttListener from './MqttListener';
|
|
||||||
import ConveyorSimulation from './ConveyorSimulation';
|
|
||||||
import MachineSimulation from './MachineSimulation';
|
|
||||||
import AgvSimulation from './AgvSimulation';
|
|
||||||
import RoboticArmSimulation from './RoboticArmSimulation';
|
|
||||||
import useModuleStore from '../../store/useModuleStore';
|
import useModuleStore from '../../store/useModuleStore';
|
||||||
|
import ConveyorSimulation from './RTSimulation/IIOTSimulation/ConveyorSimulation';
|
||||||
|
import MachineSimulation from './RTSimulation/IIOTSimulation/MachineSimulation';
|
||||||
|
import AgvSimulation from './RTSimulation/IIOTSimulation/AgvSimulation';
|
||||||
|
import RoboticArmSimulation from './RTSimulation/IIOTSimulation/RoboticArm/RoboticArmSimulation';
|
||||||
|
import MqttListener from './RTSimulation/MqttData/MqttListener';
|
||||||
|
|
||||||
type MqttData = {
|
type MqttData = {
|
||||||
state?: string;
|
state?: string;
|
||||||
|
|
|
@ -41,44 +41,3 @@ export default function Scene() {
|
||||||
</KeyboardControls>
|
</KeyboardControls>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// export default function Scene() {
|
|
||||||
// const map = useMemo(() => [
|
|
||||||
// { name: "forward", keys: ["ArrowUp", "w", "W"] },
|
|
||||||
// { name: "backward", keys: ["ArrowDown", "s", "S"] },
|
|
||||||
// { name: "left", keys: ["ArrowLeft", "a", "A"] },
|
|
||||||
// { name: "right", keys: ["ArrowRight", "d", "D"] },
|
|
||||||
// ], []);
|
|
||||||
// const { activeModule, setActiveModule } = useModuleStore();
|
|
||||||
|
|
||||||
// return (
|
|
||||||
// <KeyboardControls map={map}>
|
|
||||||
// {activeModule !== "visualization" &&
|
|
||||||
// <Canvas
|
|
||||||
// eventPrefix="client"
|
|
||||||
// gl={{ powerPreference: "high-performance", antialias: true }}
|
|
||||||
// onContextMenu={(e) => {
|
|
||||||
// e.preventDefault();
|
|
||||||
// }}
|
|
||||||
// >
|
|
||||||
// <Setup />
|
|
||||||
|
|
||||||
// <Collaboration />
|
|
||||||
|
|
||||||
// <Builder />
|
|
||||||
|
|
||||||
// <Simulation />
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// <Visualization />
|
|
||||||
// </Canvas>}
|
|
||||||
// {activeModule === "visualization" && <CanvasComponent />}
|
|
||||||
|
|
||||||
// </KeyboardControls>
|
|
||||||
// );
|
|
||||||
// }
|
|
|
@ -41,10 +41,6 @@ export default function ROIData() {
|
||||||
if (!isNaN(electricityCost) && !isNaN(fixedCost) && !isNaN(laborCost) && !isNaN(maintenanceCost) &&
|
if (!isNaN(electricityCost) && !isNaN(fixedCost) && !isNaN(laborCost) && !isNaN(maintenanceCost) &&
|
||||||
!isNaN(materialCost) && !isNaN(productionPeriod) && !isNaN(salvageValue) && !isNaN(sellingPrice) &&
|
!isNaN(materialCost) && !isNaN(productionPeriod) && !isNaN(salvageValue) && !isNaN(sellingPrice) &&
|
||||||
!isNaN(shiftLength) && !isNaN(shiftsPerDay) && !isNaN(workingDaysPerYear) && productionCapacityData > 0) {
|
!isNaN(shiftLength) && !isNaN(shiftsPerDay) && !isNaN(workingDaysPerYear) && productionCapacityData > 0) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const totalHoursPerYear = shiftLength * shiftsPerDay * workingDaysPerYear;
|
const totalHoursPerYear = shiftLength * shiftsPerDay * workingDaysPerYear;
|
||||||
|
|
||||||
// Total good units produced per year
|
// Total good units produced per year
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
import { findNearestIndex } from "./findNearestIndex";
|
||||||
|
|
||||||
|
// Helper function to collect points and check forbidden degrees
|
||||||
|
type PointWithDegree = {
|
||||||
|
position: [number, number, number];
|
||||||
|
degree: number;
|
||||||
|
};
|
||||||
|
export function collectArcPoints(circlePointsWithDegrees: PointWithDegree[], startIdx: number, endIdx: number, clockwise: boolean) {
|
||||||
|
const totalSegments = 64;
|
||||||
|
const arcPoints: [number, number, number][] = [];
|
||||||
|
let i = startIdx;
|
||||||
|
|
||||||
|
while (i !== (endIdx + (clockwise ? 1 : -1) + totalSegments) % totalSegments) {
|
||||||
|
const { degree, position } = circlePointsWithDegrees[i];
|
||||||
|
// Skip over
|
||||||
|
arcPoints.push(position);
|
||||||
|
i = (i + (clockwise ? 1 : -1) + totalSegments) % totalSegments;
|
||||||
|
}
|
||||||
|
return arcPoints;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Range to restrict angle
|
||||||
|
export function hasForbiddenDegrees(circlePoints: [number, number, number][], circlePointsWithDegrees: PointWithDegree[], arc: [number, number, number][]) {
|
||||||
|
return arc.some(p => {
|
||||||
|
const idx = findNearestIndex(p, circlePoints);
|
||||||
|
const degree = circlePointsWithDegrees[idx]?.degree || 0;
|
||||||
|
return degree >= 271 && degree <= 300; // Forbidden range: 271° to 300°
|
||||||
|
});
|
||||||
|
};
|
|
@ -0,0 +1,23 @@
|
||||||
|
// Function for find nearest Circlepoints Index
|
||||||
|
export function 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
|
||||||
|
};
|
||||||
|
|
||||||
|
//function to find nearest Circlepoints
|
||||||
|
export function findNearest(circlePoints: [number, number, number][], 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]);
|
||||||
|
};
|
|
@ -0,0 +1,29 @@
|
||||||
|
//Generate Circle Points
|
||||||
|
export 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Generate CirclePoints with Angle
|
||||||
|
export function generateRingPointsWithDegrees(radius: number, segments: number, initialRotation: [number, number, number]) {
|
||||||
|
const points: { position: [number, number, number]; degree: number }[] = [];
|
||||||
|
for (let i = 0; i < segments; i++) {
|
||||||
|
const angleRadians = (i / segments) * Math.PI * 2;
|
||||||
|
const x = Math.cos(angleRadians) * radius;
|
||||||
|
const z = Math.sin(angleRadians) * radius;
|
||||||
|
const degree = (angleRadians * 180) / Math.PI; // Convert radians to degrees
|
||||||
|
points.push({
|
||||||
|
position: [x, 1.5, z],
|
||||||
|
degree,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return points;
|
||||||
|
}
|
|
@ -3,6 +3,9 @@ import { useFrame, useThree } from '@react-three/fiber';
|
||||||
import * as THREE from 'three';
|
import * as THREE from 'three';
|
||||||
import { Line, Text } from '@react-three/drei';
|
import { Line, Text } from '@react-three/drei';
|
||||||
import { useAnimationPlaySpeed, usePauseButtonStore, usePlayButtonStore, useResetButtonStore } from '../../../../../store/usePlayButtonStore';
|
import { useAnimationPlaySpeed, usePauseButtonStore, usePlayButtonStore, useResetButtonStore } from '../../../../../store/usePlayButtonStore';
|
||||||
|
import { generateRingPoints, generateRingPointsWithDegrees } from '../../functions/generateRingPoints';
|
||||||
|
import { findNearest, findNearestIndex } from '../../functions/findNearestIndex';
|
||||||
|
import { collectArcPoints, hasForbiddenDegrees } from '../../functions/collectArcPoints';
|
||||||
|
|
||||||
type PointWithDegree = {
|
type PointWithDegree = {
|
||||||
position: [number, number, number];
|
position: [number, number, number];
|
||||||
|
@ -58,90 +61,12 @@ function RoboticArmAnimator({ HandleCallback, restPosition, ikSolver, targetBone
|
||||||
}
|
}
|
||||||
}, [isReset, isPlaying])
|
}, [isReset, isPlaying])
|
||||||
|
|
||||||
//Generate Circle Points
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Generate CirclePoints with Angle
|
|
||||||
function generateRingPointsWithDegrees(radius: number, segments: number, initialRotation: [number, number, number]) {
|
|
||||||
const points: { position: [number, number, number]; degree: number }[] = [];
|
|
||||||
for (let i = 0; i < segments; i++) {
|
|
||||||
const angleRadians = (i / segments) * Math.PI * 2;
|
|
||||||
const x = Math.cos(angleRadians) * radius;
|
|
||||||
const z = Math.sin(angleRadians) * radius;
|
|
||||||
const degree = (angleRadians * 180) / Math.PI; // Convert radians to degrees
|
|
||||||
points.push({
|
|
||||||
position: [x, 1.5, z],
|
|
||||||
degree,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return points;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle circle points based on armBot position
|
// Handle circle points based on armBot position
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const points = generateRingPointsWithDegrees(CIRCLE_RADIUS, 64, armBot.rotation);
|
const points = generateRingPointsWithDegrees(CIRCLE_RADIUS, 64, armBot.rotation);
|
||||||
setCirclePointsWithDegrees(points)
|
setCirclePointsWithDegrees(points)
|
||||||
}, [armBot.rotation]);
|
}, [armBot.rotation]);
|
||||||
|
|
||||||
// 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++) {
|
|
||||||
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
|
|
||||||
};
|
|
||||||
|
|
||||||
//function to find nearest Circlepoints
|
|
||||||
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]);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Helper function to collect points and check forbidden degrees
|
|
||||||
const collectArcPoints = (startIdx: number, endIdx: number, clockwise: boolean) => {
|
|
||||||
const totalSegments = 64;
|
|
||||||
const arcPoints: [number, number, number][] = [];
|
|
||||||
let i = startIdx;
|
|
||||||
|
|
||||||
while (i !== (endIdx + (clockwise ? 1 : -1) + totalSegments) % totalSegments) {
|
|
||||||
const { degree, position } = circlePointsWithDegrees[i];
|
|
||||||
// Skip over
|
|
||||||
arcPoints.push(position);
|
|
||||||
i = (i + (clockwise ? 1 : -1) + totalSegments) % totalSegments;
|
|
||||||
}
|
|
||||||
return arcPoints;
|
|
||||||
};
|
|
||||||
|
|
||||||
//Range to restrict angle
|
|
||||||
const hasForbiddenDegrees = (arc: [number, number, number][]) => {
|
|
||||||
return arc.some(p => {
|
|
||||||
const idx = findNearestIndex(p, circlePoints);
|
|
||||||
const degree = circlePointsWithDegrees[idx]?.degree || 0;
|
|
||||||
return degree >= 271 && degree <= 300; // Forbidden range: 271° to 300°
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Handle nearest points and final path (including arc points)
|
// Handle nearest points and final path (including arc points)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (circlePoints.length > 0 && currentPath.length > 0) {
|
if (circlePoints.length > 0 && currentPath.length > 0) {
|
||||||
|
@ -152,8 +77,8 @@ function RoboticArmAnimator({ HandleCallback, restPosition, ikSolver, targetBone
|
||||||
const raisedStart = [start[0], start[1] + 0.5, start[2]] as [number, number, number];
|
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 raisedEnd = [end[0], end[1] + 0.5, end[2]] as [number, number, number];
|
||||||
|
|
||||||
const nearestToStart = findNearest(raisedStart);
|
const nearestToStart = findNearest(circlePoints, raisedStart);
|
||||||
const nearestToEnd = findNearest(raisedEnd);
|
const nearestToEnd = findNearest(circlePoints, raisedEnd);
|
||||||
|
|
||||||
const indexOfNearestStart = findNearestIndex(nearestToStart, circlePoints);
|
const indexOfNearestStart = findNearestIndex(nearestToStart, circlePoints);
|
||||||
const indexOfNearestEnd = findNearestIndex(nearestToEnd, circlePoints);
|
const indexOfNearestEnd = findNearestIndex(nearestToEnd, circlePoints);
|
||||||
|
@ -163,11 +88,11 @@ function RoboticArmAnimator({ HandleCallback, restPosition, ikSolver, targetBone
|
||||||
const counterClockwiseDistance = (indexOfNearestStart - indexOfNearestEnd + totalSegments) % totalSegments;
|
const counterClockwiseDistance = (indexOfNearestStart - indexOfNearestEnd + totalSegments) % totalSegments;
|
||||||
|
|
||||||
// Try both directions
|
// Try both directions
|
||||||
const arcClockwise = collectArcPoints(indexOfNearestStart, indexOfNearestEnd, true);
|
const arcClockwise = collectArcPoints(circlePointsWithDegrees, indexOfNearestStart, indexOfNearestEnd, true);
|
||||||
const arcCounterClockwise = collectArcPoints(indexOfNearestStart, indexOfNearestEnd, false);
|
const arcCounterClockwise = collectArcPoints(circlePointsWithDegrees, indexOfNearestStart, indexOfNearestEnd, false);
|
||||||
|
|
||||||
const clockwiseForbidden = hasForbiddenDegrees(arcClockwise);
|
const clockwiseForbidden = hasForbiddenDegrees(circlePoints, circlePointsWithDegrees, arcClockwise);
|
||||||
const counterClockwiseForbidden = hasForbiddenDegrees(arcCounterClockwise);
|
const counterClockwiseForbidden = hasForbiddenDegrees(circlePoints, circlePointsWithDegrees, arcCounterClockwise);
|
||||||
|
|
||||||
let arcPoints: [number, number, number][] = [];
|
let arcPoints: [number, number, number][] = [];
|
||||||
|
|
||||||
|
|
|
@ -84,7 +84,6 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleDropTrigger = () => {
|
const handleDropTrigger = () => {
|
||||||
|
|
||||||
if (armBot.currentAction) {
|
if (armBot.currentAction) {
|
||||||
const action = getActionByUuid(selectedProduct.productId, armBot.currentAction.actionUuid);
|
const action = getActionByUuid(selectedProduct.productId, armBot.currentAction.actionUuid);
|
||||||
const model = getEventByModelUuid(selectedProduct.productId, action?.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid || '');
|
const model = getEventByModelUuid(selectedProduct.productId, action?.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid || '');
|
||||||
|
@ -177,6 +176,30 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function animate(currentTime: number) {
|
||||||
|
if (previousTimeRef.current === null) {
|
||||||
|
previousTimeRef.current = currentTime;
|
||||||
|
}
|
||||||
|
const deltaTime = (currentTime - previousTimeRef.current) / 1000;
|
||||||
|
previousTimeRef.current = currentTime;
|
||||||
|
if (armBot.isActive) {
|
||||||
|
if (!isPausedRef.current) {
|
||||||
|
activeSecondsElapsed.current += deltaTime * isSpeedRef.current;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!isPausedRef.current) {
|
||||||
|
idleSecondsElapsed.current += deltaTime * isSpeedRef.current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
animationFrameIdRef.current = requestAnimationFrame(animate);
|
||||||
|
}
|
||||||
|
function createCurveBetweenTwoPoints(p1: any, p2: any) {
|
||||||
|
const mid = new THREE.Vector3().addVectors(p1, p2).multiplyScalar(0.5);
|
||||||
|
const points = [p1, mid, p2];
|
||||||
|
return new THREE.CatmullRomCurve3(points);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
isPausedRef.current = isPaused;
|
isPausedRef.current = isPaused;
|
||||||
}, [isPaused]);
|
}, [isPaused]);
|
||||||
|
@ -217,27 +240,6 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
|
||||||
}
|
}
|
||||||
}, [isReset, isPlaying])
|
}, [isReset, isPlaying])
|
||||||
|
|
||||||
|
|
||||||
function animate(currentTime: number) {
|
|
||||||
if (previousTimeRef.current === null) {
|
|
||||||
previousTimeRef.current = currentTime;
|
|
||||||
}
|
|
||||||
const deltaTime = (currentTime - previousTimeRef.current) / 1000;
|
|
||||||
previousTimeRef.current = currentTime;
|
|
||||||
if (armBot.isActive) {
|
|
||||||
if (!isPausedRef.current) {
|
|
||||||
activeSecondsElapsed.current += deltaTime * isSpeedRef.current;
|
|
||||||
// console.log(' activeSecondsElapsed.current: ', activeSecondsElapsed.current);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!isPausedRef.current) {
|
|
||||||
idleSecondsElapsed.current += deltaTime * isSpeedRef.current;
|
|
||||||
// console.log('idleSecondsElapsed.current: ', idleSecondsElapsed.current);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
animationFrameIdRef.current = requestAnimationFrame(animate);
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isPlaying) return
|
if (!isPlaying) return
|
||||||
|
|
||||||
|
@ -346,11 +348,6 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
|
||||||
}, [currentPhase, armBot, isPlaying, isReset, ikSolver])
|
}, [currentPhase, armBot, isPlaying, isReset, ikSolver])
|
||||||
|
|
||||||
|
|
||||||
function createCurveBetweenTwoPoints(p1: any, p2: any) {
|
|
||||||
const mid = new THREE.Vector3().addVectors(p1, p2).multiplyScalar(0.5);
|
|
||||||
const points = [p1, mid, p2];
|
|
||||||
return new THREE.CatmullRomCurve3(points);
|
|
||||||
}
|
|
||||||
|
|
||||||
const HandleCallback = () => {
|
const HandleCallback = () => {
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue