Skip to content
Open
Show file tree
Hide file tree
Changes from all 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