arm points constraints defined and armbot movements bug cleared
This commit is contained in:
parent
4fc014cd28
commit
0b69494465
|
@ -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"
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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])}
|
||||||
|
|
|
@ -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) => {
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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]);
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ function Simulation() {
|
||||||
}, [events])
|
}, [events])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log('products: ', products);
|
// console.log('products: ', products);
|
||||||
}, [products])
|
}, [products])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -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 = () => {
|
||||||
|
|
Loading…
Reference in New Issue