Weltkarte Wald: Outline-Versatz durch Koordinaten-Mismatch behoben
Root cause: Fill nutzt fsfz = (WH-wz)/WS * FD (Skala: /FD=512), MS-Grid nutzt msW → / (fdSize-1)=511. Ergibt ~2m Versatz in Kartenmitte. Fix: h-Feld bei SEA_MASK_SIZE mit exakt der Fill-Formel aufbauen (* FD statt * (FD-1)), dann MS mit thr=0 auf diesem h-Feld. Die Isokontur liegt damit pixelgenau auf der Fill-Grenze. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1126,19 +1126,29 @@ public class WorldMapView extends VBox {
|
||||
|
||||
/** Extrahiert Wald-Konturen aus der Tree-Density-Map als geglättete Weltkoordinaten-Pfade. */
|
||||
private static List<float[][]> buildForestOutlinePaths(float[] density, int fdSize, float threshold) {
|
||||
// Z-Flip: Density mz=0=Nord, MS mz=0=Süd.
|
||||
// h = threshold - density → forest (density > threshold) ergibt h < 0 = "inside" für MS.
|
||||
// MS läuft direkt auf echten Density-Werten mit thr=0 → exakt dieselbe Isokontur wie
|
||||
// die Füllung in computeForestPixels (keine binäre Maske, kein Boundary-Versatz).
|
||||
float[] h = new float[fdSize * fdSize];
|
||||
for (int mz = 0; mz < fdSize; mz++) {
|
||||
int dz = fdSize - 1 - mz;
|
||||
for (int mx = 0; mx < fdSize; mx++) {
|
||||
h[mz * fdSize + mx] = threshold - density[dz * fdSize + mx];
|
||||
// h-Feld mit EXAKT derselben Koordinatenformel wie computeForestPixels aufbauen:
|
||||
// fsfz = (WH - wz) / WS * FD (Fill nutzt * FD=512, nicht * (FD-1)=511!)
|
||||
// Damit liegt die MS-Isokontur (h=0) pixelgenau auf der Fill-Grenze.
|
||||
final int SIZE = SEA_MASK_SIZE;
|
||||
final float WH = WorldMapRenderer.WORLD_HALF, WS = WorldMapRenderer.WORLD_SIZE;
|
||||
float[] h = new float[SIZE * SIZE];
|
||||
for (int py = 0; py < SIZE; py++) {
|
||||
float wz = (float) py / (SIZE - 1) * WS - WH;
|
||||
float fsfz = Math.max(0f, Math.min(fdSize - 1.001f, (WH - wz) / WS * fdSize));
|
||||
int fsz0 = (int) fsfz, fsz1 = Math.min(fsz0 + 1, fdSize - 1);
|
||||
float fstz = fsfz - fsz0;
|
||||
for (int px = 0; px < SIZE; px++) {
|
||||
float wx = (float) px / (SIZE - 1) * WS - WH;
|
||||
float fsfx = Math.max(0f, Math.min(fdSize - 1.001f, (wx + WH) / WS * fdSize));
|
||||
int fsx0 = (int) fsfx, fsx1 = Math.min(fsx0 + 1, fdSize - 1);
|
||||
float fstx = fsfx - fsx0;
|
||||
float d = (density[fsz0 * fdSize + fsx0] * (1 - fstx) + density[fsz0 * fdSize + fsx1] * fstx) * (1 - fstz)
|
||||
+ (density[fsz1 * fdSize + fsx0] * (1 - fstx) + density[fsz1 * fdSize + fsx1] * fstx) * fstz;
|
||||
h[py * SIZE + px] = threshold - d; // <0 = forest (inside), >0 = non-forest
|
||||
}
|
||||
}
|
||||
List<float[]> segs = new ArrayList<>();
|
||||
marchingSquares(h, fdSize, 0f, null, null, segs);
|
||||
marchingSquares(h, SIZE, 0f, null, null, segs);
|
||||
List<float[][]> paths = assembleClosedPaths(segs.toArray(new float[0][]), 0);
|
||||
|
||||
final float MIN_PERIMETER_SQ = 60f * 60f;
|
||||
|
||||
Reference in New Issue
Block a user