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