enhance simulation components with state management and event handling for armbot
This commit is contained in:
parent
73d2cc8c73
commit
60c0bef5f9
|
@ -89,7 +89,7 @@ function AgvSimulation({ data, assetName, assetUUID }: AgvSimulationProps) {
|
||||||
if (materialRef.current && offsetRef.current) {
|
if (materialRef.current && offsetRef.current) {
|
||||||
materialRef.current.position.copy(currentPos.clone().add(offsetRef.current));
|
materialRef.current.position.copy(currentPos.clone().add(offsetRef.current));
|
||||||
}
|
}
|
||||||
console.log(` ${assetName} is running at ${data.percentage}%`);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
|
@ -8,7 +8,7 @@ type PointWithDegree = {
|
||||||
degree: number;
|
degree: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
function ArmAnimator({ armBot, ikSolver, setIkSolver, targetBone, restPosition, path }: any) {
|
function ArmAnimator({ armBot, ikSolver, setIkSolver, targetBone, restPosition, path, assetName, data }: any) {
|
||||||
const { scene } = useThree();
|
const { scene } = useThree();
|
||||||
const progressRef = useRef(0);
|
const progressRef = useRef(0);
|
||||||
const curveRef = useRef<THREE.Vector3[] | null>(null);
|
const curveRef = useRef<THREE.Vector3[] | null>(null);
|
||||||
|
@ -24,9 +24,13 @@ function ArmAnimator({ armBot, ikSolver, setIkSolver, targetBone, restPosition,
|
||||||
const { speed } = useAnimationPlaySpeed();
|
const { speed } = useAnimationPlaySpeed();
|
||||||
let duration = 5000
|
let duration = 5000
|
||||||
|
|
||||||
|
const [isRunning, setIsRunning] = useState(false);
|
||||||
|
const lastPercentageRef = useRef<number>(0);
|
||||||
|
const targetPercentageRef = useRef<number>(0);
|
||||||
|
const interpolationStartTimeRef = useRef<number>(performance.now());
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
||||||
console.log('path: ', path);
|
|
||||||
setCurrentPath(path);
|
setCurrentPath(path);
|
||||||
}, [path]);
|
}, [path]);
|
||||||
|
|
||||||
|
@ -183,22 +187,32 @@ function ArmAnimator({ armBot, ikSolver, setIkSolver, targetBone, restPosition,
|
||||||
|
|
||||||
// Frame update for animation
|
// Frame update for animation
|
||||||
useFrame((state, delta) => {
|
useFrame((state, delta) => {
|
||||||
|
|
||||||
|
if (!startTimeRef.current || !isRunning) return;
|
||||||
|
|
||||||
|
|
||||||
if (!ikSolver || !customCurvePoints || customCurvePoints.length === 0) return;
|
if (!ikSolver || !customCurvePoints || customCurvePoints.length === 0) return;
|
||||||
|
|
||||||
|
|
||||||
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 (!bone) return;
|
||||||
|
|
||||||
|
|
||||||
|
const now = performance.now();
|
||||||
|
const elapsed = now - interpolationStartTimeRef.current;
|
||||||
|
const duration = 2000;
|
||||||
|
const t = Math.min(elapsed / duration, 1);
|
||||||
|
const interpolatedPercentage =
|
||||||
|
lastPercentageRef.current +
|
||||||
|
(targetPercentageRef.current - lastPercentageRef.current) * t;
|
||||||
|
const progress = Math.min(interpolatedPercentage / 100, 1);
|
||||||
|
|
||||||
const distances = segmentDistancesRef.current;
|
const distances = segmentDistancesRef.current;
|
||||||
const totalDistance = totalDistanceRef.current;
|
const totalDistance = totalDistanceRef.current;
|
||||||
|
|
||||||
// Initialize start time
|
const coveredDistance = progress * totalDistance;
|
||||||
if (startTimeRef.current === null) {
|
// console.log('coveredDistance: ', coveredDistance);
|
||||||
startTimeRef.current = state.clock.elapsedTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
const elapsed = (state.clock.elapsedTime - startTimeRef.current) * 1000; // ms
|
|
||||||
const clampedProgress = Math.min(elapsed / duration, 1); // progress [0,1]
|
|
||||||
const coveredDistance = clampedProgress * totalDistance;
|
|
||||||
|
|
||||||
// Traverse segments to find current position
|
// Traverse segments to find current position
|
||||||
let index = 0;
|
let index = 0;
|
||||||
|
@ -215,6 +229,8 @@ function ArmAnimator({ armBot, ikSolver, setIkSolver, targetBone, restPosition,
|
||||||
const segmentDistance = distances[index];
|
const segmentDistance = distances[index];
|
||||||
const t = (coveredDistance - accumulatedDistance) / segmentDistance;
|
const t = (coveredDistance - accumulatedDistance) / segmentDistance;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (startPoint && endPoint) {
|
if (startPoint && endPoint) {
|
||||||
const position = startPoint.clone().lerp(endPoint, t);
|
const position = startPoint.clone().lerp(endPoint, t);
|
||||||
bone.position.copy(position);
|
bone.position.copy(position);
|
||||||
|
@ -224,7 +240,7 @@ function ArmAnimator({ armBot, ikSolver, setIkSolver, targetBone, restPosition,
|
||||||
ikSolver.update();
|
ikSolver.update();
|
||||||
|
|
||||||
// Reset at the end
|
// Reset at the end
|
||||||
if (clampedProgress >= 1) {
|
if (progress >= 1) {
|
||||||
setCurrentPath([]);
|
setCurrentPath([]);
|
||||||
setCustomCurvePoints([]);
|
setCustomCurvePoints([]);
|
||||||
curveRef.current = null;
|
curveRef.current = null;
|
||||||
|
@ -237,6 +253,25 @@ function ArmAnimator({ armBot, ikSolver, setIkSolver, targetBone, restPosition,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (data.assetName !== assetName) return;
|
||||||
|
if (data.state === 'running' && data.percentage !== undefined) {
|
||||||
|
console.log('data.percentage: ', data.percentage);
|
||||||
|
if (data.percentage === 0) {
|
||||||
|
startTimeRef.current = performance.now();
|
||||||
|
lastPercentageRef.current = 0;
|
||||||
|
targetPercentageRef.current = 0
|
||||||
|
} else {
|
||||||
|
lastPercentageRef.current = targetPercentageRef.current;
|
||||||
|
}
|
||||||
|
targetPercentageRef.current = data.percentage;
|
||||||
|
interpolationStartTimeRef.current = performance.now();
|
||||||
|
setIsRunning(true);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
setIsRunning(false);
|
||||||
|
}
|
||||||
|
}, [data, assetName]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<></>
|
<></>
|
||||||
|
|
|
@ -85,7 +85,7 @@ function ConveyorSimulation({ data, assetName, assetUUID }: ConveyorSimulationPr
|
||||||
|
|
||||||
materialRef.current.position.copy(currentPos);
|
materialRef.current.position.copy(currentPos);
|
||||||
materialRef.current.quaternion.copy(quaternionRef.current);
|
materialRef.current.quaternion.copy(quaternionRef.current);
|
||||||
console.log(` ${assetName} is running at ${data.percentage}%`);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Update movement state
|
// Update movement state
|
||||||
|
|
|
@ -71,7 +71,7 @@ function IIotIkSolver({ modelUrl, setIkSolver, ikSolver, armBot, groupRef }: IKI
|
||||||
|
|
||||||
setSelectedArm(OOI.Target_Bone);
|
setSelectedArm(OOI.Target_Bone);
|
||||||
|
|
||||||
scene.add(helper);
|
// scene.add(helper);
|
||||||
|
|
||||||
}, [cloned, gltf, setIkSolver]);
|
}, [cloned, gltf, setIkSolver]);
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@ function MachineSimulation({ data, assetName, assetUUID }: MachineSimulationProp
|
||||||
const percentage = percentageRef.current;
|
const percentage = percentageRef.current;
|
||||||
|
|
||||||
// 🟢 Use percentage in logic if needed
|
// 🟢 Use percentage in logic if needed
|
||||||
console.log(` ${assetName} is running at ${data.percentage}%`);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -14,12 +14,13 @@ const MqttListener: React.FC<MqttListenerProps> = ({ setData }) => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!client) return;
|
if (!client) return;
|
||||||
|
|
||||||
const topic = 'conveyor0001/0001/status';
|
const topic1 = 'conveyor0001/0001/status';
|
||||||
const topic2 = 'conveyor0002/0001/status';
|
const topic2 = 'conveyor0002/0001/status';
|
||||||
const topic3 = 'cnc0001/0001/status'
|
const topic3 = 'cnc0001/0001/status'
|
||||||
const topic4 = 'agv0001/0001/status'
|
const topic4 = 'agv0001/0001/status'
|
||||||
|
const topic5 = 'arm0001/0001/status'
|
||||||
|
|
||||||
client.subscribe(topic, {} as IClientSubscribeOptions, (err) => {
|
client.subscribe(topic1, {} as IClientSubscribeOptions, (err) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.error('Subscription error:', err);
|
console.error('Subscription error:', err);
|
||||||
}
|
}
|
||||||
|
@ -39,36 +40,58 @@ const MqttListener: React.FC<MqttListenerProps> = ({ setData }) => {
|
||||||
console.error('Subscription error:', err);
|
console.error('Subscription error:', err);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
client.subscribe(topic5, {} as IClientSubscribeOptions, (err) => {
|
||||||
|
if (err) {
|
||||||
|
console.error('Subscription error:', err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const handleMessage = (receivedTopic: string, payload: Buffer) => {
|
const handleMessage = (receivedTopic: string, payload: Buffer) => {
|
||||||
if (receivedTopic === topic) {
|
if (receivedTopic === topic1) {
|
||||||
const msgStr = payload.toString();
|
const msgStr = payload.toString();
|
||||||
setData(JSON.parse(msgStr))
|
let mqttData = JSON.parse(msgStr);
|
||||||
// setMessage(msgStr);
|
// if (mqttData.state === "running") {
|
||||||
|
setData(mqttData)
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
if (receivedTopic === topic2) {
|
if (receivedTopic === topic2) {
|
||||||
const msgStr = payload.toString();
|
const msgStr = payload.toString();
|
||||||
setData(JSON.parse(msgStr))
|
let mqttData = JSON.parse(msgStr);
|
||||||
// setMessage(msgStr);
|
// if (mqttData.state === "running") {
|
||||||
|
setData(mqttData)
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
if (receivedTopic === topic3) {
|
if (receivedTopic === topic3) {
|
||||||
const msgStr = payload.toString();
|
const msgStr = payload.toString();
|
||||||
setData(JSON.parse(msgStr))
|
let mqttData = JSON.parse(msgStr);
|
||||||
|
// if (mqttData.state === "running") {
|
||||||
// setMessage(msgStr);
|
setData(mqttData)
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
if (receivedTopic === topic4) {
|
if (receivedTopic === topic4) {
|
||||||
const msgStr = payload.toString();
|
const msgStr = payload.toString();
|
||||||
setData(JSON.parse(msgStr))
|
let mqttData = JSON.parse(msgStr);
|
||||||
|
// if (mqttData.state === "running") {
|
||||||
// setMessage(msgStr);
|
setData(mqttData)
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
if (receivedTopic === topic5) {
|
||||||
|
const msgStr = payload.toString();
|
||||||
|
let mqttData = JSON.parse(msgStr);
|
||||||
|
// if (mqttData.state === "running") {
|
||||||
|
setData(mqttData)
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
client.on('message', handleMessage);
|
client.on('message', handleMessage);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
client.off('message', handleMessage);
|
client.off('message', handleMessage);
|
||||||
client.unsubscribe(topic);
|
client.unsubscribe(topic1);
|
||||||
|
client.unsubscribe(topic2);
|
||||||
|
client.unsubscribe(topic3);
|
||||||
|
client.unsubscribe(topic4);
|
||||||
|
client.unsubscribe(topic5);
|
||||||
};
|
};
|
||||||
}, [client]);
|
}, [client]);
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ import ConveyorSimulation from './ConveyorSimulation';
|
||||||
import MachineSimulation from './MachineSimulation';
|
import MachineSimulation from './MachineSimulation';
|
||||||
import AgvSimulation from './AgvSimulation';
|
import AgvSimulation from './AgvSimulation';
|
||||||
import RoboticArmSimulation from './RoboticArmSimulation';
|
import RoboticArmSimulation from './RoboticArmSimulation';
|
||||||
|
import useModuleStore from '../../store/useModuleStore';
|
||||||
|
|
||||||
type MqttData = {
|
type MqttData = {
|
||||||
state?: string;
|
state?: string;
|
||||||
|
@ -17,8 +18,14 @@ type MqttData = {
|
||||||
|
|
||||||
function RealTimeSimulation() {
|
function RealTimeSimulation() {
|
||||||
const [data, setData] = useState<MqttData>({});
|
const [data, setData] = useState<MqttData>({});
|
||||||
|
const { activeModule } = useModuleStore();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (activeModule !== "visualization") return;
|
||||||
|
// console.log('data: ', data);
|
||||||
|
if (data.state === "running") {
|
||||||
|
console.log('data: ', data);
|
||||||
|
}
|
||||||
}, [data])
|
}, [data])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -27,7 +34,7 @@ function RealTimeSimulation() {
|
||||||
<ConveyorSimulation data={data} assetName="conveyor0002" assetUUID="1288e8f9-95dd-4a1a-a087-0673bbbc3b34" />
|
<ConveyorSimulation data={data} assetName="conveyor0002" assetUUID="1288e8f9-95dd-4a1a-a087-0673bbbc3b34" />
|
||||||
<MachineSimulation data={data} assetName="cnc0001" assetUUID="d3598136-40f6-43a9-afd2-8a8899c0986d" />
|
<MachineSimulation data={data} assetName="cnc0001" assetUUID="d3598136-40f6-43a9-afd2-8a8899c0986d" />
|
||||||
<AgvSimulation data={data} assetName="agv0001" assetUUID="1dd01c22-cc58-40cf-9e08-84c26f3f4eba" />
|
<AgvSimulation data={data} assetName="agv0001" assetUUID="1dd01c22-cc58-40cf-9e08-84c26f3f4eba" />
|
||||||
<RoboticArmSimulation data={data} assetName="roboticArm" assetUUID="f8344b0b-0c13-4e78-be1f-b6cc210038a4" />
|
<RoboticArmSimulation data={data} assetName="arm0001" assetUUID="f8344b0b-0c13-4e78-be1f-b6cc210038a4" />
|
||||||
<MqttListener setData={setData} />
|
<MqttListener setData={setData} />
|
||||||
|
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -6,6 +6,7 @@ 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 ArmAnimator from "./ArmAnimator";
|
||||||
import { useFloorItems } from "../../store/builder/store";
|
import { useFloorItems } from "../../store/builder/store";
|
||||||
|
import { MaterialModel } from "../simulation/materials/instances/material/materialModel";
|
||||||
|
|
||||||
type ArmBotSimulationProps = {
|
type ArmBotSimulationProps = {
|
||||||
data: any;
|
data: any;
|
||||||
|
@ -26,6 +27,13 @@ function RoboticArmSimulation({
|
||||||
const targetBone = "Target";
|
const targetBone = "Target";
|
||||||
const restPosition = new THREE.Vector3(0, 1.75, -1.6);
|
const restPosition = new THREE.Vector3(0, 1.75, -1.6);
|
||||||
const [path, setPath] = useState<[number, number, number][]>([]);
|
const [path, setPath] = useState<[number, number, number][]>([]);
|
||||||
|
const [isRunning, setIsRunning] = useState(false);
|
||||||
|
const startTimeRef = useRef<number | null>(null);
|
||||||
|
|
||||||
|
const lastPercentageRef = useRef<number>(0);
|
||||||
|
const targetPercentageRef = useRef<number>(0);
|
||||||
|
const interpolationStartTimeRef = useRef<number>(performance.now());
|
||||||
|
const materialRef = useRef<any>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (activeModule !== "visualization") return;
|
if (activeModule !== "visualization") return;
|
||||||
|
@ -43,44 +51,139 @@ function RoboticArmSimulation({
|
||||||
position: [RoboticArmObject.position.x, RoboticArmObject.position.y, RoboticArmObject.position.z,],
|
position: [RoboticArmObject.position.x, RoboticArmObject.position.y, RoboticArmObject.position.z,],
|
||||||
rotation: [RoboticArmObject.rotation.x, RoboticArmObject.rotation.y, RoboticArmObject.rotation.z,],
|
rotation: [RoboticArmObject.rotation.x, RoboticArmObject.rotation.y, RoboticArmObject.rotation.z,],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
setArmBot(updatedArmBot);
|
setArmBot(updatedArmBot);
|
||||||
}, [scene, assetUUID, activeModule]);
|
}, [scene, assetUUID, activeModule]);
|
||||||
|
|
||||||
|
const lastEventRef = useRef<string | null>(null);
|
||||||
|
const lastPathRef = useRef<string>(""); // Stringified path to compare
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (data.assetName !== assetName) return;
|
||||||
if (!ikSolver) return;
|
if (!ikSolver) return;
|
||||||
|
if (!isRunning) return;
|
||||||
|
|
||||||
const targetBones = ikSolver?.mesh.skeleton.bones.find((b: any) => b.name === targetBone);
|
const targetBones = ikSolver.mesh.skeleton.bones.find((b: any) => b.name === targetBone);
|
||||||
if (!targetBones) return;
|
if (!targetBones) return;
|
||||||
|
//action 1
|
||||||
|
const startPoint = new THREE.Vector3(-0.5119150023588372, 1.08653750252812, 1.2082537344869024);
|
||||||
|
const endPoint = new THREE.Vector3(-0.005966507840761359, 1.101367457937616, -1.242848820163239);
|
||||||
|
//action 2
|
||||||
|
const startPoint1 = new THREE.Vector3(-0.005966507840761359, 1.101367457937616, -1.242848820163239);
|
||||||
|
const endPoint1 = new THREE.Vector3(0.8449084618119792, 1.0275816535760263, 1.399557309225635);
|
||||||
|
|
||||||
const startPoint = new THREE.Vector3(-0.050142171738890684, 1.9, -1.999371341850562);
|
if (lastEventRef.current === data.event) return;
|
||||||
const endPoint = new THREE.Vector3(1.9999942666761656, 1.9, 0.004788868599774787);
|
if (data.event === 'pick1') {
|
||||||
|
console.log("picking");
|
||||||
|
const curve = createCurveBetweenTwoPoints(targetBones.position.clone(), startPoint.clone());
|
||||||
|
if (curve) {
|
||||||
|
setPath(curve.points.map(point => [point.x, point.y, point.z]));
|
||||||
|
}
|
||||||
|
lastEventRef.current = 'pick1';
|
||||||
|
}
|
||||||
|
|
||||||
const curve1 = createCurveBetweenTwoPoints(targetBones.position.clone(), restPosition.clone());
|
if (data.event === 'drop1') {
|
||||||
const curve2 = createCurveBetweenTwoPoints(restPosition.clone(), startPoint.clone());
|
console.log("dropping");
|
||||||
const curve3 = createCurveBetweenTwoPoints(startPoint.clone(), endPoint.clone());
|
const curve = createCurveBetweenTwoPoints(startPoint.clone(), endPoint.clone());
|
||||||
const curve4 = createCurveBetweenTwoPoints(endPoint.clone(), restPosition.clone());
|
if (curve) {
|
||||||
|
setPath(curve.points.map(point => [point.x, point.y, point.z]));
|
||||||
|
}
|
||||||
|
lastEventRef.current = 'drop1';
|
||||||
|
|
||||||
const curveList = [curve1, curve2, curve3, curve4];
|
}
|
||||||
|
if (data.event === 'pick2') {
|
||||||
|
console.log("picking111");
|
||||||
|
const curve = createCurveBetweenTwoPoints(targetBones.position.clone(), startPoint1.clone());
|
||||||
|
if (curve) {
|
||||||
|
setPath(curve.points.map(point => [point.x, point.y, point.z]));
|
||||||
|
}
|
||||||
|
lastEventRef.current = 'pick2';
|
||||||
|
|
||||||
let allPoints: [number, number, number][] = [];
|
}
|
||||||
|
if (data.event === 'drop2') {
|
||||||
|
console.log("dropping1111");
|
||||||
|
const curve = createCurveBetweenTwoPoints(startPoint1.clone(), endPoint1.clone());
|
||||||
|
if (curve) {
|
||||||
|
setPath(curve.points.map(point => [point.x, point.y, point.z]));
|
||||||
|
}
|
||||||
|
lastEventRef.current = 'drop2';
|
||||||
|
|
||||||
curveList.forEach((curve, index) => {
|
}
|
||||||
setTimeout(() => {
|
}, [ikSolver, data, assetName, isRunning]);
|
||||||
if (curve) {
|
|
||||||
setPath(curve.points.map(point => [point.x, point.y, point.z]));
|
|
||||||
}
|
|
||||||
}, index * 5000); // 2 seconds delay between each curve
|
|
||||||
});
|
|
||||||
}, [ikSolver]);
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (data.assetName !== assetName) return;
|
||||||
|
if (data.state === 'running' && data.percentage !== undefined) {
|
||||||
|
if (data.percentage === 0) {
|
||||||
|
lastPercentageRef.current = 0;
|
||||||
|
targetPercentageRef.current = 0
|
||||||
|
} else {
|
||||||
|
lastPercentageRef.current = targetPercentageRef.current;
|
||||||
|
}
|
||||||
|
targetPercentageRef.current = data.percentage;
|
||||||
|
interpolationStartTimeRef.current = performance.now();
|
||||||
|
setIsRunning(true);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
setIsRunning(false);
|
||||||
|
}
|
||||||
|
}, [data, assetName]);
|
||||||
|
|
||||||
function createCurveBetweenTwoPoints(p1: any, p2: any) {
|
function createCurveBetweenTwoPoints(p1: any, p2: any) {
|
||||||
const mid = new THREE.Vector3().addVectors(p1, p2).multiplyScalar(0.5);
|
const mid = new THREE.Vector3().addVectors(p1, p2).multiplyScalar(0.5);
|
||||||
const points = [p1, mid, p2];
|
const points = [p1, mid, p2];
|
||||||
return new THREE.CatmullRomCurve3(points);
|
return new THREE.CatmullRomCurve3(points);
|
||||||
}
|
}
|
||||||
|
useEffect(() => {
|
||||||
|
if (!ikSolver || !materialRef.current) return;
|
||||||
|
|
||||||
|
const boneTarget = ikSolver.mesh.skeleton.bones.find((b: any) => b.name === "Bone004");
|
||||||
|
const bone = ikSolver.mesh.skeleton.bones.find((b: any) => b.name === "Effector");
|
||||||
|
|
||||||
|
if (!boneTarget || !bone) return;
|
||||||
|
|
||||||
|
if (data.state === "running" && data.assetName === assetName) {
|
||||||
|
// Get world positions
|
||||||
|
const boneTargetWorldPos = new THREE.Vector3();
|
||||||
|
const boneWorldPos = new THREE.Vector3();
|
||||||
|
boneTarget.getWorldPosition(boneTargetWorldPos);
|
||||||
|
bone.getWorldPosition(boneWorldPos);
|
||||||
|
|
||||||
|
// Calculate direction
|
||||||
|
const direction = new THREE.Vector3();
|
||||||
|
direction.subVectors(boneWorldPos, boneTargetWorldPos).normalize();
|
||||||
|
|
||||||
|
const adjustedPosition = boneWorldPos.clone().addScaledVector(direction, 0.01);
|
||||||
|
|
||||||
|
//set position
|
||||||
|
materialRef.current.position.copy(adjustedPosition);
|
||||||
|
|
||||||
|
// Set rotation
|
||||||
|
const worldQuaternion = new THREE.Quaternion();
|
||||||
|
bone.getWorldQuaternion(worldQuaternion);
|
||||||
|
materialRef.current.quaternion.copy(worldQuaternion);
|
||||||
|
}
|
||||||
|
|
||||||
|
}, [data])
|
||||||
|
const [isVisible, setIsVisible] = useState(false);
|
||||||
|
useEffect(() => {
|
||||||
|
if (data.assetName !== assetName) return;
|
||||||
|
|
||||||
|
if (data.state === 'running' && typeof data.percentage === 'number') {
|
||||||
|
const shouldBeVisible = data.percentage <= 100;
|
||||||
|
// Only update visibility if it changes
|
||||||
|
setIsVisible(prev => {
|
||||||
|
if (prev !== shouldBeVisible) {
|
||||||
|
return shouldBeVisible;
|
||||||
|
}
|
||||||
|
return prev;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setIsVisible(false);
|
||||||
|
}
|
||||||
|
}, [data, assetName]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{activeModule === "visualization" && armBot && (
|
{activeModule === "visualization" && armBot && (
|
||||||
|
@ -99,7 +202,15 @@ function RoboticArmSimulation({
|
||||||
restPosition={restPosition}
|
restPosition={restPosition}
|
||||||
targetBone={targetBone}
|
targetBone={targetBone}
|
||||||
path={path}
|
path={path}
|
||||||
|
assetName={assetName}
|
||||||
|
data={data}
|
||||||
/>
|
/>
|
||||||
|
{/* <MaterialModel
|
||||||
|
materialId={`${assetName}-mat`}
|
||||||
|
matRef={materialRef}
|
||||||
|
materialType={'Default material'}
|
||||||
|
visible={isVisible}
|
||||||
|
/> */}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|
Loading…
Reference in New Issue