forked from makepath/xarray-spatial
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbump.py
executable file
·141 lines (116 loc) · 4.5 KB
/
bump.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
import numpy as np
import xarray as xr
from xarray import DataArray
from xrspatial.utils import ngjit
from typing import Optional
# TODO: change parameters to take agg instead of height / width
@ngjit
def _finish_bump(width, height, locs, heights, spread):
out = np.zeros((height, width))
rows, cols = out.shape
s = spread ** 2 # removed sqrt for perf.
for i in range(len(heights)):
x = locs[i][0]
y = locs[i][1]
z = heights[i]
out[y, x] = out[y, x] + z
if s > 0:
for nx in range(max(x - spread, 0), min(x + spread, width)):
for ny in range(max(y - spread, 0), min(y + spread, height)):
d2 = (nx - x) * (nx - x) + (ny - y) * (ny - y)
if d2 <= s:
out[ny, nx] = out[ny, nx] + (out[y, x] * (d2 / s))
return out
def bump(width: int, height: int, count: Optional[int] = None,
height_func=None, spread: int = 1) -> xr.DataArray:
"""
Generate a simple bump map to simulate the appearance of land features.
Using a user-defined height function, determines at what elevation a
specific bump height is acceptable.
Bumps of number "count" are applied over the area "width" x "height".
Parameters:
----------
width: int
Total width in pixels of the image.
height: int
Total height, in pixels, of the image.
count: int (defaults: w * h / 10)
Number of bumps to generate.
height_func: function which takes x, y and returns a height value
Function used to apply varying bump heights to different elevations.
spread: tuple boundaries (default = 1)
Returns:
----------
xarray.DataArray, 2D DataArray of calculated bump heights.
Notes:
----------
Algorithm References:
- http://www.mountaincartography.org/mt_hood/pdfs/nighbert_bump1.pdf
Examples:
----------
Imports
>>> import numpy as np
>>> import datashader as ds
>>> from datashader.transfer_functions import shade
Generate Terrain
>>> from xrspatial import generate_terrain
>>> W = 800
>>> H = 600
>>> cvs = ds.Canvas(plot_width = W, plot_height = H,
x_range = (-20e6, 20e6), y_range = (-20e6, 20e6))
>>> terrain = generate_terrain(canvas=cvs)
Create Height Function
>>> from functools import partial
>>> from xrspatial import bump
>>> def heights(locations, src, src_range, height=20):
>>> num_bumps = locations.shape[0]
>>> out = np.zeros(num_bumps, dtype=np.uint16)
>>> for r in range(0, num_bumps):
>>> loc = locations[r]
>>> x = loc[0]
>>> y = loc[1]
>>> val = src[y, x]
>>> if val >= src_range[0] and val < src_range[1]:
>>> out[r] = height
>>> return out
Create Bump Map
>>> bump_count = 10000
>>> src = terrain.data
>>> bumps = bump(W, H, count = bump_count,
height_func = partial(heights,
src = src,
src_range = (1000, 1300),
height = 5))
>>> bumps += bump(W, H, count = bump_count//2,
height_func = partial(heights,
src = src,
src_range = (1300, 1700),
height = 20))
>>> print(bumps)
<xarray.DataArray (y: 600, x: 800)>
array([[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.],
...,
[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.]])
Dimensions without coordinates: y, x
Attributes:
res: 1
Terrrain Example:
- https://makepath.github.io/xarray-spatial/assets/examples/user-guide.html
"""
linx = range(width)
liny = range(height)
if count is None:
count = width * height // 10
if height_func is None:
height_func = lambda bumps: np.ones(len(bumps))
# create 2d array of random x, y for bump locations
locs = np.empty((count, 2), dtype=np.uint16)
locs[:, 0] = np.random.choice(linx, count)
locs[:, 1] = np.random.choice(liny, count)
heights = height_func(locs)
bumps = _finish_bump(width, height, locs, heights, spread)
return DataArray(bumps, dims=['y', 'x'], attrs=dict(res=1))