mirror of
https://gitlab.com/gaelysam/mapgen_rivers.git
synced 2024-11-14 23:00:22 +01:00
f0dddee33c
Lake height is calculated for every basin, and there is a lake if lake height is higher than ground height. If it is lower, there is no lake. In that case, it was previously raised to ground level, but since this can be done in Lua, we can write initial lakes height in the files. This has the advantage of reducing file size, since there are bigger areas of equal values, that are more efficiently compressed.
92 lines
3.4 KiB
Python
92 lines
3.4 KiB
Python
import numpy as np
|
|
import scipy.ndimage as im
|
|
from .rivermapper import flow
|
|
|
|
def advection(dem, dirs, rivers, time, K=1, m=0.5, sea_level=0):
|
|
"""
|
|
Simulate erosion by rivers.
|
|
This models erosion as an upstream advection of elevations ("erosion waves").
|
|
Advection speed depends on water flux and parameters:
|
|
|
|
v = K * flux^m
|
|
"""
|
|
|
|
adv_time = 1 / (K*rivers**m) # For every pixel, calculate the time an "erosion wave" will need to cross it.
|
|
dem = np.maximum(dem, sea_level)
|
|
dem_new = np.zeros(dem.shape)
|
|
|
|
for y in range(dirs.shape[0]):
|
|
for x in range(dirs.shape[1]):
|
|
# Elevations propagate upstream, so for every pixel we seek the downstream pixel whose erosion wave just reached the current pixel.
|
|
# This means summing the advection times downstream until we reach the erosion time.
|
|
x0, y0 = x, y
|
|
x1, y1 = x, y
|
|
remaining = time
|
|
while True:
|
|
# Move one pixel downstream
|
|
flow_dir = dirs[y0,x0]
|
|
if flow_dir == 0:
|
|
remaining = 0
|
|
break
|
|
elif flow_dir == 1:
|
|
y1 += 1
|
|
elif flow_dir == 2:
|
|
x1 += 1
|
|
elif flow_dir == 3:
|
|
y1 -= 1
|
|
elif flow_dir == 4:
|
|
x1 -= 1
|
|
|
|
if remaining <= adv_time[y0,x0]: # Time is over, we found it.
|
|
break
|
|
remaining -= adv_time[y0,x0]
|
|
x0, y0 = x1, y1
|
|
|
|
c = remaining / adv_time[y0,x0]
|
|
dem_new[y,x] = c*dem[y1,x1] + (1-c)*dem[y0,x0] # If between 2 pixels, perform linear interpolation.
|
|
|
|
return dem_new
|
|
|
|
def diffusion(dem, time, d=1):
|
|
radius = d * time**.5
|
|
return im.gaussian_filter(dem, radius, mode='reflect') # Diffusive erosion is a simple Gaussian blur
|
|
|
|
class EvolutionModel:
|
|
def __init__(self, dem, K=1, m=0.5, d=1, sea_level=0, flow=False, flex_radius=100):
|
|
self.dem = dem
|
|
#self.bedrock = dem
|
|
self.K = K
|
|
self.m = m
|
|
self.d = d
|
|
self.sea_level = sea_level
|
|
self.flex_radius = flex_radius
|
|
self.define_isostasy()
|
|
if flow:
|
|
self.calculate_flow()
|
|
else:
|
|
self.lakes = dem
|
|
self.dirs = np.zeros(dem.shape, dtype=int)
|
|
self.rivers = np.zeros(dem.shape, dtype=int)
|
|
self.flow_uptodate = False
|
|
|
|
def calculate_flow(self):
|
|
self.dirs, self.lakes, self.rivers = flow(self.dem)
|
|
self.flow_uptodate = True
|
|
|
|
def advection(self, time):
|
|
dem = advection(np.maximum(self.dem, self.lakes), self.dirs, self.rivers, time, K=self.K, m=self.m, sea_level=self.sea_level)
|
|
self.dem = np.minimum(dem, self.dem)
|
|
self.flow_uptodate = False
|
|
|
|
def diffusion(self, time):
|
|
self.dem = diffusion(self.dem, time, d=self.d)
|
|
self.flow_uptodate = False
|
|
|
|
def define_isostasy(self):
|
|
self.ref_isostasy = im.gaussian_filter(self.dem, self.flex_radius, mode='reflect') # Define a blurred version of the DEM that will be considered as the reference isostatic elevation.
|
|
|
|
def adjust_isostasy(self, rate=1):
|
|
isostasy = im.gaussian_filter(self.dem, self.flex_radius, mode='reflect') # Calculate blurred DEM
|
|
correction = (self.ref_isostasy - isostasy) * rate # Compare it with the reference isostasy
|
|
self.dem = self.dem + correction # Adjust
|