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

141 lines
4.6 KiB
TypeScript
Raw Normal View History

2025-03-26 12:58:14 +00:00
import React, { useCallback, useEffect, useRef, useState } from "react";
import * as THREE from "three";
import { NavMeshQuery } from "@recast-navigation/core";
import { NavMesh as RecastNavMesh } from "@recast-navigation/core";
import { useFrame, useThree } from "@react-three/fiber";
import { Line } from "@react-three/drei";
interface Pair {
x: number;
y: number;
z: number;
}
interface PathProps {
navMesh: RecastNavMesh | null; // The navigation mesh
pathPoints: Pair[] | undefined; // Array of points (or undefined)
}
const PathNavigator = ({ navMesh, pathPoints }: PathProps) => {
const { scene, raycaster, gl } = useThree();
const [path, setPath] = useState<THREE.Vector3[]>([]); // Path is an array of THREE.Vector3
const [points, setSelectedPoints] = useState<THREE.Vector3[]>([]); // Path is an array of THREE.Vector3
const progressRef = useRef<number>(0);
const meshRef = useRef<THREE.Mesh>(null!);
const handleClick = useCallback(() => {
if (!navMesh) return;
const intersects = raycaster.intersectObjects(scene.children, true);
if (intersects.length > 0) {
const { point } = intersects[0];
const newPoint = { x: point.x, y: 0, z: point.z };
setSelectedPoints((prevPoints: THREE.Vector3[]) => {
if (prevPoints.length === 2) {
// If two points already exist, replace them with the new point
return [new THREE.Vector3(newPoint.x, newPoint.y, newPoint.z)];
}
// Otherwise, append the new point to the array
return [
...prevPoints,
new THREE.Vector3(newPoint.x, newPoint.y, newPoint.z),
];
});
}
}, [navMesh, scene]);
React.useEffect(() => {
if (points?.length === 2 && navMesh) {
const [start, end] = points;
console.log("start: ", start);
console.log("end: ", end);
const navMeshQuery = new NavMeshQuery(navMesh);
console.log("navMeshQuery: ", navMeshQuery);
const { path } = navMeshQuery.computePath(start, end);
console.log("paths: ", path);
// if (path.length > 0) {
// setPath(
// path.map((point) => {
// const newY = point.y + 0.1; // Increment the y-coordinate
// return new THREE.Vector3(point.x, newY, point.z); // Create a new Vector3
// })
// );
// progressRef.current = 0;
// }
}
}, [points,]);
useFrame((_, delta) => {
if (path.length > 1 && meshRef.current) {
const speed = 3;
progressRef.current += delta * speed;
let totalDistance = 0;
const distances = [];
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;
}
let coveredDistance = progressRef.current;
let accumulatedDistance = 0;
let index = 0;
while (
index < distances.length &&
coveredDistance > accumulatedDistance + distances[index]
) {
accumulatedDistance += distances[index];
index++;
}
if (index < distances.length) {
const start = new THREE.Vector3(...path[index]);
const end = new THREE.Vector3(...path[index + 1]);
const segmentDistance = distances[index];
const t = (coveredDistance - accumulatedDistance) / segmentDistance;
const position = start.lerp(end, t);
meshRef.current.position.copy(position);
const direction = new THREE.Vector3()
.subVectors(end, start)
.normalize();
const targetQuaternion = new THREE.Quaternion().setFromUnitVectors(
new THREE.Vector3(0, 0, 1),
direction
);
meshRef.current.quaternion.slerp(targetQuaternion, 0.1);
} else {
progressRef.current = totalDistance;
}
}
});
useEffect(() => {
gl.domElement.addEventListener("click", handleClick);
return () => gl.domElement.removeEventListener("click", handleClick);
}, [handleClick]);
return (
<>
{path.length > 0 && <Line points={path} color="blue" lineWidth={3} />}
{path.length > 0 && (
// <primitive
// ref={gltfRef}
// object={gltfClone}
// position={path.length > 0 ? path[0] : [0, 0.1, 0]}
// scale={[0.5, 0.5, 0.5]}
// />
<mesh ref={meshRef} position={path.length > 0 ? path[0] : [0, 0.1, 0]}>
<boxGeometry args={[1, 1, 1]} />
<meshNormalMaterial />
</mesh>
)}
</>
);
};
export default PathNavigator;