improve topographical accuracy
This commit is contained in:
parent
8e6d87f406
commit
7b73e9ce15
1 changed files with 32 additions and 15 deletions
|
@ -32,11 +32,16 @@ def haversine_dist(lat1, lng1, lat2, lng2):
|
||||||
return 2 * EARTH_RADIUS * asin(sqrt(hav_theta))
|
return 2 * EARTH_RADIUS * asin(sqrt(hav_theta))
|
||||||
|
|
||||||
|
|
||||||
def get_elev_grid(elev_map, map_bounds, resolution, scale_factor):
|
def get_elev_grid(elev_map, map_bounds, scale_factor, resolution):
|
||||||
"""
|
"""
|
||||||
Generate a 2D array of elevation values (in model units), smoothed and
|
Generate a 2D array of elevation values (in model units), smoothed and
|
||||||
"blocked" to avoid jagged and/or superfluous edges.
|
"blocked" to avoid jagged and/or superfluous edges.
|
||||||
"""
|
"""
|
||||||
|
# Are there better factoring algorithms? Yes. Do we need one here? Nope!
|
||||||
|
block_sizes = sorted([
|
||||||
|
int(resolution / x) for x in range(2, resolution) if resolution % x == 0
|
||||||
|
])
|
||||||
|
|
||||||
elev_grid = np.zeros((resolution, resolution))
|
elev_grid = np.zeros((resolution, resolution))
|
||||||
for i in range(resolution):
|
for i in range(resolution):
|
||||||
for j in range(resolution):
|
for j in range(resolution):
|
||||||
|
@ -47,7 +52,8 @@ def get_elev_grid(elev_map, map_bounds, resolution, scale_factor):
|
||||||
elev_grid = (elev_grid - elev_grid.min()) * scale_factor
|
elev_grid = (elev_grid - elev_grid.min()) * scale_factor
|
||||||
|
|
||||||
# Convolve a uniform kernel over matrix to smooth values
|
# Convolve a uniform kernel over matrix to smooth values
|
||||||
KERNEL_SIZE = 5
|
# TODO: adjust this dynamically based on meters per grid cell
|
||||||
|
KERNEL_SIZE = 11
|
||||||
kernel_offset = (KERNEL_SIZE - 1) / 2
|
kernel_offset = (KERNEL_SIZE - 1) / 2
|
||||||
assert kernel_offset % 1 == 0
|
assert kernel_offset % 1 == 0
|
||||||
kernel_offset = int(kernel_offset)
|
kernel_offset = int(kernel_offset)
|
||||||
|
@ -57,15 +63,20 @@ def get_elev_grid(elev_map, map_bounds, resolution, scale_factor):
|
||||||
# Clamping to the array bounds makes the edges of the model less
|
# Clamping to the array bounds makes the edges of the model less
|
||||||
# smooth, but that's acceptable for these purposes
|
# smooth, but that's acceptable for these purposes
|
||||||
windowed = elev_grid[
|
windowed = elev_grid[
|
||||||
max(i - kernel_offset, 0):min(i + kernel_offset, elev_grid.shape[0]),
|
max(i - kernel_offset, 0):min(i + kernel_offset, resolution),
|
||||||
max(j - kernel_offset, 0):min(j + kernel_offset, elev_grid.shape[1]),
|
max(j - kernel_offset, 0):min(j + kernel_offset, resolution),
|
||||||
]
|
]
|
||||||
smoothed[i, j] = windowed.mean()
|
smoothed[i, j] = windowed.mean()
|
||||||
|
|
||||||
BLOCK_TOLERANCE = 0.1
|
BLOCK_TOLERANCE = 0.1 # Higher tolerance means more aggressive flattening
|
||||||
for block_size in range(2, resolution + 1):
|
for block_size in block_sizes:
|
||||||
for i in range(resolution - block_size + 1):
|
assert resolution % block_size == 0
|
||||||
for j in range(resolution - block_size + 1):
|
block_size = int(block_size)
|
||||||
|
# Sweeping a window of block_size with an increment of 1 is smoother,
|
||||||
|
# but it may smear topographical features towards the top left of the
|
||||||
|
# model
|
||||||
|
for i in range(0, resolution - block_size + 1, block_size):
|
||||||
|
for j in range(0, resolution - block_size + 1, block_size):
|
||||||
block = smoothed[i:i+block_size, j:j+block_size].flatten()
|
block = smoothed[i:i+block_size, j:j+block_size].flatten()
|
||||||
if block.max() - block.min() < BLOCK_TOLERANCE:
|
if block.max() - block.min() < BLOCK_TOLERANCE:
|
||||||
smoothed[i:i+block_size, j:j+block_size] = block.mean()
|
smoothed[i:i+block_size, j:j+block_size] = block.mean()
|
||||||
|
@ -266,18 +277,24 @@ if __name__ == "__main__":
|
||||||
help="<min lon>,<min lat>,<max lon>,<max lat>",
|
help="<min lon>,<min lat>,<max lon>,<max lat>",
|
||||||
required=True,
|
required=True,
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
|
||||||
"--elev-exaggeration",
|
|
||||||
type=float,
|
|
||||||
help="Additional scaling factor to apply to elevations for dramatic effect",
|
|
||||||
default=1.0,
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--slices",
|
"--slices",
|
||||||
type=int,
|
type=int,
|
||||||
help="Parallelize render and increase elevation resolution by splitting model into n tiles per side (--slices=3 splits work into 9 tiles)",
|
help="Parallelize render and increase elevation resolution by splitting model into n tiles per side (--slices=3 splits work into 9 tiles)",
|
||||||
default=ceil(sqrt(cpu_count())),
|
default=ceil(sqrt(cpu_count())),
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--elev-resolution",
|
||||||
|
type=int,
|
||||||
|
help="Resolution of elevation grid, per tile",
|
||||||
|
default=30,
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--elev-exaggeration",
|
||||||
|
type=float,
|
||||||
|
help="Additional scaling factor to apply to elevations for dramatic effect",
|
||||||
|
default=1.0,
|
||||||
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--edge-len",
|
"--edge-len",
|
||||||
type=float,
|
type=float,
|
||||||
|
@ -367,7 +384,7 @@ if __name__ == "__main__":
|
||||||
|
|
||||||
print("Calculating elevations...")
|
print("Calculating elevations...")
|
||||||
# Slice the model area into a rectilinear grid to approximate topography
|
# Slice the model area into a rectilinear grid to approximate topography
|
||||||
elev_grid = get_elev_grid(elev_map, map_bounds, args.slices * 25, scale_factor)
|
elev_grid = get_elev_grid(elev_map, map_bounds, scale_factor, args.elev_resolution * args.slices)
|
||||||
elev_grid *= args.elev_exaggeration
|
elev_grid *= args.elev_exaggeration
|
||||||
|
|
||||||
renderers = []
|
renderers = []
|
||||||
|
|
Loading…
Add table
Reference in a new issue