diff --git a/app/src/components/layout/sidebarRight/properties/AisleProperties.tsx b/app/src/components/layout/sidebarRight/properties/AisleProperties.tsx
index 96ef288..a613699 100644
--- a/app/src/components/layout/sidebarRight/properties/AisleProperties.tsx
+++ b/app/src/components/layout/sidebarRight/properties/AisleProperties.tsx
@@ -12,6 +12,7 @@ import Directional from "../../../../assets/image/aisleTypes/Directional.png";
import Dotted from "../../../../assets/image/aisleTypes/Dotted.png";
import Solid from "../../../../assets/image/aisleTypes/Solid.png";
import { useBuilderStore } from "../../../../store/builder/useBuilderStore";
+import InputToggle from "../../../ui/inputs/InputToggle";
interface TextureItem {
color: AisleColors;
@@ -24,7 +25,7 @@ const AisleProperties: React.FC = () => {
const [collapsePresets, setCollapsePresets] = useState(false);
const [collapseTexture, setCollapseTexture] = useState(true);
- const { aisleType, aisleWidth, aisleColor, dashLength, gapLength, dotRadius, aisleLength, setAisleType, setAisleColor, setAisleWidth, setDashLength, setGapLength, setDotRadius, setAisleLength } = useBuilderStore();
+ const { aisleType, aisleWidth, aisleColor, dashLength, gapLength, dotRadius, aisleLength, isFlipped, setAisleType, setAisleColor, setAisleWidth, setDashLength, setGapLength, setDotRadius, setAisleLength, setIsFlipped } = useBuilderStore();
const aisleTextureList: TextureItem[] = [
{ color: "yellow", id: "yellow1", brief: "pedestrian walkways", texture: "" },
@@ -90,6 +91,10 @@ const AisleProperties: React.FC = () => {
}
};
+ const handleIsFlippedChange = () => {
+ setIsFlipped(!aisleIsFlipped)
+ };
+
const dashLengthValue = useMemo(() => {
return dashLength.toString();
}, [aisleType, dashLength]);
@@ -110,6 +115,10 @@ const AisleProperties: React.FC = () => {
return aisleLength.toString();
}, [aisleType, aisleLength]);
+ const aisleIsFlipped = useMemo(() => {
+ return isFlipped;
+ }, [aisleType, isFlipped]);
+
const renderAdvancedProperties = () => {
switch (aisleType) {
case 'dashed-aisle':
@@ -185,6 +194,19 @@ const AisleProperties: React.FC = () => {
}
>
);
+ case 'junction-aisle':
+ return (
+ <>
+ {aisleType &&
+
+ }
+ >
+ )
default:
return null;
}
diff --git a/app/src/modules/builder/aisle/Instances/aisleInstances.tsx b/app/src/modules/builder/aisle/Instances/aisleInstances.tsx
index 8964434..227b2de 100644
--- a/app/src/modules/builder/aisle/Instances/aisleInstances.tsx
+++ b/app/src/modules/builder/aisle/Instances/aisleInstances.tsx
@@ -16,8 +16,8 @@ function AisleInstances() {
aisles.forEach(aisle => {
aisle.points.forEach(point => {
- if (!seenUuids.has(point.uuid)) {
- seenUuids.add(point.uuid);
+ if (!seenUuids.has(point.pointUuid)) {
+ seenUuids.add(point.pointUuid);
points.push(point);
}
});
@@ -27,7 +27,7 @@ function AisleInstances() {
}, [aisles]);
useEffect(() => {
- console.log('aisles: ', aisles);
+ // console.log('aisles: ', aisles);
}, [aisles]);
return (
@@ -35,7 +35,7 @@ function AisleInstances() {
{toggleView &&
{allPoints.map((point) => (
-
+
))}
}
@@ -46,13 +46,13 @@ function AisleInstances() {
const distance = new Vector3(...aisle.points[0].position).distanceTo(new Vector3(...aisle.points[1].position));
return (
- < React.Fragment key={aisle.uuid}>
-
+ < React.Fragment key={aisle.aisleUuid}>
+
{toggleView &&
{distance.toFixed(2)} m
diff --git a/app/src/modules/builder/aisle/Instances/instance/aisleInstance.tsx b/app/src/modules/builder/aisle/Instances/instance/aisleInstance.tsx
index 9afd3d6..c8ecdd7 100644
--- a/app/src/modules/builder/aisle/Instances/instance/aisleInstance.tsx
+++ b/app/src/modules/builder/aisle/Instances/instance/aisleInstance.tsx
@@ -1,6 +1,9 @@
+import ArrowAisle from './aisleTypes/arrowAisle';
import ArrowsAisle from './aisleTypes/arrowsAisle';
+import CircleAisle from './aisleTypes/circleAisle';
import DashedAisle from './aisleTypes/dashedAisle';
import DottedAisle from './aisleTypes/dottedAisle';
+import JunctionAisle from './aisleTypes/junctionAisle';
import SolidAisle from './aisleTypes/solidAisle';
function AisleInstance({ aisle }: { readonly aisle: Aisle }) {
@@ -22,6 +25,18 @@ function AisleInstance({ aisle }: { readonly aisle: Aisle }) {
{aisle.type.aisleType === 'arrows-aisle' && (
)}
+
+ {aisle.type.aisleType === 'arrow-aisle' && (
+
+ )}
+
+ {aisle.type.aisleType === 'circle-aisle' && (
+
+ )}
+
+ {aisle.type.aisleType === 'junction-aisle' && (
+
+ )}
>
);
}
diff --git a/app/src/modules/builder/aisle/Instances/instance/aisleTypes/arrowAisle.tsx b/app/src/modules/builder/aisle/Instances/instance/aisleTypes/arrowAisle.tsx
new file mode 100644
index 0000000..7a4e270
--- /dev/null
+++ b/app/src/modules/builder/aisle/Instances/instance/aisleTypes/arrowAisle.tsx
@@ -0,0 +1,88 @@
+import * as THREE from 'three';
+import { useMemo, useRef } from 'react';
+import { Extrude } from '@react-three/drei';
+import * as Constants from '../../../../../../types/world/worldConstants';
+import { useToolMode } from '../../../../../../store/builder/store';
+import { useBuilderStore } from '../../../../../../store/builder/useBuilderStore';
+
+function ArrowAisle({ aisle }: { readonly aisle: Aisle }) {
+ const aisleRef = useRef(null);
+ const { toolMode } = useToolMode();
+ const { setSelectedAisle, hoveredPoint } = useBuilderStore();
+
+ const arrow = useMemo(() => {
+ if (aisle.points.length < 2 || aisle.type.aisleType !== 'arrow-aisle') return null;
+
+ 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 direction = new THREE.Vector3().subVectors(end, start);
+ const length = direction.length();
+ direction.normalize();
+
+ const shape = new THREE.Shape();
+ const arrowHeadLength = width * 2;
+ const shaftLength = length - arrowHeadLength;
+
+ if (shaftLength > 0) {
+ shape.moveTo(0, 0);
+ shape.lineTo(width, -arrowHeadLength);
+ shape.lineTo(width / 2, -arrowHeadLength);
+ shape.lineTo(width / 2, -length);
+ shape.lineTo(-width / 2, -length);
+ shape.lineTo(-width / 2, -arrowHeadLength);
+ shape.lineTo(-width, -arrowHeadLength);
+ shape.lineTo(0, 0);
+ } else {
+ shape.moveTo(0, 0);
+ shape.lineTo(width, -length);
+ shape.lineTo(-width, -length);
+ shape.lineTo(0, 0);
+ }
+
+ shape.closePath();
+
+ const position = end;
+ const angle = Math.atan2(direction.x, direction.z);
+
+ return { shape, position, rotationY: angle };
+ }, [aisle]);
+
+ const handleClick = () => {
+ if (toolMode === 'move' && !hoveredPoint) {
+ setSelectedAisle(aisleRef.current);
+ }
+ }
+
+ if (!arrow) return null;
+
+ return (
+ {
+ setSelectedAisle(null);
+ }}
+ >
+
+
+
+
+
+
+ );
+}
+
+export default ArrowAisle;
\ No newline at end of file
diff --git a/app/src/modules/builder/aisle/Instances/instance/aisleTypes/circleAisle.tsx b/app/src/modules/builder/aisle/Instances/instance/aisleTypes/circleAisle.tsx
new file mode 100644
index 0000000..34caf99
--- /dev/null
+++ b/app/src/modules/builder/aisle/Instances/instance/aisleTypes/circleAisle.tsx
@@ -0,0 +1,82 @@
+import * as THREE from 'three';
+import { useMemo, useRef } from 'react';
+import { Extrude } from '@react-three/drei';
+import * as Constants from '../../../../../../types/world/worldConstants';
+import { useToolMode } from '../../../../../../store/builder/store';
+import { useBuilderStore } from '../../../../../../store/builder/useBuilderStore';
+
+function CircleAisle({ aisle }: { readonly aisle: Aisle }) {
+ const aisleRef = useRef(null);
+ const { toolMode } = useToolMode();
+ const { setSelectedAisle, hoveredPoint } = useBuilderStore();
+
+ const circle = useMemo(() => {
+ if (aisle.points.length < 2 || aisle.type.aisleType !== 'circle-aisle') return null;
+
+ const center = new THREE.Vector3(...aisle.points[0].position);
+ const widthCenter = new THREE.Vector3(...aisle.points[1].position);
+ const width = aisle.type.aisleWidth || 0.1;
+
+ const middleRadius = center.distanceTo(widthCenter);
+
+ const innerRadius = Math.max(0, middleRadius - width / 2);
+ const outerRadius = middleRadius + width / 2;
+
+ const shape = new THREE.Shape();
+ shape.absarc(0, 0, outerRadius, 0, Math.PI * 2, false);
+
+ if (innerRadius > 0) {
+ const hole = new THREE.Path();
+ hole.absarc(0, 0, innerRadius, 0, Math.PI * 2, true);
+ shape.holes.push(hole);
+ }
+
+ return {
+ shape,
+ position: center,
+ rotationY: 0
+ };
+ }, [aisle]);
+
+ const handleClick = () => {
+ if (toolMode === 'move' && !hoveredPoint) {
+ setSelectedAisle(aisleRef.current);
+ }
+ }
+
+ if (!circle) return null;
+
+ return (
+ {
+ setSelectedAisle(null);
+ }}
+ >
+
+
+
+
+
+
+ );
+}
+
+export default CircleAisle;
\ No newline at end of file
diff --git a/app/src/modules/builder/aisle/Instances/instance/aisleTypes/junctionAisle.tsx b/app/src/modules/builder/aisle/Instances/instance/aisleTypes/junctionAisle.tsx
new file mode 100644
index 0000000..52cab85
--- /dev/null
+++ b/app/src/modules/builder/aisle/Instances/instance/aisleTypes/junctionAisle.tsx
@@ -0,0 +1,125 @@
+import * as THREE from 'three';
+import { useMemo, useRef } from 'react';
+import { Extrude } from '@react-three/drei';
+import * as Constants from '../../../../../../types/world/worldConstants';
+import { useToolMode } from '../../../../../../store/builder/store';
+import { useBuilderStore } from '../../../../../../store/builder/useBuilderStore';
+
+function JunctionAisle({ aisle }: { readonly aisle: Aisle }) {
+ const aisleRef = useRef(null);
+ const { toolMode } = useToolMode();
+ const { setSelectedAisle, hoveredPoint } = useBuilderStore();
+
+ const arrows = useMemo(() => {
+ if (aisle.points.length < 2 || aisle.type.aisleType !== 'junction-aisle') return null;
+
+ 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 isFlipped = aisle.type.isFlipped || false;
+
+ const direction = new THREE.Vector3().subVectors(end, start);
+ const length = direction.length();
+ direction.normalize();
+
+ const mainShape = new THREE.Shape();
+ const arrowHeadLength = width * 2;
+ const shaftLength = length - arrowHeadLength;
+
+ if (shaftLength > 0) {
+ mainShape.moveTo(0, 0);
+ mainShape.lineTo(width, -arrowHeadLength);
+ mainShape.lineTo(width / 2, -arrowHeadLength);
+ mainShape.lineTo(width / 2, -length);
+ mainShape.lineTo(-width / 2, -length);
+ mainShape.lineTo(-width / 2, -arrowHeadLength);
+ mainShape.lineTo(-width, -arrowHeadLength);
+ mainShape.lineTo(0, 0);
+ } else {
+ mainShape.moveTo(0, 0);
+ mainShape.lineTo(width, -length);
+ mainShape.lineTo(-width, -length);
+ mainShape.lineTo(0, 0);
+ }
+ mainShape.closePath();
+
+ const secondaryLength = length / 4;
+ const secondaryShape = new THREE.Shape();
+ const secondaryHeadLength = width * 2;
+ const secondaryShaftLength = secondaryLength - secondaryHeadLength;
+
+ if (secondaryShaftLength > 0) {
+ secondaryShape.moveTo(0, 0);
+ secondaryShape.lineTo(width / 2, 0);
+ secondaryShape.lineTo(width / 2, secondaryShaftLength);
+ secondaryShape.lineTo(width, secondaryShaftLength);
+ secondaryShape.lineTo(0, secondaryLength);
+ secondaryShape.lineTo(-width, secondaryShaftLength);
+ secondaryShape.lineTo(-width / 2, secondaryShaftLength);
+ secondaryShape.lineTo(-width / 2, 0);
+ secondaryShape.lineTo(0, 0);
+ } else {
+ secondaryShape.moveTo(0, 0);
+ secondaryShape.lineTo(width, 0);
+ secondaryShape.lineTo(0, secondaryLength);
+ secondaryShape.lineTo(-width, 0);
+ secondaryShape.lineTo(0, 0);
+ }
+ secondaryShape.closePath();
+
+ const mainPosition = end;
+ const mainAngle = Math.atan2(direction.x, direction.z);
+
+ const perpendicularDirection = isFlipped
+ ? new THREE.Vector3(direction.z, 0, -direction.x).normalize()
+ : new THREE.Vector3(-direction.z, 0, direction.x).normalize();
+
+ const secondaryAngle = Math.atan2(perpendicularDirection.x, perpendicularDirection.z);
+
+ const secondaryPosition = new THREE.Vector3().lerpVectors(start, end, 0.75);
+
+ return [
+ { shape: mainShape, position: mainPosition, rotationY: mainAngle },
+ { shape: secondaryShape, position: secondaryPosition, rotationY: secondaryAngle + Math.PI }
+ ];
+ }, [aisle]);
+
+ const handleClick = () => {
+ if (toolMode === 'move' && !hoveredPoint) {
+ setSelectedAisle(aisleRef.current);
+ }
+ }
+
+ if (!arrows) return null;
+
+ return (
+ {
+ setSelectedAisle(null);
+ }}
+ >
+ {arrows.map((arrow, index) => (
+
+
+
+
+
+ ))}
+
+ );
+}
+
+export default JunctionAisle;
\ No newline at end of file
diff --git a/app/src/modules/builder/aisle/aisleCreator/aisleCreator.tsx b/app/src/modules/builder/aisle/aisleCreator/aisleCreator.tsx
index 0b14967..dca5654 100644
--- a/app/src/modules/builder/aisle/aisleCreator/aisleCreator.tsx
+++ b/app/src/modules/builder/aisle/aisleCreator/aisleCreator.tsx
@@ -1,5 +1,5 @@
import * as THREE from 'three'
-import { useEffect, useMemo, useState } from 'react'
+import { useEffect, useMemo, useRef, useState } from 'react'
import { useThree } from '@react-three/fiber';
import { useActiveLayer, useSocketStore, useToggleView, useToolMode } from '../../../../store/builder/store';
import { useAisleStore } from '../../../../store/builder/useAisleStore';
@@ -15,45 +15,37 @@ function AisleCreator() {
const { activeLayer } = useActiveLayer();
const { socket } = useSocketStore();
const { addAisle, getAislePointById } = useAisleStore();
+ const drag = useRef(false);
+ const isLeftMouseDown = useRef(false);
const [tempPoints, setTempPoints] = useState([]);
const [isCreating, setIsCreating] = useState(false);
- const { aisleType, aisleWidth, aisleColor, dashLength, gapLength, dotRadius, aisleLength, snappedPosition, snappedPoint } = useBuilderStore();
-
- // useEffect(() => {
- // if (tempPoints.length > 0) {
- // setTempPoints([]);
- // setIsCreating(false);
- // }
- // }, [aisleType]);
+ const { aisleType, aisleWidth, aisleColor, dashLength, gapLength, dotRadius, aisleLength, isFlipped, snappedPosition, snappedPoint } = useBuilderStore();
useEffect(() => {
const canvasElement = gl.domElement;
- let drag = false;
- let isLeftMouseDown = false;
-
const onMouseDown = (evt: any) => {
if (evt.button === 0) {
- isLeftMouseDown = true;
- drag = false;
+ isLeftMouseDown.current = true;
+ drag.current = false;
}
};
const onMouseUp = (evt: any) => {
if (evt.button === 0) {
- isLeftMouseDown = false;
+ isLeftMouseDown.current = false;
}
};
const onMouseMove = () => {
if (isLeftMouseDown) {
- drag = true;
+ drag.current = true;
}
};
const onMouseClick = () => {
- if (drag || !toggleView) return;
+ if (drag.current || !toggleView) return;
raycaster.setFromCamera(pointer, camera);
const intersectionPoint = new THREE.Vector3();
@@ -63,14 +55,14 @@ function AisleCreator() {
const intersects = raycaster.intersectObjects(scene.children).find((intersect) => intersect.object.name === 'Aisle-Point');
const newPoint: Point = {
- uuid: THREE.MathUtils.generateUUID(),
+ pointUuid: THREE.MathUtils.generateUUID(),
pointType: 'Aisle',
position: [position.x, position.y, position.z],
layer: activeLayer
};
if (snappedPosition && snappedPoint) {
- newPoint.uuid = snappedPoint.uuid;
+ newPoint.pointUuid = snappedPoint.pointUuid;
newPoint.position = snappedPosition;
newPoint.layer = snappedPoint.layer;
}
@@ -82,7 +74,7 @@ function AisleCreator() {
if (intersects && !snappedPoint) {
const point = getAislePointById(intersects.object.uuid);
if (point) {
- newPoint.uuid = point.uuid;
+ newPoint.pointUuid = point.pointUuid;
newPoint.position = point.position;
newPoint.layer = point.layer;
}
@@ -95,7 +87,7 @@ function AisleCreator() {
setIsCreating(true);
} else {
const aisle: Aisle = {
- uuid: THREE.MathUtils.generateUUID(),
+ aisleUuid: THREE.MathUtils.generateUUID(),
points: [tempPoints[0], newPoint],
type: {
aisleType: 'solid-aisle',
@@ -113,7 +105,7 @@ function AisleCreator() {
setIsCreating(true);
} else {
const aisle: Aisle = {
- uuid: THREE.MathUtils.generateUUID(),
+ aisleUuid: THREE.MathUtils.generateUUID(),
points: [tempPoints[0], newPoint],
type: {
aisleType: 'dashed-aisle',
@@ -133,7 +125,7 @@ function AisleCreator() {
setIsCreating(true);
} else {
const aisle: Aisle = {
- uuid: THREE.MathUtils.generateUUID(),
+ aisleUuid: THREE.MathUtils.generateUUID(),
points: [tempPoints[0], newPoint],
type: {
aisleType: 'stripped-aisle',
@@ -151,7 +143,7 @@ function AisleCreator() {
setIsCreating(true);
} else {
const aisle: Aisle = {
- uuid: THREE.MathUtils.generateUUID(),
+ aisleUuid: THREE.MathUtils.generateUUID(),
points: [tempPoints[0], newPoint],
type: {
aisleType: 'dotted-aisle',
@@ -164,7 +156,23 @@ function AisleCreator() {
setTempPoints([newPoint]);
}
} else if (aisleType === 'arrow-aisle') {
- console.log('Creating arrow-aisle');
+
+ if (tempPoints.length === 0) {
+ setTempPoints([newPoint]);
+ setIsCreating(true);
+ } else {
+ const aisle: Aisle = {
+ aisleUuid: THREE.MathUtils.generateUUID(),
+ points: [tempPoints[0], newPoint],
+ type: {
+ aisleType: 'arrow-aisle',
+ aisleColor: aisleColor,
+ aisleWidth: aisleWidth
+ }
+ };
+ addAisle(aisle);
+ setTempPoints([newPoint]);
+ }
} else if (aisleType === 'arrows-aisle') {
if (tempPoints.length === 0) {
@@ -172,7 +180,7 @@ function AisleCreator() {
setIsCreating(true);
} else {
const aisle: Aisle = {
- uuid: THREE.MathUtils.generateUUID(),
+ aisleUuid: THREE.MathUtils.generateUUID(),
points: [tempPoints[0], newPoint],
type: {
aisleType: 'arrows-aisle',
@@ -188,9 +196,42 @@ function AisleCreator() {
} else if (aisleType === 'arc-aisle') {
console.log('Creating arc-aisle');
} else if (aisleType === 'circle-aisle') {
- console.log('Creating circle-aisle');
+
+ if (tempPoints.length === 0) {
+ setTempPoints([newPoint]);
+ setIsCreating(true);
+ } else {
+ const aisle: Aisle = {
+ aisleUuid: THREE.MathUtils.generateUUID(),
+ points: [tempPoints[0], newPoint],
+ type: {
+ aisleType: 'circle-aisle',
+ aisleColor: aisleColor,
+ aisleWidth: aisleWidth
+ }
+ };
+ addAisle(aisle);
+ setTempPoints([newPoint]);
+ }
} else if (aisleType === 'junction-aisle') {
- console.log('Creating junction-aisle');
+
+ if (tempPoints.length === 0) {
+ setTempPoints([newPoint]);
+ setIsCreating(true);
+ } else {
+ const aisle: Aisle = {
+ aisleUuid: THREE.MathUtils.generateUUID(),
+ points: [tempPoints[0], newPoint],
+ type: {
+ aisleType: 'junction-aisle',
+ aisleColor: aisleColor,
+ aisleWidth: aisleWidth,
+ isFlipped: isFlipped
+ }
+ };
+ addAisle(aisle);
+ setTempPoints([newPoint]);
+ }
}
};
@@ -211,6 +252,11 @@ function AisleCreator() {
} else {
setTempPoints([]);
setIsCreating(false);
+ canvasElement.removeEventListener("mousedown", onMouseDown);
+ canvasElement.removeEventListener("mouseup", onMouseUp);
+ canvasElement.removeEventListener("mousemove", onMouseMove);
+ canvasElement.removeEventListener("click", onMouseClick);
+ canvasElement.removeEventListener("contextmenu", onContext);
}
return () => {
@@ -228,7 +274,7 @@ function AisleCreator() {
<>
{tempPoints.map((point) => (
-
+
))}
diff --git a/app/src/modules/builder/aisle/aisleCreator/referenceAisle.tsx b/app/src/modules/builder/aisle/aisleCreator/referenceAisle.tsx
index a4c331e..5bb18fd 100644
--- a/app/src/modules/builder/aisle/aisleCreator/referenceAisle.tsx
+++ b/app/src/modules/builder/aisle/aisleCreator/referenceAisle.tsx
@@ -13,7 +13,7 @@ interface ReferenceAisleProps {
}
function ReferenceAisle({ tempPoints }: Readonly) {
- const { aisleType, aisleWidth, aisleColor, dashLength, gapLength, dotRadius, aisleLength, setSnappedPosition, setSnappedPoint } = useBuilderStore();
+ const { aisleType, aisleWidth, aisleColor, dashLength, gapLength, dotRadius, aisleLength, isFlipped, setSnappedPosition, setSnappedPoint } = useBuilderStore();
const { pointer, raycaster, camera } = useThree();
const { toolMode } = useToolMode();
const { toggleView } = useToggleView();
@@ -24,7 +24,6 @@ function ReferenceAisle({ tempPoints }: Readonly) {
const [tempAisle, setTempAisle] = useState(null);
const [currentPosition, setCurrentPosition] = useState<[number, number, number]>(tempPoints[0]?.position);
- // Calculate directional snap based on current and previous points
const directionalSnap = useDirectionalSnapping(
currentPosition,
tempPoints[0]?.position || null
@@ -61,11 +60,11 @@ function ReferenceAisle({ tempPoints }: Readonly) {
if (aisleType === 'solid-aisle' || aisleType === 'stripped-aisle') {
setTempAisle({
- uuid: 'temp-aisle',
+ aisleUuid: 'temp-aisle',
points: [
tempPoints[0],
{
- uuid: 'temp-point',
+ pointUuid: 'temp-point',
pointType: 'Aisle',
position: finalPosition.current,
layer: activeLayer
@@ -79,11 +78,11 @@ function ReferenceAisle({ tempPoints }: Readonly) {
});
} else if (aisleType === 'dashed-aisle') {
setTempAisle({
- uuid: 'temp-aisle',
+ aisleUuid: 'temp-aisle',
points: [
tempPoints[0],
{
- uuid: 'temp-point',
+ pointUuid: 'temp-point',
pointType: 'Aisle',
position: finalPosition.current,
layer: activeLayer
@@ -99,11 +98,11 @@ function ReferenceAisle({ tempPoints }: Readonly) {
});
} else if (aisleType === 'dotted-aisle') {
setTempAisle({
- uuid: 'temp-aisle',
+ aisleUuid: 'temp-aisle',
points: [
tempPoints[0],
{
- uuid: 'temp-point',
+ pointUuid: 'temp-point',
pointType: 'Aisle',
position: finalPosition.current,
layer: activeLayer
@@ -116,15 +115,31 @@ function ReferenceAisle({ tempPoints }: Readonly) {
gapLength: gapLength
}
});
- } else if (aisleType === 'arrow-aisle') {
- console.log();
- } else if (aisleType === 'arrows-aisle') {
+ } else if (aisleType === 'arrow-aisle' || aisleType === 'circle-aisle') {
setTempAisle({
- uuid: 'temp-aisle',
+ aisleUuid: 'temp-aisle',
points: [
tempPoints[0],
{
- uuid: 'temp-point',
+ pointUuid: 'temp-point',
+ pointType: 'Aisle',
+ position: finalPosition.current,
+ layer: activeLayer
+ }
+ ],
+ type: {
+ aisleType: aisleType,
+ aisleColor: aisleColor,
+ aisleWidth: aisleWidth,
+ }
+ });
+ } else if (aisleType === 'arrows-aisle') {
+ setTempAisle({
+ aisleUuid: 'temp-aisle',
+ points: [
+ tempPoints[0],
+ {
+ pointUuid: 'temp-point',
pointType: 'Aisle',
position: finalPosition.current,
layer: activeLayer
@@ -140,10 +155,25 @@ function ReferenceAisle({ tempPoints }: Readonly) {
});
} else if (aisleType === 'arc-aisle') {
console.log();
- } else if (aisleType === 'circle-aisle') {
- console.log();
} else if (aisleType === 'junction-aisle') {
- console.log();
+ setTempAisle({
+ aisleUuid: 'temp-aisle',
+ points: [
+ tempPoints[0],
+ {
+ pointUuid: 'temp-point',
+ pointType: 'Aisle',
+ position: finalPosition.current,
+ layer: activeLayer
+ }
+ ],
+ type: {
+ aisleType: aisleType,
+ aisleColor: aisleColor,
+ aisleWidth: aisleWidth,
+ isFlipped: isFlipped,
+ }
+ });
}
}
} else if (tempAisle !== null) {
@@ -165,8 +195,14 @@ function ReferenceAisle({ tempPoints }: Readonly) {
return ;
case 'dotted-aisle':
return ;
+ case 'arrow-aisle':
+ return ;
case 'arrows-aisle':
- return
+ return ;
+ case 'circle-aisle':
+ return ;
+ case 'junction-aisle':
+ return ;
default:
return null;
}
@@ -182,7 +218,7 @@ function ReferenceAisle({ tempPoints }: Readonly) {
{toggleView &&
) {
sprite
>
{distance.toFixed(2)} m
@@ -446,3 +482,227 @@ function ArrowsAisle({ aisle }: { readonly aisle: Aisle }) {
);
}
+
+function ArrowAisle({ aisle }: { readonly aisle: Aisle }) {
+ const arrow = useMemo(() => {
+ if (aisle.points.length < 2 || aisle.type.aisleType !== 'arrow-aisle') return null;
+
+ 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 direction = new THREE.Vector3().subVectors(end, start);
+ const length = direction.length();
+ direction.normalize();
+
+ const shape = new THREE.Shape();
+ const arrowHeadLength = width * 2;
+ const shaftLength = length - arrowHeadLength;
+
+ if (shaftLength > 0) {
+ shape.moveTo(0, 0);
+ shape.lineTo(width, -arrowHeadLength);
+ shape.lineTo(width / 2, -arrowHeadLength);
+ shape.lineTo(width / 2, -length);
+ shape.lineTo(-width / 2, -length);
+ shape.lineTo(-width / 2, -arrowHeadLength);
+ shape.lineTo(-width, -arrowHeadLength);
+ shape.lineTo(0, 0);
+ } else {
+ shape.moveTo(0, 0);
+ shape.lineTo(width, -length);
+ shape.lineTo(-width, -length);
+ shape.lineTo(0, 0);
+ }
+
+ shape.closePath();
+
+ const position = end;
+ const angle = Math.atan2(direction.x, direction.z);
+
+ return { shape, position, rotationY: angle };
+ }, [aisle]);
+
+ if (!arrow) return null;
+
+ return (
+
+
+
+
+
+
+
+ );
+}
+
+function CircleAisle({ aisle }: { readonly aisle: Aisle }) {
+ const circle = useMemo(() => {
+ if (aisle.points.length < 2 || aisle.type.aisleType !== 'circle-aisle') return null;
+
+ const center = new THREE.Vector3(...aisle.points[0].position);
+ const widthCenter = new THREE.Vector3(...aisle.points[1].position);
+ const width = aisle.type.aisleWidth || 0.1;
+
+ const middleRadius = center.distanceTo(widthCenter);
+
+ const innerRadius = Math.max(0, middleRadius - width / 2);
+ const outerRadius = middleRadius + width / 2;
+
+ const shape = new THREE.Shape();
+ shape.absarc(0, 0, outerRadius, 0, Math.PI * 2, false);
+
+ if (innerRadius > 0) {
+ const hole = new THREE.Path();
+ hole.absarc(0, 0, innerRadius, 0, Math.PI * 2, true);
+ shape.holes.push(hole);
+ }
+
+ return {
+ shape,
+ position: center,
+ rotationY: 0
+ };
+ }, [aisle]);
+
+ if (!circle) return null;
+
+ return (
+
+
+
+
+
+
+
+ );
+}
+
+function JunctionAisle({ aisle }: { readonly aisle: Aisle }) {
+ const arrows = useMemo(() => {
+ if (aisle.points.length < 2 || aisle.type.aisleType !== 'junction-aisle') return null;
+
+ 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 isFlipped = aisle.type.isFlipped || false;
+
+ const direction = new THREE.Vector3().subVectors(end, start);
+ const length = direction.length();
+ direction.normalize();
+
+ const mainShape = new THREE.Shape();
+ const arrowHeadLength = width * 2;
+ const shaftLength = length - arrowHeadLength;
+
+ if (shaftLength > 0) {
+ mainShape.moveTo(0, 0);
+ mainShape.lineTo(width, -arrowHeadLength);
+ mainShape.lineTo(width / 2, -arrowHeadLength);
+ mainShape.lineTo(width / 2, -length);
+ mainShape.lineTo(-width / 2, -length);
+ mainShape.lineTo(-width / 2, -arrowHeadLength);
+ mainShape.lineTo(-width, -arrowHeadLength);
+ mainShape.lineTo(0, 0);
+ } else {
+ mainShape.moveTo(0, 0);
+ mainShape.lineTo(width, -length);
+ mainShape.lineTo(-width, -length);
+ mainShape.lineTo(0, 0);
+ }
+ mainShape.closePath();
+
+ const secondaryLength = length / 4;
+ const secondaryShape = new THREE.Shape();
+ const secondaryHeadLength = width * 2;
+ const secondaryShaftLength = secondaryLength - secondaryHeadLength;
+
+ if (secondaryShaftLength > 0) {
+ secondaryShape.moveTo(0, 0);
+ secondaryShape.lineTo(width / 2, 0);
+ secondaryShape.lineTo(width / 2, secondaryShaftLength);
+ secondaryShape.lineTo(width, secondaryShaftLength);
+ secondaryShape.lineTo(0, secondaryLength);
+ secondaryShape.lineTo(-width, secondaryShaftLength);
+ secondaryShape.lineTo(-width / 2, secondaryShaftLength);
+ secondaryShape.lineTo(-width / 2, 0);
+ secondaryShape.lineTo(0, 0);
+ } else {
+ secondaryShape.moveTo(0, 0);
+ secondaryShape.lineTo(width, 0);
+ secondaryShape.lineTo(0, secondaryLength);
+ secondaryShape.lineTo(-width, 0);
+ secondaryShape.lineTo(0, 0);
+ }
+ secondaryShape.closePath();
+
+ const mainPosition = end;
+ const mainAngle = Math.atan2(direction.x, direction.z);
+
+ const perpendicularDirection = isFlipped
+ ? new THREE.Vector3(direction.z, 0, -direction.x).normalize()
+ : new THREE.Vector3(-direction.z, 0, direction.x).normalize();
+
+ const secondaryAngle = Math.atan2(perpendicularDirection.x, perpendicularDirection.z);
+
+ const secondaryPosition = new THREE.Vector3().lerpVectors(start, end, 0.75);
+
+ return [
+ { shape: mainShape, position: mainPosition, rotationY: mainAngle },
+ {
+ shape: secondaryShape,
+ position: secondaryPosition,
+ rotationY: secondaryAngle + Math.PI
+ }
+ ];
+ }, [aisle]);
+
+ if (!arrows) return null;
+
+ return (
+
+ {arrows.map((arrow, index) => (
+
+
+
+
+
+ ))}
+
+ );
+}
\ No newline at end of file
diff --git a/app/src/modules/builder/builder.tsx b/app/src/modules/builder/builder.tsx
index 3263b90..911d78c 100644
--- a/app/src/modules/builder/builder.tsx
+++ b/app/src/modules/builder/builder.tsx
@@ -35,7 +35,6 @@ import * as Types from "../../types/world/worldTypes";
import SocketResponses from "../collaboration/socket/socketResponses.dev";
import FloorPlanGroup from "./groups/floorPlanGroup";
import FloorGroup from "./groups/floorGroup";
-import FloorGroupAilse from "./groups/floorGroupAisle";
import Draw from "./functions/draw";
import WallsAndWallItems from "./groups/wallsAndWallItems";
import Ground from "../scene/environment/ground";
@@ -275,26 +274,6 @@ export default function Builder() {
- {/* */}
-
{
- if (aisle.length >= 2 && aisle[0] && aisle[1]) {
- const start: Types.Vector3 = aisle[0][0];
- const end: Types.Vector3 = aisle[1][0];
-
- const direction = new THREE.Vector3(
- end.x - start.x,
- end.y - start.y,
- end.z - start.z
- ).normalize();
-
- const perp = new THREE.Vector3(-direction.z, 0, direction.x).normalize();
- const offsetDistance = CONSTANTS.aisleConfig.width;
-
- const leftStart = new THREE.Vector3().copy(start).addScaledVector(perp, offsetDistance);
- const rightStart = new THREE.Vector3().copy(start).addScaledVector(perp, -offsetDistance);
- const leftEnd = new THREE.Vector3().copy(end).addScaledVector(perp, offsetDistance);
- const rightEnd = new THREE.Vector3().copy(end).addScaledVector(perp, -offsetDistance);
-
- const stripShape = new THREE.Shape();
- stripShape.moveTo(leftStart.x, leftStart.z);
- stripShape.lineTo(leftEnd.x, leftEnd.z);
- stripShape.lineTo(rightEnd.x, rightEnd.z);
- stripShape.lineTo(rightStart.x, rightStart.z);
- stripShape.lineTo(leftStart.x, leftStart.z);
-
- const extrudeSettings = {
- depth: CONSTANTS.aisleConfig.height,
- bevelEnabled: false,
- };
-
- const stripGeometry = new THREE.ExtrudeGeometry(stripShape, extrudeSettings);
- const stripMaterial = new THREE.MeshStandardMaterial({
- color: CONSTANTS.aisleConfig.defaultColor,
- polygonOffset: true,
- polygonOffsetFactor: -1,
- polygonOffsetUnits: -1,
- });
-
- const stripMesh = new THREE.Mesh(stripGeometry, stripMaterial);
- stripMesh.receiveShadow = true;
- stripMesh.castShadow = true;
-
- stripMesh.position.y = (aisle[0][2] - 1) * CONSTANTS.wallConfig.height + 0.01;
- stripMesh.rotateX(Math.PI / 2);
-
- floorGroupAisle.current.add(stripMesh);
- }
-}
diff --git a/app/src/modules/builder/geomentries/aisles/loadAisles.ts b/app/src/modules/builder/geomentries/aisles/loadAisles.ts
deleted file mode 100644
index 437ae66..0000000
--- a/app/src/modules/builder/geomentries/aisles/loadAisles.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import * as Types from '../../../../types/world/worldTypes';
-import addAisleToScene from './addAilseToScene';
-import * as CONSTANTS from '../../../../types/world/worldConstants';
-
-export default async function loadAisles(
- lines: Types.RefLines,
- floorGroupAisle: Types.RefGroup
-) {
- // console.log('lines: ', lines.current[0][0][0]);
- if (!floorGroupAisle.current) return
- floorGroupAisle.current.children = [];
- const aisles = lines.current.filter((line) => line[0][3] && line[1][3] === CONSTANTS.lineConfig.aisleName);
-
- if (aisles.length > 0) {
- aisles.forEach((aisle: Types.Line) => {
- addAisleToScene(aisle, floorGroupAisle)
- })
- }
-}
\ No newline at end of file
diff --git a/app/src/modules/builder/groups/floorGroupAisle.tsx b/app/src/modules/builder/groups/floorGroupAisle.tsx
deleted file mode 100644
index 2c65b64..0000000
--- a/app/src/modules/builder/groups/floorGroupAisle.tsx
+++ /dev/null
@@ -1,242 +0,0 @@
-import * as THREE from 'three';
-import * as Types from '../../../types/world/worldTypes';
-import * as CONSTANTS from '../../../types/world/worldConstants';
-import { useThree } from "@react-three/fiber";
-import { useToggleView, useActiveLayer, useSocketStore, useDeletePointOrLine, useUpdateScene, useNewLines, useToolMode } from "../../../store/builder/store";
-import { useEffect } from "react";
-import removeSoloPoint from "../geomentries/points/removeSoloPoint";
-import removeReferenceLine from "../geomentries/lines/removeReferenceLine";
-import getClosestIntersection from "../geomentries/lines/getClosestIntersection";
-import addPointToScene from "../geomentries/points/addPointToScene";
-import arrayLineToObject from '../geomentries/lines/lineConvertions/arrayLineToObject';
-import addLineToScene from "../geomentries/lines/addLineToScene";
-import loadAisles from '../geomentries/aisles/loadAisles';
-
-const FloorGroupAilse = ({ floorGroupAisle, plane, floorPlanGroupLine, floorPlanGroupPoint, line, lines, currentLayerPoint, dragPointControls, floorPlanGroup, ReferenceLineMesh, LineCreated, isSnapped, ispreSnapped, snappedPoint, isSnappedUUID, isAngleSnapped, anglesnappedPoint }: any) => {
- const { toggleView } = useToggleView();
- const { setDeletePointOrLine } = useDeletePointOrLine();
- const { toolMode } = useToolMode();
- const { socket } = useSocketStore();
- const { activeLayer } = useActiveLayer();
- const { gl, raycaster } = useThree();
- const { updateScene, setUpdateScene } = useUpdateScene();
- const { setNewLines } = useNewLines();
-
- useEffect(() => {
- if (updateScene) {
- loadAisles(lines, floorGroupAisle);
- setUpdateScene(false);
- }
- }, [updateScene])
-
- useEffect(() => {
- if (toolMode === "Aisle") {
- setDeletePointOrLine(false);
- } else {
- removeSoloPoint(line, floorPlanGroupLine, floorPlanGroupPoint);
- removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
- }
- }, [toolMode]);
-
- useEffect(() => {
-
- const canvasElement = gl.domElement;
-
- let drag = false;
- let isLeftMouseDown = false;
-
- const onMouseDown = (evt: any) => {
- if (evt.button === 0) {
- isLeftMouseDown = true;
- drag = false;
- }
- };
-
- const onMouseUp = (evt: any) => {
- if (evt.button === 0) {
- isLeftMouseDown = false;
- }
- }
-
- const onMouseMove = () => {
- if (isLeftMouseDown) {
- drag = true;
- }
- };
-
- const onContextMenu = (e: any) => {
- e.preventDefault();
- if (toolMode === "Aisle") {
- removeSoloPoint(line, floorPlanGroupLine, floorPlanGroupPoint);
- removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
- }
- };
-
- const onMouseClick = (evt: any) => {
- if (!plane.current || drag) return;
-
- const intersects = raycaster.intersectObject(plane.current, true);
- let intersectionPoint = intersects[0].point;
- const points = floorPlanGroupPoint.current?.children ?? [];
- const intersectsPoint = raycaster.intersectObjects(points, true).find(intersect => intersect.object.visible);
- let intersectsLines: any = raycaster.intersectObjects(floorPlanGroupLine.current.children, true);
-
-
- if (intersectsLines.length > 0 && intersects && intersects.length > 0 && !intersectsPoint) {
- const lineType = intersectsLines[0].object.userData.linePoints[0][3];
- if (lineType === CONSTANTS.lineConfig.aisleName) {
- // console.log("intersected a aisle line");
- const ThroughPoint = (intersectsLines[0].object.geometry.parameters.path).getPoints(CONSTANTS.lineConfig.lineIntersectionPoints);
- let intersection = getClosestIntersection(ThroughPoint, intersectionPoint);
- if (!intersection) return;
- const point = addPointToScene(intersection, CONSTANTS.pointConfig.aisleOuterColor, currentLayerPoint, floorPlanGroupPoint, dragPointControls, undefined, CONSTANTS.lineConfig.aisleName);
- (line.current as Types.Line).push([new THREE.Vector3(intersection.x, 0.01, intersection.z), point.uuid, activeLayer, CONSTANTS.lineConfig.aisleName,]);
- if (line.current.length >= 2 && line.current[0] && line.current[1]) {
- lines.current.push(line.current as Types.Line);
-
- const data = arrayLineToObject(line.current as Types.Line);
-
- const email = localStorage.getItem('email')
- const organization = (email!.split("@")[1]).split(".")[0];
-
- //REST
-
- // setLine(organization, data.layer!, data.line!, data.type!);
-
- //SOCKET
-
- const input = {
- organization: organization,
- layer: data.layer,
- line: data.line,
- type: data.type,
- socketId: socket.id
- }
-
- socket.emit('v1:Line:create', input);
-
- setNewLines([line.current]);
-
- addLineToScene(line.current[0][0], line.current[1][0], CONSTANTS.pointConfig.aisleOuterColor, line.current, floorPlanGroupLine);
- let lastPoint = line.current[line.current.length - 1];
- line.current = [lastPoint];
- }
- }
- } else if (intersectsPoint && intersects && intersects.length > 0) {
- if (intersectsPoint.object.userData.type === CONSTANTS.lineConfig.aisleName) {
- // console.log("intersected a aisle point");
- intersectionPoint = intersectsPoint.object.position;
- (line.current as Types.Line).push([new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z), intersectsPoint.object.uuid, activeLayer, CONSTANTS.lineConfig.aisleName,]);
- if (line.current.length >= 2 && line.current[0] && line.current[1]) {
- lines.current.push(line.current as Types.Line);
-
- const data = arrayLineToObject(line.current as Types.Line);
-
- const email = localStorage.getItem('email')
- const organization = (email!.split("@")[1]).split(".")[0];
-
- //REST
-
- // setLine(organization, data.layer!, data.line!, data.type!);
-
- //SOCKET
-
- const input = {
- organization: organization,
- layer: data.layer,
- line: data.line,
- type: data.type,
- socketId: socket.id
- }
-
- socket.emit('v1:Line:create', input);
-
- setNewLines([line.current]);
-
- addLineToScene(line.current[0][0], line.current[1][0], CONSTANTS.pointConfig.aisleOuterColor, line.current, floorPlanGroupLine);
- let lastPoint = line.current[line.current.length - 1];
- line.current = [lastPoint];
- ispreSnapped.current = false;
- isSnapped.current = false;
- }
- }
- } else if (intersects && intersects.length > 0) {
- // console.log("intersected a empty area");
- let uuid: string = "";
- if (isAngleSnapped.current && anglesnappedPoint.current && line.current.length > 0) {
- intersectionPoint = anglesnappedPoint.current;
- const point = addPointToScene(intersectionPoint, CONSTANTS.pointConfig.aisleOuterColor, currentLayerPoint, floorPlanGroupPoint, dragPointControls, undefined, CONSTANTS.lineConfig.aisleName);
- uuid = point.uuid;
- } else if (isSnapped.current && snappedPoint.current && line.current.length > 0) {
- intersectionPoint = snappedPoint.current;
- uuid = isSnappedUUID.current!;
- } else if (ispreSnapped.current && snappedPoint.current) {
- intersectionPoint = snappedPoint.current;
- uuid = isSnappedUUID.current!;
- } else {
- const point = addPointToScene(intersectionPoint, CONSTANTS.pointConfig.aisleOuterColor, currentLayerPoint, floorPlanGroupPoint, dragPointControls, undefined, CONSTANTS.lineConfig.aisleName);
- uuid = point.uuid;
- }
- (line.current as Types.Line).push([new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z), uuid, activeLayer, CONSTANTS.lineConfig.aisleName,]);
-
- if (line.current.length >= 2 && line.current[0] && line.current[1]) {
- lines.current.push(line.current as Types.Line);
-
- const data = arrayLineToObject(line.current as Types.Line);
-
- const email = localStorage.getItem('email')
- const organization = (email!.split("@")[1]).split(".")[0];
-
- //REST
-
- // setLine(organization, data.layer!, data.line!, data.type!);
-
- //SOCKET
-
- const input = {
- organization: organization,
- layer: data.layer,
- line: data.line,
- type: data.type,
- socketId: socket.id
- }
-
- socket.emit('v1:Line:create', input);
-
- setNewLines([line.current]);
-
- addLineToScene(line.current[0][0], line.current[1][0], CONSTANTS.pointConfig.aisleOuterColor, line.current, floorPlanGroupLine);
- let lastPoint = line.current[line.current.length - 1];
- line.current = [lastPoint];
- ispreSnapped.current = false;
- isSnapped.current = false;
- }
- }
- }
-
-
- if (toolMode === 'Aisle') {
- canvasElement.addEventListener("mousedown", onMouseDown);
- canvasElement.addEventListener("mouseup", onMouseUp);
- canvasElement.addEventListener("mousemove", onMouseMove);
- canvasElement.addEventListener("click", onMouseClick);
- canvasElement.addEventListener("contextmenu", onContextMenu);
- }
-
- return () => {
- canvasElement.removeEventListener("mousedown", onMouseDown);
- canvasElement.removeEventListener("mouseup", onMouseUp);
- canvasElement.removeEventListener("mousemove", onMouseMove);
- canvasElement.removeEventListener("click", onMouseClick);
- canvasElement.removeEventListener("contextmenu", onContextMenu);
- };
- }, [toolMode])
-
-
- return (
-
-
- )
-}
-
-export default FloorGroupAilse;
\ No newline at end of file
diff --git a/app/src/modules/builder/groups/zoneGroup.tsx b/app/src/modules/builder/groups/zoneGroup.tsx
index a18e265..349fe07 100644
--- a/app/src/modules/builder/groups/zoneGroup.tsx
+++ b/app/src/modules/builder/groups/zoneGroup.tsx
@@ -3,15 +3,15 @@ import { Html, Line, Sphere } from "@react-three/drei";
import { useThree, useFrame } from "@react-three/fiber";
import * as THREE from "three";
import {
- useActiveLayer,
- useDeleteTool,
- useDeletePointOrLine,
- useSocketStore,
- useToggleView,
- useToolMode,
- useRemovedLayer,
- useZones,
- useZonePoints,
+ useActiveLayer,
+ useDeleteTool,
+ useDeletePointOrLine,
+ useSocketStore,
+ useToggleView,
+ useToolMode,
+ useRemovedLayer,
+ useZones,
+ useZonePoints,
} from "../../../store/builder/store";
import { getZonesApi } from "../../../services/factoryBuilder/zones/getZonesApi";
@@ -21,42 +21,42 @@ import { computeArea } from "../functions/computeArea";
import { useSelectedZoneStore } from "../../../store/visualization/useZoneStore";
const ZoneGroup: React.FC = () => {
- const { camera, pointer, gl, raycaster, scene, controls } = useThree();
- const [startPoint, setStartPoint] = useState(null);
- const [endPoint, setEndPoint] = useState(null);
- const { zones, setZones } = useZones();
- const { zonePoints, setZonePoints } = useZonePoints();
- const [isDragging, setIsDragging] = useState(false);
- const { selectedZone } = useSelectedZoneStore();
- const [draggedSphere, setDraggedSphere] = useState(
- null
- );
- const plane = useMemo(
- () => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0),
- []
- );
- const { toggleView } = useToggleView();
- const { deletePointOrLine, setDeletePointOrLine } = useDeletePointOrLine();
- const { removedLayer, setRemovedLayer } = useRemovedLayer();
- const { toolMode } = useToolMode();
- const { setDeleteTool } = useDeleteTool();
- const { activeLayer } = useActiveLayer();
- const { socket } = useSocketStore();
+ const { camera, pointer, gl, raycaster, scene, controls } = useThree();
+ const [startPoint, setStartPoint] = useState(null);
+ const [endPoint, setEndPoint] = useState(null);
+ const { zones, setZones } = useZones();
+ const { zonePoints, setZonePoints } = useZonePoints();
+ const [isDragging, setIsDragging] = useState(false);
+ const { selectedZone } = useSelectedZoneStore();
+ const [draggedSphere, setDraggedSphere] = useState(
+ null
+ );
+ const plane = useMemo(
+ () => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0),
+ []
+ );
+ const { toggleView } = useToggleView();
+ const { deletePointOrLine, setDeletePointOrLine } = useDeletePointOrLine();
+ const { removedLayer, setRemovedLayer } = useRemovedLayer();
+ const { toolMode } = useToolMode();
+ const { setDeleteTool } = useDeleteTool();
+ const { activeLayer } = useActiveLayer();
+ const { socket } = useSocketStore();
- const groupsRef = useRef();
+ const groupsRef = useRef();
- const zoneMaterial = useMemo(
- () =>
- new THREE.ShaderMaterial({
- side: THREE.DoubleSide,
- vertexShader: `
+ const zoneMaterial = useMemo(
+ () =>
+ new THREE.ShaderMaterial({
+ side: THREE.DoubleSide,
+ vertexShader: `
varying vec2 vUv;
void main(){
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
vUv = uv;
}
`,
- fragmentShader: `
+ fragmentShader: `
varying vec2 vUv;
uniform vec3 uOuterColor;
void main(){
@@ -64,671 +64,674 @@ const ZoneGroup: React.FC = () => {
gl_FragColor = vec4(uOuterColor, alpha);
}
`,
- uniforms: {
- uOuterColor: { value: new THREE.Color(CONSTANTS.zoneConfig.color) },
- },
- transparent: true,
- depthWrite: false,
- }),
- []
- );
-
- useEffect(() => {
- const fetchZones = async () => {
- const email = localStorage.getItem("email");
- if (!email) return;
-
- const organization = email.split("@")[1].split(".")[0];
- const data = await getZonesApi(organization);
-
- if (data.data && data.data.length > 0) {
- const fetchedZones = data.data.map((zone: any) => ({
- zoneId: zone.zoneId,
- zoneName: zone.zoneName,
- points: zone.points,
- viewPortCenter: zone.viewPortCenter,
- viewPortposition: zone.viewPortposition,
- layer: zone.layer,
- }));
-
- setZones(fetchedZones);
-
- const fetchedPoints = data.data.flatMap((zone: any) =>
- zone.points
- .slice(0, 4)
- .map(
- (point: [number, number, number]) => new THREE.Vector3(...point)
- )
- );
-
- setZonePoints(fetchedPoints);
- }
- };
-
- fetchZones();
- }, []);
-
- useEffect(() => {
- localStorage.setItem("zones", JSON.stringify(zones));
- }, [zones]);
-
- useEffect(() => {
- if (removedLayer) {
- const updatedZones = zones.filter(
- (zone: any) => zone.layer !== removedLayer
- );
- setZones(updatedZones);
-
- const updatedzonePoints = zonePoints.filter((_: any, index: any) => {
- const zoneIndex = Math.floor(index / 4);
- return zones[zoneIndex]?.layer !== removedLayer;
- });
- setZonePoints(updatedzonePoints);
-
- zones
- .filter((zone: any) => zone.layer === removedLayer)
- .forEach((zone: any) => {
- deleteZoneFromBackend(zone.zoneId);
- });
-
- setRemovedLayer(null);
- }
- }, [removedLayer]);
-
- useEffect(() => {
- if (toolMode !== "Zone") {
- setStartPoint(null);
- setEndPoint(null);
- } else {
- setDeletePointOrLine(false);
- setDeleteTool(false);
- }
- if (!toggleView) {
- setStartPoint(null);
- setEndPoint(null);
- }
- }, [toolMode, toggleView]);
-
- // eslint-disable-next-line react-hooks/exhaustive-deps
- const addZoneToBackend = async (zone: {
- zoneId: string;
- zoneName: string;
- points: [number, number, number][];
- layer: string;
- }) => {
- const email = localStorage.getItem("email");
- const userId = localStorage.getItem("userId");
- const organization = email!.split("@")[1].split(".")[0];
-
- const calculateCenter = (points: number[][]) => {
- if (!points || points.length === 0) return null;
-
- let sumX = 0,
- sumY = 0,
- sumZ = 0;
- const numPoints = points.length;
-
- points.forEach(([x, y, z]) => {
- sumX += x;
- sumY += y;
- sumZ += z;
- });
-
- return [sumX / numPoints, sumY / numPoints, sumZ / numPoints] as [
- number,
- number,
- number
- ];
- };
-
- const target: [number, number, number] | null = calculateCenter(
- zone.points
+ uniforms: {
+ uOuterColor: { value: new THREE.Color(CONSTANTS.zoneConfig.color) },
+ },
+ transparent: true,
+ depthWrite: false,
+ }),
+ []
);
- if (!target || zone.points.length < 4) return;
- const position = [target[0], 10, target[2]];
- const input = {
- userId: userId,
- organization: organization,
- zoneData: {
- zoneName: zone.zoneName,
- zoneId: zone.zoneId,
- points: zone.points,
- viewPortCenter: target,
- viewPortposition: position,
- layer: zone.layer,
- },
- };
+ useEffect(() => {
+ const fetchZones = async () => {
+ const email = localStorage.getItem("email");
+ if (!email) return;
- socket.emit("v2:zone:set", input);
- };
+ const organization = email.split("@")[1].split(".")[0];
+ const data = await getZonesApi(organization);
- // eslint-disable-next-line react-hooks/exhaustive-deps
- const updateZoneToBackend = async (zone: {
- zoneId: string;
- zoneName: string;
- points: [number, number, number][];
- layer: string;
- }) => {
- const email = localStorage.getItem("email");
- const userId = localStorage.getItem("userId");
- const organization = email!.split("@")[1].split(".")[0];
+ if (data.data && data.data.length > 0) {
+ const fetchedZones = data.data.map((zone: any) => ({
+ zoneId: zone.zoneId,
+ zoneName: zone.zoneName,
+ points: zone.points,
+ viewPortCenter: zone.viewPortCenter,
+ viewPortposition: zone.viewPortposition,
+ layer: zone.layer,
+ }));
- const calculateCenter = (points: number[][]) => {
- if (!points || points.length === 0) return null;
+ console.log('fetchedZones: ', fetchedZones);
+ setZones(fetchedZones);
- let sumX = 0,
- sumY = 0,
- sumZ = 0;
- const numPoints = points.length;
+ const fetchedPoints = data.data.flatMap((zone: any) =>
+ zone.points
+ .slice(0, 4)
+ .map(
+ (point: [number, number, number]) => new THREE.Vector3(...point)
+ )
+ );
- points.forEach(([x, y, z]) => {
- sumX += x;
- sumY += y;
- sumZ += z;
- });
-
- return [sumX / numPoints, sumY / numPoints, sumZ / numPoints] as [
- number,
- number,
- number
- ];
- };
-
- const target: [number, number, number] | null = calculateCenter(
- zone.points
- );
- if (!target || zone.points.length < 4) return;
- const position = [target[0], 10, target[2]];
-
- const input = {
- userId: userId,
- organization: organization,
- zoneData: {
- zoneName: zone.zoneName,
- zoneId: zone.zoneId,
- points: zone.points,
- viewPortCenter: target,
- viewPortposition: position,
- layer: zone.layer,
- },
- };
-
- socket.emit("v2:zone:set", input);
- };
-
- const deleteZoneFromBackend = async (zoneId: string) => {
- const email = localStorage.getItem("email");
- const userId = localStorage.getItem("userId");
- const organization = email!.split("@")[1].split(".")[0];
-
- const input = {
- userId: userId,
- organization: organization,
- zoneId: zoneId,
- };
-
- socket.emit("v2:zone:delete", input);
- };
-
- // eslint-disable-next-line react-hooks/exhaustive-deps
- const handleDeleteZone = (zoneId: string) => {
- const updatedZones = zones.filter((zone: any) => zone.zoneId !== zoneId);
- setZones(updatedZones);
-
- const zoneIndex = zones.findIndex((zone: any) => zone.zoneId === zoneId);
- if (zoneIndex !== -1) {
- const zonePointsToRemove = zonePoints.slice(
- zoneIndex * 4,
- zoneIndex * 4 + 4
- );
- zonePointsToRemove.forEach((point: any) =>
- groupsRef.current.remove(point)
- );
- const updatedzonePoints = zonePoints.filter(
- (_: any, index: any) =>
- index < zoneIndex * 4 || index >= zoneIndex * 4 + 4
- );
- setZonePoints(updatedzonePoints);
- }
- deleteZoneFromBackend(zoneId);
- };
-
- useEffect(() => {
- if (!camera || !toggleView) return;
- const canvasElement = gl.domElement;
-
- let drag = false;
- let isLeftMouseDown = false;
-
- const onMouseDown = (evt: any) => {
- if (evt.button === 0) {
- isLeftMouseDown = true;
- drag = false;
-
- raycaster.setFromCamera(pointer, camera);
- const intersects = raycaster.intersectObjects(
- groupsRef.current.children,
- true
- );
-
- if (intersects.length > 0 && toolMode === "move") {
- const clickedObject = intersects[0].object;
- const sphereIndex = zonePoints.findIndex((point: any) =>
- point.equals(clickedObject.position)
- );
- if (sphereIndex !== -1) {
- (controls as any).enabled = false;
- setDraggedSphere(zonePoints[sphereIndex]);
- setIsDragging(true);
- }
- }
- }
- };
-
- const onMouseUp = (evt: any) => {
- if (evt.button === 0 && !drag && !isDragging && !deletePointOrLine) {
- isLeftMouseDown = false;
-
- if (!startPoint && toolMode !== "move") {
- raycaster.setFromCamera(pointer, camera);
- const intersectionPoint = new THREE.Vector3();
- const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
- if (point) {
- setStartPoint(point);
- setEndPoint(null);
- }
- } else if (startPoint && toolMode !== "move") {
- raycaster.setFromCamera(pointer, camera);
- const intersectionPoint = new THREE.Vector3();
- const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
- if (!point) return;
-
- const points = [
- [startPoint.x, 0.15, startPoint.z],
- [point.x, 0.15, startPoint.z],
- [point.x, 0.15, point.z],
- [startPoint.x, 0.15, point.z],
- [startPoint.x, 0.15, startPoint.z],
- ] as [number, number, number][];
-
- const zoneName = `Zone ${zones.length + 1}`;
- const zoneId = THREE.MathUtils.generateUUID();
- const newZone = {
- zoneId,
- zoneName,
- points: points,
- layer: activeLayer,
- };
-
- const newZones = [...zones, newZone];
-
- setZones(newZones);
-
- const newzonePoints = [
- new THREE.Vector3(startPoint.x, 0.15, startPoint.z),
- new THREE.Vector3(point.x, 0.15, startPoint.z),
- new THREE.Vector3(point.x, 0.15, point.z),
- new THREE.Vector3(startPoint.x, 0.15, point.z),
- ];
-
- const updatedZonePoints = [...zonePoints, ...newzonePoints];
- setZonePoints(updatedZonePoints);
-
- addZoneToBackend(newZone);
- setStartPoint(null);
- setEndPoint(null);
- }
- } else if (
- evt.button === 0 &&
- !drag &&
- !isDragging &&
- deletePointOrLine
- ) {
- raycaster.setFromCamera(pointer, camera);
- const intersects = raycaster.intersectObjects(
- groupsRef.current.children,
- true
- );
-
- if (intersects.length > 0) {
- const clickedObject = intersects[0].object;
-
- const sphereIndex = zonePoints.findIndex((point: any) =>
- point.equals(clickedObject.position)
- );
- if (sphereIndex !== -1) {
- const zoneIndex = Math.floor(sphereIndex / 4);
- const zoneId = zones[zoneIndex].zoneId;
- handleDeleteZone(zoneId);
- return;
- }
- }
- }
-
- if (evt.button === 0) {
- if (isDragging && draggedSphere) {
- setIsDragging(false);
- setDraggedSphere(null);
-
- const sphereIndex = zonePoints.findIndex(
- (point: any) => point === draggedSphere
- );
- if (sphereIndex !== -1) {
- const zoneIndex = Math.floor(sphereIndex / 4);
-
- if (zoneIndex !== -1 && zones[zoneIndex]) {
- updateZoneToBackend(zones[zoneIndex]);
+ setZonePoints(fetchedPoints);
}
- }
+ };
+
+ fetchZones();
+ }, []);
+
+ useEffect(() => {
+ console.log('zones: ', zones);
+ localStorage.setItem("zones", JSON.stringify(zones));
+ }, [zones]);
+
+ useEffect(() => {
+ if (removedLayer) {
+ const updatedZones = zones.filter(
+ (zone: any) => zone.layer !== removedLayer
+ );
+ setZones(updatedZones);
+
+ const updatedzonePoints = zonePoints.filter((_: any, index: any) => {
+ const zoneIndex = Math.floor(index / 4);
+ return zones[zoneIndex]?.layer !== removedLayer;
+ });
+ setZonePoints(updatedzonePoints);
+
+ zones
+ .filter((zone: any) => zone.layer === removedLayer)
+ .forEach((zone: any) => {
+ deleteZoneFromBackend(zone.zoneId);
+ });
+
+ setRemovedLayer(null);
}
- }
+ }, [removedLayer]);
+
+ useEffect(() => {
+ if (toolMode !== "Zone") {
+ setStartPoint(null);
+ setEndPoint(null);
+ } else {
+ setDeletePointOrLine(false);
+ setDeleteTool(false);
+ }
+ if (!toggleView) {
+ setStartPoint(null);
+ setEndPoint(null);
+ }
+ }, [toolMode, toggleView]);
+
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ const addZoneToBackend = async (zone: {
+ zoneId: string;
+ zoneName: string;
+ points: [number, number, number][];
+ layer: string;
+ }) => {
+ console.log('zoneId: ', zone);
+ const email = localStorage.getItem("email");
+ const userId = localStorage.getItem("userId");
+ const organization = email!.split("@")[1].split(".")[0];
+
+ const calculateCenter = (points: number[][]) => {
+ if (!points || points.length === 0) return null;
+
+ let sumX = 0,
+ sumY = 0,
+ sumZ = 0;
+ const numPoints = points.length;
+
+ points.forEach(([x, y, z]) => {
+ sumX += x;
+ sumY += y;
+ sumZ += z;
+ });
+
+ return [sumX / numPoints, sumY / numPoints, sumZ / numPoints] as [
+ number,
+ number,
+ number
+ ];
+ };
+
+ const target: [number, number, number] | null = calculateCenter(
+ zone.points
+ );
+ if (!target || zone.points.length < 4) return;
+ const position = [target[0], 10, target[2]];
+
+ const input = {
+ userId: userId,
+ organization: organization,
+ zoneData: {
+ zoneName: zone.zoneName,
+ zoneId: zone.zoneId,
+ points: zone.points,
+ viewPortCenter: target,
+ viewPortposition: position,
+ layer: zone.layer,
+ },
+ };
+
+ socket.emit("v2:zone:set", input);
};
- const onMouseMove = () => {
- if (isLeftMouseDown) {
- drag = true;
- }
- raycaster.setFromCamera(pointer, camera);
- const intersects = raycaster.intersectObjects(
- groupsRef.current.children,
- true
- );
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ const updateZoneToBackend = async (zone: {
+ zoneId: string;
+ zoneName: string;
+ points: [number, number, number][];
+ layer: string;
+ }) => {
+ const email = localStorage.getItem("email");
+ const userId = localStorage.getItem("userId");
+ const organization = email!.split("@")[1].split(".")[0];
- if (
- intersects.length > 0 &&
- intersects[0].object.name.includes("point")
- ) {
- gl.domElement.style.cursor =
- toolMode === "move" ? "pointer" : "default";
- } else {
- gl.domElement.style.cursor = "default";
- }
- if (isDragging && draggedSphere) {
+ const calculateCenter = (points: number[][]) => {
+ if (!points || points.length === 0) return null;
+
+ let sumX = 0,
+ sumY = 0,
+ sumZ = 0;
+ const numPoints = points.length;
+
+ points.forEach(([x, y, z]) => {
+ sumX += x;
+ sumY += y;
+ sumZ += z;
+ });
+
+ return [sumX / numPoints, sumY / numPoints, sumZ / numPoints] as [
+ number,
+ number,
+ number
+ ];
+ };
+
+ const target: [number, number, number] | null = calculateCenter(
+ zone.points
+ );
+ if (!target || zone.points.length < 4) return;
+ const position = [target[0], 10, target[2]];
+
+ const input = {
+ userId: userId,
+ organization: organization,
+ zoneData: {
+ zoneName: zone.zoneName,
+ zoneId: zone.zoneId,
+ points: zone.points,
+ viewPortCenter: target,
+ viewPortposition: position,
+ layer: zone.layer,
+ },
+ };
+
+ socket.emit("v2:zone:set", input);
+ };
+
+ const deleteZoneFromBackend = async (zoneId: string) => {
+ const email = localStorage.getItem("email");
+ const userId = localStorage.getItem("userId");
+ const organization = email!.split("@")[1].split(".")[0];
+
+ const input = {
+ userId: userId,
+ organization: organization,
+ zoneId: zoneId,
+ };
+
+ socket.emit("v2:zone:delete", input);
+ };
+
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ const handleDeleteZone = (zoneId: string) => {
+ const updatedZones = zones.filter((zone: any) => zone.zoneId !== zoneId);
+ setZones(updatedZones);
+
+ const zoneIndex = zones.findIndex((zone: any) => zone.zoneId === zoneId);
+ if (zoneIndex !== -1) {
+ const zonePointsToRemove = zonePoints.slice(
+ zoneIndex * 4,
+ zoneIndex * 4 + 4
+ );
+ zonePointsToRemove.forEach((point: any) =>
+ groupsRef.current.remove(point)
+ );
+ const updatedzonePoints = zonePoints.filter(
+ (_: any, index: any) =>
+ index < zoneIndex * 4 || index >= zoneIndex * 4 + 4
+ );
+ setZonePoints(updatedzonePoints);
+ }
+ deleteZoneFromBackend(zoneId);
+ };
+
+ useEffect(() => {
+ if (!camera || !toggleView) return;
+ const canvasElement = gl.domElement;
+
+ let drag = false;
+ let isLeftMouseDown = false;
+
+ const onMouseDown = (evt: any) => {
+ if (evt.button === 0) {
+ isLeftMouseDown = true;
+ drag = false;
+
+ raycaster.setFromCamera(pointer, camera);
+ const intersects = raycaster.intersectObjects(
+ groupsRef.current.children,
+ true
+ );
+
+ if (intersects.length > 0 && toolMode === "move") {
+ const clickedObject = intersects[0].object;
+ const sphereIndex = zonePoints.findIndex((point: any) =>
+ point.equals(clickedObject.position)
+ );
+ if (sphereIndex !== -1) {
+ (controls as any).enabled = false;
+ setDraggedSphere(zonePoints[sphereIndex]);
+ setIsDragging(true);
+ }
+ }
+ }
+ };
+
+ const onMouseUp = (evt: any) => {
+ if (evt.button === 0 && !drag && !isDragging && !deletePointOrLine) {
+ isLeftMouseDown = false;
+
+ if (!startPoint && toolMode !== "move") {
+ raycaster.setFromCamera(pointer, camera);
+ const intersectionPoint = new THREE.Vector3();
+ const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
+ if (point) {
+ setStartPoint(point);
+ setEndPoint(null);
+ }
+ } else if (startPoint && toolMode !== "move") {
+ raycaster.setFromCamera(pointer, camera);
+ const intersectionPoint = new THREE.Vector3();
+ const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
+ if (!point) return;
+
+ const points = [
+ [startPoint.x, 0.15, startPoint.z],
+ [point.x, 0.15, startPoint.z],
+ [point.x, 0.15, point.z],
+ [startPoint.x, 0.15, point.z],
+ [startPoint.x, 0.15, startPoint.z],
+ ] as [number, number, number][];
+
+ const zoneName = `Zone ${zones.length + 1}`;
+ const zoneId = THREE.MathUtils.generateUUID();
+ const newZone = {
+ zoneId,
+ zoneName,
+ points: points,
+ layer: activeLayer,
+ };
+
+ const newZones = [...zones, newZone];
+
+ setZones(newZones);
+
+ const newzonePoints = [
+ new THREE.Vector3(startPoint.x, 0.15, startPoint.z),
+ new THREE.Vector3(point.x, 0.15, startPoint.z),
+ new THREE.Vector3(point.x, 0.15, point.z),
+ new THREE.Vector3(startPoint.x, 0.15, point.z),
+ ];
+
+ const updatedZonePoints = [...zonePoints, ...newzonePoints];
+ setZonePoints(updatedZonePoints);
+
+ addZoneToBackend(newZone);
+ setStartPoint(null);
+ setEndPoint(null);
+ }
+ } else if (
+ evt.button === 0 &&
+ !drag &&
+ !isDragging &&
+ deletePointOrLine
+ ) {
+ raycaster.setFromCamera(pointer, camera);
+ const intersects = raycaster.intersectObjects(
+ groupsRef.current.children,
+ true
+ );
+
+ if (intersects.length > 0) {
+ const clickedObject = intersects[0].object;
+
+ const sphereIndex = zonePoints.findIndex((point: any) =>
+ point.equals(clickedObject.position)
+ );
+ if (sphereIndex !== -1) {
+ const zoneIndex = Math.floor(sphereIndex / 4);
+ const zoneId = zones[zoneIndex].zoneId;
+ handleDeleteZone(zoneId);
+ return;
+ }
+ }
+ }
+
+ if (evt.button === 0) {
+ if (isDragging && draggedSphere) {
+ setIsDragging(false);
+ setDraggedSphere(null);
+
+ const sphereIndex = zonePoints.findIndex(
+ (point: any) => point === draggedSphere
+ );
+ if (sphereIndex !== -1) {
+ const zoneIndex = Math.floor(sphereIndex / 4);
+
+ if (zoneIndex !== -1 && zones[zoneIndex]) {
+ updateZoneToBackend(zones[zoneIndex]);
+ }
+ }
+ }
+ }
+ };
+
+ const onMouseMove = () => {
+ if (isLeftMouseDown) {
+ drag = true;
+ }
+ raycaster.setFromCamera(pointer, camera);
+ const intersects = raycaster.intersectObjects(
+ groupsRef.current.children,
+ true
+ );
+
+ if (
+ intersects.length > 0 &&
+ intersects[0].object.name.includes("point")
+ ) {
+ gl.domElement.style.cursor =
+ toolMode === "move" ? "pointer" : "default";
+ } else {
+ gl.domElement.style.cursor = "default";
+ }
+ if (isDragging && draggedSphere) {
+ raycaster.setFromCamera(pointer, camera);
+ const intersectionPoint = new THREE.Vector3();
+ const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
+ if (point) {
+ draggedSphere.set(point.x, 0.15, point.z);
+
+ const sphereIndex = zonePoints.findIndex(
+ (point: any) => point === draggedSphere
+ );
+ if (sphereIndex !== -1) {
+ const zoneIndex = Math.floor(sphereIndex / 4);
+ const cornerIndex = sphereIndex % 4;
+
+ const updatedZones = zones.map((zone: any, index: number) => {
+ if (index === zoneIndex) {
+ const updatedPoints = [...zone.points];
+ updatedPoints[cornerIndex] = [point.x, 0.15, point.z];
+ updatedPoints[4] = updatedPoints[0];
+ return { ...zone, points: updatedPoints };
+ }
+ return zone;
+ });
+
+ setZones(updatedZones);
+ }
+ }
+ }
+ };
+
+ const onContext = (event: any) => {
+ event.preventDefault();
+ setStartPoint(null);
+ setEndPoint(null);
+ };
+
+ if (toolMode === "Zone" || deletePointOrLine || toolMode === "move") {
+ canvasElement.addEventListener("mousedown", onMouseDown);
+ canvasElement.addEventListener("mouseup", onMouseUp);
+ canvasElement.addEventListener("mousemove", onMouseMove);
+ canvasElement.addEventListener("contextmenu", onContext);
+ }
+ return () => {
+ canvasElement.removeEventListener("mousedown", onMouseDown);
+ canvasElement.removeEventListener("mouseup", onMouseUp);
+ canvasElement.removeEventListener("mousemove", onMouseMove);
+ canvasElement.removeEventListener("contextmenu", onContext);
+ };
+ }, [
+ gl,
+ camera,
+ startPoint,
+ toggleView,
+ scene,
+ toolMode,
+ zones,
+ isDragging,
+ deletePointOrLine,
+ zonePoints,
+ draggedSphere,
+ activeLayer,
+ raycaster,
+ pointer,
+ controls,
+ plane,
+ setZones,
+ setZonePoints,
+ addZoneToBackend,
+ handleDeleteZone,
+ updateZoneToBackend,
+ ]);
+
+ useFrame(() => {
+ if (!startPoint) return;
raycaster.setFromCamera(pointer, camera);
const intersectionPoint = new THREE.Vector3();
const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
if (point) {
- draggedSphere.set(point.x, 0.15, point.z);
-
- const sphereIndex = zonePoints.findIndex(
- (point: any) => point === draggedSphere
- );
- if (sphereIndex !== -1) {
- const zoneIndex = Math.floor(sphereIndex / 4);
- const cornerIndex = sphereIndex % 4;
-
- const updatedZones = zones.map((zone: any, index: number) => {
- if (index === zoneIndex) {
- const updatedPoints = [...zone.points];
- updatedPoints[cornerIndex] = [point.x, 0.15, point.z];
- updatedPoints[4] = updatedPoints[0];
- return { ...zone, points: updatedPoints };
- }
- return zone;
- });
-
- setZones(updatedZones);
- }
+ setEndPoint(point);
}
- }
- };
+ });
- const onContext = (event: any) => {
- event.preventDefault();
- setStartPoint(null);
- setEndPoint(null);
- };
+ return (
+
+
+ {zones.map((zone: any) => (
+
+ {zone.points
+ .slice(0, -1)
+ .map((point: [number, number, number], index: number) => {
+ const nextPoint = zone.points[index + 1];
- if (toolMode === "Zone" || deletePointOrLine || toolMode === "move") {
- canvasElement.addEventListener("mousedown", onMouseDown);
- canvasElement.addEventListener("mouseup", onMouseUp);
- canvasElement.addEventListener("mousemove", onMouseMove);
- canvasElement.addEventListener("contextmenu", onContext);
- }
- return () => {
- canvasElement.removeEventListener("mousedown", onMouseDown);
- canvasElement.removeEventListener("mouseup", onMouseUp);
- canvasElement.removeEventListener("mousemove", onMouseMove);
- canvasElement.removeEventListener("contextmenu", onContext);
- };
- }, [
- gl,
- camera,
- startPoint,
- toggleView,
- scene,
- toolMode,
- zones,
- isDragging,
- deletePointOrLine,
- zonePoints,
- draggedSphere,
- activeLayer,
- raycaster,
- pointer,
- controls,
- plane,
- setZones,
- setZonePoints,
- addZoneToBackend,
- handleDeleteZone,
- updateZoneToBackend,
- ]);
+ const point1 = new THREE.Vector3(point[0], point[1], point[2]);
+ const point2 = new THREE.Vector3(
+ nextPoint[0],
+ nextPoint[1],
+ nextPoint[2]
+ );
- useFrame(() => {
- if (!startPoint) return;
- raycaster.setFromCamera(pointer, camera);
- const intersectionPoint = new THREE.Vector3();
- const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
- if (point) {
- setEndPoint(point);
- }
- });
+ const planeWidth = point1.distanceTo(point2);
+ const planeHeight = CONSTANTS.zoneConfig.height;
- return (
-
-
- {zones.map((zone: any) => (
-
- {zone.points
- .slice(0, -1)
- .map((point: [number, number, number], index: number) => {
- const nextPoint = zone.points[index + 1];
+ const midpoint = new THREE.Vector3(
+ (point1.x + point2.x) / 2,
+ CONSTANTS.zoneConfig.height / 2 +
+ (zone.layer - 1) * CONSTANTS.zoneConfig.height,
+ (point1.z + point2.z) / 2
+ );
- const point1 = new THREE.Vector3(point[0], point[1], point[2]);
- const point2 = new THREE.Vector3(
- nextPoint[0],
- nextPoint[1],
- nextPoint[2]
- );
+ const angle = Math.atan2(
+ point2.z - point1.z,
+ point2.x - point1.x
+ );
- const planeWidth = point1.distanceTo(point2);
- const planeHeight = CONSTANTS.zoneConfig.height;
+ return (
+
+
+
+
+ );
+ })}
+ {!toggleView &&
+ (() => {
+ const points3D = zone.points || [];
+ const coords2D = points3D.map((p: any) => [p[0], p[2]]);
- const midpoint = new THREE.Vector3(
- (point1.x + point2.x) / 2,
- CONSTANTS.zoneConfig.height / 2 +
- (zone.layer - 1) * CONSTANTS.zoneConfig.height,
- (point1.z + point2.z) / 2
- );
+ // Ensure the polygon is closed
+ if (
+ coords2D.length >= 4 &&
+ (coords2D[0][0] !== coords2D[coords2D.length - 1][0] ||
+ coords2D[0][1] !== coords2D[coords2D.length - 1][1])
+ ) {
+ coords2D.push(coords2D[0]);
+ }
+ if (coords2D.length < 4) return null;
- const angle = Math.atan2(
- point2.z - point1.z,
- point2.x - point1.x
- );
+ const polygon = turf.polygon([coords2D]);
+ const center2D = turf.center(polygon).geometry.coordinates;
- return (
-
-
- sum + p[1],
+ 0
+ );
+ const avgY = points3D.length > 0 ? sumY / points3D.length : 0;
+
+ const htmlPosition: [number, number, number] = [
+ center2D[0],
+ avgY + (CONSTANTS.zoneConfig.height || 0) + 1.5,
+ center2D[1],
+ ];
+
+ return (
+
+ {zone.zoneName}
+
+ );
+ })()}
+
+ ))}
+
+
+ {zones
+ .filter((zone: any) => zone.layer === activeLayer)
+ .map((zone: any) => (
+ {
+ e.stopPropagation();
+ if (deletePointOrLine) {
+ handleDeleteZone(zone.zoneId);
+ }
+ }}
+ />
+ ))}
+
+
+ {zones.map((zone: any, index: any) => {
+ if (!toggleView) return null;
+ const points3D = zone.points;
+ const coords2D = points3D.map((p: any) => [p[0], p[2]]);
+
+ if (
+ coords2D.length < 4 ||
+ coords2D[0][0] !== coords2D[coords2D.length - 1][0] ||
+ coords2D[0][1] !== coords2D[coords2D.length - 1][1]
+ ) {
+ coords2D.push(coords2D[0]);
+ }
+ if (coords2D.length < 4) return null;
+
+ const polygon = turf.polygon([coords2D]);
+ const center2D = turf.center(polygon).geometry.coordinates;
+
+ const sumY = points3D.reduce((sum: number, p: any) => sum + p[1], 0);
+ const avgY = sumY / points3D.length;
+
+ const area = computeArea(points3D, "zone");
+ const formattedArea = `${area.toFixed(2)} m²`;
+
+ const htmlPosition: [number, number, number] = [
+ center2D[0],
+ avgY + CONSTANTS.zoneConfig.height,
+ center2D[1],
+ ];
+ return (
+
+
+ {zone.zoneName} ({formattedArea})
+
+
+ );
+ })}
+
+
+
+ {zones
+ .filter((zone: any) => zone.layer === activeLayer)
+ .flatMap((zone: any) =>
+ zone.points.slice(0, 4).map((point: any, pointIndex: number) => (
+
+
+
+ ))
+ )}
+
+
+ {startPoint && endPoint && (
+
-
- );
- })}
- {!toggleView &&
- (() => {
- const points3D = zone.points || [];
- const coords2D = points3D.map((p: any) => [p[0], p[2]]);
-
- // Ensure the polygon is closed
- if (
- coords2D.length >= 4 &&
- (coords2D[0][0] !== coords2D[coords2D.length - 1][0] ||
- coords2D[0][1] !== coords2D[coords2D.length - 1][1])
- ) {
- coords2D.push(coords2D[0]);
- }
- if (coords2D.length < 4) return null;
-
- const polygon = turf.polygon([coords2D]);
- const center2D = turf.center(polygon).geometry.coordinates;
-
- // Calculate the average Y value
- const sumY = points3D.reduce(
- (sum: number, p: any) => sum + p[1],
- 0
- );
- const avgY = points3D.length > 0 ? sumY / points3D.length : 0;
-
- const htmlPosition: [number, number, number] = [
- center2D[0],
- avgY + (CONSTANTS.zoneConfig.height || 0) + 1.5,
- center2D[1],
- ];
-
- return (
-
- {zone.zoneName}
-
- );
- })()}
-
- ))}
-
-
- {zones
- .filter((zone: any) => zone.layer === activeLayer)
- .map((zone: any) => (
- {
- e.stopPropagation();
- if (deletePointOrLine) {
- handleDeleteZone(zone.zoneId);
- }
- }}
- />
- ))}
-
-
- {zones.map((zone: any, index: any) => {
- if (!toggleView) return null;
- const points3D = zone.points;
- const coords2D = points3D.map((p: any) => [p[0], p[2]]);
-
- if (
- coords2D.length < 4 ||
- coords2D[0][0] !== coords2D[coords2D.length - 1][0] ||
- coords2D[0][1] !== coords2D[coords2D.length - 1][1]
- ) {
- coords2D.push(coords2D[0]);
- }
- if (coords2D.length < 4) return null;
-
- const polygon = turf.polygon([coords2D]);
- const center2D = turf.center(polygon).geometry.coordinates;
-
- const sumY = points3D.reduce((sum: number, p: any) => sum + p[1], 0);
- const avgY = sumY / points3D.length;
-
- const area = computeArea(points3D, "zone");
- const formattedArea = `${area.toFixed(2)} m²`;
-
- const htmlPosition: [number, number, number] = [
- center2D[0],
- avgY + CONSTANTS.zoneConfig.height,
- center2D[1],
- ];
- return (
-
-
- {zone.zoneName} ({formattedArea})
-
-
- );
- })}
-
-
-
- {zones
- .filter((zone: any) => zone.layer === activeLayer)
- .flatMap((zone: any) =>
- zone.points.slice(0, 4).map((point: any, pointIndex: number) => (
-
-
-
- ))
- )}
-
-
- {startPoint && endPoint && (
-
- )}
-
-
- );
+ )}
+
+
+ );
};
export default ZoneGroup;
diff --git a/app/src/modules/builder/point/helpers/useAisleDragSnap.tsx b/app/src/modules/builder/point/helpers/useAisleDragSnap.tsx
index 123c7e3..d97e9d4 100644
--- a/app/src/modules/builder/point/helpers/useAisleDragSnap.tsx
+++ b/app/src/modules/builder/point/helpers/useAisleDragSnap.tsx
@@ -16,7 +16,7 @@ export function useAislePointSnapping(point: Point) {
} => {
if (!CAN_SNAP) return { position: newPosition, isSnapped: false, snapSources: [] };
- const connectedPoints = getConnectedPoints(point.uuid);
+ const connectedPoints = getConnectedPoints(point.pointUuid);
if (connectedPoints.length === 0) {
return {
position: newPosition,
@@ -68,7 +68,7 @@ export function useAislePointSnapping(point: Point) {
isSnapped,
snapSources
};
- }, [point.uuid, getConnectedPoints]);
+ }, [point.pointUuid, getConnectedPoints]);
return { snapPosition };
}
diff --git a/app/src/modules/builder/point/helpers/usePointSnapping.tsx b/app/src/modules/builder/point/helpers/usePointSnapping.tsx
index 4d61b8a..8d56085 100644
--- a/app/src/modules/builder/point/helpers/usePointSnapping.tsx
+++ b/app/src/modules/builder/point/helpers/usePointSnapping.tsx
@@ -13,7 +13,7 @@ export const usePointSnapping = (currentPoint: { uuid: string, pointType: string
if (!currentPoint) return [];
return aisles.flatMap(aisle =>
- aisle.points.filter(point => point.uuid !== currentPoint.uuid)
+ aisle.points.filter(point => point.pointUuid !== currentPoint.uuid)
);
}, [aisles, currentPoint]);
diff --git a/app/src/modules/builder/point/point.tsx b/app/src/modules/builder/point/point.tsx
index a6c22c9..5c000f7 100644
--- a/app/src/modules/builder/point/point.tsx
+++ b/app/src/modules/builder/point/point.tsx
@@ -17,7 +17,7 @@ function Point({ point }: { readonly point: Point }) {
const { toolMode } = useToolMode();
const { setPosition, removePoint } = useAisleStore();
const { snapPosition } = useAislePointSnapping(point);
- const { checkSnapForAisle } = usePointSnapping({ uuid: point.uuid, pointType: point.pointType, position: point.position });
+ const { checkSnapForAisle } = usePointSnapping({ uuid: point.pointUuid, pointType: point.pointType, position: point.position });
const { hoveredPoint, setHoveredPoint } = useBuilderStore();
const { deletePointOrLine } = useDeletePointOrLine();
@@ -63,7 +63,7 @@ function Point({ point }: { readonly point: Point }) {
const aisleSnappedPosition = snapPosition(newPosition);
const finalSnappedPosition = checkSnapForAisle(aisleSnappedPosition.position);
- setPosition(point.uuid, finalSnappedPosition.position);
+ setPosition(point.pointUuid, finalSnappedPosition.position);
}
}
}
@@ -76,7 +76,7 @@ function Point({ point }: { readonly point: Point }) {
const handlePointClick = (point: Point) => {
if (deletePointOrLine) {
- const removedAisles = removePoint(point.uuid);
+ const removedAisles = removePoint(point.pointUuid);
if (removedAisles.length > 0) {
setHoveredPoint(null);
console.log(removedAisles);
@@ -85,7 +85,7 @@ function Point({ point }: { readonly point: Point }) {
}
useEffect(() => {
- if (hoveredPoint && hoveredPoint.uuid !== point.uuid) {
+ if (hoveredPoint && hoveredPoint.pointUuid !== point.pointUuid) {
setIsHovered(false);
}
}, [hoveredPoint])
@@ -102,8 +102,8 @@ function Point({ point }: { readonly point: Point }) {
onDragEnd={() => { handleDragEnd(point) }}
>
{
@@ -116,7 +116,7 @@ function Point({ point }: { readonly point: Point }) {
}
}}
onPointerOut={() => {
- if (hoveredPoint && hoveredPoint.uuid === point.uuid) {
+ if (hoveredPoint && hoveredPoint.pointUuid === point.pointUuid) {
setHoveredPoint(null);
}
setIsHovered(false)
diff --git a/app/src/store/builder/useAisleStore.ts b/app/src/store/builder/useAisleStore.ts
index 71197c2..f379e35 100644
--- a/app/src/store/builder/useAisleStore.ts
+++ b/app/src/store/builder/useAisleStore.ts
@@ -30,7 +30,7 @@ interface AisleStore {
) => void;
setArcAisleWidth: (aisleUuid: string, width: number) => void;
setCircleAisleWidth: (aisleUuid: string, width: number) => void;
- setJunctionAisleWidth: (aisleUuid: string, width: number) => void;
+ setJunctionAisleProperties: (aisleUuid: string, props: { aisleWidth?: number; isFlipped: boolean; }) => void;
getAisleById: (uuid: string) => Aisle | undefined;
getAislePointById: (uuid: string) => Point | undefined;
@@ -51,21 +51,21 @@ export const useAisleStore = create()(
}),
updateAisle: (uuid, updated) => set((state) => {
- const aisle = state.aisles.find((a) => a.uuid === uuid);
+ const aisle = state.aisles.find((a) => a.aisleUuid === uuid);
if (aisle) {
Object.assign(aisle, updated);
}
}),
removeAisle: (uuid) => set((state) => {
- state.aisles = state.aisles.filter((a) => a.uuid !== uuid);
+ state.aisles = state.aisles.filter((a) => a.aisleUuid !== uuid);
}),
removePoint: (uuid) => {
const removedAisles: Aisle[] = [];
set((state) => {
state.aisles = state.aisles.filter((aisle) => {
- const hasPoint = aisle.points.some((point) => point.uuid === uuid);
+ const hasPoint = aisle.points.some((point) => point.pointUuid === uuid);
if (hasPoint) {
removedAisles.push(JSON.parse(JSON.stringify(aisle)));
return false;
@@ -79,7 +79,7 @@ export const useAisleStore = create()(
setPosition: (pointUuid, position) => set((state) => {
for (const aisle of state.aisles) {
- const point = aisle.points.find(p => p.uuid === pointUuid);
+ const point = aisle.points.find(p => p.pointUuid === pointUuid);
if (point) {
point.position = position;
}
@@ -88,7 +88,7 @@ export const useAisleStore = create()(
setLayer: (pointUuid, layer) => set((state) => {
for (const aisle of state.aisles) {
- const point = aisle.points.find(p => p.uuid === pointUuid);
+ const point = aisle.points.find(p => p.pointUuid === pointUuid);
if (point) {
point.layer = layer;
}
@@ -96,7 +96,7 @@ export const useAisleStore = create()(
}),
setColor: (aisleUuid, color) => set((state) => {
- const aisle = state.aisles.find(a => a.uuid === aisleUuid);
+ const aisle = state.aisles.find(a => a.aisleUuid === aisleUuid);
if (aisle) {
aisle.type.aisleColor = color;
}
@@ -104,14 +104,14 @@ export const useAisleStore = create()(
// Type-specific property setters
setSolidAisleWidth: (aisleUuid, width) => set((state) => {
- const aisle = state.aisles.find(a => a.uuid === aisleUuid);
+ const aisle = state.aisles.find(a => a.aisleUuid === aisleUuid);
if (aisle && aisle.type.aisleType === 'solid-aisle') {
aisle.type.aisleWidth = width;
}
}),
setDashedAisleProperties: (aisleUuid, props) => set((state) => {
- const aisle = state.aisles.find(a => a.uuid === aisleUuid);
+ const aisle = state.aisles.find(a => a.aisleUuid === aisleUuid);
if (aisle && aisle.type.aisleType === 'dashed-aisle') {
if (props.aisleWidth !== undefined) aisle.type.aisleWidth = props.aisleWidth;
if (props.dashLength !== undefined) aisle.type.dashLength = props.dashLength;
@@ -120,14 +120,14 @@ export const useAisleStore = create()(
}),
setStrippedAisleWidth: (aisleUuid, width) => set((state) => {
- const aisle = state.aisles.find(a => a.uuid === aisleUuid);
+ const aisle = state.aisles.find(a => a.aisleUuid === aisleUuid);
if (aisle && aisle.type.aisleType === 'stripped-aisle') {
aisle.type.aisleWidth = width;
}
}),
setDottedAisleProperties: (aisleUuid, props) => set((state) => {
- const aisle = state.aisles.find(a => a.uuid === aisleUuid);
+ const aisle = state.aisles.find(a => a.aisleUuid === aisleUuid);
if (aisle && aisle.type.aisleType === 'dotted-aisle') {
if (props.dotRadius !== undefined) aisle.type.dotRadius = props.dotRadius;
if (props.gapLength !== undefined) aisle.type.gapLength = props.gapLength;
@@ -135,14 +135,14 @@ export const useAisleStore = create()(
}),
setArrowAisleWidth: (aisleUuid, width) => set((state) => {
- const aisle = state.aisles.find(a => a.uuid === aisleUuid);
+ const aisle = state.aisles.find(a => a.aisleUuid === aisleUuid);
if (aisle && aisle.type.aisleType === 'arrow-aisle') {
aisle.type.aisleWidth = width;
}
}),
setArrowsAisleProperties: (aisleUuid, props) => set((state) => {
- const aisle = state.aisles.find(a => a.uuid === aisleUuid);
+ const aisle = state.aisles.find(a => a.aisleUuid === aisleUuid);
if (aisle && aisle.type.aisleType === 'arrows-aisle') {
if (props.aisleWidth !== undefined) aisle.type.aisleWidth = props.aisleWidth;
if (props.aisleLength !== undefined) aisle.type.aisleLength = props.aisleLength;
@@ -151,33 +151,34 @@ export const useAisleStore = create()(
}),
setArcAisleWidth: (aisleUuid, width) => set((state) => {
- const aisle = state.aisles.find(a => a.uuid === aisleUuid);
+ const aisle = state.aisles.find(a => a.aisleUuid === aisleUuid);
if (aisle && aisle.type.aisleType === 'arc-aisle') {
aisle.type.aisleWidth = width;
}
}),
setCircleAisleWidth: (aisleUuid, width) => set((state) => {
- const aisle = state.aisles.find(a => a.uuid === aisleUuid);
+ const aisle = state.aisles.find(a => a.aisleUuid === aisleUuid);
if (aisle && aisle.type.aisleType === 'circle-aisle') {
aisle.type.aisleWidth = width;
}
}),
- setJunctionAisleWidth: (aisleUuid, width) => set((state) => {
- const aisle = state.aisles.find(a => a.uuid === aisleUuid);
+ setJunctionAisleProperties: (aisleUuid, props) => set((state) => {
+ const aisle = state.aisles.find(a => a.aisleUuid === aisleUuid);
if (aisle && aisle.type.aisleType === 'junction-aisle') {
- aisle.type.aisleWidth = width;
+ if (props.aisleWidth !== undefined) aisle.type.aisleWidth = props.aisleWidth;
+ if (props.isFlipped !== undefined) aisle.type.isFlipped = props.isFlipped;
}
}),
getAisleById: (uuid) => {
- return get().aisles.find((a) => a.uuid === uuid);
+ return get().aisles.find((a) => a.aisleUuid === uuid);
},
getAislePointById: (uuid) => {
for (const aisle of get().aisles) {
- const point = aisle.points.find(p => p.uuid === uuid);
+ const point = aisle.points.find(p => p.pointUuid === uuid);
if (point) {
return point;
}
@@ -189,8 +190,8 @@ export const useAisleStore = create()(
const connected: Point[] = [];
for (const aisle of get().aisles) {
for (const point of aisle.points) {
- if (point.uuid === uuid) {
- connected.push(...aisle.points.filter(p => p.uuid !== uuid));
+ if (point.pointUuid === uuid) {
+ connected.push(...aisle.points.filter(p => p.pointUuid !== uuid));
}
}
}
@@ -198,7 +199,7 @@ export const useAisleStore = create()(
},
getAisleType: (uuid: string) => {
- const aisle = get().aisles.find(a => a.uuid === uuid);
+ const aisle = get().aisles.find(a => a.aisleUuid === uuid);
return aisle?.type as T | undefined;
},
}))
diff --git a/app/src/store/builder/useBuilderStore.ts b/app/src/store/builder/useBuilderStore.ts
index dc3524e..8b209dc 100644
--- a/app/src/store/builder/useBuilderStore.ts
+++ b/app/src/store/builder/useBuilderStore.ts
@@ -25,6 +25,9 @@ interface BuilderState {
// Arrows aisle properties
aisleLength: number;
+ // Junction aisle properties
+ isFlipped: boolean;
+
// Setters for common properties
setHoveredPoint: (point: Point | null) => void;
@@ -47,6 +50,9 @@ interface BuilderState {
// Setters for arrows aisle
setAisleLength: (length: number) => void;
+ // Setters for junction aisle
+ setIsFlipped: (isFlipped: boolean) => void;
+
// Batch setters
setDashedAisleProperties: (width: number, dashLength: number, gapLength: number) => void;
setDottedAisleProperties: (width: number, dotRadius: number, gapLength: number) => void;
@@ -71,6 +77,7 @@ export const useBuilderStore = create()(
gapLength: 0.3,
dotRadius: 0.1,
aisleLength: 0.6,
+ isFlipped: false,
// Individual setters
@@ -133,6 +140,11 @@ export const useBuilderStore = create()(
state.aisleLength = length;
});
},
+ setIsFlipped: (isFlipped) => {
+ set((state) => {
+ state.isFlipped = isFlipped;
+ });
+ },
// Batch setters
setDashedAisleProperties: (width, dashLength, gapLength) => {
diff --git a/app/src/types/builderTypes.d.ts b/app/src/types/builderTypes.d.ts
index b9f7616..c43805c 100644
--- a/app/src/types/builderTypes.d.ts
+++ b/app/src/types/builderTypes.d.ts
@@ -34,7 +34,7 @@ type Assets = Asset[];
type PointTypes = 'Aisle' | 'Wall' | 'Floor' | 'Zone';
interface Point {
- uuid: string;
+ pointUuid: string;
pointType: PointTypes;
position: [number, number, number];
layer: number;
@@ -102,12 +102,13 @@ interface JunctionAisle {
aisleType: 'junction-aisle';
aisleColor: AisleColors;
aisleWidth: number;
+ isFlipped: boolean;
}
type AisleType = SolidAisle | DashedAisle | StrippedAisle | DottedAisle | ArrowAisle | ArrowsAisle | ArcAisle | CircleAisle | JunctionAisle;
interface Aisle {
- uuid: string;
+ aisleUuid: string;
points: [Point, Point];
type: AisleType;
}