Dwinzo_dev/app/src/modules/builder/agv/pathNavigator.tsx

150 lines
4.8 KiB
TypeScript
Raw Normal View History

import React, { useEffect, useState, useRef } from "react";
2025-03-26 12:58:14 +00:00
import * as THREE from "three";
2025-04-02 13:42:14 +00:00
import { useFrame, useThree } from "@react-three/fiber";
2025-03-26 12:58:14 +00:00
import { NavMeshQuery } from "@recast-navigation/core";
import { Line } from "@react-three/drei";
2025-04-02 13:42:14 +00:00
import { useTh } from "leva/dist/declarations/src/styles";
import { useActiveTool } from "../../../store/store";
2025-03-26 12:58:14 +00:00
// Define interface for props
interface PathNavigatorProps {
navMesh: any;
selectedPoints: any;
2025-04-02 13:42:14 +00:00
id: string;
}
2025-03-26 12:58:14 +00:00
export default function PathNavigator({
navMesh,
selectedPoints,
2025-04-02 13:42:14 +00:00
id,
}: PathNavigatorProps) {
const [path, setPath] = useState<[number, number, number][]>([]);
const progressRef = useRef(0);
2025-04-02 13:42:14 +00:00
const distancesRef = useRef<number[]>([]);
const totalDistanceRef = useRef(0);
const currentSegmentIndex = useRef(0);
const { scene } = useThree();
const { activeTool } = useActiveTool();
const [startPoint, setStartPoint] = useState(new THREE.Vector3());
const meshRef = useRef<THREE.Mesh | null>(null);
2025-04-02 13:42:14 +00:00
useEffect(() => {
if (!scene || !id || path.length < 2) return;
let totalDistance = 0;
const distances: number[] = [];
for (let i = 0; i < path.length - 1; i++) {
const start = new THREE.Vector3(...path[i]);
const end = new THREE.Vector3(...path[i + 1]);
const segmentDistance = start.distanceTo(end);
distances.push(segmentDistance);
totalDistance += segmentDistance;
}
2025-03-26 12:58:14 +00:00
2025-04-02 13:42:14 +00:00
distancesRef.current = distances;
totalDistanceRef.current = totalDistance;
progressRef.current = 0; // Reset progress when the path changes
}, [path]);
useEffect(() => {
2025-04-02 13:42:14 +00:00
if (!navMesh || selectedPoints.length === 0) return;
2025-03-26 12:58:14 +00:00
2025-04-02 13:42:14 +00:00
// Flatten the selectedPoints array into a single list of points
const allPoints = selectedPoints.flat();
2025-03-26 12:58:14 +00:00
2025-04-02 13:42:14 +00:00
// Compute paths between consecutive points
const computedPath: [number, number, number][] = [];
for (let i = 0; i < allPoints.length - 1; i++) {
const start = allPoints[i];
setStartPoint(
new THREE.Vector3(allPoints[0].x, allPoints[0].y, allPoints[0].z)
);
2025-03-26 12:58:14 +00:00
2025-04-02 13:42:14 +00:00
const end = allPoints[i + 1];
try {
const navMeshQuery = new NavMeshQuery(navMesh);
const { path: segmentPath } = navMeshQuery.computePath(start, end);
if (segmentPath && segmentPath.length > 0) {
computedPath.push(
...segmentPath.map(({ x, y, z }): [number, number, number] => [
x,
y + 0.1,
z,
])
);
}
} catch (error) {}
}
// Set the full computed path
if (computedPath.length > 0) {
setPath(computedPath);
currentSegmentIndex.current = 0; // Reset to the first segment
2025-03-26 12:58:14 +00:00
}
2025-04-02 13:42:14 +00:00
}, [selectedPoints, navMesh, path]);
2025-03-26 12:58:14 +00:00
useFrame((_, delta) => {
2025-04-02 13:42:14 +00:00
if (!scene || !id || path.length < 2) return;
2025-04-02 13:42:14 +00:00
// Find the object in the scene
const findObject = scene.getObjectByProperty("uuid", id);
if (activeTool === "play") {
if (!findObject) return;
const speed = 5;
progressRef.current += delta * speed;
2025-03-26 12:58:14 +00:00
let coveredDistance = progressRef.current;
let accumulatedDistance = 0;
let index = 0;
2025-04-02 13:42:14 +00:00
// Determine the current segment of the path
2025-03-26 12:58:14 +00:00
while (
2025-04-02 13:42:14 +00:00
index < distancesRef.current.length &&
coveredDistance > accumulatedDistance + distancesRef.current[index]
2025-03-26 12:58:14 +00:00
) {
2025-04-02 13:42:14 +00:00
accumulatedDistance += distancesRef.current[index];
2025-03-26 12:58:14 +00:00
index++;
}
2025-04-02 13:42:14 +00:00
// If the object has reached the end of the path, stop moving
if (index >= distancesRef.current.length) {
progressRef.current = totalDistanceRef.current;
return;
2025-03-26 12:58:14 +00:00
}
2025-04-02 13:42:14 +00:00
// Interpolate position within the current segment
const start = new THREE.Vector3(...path[index]);
const end = new THREE.Vector3(...path[index + 1]);
const segmentDistance = distancesRef.current[index];
const t = (coveredDistance - accumulatedDistance) / segmentDistance;
const position = start.clone().lerp(end, t);
findObject.position.copy(position);
// Rotate the object to face the direction of movement
const direction = new THREE.Vector3().subVectors(end, start).normalize();
const targetQuaternion = new THREE.Quaternion().setFromUnitVectors(
new THREE.Vector3(0, 0, 1), // Assuming forward direction is (0, 0, 1)
direction
);
findObject.quaternion.slerp(targetQuaternion, 0.1); // Smoothly interpolate rotation
} else if (activeTool === "cursor") {
findObject?.position.copy(startPoint);
2025-03-26 12:58:14 +00:00
}
});
return (
<>
2025-04-02 13:42:14 +00:00
{path.length > 0 && <Line points={path} color="blue" lineWidth={3} />}
{/* {path.length > 0 && (
2025-03-26 12:58:14 +00:00
<mesh ref={meshRef} position={path.length > 0 ? path[0] : [0, 0.1, 0]}>
<boxGeometry args={[1, 1, 1]} />
<meshNormalMaterial />
</mesh>
2025-04-02 13:42:14 +00:00
)} */}
2025-03-26 12:58:14 +00:00
</>
);
}