Files
UnrealPrototyping/Tools/Terrain/internal/check/margin_test.go
T

97 lines
3.7 KiB
Go

package check
import (
"testing"
"salty/terrain/internal/manifest"
"salty/terrain/internal/uplift"
)
// TestBorderIsAlwaysOcean is the boundary condition the whole solve rests on, asserted rather than assumed.
//
// A cell on the map border is an outlet: `fluvial.isOutlet` returns true for it whatever else is true, so it
// takes no uplift and is never eroded, and the repose clamp will not lower it either. Land that reaches the
// border therefore freezes at whatever the initial relief gave it while the interior erodes away beneath it,
// and what that looks like is a rim of untouched terrain standing a hundred metres over its neighbour — it is
// what once reported a 66 degree slope on a map whose angle of repose was 22. `continentMask` imposes a
// margin to prevent it, and this test is what says the margin is still doing its job.
//
// It is worth a test rather than a comment because the margin is easy to break from a distance. The uplift
// rate used to be multiplied by the continent mask, so the margin's taper was suppressing uplift at the border
// as a side effect; decoupling the two (D-52) removed that, and nothing in the change was anywhere near this
// file. The invariant is the border cells themselves, so that is what is asserted; the distances and rates are
// reported alongside because they are what a person would want to see when it does fail.
func TestBorderIsAlwaysOcean(t *testing.T) {
const size = 1400
const sideM = 14280.0
cell := sideM / (size - 1)
for _, seed := range []int64{7, 9342, 67914} {
m := manifest.Defaults()
m.Source.Seed = seed
up := uplift.Build(size, cell, m)
for x := 0; x < size; x++ {
for _, i := range [2]int{x, (size-1)*size + x} {
if !up.Base[i] {
t.Errorf("seed %d: cell (%d,%d) on the top or bottom border is land", seed, i%size, i/size)
}
}
}
for y := 0; y < size; y++ {
for _, i := range [2]int{y * size, y*size + size - 1} {
if !up.Base[i] {
t.Errorf("seed %d: cell (%d,%d) on the left or right border is land", seed, i%size, i/size)
}
}
}
// How hard the margin is pressing. The margin does not only keep land off the border; where the
// continent would have run past the edge it *cuts* it, and it cuts along a contour of distance-to-edge,
// which is a straight line parallel to that edge. So a coastline inside the margin band is a coastline
// the margin drew rather than one the noise did, and the count is the measure of how much of one there
// is. It is logged, not asserted: some is unavoidable and the right threshold is a judgement.
band := int(0.04 * size)
nearest := size
var peakRate, peakHeight float64
landInBand, shoreInBand, shore := 0, 0, 0
for i := range up.Base {
x, y := i%size, i/size
d := min(min(x, size-1-x), min(y, size-1-y))
if up.Base[i] {
// A waterline cell: ocean with land in the four-neighbourhood.
for _, n := range [4]int{i - 1, i + 1, i - size, i + size} {
if n >= 0 && n < len(up.Base) && !up.Base[n] {
shore++
if d < band {
shoreInBand++
}
break
}
}
continue
}
if d < nearest {
nearest = d
}
if d < band {
landInBand++
if r := float64(up.Rate.Data[i]) * 1000; r > peakRate {
peakRate = r
}
if h := float64(up.Height.Data[i]); h > peakHeight {
peakHeight = h
}
}
}
pct := 0.0
if shore > 0 {
pct = float64(shoreInBand) / float64(shore) * 100
}
t.Logf("seed %6d: nearest land %d cells (%.0f m) from the border; inside the %d-cell margin, "+
"%d land cells, peak uplift %.2f mm/yr, peak initial relief %.0f m; %.1f%% of the shoreline is "+
"inside the margin band (a coast the margin drew, not the noise)",
seed, nearest, float64(nearest)*cell, band, landInBand, peakRate, peakHeight, pct)
}
}