arm points constraints defined and armbot movements bug cleared

This commit is contained in:
Gomathi 2025-05-03 19:11:24 +05:30
parent 4fc014cd28
commit 0b69494465
7 changed files with 189 additions and 132 deletions

View File

@ -844,7 +844,7 @@ export const LogTickIcon = () => {
fill="none" fill="none"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
> >
<g clip-path="url(#clip0_3962_4223)"> <g clipPath="url(#clip0_3962_4223)">
<path <path
d="M5.00065 0.835938C2.70482 0.835938 0.833984 2.70677 0.833984 5.0026C0.833984 7.29844 2.70482 9.16927 5.00065 9.16927C7.29648 9.16927 9.16732 7.29844 9.16732 5.0026C9.16732 2.70677 7.29648 0.835938 5.00065 0.835938ZM6.99232 4.04427L4.62982 6.40677C4.57148 6.4651 4.49232 6.49844 4.40898 6.49844C4.32565 6.49844 4.24648 6.4651 4.18815 6.40677L3.00898 5.2276C2.88815 5.10677 2.88815 4.90677 3.00898 4.78594C3.12982 4.6651 3.32982 4.6651 3.45065 4.78594L4.40898 5.74427L6.55065 3.6026C6.67148 3.48177 6.87148 3.48177 6.99232 3.6026C7.11315 3.72344 7.11315 3.91927 6.99232 4.04427Z" d="M5.00065 0.835938C2.70482 0.835938 0.833984 2.70677 0.833984 5.0026C0.833984 7.29844 2.70482 9.16927 5.00065 9.16927C7.29648 9.16927 9.16732 7.29844 9.16732 5.0026C9.16732 2.70677 7.29648 0.835938 5.00065 0.835938ZM6.99232 4.04427L4.62982 6.40677C4.57148 6.4651 4.49232 6.49844 4.40898 6.49844C4.32565 6.49844 4.24648 6.4651 4.18815 6.40677L3.00898 5.2276C2.88815 5.10677 2.88815 4.90677 3.00898 4.78594C3.12982 4.6651 3.32982 4.6651 3.45065 4.78594L4.40898 5.74427L6.55065 3.6026C6.67148 3.48177 6.87148 3.48177 6.99232 3.6026C7.11315 3.72344 7.11315 3.91927 6.99232 4.04427Z"
fill="#49B841" fill="#49B841"

View File

@ -68,7 +68,7 @@ export function PowerIcon() {
fill="none" fill="none"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
> >
<g clip-path="url(#clip0_4107_3144)"> <g clipPath="url(#clip0_4107_3144)">
<path <path
d="M12.1277 1.76564L10.7174 9.17535L15.8265 9.19254L8.87213 19.2375L10.2824 11.0856L5.17369 11.0678L12.1277 1.76564ZM12.1287 0.515664C12.0949 0.515664 12.0612 0.516895 12.0281 0.519375C11.8075 0.537207 11.6612 0.610957 11.4878 0.72752C11.3901 0.792624 11.3021 0.871096 11.2262 0.960645C11.2034 0.987526 11.1819 1.01547 11.1618 1.04439L4.15775 10.3141C3.88119 10.6931 3.84056 11.1935 4.05306 11.6116C4.26525 12.0297 4.69431 12.2947 5.16463 12.2982L8.77275 12.3244L7.63838 19.0079C7.53056 19.5822 7.83681 20.1547 8.37588 20.3854C8.53254 20.4527 8.70128 20.4873 8.87179 20.4872C9.26461 20.4872 9.58742 20.3035 9.82963 19.9716L16.8424 9.92658C17.119 9.5475 17.1593 9.04656 16.9471 8.62906C16.7349 8.21094 16.3059 7.94592 15.8356 7.9425L12.2274 7.93625L13.3496 2.05969C13.3734 1.96348 13.3854 1.86473 13.3853 1.76562C13.3853 1.08938 12.8468 0.538125 12.1731 0.51625C12.1581 0.515625 12.1434 0.515625 12.1287 0.515625L12.1287 0.515664Z" d="M12.1277 1.76564L10.7174 9.17535L15.8265 9.19254L8.87213 19.2375L10.2824 11.0856L5.17369 11.0678L12.1277 1.76564ZM12.1287 0.515664C12.0949 0.515664 12.0612 0.516895 12.0281 0.519375C11.8075 0.537207 11.6612 0.610957 11.4878 0.72752C11.3901 0.792624 11.3021 0.871096 11.2262 0.960645C11.2034 0.987526 11.1819 1.01547 11.1618 1.04439L4.15775 10.3141C3.88119 10.6931 3.84056 11.1935 4.05306 11.6116C4.26525 12.0297 4.69431 12.2947 5.16463 12.2982L8.77275 12.3244L7.63838 19.0079C7.53056 19.5822 7.83681 20.1547 8.37588 20.3854C8.53254 20.4527 8.70128 20.4873 8.87179 20.4872C9.26461 20.4872 9.58742 20.3035 9.82963 19.9716L16.8424 9.92658C17.119 9.5475 17.1593 9.04656 16.9471 8.62906C16.7349 8.21094 16.3059 7.94592 15.8356 7.9425L12.2274 7.93625L13.3496 2.05969C13.3734 1.96348 13.3854 1.86473 13.3853 1.76562C13.3853 1.08938 12.8468 0.538125 12.1731 0.51625C12.1581 0.515625 12.1434 0.515625 12.1287 0.515625L12.1287 0.515664Z"
fill="#F3C64D" fill="#F3C64D"

View File

@ -23,11 +23,14 @@ function RoboticArmAnimator({
const [currentPath, setCurrentPath] = useState<[number, number, number][]>([]); const [currentPath, setCurrentPath] = useState<[number, number, number][]>([]);
const [circlePoints, setCirclePoints] = useState<[number, number, number][]>([]); const [circlePoints, setCirclePoints] = useState<[number, number, number][]>([]);
const [customCurvePoints, setCustomCurvePoints] = useState<THREE.Vector3[] | null>(null); const [customCurvePoints, setCustomCurvePoints] = useState<THREE.Vector3[] | null>(null);
let curveHeight = 1.75
const totalDistanceRef = useRef(0);
const startTimeRef = useRef<number | null>(null);
const segmentDistancesRef = useRef<number[]>([]);
// Zustand stores // Zustand stores
const { isPlaying } = usePlayButtonStore(); const { isPlaying } = usePlayButtonStore();
const { isPaused } = usePauseButtonStore(); const { isPaused } = usePauseButtonStore();
const { isReset } = useResetButtonStore(); const { isReset, setReset } = useResetButtonStore();
const { speed } = useAnimationPlaySpeed(); const { speed } = useAnimationPlaySpeed();
// Update path state whenever `path` prop changes // Update path state whenever `path` prop changes
@ -35,20 +38,25 @@ function RoboticArmAnimator({
setCurrentPath(path); setCurrentPath(path);
}, [path]); }, [path]);
// Reset logic when `isPlaying` changes
useEffect(() => {
if (!isPlaying) {
setCurrentPath([]);
curveRef.current = null;
}
}, [isPlaying]);
// Handle circle points based on armBot position // Handle circle points based on armBot position
useEffect(() => { useEffect(() => {
const points = generateRingPoints(1.6, 64) const points = generateRingPoints(1.6, 64)
setCirclePoints(points); setCirclePoints(points);
}, [armBot.position]); }, [armBot.position]);
useEffect(() => {
if (isReset || !isPlaying) {
progressRef.current = 0;
curveRef.current = null;
setCurrentPath([]);
setCustomCurvePoints(null);
totalDistanceRef.current = 0;
startTimeRef.current = null;
segmentDistancesRef.current = [];
setReset(false);
}
}, [isReset, isPlaying])
function generateRingPoints(radius: any, segments: any) { function generateRingPoints(radius: any, segments: any) {
const points: [number, number, number][] = []; const points: [number, number, number][] = [];
@ -77,10 +85,10 @@ function RoboticArmAnimator({
return -1; // Not found return -1; // Not found
}; };
// 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) {
const start = currentPath[0]; const start = currentPath[0];
const end = currentPath[currentPath.length - 1]; const end = currentPath[currentPath.length - 1];
@ -89,43 +97,28 @@ function RoboticArmAnimator({
const findNearest = (target: [number, number, number]) => { const findNearest = (target: [number, number, number]) => {
return circlePoints.reduce((nearest, point) => { return circlePoints.reduce((nearest, point) => {
const distance = Math.hypot( const distance = Math.hypot(target[0] - point[0], target[1] - point[1], target[2] - point[2]);
target[0] - point[0], const nearestDistance = Math.hypot(target[0] - nearest[0], target[1] - nearest[1], target[2] - nearest[2]);
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; return distance < nearestDistance ? point : nearest;
}, circlePoints[0]); }, circlePoints[0]);
}; };
const nearestToStart = findNearest(raisedStart); const nearestToStart = findNearest(raisedStart);
const nearestToEnd = findNearest(raisedEnd); const nearestToEnd = findNearest(raisedEnd);
const indexOfNearestStart = findNearestIndex(nearestToStart, circlePoints); const indexOfNearestStart = findNearestIndex(nearestToStart, circlePoints);
const indexOfNearestEnd = findNearestIndex(nearestToEnd, circlePoints); const indexOfNearestEnd = findNearestIndex(nearestToEnd, circlePoints);
// Find clockwise and counter-clockwise distances
const clockwiseDistance = (indexOfNearestEnd - indexOfNearestStart + 64) % 64; const clockwiseDistance = (indexOfNearestEnd - indexOfNearestStart + 64) % 64;
const counterClockwiseDistance = (indexOfNearestStart - indexOfNearestEnd + 64) % 64; const counterClockwiseDistance = (indexOfNearestStart - indexOfNearestEnd + 64) % 64;
const clockwiseIsShorter = clockwiseDistance <= counterClockwiseDistance; const clockwiseIsShorter = clockwiseDistance <= counterClockwiseDistance;
// Collect arc points between start and end
let arcPoints: [number, number, number][] = []; let arcPoints: [number, number, number][] = [];
if (clockwiseIsShorter) { if (clockwiseIsShorter) {
if (indexOfNearestStart <= indexOfNearestEnd) { if (indexOfNearestStart <= indexOfNearestEnd) {
arcPoints = circlePoints.slice(indexOfNearestStart, indexOfNearestEnd + 1); arcPoints = circlePoints.slice(indexOfNearestStart, indexOfNearestEnd + 1);
} else { } else {
// Wrap around
arcPoints = [ arcPoints = [
...circlePoints.slice(indexOfNearestStart, 64), ...circlePoints.slice(indexOfNearestStart, 64),
...circlePoints.slice(0, indexOfNearestEnd + 1) ...circlePoints.slice(0, indexOfNearestEnd + 1)
@ -143,63 +136,92 @@ function RoboticArmAnimator({
} }
} }
// Continue your custom path logic
const pathVectors = [ const pathVectors = [
new THREE.Vector3(start[0], start[1], start[2]), // start new THREE.Vector3(start[0], start[1], start[2]),
new THREE.Vector3(raisedStart[0], raisedStart[1], raisedStart[2]), // lift up new THREE.Vector3(start[0], curveHeight, start[2]),
new THREE.Vector3(nearestToStart[0], raisedStart[1], nearestToStart[2]), // move to arc start new THREE.Vector3(nearestToStart[0], curveHeight, nearestToStart[2]),
...arcPoints.map(point => new THREE.Vector3(point[0], raisedStart[1], point[2])), ...arcPoints.map(point => new THREE.Vector3(point[0], curveHeight, point[2])),
new THREE.Vector3(nearestToEnd[0], raisedEnd[1], nearestToEnd[2]), // move from arc end new THREE.Vector3(nearestToEnd[0], curveHeight, nearestToEnd[2]),
new THREE.Vector3(raisedEnd[0], raisedEnd[1], raisedEnd[2]), // lowered end new THREE.Vector3(end[0], curveHeight, end[2]),
new THREE.Vector3(end[0], end[1], end[2]) // end new THREE.Vector3(end[0], end[1], end[2])
]; ];
const customCurve = new THREE.CatmullRomCurve3(pathVectors, false, 'centripetal', 1);
const generatedPoints = customCurve.getPoints(100); const pathSegments: [THREE.Vector3, THREE.Vector3][] = [];
setCustomCurvePoints(generatedPoints);
for (let i = 0; i < pathVectors.length - 1; i++) {
pathSegments.push([pathVectors[i], pathVectors[i + 1]]);
}
const segmentDistances = pathSegments.map(([p1, p2]) => p1.distanceTo(p2));
segmentDistancesRef.current = segmentDistances;
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]); }, [circlePoints, currentPath]);
// Frame update for animation // Frame update for animation
useFrame((_, delta) => { useFrame((state, delta) => {
if (!ikSolver) return; if (!ikSolver) 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;
if (isPlaying) { if (isPlaying) {
if (!isPaused && customCurvePoints && currentPath.length > 0) { if (!isPaused && customCurvePoints && customCurvePoints.length > 0) {
const curvePoints = customCurvePoints; const distances = segmentDistancesRef.current; // distances between each pair of points
const speedAdjustedProgress = progressRef.current + (speed * armBot.speed); const totalDistance = totalDistanceRef.current;
const index = Math.floor(speedAdjustedProgress);
if (index >= curvePoints.length) { progressRef.current += delta * (speed * armBot.speed);
// Reached the end of the curve const coveredDistance = progressRef.current;
let index = 0;
let accumulatedDistance = 0;
// Find which segment we are currently in
while (index < distances.length && coveredDistance > accumulatedDistance + distances[index]) {
accumulatedDistance += distances[index];
index++;
}
if (index < distances.length) {
const startPoint = customCurvePoints[index];
const endPoint = customCurvePoints[index + 1];
const segmentDistance = distances[index];
const t = (coveredDistance - accumulatedDistance) / segmentDistance;
if (startPoint && endPoint) {
const position = startPoint.clone().lerp(endPoint, t);
bone.position.copy(position);
}
}
if (progressRef.current >= totalDistance) {
HandleCallback(); HandleCallback();
setCurrentPath([]); setCurrentPath([]);
setCustomCurvePoints([]);
curveRef.current = null; curveRef.current = null;
progressRef.current = 0; progressRef.current = 0;
} else { startTimeRef.current = null;
const point = curvePoints[index];
bone.position.copy(point);
progressRef.current = speedAdjustedProgress;
} }
} else if (isPaused) {
logStatus(armBot.modelUuid, 'Simulation Paused');
}
ikSolver.update(); ikSolver.update();
} else if (!isPlaying && currentPath.length === 0) { }
// Not playing anymore, reset to rest } else if ((!isPlaying && currentPath.length === 0) || isReset) {
bone.position.copy(restPosition); bone.position.copy(restPosition);
ikSolver.update(); ikSolver.update();
} }
});
});
return ( return (
<> <>
{customCurvePoints && currentPath && isPlaying && ( {customCurvePoints && customCurvePoints?.length >= 2 && currentPath && isPlaying && (
<mesh rotation={armBot.rotation} position={armBot.position}> <mesh rotation={armBot.rotation} position={armBot.position}>
<Line <Line
points={customCurvePoints.map((p) => [p.x, p.y, p.z] as [number, number, number])} points={customCurvePoints.map((p) => [p.x, p.y, p.z] as [number, number, number])}

View File

@ -51,13 +51,12 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
pauseTimeRef.current = null; pauseTimeRef.current = null;
} }
const elapsedTime = performance.now() - startTime; const elapsedTime = performance.now() - startTime;
if (elapsedTime < 1500) { if (elapsedTime < 1000) {
// Wait until 1500ms has passed // Wait until 1500ms has passed
requestAnimationFrame(step); requestAnimationFrame(step);
return; return;
} }
if (currentPhase === "picking") { if (currentPhase === "picking") {
setArmBotActive(armBot.modelUuid, true); setArmBotActive(armBot.modelUuid, true);
setArmBotState(armBot.modelUuid, "running"); setArmBotState(armBot.modelUuid, "running");
setCurrentPhase("start-to-end"); setCurrentPhase("start-to-end");
@ -75,7 +74,6 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
} }
logStatus(armBot.modelUuid, "Moving armBot from start point to end position.") logStatus(armBot.modelUuid, "Moving armBot from start point to end position.")
} else if (currentPhase === "dropping") { } else if (currentPhase === "dropping") {
setArmBotActive(armBot.modelUuid, true); setArmBotActive(armBot.modelUuid, true);
setArmBotState(armBot.modelUuid, "running"); setArmBotState(armBot.modelUuid, "running");
setCurrentPhase("end-to-rest"); setCurrentPhase("end-to-rest");
@ -91,35 +89,26 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
} }
logStatus(armBot.modelUuid, "Moving armBot from end point to rest position.") logStatus(armBot.modelUuid, "Moving armBot from end point to rest position.")
} }
} }
useEffect(() => { useEffect(() => {
isPausedRef.current = isPaused; isPausedRef.current = isPaused;
}, [isPaused]); }, [isPaused]);
useEffect(() => { useEffect(() => {
const targetMesh = scene?.getObjectByProperty("uuid", armBot.modelUuid); if (isReset || !isPlaying) {
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") logStatus(armBot.modelUuid, "Simulation Play Reset Successfully")
removeCurrentAction(armBot.modelUuid) removeCurrentAction(armBot.modelUuid)
setArmBotActive(armBot.modelUuid, true) setArmBotActive(armBot.modelUuid, false)
setArmBotState(armBot.modelUuid, "running") setArmBotState(armBot.modelUuid, "idle")
setCurrentPhase("init-to-rest"); setCurrentPhase("init");
isPausedRef.current = false isPausedRef.current = false
pauseTimeRef.current = null pauseTimeRef.current = null
isPausedRef.current = false
startTime = 0 startTime = 0
const targetBones = ikSolver?.mesh.skeleton.bones.find(
(b: any) => b.name === targetBone
);
if (targetBones) { if (targetBones) {
let curve = createCurveBetweenTwoPoints(targetBones.position, targetBones.position) let curve = createCurveBetweenTwoPoints(targetBones.position, restPosition)
if (curve) { if (curve) {
setPath(curve.points.map(point => [point.x, point.y, point.z])); setPath(curve.points.map(point => [point.x, point.y, point.z]));
} }
@ -127,6 +116,16 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
setReset(false); setReset(false);
logStatus(armBot.modelUuid, "Moving armBot from initial point to rest position.") logStatus(armBot.modelUuid, "Moving armBot from initial point to rest position.")
} }
}, [isReset, isPlaying])
useEffect(() => {
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 (isPlaying) { if (isPlaying) {
//Moving armBot from initial point to rest position. //Moving armBot from initial point to rest position.
@ -136,7 +135,7 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
setArmBotState(armBot.modelUuid, "running") setArmBotState(armBot.modelUuid, "running")
setCurrentPhase("init-to-rest"); setCurrentPhase("init-to-rest");
if (targetBones) { if (targetBones) {
let curve = createCurveBetweenTwoPoints(targetBones.position, restPosition) let curve = createCurveBetweenTwoPoints(targetBones.position, targetBones.position)
if (curve) { if (curve) {
setPath(curve.points.map(point => [point.x, point.y, point.z])); setPath(curve.points.map(point => [point.x, point.y, point.z]));
} }
@ -147,8 +146,7 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
else if (armBot && !armBot.isActive && armBot.state === "idle" && currentPhase === "rest" && !armBot.currentAction) { else if (armBot && !armBot.isActive && armBot.state === "idle" && currentPhase === "rest" && !armBot.currentAction) {
logStatus(armBot.modelUuid, "Waiting to trigger CurrentAction") logStatus(armBot.modelUuid, "Waiting to trigger CurrentAction")
const timeoutId = setTimeout(() => { const timeoutId = setTimeout(() => {
addCurrentAction(armBot.modelUuid, selectedAction?.actionId); addCurrentAction(armBot.modelUuid, armBot.point.actions[0].actionUuid);
console.log('selectedAction?.actionId: ', selectedAction?.actionId);
}, 3000); }, 3000);
return () => clearTimeout(timeoutId); return () => clearTimeout(timeoutId);
} }
@ -158,11 +156,9 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
setArmBotActive(armBot.modelUuid, true); setArmBotActive(armBot.modelUuid, true);
setArmBotState(armBot.modelUuid, "running"); setArmBotState(armBot.modelUuid, "running");
setCurrentPhase("rest-to-start"); setCurrentPhase("rest-to-start");
let actiondata = getActionByUuid(selectedProduct.productId, selectedAction.actionId)
console.log('actiondata: ', actiondata);
const startPoint = armBot.point.actions[0].process.startPoint; const startPoint = armBot.point.actions[0].process.startPoint;
if (startPoint) { if (startPoint) {
let curve = createCurveBetweenTwoPoints(restPosition, new THREE.Vector3(startPoint[0], startPoint[1], startPoint[2])); let curve = createCurveBetweenTwoPoints(targetBones.position, new THREE.Vector3(startPoint[0], startPoint[1], startPoint[2]));
if (curve) { if (curve) {
setPath(curve.points.map(point => [point.x, point.y, point.z])); setPath(curve.points.map(point => [point.x, point.y, point.z]));
} }
@ -208,16 +204,19 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
// logStatus(armBot.modelUuid, "Moving armBot from end point to rest position.") // logStatus(armBot.modelUuid, "Moving armBot from end point to rest position.")
} }
} else { } else {
logStatus(armBot.modelUuid, "Simulation Play Stopped") logStatus(armBot.modelUuid, "Simulation Play Exited")
setArmBotActive(armBot.modelUuid, false) setArmBotActive(armBot.modelUuid, false)
setArmBotState(armBot.modelUuid, "idle") setArmBotState(armBot.modelUuid, "idle")
setCurrentPhase("init"); setCurrentPhase("init");
setPath([]) setPath([])
isPausedRef.current = false
pauseTimeRef.current = null
isPausedRef.current = false
startTime = 0
removeCurrentAction(armBot.modelUuid) removeCurrentAction(armBot.modelUuid)
} }
}, [currentPhase, armBot, isPlaying, ikSolver, isReset]) }, [currentPhase, armBot, isPlaying, ikSolver])
function createCurveBetweenTwoPoints(p1: any, p2: any) { function createCurveBetweenTwoPoints(p1: any, p2: any) {
@ -260,6 +259,7 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
} }
} }
const logStatus = (id: string, status: string) => { const logStatus = (id: string, status: string) => {
// //
} }

View File

@ -71,7 +71,7 @@ function IKInstance({ modelUrl, setIkSolver, ikSolver, armBot, groupRef }: IKIns
setSelectedArm(OOI.Target_Bone); setSelectedArm(OOI.Target_Bone);
// scene.add(helper); scene.add(helper);
}, [gltf]); }, [gltf]);

View File

@ -23,7 +23,7 @@ function Simulation() {
}, [events]) }, [events])
useEffect(() => { useEffect(() => {
console.log('products: ', products); // console.log('products: ', products);
}, [products]) }, [products])
return ( return (

View File

@ -1,10 +1,19 @@
import { useRef, useState } from "react"; import { useRef, useState } from "react";
import * as THREE from "three"; import * as THREE from "three";
import { ThreeEvent, useThree } from "@react-three/fiber"; import { ThreeEvent, useThree } from "@react-three/fiber";
import { useProductStore } from "../../../../store/simulation/useProductStore";
import {
useSelectedEventData,
useSelectedProduct,
} from "../../../../store/simulation/useSimulationStore";
type OnUpdateCallback = (object: THREE.Object3D) => void; type OnUpdateCallback = (object: THREE.Object3D) => void;
export default function useDraggableGLTF(onUpdate: OnUpdateCallback) { export default function useDraggableGLTF(onUpdate: OnUpdateCallback) {
const { getEventByModelUuid, updateAction, getActionByUuid } =
useProductStore();
const { selectedEventData } = useSelectedEventData();
const { selectedProduct } = useSelectedProduct();
const { camera, gl, controls } = useThree(); const { camera, gl, controls } = useThree();
const activeObjRef = useRef<THREE.Object3D | null>(null); const activeObjRef = useRef<THREE.Object3D | null>(null);
const planeRef = useRef<THREE.Plane>( const planeRef = useRef<THREE.Plane>(
@ -34,7 +43,6 @@ export default function useDraggableGLTF(onUpdate: OnUpdateCallback) {
activeObjRef.current = obj; activeObjRef.current = obj;
initialPositionRef.current.copy(obj.position); initialPositionRef.current.copy(obj.position);
// Get world position // Get world position
setObjectWorldPos(obj.getWorldPosition(objectWorldPos)); setObjectWorldPos(obj.getWorldPosition(objectWorldPos));
@ -62,57 +70,84 @@ export default function useDraggableGLTF(onUpdate: OnUpdateCallback) {
const handlePointerMove = (e: PointerEvent) => { const handlePointerMove = (e: PointerEvent) => {
if (!activeObjRef.current) return; if (!activeObjRef.current) return;
if (selectedEventData?.data.type === "roboticArm") {
const selectedArmBot = getEventByModelUuid(
selectedProduct.productId,
selectedEventData.data.modelUuid
);
if (!selectedArmBot) return;
// Check if Shift key is pressed
const isShiftKeyPressed = e.shiftKey;
// Check if Shift key is pressed // Get the mouse position relative to the canvas
const isShiftKeyPressed = e.shiftKey; 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;
// Get the mouse position relative to the canvas // Update raycaster to point to the mouse position
const rect = gl.domElement.getBoundingClientRect(); raycaster.setFromCamera(pointer, camera);
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 // Create a vector to store intersection point
raycaster.setFromCamera(pointer, camera); const intersection = new THREE.Vector3();
const intersects = raycaster.ray.intersectPlane(
planeRef.current,
intersection
);
if (!intersects) return;
// Create a vector to store intersection point // Add offset for dragging
const intersection = new THREE.Vector3(); intersection.add(offsetRef.current);
const intersects = raycaster.ray.intersectPlane(
planeRef.current,
intersection
);
if (!intersects) return;
// Add offset for dragging // Get the parent's world matrix if exists
intersection.add(offsetRef.current); const parent = activeObjRef.current.parent;
const targetPosition = new THREE.Vector3();
// Get the parent's world matrix if exists // OnPointerDown
const parent = activeObjRef.current.parent; initialPositionRef.current.copy(objectWorldPos);
const targetPosition = new THREE.Vector3();
// OnPointerDown // OnPointerMove
initialPositionRef.current.copy(objectWorldPos); if (isShiftKeyPressed) {
const { x: initialX, y: initialY } = initialPositionRef.current;
const { x: objectX, z: objectZ } = objectWorldPos;
// OnPointerMove const deltaX = intersection.x - initialX;
if (isShiftKeyPressed) {
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);
}
targetPosition.set(objectX, initialY + deltaX, objectZ); // CONSTRAIN MOVEMENT HERE:
} else { const centerX = selectedArmBot.position[0];
// For free movement const centerZ = selectedArmBot.position[2];
targetPosition.copy(intersection); const minDistance = 1.2; // 1.4 radius
const maxDistance = 2; // 2 radius
const deltaX = targetPosition.x - centerX;
const deltaZ = targetPosition.z - centerZ;
const distance = Math.sqrt(deltaX * deltaX + deltaZ * deltaZ);
if (distance < minDistance || distance > maxDistance) {
const angle = Math.atan2(deltaZ, deltaX);
const clampedDistance = Math.min(
Math.max(distance, minDistance),
maxDistance
);
targetPosition.x = centerX + Math.cos(angle) * clampedDistance;
targetPosition.z = centerZ + Math.sin(angle) * clampedDistance;
}
targetPosition.y = Math.min(Math.max(targetPosition.y, 0.6), 1.5);
// 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);
} }
// 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);
}; };
const handlePointerUp = () => { const handlePointerUp = () => {