diff --git a/app/src/components/layout/sidebarRight/properties/AisleProperties.tsx b/app/src/components/layout/sidebarRight/properties/AisleProperties.tsx
index a613699..644aad2 100644
--- a/app/src/components/layout/sidebarRight/properties/AisleProperties.tsx
+++ b/app/src/components/layout/sidebarRight/properties/AisleProperties.tsx
@@ -194,7 +194,7 @@ const AisleProperties: React.FC = () => {
}
>
);
- case 'junction-aisle':
+ case 'junction-aisle': case 'arc-aisle':
return (
<>
{aisleType &&
@@ -206,7 +206,7 @@ const AisleProperties: React.FC = () => {
/>
}
>
- )
+ );
default:
return null;
}
diff --git a/app/src/modules/builder/aisle/Instances/instance/aisleInstance.tsx b/app/src/modules/builder/aisle/Instances/instance/aisleInstance.tsx
index c8ecdd7..181d926 100644
--- a/app/src/modules/builder/aisle/Instances/instance/aisleInstance.tsx
+++ b/app/src/modules/builder/aisle/Instances/instance/aisleInstance.tsx
@@ -1,3 +1,4 @@
+import ArcAisle from './aisleTypes/arcAisle';
import ArrowAisle from './aisleTypes/arrowAisle';
import ArrowsAisle from './aisleTypes/arrowsAisle';
import CircleAisle from './aisleTypes/circleAisle';
@@ -37,6 +38,10 @@ function AisleInstance({ aisle }: { readonly aisle: Aisle }) {
{aisle.type.aisleType === 'junction-aisle' && (
)}
+
+ {aisle.type.aisleType === 'arc-aisle' && (
+
+ )}
>
);
}
diff --git a/app/src/modules/builder/aisle/Instances/instance/aisleTypes/arcAisle.tsx b/app/src/modules/builder/aisle/Instances/instance/aisleTypes/arcAisle.tsx
new file mode 100644
index 0000000..824938d
--- /dev/null
+++ b/app/src/modules/builder/aisle/Instances/instance/aisleTypes/arcAisle.tsx
@@ -0,0 +1,103 @@
+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 ArcAisle({ aisle }: { readonly aisle: Aisle }) {
+ const aisleRef = useRef(null);
+ const { toolMode } = useToolMode();
+ const { setSelectedAisle, hoveredPoint } = useBuilderStore();
+
+ const arc = useMemo(() => {
+ if (aisle.points.length < 2 || aisle.type.aisleType !== 'arc-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.5;
+ const isFlipped = aisle.type.isFlipped || false;
+
+ const direction = new THREE.Vector3().subVectors(end, start);
+ const length = direction.length();
+ direction.normalize();
+
+ const perpendicular = new THREE.Vector3(-direction.z, 0, direction.x).normalize();
+ if (!isFlipped) perpendicular.negate();
+
+ const arcHeight = length * 0.25;
+ const midPoint = new THREE.Vector3().lerpVectors(start, end, 0.5);
+ const controlPoint = new THREE.Vector3().copy(midPoint).addScaledVector(perpendicular, arcHeight);
+
+ const widthOffset = perpendicular.clone().multiplyScalar(width / 2);
+
+ const p1 = new THREE.Vector3().copy(start).add(widthOffset);
+ const p2 = new THREE.Vector3().copy(end).add(widthOffset);
+ const p3 = new THREE.Vector3().copy(end).sub(widthOffset);
+ const p4 = new THREE.Vector3().copy(start).sub(widthOffset);
+
+ const shape = new THREE.Shape();
+ shape.moveTo(p1.x, p1.z);
+
+ shape.quadraticCurveTo(
+ controlPoint.x + widthOffset.x,
+ controlPoint.z + widthOffset.z,
+ p2.x, p2.z
+ );
+
+ shape.lineTo(p3.x, p3.z);
+
+ shape.quadraticCurveTo(
+ controlPoint.x - widthOffset.x,
+ controlPoint.z - widthOffset.z,
+ p4.x, p4.z
+ );
+
+ shape.lineTo(p1.x, p1.z);
+
+ return {
+ shape,
+ position: new THREE.Vector3(0, 0, 0),
+ rotationY: 0
+ };
+ }, [aisle]);
+
+ const handleClick = () => {
+ if (toolMode === 'move' && !hoveredPoint) {
+ setSelectedAisle(aisleRef.current);
+ }
+ }
+
+ if (!arc) return null;
+
+ return (
+ {
+ setSelectedAisle(null);
+ }}
+ >
+
+
+
+
+ );
+}
+
+export default ArcAisle;
\ 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 dca5654..d4a4007 100644
--- a/app/src/modules/builder/aisle/aisleCreator/aisleCreator.tsx
+++ b/app/src/modules/builder/aisle/aisleCreator/aisleCreator.tsx
@@ -118,24 +118,6 @@ function AisleCreator() {
addAisle(aisle);
setTempPoints([newPoint]);
}
- } else if (aisleType === 'stripped-aisle') {
-
- if (tempPoints.length === 0) {
- setTempPoints([newPoint]);
- setIsCreating(true);
- } else {
- const aisle: Aisle = {
- aisleUuid: THREE.MathUtils.generateUUID(),
- points: [tempPoints[0], newPoint],
- type: {
- aisleType: 'stripped-aisle',
- aisleColor: aisleColor,
- aisleWidth: aisleWidth
- }
- };
- addAisle(aisle);
- setTempPoints([newPoint]);
- }
} else if (aisleType === 'dotted-aisle') {
if (tempPoints.length === 0) {
@@ -194,7 +176,24 @@ function AisleCreator() {
setTempPoints([newPoint]);
}
} else if (aisleType === 'arc-aisle') {
- console.log('Creating arc-aisle');
+
+ if (tempPoints.length === 0) {
+ setTempPoints([newPoint]);
+ setIsCreating(true);
+ } else {
+ const aisle: Aisle = {
+ aisleUuid: THREE.MathUtils.generateUUID(),
+ points: [tempPoints[0], newPoint],
+ type: {
+ aisleType: 'arc-aisle',
+ aisleColor: aisleColor,
+ aisleWidth: aisleWidth,
+ isFlipped: isFlipped
+ }
+ };
+ addAisle(aisle);
+ setTempPoints([newPoint]);
+ }
} else if (aisleType === 'circle-aisle') {
if (tempPoints.length === 0) {
diff --git a/app/src/modules/builder/aisle/aisleCreator/referenceAisle.tsx b/app/src/modules/builder/aisle/aisleCreator/referenceAisle.tsx
index 5bb18fd..5f40ca4 100644
--- a/app/src/modules/builder/aisle/aisleCreator/referenceAisle.tsx
+++ b/app/src/modules/builder/aisle/aisleCreator/referenceAisle.tsx
@@ -58,7 +58,7 @@ function ReferenceAisle({ tempPoints }: Readonly) {
if (!finalPosition.current) return;
- if (aisleType === 'solid-aisle' || aisleType === 'stripped-aisle') {
+ if (aisleType === 'solid-aisle') {
setTempAisle({
aisleUuid: 'temp-aisle',
points: [
@@ -153,9 +153,7 @@ function ReferenceAisle({ tempPoints }: Readonly) {
gapLength: gapLength
}
});
- } else if (aisleType === 'arc-aisle') {
- console.log();
- } else if (aisleType === 'junction-aisle') {
+ } else if (aisleType === 'junction-aisle' || aisleType === 'arc-aisle') {
setTempAisle({
aisleUuid: 'temp-aisle',
points: [
@@ -203,6 +201,8 @@ function ReferenceAisle({ tempPoints }: Readonly) {
return ;
case 'junction-aisle':
return ;
+ case 'arc-aisle':
+ return
default:
return null;
}
@@ -211,7 +211,6 @@ function ReferenceAisle({ tempPoints }: Readonly) {
const textPosition = new THREE.Vector3().addVectors(new THREE.Vector3(...tempAisle.points[0].position), new THREE.Vector3(...tempAisle.points[1].position)).divideScalar(2);
const distance = new THREE.Vector3(...tempAisle.points[0].position).distanceTo(new THREE.Vector3(...tempAisle.points[1].position));
-
const rendertext = () => {
return (
<>
@@ -705,4 +704,83 @@ function JunctionAisle({ aisle }: { readonly aisle: Aisle }) {
))}
);
+}
+
+function ArcAisle({ aisle }: { readonly aisle: Aisle }) {
+ const arc = useMemo(() => {
+ if (aisle.points.length < 2 || aisle.type.aisleType !== 'arc-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.5;
+ const isFlipped = aisle.type.isFlipped || false;
+
+ const direction = new THREE.Vector3().subVectors(end, start);
+ const length = direction.length();
+ direction.normalize();
+
+ const perpendicular = new THREE.Vector3(-direction.z, 0, direction.x).normalize();
+ if (!isFlipped) perpendicular.negate();
+
+ const arcHeight = length * 0.25;
+ const midPoint = new THREE.Vector3().lerpVectors(start, end, 0.5);
+ const controlPoint = new THREE.Vector3().copy(midPoint).addScaledVector(perpendicular, arcHeight);
+
+ const widthOffset = perpendicular.clone().multiplyScalar(width / 2);
+
+ const p1 = new THREE.Vector3().copy(start).add(widthOffset);
+ const p2 = new THREE.Vector3().copy(end).add(widthOffset);
+ const p3 = new THREE.Vector3().copy(end).sub(widthOffset);
+ const p4 = new THREE.Vector3().copy(start).sub(widthOffset);
+
+ const shape = new THREE.Shape();
+ shape.moveTo(p1.x, p1.z);
+
+ shape.quadraticCurveTo(
+ controlPoint.x + widthOffset.x,
+ controlPoint.z + widthOffset.z,
+ p2.x, p2.z
+ );
+
+ shape.lineTo(p3.x, p3.z);
+
+ shape.quadraticCurveTo(
+ controlPoint.x - widthOffset.x,
+ controlPoint.z - widthOffset.z,
+ p4.x, p4.z
+ );
+
+ shape.lineTo(p1.x, p1.z);
+
+ return {
+ shape,
+ position: new THREE.Vector3(0, 0, 0),
+ rotationY: 0
+ };
+ }, [aisle]);
+
+
+ if (!arc) return null;
+
+ return (
+
+
+
+
+
+ );
}
\ No newline at end of file
diff --git a/app/src/modules/scene/controls/selectionControls/boundingBoxHelper.tsx b/app/src/modules/scene/controls/selectionControls/boundingBoxHelper.tsx
index 32fcce7..05b43c6 100644
--- a/app/src/modules/scene/controls/selectionControls/boundingBoxHelper.tsx
+++ b/app/src/modules/scene/controls/selectionControls/boundingBoxHelper.tsx
@@ -33,8 +33,13 @@ const BoundingBox = ({ boundingBoxRef, isPerAsset = true }: BoundingBoxProps) =>
if (selectedAssets.length === 0) return [];
if (isPerAsset) {
- return selectedAssets.map((obj: any) => {
- const box = new THREE.Box3().setFromObject(obj.clone());
+ return selectedAssets.map((obj: THREE.Object3D) => {
+ const position = obj.position;
+ const rotation = obj.getWorldQuaternion(new THREE.Quaternion());
+ const clone = obj.clone();
+ clone.position.set(0, 0, 0);
+ clone.rotation.set(0, 0, 0);
+ const box = new THREE.Box3().setFromObject(clone);
const size = new THREE.Vector3();
const center = new THREE.Vector3();
box.getSize(size);
@@ -46,7 +51,8 @@ const BoundingBox = ({ boundingBoxRef, isPerAsset = true }: BoundingBoxProps) =>
return {
points: getBoxLines(min, max),
- position: center.toArray(),
+ position: [position.x, center.y, position.z],
+ rotation: rotation.toArray(),
size: size.toArray(),
};
});
@@ -66,6 +72,7 @@ const BoundingBox = ({ boundingBoxRef, isPerAsset = true }: BoundingBoxProps) =>
{
points: getBoxLines(min, max),
position: center.toArray(),
+ rotation: [0, 0, 0, 1],
size: size.toArray(),
},
];
@@ -75,7 +82,10 @@ const BoundingBox = ({ boundingBoxRef, isPerAsset = true }: BoundingBoxProps) =>
return (
<>
{boxes.map((box: any, index: number) => (
-
+
color={savedTheme === "dark" ? "#c4abf1" : "#6f42c1"}
lineWidth={2.7}
segments
+ position={[box.position[0], 0, box.position[2]]}
+ quaternion={new THREE.Quaternion(...box.rotation)}
/>
diff --git a/app/src/modules/scene/controls/selectionControls/selectionControls.tsx b/app/src/modules/scene/controls/selectionControls/selectionControls.tsx
index 0c158a9..d0954e4 100644
--- a/app/src/modules/scene/controls/selectionControls/selectionControls.tsx
+++ b/app/src/modules/scene/controls/selectionControls/selectionControls.tsx
@@ -309,7 +309,7 @@ const SelectionControls: React.FC = () => {
<>
-
+
diff --git a/app/src/store/builder/useAisleStore.ts b/app/src/store/builder/useAisleStore.ts
index f379e35..bf05851 100644
--- a/app/src/store/builder/useAisleStore.ts
+++ b/app/src/store/builder/useAisleStore.ts
@@ -18,7 +18,6 @@ interface AisleStore {
aisleUuid: string,
props: { aisleWidth?: number; dashLength?: number; gapLength?: number }
) => void;
- setStrippedAisleWidth: (aisleUuid: string, width: number) => void;
setDottedAisleProperties: (
aisleUuid: string,
props: { dotRadius?: number; gapLength?: number }
@@ -28,7 +27,7 @@ interface AisleStore {
aisleUuid: string,
props: { aisleWidth?: number; aisleLength?: number; gapLength?: number }
) => void;
- setArcAisleWidth: (aisleUuid: string, width: number) => void;
+ setArcAisleWidth: (aisleUuid: string, props: { aisleWidth?: number; isFlipped: boolean; }) => void;
setCircleAisleWidth: (aisleUuid: string, width: number) => void;
setJunctionAisleProperties: (aisleUuid: string, props: { aisleWidth?: number; isFlipped: boolean; }) => void;
@@ -73,7 +72,6 @@ export const useAisleStore = create()(
return true;
});
});
- console.log('removedAisles: ', removedAisles);
return removedAisles;
},
@@ -119,13 +117,6 @@ export const useAisleStore = create()(
}
}),
- setStrippedAisleWidth: (aisleUuid, width) => set((state) => {
- 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.aisleUuid === aisleUuid);
if (aisle && aisle.type.aisleType === 'dotted-aisle') {
@@ -150,10 +141,11 @@ export const useAisleStore = create()(
}
}),
- setArcAisleWidth: (aisleUuid, width) => set((state) => {
+ setArcAisleWidth: (aisleUuid, props) => set((state) => {
const aisle = state.aisles.find(a => a.aisleUuid === aisleUuid);
if (aisle && aisle.type.aisleType === 'arc-aisle') {
- aisle.type.aisleWidth = width;
+ if (props.aisleWidth !== undefined) aisle.type.aisleWidth = props.aisleWidth;
+ if (props.isFlipped !== undefined) aisle.type.isFlipped = props.isFlipped;
}
}),
diff --git a/app/src/types/builderTypes.d.ts b/app/src/types/builderTypes.d.ts
index c43805c..c796069 100644
--- a/app/src/types/builderTypes.d.ts
+++ b/app/src/types/builderTypes.d.ts
@@ -59,12 +59,6 @@ interface DashedAisle {
gapLength: number;
}
-interface StrippedAisle {
- aisleType: 'stripped-aisle';
- aisleColor: AisleColors;
- aisleWidth: number;
-}
-
interface DottedAisle {
aisleType: 'dotted-aisle';
aisleColor: AisleColors;
@@ -90,6 +84,7 @@ interface ArcAisle {
aisleType: 'arc-aisle';
aisleColor: AisleColors;
aisleWidth: number;
+ isFlipped: boolean;
}
interface CircleAisle {
@@ -105,7 +100,7 @@ interface JunctionAisle {
isFlipped: boolean;
}
-type AisleType = SolidAisle | DashedAisle | StrippedAisle | DottedAisle | ArrowAisle | ArrowsAisle | ArcAisle | CircleAisle | JunctionAisle;
+type AisleType = SolidAisle | DashedAisle | DottedAisle | ArrowAisle | ArrowsAisle | ArcAisle | CircleAisle | JunctionAisle;
interface Aisle {
aisleUuid: string;