diff --git a/backend/models/associations.js b/backend/models/associations.js
index 350d460..9b7859d 100644
--- a/backend/models/associations.js
+++ b/backend/models/associations.js
@@ -107,6 +107,7 @@ import TaxiLevelStats from './taxi/taxiLevelStats.js';
import TaxiMapType from './taxi/taxiMapType.js';
import TaxiMap from './taxi/taxiMap.js';
import TaxiMapTile from './taxi/taxiMapTile.js';
+import TaxiMapTileHouse from './taxi/taxiMapTileHouse.js';
import TaxiStreetName from './taxi/taxiStreetName.js';
import TaxiMapTileStreet from './taxi/taxiMapTileStreet.js';
@@ -815,4 +816,8 @@ export default function setupAssociations() {
TaxiMapTileStreet.belongsTo(TaxiStreetName, { foreignKey: 'street_name_h_id', as: 'streetNameH' });
TaxiMapTileStreet.belongsTo(TaxiStreetName, { foreignKey: 'street_name_v_id', as: 'streetNameV' });
+
+ // Houses per tile (one row per corner)
+ TaxiMap.hasMany(TaxiMapTileHouse, { foreignKey: 'map_id', as: 'tileHouses' });
+ TaxiMapTileHouse.belongsTo(TaxiMap, { foreignKey: 'map_id', as: 'map' });
}
diff --git a/backend/models/index.js b/backend/models/index.js
index 3db1b1f..bf3710b 100644
--- a/backend/models/index.js
+++ b/backend/models/index.js
@@ -96,7 +96,7 @@ import Match3UserProgress from './match3/userProgress.js';
import Match3UserLevelProgress from './match3/userLevelProgress.js';
// — Taxi Minigame —
-import { TaxiGameState, TaxiLevelStats, TaxiMapType, TaxiMap, TaxiMapTile, TaxiStreetName, TaxiMapTileStreet } from './taxi/index.js';
+import { TaxiGameState, TaxiLevelStats, TaxiMapType, TaxiMap, TaxiMapTile, TaxiStreetName, TaxiMapTileStreet, TaxiMapTileHouse } from './taxi/index.js';
// — Politische Ämter (Politics) —
import PoliticalOfficeType from './falukant/type/political_office_type.js';
@@ -242,6 +242,7 @@ const models = {
TaxiMapTile,
TaxiStreetName,
TaxiMapTileStreet,
+ TaxiMapTileHouse,
};
export default models;
diff --git a/backend/models/taxi/index.js b/backend/models/taxi/index.js
index a846b52..5fddefb 100644
--- a/backend/models/taxi/index.js
+++ b/backend/models/taxi/index.js
@@ -5,5 +5,6 @@ import TaxiMap from './taxiMap.js';
import TaxiMapTile from './taxiMapTile.js';
import TaxiStreetName from './taxiStreetName.js';
import TaxiMapTileStreet from './taxiMapTileStreet.js';
+import TaxiMapTileHouse from './taxiMapTileHouse.js';
-export { TaxiGameState, TaxiLevelStats, TaxiMapType, TaxiMap, TaxiMapTile, TaxiStreetName, TaxiMapTileStreet };
+export { TaxiGameState, TaxiLevelStats, TaxiMapType, TaxiMap, TaxiMapTile, TaxiStreetName, TaxiMapTileStreet, TaxiMapTileHouse };
diff --git a/backend/models/taxi/taxiMapTileHouse.js b/backend/models/taxi/taxiMapTileHouse.js
new file mode 100644
index 0000000..12adb2a
--- /dev/null
+++ b/backend/models/taxi/taxiMapTileHouse.js
@@ -0,0 +1,56 @@
+import { DataTypes } from 'sequelize';
+import { sequelize } from '../../utils/sequelize.js';
+
+const TaxiMapTileHouse = sequelize.define('TaxiMapTileHouse', {
+ id: {
+ type: DataTypes.INTEGER,
+ primaryKey: true,
+ autoIncrement: true
+ },
+ mapId: {
+ type: DataTypes.INTEGER,
+ allowNull: false,
+ },
+ x: {
+ type: DataTypes.INTEGER,
+ allowNull: false,
+ comment: 'X-coordinate of the tile within the map'
+ },
+ y: {
+ type: DataTypes.INTEGER,
+ allowNull: false,
+ comment: 'Y-coordinate of the tile within the map'
+ },
+ corner: {
+ type: DataTypes.ENUM('lo', 'ro', 'lu', 'ru'),
+ allowNull: false,
+ comment: 'Corner position: lo, ro, lu, ru'
+ },
+ rotation: {
+ type: DataTypes.INTEGER,
+ allowNull: false,
+ defaultValue: 0,
+ comment: 'Rotation in degrees: 0, 90, 180, 270'
+ }
+}, {
+ tableName: 'taxi_map_tile_house',
+ schema: 'taxi',
+ timestamps: true,
+ underscored: true,
+ indexes: [
+ {
+ unique: true,
+ fields: ['map_id', 'x', 'y', 'corner']
+ },
+ {
+ fields: ['map_id']
+ },
+ {
+ fields: ['x', 'y']
+ }
+ ]
+});
+
+export default TaxiMapTileHouse;
+
+
diff --git a/backend/services/taxiMapService.js b/backend/services/taxiMapService.js
index 32851e1..dc38bb7 100644
--- a/backend/services/taxiMapService.js
+++ b/backend/services/taxiMapService.js
@@ -4,6 +4,7 @@ import TaxiMapType from '../models/taxi/taxiMapType.js';
import TaxiMapTile from '../models/taxi/taxiMapTile.js';
import TaxiStreetName from '../models/taxi/taxiStreetName.js';
import TaxiMapTileStreet from '../models/taxi/taxiMapTileStreet.js';
+import TaxiMapTileHouse from '../models/taxi/taxiMapTileHouse.js';
class TaxiMapService extends BaseService {
constructor() {
@@ -43,7 +44,8 @@ class TaxiMapService extends BaseService {
{ model: TaxiStreetName, as: 'streetNameH' },
{ model: TaxiStreetName, as: 'streetNameV' }
]
- }
+ },
+ { model: TaxiMapTileHouse, as: 'tileHouses' }
],
order: [['name', 'ASC']]
});
@@ -74,7 +76,8 @@ class TaxiMapService extends BaseService {
{ model: TaxiStreetName, as: 'streetNameH' },
{ model: TaxiStreetName, as: 'streetNameV' }
]
- }
+ },
+ { model: TaxiMapTileHouse, as: 'tileHouses' }
]
});
return map;
@@ -112,7 +115,7 @@ class TaxiMapService extends BaseService {
*/
async createMap(mapData) {
try {
- const { tiles, tileStreetNames, ...mapFields } = mapData;
+ const { tiles, tileStreetNames, tileHouses, ...mapFields } = mapData;
// mapData JSON ist entfernt – map erstellen ohne mapData
const map = await TaxiMap.create(mapFields);
// Tiles upsert (optional)
@@ -123,6 +126,9 @@ class TaxiMapService extends BaseService {
if (tileStreetNames && Object.keys(tileStreetNames).length > 0) {
await this.upsertTileStreetNames(map.id, tileStreetNames);
}
+ if (tileHouses && Object.keys(tileHouses).length > 0) {
+ await this.upsertTileHouses(map.id, tileHouses);
+ }
return await this.getMapById(map.id);
} catch (error) {
console.error('Error creating map:', error);
@@ -135,7 +141,7 @@ class TaxiMapService extends BaseService {
*/
async updateMap(mapId, updateData) {
try {
- const { tiles, tileStreetNames, ...mapFields } = updateData;
+ const { tiles, tileStreetNames, tileHouses, ...mapFields } = updateData;
const [updatedRowsCount] = await TaxiMap.update(mapFields, {
where: { id: mapId }
});
@@ -151,6 +157,9 @@ class TaxiMapService extends BaseService {
if (tileStreetNames && Object.keys(tileStreetNames).length > 0) {
await this.upsertTileStreetNames(mapId, tileStreetNames);
}
+ if (tileHouses && Object.keys(tileHouses).length > 0) {
+ await this.upsertTileHouses(mapId, tileHouses);
+ }
return await this.getMapById(mapId);
} catch (error) {
console.error('Error updating map:', error);
@@ -205,6 +214,24 @@ class TaxiMapService extends BaseService {
return { success: true };
}
+ /**
+ * Speichert Häuser pro Tile (je Ecke eine Zeile)
+ * @param {number} mapId
+ * @param {{[cellKey:string]: {[corner:string]: number}}} tileHouses
+ */
+ async upsertTileHouses(mapId, tileHouses) {
+ // Löschen und neu anlegen pro Zelle ist am einfachsten und robust
+ const entries = Object.entries(tileHouses || {});
+ for (const [cellKey, cornerMap] of entries) {
+ const [x, y] = cellKey.split(',').map(Number);
+ await TaxiMapTileHouse.destroy({ where: { map_id: mapId, x, y } });
+ for (const [corner, rotation] of Object.entries(cornerMap || {})) {
+ await TaxiMapTileHouse.create({ mapId, x, y, corner, rotation: Number(rotation) || 0 });
+ }
+ }
+ return { success: true };
+ }
+
/**
* Löscht eine Map (soft delete)
*/
diff --git a/backend/utils/initializeTaxi.js b/backend/utils/initializeTaxi.js
index 446e4d2..778aaee 100644
--- a/backend/utils/initializeTaxi.js
+++ b/backend/utils/initializeTaxi.js
@@ -17,6 +17,14 @@ const initializeTaxi = async () => {
console.warn('⚠️ Konnte taxi_map_tile nicht synchronisieren:', e?.message || e);
}
+ // Stelle sicher, dass die neue Tabelle taxi_map_tile_house existiert (Häuser je Ecke)
+ try {
+ await (await import('../models/taxi/taxiMapTileHouse.js')).default.sync({ alter: true, force: false });
+ console.log('✅ Tabelle taxi.taxi_map_tile_house ist synchronisiert');
+ } catch (e) {
+ console.warn('⚠️ Konnte taxi_map_tile_house nicht synchronisieren:', e?.message || e);
+ }
+
// Stelle sicher: timestamps-Spalten in taxi_street_name vorhanden (ältere DBs hatten evtl. kein updated_at)
try {
await sequelize.query(`
diff --git a/frontend/src/views/admin/TaxiToolsView.vue b/frontend/src/views/admin/TaxiToolsView.vue
index 2c0d06c..30e642f 100644
--- a/frontend/src/views/admin/TaxiToolsView.vue
+++ b/frontend/src/views/admin/TaxiToolsView.vue
@@ -151,8 +151,18 @@
{{ $t('admin.taxiTools.mapEditor.extraElements') }}
-
@@ -375,7 +385,9 @@ const HOUSE_TYPE_MATRIX = {
fuelvertical: { lo: ['right'], ro: [], lu: ['right'], ru: [] }
};
-const DIRECTION_TO_ROTATION = { bottom: 0, right: 90, top: 180, left: 270 };
+// Canvas-Rotation ist im Browser positiv im Uhrzeigersinn (y-Achse nach unten).
+// Bild zeigt Tür unten (0°). Für "rechts" benötigen wir -90° (= 270°), für "links" +90°.
+const DIRECTION_TO_ROTATION = { bottom: 0, right: 270, top: 180, left: 90 };
export default {
name: 'AdminTaxiToolsView',
@@ -1033,9 +1045,9 @@ export default {
doorClass(deg) {
switch (deg) {
case 0: return 'door-bottom';
- case 90: return 'door-right';
+ case 90: return 'door-left';
case 180: return 'door-top';
- case 270: return 'door-left';
+ case 270: return 'door-right';
default: return 'door-bottom';
}
},
@@ -1146,6 +1158,7 @@ export default {
meta: c.extraHouses ? { houses: { ...c.extraHouses } } : null
}));
const tileStreetNames = this.collectTileStreetNames();
+ const tileHouses = this.collectTileHouses();
const mapData = {
...this.mapForm,
width: this.boardWidth,
@@ -1153,7 +1166,8 @@ export default {
tileSize: 50,
mapTypeId: 1,
tiles,
- tileStreetNames
+ tileStreetNames,
+ tileHouses
};
let savedMap;
@@ -1196,6 +1210,17 @@ export default {
return result;
},
+ collectTileHouses() {
+ const result = {};
+ for (const [key, cell] of Object.entries(this.boardCells)) {
+ if (!cell.tileType) continue;
+ if (cell.extraHouses && Object.keys(cell.extraHouses).length > 0) {
+ result[key] = { ...cell.extraHouses };
+ }
+ }
+ return result;
+ },
+
async deleteMap(mapId) {
if (confirm('Möchtest du diese Map wirklich löschen?')) {
try {
diff --git a/frontend/src/views/minigames/TaxiGame.vue b/frontend/src/views/minigames/TaxiGame.vue
index 4867af4..986e273 100644
--- a/frontend/src/views/minigames/TaxiGame.vue
+++ b/frontend/src/views/minigames/TaxiGame.vue
@@ -235,6 +235,7 @@ export default {
size: 500, // 400x400px pro Tile
images: {}
},
+ houseImage: null,
maps: [], // Geladene Maps aus der Datenbank
currentMap: null, // Aktuell verwendete Map
selectedMapId: null, // ID der ausgewählten Map
@@ -246,6 +247,7 @@ export default {
audioContext: null,
audioUnlockHandler: null,
selectedStreetName: null
+ ,houseNumbers: {}
}
},
computed: {
@@ -285,6 +287,7 @@ export default {
this.initializeMinimap();
this.loadTiles();
this.loadTaxiImage();
+ this.loadHouseImage();
this.loadMaps();
this.setupEventListeners();
await this.initializeMotorSound();
@@ -1116,9 +1119,11 @@ export default {
if (this.tiles.images[tileType]) {
this.ctx.drawImage(this.tiles.images[tileType], 0, 0, tileSize, tileSize);
}
- // Straßennamen auf Haupt-Canvas zeichnen
+ // Häuser zeichnen (aus tileHouses)
const absCol = this.currentTile.col + (this.currentMap.offsetX || 0);
const absRow = this.currentTile.row + (this.currentMap.offsetY || 0);
+ this.drawHousesOnMainCanvas(this.ctx, tileSize, absCol, absRow);
+ // Straßennamen auf Haupt-Canvas zeichnen
this.drawStreetNamesOnMainCanvas(this.ctx, tileSize, tileType, absCol, absRow);
}
}
@@ -1176,6 +1181,55 @@ export default {
drawText(hName, size - fontPx, cy, -Math.PI / 2, sel);
}
},
+ drawHousesOnMainCanvas(ctx, size, col, row) {
+ if (!this.currentMap) return;
+ const houses = Array.isArray(this.currentMap.tileHouses) ? this.currentMap.tileHouses : [];
+ if (!houses.length || !this.houseImage) return;
+ // Finde alle Häuser für diese Zelle
+ const list = houses.filter(h => h.x === col && h.y === row);
+ if (!list.length) return;
+ // Hausgröße 150x150px; an Ecken platzieren mit Abstand 3px
+ const HOUSE_W = 150;
+ const HOUSE_H = 150;
+ const pad = 30;
+ for (const h of list) {
+ const rot = (Number(h.rotation) || 0) % 360;
+ const isPortrait = (rot % 180) !== 0; // 90 oder 270 Grad
+ const w = isPortrait ? HOUSE_H : HOUSE_W;
+ const hgt = isPortrait ? HOUSE_W : HOUSE_H;
+
+ let px = 0, py = 0;
+ switch (h.corner) {
+ case 'lo': px = pad; py = pad; break;
+ case 'ro': px = size - w - pad; py = pad; break;
+ case 'lu': px = pad; py = size - hgt - pad; break;
+ case 'ru': px = size - w - pad; py = size - hgt - pad; break;
+ default: continue;
+ }
+ // Rotation: Bild zeigt Tür unten (0°). 90/180/270 drehen um Zentrum.
+ const cx = px + w / 2;
+ const cy = py + hgt / 2;
+ ctx.save();
+ ctx.translate(cx, cy);
+ const rad = rot * Math.PI / 180;
+ ctx.rotate(rad);
+ ctx.drawImage(this.houseImage, -HOUSE_W/2, -HOUSE_H/2, HOUSE_W, HOUSE_H);
+ // Hausnummer zeichnen (über dem Bild zentriert)
+ const key = `${h.x},${h.y},${h.corner}`;
+ const num = this.houseNumbers[key];
+ if (num != null) {
+ ctx.textAlign = 'center';
+ ctx.textBaseline = 'middle';
+ ctx.font = 'bold 20px sans-serif';
+ ctx.lineWidth = 4;
+ ctx.strokeStyle = 'rgba(255,255,255,0.9)';
+ ctx.strokeText(String(num), 0, 0);
+ ctx.fillStyle = '#000';
+ ctx.fillText(String(num), 0, 0);
+ }
+ ctx.restore();
+ }
+ },
getTileType(row, col, rows, cols) {
// Ecken
@@ -1336,6 +1390,16 @@ export default {
img.src = '/images/taxi/taxi.svg';
// console.log('Lade Taxi-Bild von:', '/images/taxi/taxi.svg');
},
+ loadHouseImage() {
+ const img = new Image();
+ img.onload = () => {
+ this.houseImage = img;
+ };
+ img.onerror = () => {
+ console.warn('Fehler beim Laden von house_small.png');
+ };
+ img.src = '/images/taxi/house_small.png';
+ },
async loadMaps() {
try {
@@ -1352,6 +1416,7 @@ export default {
// Minimap neu zeichnen nach dem Laden der Map
this.$nextTick(() => {
+ this.computeHouseNumbers();
this.drawMinimap();
});
}
@@ -1382,6 +1447,7 @@ export default {
// Minimap neu zeichnen
this.$nextTick(() => {
+ this.computeHouseNumbers();
this.drawMinimap();
});
}
@@ -1542,6 +1608,8 @@ export default {
map.mapData = grid;
map.offsetX = minX;
map.offsetY = minY;
+ // tileHouses vom Backend übernehmen (Array von Zeilen)
+ map.tileHouses = Array.isArray(map.tileHouses) ? map.tileHouses : [];
return map;
},
onSelectStreet(name) {
@@ -1595,6 +1663,92 @@ export default {
}
ctx.restore();
+ },
+ // ---- Hausnummern-Berechnung ----
+ computeHouseNumbers() {
+ this.houseNumbers = {};
+ if (!this.currentMap || !this.currentMap.tileHouses || !this.currentMap.mapData) return;
+ const map = this.currentMap;
+ const offsetX = map.offsetX || 0;
+ const offsetY = map.offsetY || 0;
+ const streetIndex = new Map();
+ const getEntry = (name) => { if (!streetIndex.has(name)) streetIndex.set(name, { tiles: new Map() }); return streetIndex.get(name); };
+ const tileStreets = Array.isArray(map.tileStreets) ? map.tileStreets : [];
+ for (const ts of tileStreets) {
+ const x = ts.x; const y = ts.y; const gridX = x - offsetX; const gridY = y - offsetY;
+ const tileType = (map.mapData[gridY] && map.mapData[gridY][gridX]) || null; if (!tileType) continue;
+ const makeTileObj = (name) => { const key = `${x},${y}`; const e = getEntry(name); const t = e.tiles.get(key) || { x, y, tileType, h: false, v: false }; e.tiles.set(key, t); return t; };
+ if (ts.streetNameH && ts.streetNameH.name) { makeTileObj(ts.streetNameH.name).h = true; }
+ if (ts.streetNameV && ts.streetNameV.name) { makeTileObj(ts.streetNameV.name).v = true; }
+ }
+ const allowedDirections = (tileType) => {
+ switch (tileType) {
+ case 'cornertopleft': return { left: true, up: true, right: false, down: false };
+ case 'cornertopright': return { right: true, up: true, left: false, down: false };
+ case 'cornerbottomleft': return { left: true, down: true, right: false, up: false };
+ case 'cornerbottomright': return { right: true, down: true, left: false, up: false };
+ case 'horizontal':
+ case 'fuelhorizontal': return { left: true, right: true, up: false, down: false };
+ case 'vertical':
+ case 'fuelvertical': return { up: true, down: true, left: false, right: false };
+ case 'cross': return { left: true, right: true, up: true, down: true };
+ case 'tup': return { up: true, left: true, right: true, down: false };
+ case 'tdown': return { down: true, left: true, right: true, up: false };
+ case 'tleft': return { left: true, up: true, down: true, right: false };
+ case 'tright': return { right: true, up: true, down: true, left: false };
+ default: return { left: false, right: false, up: false, down: false };
+ }
+ };
+ const getTile = (entry, x, y) => entry.tiles.get(`${x},${y}`);
+ for (const [name, entry] of streetIndex.entries()) {
+ const nodes = new Map();
+ const addNode = (x, y, axis) => nodes.set(`${x},${y},${axis}`, { x, y, axis });
+ for (const t of entry.tiles.values()) { if (t.h) addNode(t.x, t.y, 'h'); if (t.v) addNode(t.x, t.y, 'v'); }
+ const adj = new Map();
+ const addEdge = (a, b) => { if (!nodes.has(a) || !nodes.has(b)) return; if (!adj.has(a)) adj.set(a, new Set()); if (!adj.has(b)) adj.set(b, new Set()); adj.get(a).add(b); adj.get(b).add(a); };
+ for (const t of entry.tiles.values()) {
+ const dirs = allowedDirections(t.tileType); const keyH = `${t.x},${t.y},h`; const keyV = `${t.x},${t.y},v`;
+ if (t.h) { if (dirs.left) { const n = getTile(entry, t.x - 1, t.y); if (n && n.h && allowedDirections(n.tileType).right) addEdge(keyH, `${n.x},${n.y},h`); } if (dirs.right) { const n = getTile(entry, t.x + 1, t.y); if (n && n.h && allowedDirections(n.tileType).left) addEdge(keyH, `${n.x},${n.y},h`); } }
+ if (t.v) { if (dirs.up) { const n = getTile(entry, t.x, t.y - 1); if (n && n.v && allowedDirections(n.tileType).down) addEdge(keyV, `${n.x},${n.y},v`); } if (dirs.down) { const n = getTile(entry, t.x, t.y + 1); if (n && n.v && allowedDirections(n.tileType).up) addEdge(keyV, `${n.x},${n.y},v`); } }
+ if (t.h && t.v) { addEdge(keyH, keyV); }
+ }
+ if (nodes.size === 0) continue;
+ let startKey = null; for (const k of nodes.keys()) { if ((adj.get(k)?.size || 0) === 1) { startKey = k; break; } } if (!startKey) startKey = Array.from(nodes.keys()).sort()[0];
+ const visited = new Set(); let odd = 1, even = 2; let prev = null; let curr = startKey; let currOddSide = (nodes.get(curr).axis === 'h') ? 'top' : 'left';
+ while (curr) {
+ visited.add(curr);
+ const { x, y, axis } = nodes.get(curr);
+ const neighbors = Array.from(adj.get(curr) || []); const next = neighbors.find(n => !visited.has(n));
+ let dir = { dx: 0, dy: 0 }; if (next) { const nNode = nodes.get(next); dir = { dx: nNode.x - x, dy: nNode.y - y }; } else if (prev) { const pNode = nodes.get(prev); dir = { dx: x - pNode.x, dy: y - pNode.y }; }
+ if (prev) { const prevAxis = nodes.get(prev).axis; if (prevAxis !== axis) { if (prevAxis === 'v' && axis === 'h') currOddSide = 'bottom'; else if (prevAxis === 'h' && axis === 'v') currOddSide = 'left'; } }
+ const houseMap = this.currentMap.tileHouses || []; const housesHere = houseMap.filter(hh => hh.x === x && hh.y === y);
+ if (housesHere.length) {
+ const doorSideFromRotation = (rot) => {
+ const r = ((Number(rot) || 0) % 360 + 360) % 360;
+ if (r === 0) return 'bottom';
+ if (r === 90) return 'left';
+ if (r === 180) return 'top';
+ if (r === 270) return 'right';
+ return 'bottom';
+ };
+ // Nur Häuser berücksichtigen, deren Tür zur aktuellen Straßenachse passt
+ const housesFiltered = housesHere.filter(hh => {
+ const side = doorSideFromRotation(hh.rotation);
+ return axis === 'h' ? (side === 'top' || side === 'bottom') : (side === 'left' || side === 'right');
+ });
+ if (!housesFiltered.length) { prev = curr; curr = next || null; continue; }
+ const orderCorners = (list) => {
+ if (axis === 'h') { const movingRight = dir.dx > 0 || (dir.dx === 0 && !prev); const seq = movingRight ? ['lo','ro','lu','ru'] : ['ro','lo','ru','lu']; return list.slice().sort((a,b)=> seq.indexOf(a) - seq.indexOf(b)); }
+ else { const movingDown = dir.dy > 0 || (dir.dy === 0 && !prev); const seq = movingDown ? ['lo','lu','ro','ru'] : ['lu','lo','ru','ro']; return list.slice().sort((a,b)=> seq.indexOf(a) - seq.indexOf(b)); }
+ };
+ const oddCorners = (axis === 'h') ? (currOddSide === 'top' ? ['lo','ro'] : ['lu','ru']) : (currOddSide === 'left' ? ['lo','lu'] : ['ro','ru']);
+ const evenCorners = (axis === 'h') ? (currOddSide === 'top' ? ['lu','ru'] : ['lo','ro']) : (currOddSide === 'left' ? ['ro','ru'] : ['lo','lu']);
+ for (const c of orderCorners(oddCorners)) { if (housesFiltered.find(hh => hh.corner === c)) { const k = `${x},${y},${c}`; if (this.houseNumbers[k] == null) { this.houseNumbers[k] = odd; odd += 2; } } }
+ for (const c of orderCorners(evenCorners)) { if (housesFiltered.find(hh => hh.corner === c)) { const k = `${x},${y},${c}`; if (this.houseNumbers[k] == null) { this.houseNumbers[k] = even; even += 2; } } }
+ }
+ prev = curr; curr = next || null;
+ }
+ }
}
}
}