Zwischenstand gesichert bei den voxel poxoxeln
This commit is contained in:
@@ -2133,6 +2133,11 @@ public class VoxelEditorState extends BaseAppState {
|
||||
|
||||
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()) {
|
||||
long hk0 = entry.getKey();
|
||||
float h0raw = entry.getValue();
|
||||
@@ -2140,16 +2145,10 @@ public class VoxelEditorState extends BaseAppState {
|
||||
int colX2b = (int)(hk0 / 60001L) - 30000;
|
||||
int colZ2b = (int)(hk0 % 60001L) - 30000;
|
||||
|
||||
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 minRampH = h0sm;
|
||||
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++) {
|
||||
float maxThAtR = Float.NEGATIVE_INFINITY;
|
||||
float maxThAboveAtR = Float.NEGATIVE_INFINITY;
|
||||
@@ -2188,7 +2187,6 @@ public class VoxelEditorState extends BaseAppState {
|
||||
minRampH = candidate;
|
||||
}
|
||||
}
|
||||
// Aufwärts-Kandidat: gleiche Formel wie Abwärts (symmetrisch)
|
||||
if (maxThAboveAtR > Float.NEGATIVE_INFINITY) {
|
||||
float raiseCandidate = maxThAboveAtR + (r - 1) / RAMP_RATIO;
|
||||
if (raiseCandidate < minRaiseH) {
|
||||
@@ -2196,7 +2194,6 @@ public class VoxelEditorState extends BaseAppState {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Diagnose
|
||||
if (log.isTraceEnabled() && passA_maxThAbove > Float.NEGATIVE_INFINITY
|
||||
&& minRampH >= h0sm) {
|
||||
if (minRaiseH < Float.POSITIVE_INFINITY) {
|
||||
@@ -2205,61 +2202,17 @@ public class VoxelEditorState extends BaseAppState {
|
||||
colX2b, colZ2b, h0sm, minRaiseH, passA_maxThAbove));
|
||||
} else {
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
// ── Pass B: Voxel-zu-Voxel ────────────────────────────────────────
|
||||
// Nur Terrassen-Zellen (h0raw ≤ 4.25m) – Bergterrain wird nicht angefasst.
|
||||
// Pass B als if-Block (kein continue): smoothMap.put() am Ende bleibt für
|
||||
// Pass-A-Ergebnisse aller Zellen erreichbar.
|
||||
// Cascade-Schutz: alle Vergleiche ausschließlich mit RAW-Höhen (hN, h0raw),
|
||||
// nie mit smoothMap – gerampte Kliffränder behalten raw ihre Originalhöhe
|
||||
// und werden nicht fälschlicherweise als niedrigere Nachbarn erkannt.
|
||||
if (h0raw <= 4.25f) {
|
||||
boolean hadAnyLower = false;
|
||||
boolean hadNonVoxelR1R3 = false;
|
||||
voxelPassB:
|
||||
for (int r = 1; r <= MAX_RAMP_R; r++) {
|
||||
for (int dz2b = -r; dz2b <= r; dz2b++) {
|
||||
for (int dx2b = -r; dx2b <= r; dx2b++) {
|
||||
if (Math.max(Math.abs(dx2b), Math.abs(dz2b)) != r) continue;
|
||||
long hkN = (long)(colX2b + dx2b + 30000) * 60001L
|
||||
+ (colZ2b + dz2b + 30000);
|
||||
Float hN = hfMap.get(hkN);
|
||||
if (hN == null) {
|
||||
if (r <= 3) { hadNonVoxelR1R3 = true; }
|
||||
continue;
|
||||
}
|
||||
if (hN >= h0raw) continue;
|
||||
if ((h0raw - hN) >= MAX_VOXEL_DIFF) continue;
|
||||
hadAnyLower = true;
|
||||
if ((h0raw - hN) > (float) r) continue;
|
||||
float candidate = hN + r / RAMP_RATIO;
|
||||
if (candidate < minRampH) {
|
||||
minRampH = candidate;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Nach Ring-3: kein gültiger niedrigerer Voxel + kein Terrain → Plateau-Innenzelle
|
||||
if (r == 3 && !hadAnyLower && !hadNonVoxelR1R3) {
|
||||
break voxelPassB;
|
||||
}
|
||||
if (hadAnyLower) {
|
||||
break voxelPassB;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (minRampH < h0sm) {
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace(String.format("Schritt2b (%d,%d) h=%.2f → %.2f",
|
||||
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) {
|
||||
// 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));
|
||||
@@ -2267,6 +2220,61 @@ public class VoxelEditorState extends BaseAppState {
|
||||
smoothMap.put(hk0, minRaiseH);
|
||||
}
|
||||
}
|
||||
|
||||
// ── Loop 2: Pass B – Voxel-zu-Voxel ─────────────────────────────────
|
||||
// Liest smoothMap aus Loop 1 → RAISE-Zellen haben ihre angehobene Höhe.
|
||||
// Effektive Nachbarhöhe: max(raw, smooth).
|
||||
// RAISE-Nachbar (smooth > raw): smooth gewinnt → kein Kandidat unter Terrain.
|
||||
// LOWER-Nachbar (smooth < raw): raw gewinnt → Kaskaden-Schutz bleibt.
|
||||
for (Map.Entry<Long, Float> entry : hfMap.entrySet()) {
|
||||
long hk0 = entry.getKey();
|
||||
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 hadNonVoxelR1R3 = false;
|
||||
voxelPassB:
|
||||
for (int r = 1; r <= MAX_RAMP_R; r++) {
|
||||
for (int dz2b = -r; dz2b <= r; dz2b++) {
|
||||
for (int dx2b = -r; dx2b <= r; dx2b++) {
|
||||
if (Math.max(Math.abs(dx2b), Math.abs(dz2b)) != r) continue;
|
||||
long hkN = (long)(colX2b + dx2b + 30000) * 60001L
|
||||
+ (colZ2b + dz2b + 30000);
|
||||
Float hNraw = hfMap.get(hkN);
|
||||
if (hNraw == null) {
|
||||
if (r <= 3) { hadNonVoxelR1R3 = true; }
|
||||
continue;
|
||||
}
|
||||
float hN = Math.max(hNraw, smoothMap.getOrDefault(hkN, hNraw));
|
||||
if (hN >= h0raw) continue;
|
||||
if ((h0raw - hN) >= MAX_VOXEL_DIFF) continue;
|
||||
hadAnyLower = true;
|
||||
if ((h0raw - hN) > (float) r) continue;
|
||||
float candidate = hN + r / RAMP_RATIO;
|
||||
if (candidate < minRampH) {
|
||||
minRampH = candidate;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (r == 3 && !hadAnyLower && !hadNonVoxelR1R3) {
|
||||
break voxelPassB;
|
||||
}
|
||||
if (hadAnyLower) {
|
||||
break voxelPassB;
|
||||
}
|
||||
}
|
||||
if (minRampH < h0sm) {
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace(String.format("Schritt2b-B (%d,%d) h=%.2f → %.2f",
|
||||
colX2b, colZ2b, h0sm, minRampH));
|
||||
}
|
||||
smoothMap.put(hk0, minRampH);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Schritt 3: Dichte anpassen ────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user