50 lines
1.8 KiB
JavaScript
50 lines
1.8 KiB
JavaScript
export const TILE_PX = 256;
|
||
export const WORLD_HALF = 16384; // gtadb-Weltgrenze in Metern
|
||
export const CHUNK_SIZE = 250;
|
||
export const SLICE = { x0: -1000, x1: 2000, y0: -500, y1: 2500 };
|
||
export const CHUNKS_PER_SIDE = (SLICE.x1 - SLICE.x0) / CHUNK_SIZE; // 12
|
||
|
||
export const worldToThree = (X, Y) => ({ x: X, z: -Y });
|
||
export const threeToWorld = (x, z) => ({ X: x, Y: -z });
|
||
|
||
export function tileForWorld(X, Y) {
|
||
return {
|
||
row: Math.floor((WORLD_HALF - Y) / TILE_PX),
|
||
col: Math.floor((X + WORLD_HALF) / TILE_PX),
|
||
};
|
||
}
|
||
|
||
export function chunkForWorld(X, Y) {
|
||
return {
|
||
i: Math.floor((X - SLICE.x0) / CHUNK_SIZE),
|
||
j: Math.floor((SLICE.y1 - Y) / CHUNK_SIZE),
|
||
};
|
||
}
|
||
|
||
/** Nordwest-Ecke eines Chunks in Weltkoordinaten. */
|
||
export function chunkOrigin(i, j) {
|
||
return { X: SLICE.x0 + i * CHUNK_SIZE, Y: SLICE.y1 - j * CHUNK_SIZE };
|
||
}
|
||
|
||
const CHUNK_COLUMNS = "ABCDEFGHIJKL";
|
||
const CHUNK_NAME_PATTERN = /^([A-La-l])([1-9]\d?)$/;
|
||
|
||
/**
|
||
* Planquadrat-Name eines Chunks: Spalte A–L aus i (West → Ost), Zeile 1–12 aus j (Nord → Süd).
|
||
* A1 ist die Nordwest-Ecke, weil chunkOrigin i nach Osten und j von der Nordkante nach Süden zählt.
|
||
* Die Namen sind die Schnittstelle zur Feinkalibrierung: was im Chat "C10" heißt, ist chunk_2_9.
|
||
*/
|
||
export function chunkName(i, j) {
|
||
const inside = (k) => Number.isInteger(k) && k >= 0 && k < CHUNKS_PER_SIDE;
|
||
return inside(i) && inside(j) ? CHUNK_COLUMNS[i] + (j + 1) : null;
|
||
}
|
||
|
||
/** Umkehrung von chunkName. Akzeptiert Kleinschreibung, liefert null für alles außerhalb A1–L12. */
|
||
export function parseChunkName(name) {
|
||
const match = CHUNK_NAME_PATTERN.exec(String(name));
|
||
if (!match) return null;
|
||
const row = Number(match[2]);
|
||
if (row > CHUNKS_PER_SIDE) return null;
|
||
return { i: CHUNK_COLUMNS.indexOf(match[1].toUpperCase()), j: row - 1 };
|
||
}
|