Refactor aisle properties and types in builder store
- Updated AisleProperties component to include new properties for dashed, dotted, and arrows aisles. - Added new handlers for dash length, gap length, dot radius, and aisle length changes. - Enhanced aisle type management in AisleCreator to handle new aisle types and their properties. - Introduced type-specific setters in useAisleStore for better aisle property management. - Updated builderTypes to define specific interfaces for each aisle type. - Improved rendering logic for advanced properties based on selected aisle type.
This commit is contained in:
parent
d30ae34426
commit
9875239d54
|
@ -23,39 +23,20 @@ interface TextureItem {
|
|||
const AisleProperties: React.FC = () => {
|
||||
const [collapsePresets, setCollapsePresets] = useState(false);
|
||||
const [collapseTexture, setCollapseTexture] = useState(true);
|
||||
const { aisleType, aisleWidth, aisleColor, setAisleType, setAisleColor, setAisleWidth } = useBuilderStore();
|
||||
|
||||
const { aisleType, aisleWidth, aisleColor, dashLength, gapLength, dotRadius, aisleLength, setAisleType, setAisleColor, setAisleWidth, setDashLength, setGapLength, setDotRadius, setAisleLength } = useBuilderStore();
|
||||
|
||||
const aisleTextureList: TextureItem[] = [
|
||||
{
|
||||
color: "yellow",
|
||||
id: "yellow1",
|
||||
brief: "pedestrian walkways",
|
||||
texture: "",
|
||||
},
|
||||
{ color: "yellow", id: "yellow1", brief: "pedestrian walkways", texture: "" },
|
||||
{ color: "gray", id: "gray", brief: "basic", texture: "" },
|
||||
{ color: "green", id: "green1", brief: "pedestrian walkways", texture: "" },
|
||||
{ color: "orange", id: "orange", brief: "material flow", texture: "" },
|
||||
{ color: "blue", id: "blue", brief: "vehicle paths", texture: "" },
|
||||
{ color: "purple", id: "purple", brief: "material flow", texture: "" },
|
||||
{ color: "red", id: "red", brief: "safety zone", texture: "" },
|
||||
{
|
||||
color: "bright green",
|
||||
id: "bright-green",
|
||||
brief: "safety zone",
|
||||
texture: "",
|
||||
},
|
||||
{
|
||||
color: "yellow-black",
|
||||
id: "yellow-black",
|
||||
brief: "utility aisles",
|
||||
texture: "",
|
||||
},
|
||||
{
|
||||
color: "white-black",
|
||||
id: "white-black",
|
||||
brief: "utility aisles",
|
||||
texture: "",
|
||||
},
|
||||
{ color: "bright green", id: "bright-green", brief: "safety zone", texture: "" },
|
||||
{ color: "yellow-black", id: "yellow-black", brief: "utility aisles", texture: "" },
|
||||
{ color: "white-black", id: "white-black", brief: "utility aisles", texture: "" },
|
||||
];
|
||||
|
||||
const aisleTypes: {
|
||||
|
@ -64,77 +45,148 @@ const AisleProperties: React.FC = () => {
|
|||
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,
|
||||
},
|
||||
{ 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: "Continuous 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;
|
||||
if (!isNaN(width)) {
|
||||
setAisleWidth(width);
|
||||
}
|
||||
setAisleWidth(width);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDashLengthChange = (value: string) => {
|
||||
const length = parseFloat(value);
|
||||
if (!isNaN(length)) {
|
||||
setDashLength(length);
|
||||
}
|
||||
};
|
||||
|
||||
const handleGapLengthChange = (value: string) => {
|
||||
const length = parseFloat(value);
|
||||
if (!isNaN(length)) {
|
||||
setGapLength(length);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDotRadiusChange = (value: string) => {
|
||||
const radius = parseFloat(value);
|
||||
if (!isNaN(radius)) {
|
||||
setDotRadius(radius);
|
||||
}
|
||||
};
|
||||
|
||||
const handleAisleLengthChange = (value: string) => {
|
||||
const length = parseFloat(value);
|
||||
if (!isNaN(length)) {
|
||||
setAisleLength(length);
|
||||
}
|
||||
};
|
||||
|
||||
const renderAdvancedProperties = () => {
|
||||
switch (aisleType) {
|
||||
case 'dashed-aisle':
|
||||
return (
|
||||
<>
|
||||
{aisleType &&
|
||||
<>
|
||||
<InputWithDropDown
|
||||
label="Dash Length"
|
||||
value={`${dashLength}`}
|
||||
min={0.1}
|
||||
step={0.1}
|
||||
max={2}
|
||||
onChange={handleDashLengthChange}
|
||||
/>
|
||||
<InputWithDropDown
|
||||
label="Gap Length"
|
||||
value={`${gapLength}`}
|
||||
min={0.1}
|
||||
step={0.1}
|
||||
max={2}
|
||||
onChange={handleGapLengthChange}
|
||||
/>
|
||||
</>
|
||||
}
|
||||
</>
|
||||
);
|
||||
case 'dotted-aisle':
|
||||
return (
|
||||
<>
|
||||
{aisleType &&
|
||||
<>
|
||||
<InputWithDropDown
|
||||
label="Dot Radius"
|
||||
value={`${dotRadius}`}
|
||||
min={0.1}
|
||||
step={0.1}
|
||||
max={2}
|
||||
onChange={handleDotRadiusChange}
|
||||
/>
|
||||
<InputWithDropDown
|
||||
label="Gap Length"
|
||||
value={`${gapLength}`}
|
||||
min={0.1}
|
||||
step={0.1}
|
||||
max={2}
|
||||
onChange={handleGapLengthChange}
|
||||
/></>
|
||||
}
|
||||
</>
|
||||
);
|
||||
case 'arrows-aisle':
|
||||
return (
|
||||
<>
|
||||
{aisleType &&
|
||||
<>
|
||||
<InputWithDropDown
|
||||
label="Arrow Length"
|
||||
value={`${aisleLength}`}
|
||||
min={0.1}
|
||||
step={0.1}
|
||||
max={2}
|
||||
onChange={handleAisleLengthChange}
|
||||
/>
|
||||
<InputWithDropDown
|
||||
label="Gap Length"
|
||||
value={`${gapLength}`}
|
||||
min={0.1}
|
||||
step={0.1}
|
||||
max={2}
|
||||
onChange={handleGapLengthChange}
|
||||
/></>
|
||||
}
|
||||
</>
|
||||
);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="aisle-properties-container">
|
||||
<div className="header">Properties</div>
|
||||
|
||||
{/* Basic Properties */}
|
||||
<section>
|
||||
<InputWithDropDown
|
||||
label="Aisle Width"
|
||||
value={`${aisleWidth}`}
|
||||
min={0.1}
|
||||
step={0.1}
|
||||
max={2}
|
||||
defaultValue="0.1"
|
||||
onChange={handleAisleWidthChange}
|
||||
/>
|
||||
{aisleType !== 'dotted-aisle' &&
|
||||
<InputWithDropDown
|
||||
label="Aisle Width"
|
||||
value={`${aisleWidth}`}
|
||||
min={0.1}
|
||||
step={0.1}
|
||||
max={2}
|
||||
onChange={handleAisleWidthChange}
|
||||
/>
|
||||
}
|
||||
{renderAdvancedProperties()}
|
||||
</section>
|
||||
|
||||
{/* Presets */}
|
||||
|
@ -154,12 +206,9 @@ const AisleProperties: React.FC = () => {
|
|||
{aisleTypes.map((val) => (
|
||||
<div className="preset-list" key={val.id}>
|
||||
<button
|
||||
className={`thumbnail ${aisleType === val.type ? "selected" : ""
|
||||
}`}
|
||||
className={`thumbnail ${aisleType === val.type ? "selected" : ""}`}
|
||||
title={val.name}
|
||||
onClick={() => {
|
||||
setAisleType(val.type);
|
||||
}}
|
||||
onClick={() => setAisleType(val.type)}
|
||||
>
|
||||
<img src={val.thumbnail} alt="" />
|
||||
</button>
|
||||
|
@ -177,10 +226,7 @@ const AisleProperties: React.FC = () => {
|
|||
aria-expanded={!collapseTexture}
|
||||
>
|
||||
<div className="value">Aisle Texture</div>
|
||||
<div
|
||||
className="icon"
|
||||
style={{ rotate: collapseTexture ? "" : "-90deg" }}
|
||||
>
|
||||
<div className="icon" style={{ rotate: collapseTexture ? "" : "-90deg" }}>
|
||||
<ArrowIcon />
|
||||
</div>
|
||||
</button>
|
||||
|
@ -191,8 +237,7 @@ const AisleProperties: React.FC = () => {
|
|||
<button
|
||||
key={val.id}
|
||||
title={val.brief || val.id}
|
||||
className={`aisle-list ${aisleColor === val.color ? "selected" : ""
|
||||
}`}
|
||||
className={`aisle-list ${aisleColor === val.color ? "selected" : ""}`}
|
||||
onClick={() => setAisleColor(val.color)}
|
||||
aria-pressed={aisleColor === val.id}
|
||||
>
|
||||
|
|
|
@ -5,13 +5,13 @@ import * as Constants from '../../../../../../types/world/worldConstants';
|
|||
|
||||
function ArrowsAisle({ aisle }: { readonly aisle: Aisle }) {
|
||||
const arrows = useMemo(() => {
|
||||
if (aisle.points.length < 2) return [];
|
||||
if (aisle.points.length < 2 || aisle.type.aisleType !== 'arrows-aisle') 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 arrowLength = aisle.type.aisleLength || 0.6;
|
||||
const spacing = aisle.type.gapLength || 0.6;
|
||||
|
||||
const direction = new THREE.Vector3().subVectors(end, start);
|
||||
const length = direction.length();
|
||||
|
@ -22,7 +22,7 @@ function ArrowsAisle({ aisle }: { readonly aisle: Aisle }) {
|
|||
const arrowShapes: { shape: THREE.Shape; position: THREE.Vector3; rotationY: number }[] = [];
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
const initialOffset = 0.6;
|
||||
const initialOffset = arrowLength;
|
||||
const center = new THREE.Vector3().copy(start).addScaledVector(direction, initialOffset + i * (arrowLength + spacing));
|
||||
|
||||
const shape = new THREE.Shape();
|
||||
|
|
|
@ -5,13 +5,13 @@ import * as Constants from '../../../../../../types/world/worldConstants';
|
|||
|
||||
function DashedAisle({ aisle }: { readonly aisle: Aisle }) {
|
||||
const shapes = useMemo(() => {
|
||||
if (aisle.points.length < 2) return [];
|
||||
if (aisle.points.length < 2 || aisle.type.aisleType !== 'dashed-aisle') 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 dashLength = 0.5;
|
||||
const gapLength = 0.3;
|
||||
const dashLength = aisle.type.dashLength || 0.5;
|
||||
const gapLength = aisle.type.gapLength || 0.3;
|
||||
|
||||
const direction = new THREE.Vector3().subVectors(end, start).normalize();
|
||||
const perp = new THREE.Vector3(-direction.z, 0, direction.x).normalize();
|
||||
|
|
|
@ -5,12 +5,12 @@ import * as Constants from '../../../../../../types/world/worldConstants';
|
|||
|
||||
function DottedAisle({ aisle }: { readonly aisle: Aisle }) {
|
||||
const shapes = useMemo(() => {
|
||||
if (aisle.points.length < 2) return [];
|
||||
if (aisle.points.length < 2 || aisle.type.aisleType !== 'dotted-aisle') 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 width = aisle.type.dotRadius || 0.1;
|
||||
const dotSpacing = aisle.type.gapLength || 0.5;
|
||||
const dotRadius = width * 0.6;
|
||||
|
||||
const totalLength = new THREE.Vector3().subVectors(end, start).length();
|
||||
|
|
|
@ -5,7 +5,7 @@ import * as Constants from '../../../../../../types/world/worldConstants';
|
|||
|
||||
function SolidAisle({ aisle }: { readonly aisle: Aisle }) {
|
||||
const shape = useMemo(() => {
|
||||
if (aisle.points.length < 2) return null;
|
||||
if (aisle.points.length < 2 || aisle.type.aisleType !== 'solid-aisle') return null;
|
||||
|
||||
const start = new THREE.Vector3(...aisle.points[0].position);
|
||||
const end = new THREE.Vector3(...aisle.points[1].position);
|
||||
|
|
|
@ -17,7 +17,7 @@ function AisleCreator() {
|
|||
|
||||
const [tempPoints, setTempPoints] = useState<Point[]>([]);
|
||||
const [isCreating, setIsCreating] = useState(false);
|
||||
const { aisleType, aisleWidth, aisleColor } = useBuilderStore();
|
||||
const { aisleType, aisleWidth, aisleColor, dashLength, gapLength, dotRadius, aisleLength, } = useBuilderStore();
|
||||
|
||||
// useEffect(() => {
|
||||
// if (tempPoints.length > 0) {
|
||||
|
@ -86,7 +86,7 @@ function AisleCreator() {
|
|||
|
||||
if (!point) return;
|
||||
|
||||
if (['solid-aisle', 'dashed-aisle', 'stripped-aisle', 'dotted-aisle', 'arrows-aisle'].includes(aisleType)) {
|
||||
if (aisleType === 'solid-aisle') {
|
||||
const newPoint: Point = {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
position: [point.x, point.y, point.z],
|
||||
|
@ -102,18 +102,123 @@ function AisleCreator() {
|
|||
points: [tempPoints[0], newPoint],
|
||||
type: {
|
||||
typeName: 'Aisle',
|
||||
aisleType: aisleType,
|
||||
aisleType: 'solid-aisle',
|
||||
aisleColor: aisleColor,
|
||||
aisleWidth: aisleWidth
|
||||
}
|
||||
};
|
||||
|
||||
addAisle(aisle);
|
||||
|
||||
setTempPoints([newPoint]);
|
||||
}
|
||||
} else if (['arc-aisle', 'circle-aisle', 'arrow-aisle', 'junction-aisle'].includes(aisleType)) {
|
||||
console.log();
|
||||
} else if (aisleType === 'dashed-aisle') {
|
||||
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',
|
||||
aisleType: 'dashed-aisle',
|
||||
aisleColor: aisleColor,
|
||||
aisleWidth: aisleWidth,
|
||||
dashLength: dashLength,
|
||||
gapLength: gapLength
|
||||
}
|
||||
};
|
||||
addAisle(aisle);
|
||||
setTempPoints([newPoint]);
|
||||
}
|
||||
} else if (aisleType === 'stripped-aisle') {
|
||||
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',
|
||||
aisleType: 'stripped-aisle',
|
||||
aisleColor: aisleColor,
|
||||
aisleWidth: aisleWidth
|
||||
}
|
||||
};
|
||||
addAisle(aisle);
|
||||
setTempPoints([newPoint]);
|
||||
}
|
||||
} else if (aisleType === 'dotted-aisle') {
|
||||
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',
|
||||
aisleType: 'dotted-aisle',
|
||||
aisleColor: aisleColor,
|
||||
dotRadius: dotRadius,
|
||||
gapLength: gapLength
|
||||
}
|
||||
};
|
||||
addAisle(aisle);
|
||||
setTempPoints([newPoint]);
|
||||
}
|
||||
} else if (aisleType === 'arrow-aisle') {
|
||||
console.log('Creating arrow-aisle');
|
||||
} else if (aisleType === 'arrows-aisle') {
|
||||
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',
|
||||
aisleType: 'arrows-aisle',
|
||||
aisleColor: aisleColor,
|
||||
aisleWidth: aisleWidth,
|
||||
aisleLength: aisleLength,
|
||||
gapLength: gapLength
|
||||
}
|
||||
};
|
||||
addAisle(aisle);
|
||||
setTempPoints([newPoint]);
|
||||
}
|
||||
} else if (aisleType === 'arc-aisle') {
|
||||
console.log('Creating arc-aisle');
|
||||
} else if (aisleType === 'circle-aisle') {
|
||||
console.log('Creating circle-aisle');
|
||||
} else if (aisleType === 'junction-aisle') {
|
||||
console.log('Creating junction-aisle');
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -143,7 +248,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, aisleColor, aisleWidth]);
|
||||
}, [gl, camera, scene, raycaster, pointer, plane, toggleView, toolMode, activeLayer, socket, tempPoints, isCreating, addAisle, aisleType, aisleWidth, aisleColor, dashLength, gapLength, dotRadius, aisleLength]);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -161,7 +266,7 @@ function AisleCreator() {
|
|||
))}
|
||||
</group>
|
||||
|
||||
<ReferenceAisle tempPoints={tempPoints} aisleType={aisleType} aisleWidth={aisleWidth} aisleColor={aisleColor} />
|
||||
<ReferenceAisle tempPoints={tempPoints} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -4,15 +4,14 @@ import { useFrame, useThree } from '@react-three/fiber';
|
|||
import { useActiveLayer, useToolMode, useToggleView } from '../../../../store/builder/store';
|
||||
import * as Constants from '../../../../types/world/worldConstants';
|
||||
import { Extrude } from '@react-three/drei';
|
||||
import { useBuilderStore } from '../../../../store/builder/useBuilderStore';
|
||||
|
||||
interface ReferenceAisleProps {
|
||||
tempPoints: Point[];
|
||||
aisleType: AisleTypes;
|
||||
aisleWidth: number;
|
||||
aisleColor: AisleColors;
|
||||
}
|
||||
|
||||
function ReferenceAisle({ tempPoints, aisleType, aisleWidth, aisleColor }: Readonly<ReferenceAisleProps>) {
|
||||
function ReferenceAisle({ tempPoints }: Readonly<ReferenceAisleProps>) {
|
||||
const { aisleType, aisleWidth, aisleColor, dashLength, gapLength, dotRadius, aisleLength, } = useBuilderStore();
|
||||
const { pointer, raycaster, camera } = useThree();
|
||||
const { toolMode } = useToolMode();
|
||||
const { toggleView } = useToggleView();
|
||||
|
@ -31,23 +30,92 @@ function ReferenceAisle({ tempPoints, aisleType, aisleWidth, aisleColor }: Reado
|
|||
if (intersectionPoint) {
|
||||
mousePosRef.current.copy(intersectionPoint);
|
||||
|
||||
setTempAisle({
|
||||
uuid: 'temp-aisle',
|
||||
points: [
|
||||
tempPoints[0],
|
||||
{
|
||||
uuid: 'temp-point',
|
||||
position: [mousePosRef.current.x, mousePosRef.current.y, mousePosRef.current.z],
|
||||
layer: activeLayer
|
||||
if (aisleType === 'solid-aisle' || aisleType === 'stripped-aisle') {
|
||||
setTempAisle({
|
||||
uuid: 'temp-aisle',
|
||||
points: [
|
||||
tempPoints[0],
|
||||
{
|
||||
uuid: 'temp-point',
|
||||
position: [mousePosRef.current.x, mousePosRef.current.y, mousePosRef.current.z],
|
||||
layer: activeLayer
|
||||
}
|
||||
],
|
||||
type: {
|
||||
typeName: 'Aisle',
|
||||
aisleType: aisleType,
|
||||
aisleColor: aisleColor,
|
||||
aisleWidth: aisleWidth
|
||||
}
|
||||
],
|
||||
type: {
|
||||
typeName: 'Aisle',
|
||||
aisleType: aisleType,
|
||||
aisleColor: aisleColor,
|
||||
aisleWidth: aisleWidth
|
||||
}
|
||||
});
|
||||
});
|
||||
} else if (aisleType === 'dashed-aisle') {
|
||||
setTempAisle({
|
||||
uuid: 'temp-aisle',
|
||||
points: [
|
||||
tempPoints[0],
|
||||
{
|
||||
uuid: 'temp-point',
|
||||
position: [mousePosRef.current.x, mousePosRef.current.y, mousePosRef.current.z],
|
||||
layer: activeLayer
|
||||
}
|
||||
],
|
||||
type: {
|
||||
typeName: 'Aisle',
|
||||
aisleType: aisleType,
|
||||
aisleColor: aisleColor,
|
||||
aisleWidth: aisleWidth,
|
||||
dashLength: dashLength,
|
||||
gapLength: gapLength
|
||||
}
|
||||
});
|
||||
} else if (aisleType === 'dotted-aisle') {
|
||||
setTempAisle({
|
||||
uuid: 'temp-aisle',
|
||||
points: [
|
||||
tempPoints[0],
|
||||
{
|
||||
uuid: 'temp-point',
|
||||
position: [mousePosRef.current.x, mousePosRef.current.y, mousePosRef.current.z],
|
||||
layer: activeLayer
|
||||
}
|
||||
],
|
||||
type: {
|
||||
typeName: 'Aisle',
|
||||
aisleType: aisleType,
|
||||
aisleColor: aisleColor,
|
||||
dotRadius: dotRadius,
|
||||
gapLength: gapLength
|
||||
}
|
||||
});
|
||||
} else if (aisleType === 'arrow-aisle') {
|
||||
console.log();
|
||||
} else if (aisleType === 'arrows-aisle') {
|
||||
setTempAisle({
|
||||
uuid: 'temp-aisle',
|
||||
points: [
|
||||
tempPoints[0],
|
||||
{
|
||||
uuid: 'temp-point',
|
||||
position: [mousePosRef.current.x, mousePosRef.current.y, mousePosRef.current.z],
|
||||
layer: activeLayer
|
||||
}
|
||||
],
|
||||
type: {
|
||||
typeName: 'Aisle',
|
||||
aisleType: aisleType,
|
||||
aisleColor: aisleColor,
|
||||
aisleWidth: aisleWidth,
|
||||
aisleLength: aisleLength,
|
||||
gapLength: gapLength
|
||||
}
|
||||
});
|
||||
} else if (aisleType === 'arc-aisle') {
|
||||
console.log();
|
||||
} else if (aisleType === 'circle-aisle') {
|
||||
console.log();
|
||||
} else if (aisleType === 'junction-aisle') {
|
||||
console.log();
|
||||
}
|
||||
}
|
||||
} else if (tempAisle !== null) {
|
||||
setTempAisle(null);
|
||||
|
@ -86,7 +154,7 @@ export default ReferenceAisle;
|
|||
|
||||
function SolidAisle({ aisle }: { readonly aisle: Aisle }) {
|
||||
const shape = useMemo(() => {
|
||||
if (aisle.points.length < 2) return null;
|
||||
if (aisle.points.length < 2 || aisle.type.aisleType !== 'solid-aisle') return null;
|
||||
|
||||
const start = new THREE.Vector3(...aisle.points[0].position);
|
||||
const end = new THREE.Vector3(...aisle.points[1].position);
|
||||
|
@ -133,13 +201,13 @@ function SolidAisle({ aisle }: { readonly aisle: Aisle }) {
|
|||
|
||||
function DashedAisle({ aisle }: { readonly aisle: Aisle }) {
|
||||
const shapes = useMemo(() => {
|
||||
if (aisle.points.length < 2) return [];
|
||||
if (aisle.points.length < 2 || aisle.type.aisleType !== 'dashed-aisle') 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 dashLength = 0.5;
|
||||
const gapLength = 0.3;
|
||||
const dashLength = aisle.type.dashLength || 0.5;
|
||||
const gapLength = aisle.type.gapLength || 0.3;
|
||||
|
||||
const direction = new THREE.Vector3().subVectors(end, start).normalize();
|
||||
const perp = new THREE.Vector3(-direction.z, 0, direction.x).normalize();
|
||||
|
@ -198,12 +266,12 @@ function DashedAisle({ aisle }: { readonly aisle: Aisle }) {
|
|||
|
||||
function DottedAisle({ aisle }: { readonly aisle: Aisle }) {
|
||||
const shapes = useMemo(() => {
|
||||
if (aisle.points.length < 2) return [];
|
||||
if (aisle.points.length < 2 || aisle.type.aisleType !== 'dotted-aisle') 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 width = aisle.type.dotRadius || 0.1;
|
||||
const dotSpacing = aisle.type.gapLength || 0.5;
|
||||
const dotRadius = width * 0.6;
|
||||
|
||||
const totalLength = new THREE.Vector3().subVectors(end, start).length();
|
||||
|
@ -250,13 +318,13 @@ function DottedAisle({ aisle }: { readonly aisle: Aisle }) {
|
|||
|
||||
function ArrowsAisle({ aisle }: { readonly aisle: Aisle }) {
|
||||
const arrows = useMemo(() => {
|
||||
if (aisle.points.length < 2) return [];
|
||||
if (aisle.points.length < 2 || aisle.type.aisleType !== 'arrows-aisle') 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 arrowLength = aisle.type.aisleLength || 0.6;
|
||||
const spacing = aisle.type.gapLength || 0.6;
|
||||
|
||||
const direction = new THREE.Vector3().subVectors(end, start);
|
||||
const length = direction.length();
|
||||
|
@ -267,7 +335,7 @@ function ArrowsAisle({ aisle }: { readonly aisle: Aisle }) {
|
|||
const arrowShapes: { shape: THREE.Shape; position: THREE.Vector3; rotationY: number }[] = [];
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
const initialOffset = 0.6;
|
||||
const initialOffset = arrowLength;
|
||||
const center = new THREE.Vector3().copy(start).addScaledVector(direction, initialOffset + i * (arrowLength + spacing));
|
||||
|
||||
const shape = new THREE.Shape();
|
||||
|
|
|
@ -10,7 +10,7 @@ interface ConnectionLine {
|
|||
trigger: TriggerSchema;
|
||||
}
|
||||
|
||||
export function Arrows({ connections }: { connections: ConnectionLine[] }) {
|
||||
export function Arrows({ connections }: { readonly connections: ConnectionLine[] }) {
|
||||
const [hoveredLineKey, setHoveredLineKey] = useState<string | null>(null);
|
||||
const groupRef = useRef<THREE.Group>(null);
|
||||
const { scene } = useThree();
|
||||
|
|
|
@ -10,8 +10,29 @@ interface AisleStore {
|
|||
setPosition: (pointUuid: string, position: [number, number, number]) => void;
|
||||
setLayer: (pointUuid: string, layer: number) => void;
|
||||
setColor: (aisleUuid: string, color: AisleColors) => void;
|
||||
setWidth: (aisleUuid: string, width: number) => void;
|
||||
|
||||
// Type-specific setters
|
||||
setSolidAisleWidth: (aisleUuid: string, width: number) => void;
|
||||
setDashedAisleProperties: (
|
||||
aisleUuid: string,
|
||||
props: { aisleWidth?: number; dashLength?: number; gapLength?: number }
|
||||
) => void;
|
||||
setStrippedAisleWidth: (aisleUuid: string, width: number) => void;
|
||||
setDottedAisleProperties: (
|
||||
aisleUuid: string,
|
||||
props: { dotRadius?: number; gapLength?: number }
|
||||
) => void;
|
||||
setArrowAisleWidth: (aisleUuid: string, width: number) => void;
|
||||
setArrowsAisleProperties: (
|
||||
aisleUuid: string,
|
||||
props: { aisleWidth?: number; aisleLength?: number; gapLength?: number }
|
||||
) => void;
|
||||
setArcAisleWidth: (aisleUuid: string, width: number) => void;
|
||||
setCircleAisleWidth: (aisleUuid: string, width: number) => void;
|
||||
setJunctionAisleWidth: (aisleUuid: string, width: number) => void;
|
||||
|
||||
getAisleById: (uuid: string) => Aisle | undefined;
|
||||
getAisleType: <T extends AisleType>(uuid: string) => T | undefined;
|
||||
}
|
||||
|
||||
export const useAisleStore = create<AisleStore>()(
|
||||
|
@ -37,7 +58,7 @@ export const useAisleStore = create<AisleStore>()(
|
|||
state.aisles = state.aisles.filter((a) => a.uuid !== uuid);
|
||||
}),
|
||||
|
||||
setPosition: (pointUuid: string, position: [number, number, number]) => set((state) => {
|
||||
setPosition: (pointUuid, position) => set((state) => {
|
||||
for (const aisle of state.aisles) {
|
||||
const point = aisle.points.find(p => p.uuid === pointUuid);
|
||||
if (point) {
|
||||
|
@ -47,7 +68,7 @@ export const useAisleStore = create<AisleStore>()(
|
|||
}
|
||||
}),
|
||||
|
||||
setLayer: (pointUuid: string, layer: number) => set((state) => {
|
||||
setLayer: (pointUuid, layer) => set((state) => {
|
||||
for (const aisle of state.aisles) {
|
||||
const point = aisle.points.find(p => p.uuid === pointUuid);
|
||||
if (point) {
|
||||
|
@ -57,16 +78,78 @@ export const useAisleStore = create<AisleStore>()(
|
|||
}
|
||||
}),
|
||||
|
||||
setColor: (aisleUuid: string, color: AisleColors) => set((state) => {
|
||||
setColor: (aisleUuid, color) => set((state) => {
|
||||
const aisle = state.aisles.find(a => a.uuid === aisleUuid);
|
||||
if (aisle) {
|
||||
aisle.type.aisleColor = color;
|
||||
}
|
||||
}),
|
||||
|
||||
setWidth: (aisleUuid: string, width: number) => set((state) => {
|
||||
// Type-specific property setters
|
||||
setSolidAisleWidth: (aisleUuid, width) => set((state) => {
|
||||
const aisle = state.aisles.find(a => a.uuid === aisleUuid);
|
||||
if (aisle) {
|
||||
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);
|
||||
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;
|
||||
if (props.gapLength !== undefined) aisle.type.gapLength = props.gapLength;
|
||||
}
|
||||
}),
|
||||
|
||||
setStrippedAisleWidth: (aisleUuid, width) => set((state) => {
|
||||
const aisle = state.aisles.find(a => a.uuid === 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);
|
||||
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;
|
||||
}
|
||||
}),
|
||||
|
||||
setArrowAisleWidth: (aisleUuid, width) => set((state) => {
|
||||
const aisle = state.aisles.find(a => a.uuid === 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);
|
||||
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;
|
||||
if (props.gapLength !== undefined) aisle.type.gapLength = props.gapLength;
|
||||
}
|
||||
}),
|
||||
|
||||
setArcAisleWidth: (aisleUuid, width) => set((state) => {
|
||||
const aisle = state.aisles.find(a => a.uuid === 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);
|
||||
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);
|
||||
if (aisle && aisle.type.aisleType === 'junction-aisle') {
|
||||
aisle.type.aisleWidth = width;
|
||||
}
|
||||
}),
|
||||
|
@ -74,5 +157,10 @@ export const useAisleStore = create<AisleStore>()(
|
|||
getAisleById: (uuid) => {
|
||||
return get().aisles.find((a) => a.uuid === uuid);
|
||||
},
|
||||
|
||||
getAisleType: <T extends AisleType>(uuid: string) => {
|
||||
const aisle = get().aisles.find(a => a.uuid === uuid);
|
||||
return aisle?.type as T | undefined;
|
||||
},
|
||||
}))
|
||||
);
|
|
@ -2,20 +2,55 @@ import { create } from 'zustand';
|
|||
import { immer } from 'zustand/middleware/immer';
|
||||
|
||||
interface BuilderState {
|
||||
// Common properties
|
||||
aisleType: AisleTypes;
|
||||
aisleWidth: number;
|
||||
aisleColor: AisleColors;
|
||||
|
||||
// Dashed aisle properties
|
||||
dashLength: number;
|
||||
gapLength: number;
|
||||
|
||||
// Dotted aisle properties
|
||||
dotRadius: number;
|
||||
|
||||
// Arrows aisle properties
|
||||
aisleLength: number;
|
||||
|
||||
// Setters for common properties
|
||||
setAisleType: (type: AisleTypes) => void;
|
||||
setAisleWidth: (width: number) => void;
|
||||
setAisleColor: (color: AisleColors) => void;
|
||||
|
||||
// Setters for dashed aisle
|
||||
setDashLength: (length: number) => void;
|
||||
setGapLength: (length: number) => void;
|
||||
|
||||
// Setters for dotted aisle
|
||||
setDotRadius: (radius: number) => void;
|
||||
|
||||
// Setters for arrows aisle
|
||||
setAisleLength: (length: number) => void;
|
||||
|
||||
// Batch setters
|
||||
setDashedAisleProperties: (width: number, dashLength: number, gapLength: number) => void;
|
||||
setDottedAisleProperties: (width: number, dotRadius: number, gapLength: number) => void;
|
||||
setArrowsAisleProperties: (width: number, aisleLength: number, gapLength: number) => void;
|
||||
setAisleProperties: (type: AisleTypes, width: number, color: AisleColors) => void;
|
||||
}
|
||||
|
||||
export const useBuilderStore = create<BuilderState>()(
|
||||
immer((set) => ({
|
||||
// Default values
|
||||
aisleType: 'solid-aisle',
|
||||
aisleWidth: 0.1,
|
||||
aisleColor: 'yellow',
|
||||
dashLength: 0.5,
|
||||
gapLength: 0.3,
|
||||
dotRadius: 0.1,
|
||||
aisleLength: 0.6,
|
||||
|
||||
// Individual setters
|
||||
setAisleType: (type) => {
|
||||
set((state) => {
|
||||
state.aisleType = type;
|
||||
|
@ -31,6 +66,52 @@ export const useBuilderStore = create<BuilderState>()(
|
|||
state.aisleColor = color;
|
||||
});
|
||||
},
|
||||
setDashLength: (length) => {
|
||||
set((state) => {
|
||||
state.dashLength = length;
|
||||
});
|
||||
},
|
||||
setGapLength: (length) => {
|
||||
set((state) => {
|
||||
state.gapLength = length;
|
||||
});
|
||||
},
|
||||
setDotRadius: (radius) => {
|
||||
set((state) => {
|
||||
state.dotRadius = radius;
|
||||
});
|
||||
},
|
||||
setAisleLength: (length) => {
|
||||
set((state) => {
|
||||
state.aisleLength = length;
|
||||
});
|
||||
},
|
||||
|
||||
// Batch setters
|
||||
setDashedAisleProperties: (width, dashLength, gapLength) => {
|
||||
set((state) => {
|
||||
state.aisleType = 'dashed-aisle';
|
||||
state.aisleWidth = width;
|
||||
state.dashLength = dashLength;
|
||||
state.gapLength = gapLength;
|
||||
});
|
||||
},
|
||||
setDottedAisleProperties: (width, dotRadius, gapLength) => {
|
||||
set((state) => {
|
||||
state.aisleType = 'dotted-aisle';
|
||||
state.aisleWidth = width;
|
||||
state.dotRadius = dotRadius;
|
||||
state.gapLength = gapLength;
|
||||
});
|
||||
},
|
||||
setArrowsAisleProperties: (width, aisleLength, gapLength) => {
|
||||
set((state) => {
|
||||
state.aisleType = 'arrows-aisle';
|
||||
state.aisleWidth = width;
|
||||
state.aisleLength = aisleLength;
|
||||
state.gapLength = gapLength;
|
||||
});
|
||||
},
|
||||
setAisleProperties: (type, width, color) => {
|
||||
set((state) => {
|
||||
state.aisleType = type;
|
||||
|
|
|
@ -41,13 +41,76 @@ type AisleTypes = | 'solid-aisle' | 'dashed-aisle' | 'stripped-aisle' | 'dotted-
|
|||
|
||||
type AisleColors = | 'gray' | 'yellow' | 'green' | 'orange' | 'blue' | 'purple' | 'red' | 'bright green' | 'yellow-black' | 'white-black'
|
||||
|
||||
interface AisleType {
|
||||
interface SolidAisle {
|
||||
typeName: 'Aisle';
|
||||
aisleType: AisleTypes;
|
||||
aisleType: 'solid-aisle';
|
||||
aisleColor: AisleColors;
|
||||
aisleWidth: number;
|
||||
}
|
||||
|
||||
interface DashedAisle {
|
||||
typeName: 'Aisle';
|
||||
aisleType: 'dashed-aisle';
|
||||
aisleColor: AisleColors;
|
||||
aisleWidth: number;
|
||||
dashLength: number;
|
||||
gapLength: number;
|
||||
}
|
||||
|
||||
interface StrippedAisle {
|
||||
typeName: 'Aisle';
|
||||
aisleType: 'stripped-aisle';
|
||||
aisleColor: AisleColors;
|
||||
aisleWidth: number;
|
||||
}
|
||||
|
||||
interface DottedAisle {
|
||||
typeName: 'Aisle';
|
||||
aisleType: 'dotted-aisle';
|
||||
aisleColor: AisleColors;
|
||||
dotRadius: number;
|
||||
gapLength: number;
|
||||
}
|
||||
|
||||
interface ArrowAisle {
|
||||
typeName: 'Aisle';
|
||||
aisleType: 'arrow-aisle';
|
||||
aisleColor: AisleColors;
|
||||
aisleWidth: number;
|
||||
}
|
||||
|
||||
interface ArrowsAisle {
|
||||
typeName: 'Aisle';
|
||||
aisleType: 'arrows-aisle';
|
||||
aisleColor: AisleColors;
|
||||
aisleWidth: number;
|
||||
aisleLength: number;
|
||||
gapLength: number;
|
||||
}
|
||||
|
||||
interface ArcAisle {
|
||||
typeName: 'Aisle';
|
||||
aisleType: 'arc-aisle';
|
||||
aisleColor: AisleColors;
|
||||
aisleWidth: number;
|
||||
}
|
||||
|
||||
interface CircleAisle {
|
||||
typeName: 'Aisle';
|
||||
aisleType: 'circle-aisle';
|
||||
aisleColor: AisleColors;
|
||||
aisleWidth: number;
|
||||
}
|
||||
|
||||
interface JunctionAisle {
|
||||
typeName: 'Aisle';
|
||||
aisleType: 'junction-aisle';
|
||||
aisleColor: AisleColors;
|
||||
aisleWidth: number;
|
||||
}
|
||||
|
||||
type AisleType = SolidAisle | DashedAisle | StrippedAisle | DottedAisle | ArrowAisle | ArrowsAisle | ArcAisle | CircleAisle | JunctionAisle;
|
||||
|
||||
interface Aisle {
|
||||
uuid: string;
|
||||
points: [Point, Point];
|
||||
|
|
Loading…
Reference in New Issue