refactor: Add ArrowsAisle component and update aisle properties for improved functionality
This commit is contained in:
parent
879c478753
commit
d30ae34426
|
@ -26,13 +26,13 @@ const AisleProperties: React.FC = () => {
|
||||||
const { aisleType, aisleWidth, aisleColor, setAisleType, setAisleColor, setAisleWidth } = useBuilderStore();
|
const { aisleType, aisleWidth, aisleColor, setAisleType, setAisleColor, setAisleWidth } = useBuilderStore();
|
||||||
|
|
||||||
const aisleTextureList: TextureItem[] = [
|
const aisleTextureList: TextureItem[] = [
|
||||||
{ color: "gray", id: "gray", brief: "basic", texture: "" },
|
|
||||||
{
|
{
|
||||||
color: "yellow",
|
color: "yellow",
|
||||||
id: "yellow1",
|
id: "yellow1",
|
||||||
brief: "pedestrian walkways",
|
brief: "pedestrian walkways",
|
||||||
texture: "",
|
texture: "",
|
||||||
},
|
},
|
||||||
|
{ color: "gray", id: "gray", brief: "basic", texture: "" },
|
||||||
{ color: "green", id: "green1", brief: "pedestrian walkways", texture: "" },
|
{ color: "green", id: "green1", brief: "pedestrian walkways", texture: "" },
|
||||||
{ color: "orange", id: "orange", brief: "material flow", texture: "" },
|
{ color: "orange", id: "orange", brief: "material flow", texture: "" },
|
||||||
{ color: "blue", id: "blue", brief: "vehicle paths", texture: "" },
|
{ color: "blue", id: "blue", brief: "vehicle paths", texture: "" },
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import ArrowsAisle from './aisleTypes/arrowsAisle';
|
||||||
import DashedAisle from './aisleTypes/dashedAisle';
|
import DashedAisle from './aisleTypes/dashedAisle';
|
||||||
import DottedAisle from './aisleTypes/dottedAisle';
|
import DottedAisle from './aisleTypes/dottedAisle';
|
||||||
import SolidAisle from './aisleTypes/solidAisle';
|
import SolidAisle from './aisleTypes/solidAisle';
|
||||||
|
@ -17,6 +18,10 @@ function AisleInstance({ aisle }: { readonly aisle: Aisle }) {
|
||||||
{aisle.type.aisleType === 'dotted-aisle' && (
|
{aisle.type.aisleType === 'dotted-aisle' && (
|
||||||
<DottedAisle aisle={aisle} />
|
<DottedAisle aisle={aisle} />
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{aisle.type.aisleType === 'arrows-aisle' && (
|
||||||
|
<ArrowsAisle aisle={aisle} />
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
import * as THREE from 'three';
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
import { Extrude } from '@react-three/drei';
|
||||||
|
import * as Constants from '../../../../../../types/world/worldConstants';
|
||||||
|
|
||||||
|
function ArrowsAisle({ aisle }: { readonly aisle: Aisle }) {
|
||||||
|
const arrows = useMemo(() => {
|
||||||
|
if (aisle.points.length < 2) return [];
|
||||||
|
|
||||||
|
const start = new THREE.Vector3(...aisle.points[0].position);
|
||||||
|
const end = new THREE.Vector3(...aisle.points[1].position);
|
||||||
|
const width = aisle.type.aisleWidth || 0.1;
|
||||||
|
const arrowLength = 0.6;
|
||||||
|
const spacing = 0.6;
|
||||||
|
|
||||||
|
const direction = new THREE.Vector3().subVectors(end, start);
|
||||||
|
const length = direction.length();
|
||||||
|
direction.normalize();
|
||||||
|
|
||||||
|
const count = Math.floor((length + spacing) / (arrowLength + spacing));
|
||||||
|
|
||||||
|
const arrowShapes: { shape: THREE.Shape; position: THREE.Vector3; rotationY: number }[] = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < count; i++) {
|
||||||
|
const initialOffset = 0.6;
|
||||||
|
const center = new THREE.Vector3().copy(start).addScaledVector(direction, initialOffset + i * (arrowLength + spacing));
|
||||||
|
|
||||||
|
const shape = new THREE.Shape();
|
||||||
|
const w = width * 0.8;
|
||||||
|
const h = arrowLength;
|
||||||
|
|
||||||
|
shape.moveTo(0, 0);
|
||||||
|
shape.lineTo(w, h * 0.6);
|
||||||
|
shape.lineTo(w * 0.4, h * 0.6);
|
||||||
|
shape.lineTo(w * 0.4, h);
|
||||||
|
shape.lineTo(-w * 0.4, h);
|
||||||
|
shape.lineTo(-w * 0.4, h * 0.6);
|
||||||
|
shape.lineTo(-w, h * 0.6);
|
||||||
|
shape.lineTo(0, 0);
|
||||||
|
|
||||||
|
const angle = Math.atan2(direction.x, direction.z) + Math.PI;
|
||||||
|
|
||||||
|
arrowShapes.push({ shape, position: center, rotationY: angle });
|
||||||
|
}
|
||||||
|
|
||||||
|
return arrowShapes;
|
||||||
|
}, [aisle]);
|
||||||
|
|
||||||
|
if (arrows.length === 0) 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(({ shape, position, rotationY }, index) => (
|
||||||
|
<group key={index} position={[position.x, position.z, 0]} rotation={[0, 0, -rotationY]}>
|
||||||
|
<Extrude
|
||||||
|
args={[shape, { depth: 0.01, bevelEnabled: false }]}
|
||||||
|
receiveShadow
|
||||||
|
castShadow
|
||||||
|
>
|
||||||
|
<meshStandardMaterial
|
||||||
|
color={aisle.type.aisleColor || '#ffffff'}
|
||||||
|
side={THREE.DoubleSide}
|
||||||
|
/>
|
||||||
|
</Extrude>
|
||||||
|
</group>
|
||||||
|
))}
|
||||||
|
</group>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ArrowsAisle;
|
|
@ -17,7 +17,7 @@ function DashedAisle({ aisle }: { readonly aisle: Aisle }) {
|
||||||
const perp = new THREE.Vector3(-direction.z, 0, direction.x).normalize();
|
const perp = new THREE.Vector3(-direction.z, 0, direction.x).normalize();
|
||||||
|
|
||||||
const totalLength = new THREE.Vector3().subVectors(end, start).length();
|
const totalLength = new THREE.Vector3().subVectors(end, start).length();
|
||||||
const segmentCount = Math.floor(totalLength / (dashLength + gapLength));
|
const segmentCount = Math.floor((totalLength + gapLength) / (dashLength + gapLength));
|
||||||
|
|
||||||
const shapes = [];
|
const shapes = [];
|
||||||
const directionNormalized = new THREE.Vector3().subVectors(end, start).normalize();
|
const directionNormalized = new THREE.Vector3().subVectors(end, start).normalize();
|
||||||
|
|
|
@ -11,10 +11,10 @@ function DottedAisle({ aisle }: { readonly aisle: Aisle }) {
|
||||||
const end = new THREE.Vector3(...aisle.points[1].position);
|
const end = new THREE.Vector3(...aisle.points[1].position);
|
||||||
const width = aisle.type.aisleWidth || 0.1;
|
const width = aisle.type.aisleWidth || 0.1;
|
||||||
const dotSpacing = 0.5;
|
const dotSpacing = 0.5;
|
||||||
const dotRadius = width * 0.4;
|
const dotRadius = width * 0.6;
|
||||||
|
|
||||||
const totalLength = new THREE.Vector3().subVectors(end, start).length();
|
const totalLength = new THREE.Vector3().subVectors(end, start).length();
|
||||||
const dotCount = Math.floor(totalLength / dotSpacing);
|
const dotCount = Math.floor((totalLength + (dotSpacing / 2)) / dotSpacing);
|
||||||
|
|
||||||
const shapes = [];
|
const shapes = [];
|
||||||
const directionNormalized = new THREE.Vector3().subVectors(end, start).normalize();
|
const directionNormalized = new THREE.Vector3().subVectors(end, start).normalize();
|
||||||
|
|
|
@ -68,6 +68,8 @@ function ReferenceAisle({ tempPoints, aisleType, aisleWidth, aisleColor }: Reado
|
||||||
return <DashedAisle aisle={tempAisle} />;
|
return <DashedAisle aisle={tempAisle} />;
|
||||||
case 'dotted-aisle':
|
case 'dotted-aisle':
|
||||||
return <DottedAisle aisle={tempAisle} />;
|
return <DottedAisle aisle={tempAisle} />;
|
||||||
|
case 'arrows-aisle':
|
||||||
|
return <ArrowsAisle aisle={tempAisle} />
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -143,7 +145,7 @@ function DashedAisle({ aisle }: { readonly aisle: Aisle }) {
|
||||||
const perp = new THREE.Vector3(-direction.z, 0, direction.x).normalize();
|
const perp = new THREE.Vector3(-direction.z, 0, direction.x).normalize();
|
||||||
|
|
||||||
const totalLength = new THREE.Vector3().subVectors(end, start).length();
|
const totalLength = new THREE.Vector3().subVectors(end, start).length();
|
||||||
const segmentCount = Math.floor(totalLength / (dashLength + gapLength));
|
const segmentCount = Math.floor((totalLength + gapLength) / (dashLength + gapLength));
|
||||||
|
|
||||||
const shapes = [];
|
const shapes = [];
|
||||||
const directionNormalized = new THREE.Vector3().subVectors(end, start).normalize();
|
const directionNormalized = new THREE.Vector3().subVectors(end, start).normalize();
|
||||||
|
@ -202,10 +204,10 @@ function DottedAisle({ aisle }: { readonly aisle: Aisle }) {
|
||||||
const end = new THREE.Vector3(...aisle.points[1].position);
|
const end = new THREE.Vector3(...aisle.points[1].position);
|
||||||
const width = aisle.type.aisleWidth || 0.1;
|
const width = aisle.type.aisleWidth || 0.1;
|
||||||
const dotSpacing = 0.5;
|
const dotSpacing = 0.5;
|
||||||
const dotRadius = width * 0.4;
|
const dotRadius = width * 0.6;
|
||||||
|
|
||||||
const totalLength = new THREE.Vector3().subVectors(end, start).length();
|
const totalLength = new THREE.Vector3().subVectors(end, start).length();
|
||||||
const dotCount = Math.floor(totalLength / dotSpacing);
|
const dotCount = Math.floor((totalLength + (dotSpacing / 2)) / dotSpacing);
|
||||||
|
|
||||||
const shapes = [];
|
const shapes = [];
|
||||||
const directionNormalized = new THREE.Vector3().subVectors(end, start).normalize();
|
const directionNormalized = new THREE.Vector3().subVectors(end, start).normalize();
|
||||||
|
@ -244,4 +246,72 @@ function DottedAisle({ aisle }: { readonly aisle: Aisle }) {
|
||||||
))}
|
))}
|
||||||
</group>
|
</group>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function ArrowsAisle({ aisle }: { readonly aisle: Aisle }) {
|
||||||
|
const arrows = useMemo(() => {
|
||||||
|
if (aisle.points.length < 2) return [];
|
||||||
|
|
||||||
|
const start = new THREE.Vector3(...aisle.points[0].position);
|
||||||
|
const end = new THREE.Vector3(...aisle.points[1].position);
|
||||||
|
const width = aisle.type.aisleWidth || 0.1;
|
||||||
|
const arrowLength = 0.6;
|
||||||
|
const spacing = 0.6;
|
||||||
|
|
||||||
|
const direction = new THREE.Vector3().subVectors(end, start);
|
||||||
|
const length = direction.length();
|
||||||
|
direction.normalize();
|
||||||
|
|
||||||
|
const count = Math.floor((length + spacing) / (arrowLength + spacing));
|
||||||
|
|
||||||
|
const arrowShapes: { shape: THREE.Shape; position: THREE.Vector3; rotationY: number }[] = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < count; i++) {
|
||||||
|
const initialOffset = 0.6;
|
||||||
|
const center = new THREE.Vector3().copy(start).addScaledVector(direction, initialOffset + i * (arrowLength + spacing));
|
||||||
|
|
||||||
|
const shape = new THREE.Shape();
|
||||||
|
const w = width * 0.8;
|
||||||
|
const h = arrowLength;
|
||||||
|
|
||||||
|
shape.moveTo(0, 0);
|
||||||
|
shape.lineTo(w, h * 0.6);
|
||||||
|
shape.lineTo(w * 0.4, h * 0.6);
|
||||||
|
shape.lineTo(w * 0.4, h);
|
||||||
|
shape.lineTo(-w * 0.4, h);
|
||||||
|
shape.lineTo(-w * 0.4, h * 0.6);
|
||||||
|
shape.lineTo(-w, h * 0.6);
|
||||||
|
shape.lineTo(0, 0);
|
||||||
|
|
||||||
|
const angle = Math.atan2(direction.x, direction.z) + Math.PI;
|
||||||
|
|
||||||
|
arrowShapes.push({ shape, position: center, rotationY: angle });
|
||||||
|
}
|
||||||
|
|
||||||
|
return arrowShapes;
|
||||||
|
}, [aisle]);
|
||||||
|
|
||||||
|
if (arrows.length === 0) 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(({ shape, position, rotationY }, index) => (
|
||||||
|
<group key={index} position={[position.x, position.z, 0]} rotation={[0, 0, -rotationY]}>
|
||||||
|
<Extrude
|
||||||
|
args={[shape, { depth: 0.01, bevelEnabled: false }]}
|
||||||
|
receiveShadow
|
||||||
|
castShadow
|
||||||
|
>
|
||||||
|
<meshStandardMaterial
|
||||||
|
color={aisle.type.aisleColor || '#ffffff'}
|
||||||
|
side={THREE.DoubleSide}
|
||||||
|
/>
|
||||||
|
</Extrude>
|
||||||
|
</group>
|
||||||
|
))}
|
||||||
|
</group>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -553,7 +553,7 @@ const ZoneGroup: React.FC = () => {
|
||||||
const midpoint = new THREE.Vector3(
|
const midpoint = new THREE.Vector3(
|
||||||
(point1.x + point2.x) / 2,
|
(point1.x + point2.x) / 2,
|
||||||
CONSTANTS.zoneConfig.height / 2 +
|
CONSTANTS.zoneConfig.height / 2 +
|
||||||
(zone.layer - 1) * CONSTANTS.zoneConfig.height,
|
(zone.layer - 1) * CONSTANTS.zoneConfig.height,
|
||||||
(point1.z + point2.z) / 2
|
(point1.z + point2.z) / 2
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -564,7 +564,6 @@ const ZoneGroup: React.FC = () => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<mesh
|
<mesh
|
||||||
name="zonePlane"
|
|
||||||
key={index}
|
key={index}
|
||||||
position={midpoint}
|
position={midpoint}
|
||||||
rotation={[0, -angle, 0]}
|
rotation={[0, -angle, 0]}
|
||||||
|
|
|
@ -15,7 +15,7 @@ export const useBuilderStore = create<BuilderState>()(
|
||||||
immer((set) => ({
|
immer((set) => ({
|
||||||
aisleType: 'solid-aisle',
|
aisleType: 'solid-aisle',
|
||||||
aisleWidth: 0.1,
|
aisleWidth: 0.1,
|
||||||
aisleColor: 'gray',
|
aisleColor: 'yellow',
|
||||||
setAisleType: (type) => {
|
setAisleType: (type) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
state.aisleType = type;
|
state.aisleType = type;
|
||||||
|
|
Loading…
Reference in New Issue