feat: enhance aisle management with new properties and types
This commit is contained in:
parent
13ec906fac
commit
cb414f2824
|
@ -16,6 +16,7 @@ import Simulations from "./simulation/Simulations";
|
|||
import useVersionHistoryStore, {
|
||||
useSaveVersion,
|
||||
useSelectedFloorItem,
|
||||
useToolMode,
|
||||
} from "../../../store/builder/store";
|
||||
import {
|
||||
useSelectedEventData,
|
||||
|
@ -26,10 +27,12 @@ import AsstePropertiies from "./properties/AssetProperties";
|
|||
import ZoneProperties from "./properties/ZoneProperties";
|
||||
import EventProperties from "./properties/eventProperties/EventProperties";
|
||||
import VersionHistory from "./versionHisory/VersionHistory";
|
||||
import AisleProperties from "./properties/AisleProperties";
|
||||
|
||||
const SideBarRight: React.FC = () => {
|
||||
const { activeModule } = useModuleStore();
|
||||
const { toggleUIRight } = useToggleStore();
|
||||
const { toolMode } = useToolMode();
|
||||
const { subModule, setSubModule } = useSubModuleStore();
|
||||
const { selectedFloorItem } = useSelectedFloorItem();
|
||||
const { selectedEventData } = useSelectedEventData();
|
||||
|
@ -62,9 +65,8 @@ const SideBarRight: React.FC = () => {
|
|||
|
||||
return (
|
||||
<div
|
||||
className={`sidebar-right-wrapper ${
|
||||
toggleUIRight && !isVersionSaved ? "open" : "closed"
|
||||
}`}
|
||||
className={`sidebar-right-wrapper ${toggleUIRight && !isVersionSaved ? "open" : "closed"
|
||||
}`}
|
||||
>
|
||||
<Header />
|
||||
{toggleUIRight && (
|
||||
|
@ -74,9 +76,8 @@ const SideBarRight: React.FC = () => {
|
|||
{activeModule !== "simulation" && (
|
||||
<button
|
||||
id="sidebar-action-list-properties"
|
||||
className={`sidebar-action-list ${
|
||||
subModule === "properties" ? "active" : ""
|
||||
}`}
|
||||
className={`sidebar-action-list ${subModule === "properties" ? "active" : ""
|
||||
}`}
|
||||
onClick={() => {
|
||||
setSubModule("properties");
|
||||
setVersionHistory(false);
|
||||
|
@ -90,9 +91,8 @@ const SideBarRight: React.FC = () => {
|
|||
<>
|
||||
<button
|
||||
id="sidebar-action-list-simulation"
|
||||
className={`sidebar-action-list ${
|
||||
subModule === "simulations" ? "active" : ""
|
||||
}`}
|
||||
className={`sidebar-action-list ${subModule === "simulations" ? "active" : ""
|
||||
}`}
|
||||
onClick={() => {
|
||||
setSubModule("simulations");
|
||||
setVersionHistory(false);
|
||||
|
@ -103,9 +103,8 @@ const SideBarRight: React.FC = () => {
|
|||
</button>
|
||||
<button
|
||||
id="sidebar-action-list-mechanics"
|
||||
className={`sidebar-action-list ${
|
||||
subModule === "mechanics" ? "active" : ""
|
||||
}`}
|
||||
className={`sidebar-action-list ${subModule === "mechanics" ? "active" : ""
|
||||
}`}
|
||||
onClick={() => {
|
||||
setSubModule("mechanics");
|
||||
setVersionHistory(false);
|
||||
|
@ -116,9 +115,8 @@ const SideBarRight: React.FC = () => {
|
|||
</button>
|
||||
<button
|
||||
id="sidebar-action-list-analysis"
|
||||
className={`sidebar-action-list ${
|
||||
subModule === "analysis" ? "active" : ""
|
||||
}`}
|
||||
className={`sidebar-action-list ${subModule === "analysis" ? "active" : ""
|
||||
}`}
|
||||
onClick={() => {
|
||||
setSubModule("analysis");
|
||||
setVersionHistory(false);
|
||||
|
@ -147,7 +145,10 @@ const SideBarRight: React.FC = () => {
|
|||
!selectedFloorItem && (
|
||||
<div className="sidebar-right-container">
|
||||
<div className="sidebar-right-content-container">
|
||||
<GlobalProperties />
|
||||
{toolMode === "Aisle" ? (
|
||||
<AisleProperties />) : (
|
||||
<GlobalProperties />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
|
|
@ -11,9 +11,10 @@ import Dashed from "../../../../assets/image/aisleTypes/Dashed.png";
|
|||
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";
|
||||
|
||||
interface TextureItem {
|
||||
color: string;
|
||||
color: AisleColors;
|
||||
id: string;
|
||||
brief: string;
|
||||
texture: string;
|
||||
|
@ -22,10 +23,7 @@ interface TextureItem {
|
|||
const AisleProperties: React.FC = () => {
|
||||
const [collapsePresets, setCollapsePresets] = useState(false);
|
||||
const [collapseTexture, setCollapseTexture] = useState(true);
|
||||
const [selectedTexture, setSelectedTexture] = useState<string | null>(
|
||||
"yellow1"
|
||||
);
|
||||
const [selectedType, setSelectedType] = useState<string | null>("Solid");
|
||||
const { aisleType, aisleWidth, aisleColor, setAisleType, setAisleColor, setAisleWidth } = useBuilderStore();
|
||||
|
||||
const aisleTextureList: TextureItem[] = [
|
||||
{ color: "gray", id: "gray", brief: "basic", texture: "" },
|
||||
|
@ -60,58 +58,82 @@ const AisleProperties: React.FC = () => {
|
|||
},
|
||||
];
|
||||
|
||||
const aisleTypes = [
|
||||
{
|
||||
name: "Solid",
|
||||
id: "1",
|
||||
thumbnail: Solid,
|
||||
},
|
||||
{
|
||||
name: "Dotted",
|
||||
id: "2",
|
||||
thumbnail: Dotted,
|
||||
},
|
||||
{
|
||||
name: "Dashed",
|
||||
id: "3",
|
||||
thumbnail: Dashed,
|
||||
},
|
||||
{
|
||||
name: "Arrow",
|
||||
id: "4",
|
||||
thumbnail: Arrow,
|
||||
},
|
||||
{
|
||||
name: "Contiuous Arrows",
|
||||
id: "5",
|
||||
thumbnail: Arrows,
|
||||
},
|
||||
{
|
||||
name: "Directional",
|
||||
id: "6",
|
||||
thumbnail: Directional,
|
||||
},
|
||||
{
|
||||
name: "Arc",
|
||||
id: "7",
|
||||
thumbnail: Arc,
|
||||
},
|
||||
{
|
||||
name: "Circle",
|
||||
id: "8",
|
||||
thumbnail: Circle,
|
||||
},
|
||||
];
|
||||
const aisleTypes: {
|
||||
name: string;
|
||||
type: AisleTypes;
|
||||
id: string;
|
||||
thumbnail: string;
|
||||
}[] = [
|
||||
{
|
||||
name: "Solid",
|
||||
type: "solid-aisle",
|
||||
id: "1",
|
||||
thumbnail: Solid,
|
||||
},
|
||||
{
|
||||
name: "Dotted",
|
||||
type: "dotted-aisle",
|
||||
id: "2",
|
||||
thumbnail: Dotted,
|
||||
},
|
||||
{
|
||||
name: "Dashed",
|
||||
type: "dashed-aisle",
|
||||
id: "3",
|
||||
thumbnail: Dashed,
|
||||
},
|
||||
{
|
||||
name: "Arrow",
|
||||
type: "arrow-aisle",
|
||||
id: "4",
|
||||
thumbnail: Arrow,
|
||||
},
|
||||
{
|
||||
name: "Contiuous Arrows",
|
||||
type: "arrows-aisle",
|
||||
id: "5",
|
||||
thumbnail: Arrows,
|
||||
},
|
||||
{
|
||||
name: "Directional",
|
||||
type: "junction-aisle",
|
||||
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 (
|
||||
<div className="aisle-properties-container">
|
||||
<div className="header">Properties</div>
|
||||
<section>
|
||||
<InputWithDropDown
|
||||
label="Width"
|
||||
value="1"
|
||||
editableLabel
|
||||
onChange={() => {}}
|
||||
label="Aisle Width"
|
||||
value={`${aisleWidth}`}
|
||||
min={0.1}
|
||||
step={0.1}
|
||||
max={2}
|
||||
defaultValue="0.1"
|
||||
onChange={handleAisleWidthChange}
|
||||
/>
|
||||
</section>
|
||||
|
||||
|
@ -132,12 +154,11 @@ const AisleProperties: React.FC = () => {
|
|||
{aisleTypes.map((val) => (
|
||||
<div className="preset-list" key={val.id}>
|
||||
<button
|
||||
className={`thumbnail ${
|
||||
selectedType === val.name ? "selected" : ""
|
||||
}`}
|
||||
className={`thumbnail ${aisleType === val.type ? "selected" : ""
|
||||
}`}
|
||||
title={val.name}
|
||||
onClick={() => {
|
||||
setSelectedType(val.name);
|
||||
setAisleType(val.type);
|
||||
}}
|
||||
>
|
||||
<img src={val.thumbnail} alt="" />
|
||||
|
@ -170,11 +191,10 @@ const AisleProperties: React.FC = () => {
|
|||
<button
|
||||
key={val.id}
|
||||
title={val.brief || val.id}
|
||||
className={`aisle-list ${
|
||||
selectedTexture === val.id ? "selected" : ""
|
||||
}`}
|
||||
onClick={() => setSelectedTexture(val.id)}
|
||||
aria-pressed={selectedTexture === val.id}
|
||||
className={`aisle-list ${aisleColor === val.color ? "selected" : ""
|
||||
}`}
|
||||
onClick={() => setAisleColor(val.color)}
|
||||
aria-pressed={aisleColor === val.id}
|
||||
>
|
||||
<div className="texture-display">{val.texture}</div>
|
||||
<div className="aisle-color">{val.color}</div>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import DashedAisle from './aisleTypes/dashedAisle';
|
||||
import DottedAisle from './aisleTypes/dottedAisle';
|
||||
import SolidAisle from './aisleTypes/solidAisle';
|
||||
|
||||
function AisleInstance({ aisle }: { readonly aisle: Aisle }) {
|
||||
|
@ -12,6 +13,10 @@ function AisleInstance({ aisle }: { readonly aisle: Aisle }) {
|
|||
{aisle.type.aisleType === 'dashed-aisle' && (
|
||||
<DashedAisle aisle={aisle} />
|
||||
)}
|
||||
|
||||
{aisle.type.aisleType === 'dotted-aisle' && (
|
||||
<DottedAisle aisle={aisle} />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ function DashedAisle({ aisle }: { readonly aisle: Aisle }) {
|
|||
|
||||
const start = new THREE.Vector3(...aisle.points[0].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 gapLength = 0.3;
|
||||
|
||||
|
@ -59,7 +59,7 @@ function DashedAisle({ aisle }: { readonly aisle: Aisle }) {
|
|||
castShadow
|
||||
>
|
||||
<meshStandardMaterial
|
||||
color={aisle.type.color || '#ffffff'}
|
||||
color={aisle.type.aisleColor || '#ffffff'}
|
||||
side={THREE.DoubleSide}
|
||||
/>
|
||||
</Extrude>
|
||||
|
|
|
@ -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;
|
|
@ -9,7 +9,7 @@ function SolidAisle({ aisle }: { readonly aisle: Aisle }) {
|
|||
|
||||
const start = new THREE.Vector3(...aisle.points[0].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 perp = new THREE.Vector3(-direction.z, 0, direction.x).normalize();
|
||||
|
@ -42,7 +42,7 @@ function SolidAisle({ aisle }: { readonly aisle: Aisle }) {
|
|||
castShadow
|
||||
>
|
||||
<meshStandardMaterial
|
||||
color={aisle.type.color || '#ffffff'}
|
||||
color={aisle.type.aisleColor || '#ffffff'}
|
||||
side={THREE.DoubleSide}
|
||||
/>
|
||||
</Extrude>
|
||||
|
|
|
@ -3,8 +3,8 @@ import { useEffect, useMemo, useState } from 'react'
|
|||
import { useThree } from '@react-three/fiber';
|
||||
import { useActiveLayer, useSocketStore, useToggleView, useToolMode } from '../../../../store/builder/store';
|
||||
import { useAisleStore } from '../../../../store/builder/useAisleStore';
|
||||
import * as Constants from '../../../../types/world/worldConstants';
|
||||
import ReferenceAisle from './referenceAisle';
|
||||
import { useBuilderStore } from '../../../../store/builder/useBuilderStore';
|
||||
|
||||
function AisleCreator() {
|
||||
const { scene, camera, raycaster, gl, pointer } = useThree();
|
||||
|
@ -17,14 +17,14 @@ function AisleCreator() {
|
|||
|
||||
const [tempPoints, setTempPoints] = useState<Point[]>([]);
|
||||
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(() => {
|
||||
if (tempPoints.length > 0) {
|
||||
setTempPoints([]);
|
||||
setIsCreating(false);
|
||||
}
|
||||
}, [aisleType]);
|
||||
// useEffect(() => {
|
||||
// if (tempPoints.length > 0) {
|
||||
// setTempPoints([]);
|
||||
// setIsCreating(false);
|
||||
// }
|
||||
// }, [aisleType]);
|
||||
|
||||
const allPoints = useMemo(() => {
|
||||
const points: Point[] = [];
|
||||
|
@ -102,10 +102,9 @@ function AisleCreator() {
|
|||
points: [tempPoints[0], newPoint],
|
||||
type: {
|
||||
typeName: 'Aisle',
|
||||
material: 'default',
|
||||
aisleType: aisleType,
|
||||
color: Constants.aisleConfig.defaultColor,
|
||||
width: Constants.aisleConfig.width
|
||||
aisleColor: aisleColor,
|
||||
aisleWidth: aisleWidth
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -114,33 +113,7 @@ function AisleCreator() {
|
|||
setTempPoints([newPoint]);
|
||||
}
|
||||
} else if (['arc-aisle', 'circle-aisle', 'arrow-aisle', 'junction-aisle'].includes(aisleType)) {
|
||||
const newPoint: Point = {
|
||||
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);
|
||||
}
|
||||
console.log();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -170,7 +143,7 @@ function AisleCreator() {
|
|||
canvasElement.removeEventListener("click", onMouseClick);
|
||||
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 (
|
||||
<>
|
||||
|
@ -188,7 +161,7 @@ function AisleCreator() {
|
|||
))}
|
||||
</group>
|
||||
|
||||
<ReferenceAisle tempPoints={tempPoints} aisleType={aisleType} />
|
||||
<ReferenceAisle tempPoints={tempPoints} aisleType={aisleType} aisleWidth={aisleWidth} aisleColor={aisleColor} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -7,10 +7,12 @@ import { Extrude } from '@react-three/drei';
|
|||
|
||||
interface ReferenceAisleProps {
|
||||
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 { toolMode } = useToolMode();
|
||||
const { toggleView } = useToggleView();
|
||||
|
@ -41,10 +43,9 @@ function ReferenceAisle({ tempPoints, aisleType }: Readonly<ReferenceAisleProps>
|
|||
],
|
||||
type: {
|
||||
typeName: 'Aisle',
|
||||
material: 'default',
|
||||
aisleType: aisleType,
|
||||
color: Constants.aisleConfig.defaultColor,
|
||||
width: Constants.aisleConfig.width
|
||||
aisleColor: aisleColor,
|
||||
aisleWidth: aisleWidth
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -55,7 +56,7 @@ function ReferenceAisle({ tempPoints, aisleType }: Readonly<ReferenceAisleProps>
|
|||
|
||||
useEffect(() => {
|
||||
setTempAisle(null);
|
||||
}, [toolMode, toggleView, tempPoints.length, aisleType]);
|
||||
}, [toolMode, toggleView, tempPoints.length, aisleType, aisleWidth, aisleColor]);
|
||||
|
||||
if (!tempAisle) return null;
|
||||
|
||||
|
@ -65,6 +66,8 @@ function ReferenceAisle({ tempPoints, aisleType }: Readonly<ReferenceAisleProps>
|
|||
return <SolidAisle aisle={tempAisle} />;
|
||||
case 'dashed-aisle':
|
||||
return <DashedAisle aisle={tempAisle} />;
|
||||
case 'dotted-aisle':
|
||||
return <DottedAisle aisle={tempAisle} />;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
@ -79,14 +82,13 @@ function ReferenceAisle({ tempPoints, aisleType }: Readonly<ReferenceAisleProps>
|
|||
|
||||
export default ReferenceAisle;
|
||||
|
||||
|
||||
function SolidAisle({ aisle }: { readonly aisle: Aisle }) {
|
||||
const shape = useMemo(() => {
|
||||
if (aisle.points.length < 2) return null;
|
||||
|
||||
const start = new THREE.Vector3(...aisle.points[0].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 perp = new THREE.Vector3(-direction.z, 0, direction.x).normalize();
|
||||
|
@ -119,7 +121,7 @@ function SolidAisle({ aisle }: { readonly aisle: Aisle }) {
|
|||
castShadow
|
||||
>
|
||||
<meshStandardMaterial
|
||||
color={aisle.type.color || '#ffffff'}
|
||||
color={aisle.type.aisleColor || '#ffffff'}
|
||||
side={THREE.DoubleSide}
|
||||
/>
|
||||
</Extrude>
|
||||
|
@ -133,7 +135,7 @@ function DashedAisle({ aisle }: { readonly aisle: Aisle }) {
|
|||
|
||||
const start = new THREE.Vector3(...aisle.points[0].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 gapLength = 0.3;
|
||||
|
||||
|
@ -183,7 +185,59 @@ function DashedAisle({ aisle }: { readonly aisle: Aisle }) {
|
|||
castShadow
|
||||
>
|
||||
<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}
|
||||
/>
|
||||
</Extrude>
|
||||
|
|
|
@ -9,8 +9,7 @@ interface AisleStore {
|
|||
removeAisle: (uuid: string) => void;
|
||||
setPosition: (pointUuid: string, position: [number, number, number]) => void;
|
||||
setLayer: (pointUuid: string, layer: number) => void;
|
||||
setMaterial: (aisleUuid: string, material: string) => void;
|
||||
setColor: (aisleUuid: string, color: string) => void;
|
||||
setColor: (aisleUuid: string, color: AisleColors) => void;
|
||||
setWidth: (aisleUuid: string, width: number) => void;
|
||||
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);
|
||||
if (aisle) {
|
||||
aisle.type.material = material;
|
||||
}
|
||||
}),
|
||||
|
||||
setColor: (aisleUuid: string, color: string) => set((state) => {
|
||||
const aisle = state.aisles.find(a => a.uuid === aisleUuid);
|
||||
if (aisle) {
|
||||
aisle.type.color = color;
|
||||
aisle.type.aisleColor = color;
|
||||
}
|
||||
}),
|
||||
|
||||
setWidth: (aisleUuid: string, width: number) => set((state) => {
|
||||
const aisle = state.aisles.find(a => a.uuid === aisleUuid);
|
||||
if (aisle) {
|
||||
aisle.type.width = width;
|
||||
aisle.type.aisleWidth = width;
|
||||
}
|
||||
}),
|
||||
|
||||
|
|
|
@ -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;
|
||||
});
|
||||
}
|
||||
}))
|
||||
);
|
|
@ -37,12 +37,15 @@ interface Point {
|
|||
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 {
|
||||
typeName: 'Aisle';
|
||||
material: string;
|
||||
aisleType: 'solid-aisle' | 'dashed-aisle' | 'stripped-aisle' | 'dotted-aisle' | 'arrow-aisle'| 'arrows-aisle' | 'arc-aisle' | 'circle-aisle' | 'junction-aisle';
|
||||
color: string;
|
||||
width: number;
|
||||
aisleType: AisleTypes;
|
||||
aisleColor: AisleColors;
|
||||
aisleWidth: number;
|
||||
}
|
||||
|
||||
interface Aisle {
|
||||
|
|
Loading…
Reference in New Issue