test(world): ersetzte Grundrisse und feste Materialien je Ort strenger prüfen
Behebt Befunde 2-6 aus dem Abschluss-Review: der replaces-Test prüft jetzt zusätzlich jede Ecke des getroffenen Grundrisses gegen die Außenmaße plus REPLACED_OVERHANG (5 m), der Verteilungstest vergleicht als Mengen und bekommt eine Gegenrichtung je Datei, BUMP_BY_PLACE erzwingt eine Zeile je Ort statt sie mit "?? []" zu verdecken, ein Gebäude an einer Chunkgrenze bekommt einen Test über zwei Chunks samt JSDoc-Hinweis, und der Rückwand-Messwert in der Spec nennt Kapselmitte, Wandfläche und Radius einzeln. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
14fd9cefde
commit
237a4ed389
5 files changed
+59
-12
No files matched your search
@@ -9,6 +9,9 @@ import { withoutReplacedBuildings } from "../src/world/streaming.js";
|
||||
const CHUNK_LOAD_RADIUS = 400;
|
||||
const CHUNK_UNLOAD_RADIUS = 600;
|
||||
const STEP = 0.5; // Meter zwischen zwei Prüfpunkten auf der Ortsfläche
|
||||
// Wie weit darf ein ersetzter Grundriss über die Außenmaße seines Orts hinausragen? Die Tribüne liegt
|
||||
// heute 3,78 m vor der Rückseite ihres alten Kastens, Modell-z −18,60 gegen −14,82.
|
||||
const REPLACED_OVERHANG = 5; // Meter
|
||||
|
||||
const cache = new Map();
|
||||
function chunk(i, j) {
|
||||
@@ -44,10 +47,10 @@ function worldToModel(place, X, Y) {
|
||||
return { x: dx * cos - dz * sin, z: dx * sin + dz * cos };
|
||||
}
|
||||
|
||||
function insideBounds(place, X, Y) {
|
||||
function insideBounds(place, X, Y, margin = 0) {
|
||||
const { x, z } = worldToModel(place, X, Y);
|
||||
const { minX, maxX, minZ, maxZ } = place.bounds;
|
||||
return x >= minX && x <= maxX && z >= minZ && z <= maxZ;
|
||||
return x >= minX - margin && x <= maxX + margin && z >= minZ - margin && z <= maxZ + margin;
|
||||
}
|
||||
|
||||
describe.each(PLACES.map((place) => [place.id, place]))("Ort %s auf der Karte", (_id, place) => {
|
||||
@@ -76,14 +79,18 @@ describe.each(PLACES.map((place) => [place.id, place]))("Ort %s auf der Karte",
|
||||
expect(bad.slice(0, 5)).toEqual([]);
|
||||
});
|
||||
|
||||
// Bruch: Nach einem neuen Lauf der Extraktion liegt das ersetzte Gebäude woanders oder ist geteilt. Der
|
||||
// Punkt träfe dann nichts (der alte Kasten stünde wieder im Ort), mehrere Grundrisse oder einen außerhalb.
|
||||
// Bruch: Nach einem neuen Lauf der Extraktion liegt das ersetzte Gebäude woanders oder ist geteilt, oder
|
||||
// der Punkt trifft ein fremdes oder mit einem Nachbarn zusammengelegtes Gebäude. Der Punkt träfe dann
|
||||
// nichts (der alte Kasten stünde wieder im Ort), mehrere Grundrisse, einen außerhalb, oder einen mit
|
||||
// Ecken weit jenseits der Außenmaße.
|
||||
it.runIf((place.replaces ?? []).length > 0)("ersetzt mit jedem replaces-Punkt genau ein Gebäude unter sich", () => {
|
||||
const bad = place.replaces.filter(([X, Y]) => {
|
||||
const { i, j } = chunkForWorld(X, Y);
|
||||
const c = chunk(i, j);
|
||||
const hits = c.buildings.filter((building) => pointInPolygon(X - c.origin[0], -Y - c.origin[1], building.poly));
|
||||
return hits.length !== 1 || !insideBounds(place, X, Y);
|
||||
if (hits.length !== 1 || !insideBounds(place, X, Y)) return true;
|
||||
const corners = hits[0].poly.flat(1);
|
||||
return corners.some(([u, v]) => !insideBounds(place, c.origin[0] + u, -(c.origin[1] + v), REPLACED_OVERHANG));
|
||||
});
|
||||
expect(bad).toEqual([]);
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user