Files
Dwinzo_Demo/app/src/modules/simulation/vehicle/navMesh/polygonGenerator.tsx

171 lines
6.1 KiB
TypeScript

import * as THREE from "three";
import { useEffect } from "react";
import * as turf from "@turf/turf";
import * as Types from "../../../../types/world/worldTypes";
import { useThree } from "@react-three/fiber";
import { useSceneContext } from "../../../scene/sceneContext";
interface PolygonGeneratorProps {
groupRef: React.MutableRefObject<THREE.Group | null>;
}
export default function PolygonGenerator({
groupRef,
}: PolygonGeneratorProps) {
const { aisleStore, wallStore } = useSceneContext();
const { aisles } = aisleStore();
const { scene } = useThree();
const { walls } = wallStore();
useEffect(() => {
const result = aisles
.filter(
(aisle) =>
aisle.type.aisleType === "dotted-aisle" ||
aisle.type.aisleType === "solid-aisle" ||
aisle.type.aisleType === "dashed-aisle" ||
aisle.type.aisleType === "arc-aisle"
)
.map((aisle) =>
aisle.points.map((point) => ({
position: [point.position[0], point.position[2]],
uuid: point.pointUuid,
}))
);
const arcAndCircleResult = aisles
.filter(
(aisle) =>
aisle.type.aisleType === "circle-aisle" ||
aisle.type.aisleType === "arc-aisle"
)
arcAndCircleResult.forEach((arc) => {
const arcGroup = scene.getObjectByProperty("uuid", arc.aisleUuid);
if (!arcGroup) return;
const cloned = arcGroup?.clone();
cloned.position.set(cloned.position.x, cloned.position.y + 5, cloned.position.z);
cloned?.traverse((child) => {
if (child instanceof THREE.Mesh && child.geometry instanceof THREE.ExtrudeGeometry) {
const extrudeGeometry = child.geometry as THREE.ExtrudeGeometry;
extrudeGeometry.scale(1, 1, 500);
child.geometry = extrudeGeometry;
child.position.set(cloned.position.x, cloned.position.y + 0.1, cloned.position.z)
child.rotateX(Math.PI / 2);
child.name = "agv-arc-collider"
groupRef.current?.add(child)
}
});
});
const wallPoints: THREE.Vector3[][] = walls
.map((wall) =>
wall.points.map((pt) => new THREE.Vector3(pt.position[0], pt.position[1], pt.position[2]))
)
.filter(points => points.length === 2);
if (!result || result.some((line) => !line)) {
return;
}
const lineFeatures = result?.map((line: any) =>
turf.lineString(line.map((p: any) => p?.position))
);
let validLineFeatures = lineFeatures.filter((line) => {
const coords = line.geometry.coordinates;
return coords.length >= 2;
}).filter((line) => {
if (line.geometry.coordinates[0].toString() !== line.geometry.coordinates[1].toString()) {
return true;
}
})
if (validLineFeatures.length < 3) { validLineFeatures = [] }
const polygons = turf.polygonize(turf.featureCollection(validLineFeatures));
renderWallGeometry(wallPoints);
if (polygons.features.length > 0) {
polygons.features.forEach((feature) => {
if (feature.geometry.type === "Polygon") {
const shape = new THREE.Shape();
const coords = feature.geometry.coordinates[0];
shape.moveTo(coords[0][0], coords[0][1]);
for (let i = 1; i < coords.length; i++) {
shape.lineTo(coords[i][0], coords[i][1]);
}
shape.lineTo(coords[0][0], coords[0][1]);
const extrudeSettings = {
depth: 5,
bevelEnabled: false,
};
const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
const material = new THREE.MeshBasicMaterial({ color: "blue", transparent: true, opacity: 0.5 });
const mesh = new THREE.Mesh(geometry, material);
mesh.rotateX(Math.PI / 2);
mesh.name = "agv-collider";
mesh.position.y = 5;
mesh.receiveShadow = true;
groupRef.current?.add(mesh);
}
});
}
}, [aisles, scene, walls]);
const renderWallGeometry = (walls: THREE.Vector3[][]) => {
walls.forEach((wall) => {
if (wall.length < 2) return;
for (let i = 0; i < wall.length - 1; i++) {
const start = new THREE.Vector3(wall[i].x, wall[i].y, wall[i].z);
const end = new THREE.Vector3(
wall[i + 1].x,
wall[i + 1].y,
wall[i + 1].z
);
const wallHeight = 10;
const direction = new THREE.Vector3().subVectors(end, start);
const length = direction.length();
direction.normalize();
const wallGeometry = new THREE.BoxGeometry(length, wallHeight);
const wallMaterial = new THREE.MeshBasicMaterial({
color: "#aaa",
transparent: true,
opacity: 0.5,
});
const wallMesh = new THREE.Mesh(wallGeometry, wallMaterial);
const midPoint = new THREE.Vector3()
.addVectors(start, end)
.multiplyScalar(0.5);
wallMesh.position.set(midPoint.x, wallHeight / 2, midPoint.z);
const quaternion = new THREE.Quaternion();
quaternion.setFromUnitVectors(new THREE.Vector3(1, 0, 0), direction);
wallMesh.quaternion.copy(quaternion);
wallMesh.name = "agv-collider";
groupRef.current?.add(wallMesh);
}
});
};
return null;
}