-
Notifications
You must be signed in to change notification settings - Fork 128
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
numpy-replacements for image-drawing #161
Changes from all commits
e320351
6fbd05a
96962f1
40f01ee
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,7 +3,7 @@ | |
import numpy.ma as ma | ||
|
||
from worldengine.drawing_functions import draw_ancientmap, \ | ||
draw_rivers_on_image, gradient | ||
draw_rivers_on_image | ||
|
||
# ------------- | ||
# Helper values | ||
|
@@ -168,43 +168,31 @@ def draw_simple_elevation(world, sea_level, target): | |
""" This function can be used on a generic canvas (either an image to save | ||
on disk or a canvas part of a GUI) | ||
""" | ||
min_elev_sea = None | ||
max_elev_sea = None | ||
min_elev_land = None | ||
max_elev_land = None | ||
for y in range(world.height): | ||
for x in range(world.width): | ||
e = world.elevation['data'][y,x] | ||
if sea_level is None: | ||
if min_elev_land is None or e < min_elev_land: | ||
min_elev_land = e | ||
if max_elev_land is None or e > max_elev_land: | ||
max_elev_land = e | ||
elif world.is_land((x, y)): | ||
if min_elev_land is None or e < min_elev_land: | ||
min_elev_land = e | ||
if max_elev_land is None or e > max_elev_land: | ||
max_elev_land = e | ||
else: | ||
if min_elev_sea is None or e < min_elev_sea: | ||
min_elev_sea = e | ||
if max_elev_sea is None or e > max_elev_sea: | ||
max_elev_sea = e | ||
e = world.elevation['data'] | ||
c = numpy.empty(e.shape, dtype=numpy.float) | ||
|
||
has_ocean = not (sea_level is None or world.ocean is None or not world.ocean.any()) # or 'not any ocean' | ||
mask_land = numpy.ma.array(e, mask=world.ocean if has_ocean else False) # only land | ||
|
||
elev_delta_land = (max_elev_land - min_elev_land)/11 | ||
if sea_level != None: | ||
min_elev_land = mask_land.min() | ||
max_elev_land = mask_land.max() | ||
elev_delta_land = (max_elev_land - min_elev_land) / 11.0 | ||
|
||
if has_ocean: | ||
land = numpy.logical_not(world.ocean) | ||
mask_ocean = numpy.ma.array(e, mask=land) # only ocean | ||
min_elev_sea = mask_ocean.min() | ||
max_elev_sea = mask_ocean.max() | ||
elev_delta_sea = max_elev_sea - min_elev_sea | ||
|
||
|
||
c[world.ocean] = ((e[world.ocean] - min_elev_sea) / elev_delta_sea) | ||
c[land] = ((e[land] - min_elev_land) / elev_delta_land) + 1 | ||
else: | ||
c = ((e - min_elev_land) / elev_delta_land) + 1 | ||
|
||
for y in range(world.height): | ||
for x in range(world.width): | ||
e = world.elevation['data'][y, x] | ||
if sea_level is None: | ||
c = ((e - min_elev_land) / elev_delta_land) + 1 | ||
elif world.is_land((x, y)): | ||
c = ((e - min_elev_land) / elev_delta_land) + 1 | ||
else: | ||
c = ((e - min_elev_sea) / elev_delta_sea) | ||
r, g, b = elevation_color(c, sea_level) | ||
r, g, b = elevation_color(c[y, x], sea_level) | ||
target.set_pixel(x, y, (int(r * 255), int(g * 255), | ||
int(b * 255), 255)) | ||
|
||
|
@@ -213,46 +201,34 @@ def draw_riversmap(world, target): | |
sea_color = (255, 255, 255, 255) | ||
land_color = (0, 0, 0, 255) | ||
|
||
for y in range(world.height):#TODO: numpy | ||
for y in range(world.height): | ||
for x in range(world.width): | ||
if world.ocean[y, x]: | ||
target.set_pixel(x, y, sea_color) | ||
else: | ||
target.set_pixel(x, y, land_color) | ||
target.set_pixel(x, y, sea_color if world.is_ocean((x, y)) else land_color) | ||
|
||
draw_rivers_on_image(world, target, factor=1) | ||
|
||
|
||
def draw_grayscale_heightmap(world, target): | ||
min_elev_sea = None | ||
max_elev_sea = None | ||
min_elev_land = None | ||
max_elev_land = None | ||
for y in range(world.height): | ||
for x in range(world.width): | ||
e = world.elevation['data'][y, x] | ||
if world.is_land((x, y)): | ||
if min_elev_land is None or e < min_elev_land: | ||
min_elev_land = e | ||
if max_elev_land is None or e > max_elev_land: | ||
max_elev_land = e | ||
else: | ||
if min_elev_sea is None or e < min_elev_sea: | ||
min_elev_sea = e | ||
if max_elev_sea is None or e > max_elev_sea: | ||
max_elev_sea = e | ||
e = world.elevation['data'] | ||
|
||
mask = numpy.ma.array(e, mask=world.ocean) # only land | ||
min_elev_land = mask.min() | ||
max_elev_land = mask.max() | ||
elev_delta_land = max_elev_land - min_elev_land | ||
|
||
mask = numpy.ma.array(e, mask=numpy.logical_not(world.ocean)) # only ocean | ||
min_elev_sea = mask.min() | ||
max_elev_sea = mask.max() | ||
elev_delta_sea = max_elev_sea - min_elev_sea | ||
|
||
c = numpy.empty(e.shape, dtype=numpy.float) | ||
c[numpy.invert(world.ocean)] = (e[numpy.invert(world.ocean)] - min_elev_land) * 127 / elev_delta_land + 128 | ||
c[world.ocean] = (e[world.ocean] - min_elev_sea) * 127 / elev_delta_sea | ||
c = numpy.rint(c).astype(dtype=numpy.int32) # proper rounding | ||
|
||
for y in range(world.height): | ||
for x in range(world.width): | ||
e = world.elevation['data'][y, x] | ||
if world.is_land((x, y)): | ||
c = int(((e - min_elev_land) * 127) / elev_delta_land)+128 | ||
else: | ||
c = int(((e - min_elev_sea) * 127) / elev_delta_sea) | ||
target.set_pixel(x, y, (c, c, c, 255)) | ||
target.set_pixel(x, y, (c[y, x], c[y, x], c[y, x], 255)) | ||
|
||
|
||
def draw_elevation(world, shadow, target): | ||
|
@@ -262,13 +238,13 @@ def draw_elevation(world, shadow, target): | |
data = world.elevation['data'] | ||
ocean = world.ocean | ||
|
||
mask = numpy.ma.array(data, mask = ocean) | ||
mask = numpy.ma.array(data, mask=ocean) | ||
|
||
min_elev = mask.min() | ||
max_elev = mask.max() | ||
elev_delta = max_elev - min_elev | ||
|
||
for y in range(height):#TODO: numpy optimisation for the code below | ||
for y in range(height): | ||
for x in range(width): | ||
if ocean[y, x]: | ||
target.set_pixel(x, y, (0, 0, 255, 255)) | ||
|
@@ -307,24 +283,16 @@ def draw_precipitation(world, target, black_and_white=False): | |
height = world.height | ||
|
||
if black_and_white: | ||
low = None | ||
high = None | ||
for y in range(height): | ||
for x in range(width): | ||
p = world.precipitations_at((x, y)) | ||
if low is None or p < low: | ||
low = p | ||
if high is None or p > high: | ||
high = p | ||
low = world.precipitation['data'].min() | ||
high = world.precipitation['data'].max() | ||
floor = 0 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. +1 for the variables with clear names |
||
ceiling = 255 | ||
|
||
colors = numpy.interp(world.precipitation['data'], [low, high], [floor, ceiling]) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am making use of numpys interp-method (which basically does what drawing_functions.py/gradient() did before). I assume it is faster. |
||
colors = numpy.rint(colors).astype(dtype=numpy.int32) # proper rounding | ||
for y in range(height): | ||
for x in range(width): | ||
p = world.precipitations_at((x, y)) | ||
if p <= low: | ||
target.set_pixel(x, y, (0, 0, 0, 255)) | ||
elif p >= high: | ||
target.set_pixel(x, y, (255, 255, 255, 255)) | ||
else: | ||
target.set_pixel(x, y, gradient(p, low, high, (0, 0, 0), (255, 255, 255))) | ||
target.set_pixel(x, y, (colors[y, x], colors[y, x], colors[y, x], 255)) | ||
else: | ||
for y in range(height): | ||
for x in range(width): | ||
|
@@ -367,15 +335,14 @@ def draw_temperature_levels(world, target, black_and_white=False): | |
if black_and_white: | ||
low = world.temperature_thresholds()[0][1] | ||
high = world.temperature_thresholds()[5][1] | ||
floor = 0 | ||
ceiling = 255 | ||
|
||
colors = numpy.interp(world.temperature['data'], [low, high], [floor, ceiling]) | ||
colors = numpy.rint(colors).astype(dtype=numpy.int32) # proper rounding | ||
for y in range(height): | ||
for x in range(width): | ||
t = world.temperature_at((x, y)) | ||
if t <= low: | ||
target.set_pixel(x, y, (0, 0, 0, 255)) | ||
elif t >= high: | ||
target.set_pixel(x, y, (255, 255, 255, 255)) | ||
else: | ||
target.set_pixel(x, y, gradient(t, low, high, (0, 0, 0), (255, 255, 255))) | ||
target.set_pixel(x, y, (colors[y, x], colors[y, x], colors[y, x], 255)) | ||
|
||
else: | ||
for y in range(height): | ||
|
@@ -407,6 +374,7 @@ def draw_biome(world, target): | |
v = biome[y, x] | ||
target.set_pixel(x, y, _biome_colors[v]) | ||
|
||
|
||
def draw_scatter_plot(world, size, target): | ||
""" This function can be used on a generic canvas (either an image to save | ||
on disk or a canvas part of a GUI) | ||
|
@@ -431,7 +399,7 @@ def draw_scatter_plot(world, size, target): | |
#fill in 'bad' boxes with grey | ||
h_values = ['62', '50', '37', '25', '12'] | ||
t_values = [ 0, 1, 2, 3, 5 ] | ||
for loop in range(0,5): | ||
for loop in range(0, 5): | ||
h_min = (size - 1) * ((world.humidity['quantiles'][h_values[loop]] - min_humidity) / humidity_delta) | ||
if loop != 4: | ||
h_max = (size - 1) * ((world.humidity['quantiles'][h_values[loop + 1]] - min_humidity) / humidity_delta) | ||
|
@@ -455,13 +423,13 @@ def draw_scatter_plot(world, size, target): | |
#draw lines based on thresholds | ||
for t in range(0, 6): | ||
v = (size - 1) * ((world.temperature['thresholds'][t][1] - min_temperature) / temperature_delta) | ||
if v > 0 and v < size: | ||
if 0 < v < size: | ||
for y in range(0, size): | ||
target.set_pixel(int(v), (size - 1) - y, (0, 0, 0, 255)) | ||
ranges = ['87', '75', '62', '50', '37', '25', '12'] | ||
for p in ranges: | ||
h = (size - 1) * ((world.humidity['quantiles'][p] - min_humidity) / humidity_delta) | ||
if h > 0 and h < size: | ||
if 0 < h < size: | ||
for x in range(0, size): | ||
target.set_pixel(x, (size - 1) - int(h), (0, 0, 0, 255)) | ||
|
||
|
@@ -583,6 +551,7 @@ def draw_ancientmap_on_file(world, filename, resize_factor=1, | |
verbose) | ||
img.complete() | ||
|
||
|
||
def draw_scatter_plot_on_file(world, filename): | ||
img = ImagePixelSetter(512, 512, filename) | ||
draw_scatter_plot(world, 512, img) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was not rounded before, which might even be preferable.