- Create coordinates.ts with centralized SCALE constant - Add calculatePlantCoords() helper matching SmartRack grid logic - Refactor all beacon position calcs to use helper - Uses col*colSpacing where colSpacing = width/(maxCols+1) - This matches how plants are actually rendered in PlantSystem
71 lines
2.5 KiB
TypeScript
71 lines
2.5 KiB
TypeScript
import type { Section3D, Position3D } from '../../lib/layoutApi';
|
|
|
|
// Convert pixel coordinates to world units
|
|
export const SCALE = 0.1;
|
|
|
|
/**
|
|
* Calculate the world coordinates (x, y, z) for a plant position within a section.
|
|
* This is the SINGLE SOURCE OF TRUTH for plant positioning in 3D space.
|
|
*
|
|
* @param section - The section containing the position
|
|
* @param position - The position within the section (row, column, tier)
|
|
* @param floorCenterX - Half of floor width in world units for centering
|
|
* @param floorCenterZ - Half of floor height in world units for centering
|
|
*/
|
|
export function calculatePlantWorldPosition(
|
|
section: Section3D,
|
|
position: { row: number; column: number; tier: number },
|
|
floorCenterX: number = 0,
|
|
floorCenterZ: number = 0
|
|
): { x: number; y: number; z: number } {
|
|
// Scale section to world units
|
|
const scaledSection = {
|
|
posX: section.posX * SCALE,
|
|
posY: section.posY * SCALE,
|
|
width: section.width * SCALE,
|
|
height: section.height * SCALE,
|
|
};
|
|
|
|
// Calculate grid dimensions from section positions
|
|
const maxCols = Math.max(...section.positions.map(p => p.column), 1);
|
|
const maxRows = Math.max(...section.positions.map(p => p.row), 1);
|
|
|
|
// Calculate spacing to fit plants within section bounds
|
|
const colSpacing = scaledSection.width / (maxCols + 1);
|
|
const rowSpacing = scaledSection.height / (maxRows + 1);
|
|
|
|
// Calculate raw position (before floor centering)
|
|
const rawX = scaledSection.posX + (position.column * colSpacing);
|
|
const rawZ = scaledSection.posY + (position.row * rowSpacing);
|
|
const y = 0.4 + (position.tier * 0.6);
|
|
|
|
// Apply floor centering offset (scene is centered around 0,0)
|
|
const x = rawX - floorCenterX;
|
|
const z = rawZ - floorCenterZ;
|
|
|
|
return { x, y, z };
|
|
}
|
|
|
|
/**
|
|
* Calculate floor center offsets from floor dimensions
|
|
*/
|
|
export function calculateFloorCenter(floorWidth: number, floorHeight: number): { centerX: number; centerZ: number } {
|
|
return {
|
|
centerX: (floorWidth * SCALE) / 2,
|
|
centerZ: (floorHeight * SCALE) / 2,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Find a section within floor data by searching all rooms
|
|
*/
|
|
export function findSectionInFloorData(
|
|
floorData: { rooms: Array<{ sections: Section3D[] }> },
|
|
sectionId: string
|
|
): Section3D | undefined {
|
|
for (const room of floorData.rooms) {
|
|
const section = room.sections.find(s => s.id === sectionId);
|
|
if (section) return section;
|
|
}
|
|
return undefined;
|
|
}
|