solved a bug based on generating point based on zustand
This commit is contained in:
@@ -0,0 +1,436 @@
|
||||
import { useFrame, useThree } from "@react-three/fiber";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { Quaternion, Vector3 } from "three";
|
||||
import {
|
||||
useAnimationPlaySpeed,
|
||||
usePlayButtonStore,
|
||||
} from "../../../../../store/usePlayButtonStore";
|
||||
import { usePathManager } from "../../pathCreator/function/usePathManager";
|
||||
|
||||
interface VehicleAnimatorProps {
|
||||
vehiclesData: VehicleStructure[];
|
||||
}
|
||||
type ManagerData = {
|
||||
pathId: string;
|
||||
vehicleId: string;
|
||||
};
|
||||
export default function VehicleAnimator2({
|
||||
vehiclesData,
|
||||
}: VehicleAnimatorProps) {
|
||||
const [managerData, setManagerData] = useState<ManagerData>();
|
||||
const { scene } = useThree();
|
||||
const { speed } = useAnimationPlaySpeed();
|
||||
const { isPlaying } = usePlayButtonStore();
|
||||
const vehicleMovementState = useRef<
|
||||
Record<
|
||||
string,
|
||||
{
|
||||
index: number;
|
||||
progress: number;
|
||||
hasStarted: boolean;
|
||||
pathIndex: number;
|
||||
pointIndex: number;
|
||||
}
|
||||
>
|
||||
>({});
|
||||
const managerRef = useRef<ManagerData>();
|
||||
// const manager = usePathManager(managerData?.pathId, managerData?.vehicleId);
|
||||
|
||||
// useFrame((_, delta) => {
|
||||
// if (!isPlaying) return;
|
||||
|
||||
// vehiclesData.forEach((vehicle) => {
|
||||
// const { vehicleId, route } = vehicle;
|
||||
|
||||
// if (
|
||||
// !route ||
|
||||
// route.length === 0 ||
|
||||
// !route[0].pathPoints ||
|
||||
// route[0].pathPoints.length < 2
|
||||
// ) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// const mesh = scene.getObjectByProperty("uuid", vehicleId); // or getObjectByName
|
||||
// if (!mesh) return;
|
||||
// const currentPath = route[0];
|
||||
// const pathPoints = currentPath.pathPoints;
|
||||
// const currentPathId = currentPath.pathId;
|
||||
|
||||
// // ✅ Call your function here
|
||||
// setManagerData({ pathId: currentPathId, vehicleId: vehicleId });
|
||||
// const pathStart = new Vector3(...pathPoints[0].position);
|
||||
// const uuid = vehicleId;
|
||||
|
||||
// // Initialize movement state
|
||||
// if (!vehicleMovementState.current[uuid]) {
|
||||
// vehicleMovementState.current[uuid] = {
|
||||
// index: 0,
|
||||
// progress: 0,
|
||||
// hasStarted: false,
|
||||
// };
|
||||
// }
|
||||
|
||||
// const state = vehicleMovementState.current[uuid];
|
||||
|
||||
// // ✳️ Step 1: Move to start point first
|
||||
// if (!state.hasStarted) {
|
||||
// const distanceToStart = mesh.position.distanceTo(pathStart);
|
||||
// const step = speed * delta;
|
||||
|
||||
// if (distanceToStart <= step) {
|
||||
// mesh.position.copy(pathStart);
|
||||
// mesh.quaternion.identity();
|
||||
// state.hasStarted = true;
|
||||
// return;
|
||||
// }
|
||||
|
||||
// const direction = pathStart.clone().sub(mesh.position);
|
||||
// const distance = direction.length();
|
||||
|
||||
// if (distance > step) {
|
||||
// direction.normalize();
|
||||
// mesh.position.add(direction.clone().multiplyScalar(step));
|
||||
|
||||
// const forward = new Vector3(0, 0, 1);
|
||||
// const targetQuat = new Quaternion().setFromUnitVectors(
|
||||
// forward,
|
||||
// direction
|
||||
// );
|
||||
// mesh.quaternion.slerp(targetQuat, 0.1);
|
||||
// } else {
|
||||
// mesh.position.copy(pathStart);
|
||||
// mesh.quaternion.identity();
|
||||
// state.hasStarted = true;
|
||||
// state.index = 0;
|
||||
// state.progress = 0;
|
||||
// }
|
||||
|
||||
// return;
|
||||
// }
|
||||
|
||||
// // ✳️ Step 2: Move along the route
|
||||
// const currentPoint = new Vector3(...pathPoints[state.index].position);
|
||||
// const nextPoint = new Vector3(...pathPoints[state.index + 1].position);
|
||||
|
||||
// const segmentVector = new Vector3().subVectors(nextPoint, currentPoint);
|
||||
// const segmentLength = segmentVector.length();
|
||||
// const direction = segmentVector.clone().normalize();
|
||||
|
||||
// const moveDistance = speed * delta;
|
||||
// state.progress += moveDistance / segmentLength;
|
||||
|
||||
// if (state.progress >= 1) {
|
||||
// state.index++;
|
||||
// state.progress = 0;
|
||||
|
||||
// if (state.index >= pathPoints.length - 1) {
|
||||
// // Stop at the end
|
||||
// state.index = pathPoints.length - 2;
|
||||
// state.progress = 1;
|
||||
// }
|
||||
// }
|
||||
|
||||
// // Interpolate position
|
||||
// const newPos = new Vector3().lerpVectors(
|
||||
// currentPoint,
|
||||
// nextPoint,
|
||||
// state.progress
|
||||
// );
|
||||
// mesh.position.copy(newPos);
|
||||
|
||||
// // Smooth rotation
|
||||
// const forward = new Vector3(0, 0, 1);
|
||||
// const targetQuat = new Quaternion().setFromUnitVectors(
|
||||
// forward,
|
||||
// direction
|
||||
// );
|
||||
// mesh.quaternion.slerp(targetQuat, 0.1);
|
||||
// });
|
||||
// });
|
||||
// ✅ Shared waypoint reservation system
|
||||
const reservedWaypoints = new Set<string>();
|
||||
|
||||
function tryReserveWaypoint(vehicleId: string, waypointId: string) {
|
||||
if (reservedWaypoints.has(waypointId)) return false; // already reserved
|
||||
reservedWaypoints.add(waypointId);
|
||||
return true;
|
||||
}
|
||||
|
||||
function releaseWaypoint(waypointId: string) {
|
||||
reservedWaypoints.delete(waypointId);
|
||||
}
|
||||
|
||||
useFrame((_, delta) => {
|
||||
if (!isPlaying) return;
|
||||
|
||||
vehiclesData.forEach((vehicle) => {
|
||||
const { vehicleId, route } = vehicle;
|
||||
if (!route || route.length === 0) return;
|
||||
|
||||
const mesh = scene.getObjectByProperty("uuid", vehicleId);
|
||||
if (!mesh) return;
|
||||
|
||||
const uuid = vehicleId;
|
||||
|
||||
// ✅ Initialize state
|
||||
if (!vehicleMovementState.current[uuid]) {
|
||||
vehicleMovementState.current[uuid] = {
|
||||
index: 0,
|
||||
pointIndex: 0,
|
||||
pathIndex: 0,
|
||||
progress: 0,
|
||||
hasStarted: false,
|
||||
};
|
||||
}
|
||||
|
||||
const state = vehicleMovementState.current[uuid];
|
||||
let currentPath = route[state.pathIndex];
|
||||
if (
|
||||
!currentPath ||
|
||||
!currentPath.pathPoints ||
|
||||
currentPath.pathPoints.length < 2
|
||||
)
|
||||
return;
|
||||
|
||||
let pathPoints = currentPath.pathPoints;
|
||||
const pathStart = new Vector3(...pathPoints[0].position);
|
||||
|
||||
// Step 1: move mesh to start
|
||||
if (!state.hasStarted) {
|
||||
const distanceToStart = mesh.position.distanceTo(pathStart);
|
||||
const step = speed * delta;
|
||||
|
||||
if (distanceToStart <= step) {
|
||||
mesh.position.copy(pathStart);
|
||||
mesh.quaternion.identity();
|
||||
state.hasStarted = true;
|
||||
return;
|
||||
}
|
||||
|
||||
const direction = pathStart.clone().sub(mesh.position).normalize();
|
||||
mesh.position.add(direction.clone().multiplyScalar(step));
|
||||
|
||||
const forward = new Vector3(0, 0, 1);
|
||||
const targetQuat = new Quaternion().setFromUnitVectors(
|
||||
forward,
|
||||
direction
|
||||
);
|
||||
mesh.quaternion.slerp(targetQuat, 0.1);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// ✅ Conflict Resolution: Check reservation before moving
|
||||
const nextWaypointId = `${currentPath.pathId}-${state.pointIndex + 1}`;
|
||||
if (!tryReserveWaypoint(uuid, nextWaypointId)) {
|
||||
// ⏸ Wait here until waypoint becomes free
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 2: Move along current path
|
||||
const currentPoint = new Vector3(
|
||||
...pathPoints[state.pointIndex].position
|
||||
);
|
||||
const nextPoint = new Vector3(
|
||||
...pathPoints[state.pointIndex + 1].position
|
||||
);
|
||||
|
||||
const segmentVector = new Vector3().subVectors(nextPoint, currentPoint);
|
||||
const segmentLength = segmentVector.length();
|
||||
const direction = segmentVector.clone().normalize();
|
||||
|
||||
const moveDistance = speed * delta;
|
||||
state.progress += moveDistance / segmentLength;
|
||||
|
||||
if (state.progress >= 1) {
|
||||
// ✅ Release waypoint once passed
|
||||
releaseWaypoint(nextWaypointId);
|
||||
|
||||
state.pointIndex++;
|
||||
state.progress = 0;
|
||||
|
||||
// ✅ reached end of current path → switch to next path
|
||||
if (state.pointIndex >= pathPoints.length - 1) {
|
||||
state.pathIndex++;
|
||||
state.pointIndex = 0;
|
||||
state.progress = 0;
|
||||
|
||||
// 🔥 refresh path data after advancing
|
||||
if (state.pathIndex < route.length) {
|
||||
currentPath = route[state.pathIndex];
|
||||
pathPoints = currentPath.pathPoints;
|
||||
} else {
|
||||
// ✅ Finished ALL paths → stop
|
||||
state.pathIndex = route.length - 1;
|
||||
const lastPath = route[state.pathIndex];
|
||||
const lastPts = lastPath.pathPoints;
|
||||
state.pointIndex = lastPts.length - 2;
|
||||
state.progress = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Interpolate position
|
||||
const newPos = new Vector3().lerpVectors(
|
||||
new Vector3(...pathPoints[state.pointIndex].position),
|
||||
new Vector3(...pathPoints[state.pointIndex + 1].position),
|
||||
state.progress
|
||||
);
|
||||
mesh.position.copy(newPos);
|
||||
|
||||
// Smooth rotation
|
||||
const forward = new Vector3(0, 0, 1);
|
||||
const targetQuat = new Quaternion().setFromUnitVectors(
|
||||
forward,
|
||||
direction
|
||||
);
|
||||
mesh.quaternion.slerp(targetQuat, 0.1);
|
||||
});
|
||||
});
|
||||
|
||||
// useFrame((_, delta) => {
|
||||
// if (!isPlaying) return;
|
||||
|
||||
// vehiclesData.forEach((vehicle) => {
|
||||
// console.log("vehiclesData: ", vehiclesData);
|
||||
// const { vehicleId, route } = vehicle;
|
||||
// if (!route || route.length === 0) return;
|
||||
|
||||
// const mesh = scene.getObjectByProperty("uuid", vehicleId);
|
||||
// if (!mesh) return;
|
||||
|
||||
// const uuid = vehicleId;
|
||||
|
||||
// // ✅ Initialize state
|
||||
// if (!vehicleMovementState.current[uuid]) {
|
||||
// vehicleMovementState.current[uuid] = {
|
||||
// index: 0,
|
||||
// pointIndex: 0,
|
||||
// pathIndex: 0,
|
||||
// progress: 0,
|
||||
// hasStarted: false,
|
||||
// };
|
||||
// }
|
||||
|
||||
// const state = vehicleMovementState.current[uuid];
|
||||
// let currentPath = route[state.pathIndex];
|
||||
// if (
|
||||
// !currentPath ||
|
||||
// !currentPath.pathPoints ||
|
||||
// currentPath.pathPoints.length < 2
|
||||
// )
|
||||
// return;
|
||||
|
||||
// let pathPoints = currentPath.pathPoints;
|
||||
// const pathStart = new Vector3(...pathPoints[0].position);
|
||||
|
||||
// // Step 1: move mesh to start
|
||||
// if (!state.hasStarted) {
|
||||
// const distanceToStart = mesh.position.distanceTo(pathStart);
|
||||
// const step = speed * delta;
|
||||
|
||||
// if (distanceToStart <= step) {
|
||||
// mesh.position.copy(pathStart);
|
||||
// mesh.quaternion.identity();
|
||||
// state.hasStarted = true;
|
||||
// return;
|
||||
// }
|
||||
|
||||
// const direction = pathStart.clone().sub(mesh.position).normalize();
|
||||
// mesh.position.add(direction.clone().multiplyScalar(step));
|
||||
|
||||
// const forward = new Vector3(0, 0, 1);
|
||||
// const targetQuat = new Quaternion().setFromUnitVectors(
|
||||
// forward,
|
||||
// direction
|
||||
// );
|
||||
// mesh.quaternion.slerp(targetQuat, 0.1);
|
||||
|
||||
// return;
|
||||
// }
|
||||
// // managerRef.current = { pathId: currentPath.pathId, vehicleId: uuid };
|
||||
// // // ✅ only setState when pathId actually changes
|
||||
// // if (managerData?.pathId !== currentPath.pathId) {
|
||||
// // setManagerData({ pathId: currentPath.pathId, vehicleId: uuid });
|
||||
// // }
|
||||
// if (
|
||||
// !managerRef.current ||
|
||||
// managerRef.current.pathId !== currentPath.pathId ||
|
||||
// managerRef.current.vehicleId !== uuid
|
||||
// ) {
|
||||
// managerRef.current = { pathId: currentPath.pathId, vehicleId: uuid };
|
||||
// }
|
||||
// // Step 2: Move along current path
|
||||
// const currentPoint = new Vector3(
|
||||
// ...pathPoints[state.pointIndex].position
|
||||
// );
|
||||
// const nextPoint = new Vector3(
|
||||
// ...pathPoints[state.pointIndex + 1].position
|
||||
// );
|
||||
|
||||
// const segmentVector = new Vector3().subVectors(nextPoint, currentPoint);
|
||||
// const segmentLength = segmentVector.length();
|
||||
// const direction = segmentVector.clone().normalize();
|
||||
|
||||
// console.log("speed: ", speed);
|
||||
// const moveDistance = speed * delta;
|
||||
// state.progress += moveDistance / segmentLength;
|
||||
|
||||
// if (state.progress >= 1) {
|
||||
// state.pointIndex++;
|
||||
// state.progress = 0;
|
||||
|
||||
// // ✅ reached end of current path → switch to next path
|
||||
// if (state.pointIndex >= pathPoints.length - 1) {
|
||||
// state.pathIndex++;
|
||||
// state.pointIndex = 0;
|
||||
// state.progress = 0;
|
||||
|
||||
// // 🔥 refresh path data after advancing
|
||||
// if (state.pathIndex < route.length) {
|
||||
// currentPath = route[state.pathIndex];
|
||||
// pathPoints = currentPath.pathPoints;
|
||||
// } else {
|
||||
// // ✅ Finished ALL paths → stop
|
||||
// state.pathIndex = route.length - 1;
|
||||
// const lastPath = route[state.pathIndex];
|
||||
// const lastPts = lastPath.pathPoints;
|
||||
// state.pointIndex = lastPts.length - 2;
|
||||
// state.progress = 1;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// // Interpolate position
|
||||
// const newPos = new Vector3().lerpVectors(
|
||||
// new Vector3(...pathPoints[state.pointIndex].position),
|
||||
// new Vector3(...pathPoints[state.pointIndex + 1].position),
|
||||
// state.progress
|
||||
// );
|
||||
// mesh.position.copy(newPos);
|
||||
|
||||
// // Smooth rotation
|
||||
// const forward = new Vector3(0, 0, 1);
|
||||
// const targetQuat = new Quaternion().setFromUnitVectors(
|
||||
// forward,
|
||||
// direction
|
||||
// );
|
||||
// mesh.quaternion.slerp(targetQuat, 0.1);
|
||||
// });
|
||||
// });
|
||||
|
||||
// const manager = usePathManager(
|
||||
// managerRef.current?.pathId,
|
||||
// managerRef.current?.vehicleId
|
||||
// );
|
||||
|
||||
// useEffect(() => {
|
||||
// console.log("managerRef.current: ", managerRef.current);
|
||||
// if (managerRef.current) {
|
||||
// console.log("Path manager updated:", manager);
|
||||
// }
|
||||
// }, [manager, managerRef.current]);
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import { Vector3 } from "three";
|
||||
import { useSceneContext } from "../../../../scene/sceneContext";
|
||||
import { useProductContext } from "../../../products/productContext";
|
||||
import { useSelectedEventSphere } from "../../../../../store/simulation/useSimulationStore";
|
||||
import VehicleAnimator2 from "../animator/vehicleAnimator2";
|
||||
function dist(a: PointData, b: PointData): number {
|
||||
return Math.sqrt(
|
||||
(a.position[0] - b.position[0]) ** 2 +
|
||||
@@ -156,7 +157,7 @@ export default function VehicleInstance2({
|
||||
const allPoints = useMemo(() => {
|
||||
const points: PointData[] = [];
|
||||
const seen = new Set<string>();
|
||||
paths?.forEach((path: PathDataInterface) => {
|
||||
useCreatedPaths.getState().paths?.forEach((path: PathDataInterface) => {
|
||||
path.pathPoints.forEach((p) => {
|
||||
if (!seen.has(p.pointId)) {
|
||||
seen.add(p.pointId);
|
||||
@@ -214,13 +215,28 @@ export default function VehicleInstance2({
|
||||
|
||||
setTimeout(() => {
|
||||
const modelUuid = selectedEventSphere?.userData?.modelUuid;
|
||||
// const index = vehiclesData.findIndex(
|
||||
// (v) => v.vehicleId === modelUuid
|
||||
// );
|
||||
|
||||
// if (index !== -1) {
|
||||
// const updatedVehicles = [...vehiclesData];
|
||||
// updatedVehicles[index] = {
|
||||
// ...updatedVehicles[index],
|
||||
// startPoint: prevPoint.position,
|
||||
// endPoint: newPoint.position,
|
||||
// route: edges,
|
||||
// };
|
||||
//
|
||||
// setVehiclesData(updatedVehicles);
|
||||
// }
|
||||
// }, 0);
|
||||
const index = vehiclesDataRef.current.findIndex(
|
||||
(v) => v.vehicleId === modelUuid
|
||||
);
|
||||
console.log(
|
||||
"vehiclesDataRef.current: ",
|
||||
vehiclesDataRef.current,
|
||||
modelUuid
|
||||
vehiclesDataRef.current
|
||||
);
|
||||
|
||||
if (index !== -1) {
|
||||
@@ -252,7 +268,7 @@ export default function VehicleInstance2({
|
||||
return () => {
|
||||
canvasElement.removeEventListener("contextmenu", handleContextMenu);
|
||||
};
|
||||
}, [raycaster, setVehiclesData, vehiclesData]);
|
||||
}, [raycaster, setVehiclesData, vehiclesData, selectedEventSphere]);
|
||||
|
||||
return null;
|
||||
return <VehicleAnimator2 vehiclesData={vehiclesDataRef.current} />;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { useCallback, useEffect, useMemo } from "react";
|
||||
import { useEffect, useMemo } from "react";
|
||||
import { useCreatedPaths } from "../../../../../store/builder/store";
|
||||
|
||||
export const usePathManager = (pathId?: string, vehicleId?: string | null) => {
|
||||
export const usePathManager = (pathId?: string, vehicleId?: string) => {
|
||||
const { paths, allPaths, setAllPaths } = useCreatedPaths();
|
||||
|
||||
|
||||
// Initialize all paths into allPaths store
|
||||
useEffect(() => {
|
||||
if (!paths || paths.length === 0) return;
|
||||
|
||||
@@ -26,6 +26,7 @@ export const usePathManager = (pathId?: string, vehicleId?: string | null) => {
|
||||
}
|
||||
}, [paths, allPaths, setAllPaths]);
|
||||
|
||||
// Assign vehicle to a path
|
||||
useEffect(() => {
|
||||
if (!pathId || !vehicleId) return;
|
||||
|
||||
@@ -39,8 +40,10 @@ export const usePathManager = (pathId?: string, vehicleId?: string | null) => {
|
||||
}
|
||||
}, [pathId, vehicleId, allPaths, setAllPaths]);
|
||||
|
||||
// ✅ return true if path exists & isAvailable, else false
|
||||
return useMemo(() => {
|
||||
if (!pathId) return undefined;
|
||||
return allPaths.find((p: any) => p.pathId === pathId);
|
||||
if (!pathId) return false;
|
||||
const path = allPaths.find((p: any) => p.pathId === pathId);
|
||||
return path ? path.isAvailable : false;
|
||||
}, [pathId, allPaths]);
|
||||
};
|
||||
|
||||
@@ -209,13 +209,19 @@ export default function PathCreator() {
|
||||
t = Math.max(0, Math.min(1, t));
|
||||
|
||||
const closestPoint = new Vector3().lerpVectors(point1Vec, point2Vec, t);
|
||||
const filteredPath = paths.filter(
|
||||
(p: PathDataInterface) => p.pathId !== clickedPath.pathId
|
||||
);
|
||||
setPaths(filteredPath);
|
||||
// setPaths((prev: PathData) =>
|
||||
// prev.filter((p) => p.pathId !== clickedPath.pathId)
|
||||
// const filteredPath = paths.filter(
|
||||
// (p: PathDataInterface) =>
|
||||
// String(p.pathId).trim() !== String(clickedPath.pathId).trim()
|
||||
// );
|
||||
// setPaths(filteredPath);
|
||||
const filteredPath = useCreatedPaths
|
||||
.getState()
|
||||
.paths.filter(
|
||||
(p: PathDataInterface) =>
|
||||
String(p.pathId).trim() !== String(clickedPath.pathId).trim()
|
||||
);
|
||||
|
||||
setPaths(filteredPath);
|
||||
|
||||
const point1: PointData = {
|
||||
pointId: clickedPath?.pathPoints[0].pointId,
|
||||
@@ -240,8 +246,14 @@ export default function PathCreator() {
|
||||
pathPoints: [point2, splitPoint],
|
||||
};
|
||||
setDraftPoints([splitPoint]);
|
||||
// Instead of relying on "paths" from the component:
|
||||
setPaths([
|
||||
...useCreatedPaths.getState().paths, // 👈 always current from store
|
||||
path1,
|
||||
path2,
|
||||
]);
|
||||
|
||||
setPaths([...paths, path1, path2]);
|
||||
// setPaths([...paths, path1, path2]);
|
||||
} else {
|
||||
const newPath: PathDataInterface = {
|
||||
pathId: MathUtils.generateUUID(),
|
||||
@@ -256,7 +268,12 @@ export default function PathCreator() {
|
||||
pathPoints: [point2, splitPoint],
|
||||
};
|
||||
|
||||
setPaths([...paths, newPath, firstPath, secondPath]);
|
||||
setPaths([
|
||||
...useCreatedPaths.getState().paths,
|
||||
newPath,
|
||||
firstPath,
|
||||
secondPath,
|
||||
]);
|
||||
|
||||
setDraftPoints([splitPoint]);
|
||||
}
|
||||
@@ -307,7 +324,7 @@ export default function PathCreator() {
|
||||
pathId: MathUtils.generateUUID(),
|
||||
pathPoints: [draftPoints[0], newPoint],
|
||||
};
|
||||
setPaths([...paths, newPath]);
|
||||
setPaths([...useCreatedPaths.getState().paths, newPath]);
|
||||
setDraftPoints([newPoint]);
|
||||
}
|
||||
};
|
||||
@@ -352,10 +369,10 @@ export default function PathCreator() {
|
||||
});
|
||||
return points;
|
||||
}, [paths]);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
localStorage.setItem("paths", JSON.stringify(paths));
|
||||
console.log("paths: ", paths);
|
||||
}, [paths]);
|
||||
|
||||
return (
|
||||
|
||||
@@ -138,10 +138,7 @@ export default function PathHandler({
|
||||
end.z + delta.z,
|
||||
];
|
||||
|
||||
// ✅ Move both points separately (won’t overwrite other updates)
|
||||
setPathPosition(points[0].pointId, newStart, setPaths, paths);
|
||||
setPathPosition(points[1].pointId, newEnd, setPaths, paths);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -646,52 +646,6 @@ export default function PointHandler({
|
||||
);
|
||||
}, [shortestPaths]);
|
||||
|
||||
// useFrame((_, delta) => {
|
||||
// if (!isPlaying || pathSegments.length < 2) return;
|
||||
|
||||
// vehicleUuids.forEach((uuid: any) => {
|
||||
// const object = scene.getObjectByProperty("uuid", uuid);
|
||||
// if (!object) return;
|
||||
|
||||
// const state = vehicleMovementState.current[uuid];
|
||||
// if (!state) return;
|
||||
|
||||
// const startSeg = pathSegments[state.index];
|
||||
// const endSeg = pathSegments[state.index + 1];
|
||||
// if (!startSeg || !endSeg) return;
|
||||
|
||||
// const segmentDistance = startSeg.position.distanceTo(endSeg.position);
|
||||
// state.progress += (speed * delta) / segmentDistance;
|
||||
|
||||
// while (state.progress >= 1) {
|
||||
// state.progress -= 1;
|
||||
// state.index++;
|
||||
// if (state.index >= pathSegments.length - 1) {
|
||||
// state.index = 0;
|
||||
// state.progress = 0;
|
||||
// object.position.copy(pathSegments[0].position);
|
||||
// object.quaternion.identity(); // reset rotation
|
||||
// }
|
||||
// }
|
||||
|
||||
// const newPos = startSeg.position
|
||||
// .clone()
|
||||
// .lerp(endSeg.position, state.progress);
|
||||
// object.position.copy(newPos);
|
||||
|
||||
// const forward = new Vector3(0, 0, 1);
|
||||
// const targetDir = endSeg.position
|
||||
// .clone()
|
||||
// .sub(startSeg.position)
|
||||
// .normalize();
|
||||
// const targetQuat = new Quaternion().setFromUnitVectors(
|
||||
// forward,
|
||||
// targetDir
|
||||
// );
|
||||
|
||||
// object.quaternion.slerp(targetQuat, 0.1);
|
||||
// });
|
||||
// });
|
||||
|
||||
function getPathIdByPoints(
|
||||
startId: string | undefined,
|
||||
@@ -713,263 +667,7 @@ export default function PointHandler({
|
||||
}
|
||||
return null; // not found
|
||||
}
|
||||
//works
|
||||
useFrame((_, delta) => {
|
||||
if (!isPlaying || pathSegments.length < 2 || vehicleData.length === 0)
|
||||
return;
|
||||
|
||||
const vehicle = vehicleData[activeVehicleIndex];
|
||||
if (!vehicle) return;
|
||||
|
||||
const uuid = vehicle.vehicleId;
|
||||
const vehicleStartPos = new Vector3(...vehicle.vehiclePosition);
|
||||
|
||||
const object = scene.getObjectByProperty("uuid", uuid);
|
||||
if (!object) return;
|
||||
|
||||
const state = vehicleMovementState.current[uuid];
|
||||
if (!state) return;
|
||||
|
||||
const pathStart = pathSegments[0].position;
|
||||
|
||||
if (!state.hasStarted) {
|
||||
const distanceToStart = object.position.distanceTo(pathStart);
|
||||
const step = speed * delta;
|
||||
|
||||
if (distanceToStart <= step) {
|
||||
object.position.copy(pathStart);
|
||||
object.quaternion.identity();
|
||||
state.hasStarted = true;
|
||||
return;
|
||||
}
|
||||
|
||||
const direction = pathStart.clone().sub(object.position);
|
||||
const distance = direction.length();
|
||||
|
||||
if (distance > step) {
|
||||
direction.normalize();
|
||||
object.position.add(direction.clone().multiplyScalar(step));
|
||||
|
||||
const forward = new Vector3(0, 0, 1);
|
||||
const targetQuat = new Quaternion().setFromUnitVectors(
|
||||
forward,
|
||||
direction
|
||||
);
|
||||
object.quaternion.slerp(targetQuat, 0.1);
|
||||
} else {
|
||||
object.position.copy(pathStart);
|
||||
object.quaternion.identity();
|
||||
vehicleMovementState.current[uuid] = { index: 0, progress: 0 };
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 2: Follow the path
|
||||
const startSeg = pathSegments[state.index];
|
||||
const endSeg = pathSegments[state.index + 1];
|
||||
if (!startSeg || !endSeg) return;
|
||||
const currentPathId = getPathIdByPoints(
|
||||
startSeg.startId || startSeg.endId,
|
||||
endSeg.endId || endSeg.startId,
|
||||
shortestPaths
|
||||
);
|
||||
setManagerData({ pathId: currentPathId, vehicleId: uuid });
|
||||
|
||||
const segmentDistance = startSeg.position.distanceTo(endSeg.position);
|
||||
state.progress += (speed * delta) / segmentDistance;
|
||||
|
||||
while (state.progress >= 1) {
|
||||
state.progress -= 1;
|
||||
state.index++;
|
||||
|
||||
if (state.index >= pathSegments.length - 1) {
|
||||
state.index = 0;
|
||||
state.progress = 0;
|
||||
state.hasStarted = false;
|
||||
object.position.copy(vehicleStartPos);
|
||||
object.quaternion.identity();
|
||||
|
||||
setActiveVehicleIndex((prevIndex) =>
|
||||
prevIndex + 1 >= vehicleData.length ? 0 : prevIndex + 1
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const newPos = startSeg.position
|
||||
.clone()
|
||||
.lerp(endSeg.position, state.progress);
|
||||
object.position.copy(newPos);
|
||||
|
||||
const forward = new Vector3(0, 0, 1);
|
||||
const targetDir = endSeg.position
|
||||
.clone()
|
||||
.sub(startSeg.position)
|
||||
.normalize();
|
||||
const targetQuat = new Quaternion().setFromUnitVectors(forward, targetDir);
|
||||
object.quaternion.slerp(targetQuat, 0.1);
|
||||
});
|
||||
|
||||
// useFrame((_, delta) => {
|
||||
// if (!isPlaying || pathSegments.length < 2 || vehicleData.length === 0)
|
||||
// return;
|
||||
|
||||
// const vehicleStartPos = new Vector3(...agvDetail.position);
|
||||
|
||||
// const object = scene.getObjectByProperty("uuid", agvDetail.modelUuid);
|
||||
// if (!object) return;
|
||||
|
||||
// const state = vehicleMovementState.current[agvDetail.modelUuid];
|
||||
// if (!state) return;
|
||||
|
||||
// const moveSpeed = speed * delta;
|
||||
|
||||
// const pathStart = pathSegments[0].position;
|
||||
|
||||
// // ➤ Step 1: Move the object to the starting point of the path
|
||||
// if (!state.hasStarted) {
|
||||
// const distanceToStart = object.position.distanceTo(pathStart);
|
||||
|
||||
// if (distanceToStart <= moveSpeed) {
|
||||
// object.position.copy(pathStart);
|
||||
// object.quaternion.identity();
|
||||
// state.hasStarted = true;
|
||||
// state.index = 0;
|
||||
// state.progress = 0;
|
||||
// return;
|
||||
// }
|
||||
|
||||
// const direction = pathStart.clone().sub(object.position).normalize();
|
||||
// object.position.add(direction.clone().multiplyScalar(moveSpeed));
|
||||
|
||||
// const forward = new Vector3(0, 0, 1);
|
||||
// const targetQuat = new Quaternion().setFromUnitVectors(
|
||||
// forward,
|
||||
// direction
|
||||
// );
|
||||
// object.quaternion.slerp(targetQuat, 0.1);
|
||||
|
||||
// return;
|
||||
// }
|
||||
|
||||
// // ➤ Step 2: Traverse path segments
|
||||
// const startSeg = pathSegments[state.index];
|
||||
// const endSeg = pathSegments[state.index + 1];
|
||||
// if (!startSeg || !endSeg) return;
|
||||
|
||||
// const currentPathId = getPathIdByPoints(
|
||||
// startSeg.startId || startSeg.endId,
|
||||
// endSeg.endId || endSeg.startId,
|
||||
// shortestPaths
|
||||
// );
|
||||
|
||||
// setManagerData({ pathId: currentPathId, vehicleId: agvDetail.modelUuid });
|
||||
|
||||
// const segmentDistance = startSeg.position.distanceTo(endSeg.position);
|
||||
// state.progress += moveSpeed / segmentDistance;
|
||||
|
||||
// // ➤ Step 3: If we've finished this segment, move to the next
|
||||
// while (state.progress >= 1) {
|
||||
// state.progress -= 1;
|
||||
// state.index++;
|
||||
|
||||
// if (state.index >= pathSegments.length - 1) {
|
||||
// // Path completed
|
||||
// state.index = 0;
|
||||
// state.progress = 0;
|
||||
// state.hasStarted = false;
|
||||
|
||||
// object.position.copy(vehicleStartPos);
|
||||
// object.quaternion.identity();
|
||||
|
||||
// setActiveVehicleIndex((prevIndex) =>
|
||||
// prevIndex + 1 >= vehicleData.length ? 0 : prevIndex + 1
|
||||
// );
|
||||
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
|
||||
// // ➤ Step 4: Interpolate position and rotate
|
||||
// const newPos = startSeg.position
|
||||
// .clone()
|
||||
// .lerp(endSeg.position, state.progress);
|
||||
// object.position.copy(newPos);
|
||||
|
||||
// const direction = endSeg.position
|
||||
// .clone()
|
||||
// .sub(startSeg.position)
|
||||
// .normalize();
|
||||
// const forward = new Vector3(0, 0, 1);
|
||||
// const targetQuat = new Quaternion().setFromUnitVectors(forward, direction);
|
||||
// object.quaternion.slerp(targetQuat, 0.1);
|
||||
// });
|
||||
|
||||
// useFrame((_, delta) => {
|
||||
// if (!isPlaying || pathSegments.length < 2 || vehicleData.length === 0)
|
||||
// return;
|
||||
// const vehicle = vehicleData[activeVehicleIndex];
|
||||
// if (!vehicle) return;
|
||||
|
||||
// const uuid = vehicle.vehicleId;
|
||||
// const vehiclePosition = vehicle.vehiclePosition;
|
||||
|
||||
// const object = scene.getObjectByProperty("uuid", uuid);
|
||||
// if (!object) return;
|
||||
|
||||
// const state = vehicleMovementState.current[uuid];
|
||||
// if (!state) return;
|
||||
|
||||
// const startSeg = pathSegments[state.index];
|
||||
// const endSeg = pathSegments[state.index + 1];
|
||||
// if (!startSeg || !endSeg) return;
|
||||
|
||||
// const segmentDistance = startSeg.position.distanceTo(endSeg.position);
|
||||
// state.progress += (speed * delta) / segmentDistance;
|
||||
|
||||
// while (state.progress >= 1) {
|
||||
// state.progress -= 1;
|
||||
// state.index++;
|
||||
|
||||
// // If finished path
|
||||
// if (state.index >= pathSegments.length - 1) {
|
||||
// state.index = 0;
|
||||
// state.progress = 0;
|
||||
// object.position.copy(pathSegments[0].position);
|
||||
// object.quaternion.identity();
|
||||
|
||||
// // Move to next vehicle
|
||||
// setActiveVehicleIndex((prevIndex) =>
|
||||
// prevIndex + 1 >= vehicleUuids.length ? 0 : prevIndex + 1
|
||||
// );
|
||||
// return; // Stop updating this frame
|
||||
// }
|
||||
// }
|
||||
|
||||
// const newPos = startSeg.position
|
||||
// .clone()
|
||||
// .lerp(endSeg.position, state.progress);
|
||||
// object.position.copy(newPos);
|
||||
|
||||
// const forward = new Vector3(0, 0, 1);
|
||||
// const targetDir = endSeg.position
|
||||
// .clone()
|
||||
// .sub(startSeg.position)
|
||||
// .normalize();
|
||||
// const targetQuat = new Quaternion().setFromUnitVectors(forward, targetDir);
|
||||
|
||||
// object.quaternion.slerp(targetQuat, 0.1);
|
||||
// });
|
||||
|
||||
const manager = usePathManager(managerData?.pathId, managerData?.vehicleId);
|
||||
|
||||
useEffect(() => {
|
||||
// if (managerData) {
|
||||
//
|
||||
// }
|
||||
}, [managerData]);
|
||||
return (
|
||||
<>
|
||||
<DragControls
|
||||
@@ -1020,30 +718,3 @@ export default function PointHandler({
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
// const setPathPosition = useCallback(
|
||||
// (
|
||||
// pointUuid: string,
|
||||
// position: [number, number, number],
|
||||
// setPaths: React.Dispatch<React.SetStateAction<PathData>>
|
||||
// ) => {
|
||||
// setPaths((prevPaths) =>
|
||||
// prevPaths.map((path) => {
|
||||
// if (path.pathPoints.some((p) => p.pointId === pointUuid)) {
|
||||
// return {
|
||||
// ...path,
|
||||
// pathPoints: path.pathPoints.map((p) =>
|
||||
// p.pointId === pointUuid ? { ...p, position } : p
|
||||
// ) as [PointData, PointData], // 👈 force back to tuple
|
||||
// };
|
||||
// }
|
||||
// return path;
|
||||
// })
|
||||
// );
|
||||
// },
|
||||
// [setPaths]
|
||||
// );
|
||||
|
||||
// const getPathsByPointId = (pointId: any) => {
|
||||
// return paths.filter((a) => a.pathPoints.some((p) => p.pointId === pointId));
|
||||
// };
|
||||
|
||||
@@ -665,58 +665,58 @@ interface allPaths {
|
||||
type PathData = PathDataInterface[];
|
||||
export const useCreatedPaths = create<any>((set: any) => ({
|
||||
paths: [
|
||||
{
|
||||
pathId: "276724c5-05a3-4b5e-a127-a60b3533ccce",
|
||||
pathPoints: [
|
||||
{
|
||||
pointId: "19c3f429-f214-4f87-8906-7eaaedd925da",
|
||||
position: [2.33155763270131, 0, -20.538859668988927],
|
||||
},
|
||||
{
|
||||
pointId: "ea73c7c8-0e26-4aae-9ed8-2349ff2d6718",
|
||||
position: [17.13371069714903, 0, -22.156135485080462],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
pathId: "2736b20b-a433-443c-a5c9-5ba4348ac682",
|
||||
pathPoints: [
|
||||
{
|
||||
pointId: "ea73c7c8-0e26-4aae-9ed8-2349ff2d6718",
|
||||
position: [17.13371069714903, 0, -22.156135485080462],
|
||||
},
|
||||
{
|
||||
pointId: "2212bb52-c63c-4289-8b50-5ffd229d13e5",
|
||||
position: [16.29236816120279, 0, -10.819973445497789],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
pathId: "3144a2df-7aad-483d-bbc7-de7f7b5b3bfc",
|
||||
pathPoints: [
|
||||
{
|
||||
pointId: "2212bb52-c63c-4289-8b50-5ffd229d13e5",
|
||||
position: [16.29236816120279, 0, -10.819973445497789],
|
||||
},
|
||||
{
|
||||
pointId: "adfd05a7-4e16-403f-81d0-ce99f2e34f5f",
|
||||
position: [4.677047323894161, 0, -8.279486846767094],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
pathId: "e0a1b5da-27c2-44a0-81db-759b5a5eb416",
|
||||
pathPoints: [
|
||||
{
|
||||
pointId: "adfd05a7-4e16-403f-81d0-ce99f2e34f5f",
|
||||
position: [4.677047323894161, 0, -8.279486846767094],
|
||||
},
|
||||
{
|
||||
pointId: "19c3f429-f214-4f87-8906-7eaaedd925da",
|
||||
position: [2.33155763270131, 0, -20.538859668988927],
|
||||
},
|
||||
],
|
||||
},
|
||||
// {
|
||||
// pathId: "276724c5-05a3-4b5e-a127-a60b3533ccce",
|
||||
// pathPoints: [
|
||||
// {
|
||||
// pointId: "19c3f429-f214-4f87-8906-7eaaedd925da",
|
||||
// position: [2.33155763270131, 0, -20.538859668988927],
|
||||
// },
|
||||
// {
|
||||
// pointId: "ea73c7c8-0e26-4aae-9ed8-2349ff2d6718",
|
||||
// position: [17.13371069714903, 0, -22.156135485080462],
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// pathId: "2736b20b-a433-443c-a5c9-5ba4348ac682",
|
||||
// pathPoints: [
|
||||
// {
|
||||
// pointId: "ea73c7c8-0e26-4aae-9ed8-2349ff2d6718",
|
||||
// position: [17.13371069714903, 0, -22.156135485080462],
|
||||
// },
|
||||
// {
|
||||
// pointId: "2212bb52-c63c-4289-8b50-5ffd229d13e5",
|
||||
// position: [16.29236816120279, 0, -10.819973445497789],
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// pathId: "3144a2df-7aad-483d-bbc7-de7f7b5b3bfc",
|
||||
// pathPoints: [
|
||||
// {
|
||||
// pointId: "2212bb52-c63c-4289-8b50-5ffd229d13e5",
|
||||
// position: [16.29236816120279, 0, -10.819973445497789],
|
||||
// },
|
||||
// {
|
||||
// pointId: "adfd05a7-4e16-403f-81d0-ce99f2e34f5f",
|
||||
// position: [4.677047323894161, 0, -8.279486846767094],
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// pathId: "e0a1b5da-27c2-44a0-81db-759b5a5eb416",
|
||||
// pathPoints: [
|
||||
// {
|
||||
// pointId: "adfd05a7-4e16-403f-81d0-ce99f2e34f5f",
|
||||
// position: [4.677047323894161, 0, -8.279486846767094],
|
||||
// },
|
||||
// {
|
||||
// pointId: "19c3f429-f214-4f87-8906-7eaaedd925da",
|
||||
// position: [2.33155763270131, 0, -20.538859668988927],
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
],
|
||||
setPaths: (x: PathData) => set({ paths: x }),
|
||||
allPaths: [],
|
||||
|
||||
Reference in New Issue
Block a user