Added: Initial world generation tool

This commit is contained in:
Rainer Leit
2026-09-17 17:55:48 +03:00
parent d64748f76f
commit cc43ed8dc8
2065 changed files with 23664 additions and 1011 deletions
@@ -0,0 +1,50 @@
package fluvial
import (
"math"
"testing"
)
// TestClampToReposeCutsACone is the smallest possible check on the constraint: a cone far steeper than the
// repose angle must come back at or under it.
func TestClampToReposeCutsACone(t *testing.T) {
const (
w, h = 81, 81
cellM = 10.0
talus = 0.4 // about 22 degrees
)
base := make([]bool, w*h)
field := make([]float32, w*h)
for y := 0; y < h; y++ {
for x := 0; x < w; x++ {
d := math.Hypot(float64(x-w/2), float64(y-h/2)) * cellM
field[y*w+x] = float32(math.Max(0, 800-2.0*d)) // slope 2.0, five times repose
}
}
g := NewGrid(w, h, cellM, base)
g.SetElevationRange(-100, 2000)
removed := g.ClampToRepose(field, talus)
worst := 0.0
for y := 0; y < h; y++ {
for x := 0; x < w; x++ {
for k := 0; k < 8; k++ {
nx, ny := x+dx8[k], y+dy8[k]
if nx < 0 || ny < 0 || nx >= w || ny >= h {
continue
}
d := cellM
if dx8[k] != 0 && dy8[k] != 0 {
d = cellM * math.Sqrt2
}
if s := float64(field[y*w+x]-field[ny*w+nx]) / d; s > worst {
worst = s
}
}
}
}
t.Logf("removed %.2f m mean; steepest slope now %.3f (repose %.3f)", removed, worst, talus)
if worst > talus*1.02 {
t.Errorf("steepest slope %.3f exceeds repose %.3f", worst, talus)
}
}