Refactor point and aisle handling to use pointUuid and aisleUuid consistently
- Updated useAislePointSnapping and usePointSnapping to reference point.pointUuid instead of point.uuid. - Modified Point component to utilize point.pointUuid for snapping and position updates. - Changed useAisleStore methods to work with aisleUuid and point.pointUuid for better clarity and consistency. - Introduced new properties for junction aisles, including isFlipped, and updated related logic. - Added implementations for ArrowAisle, CircleAisle, and JunctionAisle components to handle rendering and interactions.
This commit is contained in:
parent
d827b4e75b
commit
da741ed6df
|
@ -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 &&
|
||||
<InputToggle
|
||||
inputKey="Flip Ailse"
|
||||
label="Flip Aisle"
|
||||
value={aisleIsFlipped}
|
||||
onClick={handleIsFlippedChange}
|
||||
/>
|
||||
}
|
||||
</>
|
||||
)
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -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 &&
|
||||
<group name='Aisle-Points-Group'>
|
||||
{allPoints.map((point) => (
|
||||
<Point key={point.uuid} point={point} />
|
||||
<Point key={point.pointUuid} point={point} />
|
||||
))}
|
||||
</group>
|
||||
}
|
||||
|
@ -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}>
|
||||
<AisleInstance aisle={aisle} key={aisle.uuid} />
|
||||
< React.Fragment key={aisle.aisleUuid}>
|
||||
<AisleInstance aisle={aisle} key={aisle.aisleUuid} />
|
||||
|
||||
{toggleView &&
|
||||
<Html
|
||||
// data
|
||||
key={`${aisle.points[0].uuid}_${aisle.points[1].uuid}`}
|
||||
key={`${aisle.points[0].pointUuid}_${aisle.points[1].pointUuid}`}
|
||||
userData={aisle}
|
||||
position={[textPosition.x, 1, textPosition.z]}
|
||||
// class
|
||||
|
@ -64,8 +64,8 @@ function AisleInstances() {
|
|||
sprite
|
||||
>
|
||||
<div
|
||||
key={aisle.uuid}
|
||||
className={`distance ${aisle.uuid}`}
|
||||
key={aisle.aisleUuid}
|
||||
className={`distance ${aisle.aisleUuid}`}
|
||||
>
|
||||
{distance.toFixed(2)} m
|
||||
</div>
|
||||
|
|
|
@ -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' && (
|
||||
<ArrowsAisle aisle={aisle} />
|
||||
)}
|
||||
|
||||
{aisle.type.aisleType === 'arrow-aisle' && (
|
||||
<ArrowAisle aisle={aisle} />
|
||||
)}
|
||||
|
||||
{aisle.type.aisleType === 'circle-aisle' && (
|
||||
<CircleAisle aisle={aisle} />
|
||||
)}
|
||||
|
||||
{aisle.type.aisleType === 'junction-aisle' && (
|
||||
<JunctionAisle aisle={aisle} />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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<THREE.Group>(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 (
|
||||
<group
|
||||
name='Arrow-Aisle'
|
||||
ref={aisleRef}
|
||||
position={[0, (aisle.points[0].layer - 1) * Constants.wallConfig.height + 0.01, 0]}
|
||||
rotation={[Math.PI / 2, 0, 0]}
|
||||
userData={aisle}
|
||||
onClick={handleClick}
|
||||
onPointerMissed={() => {
|
||||
setSelectedAisle(null);
|
||||
}}
|
||||
>
|
||||
<group position={[arrow.position.x, arrow.position.z, 0]} rotation={[0, 0, -arrow.rotationY]}>
|
||||
<Extrude
|
||||
args={[arrow.shape, { depth: 0.01, bevelEnabled: false }]}
|
||||
receiveShadow
|
||||
castShadow
|
||||
>
|
||||
<meshStandardMaterial
|
||||
color={aisle.type.aisleColor || '#ffffff'}
|
||||
side={THREE.DoubleSide}
|
||||
/>
|
||||
</Extrude>
|
||||
</group>
|
||||
</group>
|
||||
);
|
||||
}
|
||||
|
||||
export default ArrowAisle;
|
|
@ -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<THREE.Group>(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 (
|
||||
<group
|
||||
name='Circle-Aisle'
|
||||
ref={aisleRef}
|
||||
position={[0, (aisle.points[0].layer - 1) * Constants.wallConfig.height + 0.01, 0]}
|
||||
rotation={[Math.PI / 2, 0, 0]}
|
||||
userData={aisle}
|
||||
onClick={handleClick}
|
||||
onPointerMissed={() => {
|
||||
setSelectedAisle(null);
|
||||
}}
|
||||
>
|
||||
<group position={[circle.position.x, circle.position.z, 0]}>
|
||||
<Extrude
|
||||
args={[circle.shape, {
|
||||
depth: 0.01,
|
||||
bevelEnabled: false,
|
||||
steps: 1,
|
||||
curveSegments: 64
|
||||
}]}
|
||||
receiveShadow
|
||||
castShadow
|
||||
>
|
||||
<meshStandardMaterial
|
||||
color={aisle.type.aisleColor || '#ffffff'}
|
||||
side={THREE.DoubleSide}
|
||||
/>
|
||||
</Extrude>
|
||||
</group>
|
||||
</group>
|
||||
);
|
||||
}
|
||||
|
||||
export default CircleAisle;
|
|
@ -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<THREE.Group>(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 (
|
||||
<group
|
||||
name='Junction-Aisle'
|
||||
ref={aisleRef}
|
||||
position={[0, (aisle.points[0].layer - 1) * Constants.wallConfig.height + 0.01, 0]}
|
||||
rotation={[Math.PI / 2, 0, 0]}
|
||||
userData={aisle}
|
||||
onClick={handleClick}
|
||||
onPointerMissed={() => {
|
||||
setSelectedAisle(null);
|
||||
}}
|
||||
>
|
||||
{arrows.map((arrow, index) => (
|
||||
<group key={index} position={[arrow.position.x, arrow.position.z, 0]} rotation={[0, 0, -arrow.rotationY]}>
|
||||
<Extrude
|
||||
args={[arrow.shape, { depth: 0.01, bevelEnabled: false }]}
|
||||
receiveShadow
|
||||
castShadow
|
||||
>
|
||||
<meshStandardMaterial
|
||||
color={aisle.type.aisleColor || '#ffffff'}
|
||||
side={THREE.DoubleSide}
|
||||
/>
|
||||
</Extrude>
|
||||
</group>
|
||||
))}
|
||||
</group>
|
||||
);
|
||||
}
|
||||
|
||||
export default JunctionAisle;
|
|
@ -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<Point[]>([]);
|
||||
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() {
|
|||
<>
|
||||
<group name='Aisle-Reference-Points-Group'>
|
||||
{tempPoints.map((point) => (
|
||||
<ReferencePoint key={point.uuid} point={point} />
|
||||
<ReferencePoint key={point.pointUuid} point={point} />
|
||||
))}
|
||||
</group>
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ interface ReferenceAisleProps {
|
|||
}
|
||||
|
||||
function ReferenceAisle({ tempPoints }: Readonly<ReferenceAisleProps>) {
|
||||
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<ReferenceAisleProps>) {
|
|||
const [tempAisle, setTempAisle] = useState<Aisle | null>(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<ReferenceAisleProps>) {
|
|||
|
||||
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<ReferenceAisleProps>) {
|
|||
});
|
||||
} 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<ReferenceAisleProps>) {
|
|||
});
|
||||
} 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<ReferenceAisleProps>) {
|
|||
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<ReferenceAisleProps>) {
|
|||
});
|
||||
} 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<ReferenceAisleProps>) {
|
|||
return <DashedAisle aisle={tempAisle} />;
|
||||
case 'dotted-aisle':
|
||||
return <DottedAisle aisle={tempAisle} />;
|
||||
case 'arrow-aisle':
|
||||
return <ArrowAisle aisle={tempAisle} />;
|
||||
case 'arrows-aisle':
|
||||
return <ArrowsAisle aisle={tempAisle} />
|
||||
return <ArrowsAisle aisle={tempAisle} />;
|
||||
case 'circle-aisle':
|
||||
return <CircleAisle aisle={tempAisle} />;
|
||||
case 'junction-aisle':
|
||||
return <JunctionAisle aisle={tempAisle} />;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
@ -182,7 +218,7 @@ function ReferenceAisle({ tempPoints }: Readonly<ReferenceAisleProps>) {
|
|||
{toggleView &&
|
||||
<Html
|
||||
// data
|
||||
key={tempAisle.uuid}
|
||||
key={tempAisle.aisleUuid}
|
||||
userData={tempAisle}
|
||||
position={[textPosition.x, 1, textPosition.z]}
|
||||
// class
|
||||
|
@ -194,8 +230,8 @@ function ReferenceAisle({ tempPoints }: Readonly<ReferenceAisleProps>) {
|
|||
sprite
|
||||
>
|
||||
<div
|
||||
key={tempAisle.uuid}
|
||||
className={`distance ${tempAisle.uuid}`}
|
||||
key={tempAisle.aisleUuid}
|
||||
className={`distance ${tempAisle.aisleUuid}`}
|
||||
>
|
||||
{distance.toFixed(2)} m
|
||||
</div>
|
||||
|
@ -446,3 +482,227 @@ function ArrowsAisle({ aisle }: { readonly aisle: Aisle }) {
|
|||
</group>
|
||||
);
|
||||
}
|
||||
|
||||
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 (
|
||||
<group
|
||||
position={[0, (aisle.points[0].layer - 1) * Constants.wallConfig.height + 0.01, 0]}
|
||||
rotation={[Math.PI / 2, 0, 0]}
|
||||
>
|
||||
<group position={[arrow.position.x, arrow.position.z, 0]} rotation={[0, 0, -arrow.rotationY]}>
|
||||
<Extrude
|
||||
args={[arrow.shape, { depth: 0.01, bevelEnabled: false }]}
|
||||
receiveShadow
|
||||
castShadow
|
||||
>
|
||||
<meshStandardMaterial
|
||||
color={aisle.type.aisleColor || '#ffffff'}
|
||||
side={THREE.DoubleSide}
|
||||
/>
|
||||
</Extrude>
|
||||
</group>
|
||||
</group>
|
||||
);
|
||||
}
|
||||
|
||||
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 (
|
||||
<group
|
||||
position={[0, (aisle.points[0].layer - 1) * Constants.wallConfig.height + 0.01, 0]}
|
||||
rotation={[Math.PI / 2, 0, 0]}
|
||||
>
|
||||
<group position={[circle.position.x, circle.position.z, 0]}>
|
||||
<Extrude
|
||||
args={[circle.shape, {
|
||||
depth: 0.01,
|
||||
bevelEnabled: false,
|
||||
steps: 1,
|
||||
curveSegments: 64
|
||||
}]}
|
||||
receiveShadow
|
||||
castShadow
|
||||
>
|
||||
<meshStandardMaterial
|
||||
color={aisle.type.aisleColor || '#ffffff'}
|
||||
side={THREE.DoubleSide}
|
||||
/>
|
||||
</Extrude>
|
||||
</group>
|
||||
</group>
|
||||
);
|
||||
}
|
||||
|
||||
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 (
|
||||
<group
|
||||
position={[0, (aisle.points[0].layer - 1) * Constants.wallConfig.height + 0.01, 0]}
|
||||
rotation={[Math.PI / 2, 0, 0]}
|
||||
>
|
||||
{arrows.map((arrow, index) => (
|
||||
<group key={index} position={[arrow.position.x, arrow.position.z, 0]} rotation={[0, 0, -arrow.rotationY]}>
|
||||
<Extrude
|
||||
args={[arrow.shape, { depth: 0.01, bevelEnabled: false }]}
|
||||
receiveShadow
|
||||
castShadow
|
||||
>
|
||||
<meshStandardMaterial
|
||||
color={aisle.type.aisleColor || '#ffffff'}
|
||||
side={THREE.DoubleSide}
|
||||
/>
|
||||
</Extrude>
|
||||
</group>
|
||||
))}
|
||||
</group>
|
||||
);
|
||||
}
|
|
@ -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() {
|
|||
|
||||
<ZoneGroup />
|
||||
|
||||
{/* <FloorGroupAilse
|
||||
floorGroupAisle={floorGroupAisle}
|
||||
plane={plane}
|
||||
floorPlanGroupLine={floorPlanGroupLine}
|
||||
floorPlanGroupPoint={floorPlanGroupPoint}
|
||||
line={line}
|
||||
lines={lines}
|
||||
currentLayerPoint={currentLayerPoint}
|
||||
dragPointControls={dragPointControls}
|
||||
floorPlanGroup={floorPlanGroup}
|
||||
ReferenceLineMesh={ReferenceLineMesh}
|
||||
LineCreated={LineCreated}
|
||||
isSnapped={isSnapped}
|
||||
ispreSnapped={ispreSnapped}
|
||||
snappedPoint={snappedPoint}
|
||||
isSnappedUUID={isSnappedUUID}
|
||||
isAngleSnapped={isAngleSnapped}
|
||||
anglesnappedPoint={anglesnappedPoint}
|
||||
/> */}
|
||||
|
||||
<AssetsGroup
|
||||
floorGroup={floorGroup}
|
||||
plane={plane}
|
||||
|
|
|
@ -1,56 +0,0 @@
|
|||
import * as THREE from 'three';
|
||||
import * as Types from '../../../../types/world/worldTypes';
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
|
||||
export default async function addAisleToScene(
|
||||
aisle: Types.Line,
|
||||
floorGroupAisle: Types.RefGroup,
|
||||
): Promise<void> {
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -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 (
|
||||
<group ref={floorGroupAisle} visible={!toggleView} name="floorGroupAisle">
|
||||
</group>
|
||||
)
|
||||
}
|
||||
|
||||
export default FloorGroupAilse;
|
|
@ -91,6 +91,7 @@ const ZoneGroup: React.FC = () => {
|
|||
layer: zone.layer,
|
||||
}));
|
||||
|
||||
console.log('fetchedZones: ', fetchedZones);
|
||||
setZones(fetchedZones);
|
||||
|
||||
const fetchedPoints = data.data.flatMap((zone: any) =>
|
||||
|
@ -109,6 +110,7 @@ const ZoneGroup: React.FC = () => {
|
|||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
console.log('zones: ', zones);
|
||||
localStorage.setItem("zones", JSON.stringify(zones));
|
||||
}, [zones]);
|
||||
|
||||
|
@ -156,6 +158,7 @@ const ZoneGroup: React.FC = () => {
|
|||
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];
|
||||
|
|
|
@ -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 };
|
||||
}
|
||||
|
|
|
@ -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]);
|
||||
|
||||
|
|
|
@ -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) }}
|
||||
>
|
||||
<mesh
|
||||
key={point.uuid}
|
||||
uuid={point.uuid}
|
||||
key={point.pointUuid}
|
||||
uuid={point.pointUuid}
|
||||
name='Aisle-Point'
|
||||
position={new THREE.Vector3(...point.position)}
|
||||
onClick={() => {
|
||||
|
@ -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)
|
||||
|
|
|
@ -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<AisleStore>()(
|
|||
}),
|
||||
|
||||
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<AisleStore>()(
|
|||
|
||||
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<AisleStore>()(
|
|||
|
||||
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<AisleStore>()(
|
|||
}),
|
||||
|
||||
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<AisleStore>()(
|
|||
|
||||
// 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<AisleStore>()(
|
|||
}),
|
||||
|
||||
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<AisleStore>()(
|
|||
}),
|
||||
|
||||
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<AisleStore>()(
|
|||
}),
|
||||
|
||||
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<AisleStore>()(
|
|||
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<AisleStore>()(
|
|||
},
|
||||
|
||||
getAisleType: <T extends AisleType>(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;
|
||||
},
|
||||
}))
|
||||
|
|
|
@ -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<BuilderState>()(
|
|||
gapLength: 0.3,
|
||||
dotRadius: 0.1,
|
||||
aisleLength: 0.6,
|
||||
isFlipped: false,
|
||||
|
||||
// Individual setters
|
||||
|
||||
|
@ -133,6 +140,11 @@ export const useBuilderStore = create<BuilderState>()(
|
|||
state.aisleLength = length;
|
||||
});
|
||||
},
|
||||
setIsFlipped: (isFlipped) => {
|
||||
set((state) => {
|
||||
state.isFlipped = isFlipped;
|
||||
});
|
||||
},
|
||||
|
||||
// Batch setters
|
||||
setDashedAisleProperties: (width, dashLength, gapLength) => {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue