first commit
This commit is contained in:
165
app/src/modules/simulation/vehicle/navMesh/polygonGenerator.tsx
Normal file
165
app/src/modules/simulation/vehicle/navMesh/polygonGenerator.tsx
Normal file
@@ -0,0 +1,165 @@
|
||||
import * as THREE from "three";
|
||||
import { useEffect } from "react";
|
||||
import * as turf from "@turf/turf";
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
import arrayLinesToObject from "../../../builder/geomentries/lines/lineConvertions/arrayLinesToObject";
|
||||
import { useAisleStore } from "../../../../store/builder/useAisleStore";
|
||||
import { useThree } from "@react-three/fiber";
|
||||
import { clone } from "chart.js/dist/helpers/helpers.core";
|
||||
|
||||
interface PolygonGeneratorProps {
|
||||
groupRef: React.MutableRefObject<THREE.Group | null>;
|
||||
lines: Types.RefLines;
|
||||
}
|
||||
|
||||
export default function PolygonGenerator({
|
||||
groupRef,
|
||||
lines,
|
||||
}: PolygonGeneratorProps) {
|
||||
const { aisles } = useAisleStore();
|
||||
const { scene } = useThree();
|
||||
|
||||
useEffect(() => {
|
||||
let allLines = arrayLinesToObject(lines.current);
|
||||
const wallLines = allLines?.filter((line) => line?.type === "WallLine");
|
||||
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 = wallLines
|
||||
.map((pair) => pair?.line.map((vals) => vals.position))
|
||||
.filter((wall): wall is THREE.Vector3[] => !!wall);
|
||||
|
||||
|
||||
if (!result || result.some((line) => !line)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const lineFeatures = result?.map((line: any) =>
|
||||
turf.lineString(line.map((p: any) => p?.position))
|
||||
);
|
||||
|
||||
const validLineFeatures = lineFeatures.filter((line) => {
|
||||
const coords = line.geometry.coordinates;
|
||||
return coords.length >= 2;
|
||||
});
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}, [lines.current, aisles, scene]);
|
||||
|
||||
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;
|
||||
}
|
||||
Reference in New Issue
Block a user