feat: enhance aisle management with new properties and types

This commit is contained in:
Jerald-Golden-B 2025-05-28 10:44:19 +05:30
parent 13ec906fac
commit cb414f2824
11 changed files with 296 additions and 148 deletions

View File

@ -16,6 +16,7 @@ import Simulations from "./simulation/Simulations";
import useVersionHistoryStore, { import useVersionHistoryStore, {
useSaveVersion, useSaveVersion,
useSelectedFloorItem, useSelectedFloorItem,
useToolMode,
} from "../../../store/builder/store"; } from "../../../store/builder/store";
import { import {
useSelectedEventData, useSelectedEventData,
@ -26,10 +27,12 @@ import AsstePropertiies from "./properties/AssetProperties";
import ZoneProperties from "./properties/ZoneProperties"; import ZoneProperties from "./properties/ZoneProperties";
import EventProperties from "./properties/eventProperties/EventProperties"; import EventProperties from "./properties/eventProperties/EventProperties";
import VersionHistory from "./versionHisory/VersionHistory"; import VersionHistory from "./versionHisory/VersionHistory";
import AisleProperties from "./properties/AisleProperties";
const SideBarRight: React.FC = () => { const SideBarRight: React.FC = () => {
const { activeModule } = useModuleStore(); const { activeModule } = useModuleStore();
const { toggleUIRight } = useToggleStore(); const { toggleUIRight } = useToggleStore();
const { toolMode } = useToolMode();
const { subModule, setSubModule } = useSubModuleStore(); const { subModule, setSubModule } = useSubModuleStore();
const { selectedFloorItem } = useSelectedFloorItem(); const { selectedFloorItem } = useSelectedFloorItem();
const { selectedEventData } = useSelectedEventData(); const { selectedEventData } = useSelectedEventData();
@ -62,9 +65,8 @@ const SideBarRight: React.FC = () => {
return ( return (
<div <div
className={`sidebar-right-wrapper ${ className={`sidebar-right-wrapper ${toggleUIRight && !isVersionSaved ? "open" : "closed"
toggleUIRight && !isVersionSaved ? "open" : "closed" }`}
}`}
> >
<Header /> <Header />
{toggleUIRight && ( {toggleUIRight && (
@ -74,9 +76,8 @@ const SideBarRight: React.FC = () => {
{activeModule !== "simulation" && ( {activeModule !== "simulation" && (
<button <button
id="sidebar-action-list-properties" id="sidebar-action-list-properties"
className={`sidebar-action-list ${ className={`sidebar-action-list ${subModule === "properties" ? "active" : ""
subModule === "properties" ? "active" : "" }`}
}`}
onClick={() => { onClick={() => {
setSubModule("properties"); setSubModule("properties");
setVersionHistory(false); setVersionHistory(false);
@ -90,9 +91,8 @@ const SideBarRight: React.FC = () => {
<> <>
<button <button
id="sidebar-action-list-simulation" id="sidebar-action-list-simulation"
className={`sidebar-action-list ${ className={`sidebar-action-list ${subModule === "simulations" ? "active" : ""
subModule === "simulations" ? "active" : "" }`}
}`}
onClick={() => { onClick={() => {
setSubModule("simulations"); setSubModule("simulations");
setVersionHistory(false); setVersionHistory(false);
@ -103,9 +103,8 @@ const SideBarRight: React.FC = () => {
</button> </button>
<button <button
id="sidebar-action-list-mechanics" id="sidebar-action-list-mechanics"
className={`sidebar-action-list ${ className={`sidebar-action-list ${subModule === "mechanics" ? "active" : ""
subModule === "mechanics" ? "active" : "" }`}
}`}
onClick={() => { onClick={() => {
setSubModule("mechanics"); setSubModule("mechanics");
setVersionHistory(false); setVersionHistory(false);
@ -116,9 +115,8 @@ const SideBarRight: React.FC = () => {
</button> </button>
<button <button
id="sidebar-action-list-analysis" id="sidebar-action-list-analysis"
className={`sidebar-action-list ${ className={`sidebar-action-list ${subModule === "analysis" ? "active" : ""
subModule === "analysis" ? "active" : "" }`}
}`}
onClick={() => { onClick={() => {
setSubModule("analysis"); setSubModule("analysis");
setVersionHistory(false); setVersionHistory(false);
@ -147,7 +145,10 @@ const SideBarRight: React.FC = () => {
!selectedFloorItem && ( !selectedFloorItem && (
<div className="sidebar-right-container"> <div className="sidebar-right-container">
<div className="sidebar-right-content-container"> <div className="sidebar-right-content-container">
<GlobalProperties /> {toolMode === "Aisle" ? (
<AisleProperties />) : (
<GlobalProperties />
)}
</div> </div>
</div> </div>
)} )}

View File

@ -11,9 +11,10 @@ import Dashed from "../../../../assets/image/aisleTypes/Dashed.png";
import Directional from "../../../../assets/image/aisleTypes/Directional.png"; import Directional from "../../../../assets/image/aisleTypes/Directional.png";
import Dotted from "../../../../assets/image/aisleTypes/Dotted.png"; import Dotted from "../../../../assets/image/aisleTypes/Dotted.png";
import Solid from "../../../../assets/image/aisleTypes/Solid.png"; import Solid from "../../../../assets/image/aisleTypes/Solid.png";
import { useBuilderStore } from "../../../../store/builder/useBuilderStore";
interface TextureItem { interface TextureItem {
color: string; color: AisleColors;
id: string; id: string;
brief: string; brief: string;
texture: string; texture: string;
@ -22,10 +23,7 @@ interface TextureItem {
const AisleProperties: React.FC = () => { const AisleProperties: React.FC = () => {
const [collapsePresets, setCollapsePresets] = useState(false); const [collapsePresets, setCollapsePresets] = useState(false);
const [collapseTexture, setCollapseTexture] = useState(true); const [collapseTexture, setCollapseTexture] = useState(true);
const [selectedTexture, setSelectedTexture] = useState<string | null>( const { aisleType, aisleWidth, aisleColor, setAisleType, setAisleColor, setAisleWidth } = useBuilderStore();
"yellow1"
);
const [selectedType, setSelectedType] = useState<string | null>("Solid");
const aisleTextureList: TextureItem[] = [ const aisleTextureList: TextureItem[] = [
{ color: "gray", id: "gray", brief: "basic", texture: "" }, { color: "gray", id: "gray", brief: "basic", texture: "" },
@ -60,58 +58,82 @@ const AisleProperties: React.FC = () => {
}, },
]; ];
const aisleTypes = [ const aisleTypes: {
{ name: string;
name: "Solid", type: AisleTypes;
id: "1", id: string;
thumbnail: Solid, thumbnail: string;
}, }[] = [
{ {
name: "Dotted", name: "Solid",
id: "2", type: "solid-aisle",
thumbnail: Dotted, id: "1",
}, thumbnail: Solid,
{ },
name: "Dashed", {
id: "3", name: "Dotted",
thumbnail: Dashed, type: "dotted-aisle",
}, id: "2",
{ thumbnail: Dotted,
name: "Arrow", },
id: "4", {
thumbnail: Arrow, name: "Dashed",
}, type: "dashed-aisle",
{ id: "3",
name: "Contiuous Arrows", thumbnail: Dashed,
id: "5", },
thumbnail: Arrows, {
}, name: "Arrow",
{ type: "arrow-aisle",
name: "Directional", id: "4",
id: "6", thumbnail: Arrow,
thumbnail: Directional, },
}, {
{ name: "Contiuous Arrows",
name: "Arc", type: "arrows-aisle",
id: "7", id: "5",
thumbnail: Arc, thumbnail: Arrows,
}, },
{ {
name: "Circle", name: "Directional",
id: "8", type: "junction-aisle",
thumbnail: Circle, id: "6",
}, thumbnail: Directional,
]; },
{
name: "Arc",
type: "arc-aisle",
id: "7",
thumbnail: Arc,
},
{
name: "Circle",
type: "circle-aisle",
id: "8",
thumbnail: Circle,
},
];
const handleAisleWidthChange = (value: string) => {
const width = parseFloat(value);
if (isNaN(width)) {
return;
}
setAisleWidth(width);
}
return ( return (
<div className="aisle-properties-container"> <div className="aisle-properties-container">
<div className="header">Properties</div> <div className="header">Properties</div>
<section> <section>
<InputWithDropDown <InputWithDropDown
label="Width" label="Aisle Width"
value="1" value={`${aisleWidth}`}
editableLabel min={0.1}
onChange={() => {}} step={0.1}
max={2}
defaultValue="0.1"
onChange={handleAisleWidthChange}
/> />
</section> </section>
@ -132,12 +154,11 @@ const AisleProperties: React.FC = () => {
{aisleTypes.map((val) => ( {aisleTypes.map((val) => (
<div className="preset-list" key={val.id}> <div className="preset-list" key={val.id}>
<button <button
className={`thumbnail ${ className={`thumbnail ${aisleType === val.type ? "selected" : ""
selectedType === val.name ? "selected" : "" }`}
}`}
title={val.name} title={val.name}
onClick={() => { onClick={() => {
setSelectedType(val.name); setAisleType(val.type);
}} }}
> >
<img src={val.thumbnail} alt="" /> <img src={val.thumbnail} alt="" />
@ -170,11 +191,10 @@ const AisleProperties: React.FC = () => {
<button <button
key={val.id} key={val.id}
title={val.brief || val.id} title={val.brief || val.id}
className={`aisle-list ${ className={`aisle-list ${aisleColor === val.color ? "selected" : ""
selectedTexture === val.id ? "selected" : "" }`}
}`} onClick={() => setAisleColor(val.color)}
onClick={() => setSelectedTexture(val.id)} aria-pressed={aisleColor === val.id}
aria-pressed={selectedTexture === val.id}
> >
<div className="texture-display">{val.texture}</div> <div className="texture-display">{val.texture}</div>
<div className="aisle-color">{val.color}</div> <div className="aisle-color">{val.color}</div>

View File

@ -1,4 +1,5 @@
import DashedAisle from './aisleTypes/dashedAisle'; import DashedAisle from './aisleTypes/dashedAisle';
import DottedAisle from './aisleTypes/dottedAisle';
import SolidAisle from './aisleTypes/solidAisle'; import SolidAisle from './aisleTypes/solidAisle';
function AisleInstance({ aisle }: { readonly aisle: Aisle }) { function AisleInstance({ aisle }: { readonly aisle: Aisle }) {
@ -12,6 +13,10 @@ function AisleInstance({ aisle }: { readonly aisle: Aisle }) {
{aisle.type.aisleType === 'dashed-aisle' && ( {aisle.type.aisleType === 'dashed-aisle' && (
<DashedAisle aisle={aisle} /> <DashedAisle aisle={aisle} />
)} )}
{aisle.type.aisleType === 'dotted-aisle' && (
<DottedAisle aisle={aisle} />
)}
</> </>
); );
} }

View File

@ -9,7 +9,7 @@ function DashedAisle({ aisle }: { readonly aisle: Aisle }) {
const start = new THREE.Vector3(...aisle.points[0].position); const start = new THREE.Vector3(...aisle.points[0].position);
const end = new THREE.Vector3(...aisle.points[1].position); const end = new THREE.Vector3(...aisle.points[1].position);
const width = aisle.type.width || 0.1; const width = aisle.type.aisleWidth || 0.1;
const dashLength = 0.5; const dashLength = 0.5;
const gapLength = 0.3; const gapLength = 0.3;
@ -59,7 +59,7 @@ function DashedAisle({ aisle }: { readonly aisle: Aisle }) {
castShadow castShadow
> >
<meshStandardMaterial <meshStandardMaterial
color={aisle.type.color || '#ffffff'} color={aisle.type.aisleColor || '#ffffff'}
side={THREE.DoubleSide} side={THREE.DoubleSide}
/> />
</Extrude> </Extrude>

View File

@ -0,0 +1,58 @@
import * as THREE from 'three';
import { useMemo } from 'react';
import { Extrude } from '@react-three/drei';
import * as Constants from '../../../../../../types/world/worldConstants';
function DottedAisle({ aisle }: { readonly aisle: Aisle }) {
const shapes = 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 dotSpacing = 0.5;
const dotRadius = width * 0.4;
const totalLength = new THREE.Vector3().subVectors(end, start).length();
const dotCount = Math.floor(totalLength / dotSpacing);
const shapes = [];
const directionNormalized = new THREE.Vector3().subVectors(end, start).normalize();
for (let i = 0; i < dotCount; i++) {
const dotCenter = new THREE.Vector3().copy(start).addScaledVector(directionNormalized, i * dotSpacing + dotSpacing / 2);
const shape = new THREE.Shape();
shape.absarc(dotCenter.x, dotCenter.z, dotRadius, 0, Math.PI * 2, false);
shapes.push(shape);
}
return shapes;
}, [aisle]);
if (shapes.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]}
>
{shapes.map((shape, index) => (
<Extrude
key={index}
args={[shape, { depth: 0.01, bevelEnabled: false }]}
receiveShadow
castShadow
>
<meshStandardMaterial
color={aisle.type.aisleColor || '#ffffff'}
side={THREE.DoubleSide}
/>
</Extrude>
))}
</group>
);
}
export default DottedAisle;

View File

@ -9,7 +9,7 @@ function SolidAisle({ aisle }: { readonly aisle: Aisle }) {
const start = new THREE.Vector3(...aisle.points[0].position); const start = new THREE.Vector3(...aisle.points[0].position);
const end = new THREE.Vector3(...aisle.points[1].position); const end = new THREE.Vector3(...aisle.points[1].position);
const width = aisle.type.width || 0.1; const width = aisle.type.aisleWidth || 0.1;
const direction = new THREE.Vector3().subVectors(end, start).normalize(); const direction = new THREE.Vector3().subVectors(end, start).normalize();
const perp = new THREE.Vector3(-direction.z, 0, direction.x).normalize(); const perp = new THREE.Vector3(-direction.z, 0, direction.x).normalize();
@ -42,7 +42,7 @@ function SolidAisle({ aisle }: { readonly aisle: Aisle }) {
castShadow castShadow
> >
<meshStandardMaterial <meshStandardMaterial
color={aisle.type.color || '#ffffff'} color={aisle.type.aisleColor || '#ffffff'}
side={THREE.DoubleSide} side={THREE.DoubleSide}
/> />
</Extrude> </Extrude>

View File

@ -3,8 +3,8 @@ import { useEffect, useMemo, useState } from 'react'
import { useThree } from '@react-three/fiber'; import { useThree } from '@react-three/fiber';
import { useActiveLayer, useSocketStore, useToggleView, useToolMode } from '../../../../store/builder/store'; import { useActiveLayer, useSocketStore, useToggleView, useToolMode } from '../../../../store/builder/store';
import { useAisleStore } from '../../../../store/builder/useAisleStore'; import { useAisleStore } from '../../../../store/builder/useAisleStore';
import * as Constants from '../../../../types/world/worldConstants';
import ReferenceAisle from './referenceAisle'; import ReferenceAisle from './referenceAisle';
import { useBuilderStore } from '../../../../store/builder/useBuilderStore';
function AisleCreator() { function AisleCreator() {
const { scene, camera, raycaster, gl, pointer } = useThree(); const { scene, camera, raycaster, gl, pointer } = useThree();
@ -17,14 +17,14 @@ function AisleCreator() {
const [tempPoints, setTempPoints] = useState<Point[]>([]); const [tempPoints, setTempPoints] = useState<Point[]>([]);
const [isCreating, setIsCreating] = useState(false); const [isCreating, setIsCreating] = useState(false);
const [aisleType, setAisleType] = useState<'solid-aisle' | 'dashed-aisle' | 'stripped-aisle' | 'dotted-aisle' | 'arrow-aisle' | 'arrows-aisle' | 'arc-aisle' | 'circle-aisle' | 'junction-aisle'>('dashed-aisle'); const { aisleType, aisleWidth, aisleColor } = useBuilderStore();
useEffect(() => { // useEffect(() => {
if (tempPoints.length > 0) { // if (tempPoints.length > 0) {
setTempPoints([]); // setTempPoints([]);
setIsCreating(false); // setIsCreating(false);
} // }
}, [aisleType]); // }, [aisleType]);
const allPoints = useMemo(() => { const allPoints = useMemo(() => {
const points: Point[] = []; const points: Point[] = [];
@ -102,10 +102,9 @@ function AisleCreator() {
points: [tempPoints[0], newPoint], points: [tempPoints[0], newPoint],
type: { type: {
typeName: 'Aisle', typeName: 'Aisle',
material: 'default',
aisleType: aisleType, aisleType: aisleType,
color: Constants.aisleConfig.defaultColor, aisleColor: aisleColor,
width: Constants.aisleConfig.width aisleWidth: aisleWidth
} }
}; };
@ -114,33 +113,7 @@ function AisleCreator() {
setTempPoints([newPoint]); setTempPoints([newPoint]);
} }
} else if (['arc-aisle', 'circle-aisle', 'arrow-aisle', 'junction-aisle'].includes(aisleType)) { } else if (['arc-aisle', 'circle-aisle', 'arrow-aisle', 'junction-aisle'].includes(aisleType)) {
const newPoint: Point = { console.log();
uuid: THREE.MathUtils.generateUUID(),
position: [point.x, point.y, point.z],
layer: activeLayer
};
if (tempPoints.length === 0) {
setTempPoints([newPoint]);
setIsCreating(true);
} else {
const aisle: Aisle = {
uuid: THREE.MathUtils.generateUUID(),
points: [tempPoints[0], newPoint],
type: {
typeName: 'Aisle',
material: 'default',
aisleType: aisleType,
color: Constants.aisleConfig.defaultColor,
width: Constants.aisleConfig.width
}
};
addAisle(aisle);
setTempPoints([]);
setIsCreating(false);
}
} }
}; };
@ -170,7 +143,7 @@ function AisleCreator() {
canvasElement.removeEventListener("click", onMouseClick); canvasElement.removeEventListener("click", onMouseClick);
canvasElement.removeEventListener("contextmenu", onContext); canvasElement.removeEventListener("contextmenu", onContext);
}; };
}, [gl, camera, scene, raycaster, pointer, plane, toggleView, toolMode, activeLayer, socket, tempPoints, isCreating, addAisle, aisleType]); }, [gl, camera, scene, raycaster, pointer, plane, toggleView, toolMode, activeLayer, socket, tempPoints, isCreating, addAisle, aisleType, aisleColor, aisleWidth]);
return ( return (
<> <>
@ -188,7 +161,7 @@ function AisleCreator() {
))} ))}
</group> </group>
<ReferenceAisle tempPoints={tempPoints} aisleType={aisleType} /> <ReferenceAisle tempPoints={tempPoints} aisleType={aisleType} aisleWidth={aisleWidth} aisleColor={aisleColor} />
</> </>
); );
} }

View File

@ -7,10 +7,12 @@ import { Extrude } from '@react-three/drei';
interface ReferenceAisleProps { interface ReferenceAisleProps {
tempPoints: Point[]; tempPoints: Point[];
aisleType: 'solid-aisle' | 'dashed-aisle' | 'stripped-aisle' | 'dotted-aisle' | 'arrow-aisle' | 'arrows-aisle' | 'arc-aisle' | 'circle-aisle' | 'junction-aisle'; aisleType: AisleTypes;
aisleWidth: number;
aisleColor: AisleColors;
} }
function ReferenceAisle({ tempPoints, aisleType }: Readonly<ReferenceAisleProps>) { function ReferenceAisle({ tempPoints, aisleType, aisleWidth, aisleColor }: Readonly<ReferenceAisleProps>) {
const { pointer, raycaster, camera } = useThree(); const { pointer, raycaster, camera } = useThree();
const { toolMode } = useToolMode(); const { toolMode } = useToolMode();
const { toggleView } = useToggleView(); const { toggleView } = useToggleView();
@ -41,10 +43,9 @@ function ReferenceAisle({ tempPoints, aisleType }: Readonly<ReferenceAisleProps>
], ],
type: { type: {
typeName: 'Aisle', typeName: 'Aisle',
material: 'default',
aisleType: aisleType, aisleType: aisleType,
color: Constants.aisleConfig.defaultColor, aisleColor: aisleColor,
width: Constants.aisleConfig.width aisleWidth: aisleWidth
} }
}); });
} }
@ -55,7 +56,7 @@ function ReferenceAisle({ tempPoints, aisleType }: Readonly<ReferenceAisleProps>
useEffect(() => { useEffect(() => {
setTempAisle(null); setTempAisle(null);
}, [toolMode, toggleView, tempPoints.length, aisleType]); }, [toolMode, toggleView, tempPoints.length, aisleType, aisleWidth, aisleColor]);
if (!tempAisle) return null; if (!tempAisle) return null;
@ -65,6 +66,8 @@ function ReferenceAisle({ tempPoints, aisleType }: Readonly<ReferenceAisleProps>
return <SolidAisle aisle={tempAisle} />; return <SolidAisle aisle={tempAisle} />;
case 'dashed-aisle': case 'dashed-aisle':
return <DashedAisle aisle={tempAisle} />; return <DashedAisle aisle={tempAisle} />;
case 'dotted-aisle':
return <DottedAisle aisle={tempAisle} />;
default: default:
return null; return null;
} }
@ -79,14 +82,13 @@ function ReferenceAisle({ tempPoints, aisleType }: Readonly<ReferenceAisleProps>
export default ReferenceAisle; export default ReferenceAisle;
function SolidAisle({ aisle }: { readonly aisle: Aisle }) { function SolidAisle({ aisle }: { readonly aisle: Aisle }) {
const shape = useMemo(() => { const shape = useMemo(() => {
if (aisle.points.length < 2) return null; if (aisle.points.length < 2) return null;
const start = new THREE.Vector3(...aisle.points[0].position); const start = new THREE.Vector3(...aisle.points[0].position);
const end = new THREE.Vector3(...aisle.points[1].position); const end = new THREE.Vector3(...aisle.points[1].position);
const width = aisle.type.width || 0.1; const width = aisle.type.aisleWidth || 0.1;
const direction = new THREE.Vector3().subVectors(end, start).normalize(); const direction = new THREE.Vector3().subVectors(end, start).normalize();
const perp = new THREE.Vector3(-direction.z, 0, direction.x).normalize(); const perp = new THREE.Vector3(-direction.z, 0, direction.x).normalize();
@ -119,7 +121,7 @@ function SolidAisle({ aisle }: { readonly aisle: Aisle }) {
castShadow castShadow
> >
<meshStandardMaterial <meshStandardMaterial
color={aisle.type.color || '#ffffff'} color={aisle.type.aisleColor || '#ffffff'}
side={THREE.DoubleSide} side={THREE.DoubleSide}
/> />
</Extrude> </Extrude>
@ -133,7 +135,7 @@ function DashedAisle({ aisle }: { readonly aisle: Aisle }) {
const start = new THREE.Vector3(...aisle.points[0].position); const start = new THREE.Vector3(...aisle.points[0].position);
const end = new THREE.Vector3(...aisle.points[1].position); const end = new THREE.Vector3(...aisle.points[1].position);
const width = aisle.type.width || 0.1; const width = aisle.type.aisleWidth || 0.1;
const dashLength = 0.5; const dashLength = 0.5;
const gapLength = 0.3; const gapLength = 0.3;
@ -183,7 +185,59 @@ function DashedAisle({ aisle }: { readonly aisle: Aisle }) {
castShadow castShadow
> >
<meshStandardMaterial <meshStandardMaterial
color={aisle.type.color || '#ffffff'} color={aisle.type.aisleColor || '#ffffff'}
side={THREE.DoubleSide}
/>
</Extrude>
))}
</group>
);
}
function DottedAisle({ aisle }: { readonly aisle: Aisle }) {
const shapes = 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 dotSpacing = 0.5;
const dotRadius = width * 0.4;
const totalLength = new THREE.Vector3().subVectors(end, start).length();
const dotCount = Math.floor(totalLength / dotSpacing);
const shapes = [];
const directionNormalized = new THREE.Vector3().subVectors(end, start).normalize();
for (let i = 0; i < dotCount; i++) {
const dotCenter = new THREE.Vector3().copy(start).addScaledVector(directionNormalized, i * dotSpacing + dotSpacing / 2);
const shape = new THREE.Shape();
shape.absarc(dotCenter.x, dotCenter.z, dotRadius, 0, Math.PI * 2, false);
shapes.push(shape);
}
return shapes;
}, [aisle]);
if (shapes.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]}
>
{shapes.map((shape, index) => (
<Extrude
key={index}
args={[shape, { depth: 0.01, bevelEnabled: false }]}
receiveShadow
castShadow
>
<meshStandardMaterial
color={aisle.type.aisleColor || '#ffffff'}
side={THREE.DoubleSide} side={THREE.DoubleSide}
/> />
</Extrude> </Extrude>

View File

@ -9,8 +9,7 @@ interface AisleStore {
removeAisle: (uuid: string) => void; removeAisle: (uuid: string) => void;
setPosition: (pointUuid: string, position: [number, number, number]) => void; setPosition: (pointUuid: string, position: [number, number, number]) => void;
setLayer: (pointUuid: string, layer: number) => void; setLayer: (pointUuid: string, layer: number) => void;
setMaterial: (aisleUuid: string, material: string) => void; setColor: (aisleUuid: string, color: AisleColors) => void;
setColor: (aisleUuid: string, color: string) => void;
setWidth: (aisleUuid: string, width: number) => void; setWidth: (aisleUuid: string, width: number) => void;
getAisleById: (uuid: string) => Aisle | undefined; getAisleById: (uuid: string) => Aisle | undefined;
} }
@ -58,24 +57,17 @@ export const useAisleStore = create<AisleStore>()(
} }
}), }),
setMaterial: (aisleUuid: string, material: string) => set((state) => { setColor: (aisleUuid: string, color: AisleColors) => set((state) => {
const aisle = state.aisles.find(a => a.uuid === aisleUuid); const aisle = state.aisles.find(a => a.uuid === aisleUuid);
if (aisle) { if (aisle) {
aisle.type.material = material; aisle.type.aisleColor = color;
}
}),
setColor: (aisleUuid: string, color: string) => set((state) => {
const aisle = state.aisles.find(a => a.uuid === aisleUuid);
if (aisle) {
aisle.type.color = color;
} }
}), }),
setWidth: (aisleUuid: string, width: number) => set((state) => { setWidth: (aisleUuid: string, width: number) => set((state) => {
const aisle = state.aisles.find(a => a.uuid === aisleUuid); const aisle = state.aisles.find(a => a.uuid === aisleUuid);
if (aisle) { if (aisle) {
aisle.type.width = width; aisle.type.aisleWidth = width;
} }
}), }),

View File

@ -0,0 +1,42 @@
import { create } from 'zustand';
import { immer } from 'zustand/middleware/immer';
interface BuilderState {
aisleType: AisleTypes;
aisleWidth: number;
aisleColor: AisleColors;
setAisleType: (type: AisleTypes) => void;
setAisleWidth: (width: number) => void;
setAisleColor: (color: AisleColors) => void;
setAisleProperties: (type: AisleTypes, width: number, color: AisleColors) => void;
}
export const useBuilderStore = create<BuilderState>()(
immer((set) => ({
aisleType: 'solid-aisle',
aisleWidth: 0.1,
aisleColor: 'gray',
setAisleType: (type) => {
set((state) => {
state.aisleType = type;
});
},
setAisleWidth: (width) => {
set((state) => {
state.aisleWidth = width;
});
},
setAisleColor: (color) => {
set((state) => {
state.aisleColor = color;
});
},
setAisleProperties: (type, width, color) => {
set((state) => {
state.aisleType = type;
state.aisleWidth = width;
state.aisleColor = color;
});
}
}))
);

View File

@ -37,12 +37,15 @@ interface Point {
layer: number; layer: number;
} }
type AisleTypes = | 'solid-aisle' | 'dashed-aisle' | 'stripped-aisle' | 'dotted-aisle' | 'arrow-aisle' | 'arrows-aisle' | 'arc-aisle' | 'circle-aisle' | 'junction-aisle';
type AisleColors = | 'gray' | 'yellow' | 'green' | 'orange' | 'blue' | 'purple' | 'red' | 'bright green' | 'yellow-black' | 'white-black'
interface AisleType { interface AisleType {
typeName: 'Aisle'; typeName: 'Aisle';
material: string; aisleType: AisleTypes;
aisleType: 'solid-aisle' | 'dashed-aisle' | 'stripped-aisle' | 'dotted-aisle' | 'arrow-aisle'| 'arrows-aisle' | 'arc-aisle' | 'circle-aisle' | 'junction-aisle'; aisleColor: AisleColors;
color: string; aisleWidth: number;
width: number;
} }
interface Aisle { interface Aisle {