Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions tests/draw_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,13 +113,13 @@ def test_draw_river_map(self):

def test_draw_grayscale_heightmap(self):
w = World.open_protobuf("%s/seed_28070.world" % self.tests_data_dir)
target = PNGWriter.grayscale_from_array(w.layers['elevation'].data, scale_to_range=True)
target = PNGWriter.grayscale_from_array(w.elevation.data, scale_to_range=True)
self._assert_img_equal("grayscale_heightmap_28070", target)

def test_draw_ocean(self):
w = World.open_protobuf("%s/seed_28070.world" % self.tests_data_dir)
target = PNGWriter.rgba_from_dimensions(w.width, w.height)
draw_ocean(w.layers['ocean'].data, target)
draw_ocean(w.ocean.data, target)
self._assert_img_equal("ocean_28070", target)

def test_draw_precipitation(self):
Expand Down
2 changes: 1 addition & 1 deletion tests/serialization_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def test_hdf5_serialize_unserialize(self):
serialized = save_world_to_hdf5(w, filename)
unserialized = load_world_to_hdf5(filename)
self.assertEqual(Set(w.layers.keys()), Set(unserialized.layers.keys()))
self.assertEqual(w.layers['humidity'].quantiles, unserialized.layers['humidity'].quantiles)
self.assertEqual(w.humidity.quantiles, unserialized.humidity.quantiles)
for l in w.layers.keys():
self.assertEqual(w.layers[l], unserialized.layers[l], "Comparing %s" % l)
self.assertTrue(_equal(w.ocean_level, unserialized.ocean_level))
Expand Down
12 changes: 7 additions & 5 deletions worldengine/cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@

import worldengine.generation as geo
from worldengine.common import set_verbose, print_verbose
from worldengine.draw import draw_ancientmap_on_file, draw_biome_on_file, draw_ocean_on_file, \
draw_precipitation_on_file, draw_grayscale_heightmap_on_file, draw_simple_elevation_on_file, \
draw_temperature_levels_on_file, draw_riversmap_on_file, draw_scatter_plot_on_file, \
draw_satellite_on_file, draw_icecaps_on_file
from worldengine.draw import *
from worldengine.plates import world_gen, generate_plates_simulation
from worldengine.imex import export
from worldengine.step import Step
Expand Down Expand Up @@ -54,9 +51,14 @@ def generate_world(world_name, width, height, seed, num_plates, output_dir,

# Generate images
filename = '%s/%s_ocean.png' % (output_dir, world_name)
draw_ocean_on_file(w.layers['ocean'].data, filename)
draw_ocean_on_file(w.ocean.data, filename)
print("* ocean image generated in '%s'" % filename)

if step.include_wind:
filename = '%s/%s_wind.png' % (output_dir, world_name)
draw_wind_on_file(w, filename)
print("* wind image generated in '%s'" % filename)

if step.include_precipitations:
filename = '%s/%s_precipitation.png' % (output_dir, world_name)
draw_precipitation_on_file(w, filename, black_and_white)
Expand Down
83 changes: 57 additions & 26 deletions worldengine/draw.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import numpy

from worldengine.drawing_functions import draw_ancientmap, \
draw_rivers_on_image
draw_rivers_on_image, gradient
from worldengine.image_io import PNGWriter

# -------------
Expand Down Expand Up @@ -235,8 +235,8 @@ def get_normalized_elevation_array(world):
''' Convert raw elevation into normalized values between 0 and 255,
and return a numpy array of these values '''

e = world.layers['elevation'].data
ocean = world.layers['ocean'].data
e = world.elevation.data
ocean = world.ocean.data

mask = numpy.ma.array(e, mask=ocean) # only land
min_elev_land = mask.min()
Expand Down Expand Up @@ -324,24 +324,24 @@ 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)
"""
e = world.layers['elevation'].data
e = world.elevation.data
c = numpy.empty(e.shape, dtype=numpy.float)

has_ocean = not (sea_level is None or world.layers['ocean'].data is None or not world.layers['ocean'].data.any()) # or 'not any ocean'
mask_land = numpy.ma.array(e, mask=world.layers['ocean'].data if has_ocean else False) # only land
has_ocean = not (sea_level is None or world.ocean.data is None or not world.ocean.data.any()) # or 'not any ocean'
mask_land = numpy.ma.array(e, mask=world.ocean.data if has_ocean else False) # only land

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.layers['ocean'].data)
land = numpy.logical_not(world.ocean.data)
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.layers['ocean'].data] = ((e[world.layers['ocean'].data] - min_elev_sea) / elev_delta_sea)
c[world.ocean.data] = ((e[world.ocean.data] - 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
Expand Down Expand Up @@ -377,7 +377,7 @@ def draw_satellite(world, target):

# Get an elevation mask where heights are normalized between 0 and 255
elevation_mask = get_normalized_elevation_array(world)
smooth_mask = numpy.invert(world.layers['ocean'].data) # all land shall be smoothed (other tiles can be included by setting them to True)
smooth_mask = numpy.invert(world.ocean.data) # all land shall be smoothed (other tiles can be included by setting them to True)

rng = numpy.random.RandomState(world.seed) # create our own random generator; necessary for now to make the tests reproducible, even though it is a bit ugly

Expand All @@ -399,7 +399,7 @@ def draw_satellite(world, target):
ice_color_variation = int(30) # 0 means perfectly white ice; must be in [0, 255]; only affects R- and G-channel
for y in range(world.height):
for x in range(world.width):
if world.layers['icecap'].data[y, x] > 0.0:
if world.icecap.data[y, x] > 0.0:
smooth_mask[y, x] = True # smooth the frozen areas, too
variation = rng.randint(0, ice_color_variation)
target.set_pixel(x, y, (255 - ice_color_variation + variation, 255 - ice_color_variation + variation, 255, 255))
Expand Down Expand Up @@ -438,14 +438,14 @@ def draw_satellite(world, target):
for y in range(world.height):
for x in range(world.width):
## Color rivers
if world.is_land((x, y)) and (world.layers['river_map'].data[y, x] > 0.0):
if world.is_land((x, y)) and (world.river_map.data[y, x] > 0.0):
base_color = target[y, x]

r, g, b = add_colors(base_color, RIVER_COLOR_CHANGE)
target.set_pixel(x, y, (r, g, b, 255))

## Color lakes
if world.is_land((x, y)) and (world.layers['lake_map'].data[y, x] != 0):
if world.is_land((x, y)) and (world.lake_map.data[y, x] != 0):
base_color = target[y, x]

r, g, b = add_colors(base_color, LAKE_COLOR_CHANGE)
Expand All @@ -459,13 +459,13 @@ def draw_satellite(world, target):

# Build up list of elevations in the previous n tiles, where n is the shadow size.
# This goes northwest to southeast
prev_elevs = [ world.layers['elevation'].data[y-n, x-n] for n in range(1, SAT_SHADOW_SIZE+1) ]
prev_elevs = [ world.elevation.data[y-n, x-n] for n in range(1, SAT_SHADOW_SIZE+1) ]

# Take the average of the height of the previous n tiles
avg_prev_elev = int( sum(prev_elevs) / len(prev_elevs) )

# Find the difference between this tile's elevation, and the average of the previous elevations
difference = int(world.layers['elevation'].data[y, x] - avg_prev_elev)
difference = int(world.elevation.data[y, x] - avg_prev_elev)

# Amplify the difference
adjusted_difference = difference * SAT_SHADOW_DISTANCE_MULTIPLIER
Expand All @@ -485,8 +485,8 @@ def draw_elevation(world, shadow, target):
width = world.width
height = world.height

data = world.layers['elevation'].data
ocean = world.layers['ocean'].data
data = world.elevation.data
ocean = world.ocean.data

mask = numpy.ma.array(data, mask=ocean)

Expand Down Expand Up @@ -527,6 +527,31 @@ def draw_ocean(ocean, target):
target.set_pixel(x, y, (0, 255, 255, 255))


def draw_wind(world, target):

WEST_COLOR = (255, 0, 0)
NORTH_COLOR = (0, 255, 0)
EAST_COLOR = (0, 0, 255)
SOUTH_COLOR = (255, 255, 0)

def _wind_color(dir):
if dir > 0.75:
return gradient(dir, 0.75, 1.00, WEST_COLOR, NORTH_COLOR)
elif dir > 0.5:
return gradient(dir, 0.50, 0.75, SOUTH_COLOR, WEST_COLOR)
elif dir > 0.25:
return gradient(dir, 0.25, 0.50, EAST_COLOR, SOUTH_COLOR)
else:
return gradient(dir, 0.00, 0.25, NORTH_COLOR, EAST_COLOR)

width = world.width
height = world.height

for y in range(height):
for x in range(width):
target.set_pixel(x, y, _wind_color(world.layers['wind_direction'].data[y, x]))


def draw_precipitation(world, target, black_and_white=False):
# FIXME we are drawing humidity, not precipitations
width = world.width
Expand Down Expand Up @@ -574,7 +599,7 @@ def draw_world(world, target):
biome = world.biome_at((x, y))
target.set_pixel(x, y, _biome_colors[biome.name()])
else:
c = int(world.layers['sea_depth'].data[y, x] * 200 + 50)
c = int(world.sea_depth.data[y, x] * 200 + 50)
target.set_pixel(x, y, (0, 0, 255 - c, 255))


Expand Down Expand Up @@ -617,7 +642,7 @@ def draw_biome(world, target):
width = world.width
height = world.height

biome = world.layers['biome'].data
biome = world.biome.data

for y in range(height):
for x in range(width):
Expand All @@ -632,8 +657,8 @@ def draw_scatter_plot(world, size, target):

#Find min and max values of humidity and temperature on land so we can
#normalize temperature and humidity to the chart
humid = numpy.ma.masked_array(world.layers['humidity'].data, mask=world.layers['ocean'].data)
temp = numpy.ma.masked_array(world.layers['temperature'].data, mask=world.layers['ocean'].data)
humid = numpy.ma.masked_array(world.humidity.data, mask=world.ocean.data)
temp = numpy.ma.masked_array(world.temperature.data, mask=world.ocean.data)
min_humidity = humid.min()
max_humidity = humid.max()
min_temperature = temp.min()
Expand All @@ -650,12 +675,12 @@ def draw_scatter_plot(world, size, target):
h_values = ['62', '50', '37', '25', '12']
t_values = [ 0, 1, 2, 3, 5 ]
for loop in range(0, 5):
h_min = (size - 1) * ((world.layers['humidity'].quantiles[h_values[loop]] - min_humidity) / humidity_delta)
h_min = (size - 1) * ((world.humidity.quantiles[h_values[loop]] - min_humidity) / humidity_delta)
if loop != 4:
h_max = (size - 1) * ((world.layers['humidity'].quantiles[h_values[loop + 1]] - min_humidity) / humidity_delta)
h_max = (size - 1) * ((world.humidity.quantiles[h_values[loop + 1]] - min_humidity) / humidity_delta)
else:
h_max = size
v_max = (size - 1) * ((world.layers['temperature'].thresholds[t_values[loop]][1] - min_temperature) / temperature_delta)
v_max = (size - 1) * ((world.temperature.thresholds[t_values[loop]][1] - min_temperature) / temperature_delta)
if h_min < 0:
h_min = 0
if h_max > size:
Expand All @@ -672,13 +697,13 @@ def draw_scatter_plot(world, size, target):

#draw lines based on thresholds
for t in range(0, 6):
v = (size - 1) * ((world.layers['temperature'].thresholds[t][1] - min_temperature) / temperature_delta)
v = (size - 1) * ((world.temperature.thresholds[t][1] - min_temperature) / temperature_delta)
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.layers['humidity'].quantiles[p] - min_humidity) / humidity_delta)
h = (size - 1) * ((world.humidity.quantiles[p] - min_humidity) / humidity_delta)
if 0 < h < size:
for x in range(0, size):
target.set_pixel(x, (size - 1) - int(h), (0, 0, 0, 255))
Expand Down Expand Up @@ -756,7 +781,7 @@ def draw_riversmap_on_file(world, filename):


def draw_grayscale_heightmap_on_file(world, filename):
img = PNGWriter.grayscale_from_array(world.layers['elevation'].data, filename, scale_to_range=True)
img = PNGWriter.grayscale_from_array(world.elevation.data, filename, scale_to_range=True)
img.complete()


Expand Down Expand Up @@ -797,6 +822,12 @@ def draw_biome_on_file(world, filename):
img.complete()


def draw_wind_on_file(world, filename):
img = PNGWriter.rgba_from_dimensions(world.width, world.height, filename)
draw_wind(world, img)
img.complete()


def draw_ancientmap_on_file(world, filename, resize_factor=1,
sea_color=(212, 198, 169, 255),
draw_biome=True, draw_rivers=True, draw_mountains=True,
Expand Down
4 changes: 2 additions & 2 deletions worldengine/drawing_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,11 @@ def draw_rivers_on_image(world, target, factor=1):

for y in range(world.height):
for x in range(world.width):
if world.is_land((x, y)) and (world.layers['river_map'].data[y, x] > 0.0):
if world.is_land((x, y)) and (world.river_map.data[y, x] > 0.0):
for dx in range(factor):
for dy in range(factor):
target.set_pixel(x * factor + dx, y * factor + dy, (0, 0, 128, 255))
if world.is_land((x, y)) and (world.layers['lake_map'].data[y, x] != 0):
if world.is_land((x, y)) and (world.lake_map.data[y, x] != 0):
for dx in range(factor):
for dy in range(factor):
target.set_pixel(x * factor + dx, y * factor + dy, (0, 100, 128, 255))
Expand Down
27 changes: 17 additions & 10 deletions worldengine/generation.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from worldengine.simulations.precipitation import PrecipitationSimulation
from worldengine.simulations.biome import BiomeSimulation
from worldengine.simulations.icecap import IcecapSimulation
from worldengine.simulations.wind import WindSimulation
from worldengine.common import anti_alias, get_verbose


Expand All @@ -24,19 +25,19 @@ def center_land(world):
"""Translate the map horizontally and vertically to put as much ocean as
possible at the borders. It operates on elevation and plates map"""

y_sums = world.layers['elevation'].data.sum(1) # 1 == sum along x-axis
y_sums = world.elevation.data.sum(1) # 1 == sum along x-axis
y_with_min_sum = y_sums.argmin()
if get_verbose():
print("geo.center_land: height complete")

x_sums = world.layers['elevation'].data.sum(0) # 0 == sum along y-axis
x_sums = world.elevation.data.sum(0) # 0 == sum along y-axis
x_with_min_sum = x_sums.argmin()
if get_verbose():
print("geo.center_land: width complete")

latshift = 0
world.layers['elevation'].data = numpy.roll(numpy.roll(world.layers['elevation'].data, -y_with_min_sum + latshift, axis=0), - x_with_min_sum, axis=1)
world.layers['plates'].data = numpy.roll(numpy.roll(world.layers['plates'].data, -y_with_min_sum + latshift, axis=0), - x_with_min_sum, axis=1)
world.elevation.data = numpy.roll(numpy.roll(world.elevation.data, -y_with_min_sum + latshift, axis=0), - x_with_min_sum, axis=1)
world.plates.data = numpy.roll(numpy.roll(world.plates.data, -y_with_min_sum + latshift, axis=0), - x_with_min_sum, axis=1)
if get_verbose():
print("geo.center_land: width complete")

Expand All @@ -49,8 +50,8 @@ def place_oceans_at_map_borders(world):
ocean_border = int(min(30, max(world.width / 5, world.height / 5)))

def place_ocean(x, y, i):
world.layers['elevation'].data[y, x] = \
(world.layers['elevation'].data[y, x] * i) / ocean_border
world.elevation.data[y, x] = \
(world.elevation.data[y, x] * i) / ocean_border

for x in range(world.width):
for i in range(ocean_border):
Expand All @@ -69,7 +70,7 @@ def add_noise_to_elevation(world, seed):
for y in range(world.height):
for x in range(world.width):
n = snoise2(x / freq * 2, y / freq * 2, octaves, base=seed)
world.layers['elevation'].data[y, x] += n
world.elevation.data[y, x] += n


def fill_ocean(elevation, sea_level):#TODO: Make more use of numpy?
Expand Down Expand Up @@ -105,7 +106,7 @@ def initialize_ocean_and_thresholds(world, ocean_level=1.0):
:param ocean_level: the elevation representing the ocean level
:return: nothing, the world will be changed
"""
e = world.layers['elevation'].data
e = world.elevation.data
ocean = fill_ocean(e, ocean_level)
hl = find_threshold_f(e, 0.10) # the highest 10% of all (!) land are declared hills
ml = find_threshold_f(e, 0.03) # the highest 3% are declared mountains
Expand Down Expand Up @@ -141,7 +142,7 @@ def harmonize_ocean(ocean, elevation, ocean_level):
# ----

def sea_depth(world, sea_level):
sea_depth = sea_level - world.layers['elevation'].data
sea_depth = sea_level - world.elevation.data
for y in range(world.height):
for x in range(world.width):
if world.tiles_around((x, y), radius=1, predicate=world.is_land):
Expand Down Expand Up @@ -178,7 +179,7 @@ def generate_world(w, step):
if isinstance(step, str):
step = Step.get_by_name(step)

if not step.include_precipitations:
if not step.include_wind:
return w

# Prepare sufficient seeds for the different steps of the generation
Expand All @@ -194,9 +195,15 @@ def generate_world(w, step):
'PermeabilitySimulation': sub_seeds[ 6],
'BiomeSimulation': sub_seeds[ 7],
'IcecapSimulation': sub_seeds[ 8],
'WindSimulation': sub_seeds[ 9],
'': sub_seeds[99]
}

WindSimulation().execute(w, seed_dict['WindSimulation'])

if not step.include_precipitations:
return w

TemperatureSimulation().execute(w, seed_dict['TemperatureSimulation'])
# Precipitation with thresholds
PrecipitationSimulation().execute(w, seed_dict['PrecipitationSimulation'])
Expand Down
Loading