diff --git a/app/src/modules/builder/aisle/Instances/aisleInstances.tsx b/app/src/modules/builder/aisle/Instances/aisleInstances.tsx
index 7683457..cb4ca35 100644
--- a/app/src/modules/builder/aisle/Instances/aisleInstances.tsx
+++ b/app/src/modules/builder/aisle/Instances/aisleInstances.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect, useMemo } from 'react';
+import React, { useMemo } from 'react';
import { useToggleView } from '../../../../store/builder/store';
import AisleInstance from './instance/aisleInstance';
import Point from '../../point/point';
diff --git a/app/src/modules/builder/aisle/Instances/instance/aisleTypes/arrowsAisle.tsx b/app/src/modules/builder/aisle/Instances/instance/aisleTypes/arrowsAisle.tsx
index 8bc6fd5..c49388a 100644
--- a/app/src/modules/builder/aisle/Instances/instance/aisleTypes/arrowsAisle.tsx
+++ b/app/src/modules/builder/aisle/Instances/instance/aisleTypes/arrowsAisle.tsx
@@ -1,6 +1,6 @@
import * as THREE from 'three';
import { useMemo, useRef } from 'react';
-import { Extrude } from '@react-three/drei';
+import { Instances, Instance } from '@react-three/drei';
import * as Constants from '../../../../../../types/world/worldConstants';
import { useToolMode } from '../../../../../../store/builder/store';
import { useBuilderStore } from '../../../../../../store/builder/useBuilderStore';
@@ -10,8 +10,16 @@ function ArrowsAisle({ aisle }: { readonly aisle: Aisle }) {
const { toolMode } = useToolMode();
const { setSelectedAisle, hoveredPoint } = useBuilderStore();
- const arrows = useMemo(() => {
- if (aisle.points.length < 2 || aisle.type.aisleType !== 'arrows-aisle') return [];
+ const { arrowGeometry, arrowInstances } = useMemo(() => {
+ const result = {
+ arrowGeometry: null as THREE.ExtrudeGeometry | null,
+ arrowInstances: [] as {
+ position: [number, number, number];
+ rotation: [number, number, number];
+ }[],
+ };
+
+ if (aisle.points.length < 2 || aisle.type.aisleType !== 'arrows-aisle') return result;
const start = new THREE.Vector3(...aisle.points[0].position);
const end = new THREE.Vector3(...aisle.points[1].position);
@@ -24,69 +32,67 @@ function ArrowsAisle({ aisle }: { readonly aisle: Aisle }) {
direction.normalize();
const count = Math.floor((length + spacing) / (arrowLength + spacing));
+ const angle = Math.atan2(direction.x, direction.z) + Math.PI;
- const arrowShapes: { shape: THREE.Shape; position: THREE.Vector3; rotationY: number }[] = [];
+ const shape = new THREE.Shape();
+ const w = width * 0.8;
+ const h = arrowLength;
+
+ shape.moveTo(0, 0);
+ shape.lineTo(w, h * 0.6);
+ shape.lineTo(w * 0.4, h * 0.6);
+ shape.lineTo(w * 0.4, h);
+ shape.lineTo(-w * 0.4, h);
+ shape.lineTo(-w * 0.4, h * 0.6);
+ shape.lineTo(-w, h * 0.6);
+ shape.lineTo(0, 0);
+
+ result.arrowGeometry = new THREE.ExtrudeGeometry(shape, {
+ depth: 0.01,
+ bevelEnabled: false,
+ });
+
+ result.arrowGeometry.rotateX(Math.PI / 2);
for (let i = 0; i < count; i++) {
- const initialOffset = arrowLength;
- const center = new THREE.Vector3().copy(start).addScaledVector(direction, initialOffset + i * (arrowLength + spacing));
+ const offset = arrowLength + i * (arrowLength + spacing);
+ const center = new THREE.Vector3().copy(start).addScaledVector(direction, offset);
- const shape = new THREE.Shape();
- const w = width * 0.8;
- const h = arrowLength;
-
- shape.moveTo(0, 0);
- shape.lineTo(w, h * 0.6);
- shape.lineTo(w * 0.4, h * 0.6);
- shape.lineTo(w * 0.4, h);
- shape.lineTo(-w * 0.4, h);
- shape.lineTo(-w * 0.4, h * 0.6);
- shape.lineTo(-w, h * 0.6);
- shape.lineTo(0, 0);
-
- const angle = Math.atan2(direction.x, direction.z) + Math.PI;
-
- arrowShapes.push({ shape, position: center, rotationY: angle });
+ result.arrowInstances.push({
+ position: [center.x, 0, center.z],
+ rotation: [0, angle, 0],
+ });
}
- return arrowShapes;
+ return result;
}, [aisle]);
const handleClick = () => {
if (toolMode === 'move' && !hoveredPoint) {
setSelectedAisle(aisleRef.current);
}
- }
+ };
- if (arrows.length === 0) return null;
+ if (!arrowGeometry || arrowInstances.length === 0) return null;
return (
{
setSelectedAisle(null);
}}
>
- {arrows.map(({ shape, position, rotationY }, index) => (
-
-
-
-
-
- ))}
+
+
+ {arrowInstances.map(({ position, rotation }, i) => (
+
+ ))}
+
);
}
diff --git a/app/src/modules/builder/aisle/Instances/instance/aisleTypes/dashedAisle.tsx b/app/src/modules/builder/aisle/Instances/instance/aisleTypes/dashedAisle.tsx
index bbdad90..72fb3c7 100644
--- a/app/src/modules/builder/aisle/Instances/instance/aisleTypes/dashedAisle.tsx
+++ b/app/src/modules/builder/aisle/Instances/instance/aisleTypes/dashedAisle.tsx
@@ -1,6 +1,6 @@
import * as THREE from 'three';
import { useMemo, useRef } from 'react';
-import { Extrude } from '@react-three/drei';
+import { Instances, Instance } from '@react-three/drei';
import * as Constants from '../../../../../../types/world/worldConstants';
import { useToolMode } from '../../../../../../store/builder/store';
import { useBuilderStore } from '../../../../../../store/builder/useBuilderStore';
@@ -10,82 +10,71 @@ function DashedAisle({ aisle }: { readonly aisle: Aisle }) {
const { toolMode } = useToolMode();
const { setSelectedAisle, hoveredPoint } = useBuilderStore();
- const shapes = useMemo(() => {
+ const dashInstances = useMemo(() => {
if (aisle.points.length < 2 || aisle.type.aisleType !== 'dashed-aisle') return [];
const start = new THREE.Vector3(...aisle.points[0].position);
const end = new THREE.Vector3(...aisle.points[1].position);
+
const width = aisle.type.aisleWidth || 0.1;
const dashLength = aisle.type.dashLength || 0.5;
const gapLength = aisle.type.gapLength || 0.3;
- const direction = new THREE.Vector3().subVectors(end, start).normalize();
- const perp = new THREE.Vector3(-direction.z, 0, direction.x).normalize();
-
- const totalLength = new THREE.Vector3().subVectors(end, start).length();
+ const totalVec = new THREE.Vector3().subVectors(end, start);
+ const totalLength = totalVec.length();
+ const direction = totalVec.clone().normalize();
const segmentCount = Math.floor((totalLength + gapLength) / (dashLength + gapLength));
- const shapes = [];
- const directionNormalized = new THREE.Vector3().subVectors(end, start).normalize();
+ const instances = [];
for (let i = 0; i < segmentCount; i++) {
- const segmentStart = new THREE.Vector3().copy(start).addScaledVector(directionNormalized, i * (dashLength + gapLength));
- const segmentEnd = new THREE.Vector3().copy(segmentStart).addScaledVector(directionNormalized, dashLength);
+ const center = start.clone().addScaledVector(direction, i * (dashLength + gapLength) + dashLength / 2);
- const leftStart = new THREE.Vector3().copy(segmentStart).addScaledVector(perp, width / 2);
- const rightStart = new THREE.Vector3().copy(segmentStart).addScaledVector(perp, -width / 2);
- const leftEnd = new THREE.Vector3().copy(segmentEnd).addScaledVector(perp, width / 2);
- const rightEnd = new THREE.Vector3().copy(segmentEnd).addScaledVector(perp, -width / 2);
+ const rotationY = Math.atan2(direction.x, direction.z);
- const shape = new THREE.Shape();
- shape.moveTo(leftStart.x, leftStart.z);
- shape.lineTo(leftEnd.x, leftEnd.z);
- shape.lineTo(rightEnd.x, rightEnd.z);
- shape.lineTo(rightStart.x, rightStart.z);
- shape.closePath();
-
- shapes.push(shape);
+ instances.push({
+ position: [center.x, 0, center.z] as [number, number, number],
+ scale: [width, 0.001, dashLength] as [number, number, number],
+ rotation: [0, rotationY, 0] as [number, number, number],
+ });
}
- return shapes;
+ return instances;
}, [aisle]);
const handleClick = () => {
if (toolMode === 'move' && !hoveredPoint) {
setSelectedAisle(aisleRef.current);
}
- }
+ };
- if (shapes.length === 0) return null;
+ if (dashInstances.length === 0) return null;
return (
{
setSelectedAisle(null);
}}
>
- {shapes.map((shape, index) => (
-
-
+
+
+ {dashInstances.map((inst, i) => (
+
-
- ))}
+ ))}
+
);
}
-export default DashedAisle;
\ No newline at end of file
+export default DashedAisle;
diff --git a/app/src/modules/builder/aisle/Instances/instance/aisleTypes/dottedAisle.tsx b/app/src/modules/builder/aisle/Instances/instance/aisleTypes/dottedAisle.tsx
index bf17d08..e411269 100644
--- a/app/src/modules/builder/aisle/Instances/instance/aisleTypes/dottedAisle.tsx
+++ b/app/src/modules/builder/aisle/Instances/instance/aisleTypes/dottedAisle.tsx
@@ -1,6 +1,6 @@
import * as THREE from 'three';
import { useMemo, useRef } from 'react';
-import { Extrude } from '@react-three/drei';
+import { Instance, Instances } from '@react-three/drei';
import * as Constants from '../../../../../../types/world/worldConstants';
import { useToolMode } from '../../../../../../store/builder/store';
import { useBuilderStore } from '../../../../../../store/builder/useBuilderStore';
@@ -10,31 +10,20 @@ function DottedAisle({ aisle }: { readonly aisle: Aisle }) {
const { toolMode } = useToolMode();
const { setSelectedAisle, hoveredPoint } = useBuilderStore();
- const shapes = useMemo(() => {
+ const dotPositions = useMemo(() => {
if (aisle.points.length < 2 || aisle.type.aisleType !== 'dotted-aisle') return [];
const start = new THREE.Vector3(...aisle.points[0].position);
const end = new THREE.Vector3(...aisle.points[1].position);
- const width = aisle.type.dotRadius || 0.1;
const dotSpacing = aisle.type.gapLength || 0.5;
- const dotRadius = width * 0.6;
const totalLength = new THREE.Vector3().subVectors(end, start).length();
const dotCount = Math.floor((totalLength + (dotSpacing / 2)) / dotSpacing);
-
- const shapes = [];
const directionNormalized = new THREE.Vector3().subVectors(end, start).normalize();
- for (let i = 0; i < dotCount; i++) {
- const dotCenter = new THREE.Vector3().copy(start).addScaledVector(directionNormalized, i * dotSpacing + dotSpacing / 2);
-
- const shape = new THREE.Shape();
- shape.absarc(dotCenter.x, dotCenter.z, dotRadius, 0, Math.PI * 2, false);
-
- shapes.push(shape);
- }
-
- return shapes;
+ return Array.from({ length: dotCount }, (_, i) => {
+ return new THREE.Vector3().copy(start).addScaledVector(directionNormalized, i * dotSpacing + dotSpacing / 2);
+ });
}, [aisle]);
const handleClick = () => {
@@ -43,7 +32,14 @@ function DottedAisle({ aisle }: { readonly aisle: Aisle }) {
}
}
- if (shapes.length === 0) return null;
+ const { dotRadius, color } = useMemo(() => {
+ return {
+ dotRadius: aisle.type.aisleType === 'dotted-aisle' ? ((aisle.type as any).dotRadius || 0.1) * 0.6 : 0.06,
+ color: aisle.type.aisleColor || '#ffffff'
+ };
+ }, [aisle]);
+
+ if (dotPositions.length === 0) return null;
return (
{
setSelectedAisle(null);
}}
>
- {shapes.map((shape, index) => (
-
-
+
+
+ {dotPositions.map((position, index) => (
+
-
- ))}
+ ))}
+
);
}
diff --git a/app/src/modules/builder/aisle/aisleCreator/referenceAisle.tsx b/app/src/modules/builder/aisle/aisleCreator/referenceAisle.tsx
index 6ce66fe..38f0dbc 100644
--- a/app/src/modules/builder/aisle/aisleCreator/referenceAisle.tsx
+++ b/app/src/modules/builder/aisle/aisleCreator/referenceAisle.tsx
@@ -3,7 +3,7 @@ import * as THREE from 'three';
import { useFrame, useThree } from '@react-three/fiber';
import { useActiveLayer, useToolMode, useToggleView } from '../../../../store/builder/store';
import * as Constants from '../../../../types/world/worldConstants';
-import { Extrude, Html } from '@react-three/drei';
+import { Extrude, Html, Instance, Instances } from '@react-three/drei';
import { useBuilderStore } from '../../../../store/builder/useBuilderStore';
import { useDirectionalSnapping } from '../../point/helpers/useDirectionalSnapping';
import { usePointSnapping } from '../../point/helpers/usePointSnapping';
@@ -289,125 +289,119 @@ function SolidAisle({ aisle }: { readonly aisle: Aisle }) {
}
function DashedAisle({ aisle }: { readonly aisle: Aisle }) {
- const shapes = useMemo(() => {
+
+ const dashInstances = useMemo(() => {
if (aisle.points.length < 2 || aisle.type.aisleType !== 'dashed-aisle') return [];
const start = new THREE.Vector3(...aisle.points[0].position);
const end = new THREE.Vector3(...aisle.points[1].position);
+
const width = aisle.type.aisleWidth || 0.1;
const dashLength = aisle.type.dashLength || 0.5;
const gapLength = aisle.type.gapLength || 0.3;
- const direction = new THREE.Vector3().subVectors(end, start).normalize();
- const perp = new THREE.Vector3(-direction.z, 0, direction.x).normalize();
-
- const totalLength = new THREE.Vector3().subVectors(end, start).length();
+ const totalVec = new THREE.Vector3().subVectors(end, start);
+ const totalLength = totalVec.length();
+ const direction = totalVec.clone().normalize();
const segmentCount = Math.floor((totalLength + gapLength) / (dashLength + gapLength));
- const shapes = [];
- const directionNormalized = new THREE.Vector3().subVectors(end, start).normalize();
+ const instances = [];
for (let i = 0; i < segmentCount; i++) {
- const segmentStart = new THREE.Vector3().copy(start).addScaledVector(directionNormalized, i * (dashLength + gapLength));
- const segmentEnd = new THREE.Vector3().copy(segmentStart).addScaledVector(directionNormalized, dashLength);
+ const center = start.clone().addScaledVector(direction, i * (dashLength + gapLength) + dashLength / 2);
- const leftStart = new THREE.Vector3().copy(segmentStart).addScaledVector(perp, width / 2);
- const rightStart = new THREE.Vector3().copy(segmentStart).addScaledVector(perp, -width / 2);
- const leftEnd = new THREE.Vector3().copy(segmentEnd).addScaledVector(perp, width / 2);
- const rightEnd = new THREE.Vector3().copy(segmentEnd).addScaledVector(perp, -width / 2);
+ const rotationY = Math.atan2(direction.x, direction.z);
- const shape = new THREE.Shape();
- shape.moveTo(leftStart.x, leftStart.z);
- shape.lineTo(leftEnd.x, leftEnd.z);
- shape.lineTo(rightEnd.x, rightEnd.z);
- shape.lineTo(rightStart.x, rightStart.z);
- shape.closePath();
-
- shapes.push(shape);
+ instances.push({
+ position: [center.x, 0, center.z] as [number, number, number],
+ scale: [width, 0.001, dashLength] as [number, number, number],
+ rotation: [0, rotationY, 0] as [number, number, number],
+ });
}
- return shapes;
+ return instances;
}, [aisle]);
- if (shapes.length === 0) return null;
+ if (dashInstances.length === 0) return null;
return (
- {shapes.map((shape, index) => (
-
-
+
+
+ {dashInstances.map((inst, i) => (
+
-
- ))}
+ ))}
+
);
}
function DottedAisle({ aisle }: { readonly aisle: Aisle }) {
- const shapes = useMemo(() => {
+
+ const dotPositions = useMemo(() => {
if (aisle.points.length < 2 || aisle.type.aisleType !== 'dotted-aisle') return [];
const start = new THREE.Vector3(...aisle.points[0].position);
const end = new THREE.Vector3(...aisle.points[1].position);
- const width = aisle.type.dotRadius || 0.1;
const dotSpacing = aisle.type.gapLength || 0.5;
- const dotRadius = width * 0.6;
const totalLength = new THREE.Vector3().subVectors(end, start).length();
const dotCount = Math.floor((totalLength + (dotSpacing / 2)) / dotSpacing);
-
- const shapes = [];
const directionNormalized = new THREE.Vector3().subVectors(end, start).normalize();
- for (let i = 0; i < dotCount; i++) {
- const dotCenter = new THREE.Vector3().copy(start).addScaledVector(directionNormalized, i * dotSpacing + dotSpacing / 2);
-
- const shape = new THREE.Shape();
- shape.absarc(dotCenter.x, dotCenter.z, dotRadius, 0, Math.PI * 2, false);
-
- shapes.push(shape);
- }
-
- return shapes;
+ return Array.from({ length: dotCount }, (_, i) => {
+ return new THREE.Vector3().copy(start).addScaledVector(directionNormalized, i * dotSpacing + dotSpacing / 2);
+ });
}, [aisle]);
- if (shapes.length === 0) return null;
+ const { dotRadius, color } = useMemo(() => {
+ return {
+ dotRadius: aisle.type.aisleType === 'dotted-aisle' ? ((aisle.type as any).dotRadius || 0.1) * 0.6 : 0.06,
+ color: aisle.type.aisleColor || '#ffffff'
+ };
+ }, [aisle]);
+
+ if (dotPositions.length === 0) return null;
return (
- {shapes.map((shape, index) => (
-
-
+
+
+ {dotPositions.map((position, index) => (
+
-
- ))}
+ ))}
+
);
}
function ArrowsAisle({ aisle }: { readonly aisle: Aisle }) {
- const arrows = useMemo(() => {
- if (aisle.points.length < 2 || aisle.type.aisleType !== 'arrows-aisle') return [];
+
+ const { arrowGeometry, arrowInstances } = useMemo(() => {
+ const result = {
+ arrowGeometry: null as THREE.ExtrudeGeometry | null,
+ arrowInstances: [] as {
+ position: [number, number, number];
+ rotation: [number, number, number];
+ }[],
+ };
+
+ if (aisle.points.length < 2 || aisle.type.aisleType !== 'arrows-aisle') return result;
const start = new THREE.Vector3(...aisle.points[0].position);
const end = new THREE.Vector3(...aisle.points[1].position);
@@ -420,55 +414,53 @@ function ArrowsAisle({ aisle }: { readonly aisle: Aisle }) {
direction.normalize();
const count = Math.floor((length + spacing) / (arrowLength + spacing));
+ const angle = Math.atan2(direction.x, direction.z) + Math.PI;
- const arrowShapes: { shape: THREE.Shape; position: THREE.Vector3; rotationY: number }[] = [];
+ const shape = new THREE.Shape();
+ const w = width * 0.8;
+ const h = arrowLength;
+
+ shape.moveTo(0, 0);
+ shape.lineTo(w, h * 0.6);
+ shape.lineTo(w * 0.4, h * 0.6);
+ shape.lineTo(w * 0.4, h);
+ shape.lineTo(-w * 0.4, h);
+ shape.lineTo(-w * 0.4, h * 0.6);
+ shape.lineTo(-w, h * 0.6);
+ shape.lineTo(0, 0);
+
+ result.arrowGeometry = new THREE.ExtrudeGeometry(shape, {
+ depth: 0.01,
+ bevelEnabled: false,
+ });
+
+ result.arrowGeometry.rotateX(Math.PI / 2);
for (let i = 0; i < count; i++) {
- const initialOffset = arrowLength;
- const center = new THREE.Vector3().copy(start).addScaledVector(direction, initialOffset + i * (arrowLength + spacing));
+ const offset = arrowLength + i * (arrowLength + spacing);
+ const center = new THREE.Vector3().copy(start).addScaledVector(direction, offset);
- const shape = new THREE.Shape();
- const w = width * 0.8;
- const h = arrowLength;
-
- shape.moveTo(0, 0);
- shape.lineTo(w, h * 0.6);
- shape.lineTo(w * 0.4, h * 0.6);
- shape.lineTo(w * 0.4, h);
- shape.lineTo(-w * 0.4, h);
- shape.lineTo(-w * 0.4, h * 0.6);
- shape.lineTo(-w, h * 0.6);
- shape.lineTo(0, 0);
-
- const angle = Math.atan2(direction.x, direction.z) + Math.PI;
-
- arrowShapes.push({ shape, position: center, rotationY: angle });
+ result.arrowInstances.push({
+ position: [center.x, 0, center.z],
+ rotation: [0, angle, 0],
+ });
}
- return arrowShapes;
+ return result;
}, [aisle]);
- if (arrows.length === 0) return null;
+ if (!arrowGeometry || arrowInstances.length === 0) return null;
return (
- {arrows.map(({ shape, position, rotationY }, index) => (
-
-
-
-
-
- ))}
+
+
+ {arrowInstances.map(({ position, rotation }, i) => (
+
+ ))}
+
);
}
diff --git a/app/src/modules/simulation/vehicle/navMesh/polygonGenerator.tsx b/app/src/modules/simulation/vehicle/navMesh/polygonGenerator.tsx
index 19e9482..57f8ab2 100644
--- a/app/src/modules/simulation/vehicle/navMesh/polygonGenerator.tsx
+++ b/app/src/modules/simulation/vehicle/navMesh/polygonGenerator.tsx
@@ -40,7 +40,6 @@ export default function PolygonGenerator({
aisle.type.aisleType === "arc-aisle"
)
-
arcAndCircleResult.forEach((arc) => {
const arcGroup = scene.getObjectByProperty("uuid", arc.aisleUuid);
if (!arcGroup) return;
@@ -60,7 +59,6 @@ export default function PolygonGenerator({
});
});
-
const wallPoints: THREE.Vector3[][] = walls
.map((wall) =>
wall.points.map((pt) => new THREE.Vector3(pt.position[0], pt.position[1], pt.position[2]))