414 lines
12 KiB
TypeScript
414 lines
12 KiB
TypeScript
import { Object3D, Vector3 } from 'three';
|
|
import { create } from 'zustand';
|
|
import { immer } from 'zustand/middleware/immer';
|
|
|
|
interface BuilderState {
|
|
// Point & Line Interaction
|
|
hoveredPoint: Point | null;
|
|
snappedPoint: Point | null;
|
|
snappedPosition: [number, number, number] | null;
|
|
hoveredLine: [Point, Point] | null;
|
|
|
|
// Wall Asset
|
|
selectedWallAsset: Object3D | null;
|
|
deletableWallAsset: Object3D | null;
|
|
|
|
// Floor Asset
|
|
selectedFloorAsset: Object3D | null;
|
|
loopAnimation: boolean;
|
|
|
|
// Wall Settings
|
|
selectedWall: Object3D | null;
|
|
wallThickness: number;
|
|
wallHeight: number;
|
|
outsideMaterial: string;
|
|
insideMaterial: string;
|
|
|
|
// Floor Settings
|
|
selectedFloor: Object3D | null;
|
|
floorDepth: number;
|
|
isBeveled: boolean;
|
|
bevelStrength: number;
|
|
sideMaterial: string;
|
|
topMaterial: string;
|
|
|
|
// Zone Settings
|
|
selectedZone: Object3D | null;
|
|
zoneHeight: number;
|
|
zoneColor: string;
|
|
|
|
// Decal Settings
|
|
selectedDecal: { decalMesh: Object3D | null, decalData: Decal } | null;
|
|
deletableDecal: Object3D | null;
|
|
decalDragState: {
|
|
isDragging: boolean,
|
|
draggingDecalUuid: string | null,
|
|
dragOffset: Vector3 | null,
|
|
},
|
|
|
|
// Aisle General
|
|
selectedAisle: Object3D | null;
|
|
aisleType: AisleTypes;
|
|
aisleWidth: number;
|
|
aisleColor: AisleColors;
|
|
|
|
// Aisle Specific Styles
|
|
dashLength: number;
|
|
gapLength: number;
|
|
dotRadius: number;
|
|
aisleLength: number;
|
|
isFlipped: boolean;
|
|
|
|
// Setters - Point/Line
|
|
setHoveredPoint: (point: Point | null) => void;
|
|
setSnappedPoint: (point: Point | null) => void;
|
|
setSnappedPosition: (position: [number, number, number] | null) => void;
|
|
setHoveredLine: (line: [Point, Point] | null) => void;
|
|
|
|
// Setters - Wall Asset
|
|
setSelectedWallAsset: (asset: Object3D | null) => void;
|
|
setDeletableWallAsset: (asset: Object3D | null) => void;
|
|
|
|
// Setters - Floor Asset
|
|
setSelectedFloorAsset: (asset: Object3D | null) => void;
|
|
setLoopAnimation: (loop: boolean) => void;
|
|
|
|
// Setters - Wall
|
|
setSelectedWall: (wall: Object3D | null) => void;
|
|
setWallThickness: (thickness: number) => void;
|
|
setWallHeight: (height: number) => void;
|
|
setWallMaterial: (material: string, side: 'inside' | 'outside') => void;
|
|
|
|
// Setters - Floor
|
|
setSelectedFloor: (floor: Object3D | null) => void;
|
|
setFloorDepth: (depth: number) => void;
|
|
setIsBeveled: (isBeveled: boolean) => void;
|
|
setBevelStrength: (strength: number) => void;
|
|
setFloorMaterial: (material: string, side: 'side' | 'top') => void;
|
|
|
|
// Setters - Zone
|
|
setSelectedZone: (zone: Object3D | null) => void;
|
|
setZoneHeight: (height: number) => void;
|
|
setZoneColor: (color: string) => void;
|
|
|
|
// Setters - Decal
|
|
setSelectedDecal: (decal: { decalMesh: Object3D | null, decalData: Decal } | null) => void;
|
|
setDeletableDecal: (decal: Object3D | null) => void;
|
|
setDecalDragState: (isDragging: boolean, draggingDecalUuid: string | null, dragOffset: Vector3 | null) => void;
|
|
|
|
// Setters - Aisle General
|
|
setSelectedAisle: (aisle: Object3D | null) => void;
|
|
setAisleType: (type: AisleTypes) => void;
|
|
setAisleWidth: (width: number) => void;
|
|
setAisleColor: (color: AisleColors) => void;
|
|
|
|
// Setters - Aisle Specific
|
|
setDashLength: (length: number) => void;
|
|
setGapLength: (length: number) => void;
|
|
setDotRadius: (radius: number) => void;
|
|
setAisleLength: (length: number) => void;
|
|
setIsFlipped: (isFlipped: boolean) => 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) => ({
|
|
// === Defaults ===
|
|
hoveredPoint: null,
|
|
snappedPoint: null,
|
|
snappedPosition: null,
|
|
hoveredLine: null,
|
|
|
|
selectedWallAsset: null,
|
|
deletableWallAsset: null,
|
|
|
|
selectedFloorAsset: null,
|
|
loopAnimation: true,
|
|
|
|
selectedWall: null,
|
|
wallThickness: 0.5,
|
|
wallHeight: 7,
|
|
outsideMaterial: 'Default Material',
|
|
insideMaterial: 'Material 1',
|
|
|
|
selectedFloor: null,
|
|
floorDepth: 0.1,
|
|
isBeveled: false,
|
|
bevelStrength: 5,
|
|
sideMaterial: 'Material 1',
|
|
topMaterial: 'Default Material',
|
|
|
|
selectedZone: null,
|
|
zoneHeight: 7,
|
|
zoneColor: 'blue',
|
|
|
|
selectedDecal: null,
|
|
deletableDecal: null,
|
|
decalDragState: {
|
|
isDragging: false,
|
|
draggingDecalUuid: null,
|
|
dragOffset: null,
|
|
},
|
|
|
|
selectedAisle: null,
|
|
aisleType: 'solid-aisle',
|
|
aisleWidth: 0.1,
|
|
aisleColor: 'yellow',
|
|
|
|
dashLength: 0.5,
|
|
gapLength: 0.3,
|
|
dotRadius: 0.1,
|
|
aisleLength: 0.6,
|
|
isFlipped: false,
|
|
|
|
// === Setters: Point/Line ===
|
|
|
|
setHoveredPoint: (point: Point | null) => {
|
|
set((state) => {
|
|
state.hoveredPoint = point;
|
|
});
|
|
},
|
|
|
|
setSnappedPoint: (point: Point | null) => {
|
|
set((state) => {
|
|
state.snappedPoint = point;
|
|
});
|
|
},
|
|
|
|
setSnappedPosition: (position: [number, number, number] | null) => {
|
|
set((state) => {
|
|
state.snappedPosition = position;
|
|
});
|
|
},
|
|
|
|
setHoveredLine: (line: [Point, Point] | null) => {
|
|
set((state) => {
|
|
state.hoveredLine = line;
|
|
})
|
|
},
|
|
|
|
// === Setters: Wall Asset ===
|
|
|
|
setSelectedWallAsset(asset: Object3D | null) {
|
|
set((state) => {
|
|
state.selectedWallAsset = asset;
|
|
});
|
|
},
|
|
|
|
setDeletableWallAsset(asset: Object3D | null) {
|
|
set((state) => {
|
|
state.deletableWallAsset = asset;
|
|
});
|
|
},
|
|
|
|
// === Setters: Floor Asset ===
|
|
|
|
setSelectedFloorAsset(asset: Object3D | null) {
|
|
set((state) => {
|
|
state.selectedFloorAsset = asset;
|
|
});
|
|
},
|
|
|
|
setLoopAnimation(loopAnimation: boolean) {
|
|
set((state) => {
|
|
state.loopAnimation = loopAnimation;
|
|
});
|
|
},
|
|
|
|
// === Setters: Wall ===
|
|
|
|
setSelectedWall: (wall: Object3D | null) => {
|
|
set((state) => {
|
|
state.selectedWall = wall;
|
|
})
|
|
},
|
|
|
|
setWallThickness: (thickness: number) => {
|
|
set((state) => {
|
|
state.wallThickness = thickness;
|
|
})
|
|
},
|
|
|
|
setWallHeight: (height: number) => {
|
|
set((state) => {
|
|
state.wallHeight = height;
|
|
})
|
|
},
|
|
|
|
setWallMaterial: (material: string, side: 'inside' | 'outside') => {
|
|
set((state) => {
|
|
if (side === 'outside') state.outsideMaterial = material;
|
|
else state.insideMaterial = material;
|
|
});
|
|
},
|
|
|
|
// === Setters: Floor ===
|
|
setSelectedFloor: (floor: Object3D | null) => {
|
|
set((state) => {
|
|
state.selectedFloor = floor;
|
|
});
|
|
},
|
|
|
|
setFloorDepth: (depth: number) => {
|
|
set((state) => {
|
|
state.floorDepth = depth;
|
|
});
|
|
},
|
|
|
|
setIsBeveled: (isBeveled: boolean) => {
|
|
set((state) => {
|
|
state.isBeveled = isBeveled;
|
|
});
|
|
},
|
|
|
|
setBevelStrength: (strength: number) => {
|
|
set((state) => {
|
|
state.bevelStrength = strength;
|
|
});
|
|
},
|
|
|
|
setFloorMaterial: (material: string, side: 'side' | 'top') => {
|
|
set((state) => {
|
|
if (side === 'side') state.sideMaterial = material;
|
|
else state.topMaterial = material;
|
|
});
|
|
},
|
|
|
|
// === Setters: Zone ===
|
|
|
|
setSelectedZone: (zone: Object3D | null) => {
|
|
set((state) => {
|
|
state.selectedZone = zone;
|
|
});
|
|
},
|
|
|
|
setZoneHeight: (height: number) => {
|
|
set((state) => {
|
|
state.zoneHeight = height;
|
|
});
|
|
},
|
|
|
|
setZoneColor: (color: string) => {
|
|
set((state) => {
|
|
state.zoneColor = color;
|
|
});
|
|
},
|
|
|
|
// === Setters: Decal ===
|
|
|
|
setSelectedDecal: (decal: { decalMesh: Object3D | null, decalData: Decal } | null) => {
|
|
set((state) => {
|
|
state.selectedDecal = decal;
|
|
})
|
|
},
|
|
|
|
setDeletableDecal: (decal: Object3D | null) => {
|
|
set((state) => {
|
|
state.deletableDecal = decal;
|
|
})
|
|
},
|
|
|
|
setDecalDragState: (isDragging: boolean, draggingDecalUuid: string | null, dragOffset: Vector3 | null) => {
|
|
set((state) => {
|
|
state.decalDragState = {
|
|
isDragging,
|
|
draggingDecalUuid,
|
|
dragOffset,
|
|
}
|
|
})
|
|
},
|
|
|
|
// === Setters: Aisle General ===
|
|
|
|
setSelectedAisle: (aisle: Object3D | null) => {
|
|
set((state) => {
|
|
state.selectedAisle = aisle;
|
|
});
|
|
},
|
|
|
|
setAisleType: (type) => {
|
|
set((state) => {
|
|
state.aisleType = type;
|
|
});
|
|
},
|
|
|
|
setAisleWidth: (width) => {
|
|
set((state) => {
|
|
state.aisleWidth = width;
|
|
});
|
|
},
|
|
|
|
setAisleColor: (color) => {
|
|
set((state) => {
|
|
state.aisleColor = color;
|
|
});
|
|
},
|
|
|
|
// === Setters: Aisle Specific ===
|
|
|
|
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;
|
|
});
|
|
},
|
|
|
|
setIsFlipped: (isFlipped) => {
|
|
set((state) => {
|
|
state.isFlipped = isFlipped;
|
|
});
|
|
},
|
|
|
|
// === 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;
|
|
state.aisleWidth = width;
|
|
state.aisleColor = color;
|
|
})
|
|
}))
|
|
);
|