RobotHub-Frontend / src /lib /utils /positionManager.ts
blanchon's picture
Update
6ce4ca6
import type { Position3D } from './positionUtils';
/**
* Spiral-based position manager
* Assigns positions in a spiral pattern starting from center to avoid overlapping objects
*
* Pattern: Center -> Right -> Up -> Left -> Down -> Right (outward spiral)
* Example positions: (0,0) -> (1,0) -> (1,-1) -> (0,-1) -> (-1,-1) -> (-1,0) -> (-1,1) -> (0,1) -> (1,1) -> (2,1) ...
*/
export class PositionManager {
private static instance: PositionManager;
private gridSize = 5; // Distance between grid points
private spiralGenerator: Generator<{ x: number; z: number }, never, unknown>;
static getInstance(): PositionManager {
if (!PositionManager.instance) {
PositionManager.instance = new PositionManager();
}
return PositionManager.instance;
}
constructor() {
this.spiralGenerator = this.generateSpiralPositions();
// Skip the center position since there's already an object there
this.spiralGenerator.next();
}
/**
* Get next available position in a spiral pattern
* Starts from center (0,0) and spirals outward
*/
getNextPosition(): Position3D {
const { value: coord } = this.spiralGenerator.next();
return {
x: coord.x * this.gridSize,
y: 0,
z: coord.z * this.gridSize
};
}
/**
* Generator function that yields spiral positions infinitely
* Uses a simple clockwise spiral starting from origin
*/
private *generateSpiralPositions(): Generator<{ x: number; z: number }, never, unknown> {
let x = 0, z = 0;
let dx = 1, dz = 0; // Start moving right
let steps = 1;
let stepCount = 0;
let changeDirection = 0;
// Yield center position first
yield { x, z };
// Generate spiral positions infinitely
while (true) {
x += dx;
z += dz;
yield { x, z };
stepCount++;
// Change direction when we've completed the required steps
if (stepCount === steps) {
stepCount = 0;
changeDirection++;
// Rotate 90 degrees clockwise: (dx, dz) -> (dz, -dx)
const temp = dx;
dx = dz;
dz = -temp;
// Increase step count after every two direction changes
if (changeDirection % 2 === 0) {
steps++;
}
}
}
}
/**
* Reset position generator (useful for testing)
*/
reset(): void {
this.spiralGenerator = this.generateSpiralPositions();
// Skip the center position since there's already an object there
this.spiralGenerator.next();
}
}
// Global instance
export const positionManager = PositionManager.getInstance();