diff --git a/app/package-lock.json b/app/package-lock.json
index 5da4733..b5a2eda 100644
--- a/app/package-lock.json
+++ b/app/package-lock.json
@@ -2026,7 +2026,7 @@
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
"integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
- "dev": true,
+ "devOptional": true,
"dependencies": {
"@jridgewell/trace-mapping": "0.3.9"
},
@@ -2038,7 +2038,7 @@
"version": "0.3.9",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
"integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
- "dev": true,
+ "devOptional": true,
"dependencies": {
"@jridgewell/resolve-uri": "^3.0.3",
"@jridgewell/sourcemap-codec": "^1.4.10"
@@ -4180,6 +4180,26 @@
"url": "https://github.com/sponsors/gregberge"
}
},
+ "node_modules/@testing-library/dom": {
+ "version": "10.4.1",
+ "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz",
+ "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.10.4",
+ "@babel/runtime": "^7.12.5",
+ "@types/aria-query": "^5.0.1",
+ "aria-query": "5.3.0",
+ "dom-accessibility-api": "^0.5.9",
+ "lz-string": "^1.5.0",
+ "picocolors": "1.1.1",
+ "pretty-format": "^27.0.2"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/@testing-library/jest-dom": {
"version": "5.17.0",
"resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.17.0.tgz",
@@ -4291,25 +4311,25 @@
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz",
"integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==",
- "dev": true
+ "devOptional": true
},
"node_modules/@tsconfig/node12": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
"integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
- "dev": true
+ "devOptional": true
},
"node_modules/@tsconfig/node14": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
"integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
- "dev": true
+ "devOptional": true
},
"node_modules/@tsconfig/node16": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz",
"integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
- "dev": true
+ "devOptional": true
},
"node_modules/@turf/along": {
"version": "7.2.0",
@@ -9063,7 +9083,7 @@
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
- "dev": true
+ "devOptional": true
},
"node_modules/cross-env": {
"version": "7.0.3",
@@ -9940,7 +9960,7 @@
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
- "dev": true,
+ "devOptional": true,
"engines": {
"node": ">=0.3.1"
}
@@ -15324,7 +15344,7 @@
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
- "dev": true
+ "devOptional": true
},
"node_modules/makeerror": {
"version": "1.0.12",
@@ -20801,7 +20821,7 @@
"version": "10.9.2",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz",
"integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
- "dev": true,
+ "devOptional": true,
"dependencies": {
"@cspotcode/source-map-support": "^0.8.0",
"@tsconfig/node10": "^1.0.7",
@@ -20844,7 +20864,7 @@
"version": "8.3.4",
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz",
"integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==",
- "dev": true,
+ "devOptional": true,
"dependencies": {
"acorn": "^8.11.0"
},
@@ -20856,7 +20876,7 @@
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
- "dev": true
+ "devOptional": true
},
"node_modules/tsconfig-paths": {
"version": "3.15.0",
@@ -21352,7 +21372,7 @@
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
"integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
- "dev": true
+ "devOptional": true
},
"node_modules/v8-to-istanbul": {
"version": "8.1.1",
@@ -22411,7 +22431,7 @@
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
- "dev": true,
+ "devOptional": true,
"engines": {
"node": ">=6"
}
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..6908cf3 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..e2b264a 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..ec90f8d 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/builder/asset/assetsGroup.tsx b/app/src/modules/builder/asset/assetsGroup.tsx
index 89f7471..0215a9f 100644
--- a/app/src/modules/builder/asset/assetsGroup.tsx
+++ b/app/src/modules/builder/asset/assetsGroup.tsx
@@ -345,7 +345,7 @@ function AssetsGroup({ plane }: { readonly plane: RefMesh }) {
canvasElement.removeEventListener("mousemove", onMouseMove);
canvasElement.removeEventListener("mouseup", onMouseUp);
};
- }, [selectedItem, camera, pointer, activeModule, controls, isRenameMode]);
+ }, [selectedItem, camera, activeModule, controls, isRenameMode]);
return (
diff --git a/app/src/modules/builder/asset/models/model/model.tsx b/app/src/modules/builder/asset/models/model/model.tsx
index 1679b10..9cc0af4 100644
--- a/app/src/modules/builder/asset/models/model/model.tsx
+++ b/app/src/modules/builder/asset/models/model/model.tsx
@@ -162,8 +162,7 @@ function Model({ asset, isRendered }: { readonly asset: Asset, isRendered: boole
console.error(`[Backend] Error storing/loading ${asset.modelName}:`, error);
}
};
- loader.load(
- modelUrl,
+ loader.load(modelUrl,
handleBackendLoad,
undefined,
(error) => {
@@ -418,26 +417,26 @@ function Model({ asset, isRendered }: { readonly asset: Asset, isRendered: boole
castShadow
receiveShadow
onDoubleClick={(e) => {
- e.stopPropagation();
if (!toggleView) {
+ e.stopPropagation();
handleDblClick(asset);
}
}}
onClick={(e) => {
- e.stopPropagation();
if (!toggleView) {
+ e.stopPropagation();
handleClick(e, asset);
}
}}
onPointerOver={(e) => {
- e.stopPropagation();
if (!toggleView) {
+ e.stopPropagation();
handlePointerOver(asset);
}
}}
onPointerLeave={(e) => {
- e.stopPropagation();
if (!toggleView) {
+ e.stopPropagation();
handlePointerOut(e, asset);
}
}}
diff --git a/app/src/modules/builder/point/point.tsx b/app/src/modules/builder/point/point.tsx
index e62eb99..cf44c26 100644
--- a/app/src/modules/builder/point/point.tsx
+++ b/app/src/modules/builder/point/point.tsx
@@ -708,7 +708,6 @@ function Point({ point }: { readonly point: Point }) {
-
}
>
);
diff --git a/app/src/modules/builder/wall/Instances/instance/wall.tsx b/app/src/modules/builder/wall/Instances/instance/wall.tsx
index 1a73bfe..9023dc6 100644
--- a/app/src/modules/builder/wall/Instances/instance/wall.tsx
+++ b/app/src/modules/builder/wall/Instances/instance/wall.tsx
@@ -16,8 +16,10 @@ import defaultMaterial from '../../../../../assets/textures/floor/wall-tex.png';
import material1 from '../../../../../assets/textures/floor/factory wall texture.jpg';
function Wall({ wall }: { readonly wall: Wall }) {
- const { wallStore } = useSceneContext();
+ const { wallStore, wallAssetStore } = useSceneContext();
const { walls, addDecal } = wallStore();
+ const { wallAssets, getAssetsByWall } = wallAssetStore();
+ const assets = getAssetsByWall(wall.wallUuid);
const { selectedWall, setSelectedWall, setSelectedDecal } = useBuilderStore();
const { togglView } = useToggleView();
const { activeModule } = useModuleStore();
@@ -105,19 +107,35 @@ function Wall({ wall }: { readonly wall: Wall }) {
key={wall.wallUuid}
userData={wall}
>
-
- {materials.map((material, index) => (
-
- ))}
-
+ {(assets.length > 0 || (walls[0].wallUuid === wall.wallUuid && wallAssets.length > 0)) ?
+
+ {materials.map((material, index) => (
+
+ ))}
+
+ :
+
+ {materials.map((material, index) => (
+
+ ))}
+
+ }
{
const canvasElement = gl.domElement;
- const onPointerUp = () => {
+ const onPointerUp = (e: PointerEvent) => {
draggingRef.current = false;
if (controls) {
(controls as any).enabled = true;
}
+
+ if (selectedWallAsset) {
+ pointer.x = (e.clientX / window.innerWidth) * 2 - 1;
+ pointer.y = -(e.clientY / window.innerHeight) * 2 + 1;
+
+ raycaster.setFromCamera(pointer, camera);
+ const intersects = raycaster.intersectObjects(scene.children, true);
+ const intersect = intersects.find((i: any) => i.object.name.includes('WallReference'));
+
+ if (intersect && intersect.object.userData.wallUuid && selectedWallAsset.userData.modelUuid === wallAsset.modelUuid) {
+ const newPoint = closestPointOnLineSegment(
+ new THREE.Vector3(intersect.point.x, 0, intersect.point.z),
+ new THREE.Vector3(...intersect.object.userData.points[0].position),
+ new THREE.Vector3(...intersect.object.userData.points[1].position)
+ );
+
+ const wallRotation = intersect.object.rotation.clone();
+
+ const updatedWallAsset = updateWallAsset(wallAsset.modelUuid, {
+ wallUuid: intersect.object.userData.wallUuid,
+ position: [newPoint.x, wallAsset.wallAssetType === 'fixed-move' ? 0 : intersect.point.y, newPoint.z],
+ rotation: [wallRotation.x, wallRotation.y, wallRotation.z],
+ });
+
+ if (projectId && updatedWallAsset) {
+
+ // API
+
+ // upsertWallAssetApi(projectId, selectedVersion?.versionId || '', updatedWallAsset);
+
+ // SOCKET
+
+ const data = {
+ wallAssetData: updatedWallAsset,
+ projectId: projectId,
+ versionId: selectedVersion?.versionId || '',
+ userId: userId,
+ organization: organization
+ }
+
+ socket.emit('v1:wall-asset:add', data);
+
+ }
+ }
+ }
};
const onPointerMove = (e: any) => {
@@ -142,31 +187,11 @@ function WallAssetInstance({ wallAsset }: { wallAsset: WallAsset }) {
const wallRotation = intersect.object.rotation.clone();
- const updatedWallAsset = updateWallAsset(wallAsset.modelUuid, {
+ updateWallAsset(wallAsset.modelUuid, {
wallUuid: intersect.object.userData.wallUuid,
position: [newPoint.x, wallAsset.wallAssetType === 'fixed-move' ? 0 : intersect.point.y, newPoint.z],
rotation: [wallRotation.x, wallRotation.y, wallRotation.z],
});
-
- if (projectId && updatedWallAsset) {
-
- // API
-
- // upsertWallAssetApi(projectId, selectedVersion?.versionId || '', updatedWallAsset);
-
- // SOCKET
-
- const data = {
- wallAssetData: updatedWallAsset,
- projectId: projectId,
- versionId: selectedVersion?.versionId || '',
- userId: userId,
- organization: organization
- }
-
- socket.emit('v1:wall-asset:add', data);
-
- }
}
};
@@ -225,7 +250,7 @@ function WallAssetInstance({ wallAsset }: { wallAsset: WallAsset }) {
}
}, [activeTool, deletableWallAsset]);
- if (!gltfScene || !boundingBox || !wall) { return null }
+ if (!gltfScene || !boundingBox) { return null }
const size = new THREE.Vector3();
boundingBox.getSize(size);
const center = new THREE.Vector3();
@@ -242,7 +267,7 @@ function WallAssetInstance({ wallAsset }: { wallAsset: WallAsset }) {
visible={wallAsset.isVisible}
userData={wallAsset}
>
-
+
diff --git a/app/src/modules/scene/camera/camMode.tsx b/app/src/modules/scene/camera/camMode.tsx
index 2f03c97..77e2f31 100644
--- a/app/src/modules/scene/camera/camMode.tsx
+++ b/app/src/modules/scene/camera/camMode.tsx
@@ -9,124 +9,89 @@ import { detectModifierKeys } from "../../../utils/shortcutkeys/detectModifierKe
import { firstPersonCamera } from "./firstPersonCamera";
const CamMode: React.FC = () => {
- const { camMode, setCamMode } = useCamMode();
- const [, get] = useKeyboardControls();
- const [isTransitioning, setIsTransitioning] = useState(false);
- const state: any = useThree();
- const { toggleView } = useToggleView();
- const [isShiftActive, setIsShiftActive] = useState(false);
+ const { camMode, setCamMode } = useCamMode();
+ const [_, get] = useKeyboardControls();
+ const [isTransitioning, setIsTransitioning] = useState(false);
+ const state: any = useThree();
+ const { toggleView } = useToggleView();
+ const [isShiftActive, setIsShiftActive] = useState(false);
- useEffect(() => {
- const handlePointerLockChange = async () => {
- if (document.pointerLockElement && !toggleView) {
- // Pointer is locked
- } else if (camMode === "FirstPerson" && !toggleView) {
- // Pointer is unlocked
- setCamMode("ThirdPerson");
- await switchToThirdPerson(state.controls, state.camera);
- }
- };
+ useEffect(() => {
+ const handlePointerLockChange = async () => {
+ if (document.pointerLockElement && !toggleView) {
+ } else if (camMode === "FirstPerson" && !toggleView) {
+ setCamMode("ThirdPerson");
+ await switchToThirdPerson(state.controls, state.camera);
+ }
+ };
- document.addEventListener("pointerlockchange", handlePointerLockChange);
+ document.addEventListener("pointerlockchange", handlePointerLockChange);
- return () => {
- document.removeEventListener(
- "pointerlockchange",
- handlePointerLockChange
- );
- };
- }, [camMode, toggleView, setCamMode, state.controls, state.camera]);
+ return () => {
+ document.removeEventListener("pointerlockchange", handlePointerLockChange);
+ };
+ }, [camMode, toggleView, setCamMode, state.controls, state.camera]);
- useEffect(() => {
- const handleKeyDown = (event: KeyboardEvent) => {
- if (event.key === "Shift") {
- setIsShiftActive(true);
- }
- };
+ useEffect(() => {
+ const handleKeyPress = async (event: KeyboardEvent) => {
+ if (!state.controls) return;
- const handleKeyUp = (event: KeyboardEvent) => {
- if (event.key === "Shift") {
- setIsShiftActive(false);
- }
- };
+ const keyCombination = detectModifierKeys(event);
- window.addEventListener("keydown", handleKeyDown);
- window.addEventListener("keyup", handleKeyUp);
+ if (keyCombination === "/" && !isTransitioning && !toggleView) {
+ firstPersonCamera({
+ setIsTransitioning,
+ state,
+ camMode,
+ setCamMode,
+ switchToFirstPerson,
+ switchToThirdPerson,
+ });
+ }
- return () => {
- window.removeEventListener("keydown", handleKeyDown);
- window.removeEventListener("keyup", handleKeyUp);
- };
- }, []);
+ if (keyCombination === 'Shift') {
+ setIsShiftActive(true);
+ }
+ };
- useEffect(() => {
- const handleKeyPress = async (event: KeyboardEvent) => {
- if (!state.controls) return;
+ const handleKeyUp = (event: KeyboardEvent) => {
+ if (event.key === "Shift") {
+ setIsShiftActive(false);
+ }
+ };
- const keyCombination = detectModifierKeys(event);
+ window.addEventListener("keydown", handleKeyPress);
+ window.addEventListener("keyup", handleKeyUp);
- if (keyCombination === "/" && !isTransitioning && !toggleView) {
- firstPersonCamera({
- setIsTransitioning,
- state,
- camMode,
- setCamMode,
- switchToFirstPerson,
- switchToThirdPerson,
- });
- }
- };
+ return () => {
+ window.removeEventListener("keydown", handleKeyPress);
+ window.removeEventListener("keyup", handleKeyUp);
+ };
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [camMode, isTransitioning, toggleView, state.controls, state.camera, setCamMode]);
- window.addEventListener("keydown", handleKeyPress);
- return () => {
- window.removeEventListener("keydown", handleKeyPress);
- };
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [
- camMode,
- isTransitioning,
- toggleView,
- state.controls,
- state.camera,
- setCamMode,
- ]);
+ useFrame(() => {
+ const { forward, backward, left, right } = get();
+ if (!state.controls) return;
+ if (camMode === "ThirdPerson" || !document.pointerLockElement) return;
- useFrame(() => {
- const { forward, backward, left, right } = get();
- if (!state.controls) return;
- if (camMode === "ThirdPerson" || !document.pointerLockElement) return;
+ const speedMultiplier = isShiftActive ? 4 : 1;
- const speedMultiplier = isShiftActive ? 4 : 1;
+ if (forward) {
+ state.controls.forward(CONSTANTS.firstPersonControls.forwardSpeed * speedMultiplier, true);
+ }
+ if (backward) {
+ state.controls.forward(CONSTANTS.firstPersonControls.backwardSpeed * speedMultiplier, true);
+ }
+ if (left) {
+ state.controls.truck(CONSTANTS.firstPersonControls.leftSpeed * speedMultiplier, 0, true);
+ }
+ if (right) {
+ state.controls.truck(CONSTANTS.firstPersonControls.rightSpeed * speedMultiplier, 0, true);
+ }
+ });
- if (forward) {
- state.controls.forward(
- CONSTANTS.firstPersonControls.forwardSpeed * speedMultiplier,
- true
- );
- }
- if (backward) {
- state.controls.forward(
- CONSTANTS.firstPersonControls.backwardSpeed * speedMultiplier,
- true
- );
- }
- if (left) {
- state.controls.truck(
- CONSTANTS.firstPersonControls.leftSpeed * speedMultiplier,
- 0,
- true
- );
- }
- if (right) {
- state.controls.truck(
- CONSTANTS.firstPersonControls.rightSpeed * speedMultiplier,
- 0,
- true
- );
- }
- });
-
- return null; // This component does not render any UI
+ return null;
};
export default CamMode;
diff --git a/app/src/modules/scene/camera/switchView.tsx b/app/src/modules/scene/camera/switchView.tsx
index ce64e1f..b9501b3 100644
--- a/app/src/modules/scene/camera/switchView.tsx
+++ b/app/src/modules/scene/camera/switchView.tsx
@@ -1,73 +1,68 @@
-import * as THREE from "three";
-import { useEffect, useRef } from "react";
-import { useToggleView } from "../../../store/builder/store";
+import { useEffect } from "react";
import { useThree } from "@react-three/fiber";
-import { getCamera } from "../../../services/factoryBuilder/camera/getCameraApi";
-import * as CONSTANTS from '../../../types/world/worldConstants';
+import * as THREE from 'three';
+import { PerspectiveCamera, OrthographicCamera, CameraControls } from '@react-three/drei';
import { useParams } from "react-router-dom";
+import * as CONSTANTS from '../../../types/world/worldConstants';
+import { getCamera } from "../../../services/factoryBuilder/camera/getCameraApi";
import { getUserData } from "../../../functions/getUserData";
-import { CameraControls } from "@react-three/drei";
+import { useToggleView } from "../../../store/builder/store";
export default function SwitchView() {
- const { toggleView } = useToggleView();
- const state: any = useThree();
- const { set } = useThree();
- const perspectiveCamera = useRef(null);
- const orthoCamera = useRef(null);
- orthoCamera.current = new THREE.OrthographicCamera(-window.innerWidth / 2, window.innerWidth / 2, window.innerHeight / 2, -window.innerHeight / 2, 0.01, 1000);
- perspectiveCamera.current = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.01, 1000);
- const { projectId } = useParams();
- const { organization } = getUserData();
+ const { toggleView } = useToggleView();
+ const { controls } = useThree();
+ const { projectId } = useParams();
+ const { organization } = getUserData();
- useEffect(() => {
- if (!perspectiveCamera.current || !orthoCamera.current) return;
- if (toggleView) {
- orthoCamera.current.zoom = 10;
- orthoCamera.current.position.set(...CONSTANTS.twoDimension.defaultPosition);
- orthoCamera.current.lookAt(new THREE.Vector3(...CONSTANTS.twoDimension.defaultTarget));
- orthoCamera.current.updateProjectionMatrix();
- set({ camera: orthoCamera.current });
- orthoCamera.current.updateProjectionMatrix();
- } else if (!toggleView) {
- perspectiveCamera.current.position.set(...CONSTANTS.threeDimension.defaultPosition);
- perspectiveCamera.current.lookAt(new THREE.Vector3(...CONSTANTS.threeDimension.defaultTarget));
- set({ camera: perspectiveCamera.current });
- }
- }, [toggleView, set]);
+ useEffect(() => {
+ if (toggleView && controls) {
+ (controls as any).mouseButtons.left = CONSTANTS.twoDimension.leftMouse;
+ (controls as any).mouseButtons.right = CONSTANTS.twoDimension.rightMouse;
+ } else {
+ try {
+ getCamera(organization, localStorage.getItem('userId')!, projectId).then((data) => {
+ if (data && data.position && data.target) {
+ (controls as CameraControls)?.setPosition(data.position.x, data.position.y, data.position.z);
+ (controls as CameraControls)?.setTarget(data.target.x, data.target.y, data.target.z);
+ } else {
+ (controls as CameraControls)?.setPosition(...CONSTANTS.threeDimension.defaultPosition);
+ (controls as CameraControls)?.setTarget(...CONSTANTS.threeDimension.defaultTarget);
+ }
+ });
+ } catch (error) {
+ echo.error("Failed to retrieve camera position or target");
+ (controls as CameraControls)?.setPosition(...CONSTANTS.threeDimension.defaultPosition);
+ (controls as CameraControls)?.setTarget(...CONSTANTS.threeDimension.defaultTarget);
+ }
- useEffect(() => {
- if (toggleView && state.controls) {
- state.controls.mouseButtons.left = CONSTANTS.twoDimension.leftMouse;
- state.controls.mouseButtons.right = CONSTANTS.twoDimension.rightMouse;
- } else {
- try {
- getCamera(organization, localStorage.getItem('userId')!, projectId).then((data) => {
- if (data && data.position && data.target) {
- // state.controls?.setLookAt(data.position.x, data.position.y, data.position.z, data.target.x, data.target.y, data.target.z, true)
- state.controls?.setPosition(data.position.x, data.position.y, data.position.z);
- state.controls?.setTarget(data.target.x, data.target.y, data.target.z);
- } else {
- // state.controls?.setLookAt(...CONSTANTS.threeDimension.defaultPosition, ...CONSTANTS.threeDimension.defaultTarget, true);
- state.controls?.setPosition(...CONSTANTS.threeDimension.defaultPosition);
- state.controls?.setTarget(...CONSTANTS.threeDimension.defaultTarget);
- }
- });
- } catch (error) {
- echo.error("Failed to retrieve camera position or target");
- console.error("Failed to retrieve camera position or target:", error);
- // state.controls?.setLookAt(...CONSTANTS.threeDimension.defaultPosition, ...CONSTANTS.threeDimension.defaultTarget, true);
- state.controls?.setPosition(...CONSTANTS.threeDimension.defaultPosition);
- state.controls?.setTarget(...CONSTANTS.threeDimension.defaultTarget);
- }
+ if (controls) {
+ (controls as any).mouseButtons.left = CONSTANTS.threeDimension.leftMouse;
+ (controls as any).mouseButtons.right = CONSTANTS.threeDimension.rightMouse;
+ }
+ }
+ }, [toggleView, controls]);
- if (state.controls) {
- state.controls.mouseButtons.left = CONSTANTS.threeDimension.leftMouse;
- state.controls.mouseButtons.right = CONSTANTS.threeDimension.rightMouse;
- }
- }
- }, [toggleView, state.controls]);
-
- return (
- <>>
- );
+ return (
+ <>
+ {toggleView ? (
+ self.lookAt(new THREE.Vector3(...CONSTANTS.twoDimension.defaultTarget))}
+ />
+ ) : (
+ self.lookAt(new THREE.Vector3(...CONSTANTS.threeDimension.defaultTarget))}
+ />
+ )}
+ >
+ );
}
\ No newline at end of file
diff --git a/app/src/modules/scene/controls/controls.tsx b/app/src/modules/scene/controls/controls.tsx
index 77f234c..845a82d 100644
--- a/app/src/modules/scene/controls/controls.tsx
+++ b/app/src/modules/scene/controls/controls.tsx
@@ -13,16 +13,17 @@ import SelectionControls3D from "./selectionControls/selection3D/selectionContro
import TransformControl from "./transformControls/transformControls";
import { useParams } from "react-router-dom";
import { getUserData } from "../../../functions/getUserData";
+
import SelectionControls2D from "./selectionControls/selection2D/selectionControls2D";
import UndoRedo2DControls from "./undoRedoControls/undoRedo2D/undoRedo2DControls";
export default function Controls() {
const controlsRef = useRef(null);
+ const state = useThree();
const { toggleView } = useToggleView();
const { resetCamera, setResetCamera } = useResetCamera();
const { socket } = useSocketStore();
- const state = useThree();
const { projectId } = useParams();
const { userId, organization } = getUserData();
@@ -33,7 +34,6 @@ export default function Controls() {
}
getCamera(organization, userId, projectId).then((data) => {
- // console.log('data: ', data);
if (data && data.position && data.target) {
controlsRef.current?.setPosition(data.position.x, data.position.y, data.position.z);
controlsRef.current?.setTarget(data.target.x, data.target.y, data.target.z);
@@ -41,8 +41,7 @@ export default function Controls() {
controlsRef.current?.setPosition(...CONSTANTS.threeDimension.defaultPosition);
controlsRef.current?.setTarget(...CONSTANTS.threeDimension.defaultTarget);
}
- })
- .catch((error) => console.error("Failed to fetch camera data:", error));
+ }).catch((error) => console.error("Failed to fetch camera data:", error));
}, []);
useEffect(() => {
@@ -60,7 +59,6 @@ export default function Controls() {
socketId: socket.id,
projectId
};
- // console.log('CameracamData: ', camData);
socket.emit('v1:Camera:set', camData)
setResetCamera(false);
@@ -130,7 +128,7 @@ export default function Controls() {
camera={state.camera}
verticalDragToForward={true}
boundaryEnclosesCamera={true}
- dollyToCursor={toggleView}
+ dollyDragInverted
>
diff --git a/app/src/modules/scene/controls/selectionControls/selection3D/selectionControls3D.tsx b/app/src/modules/scene/controls/selectionControls/selection3D/selectionControls3D.tsx
index eb8bdae..c72da8b 100644
--- a/app/src/modules/scene/controls/selectionControls/selection3D/selectionControls3D.tsx
+++ b/app/src/modules/scene/controls/selectionControls/selection3D/selectionControls3D.tsx
@@ -333,6 +333,7 @@ const SelectionControls3D: React.FC = () => {
return (
<>
+
@@ -340,6 +341,7 @@ const SelectionControls3D: React.FC = () => {
+
>
);
};
diff --git a/app/src/modules/scene/environment/sky.tsx b/app/src/modules/scene/environment/sky.tsx
index 4a584ee..ee7f2d9 100644
--- a/app/src/modules/scene/environment/sky.tsx
+++ b/app/src/modules/scene/environment/sky.tsx
@@ -6,9 +6,9 @@ import * as CONSTANTS from '../../../types/world/worldConstants';
export default function Sun() {
const savedTheme: string | null = localStorage.getItem("theme");
- const { elevation, setElevation } = useElevation();
- const { sunPosition, setSunPosition } = useSunPosition();
- const { azimuth, setAzimuth } = useAzimuth();
+ const { elevation } = useElevation();
+ const { setSunPosition } = useSunPosition();
+ const { azimuth } = useAzimuth();
const [turbidity, setTurbidity] = useState(CONSTANTS.skyConfig.defaultTurbidity);
const sunPositionRef = useRef(new THREE.Vector3(0, 0, 0));
const [_, forceUpdate] = useState(0);
diff --git a/app/src/modules/scene/postProcessing/postProcessing.tsx b/app/src/modules/scene/postProcessing/postProcessing.tsx
index 16cb9bb..3b96455 100644
--- a/app/src/modules/scene/postProcessing/postProcessing.tsx
+++ b/app/src/modules/scene/postProcessing/postProcessing.tsx
@@ -1,4 +1,5 @@
-import { Bloom, EffectComposer, N8AO, Outline } from "@react-three/postprocessing";
+import { DepthOfField, Bloom, EffectComposer, N8AO, Outline } from "@react-three/postprocessing";
+import { useThree } from "@react-three/fiber";
import { BlendFunction } from "postprocessing";
import {
useDeletableFloorItem,
@@ -11,6 +12,7 @@ import { useEffect } from "react";
import { useBuilderStore } from "../../../store/builder/useBuilderStore";
export default function PostProcessing() {
+ const { scene } = useThree();
const { selectedPoints } = useSelectedPoints();
const { deletableFloorItem } = useDeletableFloorItem();
const { selectedWallItem } = useSelectedWallItem();
@@ -77,11 +79,16 @@ export default function PostProcessing() {
denoiseRadius={6}
denoiseSamples={16}
/>
+
{selectedWallAsset && (
{
e.preventDefault();
}}
+ performance={{ min: 0.9, max: 1.0 }}
onCreated={(e) => {
e.scene.background = layout === 'Main Layout' ? null : new Color(0x19191d);
}}
@@ -75,6 +76,7 @@ export default function Scene({ layout }: { readonly layout: 'Main Layout' | 'Co
+
);
diff --git a/app/src/modules/scene/setup/setup.tsx b/app/src/modules/scene/setup/setup.tsx
index 4a0d68d..71dcce7 100644
--- a/app/src/modules/scene/setup/setup.tsx
+++ b/app/src/modules/scene/setup/setup.tsx
@@ -2,7 +2,7 @@ import Sun from '../environment/sky'
import Shadows from '../environment/shadow'
import PostProcessing from '../postProcessing/postProcessing'
import Controls from '../controls/controls';
-import { Environment } from '@react-three/drei'
+import { AdaptiveDpr, AdaptiveEvents, Environment } from '@react-three/drei'
import background from "../../../assets/textures/hdr/mudroadpuresky2k.hdr";
// import { Perf } from 'r3f-perf';
@@ -23,6 +23,10 @@ function Setup() {
{/* */}
+
+
+
+
>
)
}
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]))
diff --git a/app/src/types/world/worldConstants.ts b/app/src/types/world/worldConstants.ts
index 71d9caf..04214c1 100644
--- a/app/src/types/world/worldConstants.ts
+++ b/app/src/types/world/worldConstants.ts
@@ -206,7 +206,7 @@ export const thirdPersonControls: ThirdPersonControls = {
polarRotateSpeed: 1, // Speed of rotation around the polar axis
truckSpeed: 2, // Speed of truck movement
maxDistance: 100, // Maximum distance from the target
- maxPolarAngle: Math.PI / 2 - 0.05, // Maximum polar angle
+ maxPolarAngle: Math.PI / 2, // Maximum polar angle
minZoom: 6, // Minimum zoom level
maxZoom: 100, // Maximum zoom level
targetOffset: 20, // Offset of the target from the camera