Zwischenstand gesichert bei den voxel poxoxeln

This commit is contained in:
2026-08-09 22:02:00 +02:00
parent 00a7ccbe47
commit 46be9ffe57
6 changed files with 65 additions and 57 deletions

View File

@@ -2133,6 +2133,11 @@ public class VoxelEditorState extends BaseAppState {
Map<Long, Float> terrainCache2b = new HashMap<>(); Map<Long, Float> terrainCache2b = new HashMap<>();
// ── Loop 1: Pass A Basisterrain (LOWER + RAISE) ───────────────────
// Muss als eigenständiger Loop VOR Pass B laufen: Pass B liest smoothMap
// der Nachbarn. Wären beide Passes im selben Loop, sähe Pass B manchmal
// noch den vergrabenen h0raw einer Nachbarzelle, die von PassA-RAISE noch
// nicht angehoben wurde (HashMap-Reihenfolge unbestimmt) → Graben.
for (Map.Entry<Long, Float> entry : hfMap.entrySet()) { for (Map.Entry<Long, Float> entry : hfMap.entrySet()) {
long hk0 = entry.getKey(); long hk0 = entry.getKey();
float h0raw = entry.getValue(); float h0raw = entry.getValue();
@@ -2141,15 +2146,9 @@ public class VoxelEditorState extends BaseAppState {
int colZ2b = (int)(hk0 % 60001L) - 30000; int colZ2b = (int)(hk0 % 60001L) - 30000;
float minRampH = h0sm; float minRampH = h0sm;
// Terrain ÜBER dem Voxel: Voxel nach oben auf Terrain-Niveau heben.
// Kein +0.1f-Offset an Ring-1 → Ring-1-Oberfläche liegt exakt auf Terrain
// (nahtloser Übergang). Innere Ringe steigen per 4:1-Rampe weiter an.
float minRaiseH = Float.POSITIVE_INFINITY; float minRaiseH = Float.POSITIVE_INFINITY;
float passA_maxThAbove = Float.NEGATIVE_INFINITY;
// ── Pass A: Basisterrain ──────────────────────────────────────────
// Pro Ring: höchstes qualifizierendes th (maxThAtR) → Abwärts-Kandidat.
// Gegenfall: Terrain ÜBER h0sm (maxThAboveAtR) → Aufwärts-Kandidat.
float passA_maxThAbove = Float.NEGATIVE_INFINITY; // Terrain ÜBER h0sm (r=1, Diagnose)
for (int r = 1; r <= MAX_RAMP_R_TERRAIN; r++) { for (int r = 1; r <= MAX_RAMP_R_TERRAIN; r++) {
float maxThAtR = Float.NEGATIVE_INFINITY; float maxThAtR = Float.NEGATIVE_INFINITY;
float maxThAboveAtR = Float.NEGATIVE_INFINITY; float maxThAboveAtR = Float.NEGATIVE_INFINITY;
@@ -2188,7 +2187,6 @@ public class VoxelEditorState extends BaseAppState {
minRampH = candidate; minRampH = candidate;
} }
} }
// Aufwärts-Kandidat: gleiche Formel wie Abwärts (symmetrisch)
if (maxThAboveAtR > Float.NEGATIVE_INFINITY) { if (maxThAboveAtR > Float.NEGATIVE_INFINITY) {
float raiseCandidate = maxThAboveAtR + (r - 1) / RAMP_RATIO; float raiseCandidate = maxThAboveAtR + (r - 1) / RAMP_RATIO;
if (raiseCandidate < minRaiseH) { if (raiseCandidate < minRaiseH) {
@@ -2196,7 +2194,6 @@ public class VoxelEditorState extends BaseAppState {
} }
} }
} }
// Diagnose
if (log.isTraceEnabled() && passA_maxThAbove > Float.NEGATIVE_INFINITY if (log.isTraceEnabled() && passA_maxThAbove > Float.NEGATIVE_INFINITY
&& minRampH >= h0sm) { && minRampH >= h0sm) {
if (minRaiseH < Float.POSITIVE_INFINITY) { if (minRaiseH < Float.POSITIVE_INFINITY) {
@@ -2205,19 +2202,39 @@ public class VoxelEditorState extends BaseAppState {
colX2b, colZ2b, h0sm, minRaiseH, passA_maxThAbove)); colX2b, colZ2b, h0sm, minRaiseH, passA_maxThAbove));
} else { } else {
log.trace(String.format( log.trace(String.format(
"PassA-UNTEN (%d,%d) h0sm=%.3f h0raw=%.3f terrainR1=%.3f Terrain zu weit oben (>MAX_TERRAIN_DIFF), kein Kandidat", "PassA-UNTEN (%d,%d) h0sm=%.3f h0raw=%.3f terrainR1=%.3f",
colX2b, colZ2b, h0sm, h0raw, passA_maxThAbove)); colX2b, colZ2b, h0sm, h0raw, passA_maxThAbove));
} }
} }
if (minRampH < h0sm) {
if (log.isTraceEnabled()) {
log.trace(String.format("Schritt2b-A (%d,%d) h=%.2f → %.2f",
colX2b, colZ2b, h0sm, minRampH));
}
smoothMap.put(hk0, minRampH);
} else if (minRaiseH > h0sm && minRaiseH < Float.POSITIVE_INFINITY) {
if (log.isTraceEnabled()) {
log.trace(String.format("Schritt2b-RAISE (%d,%d) h=%.2f → %.2f",
colX2b, colZ2b, h0sm, minRaiseH));
}
smoothMap.put(hk0, minRaiseH);
}
}
// ── Pass B: Voxel-zu-Voxel ──────────────────────────────────────── // ── Loop 2: Pass B Voxel-zu-Voxel ─────────────────────────────────
// Nur Terrassen-Zellen (h0raw ≤ 4.25m) Bergterrain wird nicht angefasst. // Liest smoothMap aus Loop 1 → RAISE-Zellen haben ihre angehobene Höhe.
// Pass B als if-Block (kein continue): smoothMap.put() am Ende bleibt für // Effektive Nachbarhöhe: max(raw, smooth).
// Pass-A-Ergebnisse aller Zellen erreichbar. // RAISE-Nachbar (smooth > raw): smooth gewinnt → kein Kandidat unter Terrain.
// Cascade-Schutz: alle Vergleiche ausschließlich mit RAW-Höhen (hN, h0raw), // LOWER-Nachbar (smooth < raw): raw gewinnt → Kaskaden-Schutz bleibt.
// nie mit smoothMap gerampte Kliffränder behalten raw ihre Originalhöhe for (Map.Entry<Long, Float> entry : hfMap.entrySet()) {
// und werden nicht fälschlicherweise als niedrigere Nachbarn erkannt. long hk0 = entry.getKey();
if (h0raw <= 4.25f) { float h0raw = entry.getValue();
if (h0raw > 4.25f) continue;
float h0sm = smoothMap.getOrDefault(hk0, h0raw);
int colX2b = (int)(hk0 / 60001L) - 30000;
int colZ2b = (int)(hk0 % 60001L) - 30000;
float minRampH = h0sm;
boolean hadAnyLower = false; boolean hadAnyLower = false;
boolean hadNonVoxelR1R3 = false; boolean hadNonVoxelR1R3 = false;
voxelPassB: voxelPassB:
@@ -2227,11 +2244,12 @@ public class VoxelEditorState extends BaseAppState {
if (Math.max(Math.abs(dx2b), Math.abs(dz2b)) != r) continue; if (Math.max(Math.abs(dx2b), Math.abs(dz2b)) != r) continue;
long hkN = (long)(colX2b + dx2b + 30000) * 60001L long hkN = (long)(colX2b + dx2b + 30000) * 60001L
+ (colZ2b + dz2b + 30000); + (colZ2b + dz2b + 30000);
Float hN = hfMap.get(hkN); Float hNraw = hfMap.get(hkN);
if (hN == null) { if (hNraw == null) {
if (r <= 3) { hadNonVoxelR1R3 = true; } if (r <= 3) { hadNonVoxelR1R3 = true; }
continue; continue;
} }
float hN = Math.max(hNraw, smoothMap.getOrDefault(hkN, hNraw));
if (hN >= h0raw) continue; if (hN >= h0raw) continue;
if ((h0raw - hN) >= MAX_VOXEL_DIFF) continue; if ((h0raw - hN) >= MAX_VOXEL_DIFF) continue;
hadAnyLower = true; hadAnyLower = true;
@@ -2242,7 +2260,6 @@ public class VoxelEditorState extends BaseAppState {
} }
} }
} }
// Nach Ring-3: kein gültiger niedrigerer Voxel + kein Terrain → Plateau-Innenzelle
if (r == 3 && !hadAnyLower && !hadNonVoxelR1R3) { if (r == 3 && !hadAnyLower && !hadNonVoxelR1R3) {
break voxelPassB; break voxelPassB;
} }
@@ -2250,21 +2267,12 @@ public class VoxelEditorState extends BaseAppState {
break voxelPassB; break voxelPassB;
} }
} }
}
if (minRampH < h0sm) { if (minRampH < h0sm) {
if (log.isTraceEnabled()) { if (log.isTraceEnabled()) {
log.trace(String.format("Schritt2b (%d,%d) h=%.2f → %.2f", log.trace(String.format("Schritt2b-B (%d,%d) h=%.2f → %.2f",
colX2b, colZ2b, h0sm, minRampH)); colX2b, colZ2b, h0sm, minRampH));
} }
smoothMap.put(hk0, minRampH); smoothMap.put(hk0, minRampH);
} else if (minRaiseH > h0sm && minRaiseH < Float.POSITIVE_INFINITY) {
// Voxel lag unter dem Terrain → auf Terrain-Niveau anheben
if (log.isTraceEnabled()) {
log.trace(String.format("Schritt2b-RAISE (%d,%d) h=%.2f → %.2f",
colX2b, colZ2b, h0sm, minRaiseH));
}
smoothMap.put(hk0, minRaiseH);
} }
} }
} }

Binary file not shown.