added available paths

This commit is contained in:
2025-08-28 09:43:42 +05:30
parent 5117e48527
commit a0e5115c6c
9 changed files with 931 additions and 470 deletions

View File

@@ -172,6 +172,7 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai
}
}
});
const updatePoint = (index: number, pos: THREE.Vector3) => {

View File

@@ -29,10 +29,10 @@ export const getPathsByPointId = (pointId: any, paths: PathData) => {
export const setPathPosition = (
pointUuid: string,
position: [number, number, number],
setPaths: React.Dispatch<React.SetStateAction<PathData>>
setPaths: React.Dispatch<React.SetStateAction<PathData>>,
paths: PathData
) => {
setPaths((prevPaths) =>
prevPaths.map((path: any) => {
const newPaths = paths.map((path: any) => {
if (path?.pathPoints.some((p: any) => p.pointId === pointUuid)) {
return {
...path,
@@ -42,6 +42,7 @@ export const setPathPosition = (
};
}
return path;
})
);
});
setPaths(newPaths);
};

View File

@@ -0,0 +1,46 @@
import { useCallback, useEffect, useMemo } from "react";
import { useCreatedPaths } from "../../../../../store/builder/store";
export const usePathManager = (pathId?: string, vehicleId?: string | null) => {
const { paths, allPaths, setAllPaths } = useCreatedPaths();
console.log("allPaths: ", allPaths);
useEffect(() => {
if (!paths || paths.length === 0) return;
const newPaths = paths.map((val: any) => ({
pathId: val.pathId,
isAvailable: true,
vehicleId: null,
}));
const merged = [...allPaths];
newPaths.forEach((p: any) => {
if (!merged.find((m) => m.pathId === p.pathId)) {
merged.push(p);
}
});
if (merged.length !== allPaths.length) {
setAllPaths(merged);
}
}, [paths, allPaths, setAllPaths]);
useEffect(() => {
if (!pathId || !vehicleId) return;
const updated = allPaths.map((p: any) =>
p.pathId === pathId ? { ...p, vehicleId, isAvailable: false } : p
);
const hasChanged = JSON.stringify(updated) !== JSON.stringify(allPaths);
if (hasChanged) {
setAllPaths(updated);
}
}, [pathId, vehicleId, allPaths, setAllPaths]);
return useMemo(() => {
if (!pathId) return undefined;
return allPaths.find((p: any) => p.pathId === pathId);
}, [pathId, allPaths]);
};

View File

@@ -8,10 +8,9 @@ import React, {
useState,
} from "react";
import { LineCurve3, MathUtils, Plane, Vector3 } from "three";
import { Vector3Array } from "../../../../types/world/worldTypes";
import {
useActiveSubTool,
useActiveTool,
useCreatedPaths,
useToolMode,
} from "../../../../store/builder/store";
import PointHandler from "./pointHandler";
@@ -36,15 +35,19 @@ interface PathDataInterface {
type PathData = PathDataInterface[];
export default function PathCreator() {
const [paths, setPaths] = useState<PathData>([]);
// const [paths, setPaths] = useState<PathData>([]);
// const [paths, setPaths] = useState<PathData>(() => {
// const stored = localStorage.getItem("paths");
// return stored ? JSON.parse(stored) : [];
// });
const { paths, setPaths } = useCreatedPaths();
const { activeTool } = useActiveTool();
const { toolMode } = useToolMode();
const [draftPoints, setDraftPoints] = useState<PointData[]>([]);
const [mousePos, setMousePos] = useState<[number, number, number] | null>(
null
);
const { toolMode } = useToolMode();
const plane = useMemo(() => new Plane(new Vector3(0, 1, 0), 0), []);
const { scene, raycaster, gl } = useThree();
const [snappedPosition, setSnappedPosition] = useState<
[number, number, number] | null
>(null);
@@ -54,21 +57,33 @@ export default function PathCreator() {
null
);
const [hoveredPoint, setHoveredPoint] = useState<PointData | null>(null);
const { activeSubTool } = useActiveSubTool();
const { activeTool } = useActiveTool();
const [pathPointsList, setPathPointsList] = useState<PointData[]>([]);
const [selectedPointIndices, setSelectedPointIndices] = useState<number[]>(
[]
);
const plane = useMemo(() => new Plane(new Vector3(0, 1, 0), 0), []);
const { scene, raycaster, gl } = useThree();
const POINT_SNAP_THRESHOLD = 0.5;
const CAN_POINT_SNAP = true;
useEffect(() => {}, [paths]);
const getAllOtherPathPoints = useCallback((): PointData[] => {
if (draftPoints.length === 0) return [];
return (
paths?.flatMap((path) =>
path.pathPoints.filter((pt) => pt.pointId !== draftPoints[0].pointId)
paths?.flatMap((path: any) =>
path.pathPoints.filter(
(pt: PointData) => pt.pointId !== draftPoints[0].pointId
)
) ?? []
);
}, [paths, draftPoints]);
useEffect(() => {
const stored = localStorage.getItem("paths");
setPaths(stored ? JSON.parse(stored) : []);
}, []);
const snapPathPoint = useCallback(
(position: [number, number, number]) => {
@@ -134,13 +149,11 @@ export default function PathCreator() {
});
useEffect(() => {}, [paths]);
const getPathPointById = (uuid: any) => {
for (const path of paths) {
const point = path.pathPoints.find((p) => p.pointId === uuid);
console.log(
"point: ",
path.pathPoints.map((val) => val)
);
const point = path.pathPoints.find((p: PointData) => p.pointId === uuid);
if (point) return point;
}
return undefined;
@@ -170,7 +183,9 @@ export default function PathCreator() {
paths
);
if (clickedPath) {
const hitPath = paths.find((p) => p.pathId === clickedPath.pathId);
const hitPath = paths.find(
(p: PathDataInterface) => p.pathId === clickedPath.pathId
);
if (!hitPath) return;
@@ -197,7 +212,13 @@ export default function PathCreator() {
t = Math.max(0, Math.min(1, t));
const closestPoint = new Vector3().lerpVectors(point1Vec, point2Vec, t);
setPaths((prev) => prev.filter((p) => p.pathId !== clickedPath.pathId));
const filteredPath = paths.filter(
(p: PathDataInterface) => p.pathId !== clickedPath.pathId
);
setPaths(filteredPath);
// setPaths((prev: PathData) =>
// prev.filter((p) => p.pathId !== clickedPath.pathId)
// );
const point1: PointData = {
pointId: clickedPath?.pathPoints[0].pointId,
@@ -222,7 +243,8 @@ export default function PathCreator() {
pathPoints: [point2, splitPoint],
};
setDraftPoints([splitPoint]);
setPaths((prev) => [...prev, path1, path2]);
setPaths([...paths, path1, path2]);
} else {
const newPath: PathDataInterface = {
pathId: MathUtils.generateUUID(),
@@ -237,7 +259,8 @@ export default function PathCreator() {
pathPoints: [point2, splitPoint],
};
setPaths((prev) => [...prev, newPath, firstPath, secondPath]);
setPaths([...paths, newPath, firstPath, secondPath]);
setDraftPoints([splitPoint]);
}
@@ -287,8 +310,7 @@ export default function PathCreator() {
pathId: MathUtils.generateUUID(),
pathPoints: [draftPoints[0], newPoint],
};
setPaths((prev) => [...prev, newPath]);
setPaths([...paths, newPath]);
setDraftPoints([newPoint]);
}
};
@@ -322,7 +344,8 @@ export default function PathCreator() {
const allPoints = useMemo(() => {
const points: PointData[] = [];
const seen = new Set<string>();
paths.forEach((path) => {
console.log("paths: ", paths);
paths?.forEach((path: PathDataInterface) => {
path.pathPoints.forEach((p) => {
if (!seen.has(p.pointId)) {
seen.add(p.pointId);
@@ -334,8 +357,10 @@ export default function PathCreator() {
}, [paths]);
useEffect(() => {
console.log("allPoints: ", allPoints);
console.log("paths ", paths);
localStorage.setItem("paths", JSON.stringify(paths));
}, [paths]);
return (
<>
{/* Draft points (red) */}
@@ -358,6 +383,8 @@ export default function PathCreator() {
setHoveredPoint={setHoveredPoint}
hoveredLine={hoveredLine}
hoveredPoint={hoveredPoint}
selected={selectedPointIndices}
setSelected={setSelectedPointIndices}
/>
))}
@@ -372,7 +399,7 @@ export default function PathCreator() {
)}
{/* Permanent paths */}
{paths.map((path) => (
{paths.map((path: PathDataInterface) => (
<PathHandler
key={path.pathId}
selectedPath={path}

View File

@@ -55,14 +55,17 @@ export default function PathHandler({
const [start, end] = points.map((p) => new Vector3(...p.position));
return new LineCurve3(start, end);
}, [points]);
const removePath = (pathId: string) => {
setPaths((prevPaths) => prevPaths.filter((p) => p.pathId !== pathId));
};
const handlePathClick = (pointId: string) => {
if (toolMode === "3D-Delete") {
removePath(pointId);
}
};
const handleDragStart = (points: [PointData, PointData]) => {
if (activeTool !== "cursor") return;
const intersectionPoint = new Vector3();
@@ -77,6 +80,7 @@ export default function PathHandler({
setInitialPositions({ paths: pathSet });
}
};
// const handleDrag = (points: [PointData, PointData]) => {
// if (isHovered && dragOffset) {
// const intersectionPoint = new Vector3();
@@ -135,13 +139,14 @@ export default function PathHandler({
];
// ✅ Move both points separately (wont overwrite other updates)
setPathPosition(points[0].pointId, newStart, setPaths);
setPathPosition(points[1].pointId, newEnd, setPaths);
setPathPosition(points[0].pointId, newStart, setPaths, paths);
setPathPosition(points[1].pointId, newEnd, setPaths, paths);
}
}
};
const handleDragEnd = (points: [PointData, PointData]) => {};
return (
<>
<DragControls

View File

@@ -1,11 +1,27 @@
import { DragControls } from "@react-three/drei";
import React, { useCallback, useEffect, useMemo, useState } from "react";
import { useActiveTool, useToolMode } from "../../../../store/builder/store";
import { Plane, Vector3 } from "three";
import { useThree } from "@react-three/fiber";
import { DragControls, Line } from "@react-three/drei";
import React, {
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from "react";
import {
useActiveTool,
useCreatedPaths,
useToolMode,
} from "../../../../store/builder/store";
import { CubicBezierCurve3, Plane, Quaternion, Vector3 } from "three";
import { useFrame, useThree } from "@react-three/fiber";
import { handleCanvasCursors } from "../../../../utils/mouseUtils/handleCanvasCursors";
import { getPathsByPointId, setPathPosition } from "./function/getPaths";
import { aStar } from "../structuredPath/functions/aStar";
import {
useAnimationPlaySpeed,
usePlayButtonStore,
} from "../../../../store/usePlayButtonStore";
import { useSceneContext } from "../../../scene/sceneContext";
import { usePathManager } from "./function/usePathManager";
type PointData = {
pointId: string;
position: [number, number, number];
@@ -31,6 +47,8 @@ type PointHandlerProps = {
hoveredLine: PathDataInterface | null;
pointIndex: any;
points: PointData[];
selected: number[];
setSelected: React.Dispatch<React.SetStateAction<number[]>>;
};
function dist(a: PointData, b: PointData): number {
return Math.sqrt(
@@ -39,6 +57,13 @@ function dist(a: PointData, b: PointData): number {
(a.position[2] - b.position[2]) ** 2
);
}
type SegmentPoint = {
position: Vector3;
originalPoint?: PointData;
pathId?: string;
startId?: string;
endId?: string;
};
/** --- A* Algorithm --- */
type AStarResult = {
@@ -153,16 +178,31 @@ function nodePathToEdges(
return edges;
}
type VehicleDetails = {
vehicleId: string;
vehiclePosition: [number, number, number];
};
type Manager = {
pathId: string;
vehicleId: string;
};
export default function PointHandler({
point,
setPaths,
paths,
// setPaths,
// paths,
setHoveredPoint,
hoveredLine,
hoveredPoint,
pointIndex,
points,
setSelected,
selected,
}: PointHandlerProps) {
const { isPlaying } = usePlayButtonStore();
const [multiPaths, setMultiPaths] = useState<
{ id: number; path: PathData }[]
>([]);
const pathIdRef = useRef(1); // To ensure unique incremental IDs
const { toolMode } = useToolMode();
const { activeTool } = useActiveTool();
const { scene, raycaster } = useThree();
@@ -172,29 +212,82 @@ export default function PointHandler({
const [initialPositions, setInitialPositions] = useState<{
paths?: any;
}>({});
const [selectedPoints, setSelectedPoints] = useState<PointData[]>([]);
const [shortestEdges, setShortestEdges] = useState<PathData>([]);
const [shortestPaths, setShortestPaths] = useState<PathData>([]);
const POINT_SNAP_THRESHOLD = 0.5; // Distance threshold for snapping in meters
const [selectedPointIndices, setSelectedPointIndices] = useState<number[]>(
[]
);
const [vehicleUuids, setVehicleUuids] = useState<any>();
const CAN_POINT_SNAP = true;
const CAN_ANGLE_SNAP = true;
const ANGLE_SNAP_DISTANCE_THRESHOLD = 0.5;
const [selectedPointIndices, setSelectedPointIndices] = useState<number[]>(
[]
);
const [shortestEdges, setShortestEdges] = useState<PathData>([]);
const { speed } = useAnimationPlaySpeed();
const { assetStore } = useSceneContext();
const { assets } = assetStore();
const vehicleMovementState = useRef<any>({});
const [activeVehicleIndex, setActiveVehicleIndex] = useState(0);
const [vehicleData, setVehicleData] = useState<VehicleDetails[]>([]);
const { paths, setPaths } = useCreatedPaths();
const [managerData, setManagerData] = useState<Manager>();
// useEffect(() => {
// const findVehicle = assets
// .filter((val) => val.eventData?.type === "Vehicle")
// ?.map((val) => val.modelUuid);
//
// setVehicleUuids(findVehicle);
// vehicleMovementState.current = {};
// findVehicle.forEach((uuid) => {
// vehicleMovementState.current[uuid] = { index: 0, progress: 0 };
// });
// }, [assets]);
useEffect(() => {
const findVehicle = assets
.filter((val) => val.eventData?.type === "Vehicle")
?.map((val) => val.modelUuid);
const findVehicleDatas = assets
.filter((val) => val.eventData?.type === "Vehicle")
?.map((val) => val);
findVehicleDatas.forEach((val) => {
const vehicledId = val.modelUuid;
const vehiclePosition: [number, number, number] = val.position;
setVehicleData((prev) => [
...prev,
{ vehicleId: vehicledId, vehiclePosition },
]);
});
setVehicleUuids(findVehicle);
setActiveVehicleIndex(0); // Reset to first vehicle
vehicleMovementState.current = {};
findVehicle.forEach((uuid) => {
vehicleMovementState.current[uuid] = {
index: 0,
progress: 0,
hasStarted: false,
};
});
}, [assets]);
const removePathByPoint = (pointId: string): PathDataInterface[] => {
const removedPaths: PathDataInterface[] = [];
setPaths((prevPaths) =>
prevPaths.filter((path) => {
const hasPoint = path.pathPoints.some((p) => p.pointId === pointId);
const newPaths = paths.filter((path: PathDataInterface) => {
const hasPoint = path.pathPoints.some(
(p: PointData) => p.pointId === pointId
);
if (hasPoint) {
removedPaths.push(JSON.parse(JSON.stringify(path))); // keep a copy
return false; // remove this path
}
return true; // keep this path
})
);
});
setPaths(newPaths);
return removedPaths;
};
@@ -288,8 +381,8 @@ export default function PointHandler({
const getAllOtherPathPoints = useCallback((): PointData[] => {
return (
paths?.flatMap((path) =>
path.pathPoints.filter((pt) => pt.pointId !== point.pointId)
paths?.flatMap((path: PathDataInterface) =>
path.pathPoints.filter((pt: PointData) => pt.pointId !== point.pointId)
) ?? []
);
}, [paths]);
@@ -317,43 +410,7 @@ export default function PointHandler({
},
[getAllOtherPathPoints]
);
let isHandlingShiftClick = false;
// const handlePointClick = (e: any, point: PointData) => {
// if (toolMode === "3D-Delete") {
// removePathByPoint(point.pointId);
// }
// if (e.shiftKey) {
// setSelectedPointIndices((prev) => {
// if (prev.length === 0) return [pointIndex];
// if (prev.length === 1) {
// // defer shortest path calculation
// setTimeout(() => {
// console.log("points: ", points);
// const p1 = points[prev[0]];
// console.log(' p1: ', p1);
// const p2 = points[pointIndex];
// console.log('p2: ', p2);
// const result = aStarShortestPath(
// p1.pointId,
// p2.pointId,
// points,
// paths
// );
// if (result) {
// const edges = nodePathToEdges(result.pointIds, points, paths);
// console.log("edges: ", edges);
// setShortestEdges(edges);
// } else {
// setShortestEdges([]);
// }
// }, 0);
// return [prev[0], pointIndex];
// }
// return [pointIndex];
// });
// }
// };
const handlePointClick = (e: any, point: PointData) => {
e.stopPropagation();
if (toolMode === "3D-Delete") {
@@ -362,53 +419,82 @@ export default function PointHandler({
}
if (e.shiftKey) {
if (isHandlingShiftClick) return; // prevent double-handling
isHandlingShiftClick = true;
setTimeout(() => {
isHandlingShiftClick = false;
}, 100); // reset the flag after a short delay
setSelectedPointIndices((prev) => {
// console.log("Clicked point index:", pointIndex);
console.log("Previous selection:", prev);
const pointIndex = points.findIndex((p) => p.pointId === point.pointId);
if (pointIndex === -1) {
return;
}
setSelected((prev) => {
if (prev.length === 0) {
console.log("first works");
return [pointIndex];
}
// if (prev.length === 1) {
// setTimeout(() => {
//
// const prevPoint = points[prev[0]];
//
// const newPoint = points[pointIndex];
//
// const result = aStarShortestPath(
// prevPoint.pointId,
// newPoint.pointId,
// points,
// paths
// );
// if (result) {
// const edges = nodePathToEdges(result.pointIds, points, paths);
//
// setShortestPaths(edges);
// setShortestEdges(edges);
// } else {
// setShortestPaths([]);
// setShortestEdges([]);
// }
// if (prevPoint.pointId === newPoint.pointId) {
// return prev;
// }
// }, 0);
// return [prev[0], pointIndex];
// }
// More than two points — reset
if (prev.length === 1) {
if (prev[0] === pointIndex) {
console.log("Same point selected twice — ignoring");
return prev;
}
setTimeout(() => {
const prevPoint = points[prev[0]];
const newPoint = points[pointIndex];
const p1 = points[prev[0]];
const p2 = points[pointIndex];
if (prevPoint.pointId === newPoint.pointId) return;
console.log("Point 1:", p1);
console.log("Point 2:", p2);
if (p1 && p2) {
const result = aStarShortestPath(
p1.pointId,
p2.pointId,
prevPoint.pointId,
newPoint.pointId,
points,
paths
);
if (result) {
const edges = nodePathToEdges(result.pointIds, points, paths);
// Create a new path object
const newPathObj = {
id: pathIdRef.current++,
path: edges,
};
setShortestPaths(edges);
setShortestEdges(edges);
} else {
setShortestEdges([]);
}
// Append it to the list of paths
setMultiPaths((prevPaths) => [...prevPaths, newPathObj]);
}
// Reset selection to allow new pair selection
}, 0);
return [prev[0], pointIndex];
}
setShortestPaths([]);
return [pointIndex];
});
}
@@ -426,6 +512,7 @@ export default function PointHandler({
setInitialPositions({ paths: pathIntersection });
}
};
const handleDrag = (point: PointData) => {
if (isHovered && dragOffset) {
const intersectionPoint = new Vector3();
@@ -442,7 +529,7 @@ export default function PointHandler({
// ✅ Pass newPosition and pointId
const pathSnapped = snapPathAngle(newPosition, point.pointId);
const finalSnapped = snapPathPoint(pathSnapped.position);
setPathPosition(point.pointId, finalSnapped.position, setPaths);
setPathPosition(point.pointId, finalSnapped.position, setPaths, paths);
}
}
};
@@ -454,10 +541,265 @@ export default function PointHandler({
}
};
useEffect(() => {
console.log("selectedPoints: ", selectedPoints);
}, [selectedPoints]);
const pathSegments = useMemo(() => {
if (!shortestPaths || shortestPaths.length === 0) return [];
const segments: SegmentPoint[] = [];
shortestPaths.forEach((path) => {
const [start, end] = path.pathPoints;
const startPos = new Vector3(...start.position);
const endPos = new Vector3(...end.position);
segments.push(
{ position: startPos, originalPoint: start, startId: start.pointId },
{ position: endPos, originalPoint: end, endId: end.pointId }
);
});
return segments.filter(
(v, i, arr) => i === 0 || !v.position.equals(arr[i - 1].position)
);
}, [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,
endId: string | undefined,
shortestPaths: any[]
) {
for (const path of shortestPaths) {
for (let i = 0; i < path.pathPoints.length - 1; i++) {
const s = path.pathPoints[i];
const e = path.pathPoints[i + 1];
if (
(s.pointId === startId && e.pointId === endId) ||
(s.pointId === endId && e.pointId === startId) // handle both directions
) {
return path.pathId;
}
}
}
return null; // not found
}
//
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;
// Step 1: Move vehicle to the start of the path
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; // start path animation next frame
return;
}
// Move toward path start
const direction = pathStart.clone().sub(object.position);
const distance = direction.length();
if (distance > step) {
direction.normalize();
object.position.add(direction.clone().multiplyScalar(step));
// ROTATE toward direction of movement
const forward = new Vector3(0, 0, 1); // <-- adjust this based on your model
const targetQuat = new Quaternion().setFromUnitVectors(
forward,
direction
);
object.quaternion.slerp(targetQuat, 0.1); // smooth rotation
} else {
// Snap to start segment when close enough
object.position.copy(pathStart);
object.quaternion.identity(); // reset orientation or leave as-is
vehicleMovementState.current[uuid] = { index: 0, progress: 0 };
}
return; // still approaching start
}
// 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) {
// Path complete
state.index = 0;
state.progress = 0;
state.hasStarted = false; // reset for next loop
object.position.copy(vehicleStartPos); // go back to start
object.quaternion.identity();
// Move to next vehicle
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 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);
// });
useEffect(() => {}, [multiPaths]);
const manager = usePathManager(managerData?.pathId, managerData?.vehicleId);
useEffect(() => {
// if (managerData) {
// console.log("manager: ", manager);
// }
}, [managerData]);
return (
<>
<DragControls
@@ -496,6 +838,14 @@ export default function PointHandler({
<meshBasicMaterial color="pink" />
</mesh>
</DragControls>
{shortestEdges.map((edge) => (
<Line
key={`sp-${edge.pathId}`}
points={edge.pathPoints.map((p) => p.position)}
color="yellow"
lineWidth={3}
/>
))}
</>
);
}

View File

@@ -446,7 +446,7 @@ type PointData = {
interface PathDataInterface {
pathId: string;
pathPoints: [PointData, PointData]; // always two points
pathPoints: [PointData, PointData];
}
type PathData = PathDataInterface[];
@@ -616,11 +616,13 @@ export default function PointHandlers({
if (e.shiftKey) {
setSelected((prev) => {
console.log("prev: ", prev);
console.log("pointIndex: ", pointIndex);
if (prev.length === 0) return [pointIndex];
if (prev.length === 1) {
// defer shortest path calculation
setTimeout(() => {
console.log('points: ', points);
console.log("points: ", points);
const p1 = points[prev[0]];
const p2 = points[pointIndex];
const result = aStarShortestPath(
@@ -631,7 +633,7 @@ export default function PointHandlers({
);
if (result) {
const edges = nodePathToEdges(result.pointIds, points, paths);
console.log('edges: ', edges);
console.log("edges: ", edges);
setShortestEdges(edges);
setShortestPath(edges);
} else {
@@ -767,6 +769,8 @@ export default function PointHandlers({
}
});
return (
<>
{/* Main point */}

View File

@@ -33,7 +33,7 @@ function Vehicles() {
<PathCreator />
{/* <StructuredPath /> */}
{/* <PreDefinedPath /> */}
{/* <VehicleInstances /> */}
<VehicleInstances />
{isVehicleSelected && selectedEventSphere && !isPlaying && <VehicleUI />}
</>
);

View File

@@ -642,3 +642,30 @@ export const useContextActionStore = create<any>((set: any) => ({
contextAction: null,
setContextAction: (x: any) => set({ contextAction: x }),
}));
type PointData = {
pointId: string;
position: [number, number, number];
isCurved?: boolean;
handleA?: [number, number, number] | null;
handleB?: [number, number, number] | null;
};
interface PathDataInterface {
pathId: string;
isActive?: boolean;
isCurved?: boolean;
pathPoints: [PointData, PointData];
}
interface allPaths {
paths: string;
isAvailable: boolean;
vehicleId: string;
}
type PathData = PathDataInterface[];
export const useCreatedPaths = create<any>((set: any) => ({
paths: [],
setPaths: (x: PathData) => set({ paths: x }),
allPaths: [],
setAllPaths: (x: allPaths) => set({ allPaths: x }),
}));