From d5e0f3060452f957749118b63393b9e84df496fe Mon Sep 17 00:00:00 2001 From: Federico Tomassetti Date: Thu, 19 Nov 2015 11:33:58 +0100 Subject: [PATCH 1/8] model: introduce Size --- tests/biome_test.py | 5 ++-- .../generated_blessed_images.py | 3 +- tests/draw_test.py | 5 ++-- tests/drawing_functions_test.py | 2 +- tests/generation_test.py | 4 +-- tests/serialization_test.py | 7 +++-- worldengine/cli/main.py | 10 +++++-- worldengine/common.py | 2 +- worldengine/generation.py | 7 +++-- worldengine/hdf5_serialization.py | 9 +++--- worldengine/model/__init__.py | 1 + worldengine/{ => model}/world.py | 28 +++++++++++++++---- worldengine/plates.py | 4 +-- 13 files changed, 59 insertions(+), 28 deletions(-) create mode 100644 worldengine/model/__init__.py rename worldengine/{ => model}/world.py (98%) diff --git a/tests/biome_test.py b/tests/biome_test.py index 27263ae8..6fe7c4bb 100644 --- a/tests/biome_test.py +++ b/tests/biome_test.py @@ -1,9 +1,10 @@ import unittest +import os + from worldengine.biome import Biome, Ocean, PolarDesert, SubpolarDryTundra, \ CoolTemperateMoistForest, biome_name_to_index, biome_index_to_name from worldengine.simulations.biome import BiomeSimulation -from worldengine.world import World -import os +from worldengine.model.world import World class TestBiome(unittest.TestCase): diff --git a/tests/blessed_images/generated_blessed_images.py b/tests/blessed_images/generated_blessed_images.py index cb35ce03..c7ee9e6b 100644 --- a/tests/blessed_images/generated_blessed_images.py +++ b/tests/blessed_images/generated_blessed_images.py @@ -8,7 +8,8 @@ """ import os -from worldengine.world import * + +from worldengine.model.world import * from worldengine.draw import * from worldengine.image_io import PNGWriter diff --git a/tests/draw_test.py b/tests/draw_test.py index 610029be..29010ce0 100644 --- a/tests/draw_test.py +++ b/tests/draw_test.py @@ -1,11 +1,12 @@ import unittest import os import numpy + from worldengine.draw import _biome_colors, draw_simple_elevation, elevation_color, \ - draw_elevation, draw_riversmap, draw_grayscale_heightmap, draw_ocean, draw_precipitation, \ + draw_elevation, draw_riversmap, draw_ocean, draw_precipitation, \ draw_world, draw_temperature_levels, draw_biome, draw_scatter_plot, draw_satellite from worldengine.biome import Biome -from worldengine.world import World +from worldengine.model.world import World from worldengine.image_io import PNGWriter, PNGReader diff --git a/tests/drawing_functions_test.py b/tests/drawing_functions_test.py index 67496e23..deb23971 100644 --- a/tests/drawing_functions_test.py +++ b/tests/drawing_functions_test.py @@ -1,7 +1,7 @@ import unittest from worldengine.drawing_functions import draw_ancientmap, gradient, draw_rivers_on_image -from worldengine.world import World +from worldengine.model.world import World from worldengine.image_io import PNGWriter from tests.draw_test import TestBase diff --git a/tests/generation_test.py b/tests/generation_test.py index f34f7eda..45b790b9 100644 --- a/tests/generation_test.py +++ b/tests/generation_test.py @@ -1,7 +1,7 @@ import unittest -from worldengine.plates import Step, center_land, world_gen -from worldengine.world import World +from worldengine.plates import Step, center_land, world_gen +from worldengine.model.world import World from tests.draw_test import TestBase diff --git a/tests/serialization_test.py b/tests/serialization_test.py index f8509f6c..8cab7277 100644 --- a/tests/serialization_test.py +++ b/tests/serialization_test.py @@ -1,9 +1,10 @@ import unittest -from worldengine.plates import Step, world_gen -from worldengine.world import World -from worldengine.common import _equal import tempfile import os + +from worldengine.plates import Step, world_gen +from worldengine.model.world import World +from worldengine.common import _equal from worldengine.hdf5_serialization import save_world_to_hdf5, load_world_to_hdf5 diff --git a/worldengine/cli/main.py b/worldengine/cli/main.py index f07bd339..e4da3323 100644 --- a/worldengine/cli/main.py +++ b/worldengine/cli/main.py @@ -2,6 +2,7 @@ from argparse import ArgumentParser import os import numpy + 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, \ @@ -11,8 +12,9 @@ from worldengine.plates import world_gen, generate_plates_simulation from worldengine.imex import export from worldengine.step import Step -from worldengine.world import World +from worldengine.model.world import World, Size from worldengine.version import __version__ + try: from worldengine.hdf5_serialization import save_world_to_hdf5 HDF5_AVAILABLE = True @@ -84,18 +86,22 @@ def generate_rivers_map(world, filename): draw_riversmap_on_file(world, filename) print("+ rivers map generated in '%s'" % filename) + def draw_scatter_plot(world, filename): draw_scatter_plot_on_file(world, filename) print("+ scatter plot generated in '%s'" % filename) + def draw_satellite_map(world, filename): draw_satellite_on_file(world, filename) print("+ satellite map generated in '%s'" % filename) + def draw_icecaps_map(world, filename): draw_icecaps_on_file(world, filename) print("+ icecap map generated in '%s'" % filename) + def generate_plates(seed, world_name, output_dir, width, height, num_plates=10): """ @@ -112,7 +118,7 @@ def generate_plates(seed, world_name, output_dir, width, height, elevation, plates = generate_plates_simulation(seed, width, height, num_plates=num_plates) - world = World(world_name, width, height, seed, num_plates, -1.0, "plates") + world = World(world_name, Size(width, height), seed, num_plates, -1.0, "plates") world.set_elevation(numpy.array(elevation).reshape(height, width), None) world.set_plates(numpy.array(plates, dtype=numpy.uint16).reshape(height, width)) diff --git a/worldengine/common.py b/worldengine/common.py index 90659c6a..acbacdc8 100644 --- a/worldengine/common.py +++ b/worldengine/common.py @@ -117,4 +117,4 @@ def _equal(a, b): return(False) return(t) else:#fallback - return(a == b) + return (a == b) diff --git a/worldengine/generation.py b/worldengine/generation.py index 7854f662..ba52b5e0 100644 --- a/worldengine/generation.py +++ b/worldengine/generation.py @@ -1,5 +1,8 @@ +import numpy + from noise import snoise2 -from worldengine.world import Step + +from worldengine.model.world import Step from worldengine.simulations.basic import find_threshold_f from worldengine.simulations.hydrology import WatermapSimulation from worldengine.simulations.irrigation import IrrigationSimulation @@ -11,7 +14,7 @@ from worldengine.simulations.biome import BiomeSimulation from worldengine.simulations.icecap import IcecapSimulation from worldengine.common import anti_alias, get_verbose -import numpy + # ------------------ diff --git a/worldengine/hdf5_serialization.py b/worldengine/hdf5_serialization.py index daa0c392..719efd6f 100644 --- a/worldengine/hdf5_serialization.py +++ b/worldengine/hdf5_serialization.py @@ -1,8 +1,10 @@ +import numpy + import h5py + from worldengine.version import __version__ from worldengine.biome import biome_name_to_index, biome_index_to_name -from worldengine.world import World, Step -import numpy +from worldengine.model.world import World, Step, Size def save_world_to_hdf5(world, filename): @@ -125,8 +127,7 @@ def load_world_to_hdf5(filename): f = h5py.File(filename, libver='latest', mode='r') w = World(f['general/name'].value, - f['general/width'].value, - f['general/height'].value, + Size(f['general/width'].value, f['general/height'].value), f['generation_params/seed'].value, f['generation_params/n_plates'].value, f['generation_params/ocean_level'].value, diff --git a/worldengine/model/__init__.py b/worldengine/model/__init__.py new file mode 100644 index 00000000..74b9d87e --- /dev/null +++ b/worldengine/model/__init__.py @@ -0,0 +1 @@ +__author__ = 'federico' diff --git a/worldengine/world.py b/worldengine/model/world.py similarity index 98% rename from worldengine/world.py rename to worldengine/model/world.py index 9bcb20d6..8b5c4d23 100644 --- a/worldengine/world.py +++ b/worldengine/model/world.py @@ -17,18 +17,30 @@ from worldengine.version import __version__ +class Size(object): + + def __init__(self, width, height): + self.width = width + self.height = height + + def __eq__(self, other): + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + else: + return False + + class World(object): """A world composed by name, dimensions and all the characteristics of each cell. """ - def __init__(self, name, width, height, seed, num_plates, ocean_level, + def __init__(self, name, size, seed, num_plates, ocean_level, step, temps=[0.874, 0.765, 0.594, 0.439, 0.366, 0.124], humids = [.941, .778, .507, .236, 0.073, .014, .002], gamma_curve=1.25, curve_offset=.2): self.name = name - self.width = width - self.height = height + self.size = size self.seed = seed self.n_plates = num_plates self.ocean_level = ocean_level @@ -38,6 +50,10 @@ def __init__(self, name, width, height, seed, num_plates, ocean_level, self.gamma_curve = gamma_curve self.curve_offset = curve_offset + # Deprecated + self.width = size.width + self.height = size.height + # # General methods # @@ -46,12 +62,12 @@ def __eq__(self, other): return _equal(self.__dict__, other.__dict__) # - # Serialization/Unserialization + # Serialization / Unserialization # @classmethod def from_dict(cls, dict): - instance = World(dict['name'], dict['width'], dict['height']) + instance = World(dict['name'], Size(dict['width'], dict['height'])) for k in dict: instance.__dict__[k] = dict[k] return instance @@ -233,7 +249,7 @@ def _to_protobuf_world(self): @classmethod def _from_protobuf_world(cls, p_world): - w = World(p_world.name, p_world.width, p_world.height, + w = World(p_world.name, Size(p_world.width, p_world.height), p_world.generationData.seed, p_world.generationData.n_plates, p_world.generationData.ocean_level, diff --git a/worldengine/plates.py b/worldengine/plates.py index e45ec4af..bfce44bd 100644 --- a/worldengine/plates.py +++ b/worldengine/plates.py @@ -7,7 +7,7 @@ from worldengine.generation import Step, add_noise_to_elevation, center_land, generate_world, \ get_verbose, initialize_ocean_and_thresholds, place_oceans_at_map_borders -from worldengine.world import World +from worldengine.model.world import World, Size def generate_plates_simulation(seed, width, height, sea_level=0.65, @@ -44,7 +44,7 @@ def _plates_simulation(name, width, height, seed, temps= num_plates=num_plates, verbose=verbose) - world = World(name, width, height, seed, num_plates, ocean_level, step, temps, + world = World(name, Size(width, height), seed, num_plates, ocean_level, step, temps, humids, gamma_curve, curve_offset) world.set_elevation(numpy.array(e_as_array).reshape(height, width), None) world.set_plates(numpy.array(p_as_array, dtype=numpy.uint16).reshape(height, width)) From 59bb0962c4a41a768b038858d5ca4c993f9fc6ce Mon Sep 17 00:00:00 2001 From: Federico Tomassetti Date: Thu, 19 Nov 2015 11:49:17 +0100 Subject: [PATCH 2/8] model: add GenerationParameters --- worldengine/cli/main.py | 4 ++-- worldengine/hdf5_serialization.py | 8 ++++---- worldengine/model/world.py | 32 +++++++++++++++++++++++-------- worldengine/plates.py | 7 ++++--- 4 files changed, 34 insertions(+), 17 deletions(-) diff --git a/worldengine/cli/main.py b/worldengine/cli/main.py index e4da3323..ca4a99ca 100644 --- a/worldengine/cli/main.py +++ b/worldengine/cli/main.py @@ -12,7 +12,7 @@ from worldengine.plates import world_gen, generate_plates_simulation from worldengine.imex import export from worldengine.step import Step -from worldengine.model.world import World, Size +from worldengine.model.world import World, Size, GenerationParameters from worldengine.version import __version__ try: @@ -118,7 +118,7 @@ def generate_plates(seed, world_name, output_dir, width, height, elevation, plates = generate_plates_simulation(seed, width, height, num_plates=num_plates) - world = World(world_name, Size(width, height), seed, num_plates, -1.0, "plates") + world = World(world_name, Size(width, height), seed, GenerationParameters(num_plates, -1.0, "plates")) world.set_elevation(numpy.array(elevation).reshape(height, width), None) world.set_plates(numpy.array(plates, dtype=numpy.uint16).reshape(height, width)) diff --git a/worldengine/hdf5_serialization.py b/worldengine/hdf5_serialization.py index 719efd6f..b0699597 100644 --- a/worldengine/hdf5_serialization.py +++ b/worldengine/hdf5_serialization.py @@ -4,7 +4,7 @@ from worldengine.version import __version__ from worldengine.biome import biome_name_to_index, biome_index_to_name -from worldengine.model.world import World, Step, Size +from worldengine.model.world import World, Step, Size, GenerationParameters def save_world_to_hdf5(world, filename): @@ -129,9 +129,9 @@ def load_world_to_hdf5(filename): w = World(f['general/name'].value, Size(f['general/width'].value, f['general/height'].value), f['generation_params/seed'].value, - f['generation_params/n_plates'].value, - f['generation_params/ocean_level'].value, - Step.get_by_name(f['generation_params/step'].value)) + GenerationParameters(f['generation_params/n_plates'].value, + f['generation_params/ocean_level'].value, + Step.get_by_name(f['generation_params/step'].value))) # Elevation e = numpy.array(f['elevation/data']) diff --git a/worldengine/model/world.py b/worldengine/model/world.py index 8b5c4d23..cd6576cc 100644 --- a/worldengine/model/world.py +++ b/worldengine/model/world.py @@ -30,29 +30,45 @@ def __eq__(self, other): return False +class GenerationParameters(object): + + def __init__(self, n_plates, ocean_level, step): + self.n_plates = n_plates + self.ocean_level = ocean_level + self.step = step + + def __eq__(self, other): + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + else: + return False + + class World(object): """A world composed by name, dimensions and all the characteristics of each cell. """ - def __init__(self, name, size, seed, num_plates, ocean_level, - step, temps=[0.874, 0.765, 0.594, 0.439, 0.366, 0.124], + def __init__(self, name, size, seed, generation_params, + temps=[0.874, 0.765, 0.594, 0.439, 0.366, 0.124], humids = [.941, .778, .507, .236, 0.073, .014, .002], gamma_curve=1.25, curve_offset=.2): self.name = name self.size = size self.seed = seed - self.n_plates = num_plates - self.ocean_level = ocean_level - self.step = step self.temps = temps self.humids = humids self.gamma_curve = gamma_curve self.curve_offset = curve_offset + self.generation_params = generation_params + # Deprecated self.width = size.width self.height = size.height + self.n_plates = generation_params.n_plates + self.step = generation_params.step + self.ocean_level = generation_params.ocean_level # # General methods @@ -251,9 +267,9 @@ def _to_protobuf_world(self): def _from_protobuf_world(cls, p_world): w = World(p_world.name, Size(p_world.width, p_world.height), p_world.generationData.seed, - p_world.generationData.n_plates, - p_world.generationData.ocean_level, - Step.get_by_name(p_world.generationData.step)) + GenerationParameters(p_world.generationData.n_plates, + p_world.generationData.ocean_level, + Step.get_by_name(p_world.generationData.step))) # Elevation e = numpy.array(World._from_protobuf_matrix(p_world.heightMapData)) diff --git a/worldengine/plates.py b/worldengine/plates.py index bfce44bd..53176695 100644 --- a/worldengine/plates.py +++ b/worldengine/plates.py @@ -7,7 +7,7 @@ from worldengine.generation import Step, add_noise_to_elevation, center_land, generate_world, \ get_verbose, initialize_ocean_and_thresholds, place_oceans_at_map_borders -from worldengine.model.world import World, Size +from worldengine.model.world import World, Size, GenerationParameters def generate_plates_simulation(seed, width, height, sea_level=0.65, @@ -44,8 +44,9 @@ def _plates_simulation(name, width, height, seed, temps= num_plates=num_plates, verbose=verbose) - world = World(name, Size(width, height), seed, num_plates, ocean_level, step, temps, - humids, gamma_curve, curve_offset) + world = World(name, Size(width, height), seed, + GenerationParameters(num_plates, ocean_level, step), + temps, humids, gamma_curve, curve_offset) world.set_elevation(numpy.array(e_as_array).reshape(height, width), None) world.set_plates(numpy.array(p_as_array, dtype=numpy.uint16).reshape(height, width)) return world From ed1f4ea3b4c54d520b9598e437e5729c0292f350 Mon Sep 17 00:00:00 2001 From: Federico Tomassetti Date: Thu, 19 Nov 2015 12:52:41 +0100 Subject: [PATCH 3/8] model: introduce layers --- tests/draw_test.py | 5 +- tests/serialization_test.py | 6 +- worldengine/draw.py | 15 +++-- worldengine/generation.py | 17 +++--- worldengine/hdf5_serialization.py | 8 +-- worldengine/model/world.py | 78 +++++++++++++++++--------- worldengine/simulations/erosion.py | 34 ++++++----- worldengine/simulations/hydrology.py | 4 +- worldengine/simulations/temperature.py | 2 +- 9 files changed, 96 insertions(+), 73 deletions(-) diff --git a/tests/draw_test.py b/tests/draw_test.py index 29010ce0..bf0dd3e3 100644 --- a/tests/draw_test.py +++ b/tests/draw_test.py @@ -95,14 +95,12 @@ def test_draw_simple_elevation(self): def test_draw_elevation_shadow(self): w = World.open_protobuf("%s/seed_28070.world" % self.tests_data_dir) - data = w.elevation['data'] target = PNGWriter.rgba_from_dimensions(w.width, w.height) draw_elevation(w, True, target) self._assert_img_equal("elevation_28070_shadow", target) def test_draw_elevation_no_shadow(self): w = World.open_protobuf("%s/seed_28070.world" % self.tests_data_dir) - data = w.elevation['data'] target = PNGWriter.rgba_from_dimensions(w.width, w.height) draw_elevation(w, False, target) self._assert_img_equal("elevation_28070_no_shadow", target) @@ -115,8 +113,7 @@ 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.elevation['data'], scale_to_range=True) - #draw_grayscale_heightmap(w, target) + target = PNGWriter.grayscale_from_array(w.layers['elevation'].data, scale_to_range=True) self._assert_img_equal("grayscale_heightmap_28070", target) def test_draw_ocean(self): diff --git a/tests/serialization_test.py b/tests/serialization_test.py index 8cab7277..2a788b52 100644 --- a/tests/serialization_test.py +++ b/tests/serialization_test.py @@ -17,8 +17,7 @@ def test_protobuf_serialize_unserialize(self): w = world_gen("Dummy", 32, 16, 1, step=Step.get_by_name("full")) serialized = w.protobuf_serialize() unserialized = World.protobuf_unserialize(serialized) - self.assertTrue(_equal(w.elevation['data'], unserialized.elevation['data'])) - self.assertEqual(w.elevation['thresholds'], unserialized.elevation['thresholds']) + self.assertTrue(_equal(w.layers, unserialized.layers)) self.assertTrue(_equal(w.plates, unserialized.plates)) self.assertTrue(_equal(w.ocean, unserialized.ocean)) self.assertTrue(_equal(w.biome, unserialized.biome)) @@ -48,8 +47,7 @@ def test_hdf5_serialize_unserialize(self): filename = f.name serialized = save_world_to_hdf5(w, filename) unserialized = load_world_to_hdf5(filename) - self.assertTrue(_equal(w.elevation['data'], unserialized.elevation['data'])) - self.assertEqual(w.elevation['thresholds'], unserialized.elevation['thresholds']) + self.assertTrue(_equal(w.layers, unserialized.layers)) self.assertTrue(_equal(w.plates, unserialized.plates)) self.assertTrue(_equal(w.ocean, unserialized.ocean)) self.assertTrue(_equal(w.biome, unserialized.biome)) diff --git a/worldengine/draw.py b/worldengine/draw.py index 663c0c1a..9af265df 100644 --- a/worldengine/draw.py +++ b/worldengine/draw.py @@ -214,12 +214,14 @@ def _sature_color(color): def elevation_color(elevation, sea_level=1.0): return _sature_color(_elevation_color(elevation, sea_level)) + def add_colors(*args): ''' Do some *args magic to return a tuple, which has the sums of all tuples in *args ''' # Adapted from an answer here: http://stackoverflow.com/questions/14180866/sum-each-value-in-a-list-of-tuples added = [sum(x) for x in zip(*args)] return numpy.clip(added, 0, 255) # restrict to uint8 + def average_colors(c1, c2): ''' Average the values of two colors together ''' r = int((c1[0] + c2[0])/2) @@ -228,11 +230,12 @@ def average_colors(c1, c2): return (r, g, b) + 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.elevation['data'] + e = world.layers['elevation'].data mask = numpy.ma.array(e, mask=world.ocean) # only land min_elev_land = mask.min() @@ -320,7 +323,7 @@ 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.elevation['data'] + e = world.layers['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' @@ -455,13 +458,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.elevation['data'][y-n, x-n] for n in range(1, SAT_SHADOW_SIZE+1) ] + prev_elevs = [ world.layers['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.elevation['data'][y, x] - avg_prev_elev) + difference = int(world.layers['elevation'].data[y, x] - avg_prev_elev) # Amplify the difference adjusted_difference = difference * SAT_SHADOW_DISTANCE_MULTIPLIER @@ -481,7 +484,7 @@ def draw_elevation(world, shadow, target): width = world.width height = world.height - data = world.elevation['data'] + data = world.layers['elevation'].data ocean = world.ocean mask = numpy.ma.array(data, mask=ocean) @@ -752,7 +755,7 @@ def draw_riversmap_on_file(world, filename): def draw_grayscale_heightmap_on_file(world, filename): - img = PNGWriter.grayscale_from_array(world.elevation['data'], filename, scale_to_range=True) + img = PNGWriter.grayscale_from_array(world.layers['elevation'].data, filename, scale_to_range=True) #draw_grayscale_heightmap(world, img) img.complete() diff --git a/worldengine/generation.py b/worldengine/generation.py index ba52b5e0..bcf3bf56 100644 --- a/worldengine/generation.py +++ b/worldengine/generation.py @@ -16,7 +16,6 @@ from worldengine.common import anti_alias, get_verbose - # ------------------ # Initial generation # ------------------ @@ -25,18 +24,18 @@ 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.elevation['data'].sum(1) # 1 == sum along x-axis + y_sums = world.layers['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.elevation['data'].sum(0) # 0 == sum along y-axis + x_sums = world.layers['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.elevation['data'] = numpy.roll(numpy.roll(world.elevation['data'], -y_with_min_sum + latshift, axis=0), -x_with_min_sum, axis=1) + 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.plates = numpy.roll(numpy.roll(world.plates, -y_with_min_sum + latshift, axis=0), -x_with_min_sum, axis=1) if get_verbose(): print("geo.center_land: width complete") @@ -50,8 +49,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.elevation['data'][y, x] = \ - (world.elevation['data'][y, x] * i) / ocean_border + world.layers['elevation'].data[y, x] = \ + (world.layers['elevation'].data[y, x] * i) / ocean_border for x in range(world.width): for i in range(ocean_border): @@ -70,7 +69,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.elevation['data'][y, x] += n + world.layers['elevation'].data[y, x] += n def fill_ocean(elevation, sea_level):#TODO: Make more use of numpy? @@ -106,7 +105,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.elevation['data'] + e = world.layers['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 @@ -142,7 +141,7 @@ def harmonize_ocean(ocean, elevation, ocean_level): # ---- def sea_depth(world, sea_level): - sea_depth = sea_level - world.elevation['data'] + sea_depth = sea_level - world.layers['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): diff --git a/worldengine/hdf5_serialization.py b/worldengine/hdf5_serialization.py index b0699597..2eb974ab 100644 --- a/worldengine/hdf5_serialization.py +++ b/worldengine/hdf5_serialization.py @@ -18,11 +18,11 @@ def save_world_to_hdf5(world, filename): elevation_grp = f.create_group("elevation") elevation_ths_grp = elevation_grp.create_group("thresholds") - elevation_ths_grp["sea"] = world.elevation['thresholds'][0][1] - elevation_ths_grp["plain"] = world.elevation['thresholds'][1][1] - elevation_ths_grp["hill"] = world.elevation['thresholds'][2][1] + elevation_ths_grp["sea"] = world.layers['elevation'].thresholds[0][1] + elevation_ths_grp["plain"] = world.layers['elevation'].thresholds[1][1] + elevation_ths_grp["hill"] = world.layers['elevation'].thresholds[2][1] elevation_data = elevation_grp.create_dataset("data", (world.height, world.width), dtype=numpy.float) - elevation_data.write_direct(world.elevation['data']) + elevation_data.write_direct(world.layers['elevation'].data) plates_data = f.create_dataset("plates", (world.height, world.width), dtype=numpy.uint16) plates_data.write_direct(world.plates) diff --git a/worldengine/model/world.py b/worldengine/model/world.py index cd6576cc..337ce0ff 100644 --- a/worldengine/model/world.py +++ b/worldengine/model/world.py @@ -44,6 +44,32 @@ def __eq__(self, other): return False +class Layer(object): + + def __init__(self, data): + self.data = data + + def __eq__(self, other): + if isinstance(other, self.__class__): + return _equal(self.data, other.data) + else: + return False + + +class LayerWithThresholds(Layer): + + def __init__(self, data, thresholds): + Layer.__init__(self, data) + self.thresholds = thresholds + + def __eq__(self, other): + if isinstance(other, self.__class__): + + return _equal(self.data, other.data) and _equal(self.thresholds, other.thresholds) + else: + return False + + class World(object): """A world composed by name, dimensions and all the characteristics of each cell. @@ -63,6 +89,8 @@ def __init__(self, name, size, seed, generation_params, self.generation_params = generation_params + self.layers = {} + # Deprecated self.width = size.width self.height = size.height @@ -196,10 +224,10 @@ def _to_protobuf_world(self): p_world.generationData.step = self.step.name # Elevation - self._to_protobuf_matrix(self.elevation['data'], p_world.heightMapData) - p_world.heightMapTh_sea = self.elevation['thresholds'][0][1] - p_world.heightMapTh_plain = self.elevation['thresholds'][1][1] - p_world.heightMapTh_hill = self.elevation['thresholds'][2][1] + self._to_protobuf_matrix(self.layers['elevation'].data, p_world.heightMapData) + p_world.heightMapTh_sea = self.layers['elevation'].thresholds[0][1] + p_world.heightMapTh_plain = self.layers['elevation'].thresholds[1][1] + p_world.heightMapTh_hill = self.layers['elevation'].thresholds[2][1] # Plates self._to_protobuf_matrix(self.plates, p_world.plates) @@ -381,7 +409,7 @@ def is_ocean(self, pos): return self.ocean[pos[1], pos[0]] def sea_level(self): - return self.elevation['thresholds'][0][1] + return self.layers['elevation'].thresholds[0][1] # # Tiles around @@ -448,69 +476,69 @@ def tiles_around_many(self, pos_list, radius=1, predicate=None): # def start_mountain_th(self): - return self.elevation['thresholds'][2][1] + return self.layers['elevation'].thresholds[2][1] def is_mountain(self, pos): if self.ocean[pos[1], pos[0]]: return False - if len(self.elevation['thresholds']) == 4: + if len(self.layers['elevation'].thresholds) == 4: mi = 2 else: mi = 1 - mountain_level = self.elevation['thresholds'][mi][1] + mountain_level = self.layers['elevation'].thresholds[mi][1] x, y = pos - return self.elevation['data'][y][x] > mountain_level + return self.layers['elevation'].data[y][x] > mountain_level def is_low_mountain(self, pos): if not self.is_mountain(pos): return False - if len(self.elevation['thresholds']) == 4: + if len(self.layers['elevation'].thresholds) == 4: mi = 2 else: mi = 1 - mountain_level = self.elevation['thresholds'][mi][1] + mountain_level = self.layers['elevation'].thresholds[mi][1] x, y = pos - return self.elevation['data'][y, x] < mountain_level + 2.0 + return self.layers['elevation'].data[y, x] < mountain_level + 2.0 def level_of_mountain(self, pos): if self.ocean[pos[1], pos[0]]: return False - if len(self.elevation['thresholds']) == 4: + if len(self.layers['elevation'].thresholds) == 4: mi = 2 else: mi = 1 - mountain_level = self.elevation['thresholds'][mi][1] + mountain_level = self.layers['elevation'].thresholds[mi][1] x, y = pos - if self.elevation['data'][y, x] <= mountain_level: + if self.layers['elevation'].data[y, x] <= mountain_level: return 0 else: - return self.elevation['data'][y, x] - mountain_level + return self.layers['elevation'].data[y, x] - mountain_level def is_high_mountain(self, pos): if not self.is_mountain(pos): return False - if len(self.elevation['thresholds']) == 4: + if len(self.layers['elevation'].thresholds) == 4: mi = 2 else: mi = 1 - mountain_level = self.elevation['thresholds'][mi][1] + mountain_level = self.layers['elevation'].thresholds[mi][1] x, y = pos - return self.elevation['data'][y, x] > mountain_level + 4.0 + return self.layers['elevation'].data[y, x] > mountain_level + 4.0 def is_hill(self, pos): if self.ocean[pos[1], pos[0]]: return False - if len(self.elevation['thresholds']) == 4: + if len(self.layers['elevation'].thresholds) == 4: hi = 1 else: hi = 0 - hill_level = self.elevation['thresholds'][hi][1] - mountain_level = self.elevation['thresholds'][hi + 1][1] + hill_level = self.layers['elevation'].thresholds[hi][1] + mountain_level = self.layers['elevation'].thresholds[hi + 1][1] x, y = pos - return hill_level < self.elevation['data'][y, x] < mountain_level + return hill_level < self.layers['elevation'].data[y, x] < mountain_level def elevation_at(self, pos): - return self.elevation['data'][pos[1], pos[0]] + return self.layers['elevation'].data[pos[1], pos[0]] # # Precipitations @@ -836,7 +864,7 @@ def set_elevation(self, data, thresholds): "Setting elevation map with wrong dimension. " "Expected %d x %d, found %d x %d" % ( self.width, self.height, data.shape[1], data.shape[0])) - self.elevation = {'data': data, 'thresholds': thresholds} + self.layers['elevation'] = LayerWithThresholds(data, thresholds) def set_plates(self, data): if (data.shape[0] != self.height) or (data.shape[1] != self.width): diff --git a/worldengine/simulations/erosion.py b/worldengine/simulations/erosion.py index 65b93847..d7bbad91 100644 --- a/worldengine/simulations/erosion.py +++ b/worldengine/simulations/erosion.py @@ -101,7 +101,7 @@ def find_quick_path(self, river, world): # *** 1,2 *** x, y = river new_path = [] - lowest_elevation = world.elevation['data'][y, x] + lowest_elevation = world.layers['elevation'].data[y, x] # lowestDirection = [0, 0] for dx, dy in DIR_NEIGHBORS: @@ -113,7 +113,7 @@ def find_quick_path(self, river, world): tx, ty = overflow(tx, world.width), overflow(ty, world.height) - elevation = world.elevation['data'][ty, tx] + elevation = world.layers['elevation'].data[ty, tx] if elevation < lowest_elevation: if world.contains(temp_dir): @@ -221,7 +221,7 @@ def river_flow(self, source, world, river_list, lake_list): current_location, world) if lower_elevation and not is_wrapped: lower_path = worldengine.astar.PathFinder().find( - world.elevation['data'], current_location, lower_elevation) + world.layers['elevation'].data, current_location, lower_elevation) if lower_path: path += lower_path current_location = path[-1] @@ -264,7 +264,7 @@ def river_flow(self, source, world, river_list, lake_list): # find our way to the edge edge_path = worldengine.astar.PathFinder().find( - world.elevation['data'], [cx, cy], [lx, ly]) + world.layers['elevation'].data, [cx, cy], [lx, ly]) if not edge_path: # can't find another other path, make it a lake lake_list.append(current_location) @@ -275,7 +275,7 @@ def river_flow(self, source, world, river_list, lake_list): # find our way to lowest position original found lower_path = worldengine.astar.PathFinder().find( - world.elevation['data'], current_location, lower_elevation) + world.layers['elevation'].data, current_location, lower_elevation) path += lower_path current_location = path[-1] @@ -294,11 +294,11 @@ def cleanUpFlow(self, river, world): celevation = 1.0 for r in river: rx, ry = r - relevation = world.elevation['data'][ry, rx] + relevation = world.layers['elevation'].data[ry, rx] if relevation <= celevation: celevation = relevation elif relevation > celevation: - world.elevation['data'][ry, rx] = celevation + world.layers['elevation'].data[ry, rx] = celevation return river def findLowerElevation(self, source, world): @@ -307,7 +307,7 @@ def findLowerElevation(self, source, world): x, y = source currentRadius = 1 maxRadius = 40 - lowestElevation = world.elevation['data'][y, x] + lowestElevation = world.layers['elevation'].data[y, x] destination = [] notFound = True isWrapped = False @@ -332,7 +332,7 @@ def findLowerElevation(self, source, world): # if utilities.outOfBounds([x+cx, y+cy], self.size): # print "Fixed:",x ,y, rx, ry - elevation = world.elevation['data'][ry, rx] + elevation = world.layers['elevation'].data[ry, rx] # have we found a lower elevation? if elevation < lowestElevation: lowestElevation = elevation @@ -370,9 +370,8 @@ def river_erosion(self, river, world): continue if [x, y] in river: # ignore river itself continue - if world.elevation['data'][y, x] <= \ - world.elevation['data'][ry, - rx]: # ignore areas lower than river itself + if world.layers['elevation'].data[y, x] <= world.layers['elevation'].data[ry, rx]: + # ignore areas lower than river itself continue if not in_circle(radius, rx, ry, x, y): # ignore things outside a circle @@ -384,14 +383,13 @@ def river_erosion(self, river, world): elif adx == 2 or ady == 2: curve = 0.05 - diff = world.elevation['data'][ry, rx] - \ - world.elevation['data'][y, x] - newElevation = world.elevation['data'][y, x] + ( + diff = world.layers['elevation'].data[ry, rx] - world.layers['elevation'].data[y, x] + newElevation = world.layers['elevation'].data[y, x] + ( diff * curve) - if newElevation <= world.elevation['data'][ry, rx]: + if newElevation <= world.layers['elevation'].data[ry, rx]: print('newElevation is <= than river, fix me...') - newElevation = world.elevation['data'][r, x] - world.elevation['data'][y, x] = newElevation + newElevation = world.layers['elevation'].data[r, x] + world.layers['elevation'].data[y, x] = newElevation return def rivermap_update(self, river, water_flow, rivermap, precipitations): diff --git a/worldengine/simulations/hydrology.py b/worldengine/simulations/hydrology.py index e0424075..ef3d707b 100644 --- a/worldengine/simulations/hydrology.py +++ b/worldengine/simulations/hydrology.py @@ -18,7 +18,7 @@ def droplet(world, pos, q, _watermap): if q < 0: return x, y = pos - pos_elev = world.elevation['data'][y, x] + _watermap[y, x] + pos_elev = world.layers['elevation'].data[y, x] + _watermap[y, x] lowers = [] min_higher = None min_lower = None @@ -26,7 +26,7 @@ def droplet(world, pos, q, _watermap): tot_lowers = 0 for p in world.tiles_around((x, y)):#TODO: switch to numpy px, py = p - e = world.elevation['data'][py, px] + _watermap[py, px] + e = world.layers['elevation'].data[py, px] + _watermap[py, px] if e < pos_elev: dq = int(pos_elev - e) << 2 if min_lower is None or e < min_lower: diff --git a/worldengine/simulations/temperature.py b/worldengine/simulations/temperature.py index 23acc20e..2a0b0e85 100644 --- a/worldengine/simulations/temperature.py +++ b/worldengine/simulations/temperature.py @@ -10,7 +10,7 @@ def is_applicable(world): return not world.has_temperature() def execute(self, world, seed): - e = world.elevation['data'] + e = world.layers['elevation'].data ml = world.start_mountain_th() # returns how many percent of the world are mountains ocean = world.ocean From bbd075797f73fe55863b380afa6d73f7d106769e Mon Sep 17 00:00:00 2001 From: Federico Tomassetti Date: Thu, 19 Nov 2015 13:46:05 +0100 Subject: [PATCH 4/8] model: move plates among layers --- tests/serialization_test.py | 2 -- worldengine/generation.py | 4 ++-- worldengine/hdf5_serialization.py | 2 +- worldengine/model/world.py | 8 ++++---- 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/tests/serialization_test.py b/tests/serialization_test.py index 2a788b52..3e92a440 100644 --- a/tests/serialization_test.py +++ b/tests/serialization_test.py @@ -18,7 +18,6 @@ def test_protobuf_serialize_unserialize(self): serialized = w.protobuf_serialize() unserialized = World.protobuf_unserialize(serialized) self.assertTrue(_equal(w.layers, unserialized.layers)) - self.assertTrue(_equal(w.plates, unserialized.plates)) self.assertTrue(_equal(w.ocean, unserialized.ocean)) self.assertTrue(_equal(w.biome, unserialized.biome)) self.assertTrue(_equal(w.humidity, unserialized.humidity)) @@ -48,7 +47,6 @@ def test_hdf5_serialize_unserialize(self): serialized = save_world_to_hdf5(w, filename) unserialized = load_world_to_hdf5(filename) self.assertTrue(_equal(w.layers, unserialized.layers)) - self.assertTrue(_equal(w.plates, unserialized.plates)) self.assertTrue(_equal(w.ocean, unserialized.ocean)) self.assertTrue(_equal(w.biome, unserialized.biome)) self.assertTrue(_equal(w.humidity['quantiles'], unserialized.humidity['quantiles'])) diff --git a/worldengine/generation.py b/worldengine/generation.py index bcf3bf56..1fcecd1c 100644 --- a/worldengine/generation.py +++ b/worldengine/generation.py @@ -35,8 +35,8 @@ def center_land(world): 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.plates = numpy.roll(numpy.roll(world.plates, -y_with_min_sum + latshift, axis=0), -x_with_min_sum, axis=1) + 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) if get_verbose(): print("geo.center_land: width complete") diff --git a/worldengine/hdf5_serialization.py b/worldengine/hdf5_serialization.py index 2eb974ab..f85c8045 100644 --- a/worldengine/hdf5_serialization.py +++ b/worldengine/hdf5_serialization.py @@ -25,7 +25,7 @@ def save_world_to_hdf5(world, filename): elevation_data.write_direct(world.layers['elevation'].data) plates_data = f.create_dataset("plates", (world.height, world.width), dtype=numpy.uint16) - plates_data.write_direct(world.plates) + plates_data.write_direct(world.layers['plates'].data) ocean_data = f.create_dataset("ocean", (world.height, world.width), dtype=numpy.bool) ocean_data.write_direct(world.ocean) diff --git a/worldengine/model/world.py b/worldengine/model/world.py index 337ce0ff..1feae2ec 100644 --- a/worldengine/model/world.py +++ b/worldengine/model/world.py @@ -230,7 +230,7 @@ def _to_protobuf_world(self): p_world.heightMapTh_hill = self.layers['elevation'].thresholds[2][1] # Plates - self._to_protobuf_matrix(self.plates, p_world.plates) + self._to_protobuf_matrix(self.layers['plates'].data, p_world.plates) # Ocean self._to_protobuf_matrix(self.ocean, p_world.ocean) @@ -318,7 +318,7 @@ def _from_protobuf_world(cls, p_world): if len(p_world.biome.rows) > 0: w.set_biome(numpy.array( World._from_protobuf_matrix( - p_world.biome, biome_index_to_name), dtype = object)) + p_world.biome, biome_index_to_name), dtype=object)) # Humidity # FIXME: use setters @@ -852,7 +852,7 @@ def is_chaparral(self, pos): # def n_actual_plates(self): - return self.plates.max() + 1 + return self.layers['plates'].data.max() + 1 # # Setters @@ -872,7 +872,7 @@ def set_plates(self, data): "Setting plates map with wrong dimension. " "Expected %d x %d, found %d x %d" % ( self.width, self.height, data.shape[1], data.shape[0])) - self.plates = data + self.layers['plates'] = Layer(data) def set_biome(self, biome): if biome.shape[0] != self.height: From f253694ed3ee595285ecf025940f3816b8b0378c Mon Sep 17 00:00:00 2001 From: Federico Tomassetti Date: Thu, 19 Nov 2015 14:22:26 +0100 Subject: [PATCH 5/8] model: insert ocean and sea_depth among the layers --- tests/draw_test.py | 2 +- tests/serialization_test.py | 7 ++-- worldengine/cli/main.py | 2 +- worldengine/draw.py | 26 +++++++------- worldengine/drawing_functions.py | 6 ++-- worldengine/generation.py | 2 +- worldengine/hdf5_serialization.py | 6 ++-- worldengine/model/world.py | 43 ++++++++++++------------ worldengine/simulations/biome.py | 2 +- worldengine/simulations/erosion.py | 4 +-- worldengine/simulations/humidity.py | 22 +++++------- worldengine/simulations/hydrology.py | 14 +++----- worldengine/simulations/icecap.py | 4 +-- worldengine/simulations/irrigation.py | 2 +- worldengine/simulations/permeability.py | 5 +-- worldengine/simulations/precipitation.py | 5 +-- worldengine/simulations/temperature.py | 2 +- 17 files changed, 71 insertions(+), 83 deletions(-) diff --git a/tests/draw_test.py b/tests/draw_test.py index bf0dd3e3..107d4d6e 100644 --- a/tests/draw_test.py +++ b/tests/draw_test.py @@ -119,7 +119,7 @@ def test_draw_grayscale_heightmap(self): 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.ocean, target) + draw_ocean(w.layers['ocean'].data, target) self._assert_img_equal("ocean_28070", target) def test_draw_precipitation(self): diff --git a/tests/serialization_test.py b/tests/serialization_test.py index 3e92a440..741943fc 100644 --- a/tests/serialization_test.py +++ b/tests/serialization_test.py @@ -18,7 +18,6 @@ def test_protobuf_serialize_unserialize(self): serialized = w.protobuf_serialize() unserialized = World.protobuf_unserialize(serialized) self.assertTrue(_equal(w.layers, unserialized.layers)) - self.assertTrue(_equal(w.ocean, unserialized.ocean)) self.assertTrue(_equal(w.biome, unserialized.biome)) self.assertTrue(_equal(w.humidity, unserialized.humidity)) self.assertTrue(_equal(w.irrigation, unserialized.irrigation)) @@ -26,7 +25,6 @@ def test_protobuf_serialize_unserialize(self): self.assertTrue(_equal(w.watermap, unserialized.watermap)) self.assertTrue(_equal(w.precipitation, unserialized.precipitation)) self.assertTrue(_equal(w.temperature, unserialized.temperature)) - self.assertTrue(_equal(w.sea_depth, unserialized.sea_depth)) self.assertTrue(_equal(w.ocean_level, unserialized.ocean_level)) self.assertTrue(_equal(w.lake_map, unserialized.lake_map)) self.assertTrue(_equal(w.river_map, unserialized.river_map)) @@ -46,8 +44,8 @@ def test_hdf5_serialize_unserialize(self): filename = f.name serialized = save_world_to_hdf5(w, filename) unserialized = load_world_to_hdf5(filename) - self.assertTrue(_equal(w.layers, unserialized.layers)) - self.assertTrue(_equal(w.ocean, unserialized.ocean)) + self.assertEqual(w.layers.keys(), unserialized.layers.keys()) + self.assertTrue(_equal(w.layers['elevation'], unserialized.layers['elevation'])) self.assertTrue(_equal(w.biome, unserialized.biome)) self.assertTrue(_equal(w.humidity['quantiles'], unserialized.humidity['quantiles'])) self.assertTrue(_equal(w.humidity['data'], unserialized.humidity['data'])) @@ -59,7 +57,6 @@ def test_hdf5_serialize_unserialize(self): self.assertTrue(_equal(w.precipitation['data'], unserialized.precipitation['data'])) self.assertTrue(_equal(w.precipitation, unserialized.precipitation)) self.assertTrue(_equal(w.temperature, unserialized.temperature)) - self.assertTrue(_equal(w.sea_depth, unserialized.sea_depth)) self.assertTrue(_equal(w.ocean_level, unserialized.ocean_level)) self.assertTrue(_equal(w.lake_map, unserialized.lake_map)) self.assertTrue(_equal(w.river_map, unserialized.river_map)) diff --git a/worldengine/cli/main.py b/worldengine/cli/main.py index ca4a99ca..93ec93ef 100644 --- a/worldengine/cli/main.py +++ b/worldengine/cli/main.py @@ -54,7 +54,7 @@ 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.ocean, filename) + draw_ocean_on_file(w.layers['ocean'].data, filename) print("* ocean image generated in '%s'" % filename) if step.include_precipitations: diff --git a/worldengine/draw.py b/worldengine/draw.py index 9af265df..a22f4df0 100644 --- a/worldengine/draw.py +++ b/worldengine/draw.py @@ -237,19 +237,19 @@ def get_normalized_elevation_array(world): e = world.layers['elevation'].data - mask = numpy.ma.array(e, mask=world.ocean) # only land + mask = numpy.ma.array(e, mask=world.layers['ocean'].data) # 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 + mask = numpy.ma.array(e, mask=numpy.logical_not(world.layers['ocean'].data)) # 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.invert(world.layers['ocean'].data)] = (e[numpy.invert(world.layers['ocean'].data)] - min_elev_land) * 127 / elev_delta_land + 128 + c[world.layers['ocean'].data] = (e[world.layers['ocean'].data] - min_elev_sea) * 127 / elev_delta_sea c = numpy.rint(c).astype(dtype=numpy.int32) # proper rounding return c @@ -326,21 +326,21 @@ def draw_simple_elevation(world, sea_level, target): e = world.layers['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 + 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 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) + land = numpy.logical_not(world.layers['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.ocean] = ((e[world.ocean] - min_elev_sea) / elev_delta_sea) + c[world.layers['ocean'].data] = ((e[world.layers['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 @@ -376,7 +376,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.ocean) # all land shall be smoothed (other tiles can be included by setting them to True) + smooth_mask = numpy.invert(world.layers['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 @@ -485,7 +485,7 @@ def draw_elevation(world, shadow, target): height = world.height data = world.layers['elevation'].data - ocean = world.ocean + ocean = world.layers['ocean'].data mask = numpy.ma.array(data, mask=ocean) @@ -573,7 +573,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.sea_depth[y, x] * 200 + 50) + c = int(world.layers['sea_depth'].data[y, x] * 200 + 50) target.set_pixel(x, y, (0, 0, 255 - c, 255)) @@ -631,8 +631,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.humidity['data'], mask=world.ocean) - temp = numpy.ma.masked_array(world.temperature['data'], mask=world.ocean) + humid = numpy.ma.masked_array(world.humidity['data'], mask=world.layers['ocean'].data) + temp = numpy.ma.masked_array(world.temperature['data'], mask=world.layers['ocean'].data) min_humidity = humid.min() max_humidity = humid.max() min_temperature = temp.min() diff --git a/worldengine/drawing_functions.py b/worldengine/drawing_functions.py index b6acd34a..9b024abf 100644 --- a/worldengine/drawing_functions.py +++ b/worldengine/drawing_functions.py @@ -61,7 +61,7 @@ def _find_land_borders(world, factor): #scale ocean for y in range(world.height * factor): # TODO: numpy for x in range(world.width * factor): - if world.ocean[int(y / factor), int(x / factor)]: + if world.is_ocean((int(x / factor), int(y / factor))): _ocean[y, x] = True def my_is_ocean(pos): @@ -82,7 +82,7 @@ def _find_outer_borders(world, factor, inner_borders): #scale ocean for y in range(world.height * factor): # TODO: numpy for x in range(world.width * factor): - if world.ocean[int(y / factor)][int(x / factor)]: + if world.is_ocean(int(x / factor), int(y / factor)): _ocean[y, x] = True def is_inner_border(pos): @@ -671,7 +671,7 @@ def on_border(pos): target.set_pixel(x, y, border_color) elif draw_outer_land_border and outer_borders[y, x]: target.set_pixel(x, y, outer_border_color) - elif world.ocean[yf, xf]: + elif world.is_ocean((xf, yf)): target.set_pixel(x, y, sea_color) else: target.set_pixel(x, y, land_color) diff --git a/worldengine/generation.py b/worldengine/generation.py index 1fcecd1c..f0f5f6e7 100644 --- a/worldengine/generation.py +++ b/worldengine/generation.py @@ -116,7 +116,7 @@ def initialize_ocean_and_thresholds(world, ocean_level=1.0): harmonize_ocean(ocean, e, ocean_level) world.set_ocean(ocean) world.set_elevation(e, e_th) - world.sea_depth = sea_depth(world, ocean_level) + world.set_sea_depth(sea_depth(world, ocean_level)) def harmonize_ocean(ocean, elevation, ocean_level): diff --git a/worldengine/hdf5_serialization.py b/worldengine/hdf5_serialization.py index f85c8045..4f260a4a 100644 --- a/worldengine/hdf5_serialization.py +++ b/worldengine/hdf5_serialization.py @@ -28,10 +28,10 @@ def save_world_to_hdf5(world, filename): plates_data.write_direct(world.layers['plates'].data) ocean_data = f.create_dataset("ocean", (world.height, world.width), dtype=numpy.bool) - ocean_data.write_direct(world.ocean) + ocean_data.write_direct(world.layers['ocean'].data) sea_depth_data = f.create_dataset("sea_depth", (world.height, world.width), dtype=numpy.float) - sea_depth_data.write_direct(world.sea_depth) + sea_depth_data.write_direct(world.layers['sea_depth'].data) if hasattr(world, 'biome'): biome_data = f.create_dataset("biome", (world.height, world.width), dtype=numpy.uint16) @@ -146,7 +146,7 @@ def load_world_to_hdf5(filename): # Ocean w.set_ocean(numpy.array(f['ocean'])) - w.sea_depth = numpy.array(f['sea_depth']) + w.set_sea_depth(numpy.array(f['sea_depth'])) # Biome if 'biome' in f.keys(): diff --git a/worldengine/model/world.py b/worldengine/model/world.py index 1feae2ec..f154654f 100644 --- a/worldengine/model/world.py +++ b/worldengine/model/world.py @@ -1,16 +1,6 @@ import numpy -from worldengine.biome import Biome, BorealDesert, BorealDryScrub, BorealMoistForest, \ - BorealRainForest, BorealWetForest, CoolTemperateDesertScrub, CoolTemperateDesert, \ - CoolTemperateMoistForest, CoolTemperateRainForest, CoolTemperateSteppe, CoolTemperateWetForest,\ - Ice, PolarDesert, SubpolarDryTundra, SubpolarMoistTundra, SubpolarRainTundra, \ - SubpolarWetTundra, SubtropicalDesert, SubtropicalDesertScrub, SubtropicalDryForest, \ - SubtropicalMoistForest, SubtropicalRainForest, SubtropicalThornWoodland, SubtropicalWetForest, \ - WarmTemperateDesert, WarmTemperateDesertScrub, WarmTemperateDryForest, \ - WarmTemperateMoistForest, WarmTemperateRainForest, WarmTemperateThornScrub, \ - WarmTemperateWetForest, TropicalDesert, TropicalDesertScrub, TropicalDryForest, \ - TropicalMoistForest, TropicalRainForest, TropicalThornWoodland, TropicalWetForest, \ - TropicalVeryDryForest, biome_index_to_name, biome_name_to_index +from worldengine.biome import * import worldengine.protobuf.World_pb2 as Protobuf from worldengine.step import Step from worldengine.common import _equal @@ -233,8 +223,8 @@ def _to_protobuf_world(self): self._to_protobuf_matrix(self.layers['plates'].data, p_world.plates) # Ocean - self._to_protobuf_matrix(self.ocean, p_world.ocean) - self._to_protobuf_matrix(self.sea_depth, p_world.sea_depth) + self._to_protobuf_matrix(self.layers['ocean'].data, p_world.ocean) + self._to_protobuf_matrix(self.layers['sea_depth'].data, p_world.sea_depth) # Biome if hasattr(self, 'biome'): @@ -312,7 +302,7 @@ def _from_protobuf_world(cls, p_world): # Ocean w.set_ocean(numpy.array(World._from_protobuf_matrix(p_world.ocean))) - w.sea_depth = numpy.array(World._from_protobuf_matrix(p_world.sea_depth)) + w.set_sea_depth(numpy.array(World._from_protobuf_matrix(p_world.sea_depth))) # Biome if len(p_world.biome.rows) > 0: @@ -395,18 +385,18 @@ def contains(self, pos): # def random_land(self): - if self.ocean.all(): + if self.layers['ocean'].data.all(): return None, None # return invalid indices if there is no land at all - lands = numpy.invert(self.ocean) + lands = numpy.invert(self.layers['ocean'].data) lands = numpy.transpose(lands.nonzero()) # returns a list of tuples/indices with land positions y, x = lands[numpy.random.randint(0, len(lands))] # uses global RNG return x, y def is_land(self, pos): - return not self.ocean[pos[1], pos[0]]#faster than reversing pos or transposing ocean + return not self.layers['ocean'].data[pos[1], pos[0]]#faster than reversing pos or transposing ocean def is_ocean(self, pos): - return self.ocean[pos[1], pos[0]] + return self.layers['ocean'].data[pos[1], pos[0]] def sea_level(self): return self.layers['elevation'].thresholds[0][1] @@ -479,7 +469,7 @@ def start_mountain_th(self): return self.layers['elevation'].thresholds[2][1] def is_mountain(self, pos): - if self.ocean[pos[1], pos[0]]: + if self.is_ocean(pos): return False if len(self.layers['elevation'].thresholds) == 4: mi = 2 @@ -501,7 +491,7 @@ def is_low_mountain(self, pos): return self.layers['elevation'].data[y, x] < mountain_level + 2.0 def level_of_mountain(self, pos): - if self.ocean[pos[1], pos[0]]: + if self.is_ocean(pos): return False if len(self.layers['elevation'].thresholds) == 4: mi = 2 @@ -526,7 +516,7 @@ def is_high_mountain(self, pos): return self.layers['elevation'].data[y, x] > mountain_level + 4.0 def is_hill(self, pos): - if self.ocean[pos[1], pos[0]]: + if self.is_ocean(pos): return False if len(self.layers['elevation'].thresholds) == 4: hi = 1 @@ -892,7 +882,16 @@ def set_ocean(self, ocean): "found %d x %d" % (self.width, self.height, ocean.shape[1], ocean.shape[0])) - self.ocean = ocean + self.layers['ocean'] = Layer(ocean) + + def set_sea_depth(self, data): + if (data.shape[0] != self.height) or (data.shape[1] != self.width): + raise Exception( + "Setting sea depth map with wrong dimension. Expected %d x %d, " + "found %d x %d" % (self.width, self.height, + data.shape[1], data.shape[0])) + + self.layers['sea_depth'] = Layer(data) def set_precipitation(self, data, thresholds): """"Precipitation is a value in [-1,1]""" diff --git a/worldengine/simulations/biome.py b/worldengine/simulations/biome.py index d4ca2063..926dc94f 100644 --- a/worldengine/simulations/biome.py +++ b/worldengine/simulations/biome.py @@ -13,7 +13,7 @@ def execute(world, seed): w = world width = world.width height = world.height - ocean = world.ocean + ocean = world.layers['ocean'].data cm = {} biome_cm = {} biome = numpy.zeros((height, width), dtype = object)#this is still kind of expensive memory-wise diff --git a/worldengine/simulations/erosion.py b/worldengine/simulations/erosion.py index d7bbad91..e653e243 100644 --- a/worldengine/simulations/erosion.py +++ b/worldengine/simulations/erosion.py @@ -56,7 +56,7 @@ def execute(self, world, seed): river_list.append(river) self.cleanUpFlow(river, world) rx, ry = river[-1] # find last cell in river - if not world.ocean[ry, rx]: + if not world.is_ocean((rx, ry)): lake_list.append(river[-1]) # river flowed into a lake # step four: simulate erosion and updating river map @@ -206,7 +206,7 @@ def river_flow(self, source, world, river_list, lake_list): return path # skip the rest, return path # found a sea? - if world.ocean[y, x]: + if world.is_ocean((x, y)): break # find our immediate lowest elevation and flow there diff --git a/worldengine/simulations/humidity.py b/worldengine/simulations/humidity.py index 921ffdc1..42b90b97 100644 --- a/worldengine/simulations/humidity.py +++ b/worldengine/simulations/humidity.py @@ -24,19 +24,13 @@ def _calculate(world): # These were originally evenly spaced at 12.5% each but changing them # to a bell curve produced better results + ocean = world.layers['ocean'].data humidity['quantiles'] = {} - humidity['quantiles']['12'] = find_threshold_f(humidity['data'], humids[6], - world.ocean) - humidity['quantiles']['25'] = find_threshold_f(humidity['data'], humids[5], - world.ocean) - humidity['quantiles']['37'] = find_threshold_f(humidity['data'], humids[4], - world.ocean) - humidity['quantiles']['50'] = find_threshold_f(humidity['data'], humids[3], - world.ocean) - humidity['quantiles']['62'] = find_threshold_f(humidity['data'], humids[2], - world.ocean) - humidity['quantiles']['75'] = find_threshold_f(humidity['data'], humids[1], - world.ocean) - humidity['quantiles']['87'] = find_threshold_f(humidity['data'], humids[0], - world.ocean) + humidity['quantiles']['12'] = find_threshold_f(humidity['data'], humids[6], ocean) + humidity['quantiles']['25'] = find_threshold_f(humidity['data'], humids[5], ocean) + humidity['quantiles']['37'] = find_threshold_f(humidity['data'], humids[4], ocean) + humidity['quantiles']['50'] = find_threshold_f(humidity['data'], humids[3], ocean) + humidity['quantiles']['62'] = find_threshold_f(humidity['data'], humids[2], ocean) + humidity['quantiles']['75'] = find_threshold_f(humidity['data'], humids[1], ocean) + humidity['quantiles']['87'] = find_threshold_f(humidity['data'], humids[0], ocean) return humidity diff --git a/worldengine/simulations/hydrology.py b/worldengine/simulations/hydrology.py index ef3d707b..7869af7d 100644 --- a/worldengine/simulations/hydrology.py +++ b/worldengine/simulations/hydrology.py @@ -44,7 +44,7 @@ def droplet(world, pos, q, _watermap): f = q / tot_lowers for l in lowers: s, p = l - if not world.ocean[p[1], p[0]]: + if not world.is_ocean(p): px, py = p ql = f * s # ql = q @@ -61,15 +61,11 @@ def droplet(world, pos, q, _watermap): if x is not None and world.precipitation['data'][y, x] > 0: droplet(world, (x, y), world.precipitation['data'][y, x], _watermap_data) + ocean = world.layers['ocean'].data _watermap = dict() _watermap['data'] = _watermap_data _watermap['thresholds'] = dict() - _watermap['thresholds']['creek'] = find_threshold_f(_watermap_data, - 0.05, - ocean=world.ocean) - _watermap['thresholds']['river'] = find_threshold_f(_watermap_data, - 0.02, - ocean=world.ocean) - _watermap['thresholds']['main river'] = \ - find_threshold_f(_watermap_data, 0.007, ocean=world.ocean) + _watermap['thresholds']['creek'] = find_threshold_f(_watermap_data, 0.05, ocean=ocean) + _watermap['thresholds']['river'] = find_threshold_f(_watermap_data, 0.02, ocean=ocean) + _watermap['thresholds']['main river'] = find_threshold_f(_watermap_data, 0.007, ocean=ocean) return _watermap diff --git a/worldengine/simulations/icecap.py b/worldengine/simulations/icecap.py index b8839eed..fb66f5ba 100644 --- a/worldengine/simulations/icecap.py +++ b/worldengine/simulations/icecap.py @@ -25,7 +25,7 @@ def _calculate(world, seed): # width * height * sizeof(numpy.bool) (temporary) # constants for convenience (or performance) - ocean = world.ocean + ocean = world.layers['ocean'].data temperature = world.temperature['data'] # primary constants (could be used as global variables at some point); all values should be in [0, 1] @@ -54,7 +54,7 @@ def _calculate(world, seed): for y in range(world.height): for x in range(world.width): - if ocean[y, x]: # or world.river_map[y, x] > 0 or world.lake_map[y, x] > 0 or world.watermap['data'][y, x] > 0: + if world.is_ocean((x, y)): # or world.river_map[y, x] > 0 or world.lake_map[y, x] > 0 or world.watermap['data'][y, x] > 0: t = temperature[y, x] if t - temp_min < freeze_threshold: # map temperature to freeze-chance (linear interpolation) diff --git a/worldengine/simulations/irrigation.py b/worldengine/simulations/irrigation.py index 332387a7..d884cae5 100644 --- a/worldengine/simulations/irrigation.py +++ b/worldengine/simulations/irrigation.py @@ -32,7 +32,7 @@ def _calculate(world): while not it_all.finished: x = it_all.multi_index[1] y = it_all.multi_index[0] - if world.ocean[y, x]: + if world.is_ocean((x, y)): #coordinates used for the values-slice (tl = top-left etc.) tl_v = (max(x - radius, 0) , max(y - radius, 0)) br_v = (min(x + radius, width - 1), min(y + radius, height - 1)) diff --git a/worldengine/simulations/permeability.py b/worldengine/simulations/permeability.py index 6ed21756..d7e29837 100644 --- a/worldengine/simulations/permeability.py +++ b/worldengine/simulations/permeability.py @@ -11,9 +11,10 @@ def is_applicable(world): def execute(self, world, seed): perm = self._calculate(seed, world.width, world.height) + ocean = world.layers['ocean'].data perm_th = [ - ('low', find_threshold_f(perm, 0.75, world.ocean)), - ('med', find_threshold_f(perm, 0.25, world.ocean)), + ('low', find_threshold_f(perm, 0.75, ocean)), + ('med', find_threshold_f(perm, 0.25, ocean)), ('hig', None) ] world.set_permeability(perm, perm_th) diff --git a/worldengine/simulations/precipitation.py b/worldengine/simulations/precipitation.py index 9a28ef45..36e61d4d 100644 --- a/worldengine/simulations/precipitation.py +++ b/worldengine/simulations/precipitation.py @@ -16,9 +16,10 @@ def execute(self, world, seed): if get_verbose(): start_time = time.time() pre_calculated = self._calculate(seed, world) + ocean = world.layers['ocean'].data ths = [ - ('low', find_threshold_f(pre_calculated, 0.75, world.ocean)), - ('med', find_threshold_f(pre_calculated, 0.3, world.ocean)), + ('low', find_threshold_f(pre_calculated, 0.75, ocean)), + ('med', find_threshold_f(pre_calculated, 0.3, ocean)), ('hig', None) ] world.set_precipitation(pre_calculated, ths) diff --git a/worldengine/simulations/temperature.py b/worldengine/simulations/temperature.py index 2a0b0e85..bf9860a5 100644 --- a/worldengine/simulations/temperature.py +++ b/worldengine/simulations/temperature.py @@ -12,7 +12,7 @@ def is_applicable(world): def execute(self, world, seed): e = world.layers['elevation'].data ml = world.start_mountain_th() # returns how many percent of the world are mountains - ocean = world.ocean + ocean = world.layers['ocean'].data t = self._calculate(world, seed, e, ml) t_th = [ From f1db99bbc7e9c66247decdcaf8450b5a08ea9180 Mon Sep 17 00:00:00 2001 From: Federico Tomassetti Date: Thu, 19 Nov 2015 14:56:27 +0100 Subject: [PATCH 6/8] model: make biome, irrigation and permeability into layers --- tests/serialization_test.py | 13 +++---- worldengine/draw.py | 4 +-- worldengine/hdf5_serialization.py | 26 +++++++------- worldengine/model/world.py | 51 +++++++++++++++------------ worldengine/simulations/humidity.py | 2 +- worldengine/simulations/irrigation.py | 2 +- 6 files changed, 51 insertions(+), 47 deletions(-) diff --git a/tests/serialization_test.py b/tests/serialization_test.py index 741943fc..2702b780 100644 --- a/tests/serialization_test.py +++ b/tests/serialization_test.py @@ -17,11 +17,10 @@ def test_protobuf_serialize_unserialize(self): w = world_gen("Dummy", 32, 16, 1, step=Step.get_by_name("full")) serialized = w.protobuf_serialize() unserialized = World.protobuf_unserialize(serialized) - self.assertTrue(_equal(w.layers, unserialized.layers)) - self.assertTrue(_equal(w.biome, unserialized.biome)) + self.assertEqual(w.layers.keys(), unserialized.layers.keys()) + for l in w.layers.keys(): + self.assertEqual(w.layers[l], unserialized.layers[l]) self.assertTrue(_equal(w.humidity, unserialized.humidity)) - self.assertTrue(_equal(w.irrigation, unserialized.irrigation)) - self.assertTrue(_equal(w.permeability, unserialized.permeability)) self.assertTrue(_equal(w.watermap, unserialized.watermap)) self.assertTrue(_equal(w.precipitation, unserialized.precipitation)) self.assertTrue(_equal(w.temperature, unserialized.temperature)) @@ -45,13 +44,11 @@ def test_hdf5_serialize_unserialize(self): serialized = save_world_to_hdf5(w, filename) unserialized = load_world_to_hdf5(filename) self.assertEqual(w.layers.keys(), unserialized.layers.keys()) - self.assertTrue(_equal(w.layers['elevation'], unserialized.layers['elevation'])) - self.assertTrue(_equal(w.biome, unserialized.biome)) + for l in w.layers.keys(): + self.assertEqual(w.layers[l], unserialized.layers[l]) self.assertTrue(_equal(w.humidity['quantiles'], unserialized.humidity['quantiles'])) self.assertTrue(_equal(w.humidity['data'], unserialized.humidity['data'])) self.assertTrue(_equal(w.humidity, unserialized.humidity)) - self.assertTrue(_equal(w.irrigation, unserialized.irrigation)) - self.assertTrue(_equal(w.permeability, unserialized.permeability)) self.assertTrue(_equal(w.watermap, unserialized.watermap)) self.assertTrue(_equal(w.precipitation['thresholds'], unserialized.precipitation['thresholds'])) self.assertTrue(_equal(w.precipitation['data'], unserialized.precipitation['data'])) diff --git a/worldengine/draw.py b/worldengine/draw.py index a22f4df0..2b3508bf 100644 --- a/worldengine/draw.py +++ b/worldengine/draw.py @@ -272,7 +272,7 @@ def get_biome_color_based_on_elevation(world, elev, x, y, rng): rng refers to an instance of a random number generator used to draw the random samples needed by this function. ''' - v = world.biome[y, x] + v = world.biome_at((x, y)).name() biome_color = _biome_satellite_colors[v] # Default is no noise - will be overwritten if this tile is land @@ -616,7 +616,7 @@ def draw_biome(world, target): width = world.width height = world.height - biome = world.biome + biome = world.layers['biome'].data for y in range(height): for x in range(width): diff --git a/worldengine/hdf5_serialization.py b/worldengine/hdf5_serialization.py index 4f260a4a..fe8635a8 100644 --- a/worldengine/hdf5_serialization.py +++ b/worldengine/hdf5_serialization.py @@ -33,13 +33,13 @@ def save_world_to_hdf5(world, filename): sea_depth_data = f.create_dataset("sea_depth", (world.height, world.width), dtype=numpy.float) sea_depth_data.write_direct(world.layers['sea_depth'].data) - if hasattr(world, 'biome'): + if world.has_biome(): biome_data = f.create_dataset("biome", (world.height, world.width), dtype=numpy.uint16) for y in range(world.height): for x in range(world.width): - biome_data[y, x] = biome_name_to_index(world.biome[y][x]) + biome_data[y, x] = biome_name_to_index(world.layers['biome'].data[y][x]) - if hasattr(world, 'humidity'): + if world.has_humidity(): humidity_grp = f.create_group("humidity") humidity_quantiles_grp = humidity_grp.create_group("quantiles") for k in world.humidity['quantiles'].keys(): @@ -47,19 +47,19 @@ def save_world_to_hdf5(world, filename): humidity_data = humidity_grp.create_dataset("data", (world.height, world.width), dtype=numpy.float) humidity_data.write_direct(world.humidity['data']) - if hasattr(world, 'irrigation'): + if world.has_irrigation(): irrigation_data = f.create_dataset("irrigation", (world.height, world.width), dtype=numpy.float) - irrigation_data.write_direct(world.irrigation) + irrigation_data.write_direct(world.layers['irrigation'].data) - if hasattr(world, 'permeability'): + if world.has_permeability(): permeability_grp = f.create_group("permeability") permeability_ths_grp = permeability_grp.create_group("thresholds") - permeability_ths_grp['low'] = world.permeability['thresholds'][0][1] - permeability_ths_grp['med'] = world.permeability['thresholds'][1][1] + permeability_ths_grp['low'] = world.layers['permeability'].thresholds[0][1] + permeability_ths_grp['med'] = world.layers['permeability'].thresholds[1][1] permeability_data = permeability_grp.create_dataset("data", (world.height, world.width), dtype=numpy.float) - permeability_data.write_direct(world.permeability['data']) + permeability_data.write_direct(world.layers['permeability'].data) - if hasattr(world, 'watermap'): + if world.has_watermap(): watermap_grp = f.create_group("watermap") watermap_ths_grp = watermap_grp.create_group("thresholds") watermap_ths_grp['creek'] = world.watermap['thresholds']['creek'] @@ -68,7 +68,7 @@ def save_world_to_hdf5(world, filename): watermap_data = watermap_grp.create_dataset("data", (world.height, world.width), dtype=numpy.float) watermap_data.write_direct(world.watermap['data']) - if hasattr(world, 'precipitation'): + if world.has_precipitations(): precipitation_grp = f.create_group("precipitation") precipitation_ths_grp = precipitation_grp.create_group("thresholds") precipitation_ths_grp['low'] = world.precipitation['thresholds'][0][1] @@ -76,7 +76,7 @@ def save_world_to_hdf5(world, filename): precipitation_data = precipitation_grp.create_dataset("data", (world.height, world.width), dtype=numpy.float) precipitation_data.write_direct(world.precipitation['data']) - if hasattr(world, 'temperature'): + if world.has_temperature(): temperature_grp = f.create_group("temperature") temperature_ths_grp = temperature_grp.create_group("thresholds") temperature_ths_grp['polar'] = world.temperature['thresholds'][0][1] @@ -167,7 +167,7 @@ def load_world_to_hdf5(filename): w.humidity['data'] = numpy.array(w.humidity['data']) # numpy conversion if 'irrigation' in f.keys(): - w.irrigation = numpy.array(f['irrigation']) + w.set_irrigation(numpy.array(f['irrigation'])) if 'permeability' in f.keys(): p = numpy.array(f['permeability/data']) diff --git a/worldengine/model/world.py b/worldengine/model/world.py index f154654f..cf9c3ca6 100644 --- a/worldengine/model/world.py +++ b/worldengine/model/world.py @@ -227,25 +227,25 @@ def _to_protobuf_world(self): self._to_protobuf_matrix(self.layers['sea_depth'].data, p_world.sea_depth) # Biome - if hasattr(self, 'biome'): - self._to_protobuf_matrix(self.biome, p_world.biome, + if self.has_biome(): + self._to_protobuf_matrix(self.layers['biome'].data, p_world.biome, biome_name_to_index) # Humidity - if hasattr(self, 'humidity'): + if self.has_humidity(): self._to_protobuf_matrix_with_quantiles(self.humidity, p_world.humidity) - if hasattr(self, 'irrigation'): - self._to_protobuf_matrix(self.irrigation, p_world.irrigation) + if self.has_irrigation(): + self._to_protobuf_matrix(self.layers['irrigation'].data, p_world.irrigation) - if hasattr(self, 'permeability'): - self._to_protobuf_matrix(self.permeability['data'], + if self.has_permeability(): + self._to_protobuf_matrix(self.layers['permeability'].data, p_world.permeabilityData) - p_world.permeability_low = self.permeability['thresholds'][0][1] - p_world.permeability_med = self.permeability['thresholds'][1][1] + p_world.permeability_low = self.layers['permeability'].thresholds[0][1] + p_world.permeability_med = self.layers['permeability'].thresholds[1][1] - if hasattr(self, 'watermap'): + if self.has_watermap(): self._to_protobuf_matrix(self.watermap['data'], p_world.watermapData) p_world.watermap_creek = self.watermap['thresholds']['creek'] @@ -259,13 +259,13 @@ def _to_protobuf_world(self): if hasattr(self, 'river_map'): self._to_protobuf_matrix(self.river_map, p_world.rivermap) - if hasattr(self, 'precipitation'): + if self.has_precipitations(): self._to_protobuf_matrix(self.precipitation['data'], p_world.precipitationData) p_world.precipitation_low = self.precipitation['thresholds'][0][1] p_world.precipitation_med = self.precipitation['thresholds'][1][1] - if hasattr(self, 'temperature'): + if self.has_temperature(): self._to_protobuf_matrix(self.temperature['data'], p_world.temperatureData) p_world.temperature_polar = self.temperature['thresholds'][0][1] @@ -306,9 +306,7 @@ def _from_protobuf_world(cls, p_world): # Biome if len(p_world.biome.rows) > 0: - w.set_biome(numpy.array( - World._from_protobuf_matrix( - p_world.biome, biome_index_to_name), dtype=object)) + w.set_biome(numpy.array(World._from_protobuf_matrix(p_world.biome, biome_index_to_name), dtype=object)) # Humidity # FIXME: use setters @@ -318,7 +316,7 @@ def _from_protobuf_world(cls, p_world): w.humidity['data'] = numpy.array(w.humidity['data'])#numpy conversion if len(p_world.irrigation.rows) > 0: - w.irrigation = numpy.array(World._from_protobuf_matrix(p_world.irrigation)) + w.set_irrigation(numpy.array(World._from_protobuf_matrix(p_world.irrigation))) if len(p_world.permeabilityData.rows) > 0: p = numpy.array(World._from_protobuf_matrix(p_world.permeabilityData)) @@ -698,7 +696,7 @@ def watermap_at(self, pos): def biome_at(self, pos): x, y = pos - b = Biome.by_name(self.biome[y, x]) + b = Biome.by_name(self.layers['biome'].data[y, x]) if b is None: raise Exception('Not found') return b @@ -873,7 +871,7 @@ def set_biome(self, biome): if biome.shape[1] != self.width: raise Exception("Setting data with wrong width") - self.biome = biome + self.layers['biome'] = Layer(biome) def set_ocean(self, ocean): if (ocean.shape[0] != self.height) or (ocean.shape[1] != self.width): @@ -903,6 +901,15 @@ def set_precipitation(self, data, thresholds): self.precipitation = {'data': data, 'thresholds': thresholds} + + def set_irrigation(self, data): + if data.shape[0] != self.height: + raise Exception("Setting data with wrong height") + if data.shape[1] != self.width: + raise Exception("Setting data with wrong width") + + self.layers['irrigation'] = Layer(data) + def set_temperature(self, data, thresholds): if data.shape[0] != self.height: raise Exception("Setting data with wrong height") @@ -917,7 +924,7 @@ def set_permeability(self, data, thresholds): if data.shape[1] != self.width: raise Exception("Setting data with wrong width") - self.permeability = {'data': data, 'thresholds': thresholds} + self.layers['permeability'] = LayerWithThresholds(data, thresholds) def has_ocean(self): return hasattr(self, 'ocean') @@ -929,7 +936,7 @@ def has_watermap(self): return hasattr(self, 'watermap') def has_irrigation(self): - return hasattr(self, 'irrigation') + return 'irrigation' in self.layers def has_humidity(self): return hasattr(self, 'humidity') @@ -938,10 +945,10 @@ def has_temperature(self): return hasattr(self, 'temperature') def has_permeability(self): - return hasattr(self, 'permeability') + return 'permeability' in self.layers def has_biome(self): - return hasattr(self, 'biome') + return 'biome' in self.layers def set_rivermap(self, river_map): self.river_map = river_map diff --git a/worldengine/simulations/humidity.py b/worldengine/simulations/humidity.py index 42b90b97..2e1e4bef 100644 --- a/worldengine/simulations/humidity.py +++ b/worldengine/simulations/humidity.py @@ -20,7 +20,7 @@ def _calculate(world): irrigationWeight = 3 humidity['data'] = numpy.zeros((world.height, world.width), dtype=float) - humidity['data'] = (world.precipitation['data'] * precipitationWeight - world.irrigation * irrigationWeight)/(precipitationWeight + irrigationWeight) + humidity['data'] = (world.precipitation['data'] * precipitationWeight - world.layers['irrigation'].data * irrigationWeight)/(precipitationWeight + irrigationWeight) # These were originally evenly spaced at 12.5% each but changing them # to a bell curve produced better results diff --git a/worldengine/simulations/irrigation.py b/worldengine/simulations/irrigation.py index d884cae5..5f2097db 100644 --- a/worldengine/simulations/irrigation.py +++ b/worldengine/simulations/irrigation.py @@ -6,7 +6,7 @@ def is_applicable(world): return world.has_watermap() and (not world.has_irrigation()) def execute(self, world, seed): - world.irrigation = self._calculate(world) + world.set_irrigation(self._calculate(world)) @staticmethod def _calculate(world): From c53873e277b88b8a9f6516609cb2a4a45a4e034d Mon Sep 17 00:00:00 2001 From: Federico Tomassetti Date: Thu, 19 Nov 2015 16:00:47 +0100 Subject: [PATCH 7/8] model: use layers for all remaining data --- tests/serialization_test.py | 28 +-- worldengine/draw.py | 23 +- worldengine/drawing_functions.py | 4 +- worldengine/hdf5_serialization.py | 72 +++---- worldengine/model/world.py | 256 +++++++++++++---------- worldengine/simulations/basic.py | 1 + worldengine/simulations/biome.py | 4 +- worldengine/simulations/erosion.py | 8 +- worldengine/simulations/humidity.py | 26 +-- worldengine/simulations/hydrology.py | 20 +- worldengine/simulations/icecap.py | 6 +- worldengine/simulations/irrigation.py | 2 +- worldengine/simulations/precipitation.py | 6 +- 13 files changed, 233 insertions(+), 223 deletions(-) diff --git a/tests/serialization_test.py b/tests/serialization_test.py index 2702b780..4d768bb8 100644 --- a/tests/serialization_test.py +++ b/tests/serialization_test.py @@ -6,6 +6,7 @@ from worldengine.model.world import World from worldengine.common import _equal from worldengine.hdf5_serialization import save_world_to_hdf5, load_world_to_hdf5 +from sets import Set class TestSerialization(unittest.TestCase): @@ -17,17 +18,10 @@ def test_protobuf_serialize_unserialize(self): w = world_gen("Dummy", 32, 16, 1, step=Step.get_by_name("full")) serialized = w.protobuf_serialize() unserialized = World.protobuf_unserialize(serialized) - self.assertEqual(w.layers.keys(), unserialized.layers.keys()) + self.assertEqual(Set(w.layers.keys()), Set(unserialized.layers.keys())) for l in w.layers.keys(): - self.assertEqual(w.layers[l], unserialized.layers[l]) - self.assertTrue(_equal(w.humidity, unserialized.humidity)) - self.assertTrue(_equal(w.watermap, unserialized.watermap)) - self.assertTrue(_equal(w.precipitation, unserialized.precipitation)) - self.assertTrue(_equal(w.temperature, unserialized.temperature)) + self.assertEqual(w.layers[l], unserialized.layers[l], "Comparing %s" % l) self.assertTrue(_equal(w.ocean_level, unserialized.ocean_level)) - self.assertTrue(_equal(w.lake_map, unserialized.lake_map)) - self.assertTrue(_equal(w.river_map, unserialized.river_map)) - self.assertTrue(_equal(w.icecap, unserialized.icecap)) self.assertEquals(w.seed, unserialized.seed) self.assertEquals(w.n_plates, unserialized.n_plates) self.assertEquals(w.step, unserialized.step) @@ -43,21 +37,11 @@ def test_hdf5_serialize_unserialize(self): filename = f.name serialized = save_world_to_hdf5(w, filename) unserialized = load_world_to_hdf5(filename) - self.assertEqual(w.layers.keys(), unserialized.layers.keys()) + self.assertEqual(Set(w.layers.keys()), Set(unserialized.layers.keys())) + self.assertEqual(w.layers['humidity'].quantiles, unserialized.layers['humidity'].quantiles) for l in w.layers.keys(): - self.assertEqual(w.layers[l], unserialized.layers[l]) - self.assertTrue(_equal(w.humidity['quantiles'], unserialized.humidity['quantiles'])) - self.assertTrue(_equal(w.humidity['data'], unserialized.humidity['data'])) - self.assertTrue(_equal(w.humidity, unserialized.humidity)) - self.assertTrue(_equal(w.watermap, unserialized.watermap)) - self.assertTrue(_equal(w.precipitation['thresholds'], unserialized.precipitation['thresholds'])) - self.assertTrue(_equal(w.precipitation['data'], unserialized.precipitation['data'])) - self.assertTrue(_equal(w.precipitation, unserialized.precipitation)) - self.assertTrue(_equal(w.temperature, unserialized.temperature)) + self.assertEqual(w.layers[l], unserialized.layers[l], "Comparing %s" % l) self.assertTrue(_equal(w.ocean_level, unserialized.ocean_level)) - self.assertTrue(_equal(w.lake_map, unserialized.lake_map)) - self.assertTrue(_equal(w.river_map, unserialized.river_map)) - self.assertTrue(_equal(w.icecap, unserialized.icecap)) self.assertEquals(w.seed, unserialized.seed) self.assertEquals(w.n_plates, unserialized.n_plates) self.assertEquals(w.step, unserialized.step) diff --git a/worldengine/draw.py b/worldengine/draw.py index 2b3508bf..4ce555f3 100644 --- a/worldengine/draw.py +++ b/worldengine/draw.py @@ -398,7 +398,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.icecap[y, x] > 0.0: + if world.layers['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)) @@ -437,14 +437,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.river_map[y, x] > 0.0): + if world.is_land((x, y)) and (world.layers['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.lake_map[y, x] != 0): + if world.is_land((x, y)) and (world.layers['lake_map'].data[y, x] != 0): base_color = target[y, x] r, g, b = add_colors(base_color, LAKE_COLOR_CHANGE) @@ -631,8 +631,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.humidity['data'], mask=world.layers['ocean'].data) - temp = numpy.ma.masked_array(world.temperature['data'], mask=world.layers['ocean'].data) + 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) min_humidity = humid.min() max_humidity = humid.max() min_temperature = temp.min() @@ -649,12 +649,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.humidity['quantiles'][h_values[loop]] - min_humidity) / humidity_delta) + h_min = (size - 1) * ((world.layers['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) + h_max = (size - 1) * ((world.layers['humidity'].quantiles[h_values[loop + 1]] - min_humidity) / humidity_delta) else: h_max = size - v_max = (size - 1) * ((world.temperature['thresholds'][t_values[loop]][1] - min_temperature) / temperature_delta) + v_max = (size - 1) * ((world.layers['temperature'].thresholds[t_values[loop]][1] - min_temperature) / temperature_delta) if h_min < 0: h_min = 0 if h_max > size: @@ -671,13 +671,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) + v = (size - 1) * ((world.layers['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.humidity['quantiles'][p] - min_humidity) / humidity_delta) + h = (size - 1) * ((world.layers['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)) @@ -696,7 +696,7 @@ def draw_scatter_plot(world, size, target): for x in range(world.width): if world.is_land((x, y)): t = world.temperature_at((x, y)) - p = world.humidity['data'][y, x] + p = world.humidity_at((x, y)) #get red and blue values depending on temperature and humidity if world.is_temperature_polar((x, y)): @@ -756,7 +756,6 @@ 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) - #draw_grayscale_heightmap(world, img) img.complete() diff --git a/worldengine/drawing_functions.py b/worldengine/drawing_functions.py index 9b024abf..f0063d93 100644 --- a/worldengine/drawing_functions.py +++ b/worldengine/drawing_functions.py @@ -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.river_map[y, x] > 0.0): + if world.is_land((x, y)) and (world.layers['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.lake_map[y, x] != 0): + if world.is_land((x, y)) and (world.layers['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)) diff --git a/worldengine/hdf5_serialization.py b/worldengine/hdf5_serialization.py index fe8635a8..41d23ba7 100644 --- a/worldengine/hdf5_serialization.py +++ b/worldengine/hdf5_serialization.py @@ -42,10 +42,10 @@ def save_world_to_hdf5(world, filename): if world.has_humidity(): humidity_grp = f.create_group("humidity") humidity_quantiles_grp = humidity_grp.create_group("quantiles") - for k in world.humidity['quantiles'].keys(): - humidity_quantiles_grp[k] = world.humidity['quantiles'][k] + for k in world.layers['humidity'].quantiles.keys(): + humidity_quantiles_grp[k] = world.layers['humidity'].quantiles[k] humidity_data = humidity_grp.create_dataset("data", (world.height, world.width), dtype=numpy.float) - humidity_data.write_direct(world.humidity['data']) + humidity_data.write_direct(world.layers['humidity'].data) if world.has_irrigation(): irrigation_data = f.create_dataset("irrigation", (world.height, world.width), dtype=numpy.float) @@ -62,43 +62,44 @@ def save_world_to_hdf5(world, filename): if world.has_watermap(): watermap_grp = f.create_group("watermap") watermap_ths_grp = watermap_grp.create_group("thresholds") - watermap_ths_grp['creek'] = world.watermap['thresholds']['creek'] - watermap_ths_grp['river'] = world.watermap['thresholds']['river'] - watermap_ths_grp['mainriver'] = world.watermap['thresholds']['main river'] + watermap_ths_grp['creek'] = world.layers['watermap'].thresholds['creek'] + watermap_ths_grp['river'] = world.layers['watermap'].thresholds['river'] + watermap_ths_grp['mainriver'] = world.layers['watermap'].thresholds['main river'] watermap_data = watermap_grp.create_dataset("data", (world.height, world.width), dtype=numpy.float) - watermap_data.write_direct(world.watermap['data']) + watermap_data.write_direct(world.layers['watermap'].data) if world.has_precipitations(): precipitation_grp = f.create_group("precipitation") precipitation_ths_grp = precipitation_grp.create_group("thresholds") - precipitation_ths_grp['low'] = world.precipitation['thresholds'][0][1] - precipitation_ths_grp['med'] = world.precipitation['thresholds'][1][1] + precipitation_ths_grp['low'] = world.layers['precipitation'].thresholds[0][1] + precipitation_ths_grp['med'] = world.layers['precipitation'].thresholds[1][1] precipitation_data = precipitation_grp.create_dataset("data", (world.height, world.width), dtype=numpy.float) - precipitation_data.write_direct(world.precipitation['data']) + precipitation_data.write_direct(world.layers['precipitation'].data) if world.has_temperature(): temperature_grp = f.create_group("temperature") temperature_ths_grp = temperature_grp.create_group("thresholds") - temperature_ths_grp['polar'] = world.temperature['thresholds'][0][1] - temperature_ths_grp['alpine'] = world.temperature['thresholds'][1][1] - temperature_ths_grp['boreal'] = world.temperature['thresholds'][2][1] - temperature_ths_grp['cool'] = world.temperature['thresholds'][3][1] - temperature_ths_grp['warm'] = world.temperature['thresholds'][4][1] - temperature_ths_grp['subtropical'] = world.temperature['thresholds'][5][1] + th = world.layers['temperature'].thresholds + temperature_ths_grp['polar'] = th[0][1] + temperature_ths_grp['alpine'] = th[1][1] + temperature_ths_grp['boreal'] = th[2][1] + temperature_ths_grp['cool'] = th[3][1] + temperature_ths_grp['warm'] = th[4][1] + temperature_ths_grp['subtropical'] = th[5][1] temperature_data = temperature_grp.create_dataset("data", (world.height, world.width), dtype=numpy.float) - temperature_data.write_direct(world.temperature['data']) + temperature_data.write_direct(world.layers['temperature'].data) - if hasattr(world, 'icecap'): + if world.has_icecap(): icecap_data = f.create_dataset("icecap", (world.height, world.width), dtype=numpy.float) - icecap_data.write_direct(world.icecap) + icecap_data.write_direct(world.layers['icecap'].data) - if hasattr(world, 'lake_map'): + if world.has_lakemap(): lake_map_data = f.create_dataset("lake_map", (world.height, world.width), dtype=numpy.float) - lake_map_data.write_direct(world.lake_map) + lake_map_data.write_direct(world.layers['lake_map'].data) - if hasattr(world, 'river_map'): + if world.has_rivermap(): river_map_data = f.create_dataset("river_map", (world.height, world.width), dtype=numpy.float) - river_map_data.write_direct(world.river_map) + river_map_data.write_direct(world.layers['river_map'].data) generation_params_grp = f.create_group("generation_params") generation_params_grp['seed'] = world.seed @@ -117,10 +118,7 @@ def _from_hdf5_quantiles(p_quantiles): def _from_hdf5_matrix_with_quantiles(p_matrix): - matrix = dict() - matrix['data'] = p_matrix['data'] - matrix['quantiles'] = _from_hdf5_quantiles(p_matrix['quantiles']) - return matrix + return numpy.array(p_matrix['data']), _from_hdf5_quantiles(p_matrix['quantiles']) def load_world_to_hdf5(filename): @@ -160,11 +158,9 @@ def load_world_to_hdf5(filename): biome = numpy.array(biome_data, dtype=object) w.set_biome(biome) - # Humidity - # FIXME: use setters if 'humidity' in f.keys(): - w.humidity = _from_hdf5_matrix_with_quantiles(f['humidity']) - w.humidity['data'] = numpy.array(w.humidity['data']) # numpy conversion + data, quantiles = _from_hdf5_matrix_with_quantiles(f['humidity']) + w.set_humidity(data, quantiles) if 'irrigation' in f.keys(): w.set_irrigation(numpy.array(f['irrigation'])) @@ -179,12 +175,12 @@ def load_world_to_hdf5(filename): w.set_permeability(p, p_th) if 'watermap' in f.keys(): - w.watermap = dict() - w.watermap['data'] = numpy.array(f['watermap/data']) - w.watermap['thresholds'] = {} - w.watermap['thresholds']['creek'] = f['watermap/thresholds/creek'].value - w.watermap['thresholds']['river'] = f['watermap/thresholds/river'].value - w.watermap['thresholds']['main river'] = f['watermap/thresholds/mainriver'].value + data = numpy.array(f['watermap/data']) + thresholds = {} + thresholds['creek'] = f['watermap/thresholds/creek'].value + thresholds['river'] = f['watermap/thresholds/river'].value + thresholds['main river'] = f['watermap/thresholds/mainriver'].value + w.set_watermap(data, thresholds) if 'precipitation' in f.keys(): p = numpy.array(f['precipitation/data']) @@ -209,7 +205,7 @@ def load_world_to_hdf5(filename): w.set_temperature(t, t_th) if 'icecap' in f.keys(): - w.icecap = numpy.array(f['icecap']) + w.set_icecap(numpy.array(f['icecap'])) if 'lake_map' in f.keys(): m = numpy.array(f['lake_map']) diff --git a/worldengine/model/world.py b/worldengine/model/world.py index cf9c3ca6..ebc64b14 100644 --- a/worldengine/model/world.py +++ b/worldengine/model/world.py @@ -45,6 +45,12 @@ def __eq__(self, other): else: return False + def min(self): + return self.data.min() + + def max(self): + return self.data.max() + class LayerWithThresholds(Layer): @@ -60,6 +66,20 @@ def __eq__(self, other): return False +class LayerWithQuantiles(Layer): + + def __init__(self, data, quantiles): + Layer.__init__(self, data) + self.quantiles = quantiles + + def __eq__(self, other): + if isinstance(other, self.__class__): + + return _equal(self.data, other.data) and _equal(self.quantiles, other.quantiles) + else: + return False + + class World(object): """A world composed by name, dimensions and all the characteristics of each cell. @@ -157,8 +177,8 @@ def _to_protobuf_quantiles(quantiles, p_quantiles): @staticmethod def _to_protobuf_matrix_with_quantiles(matrix, p_matrix): - World._to_protobuf_quantiles(matrix['quantiles'], p_matrix.quantiles) - World._to_protobuf_matrix(matrix['data'], p_matrix) + World._to_protobuf_quantiles(matrix.quantiles, p_matrix.quantiles) + World._to_protobuf_matrix(matrix.data, p_matrix) @staticmethod def _from_protobuf_matrix(p_matrix, transformation=None): @@ -182,11 +202,9 @@ def _from_protobuf_quantiles(p_quantiles): @staticmethod def _from_protobuf_matrix_with_quantiles(p_matrix): - matrix = dict() - matrix['data'] = World._from_protobuf_matrix(p_matrix) - matrix['quantiles'] = World._from_protobuf_quantiles( - p_matrix.quantiles) - return matrix + data = World._from_protobuf_matrix(p_matrix) + quantiles = World._from_protobuf_quantiles(p_matrix.quantiles) + return data, quantiles @staticmethod def worldengine_tag(): @@ -226,15 +244,11 @@ def _to_protobuf_world(self): self._to_protobuf_matrix(self.layers['ocean'].data, p_world.ocean) self._to_protobuf_matrix(self.layers['sea_depth'].data, p_world.sea_depth) - # Biome if self.has_biome(): - self._to_protobuf_matrix(self.layers['biome'].data, p_world.biome, - biome_name_to_index) + self._to_protobuf_matrix(self.layers['biome'].data, p_world.biome, biome_name_to_index) - # Humidity if self.has_humidity(): - self._to_protobuf_matrix_with_quantiles(self.humidity, - p_world.humidity) + self._to_protobuf_matrix_with_quantiles(self.layers['humidity'], p_world.humidity) if self.has_irrigation(): self._to_protobuf_matrix(self.layers['irrigation'].data, p_world.irrigation) @@ -246,38 +260,33 @@ def _to_protobuf_world(self): p_world.permeability_med = self.layers['permeability'].thresholds[1][1] if self.has_watermap(): - self._to_protobuf_matrix(self.watermap['data'], - p_world.watermapData) - p_world.watermap_creek = self.watermap['thresholds']['creek'] - p_world.watermap_river = self.watermap['thresholds']['river'] - p_world.watermap_mainriver = self.watermap['thresholds'][ - 'main river'] + self._to_protobuf_matrix(self.layers['watermap'].data, p_world.watermapData) + p_world.watermap_creek = self.layers['watermap'].thresholds['creek'] + p_world.watermap_river = self.layers['watermap'].thresholds['river'] + p_world.watermap_mainriver = self.layers['watermap'].thresholds['main river'] - if hasattr(self, 'lake_map'): - self._to_protobuf_matrix(self.lake_map, p_world.lakemap) + if self.has_lakemap(): + self._to_protobuf_matrix(self.layers['lake_map'].data, p_world.lakemap) - if hasattr(self, 'river_map'): - self._to_protobuf_matrix(self.river_map, p_world.rivermap) + if self.has_rivermap(): + self._to_protobuf_matrix(self.layers['river_map'].data, p_world.rivermap) if self.has_precipitations(): - self._to_protobuf_matrix(self.precipitation['data'], - p_world.precipitationData) - p_world.precipitation_low = self.precipitation['thresholds'][0][1] - p_world.precipitation_med = self.precipitation['thresholds'][1][1] + self._to_protobuf_matrix(self.layers['precipitation'].data, p_world.precipitationData) + p_world.precipitation_low = self.layers['precipitation'].thresholds[0][1] + p_world.precipitation_med = self.layers['precipitation'].thresholds[1][1] if self.has_temperature(): - self._to_protobuf_matrix(self.temperature['data'], - p_world.temperatureData) - p_world.temperature_polar = self.temperature['thresholds'][0][1] - p_world.temperature_alpine = self.temperature['thresholds'][1][1] - p_world.temperature_boreal = self.temperature['thresholds'][2][1] - p_world.temperature_cool = self.temperature['thresholds'][3][1] - p_world.temperature_warm = self.temperature['thresholds'][4][1] - p_world.temperature_subtropical = \ - self.temperature['thresholds'][5][1] - - if hasattr(self, 'icecap'): - self._to_protobuf_matrix(self.icecap, p_world.icecap) + self._to_protobuf_matrix(self.layers['temperature'].data, p_world.temperatureData) + p_world.temperature_polar = self.layers['temperature'].thresholds[0][1] + p_world.temperature_alpine = self.layers['temperature'].thresholds[1][1] + p_world.temperature_boreal = self.layers['temperature'].thresholds[2][1] + p_world.temperature_cool = self.layers['temperature'].thresholds[3][1] + p_world.temperature_warm = self.layers['temperature'].thresholds[4][1] + p_world.temperature_subtropical = self.layers['temperature'].thresholds[5][1] + + if self.has_icecap(): + self._to_protobuf_matrix(self.layers['icecap'].data, p_world.icecap) return p_world @@ -311,9 +320,8 @@ def _from_protobuf_world(cls, p_world): # Humidity # FIXME: use setters if len(p_world.humidity.rows) > 0: - w.humidity = World._from_protobuf_matrix_with_quantiles( - p_world.humidity) - w.humidity['data'] = numpy.array(w.humidity['data'])#numpy conversion + data, quantiles = World._from_protobuf_matrix_with_quantiles(p_world.humidity) + w.set_humidity(numpy.array(data), quantiles) if len(p_world.irrigation.rows) > 0: w.set_irrigation(numpy.array(World._from_protobuf_matrix(p_world.irrigation))) @@ -328,13 +336,13 @@ def _from_protobuf_world(cls, p_world): w.set_permeability(p, p_th) if len(p_world.watermapData.rows) > 0: - w.watermap = dict() - w.watermap['data'] = numpy.array(World._from_protobuf_matrix( + data = numpy.array(World._from_protobuf_matrix( p_world.watermapData)) - w.watermap['thresholds'] = {} - w.watermap['thresholds']['creek'] = p_world.watermap_creek - w.watermap['thresholds']['river'] = p_world.watermap_river - w.watermap['thresholds']['main river'] = p_world.watermap_mainriver + thresholds = {} + thresholds['creek'] = p_world.watermap_creek + thresholds['river'] = p_world.watermap_river + thresholds['main river'] = p_world.watermap_mainriver + w.set_watermap(data, thresholds) if len(p_world.precipitationData.rows) > 0: p = numpy.array(World._from_protobuf_matrix(p_world.precipitationData)) @@ -367,7 +375,7 @@ def _from_protobuf_world(cls, p_world): w.set_rivermap(m) if len(p_world.icecap.rows) > 0: - w.icecap = numpy.array(World._from_protobuf_matrix(p_world.icecap)) + w.set_icecap(numpy.array(World._from_protobuf_matrix(p_world.icecap))) return w @@ -534,131 +542,135 @@ def elevation_at(self, pos): def precipitations_at(self, pos): x, y = pos - return self.precipitation['data'][y, x] + return self.layers['precipitation'].data[y, x] def precipitations_thresholds(self): - return self.precipitation['thresholds'] + return self.layers['precipitation'].thresholds # # Temperature # def is_temperature_polar(self, pos): - th_max = self.temperature['thresholds'][0][1] + th_max = self.layers['temperature'].thresholds[0][1] x, y = pos - t = self.temperature['data'][y, x] + t = self.layers['temperature'].data[y, x] return t < th_max def is_temperature_alpine(self, pos): - th_min = self.temperature['thresholds'][0][1] - th_max = self.temperature['thresholds'][1][1] + th_min = self.layers['temperature'].thresholds[0][1] + th_max = self.layers['temperature'].thresholds[1][1] x, y = pos - t = self.temperature['data'][y, x] + t = self.layers['temperature'].data[y, x] return th_max > t >= th_min def is_temperature_boreal(self, pos): - th_min = self.temperature['thresholds'][1][1] - th_max = self.temperature['thresholds'][2][1] + th_min = self.layers['temperature'].thresholds[1][1] + th_max = self.layers['temperature'].thresholds[2][1] x, y = pos - t = self.temperature['data'][y, x] + t = self.layers['temperature'].data[y, x] return th_max > t >= th_min def is_temperature_cool(self, pos): - th_min = self.temperature['thresholds'][2][1] - th_max = self.temperature['thresholds'][3][1] + th_min = self.layers['temperature'].thresholds[2][1] + th_max = self.layers['temperature'].thresholds[3][1] x, y = pos - t = self.temperature['data'][y, x] + t = self.layers['temperature'].data[y, x] return th_max > t >= th_min def is_temperature_warm(self, pos): - th_min = self.temperature['thresholds'][3][1] - th_max = self.temperature['thresholds'][4][1] + th_min = self.layers['temperature'].thresholds[3][1] + th_max = self.layers['temperature'].thresholds[4][1] x, y = pos - t = self.temperature['data'][y, x] + t = self.layers['temperature'].data[y, x] return th_max > t >= th_min def is_temperature_subtropical(self, pos): - th_min = self.temperature['thresholds'][4][1] - th_max = self.temperature['thresholds'][5][1] + th_min = self.layers['temperature'].thresholds[4][1] + th_max = self.layers['temperature'].thresholds[5][1] x, y = pos - t = self.temperature['data'][y, x] + t = self.layers['temperature'].data[y, x] return th_max > t >= th_min def is_temperature_tropical(self, pos): - th_min = self.temperature['thresholds'][5][1] + th_min = self.layers['temperature'].thresholds[5][1] x, y = pos - t = self.temperature['data'][y, x] + t = self.layers['temperature'].data[y, x] return t >= th_min def temperature_at(self, pos): x, y = pos - return self.temperature['data'][y, x] + return self.layers['temperature'].data[y, x] def temperature_thresholds(self): - return self.temperature['thresholds'] + return self.layers['temperature'].thresholds # # Humidity # + def humidity_at(self, pos): + x, y = pos + return self.layers['humidity'].data[y, x] + def is_humidity_above_quantile(self, pos, q): - th = self.humidity['quantiles'][str(q)] + th = self.layers['humidity'].quantiles[str(q)] x, y = pos - v = self.humidity['data'][y, x] - return v >= th + t = self.layers['humidity'].data[y, x] + return t >= th def is_humidity_superarid(self, pos): - th_max = self.humidity['quantiles']['87'] + th_max = self.layers['humidity'].quantiles['87'] x, y = pos - t = self.humidity['data'][y, x] + t = self.layers['humidity'].data[y, x] return t < th_max def is_humidity_perarid(self, pos): - th_min = self.humidity['quantiles']['87'] - th_max = self.humidity['quantiles']['75'] + th_min = self.layers['humidity'].quantiles['87'] + th_max = self.layers['humidity'].quantiles['75'] x, y = pos - t = self.humidity['data'][y, x] + t = self.layers['humidity'].data[y, x] return th_max > t >= th_min def is_humidity_arid(self, pos): - th_min = self.humidity['quantiles']['75'] - th_max = self.humidity['quantiles']['62'] + th_min = self.layers['humidity'].quantiles['75'] + th_max = self.layers['humidity'].quantiles['62'] x, y = pos - t = self.humidity['data'][y, x] + t = self.layers['humidity'].data[y, x] return th_max > t >= th_min def is_humidity_semiarid(self, pos): - th_min = self.humidity['quantiles']['62'] - th_max = self.humidity['quantiles']['50'] + th_min = self.layers['humidity'].quantiles['62'] + th_max = self.layers['humidity'].quantiles['50'] x, y = pos - t = self.humidity['data'][y, x] + t = self.layers['humidity'].data[y, x] return th_max > t >= th_min def is_humidity_subhumid(self, pos): - th_min = self.humidity['quantiles']['50'] - th_max = self.humidity['quantiles']['37'] + th_min = self.layers['humidity'].quantiles['50'] + th_max = self.layers['humidity'].quantiles['37'] x, y = pos - t = self.humidity['data'][y, x] + t = self.layers['humidity'].data[y, x] return th_max > t >= th_min def is_humidity_humid(self, pos): - th_min = self.humidity['quantiles']['37'] - th_max = self.humidity['quantiles']['25'] + th_min = self.layers['humidity'].quantiles['37'] + th_max = self.layers['humidity'].quantiles['25'] x, y = pos - t = self.humidity['data'][y, x] + t = self.layers['humidity'].data[y, x] return th_max > t >= th_min def is_humidity_perhumid(self, pos): - th_min = self.humidity['quantiles']['25'] - th_max = self.humidity['quantiles']['12'] + th_min = self.layers['humidity'].quantiles['25'] + th_max = self.layers['humidity'].quantiles['12'] x, y = pos - t = self.humidity['data'][y, x] + t = self.layers['humidity'].data[y, x] return th_max > t >= th_min def is_humidity_superhumid(self, pos): - th_min = self.humidity['quantiles']['12'] + th_min = self.layers['humidity'].quantiles['12'] x, y = pos - t = self.humidity['data'][y, x] + t = self.layers['humidity'].data[y, x] return t >= th_min # @@ -898,9 +910,14 @@ def set_precipitation(self, data, thresholds): raise Exception("Setting data with wrong height") if data.shape[1] != self.width: raise Exception("Setting data with wrong width") + self.layers['precipitation'] = LayerWithThresholds(data, thresholds) - self.precipitation = {'data': data, 'thresholds': thresholds} - + def set_humidity(self, data, quantiles): + if data.shape[0] != self.height: + raise Exception("Setting data with wrong height") + if data.shape[1] != self.width: + raise Exception("Setting data with wrong width") + self.layers['humidity'] = LayerWithQuantiles(data, quantiles) def set_irrigation(self, data): if data.shape[0] != self.height: @@ -915,34 +932,48 @@ def set_temperature(self, data, thresholds): raise Exception("Setting data with wrong height") if data.shape[1] != self.width: raise Exception("Setting data with wrong width") - - self.temperature = {'data': data, 'thresholds': thresholds} + self.layers['temperature'] = LayerWithThresholds(data, thresholds) def set_permeability(self, data, thresholds): if data.shape[0] != self.height: raise Exception("Setting data with wrong height") if data.shape[1] != self.width: raise Exception("Setting data with wrong width") - self.layers['permeability'] = LayerWithThresholds(data, thresholds) + def set_watermap(self, data, thresholds): + if data.shape[0] != self.height: + raise Exception("Setting data with wrong height") + if data.shape[1] != self.width: + raise Exception("Setting data with wrong width") + self.layers['watermap'] = LayerWithThresholds(data, thresholds) + + def set_rivermap(self, river_map): + self.layers['river_map'] = Layer(river_map) + + def set_lakemap(self, lake_map): + self.layers['lake_map'] = Layer(lake_map) + + def set_icecap(self, icecap): + self.layers['icecap'] = Layer(icecap) + def has_ocean(self): - return hasattr(self, 'ocean') + return 'ocean' in self.layers def has_precipitations(self): - return hasattr(self, 'precipitation') + return 'precipitation' in self.layers def has_watermap(self): - return hasattr(self, 'watermap') + return 'watermap' in self.layers def has_irrigation(self): return 'irrigation' in self.layers def has_humidity(self): - return hasattr(self, 'humidity') + return 'humidity' in self.layers def has_temperature(self): - return hasattr(self, 'temperature') + return 'temperature' in self.layers def has_permeability(self): return 'permeability' in self.layers @@ -950,8 +981,11 @@ def has_permeability(self): def has_biome(self): return 'biome' in self.layers - def set_rivermap(self, river_map): - self.river_map = river_map + def has_rivermap(self): + return 'river_map' in self.layers - def set_lakemap(self, lake_map): - self.lake_map = lake_map + def has_lakemap(self): + return 'lake_map' in self.layers + + def has_icecap(self): + return 'icecap' in self.layers diff --git a/worldengine/simulations/basic.py b/worldengine/simulations/basic.py index 69080cc2..ef2acc43 100644 --- a/worldengine/simulations/basic.py +++ b/worldengine/simulations/basic.py @@ -1,5 +1,6 @@ import numpy + def find_threshold(map_data, land_percentage, ocean=None):#never used anywhere? height, width = map_data.shape diff --git a/worldengine/simulations/biome.py b/worldengine/simulations/biome.py index 926dc94f..e3e2d473 100644 --- a/worldengine/simulations/biome.py +++ b/worldengine/simulations/biome.py @@ -1,11 +1,11 @@ import numpy + class BiomeSimulation(object): @staticmethod def is_applicable(world): - return world.has_humidity() and world.has_temperature() and \ - (not world.has_biome()) + return world.has_humidity() and world.has_temperature() and not world.has_biome() @staticmethod def execute(world, seed): diff --git a/worldengine/simulations/erosion.py b/worldengine/simulations/erosion.py index e653e243..a08a0bc2 100644 --- a/worldengine/simulations/erosion.py +++ b/worldengine/simulations/erosion.py @@ -62,8 +62,7 @@ def execute(self, world, seed): # step four: simulate erosion and updating river map for river in river_list: self.river_erosion(river, world) - self.rivermap_update(river, water_flow, river_map, - world.precipitation['data']) + self.rivermap_update(river, water_flow, river_map, world.layers['precipitation'].data) # step five: rivers with no paths to sea form lakes for lake in lake_list: @@ -141,7 +140,7 @@ def river_sources(world, water_flow, water_path): # above sea level are marked as 'sources'. for x in range(0, world.width - 1): for y in range(0, world.height - 1): - rain_fall = world.precipitation['data'][y, x] + rain_fall = world.layers['precipitation'].data[y, x] water_flow[y, x] = rain_fall if water_path[y, x] == 0: @@ -152,8 +151,7 @@ def river_sources(world, water_flow, water_path): while not neighbour_seed_found: # have we found a seed? - if world.is_mountain((cx, cy)) and \ - water_flow[cy, cx] >= RIVER_TH: + if world.is_mountain((cx, cy)) and water_flow[cy, cx] >= RIVER_TH: # try not to create seeds around other seeds for seed in river_source_list: diff --git a/worldengine/simulations/humidity.py b/worldengine/simulations/humidity.py index 2e1e4bef..916386d2 100644 --- a/worldengine/simulations/humidity.py +++ b/worldengine/simulations/humidity.py @@ -10,27 +10,27 @@ def is_applicable(world): def execute(self, world, seed): assert seed is not None - world.humidity = self._calculate(world) + data, quantiles = self._calculate(world) + world.set_humidity(data, quantiles) @staticmethod def _calculate(world): humids = world.humids - humidity = dict() precipitationWeight = 1.0 irrigationWeight = 3 - humidity['data'] = numpy.zeros((world.height, world.width), dtype=float) + data = numpy.zeros((world.height, world.width), dtype=float) - humidity['data'] = (world.precipitation['data'] * precipitationWeight - world.layers['irrigation'].data * irrigationWeight)/(precipitationWeight + irrigationWeight) + data = (world.layers['precipitation'].data * precipitationWeight - world.layers['irrigation'].data * irrigationWeight)/(precipitationWeight + irrigationWeight) # These were originally evenly spaced at 12.5% each but changing them # to a bell curve produced better results ocean = world.layers['ocean'].data - humidity['quantiles'] = {} - humidity['quantiles']['12'] = find_threshold_f(humidity['data'], humids[6], ocean) - humidity['quantiles']['25'] = find_threshold_f(humidity['data'], humids[5], ocean) - humidity['quantiles']['37'] = find_threshold_f(humidity['data'], humids[4], ocean) - humidity['quantiles']['50'] = find_threshold_f(humidity['data'], humids[3], ocean) - humidity['quantiles']['62'] = find_threshold_f(humidity['data'], humids[2], ocean) - humidity['quantiles']['75'] = find_threshold_f(humidity['data'], humids[1], ocean) - humidity['quantiles']['87'] = find_threshold_f(humidity['data'], humids[0], ocean) - return humidity + quantiles = {} + quantiles['12'] = find_threshold_f(data, humids[6], ocean) + quantiles['25'] = find_threshold_f(data, humids[5], ocean) + quantiles['37'] = find_threshold_f(data, humids[4], ocean) + quantiles['50'] = find_threshold_f(data, humids[3], ocean) + quantiles['62'] = find_threshold_f(data, humids[2], ocean) + quantiles['75'] = find_threshold_f(data, humids[1], ocean) + quantiles['87'] = find_threshold_f(data, humids[0], ocean) + return data, quantiles diff --git a/worldengine/simulations/hydrology.py b/worldengine/simulations/hydrology.py index 7869af7d..b162f971 100644 --- a/worldengine/simulations/hydrology.py +++ b/worldengine/simulations/hydrology.py @@ -10,7 +10,8 @@ def is_applicable(world): def execute(self, world, seed): assert seed is not None - world.watermap = self._watermap(world, 20000) + data, thresholds = self._watermap(world, 20000) + world.set_watermap(data, thresholds) @staticmethod def _watermap(world, n): @@ -58,14 +59,11 @@ def droplet(world, pos, q, _watermap): _watermap_data = numpy.zeros((world.height, world.width), dtype=float) for i in range(n): x, y = world.random_land() # will return None for x and y if no land exists - if x is not None and world.precipitation['data'][y, x] > 0: - droplet(world, (x, y), world.precipitation['data'][y, x], - _watermap_data) + if x is not None and world.precipitations_at((x, y)) > 0: + droplet(world, (x, y), world.precipitations_at((x, y)), _watermap_data) ocean = world.layers['ocean'].data - _watermap = dict() - _watermap['data'] = _watermap_data - _watermap['thresholds'] = dict() - _watermap['thresholds']['creek'] = find_threshold_f(_watermap_data, 0.05, ocean=ocean) - _watermap['thresholds']['river'] = find_threshold_f(_watermap_data, 0.02, ocean=ocean) - _watermap['thresholds']['main river'] = find_threshold_f(_watermap_data, 0.007, ocean=ocean) - return _watermap + thresholds = dict() + thresholds['creek'] = find_threshold_f(_watermap_data, 0.05, ocean=ocean) + thresholds['river'] = find_threshold_f(_watermap_data, 0.02, ocean=ocean) + thresholds['main river'] = find_threshold_f(_watermap_data, 0.007, ocean=ocean) + return _watermap_data, thresholds diff --git a/worldengine/simulations/icecap.py b/worldengine/simulations/icecap.py index fb66f5ba..f6b58d3c 100644 --- a/worldengine/simulations/icecap.py +++ b/worldengine/simulations/icecap.py @@ -14,7 +14,7 @@ def is_applicable(world): return world.has_ocean() and world.has_temperature() def execute(self, world, seed): - world.icecap = self._calculate(world, seed) + world.set_icecap(self._calculate(world, seed)) @staticmethod def _calculate(world, seed): @@ -26,7 +26,7 @@ def _calculate(world, seed): # constants for convenience (or performance) ocean = world.layers['ocean'].data - temperature = world.temperature['data'] + temperature = world.layers['temperature'].data # primary constants (could be used as global variables at some point); all values should be in [0, 1] max_freeze_percentage = 0.60 # only the coldest x% of the cold area will freeze (0 = no ice, 1 = all ice) @@ -35,7 +35,7 @@ def _calculate(world, seed): # secondary constants temp_min = temperature.min() # coldest spot in the world - freeze_threshold = world.temperature['thresholds'][0][1] # upper temperature-limit for freezing effects + freeze_threshold = world.layers['temperature'].thresholds[0][1] # upper temperature-limit for freezing effects # Cold biomes: TODO: find and pick most appropriate threshold # polar: self.temperature['thresholds'][0][1] # alpine: self.temperature['thresholds'][1][1] diff --git a/worldengine/simulations/irrigation.py b/worldengine/simulations/irrigation.py index 5f2097db..03a379e7 100644 --- a/worldengine/simulations/irrigation.py +++ b/worldengine/simulations/irrigation.py @@ -44,7 +44,7 @@ def _calculate(world): logs_relevant = logs[tl_l[1]:br_l[1]+1, tl_l[0]:br_l[0]+1] #finish calculation - values[tl_v[1]:br_v[1]+1, tl_v[0]:br_v[0]+1] += world.watermap['data'][y, x] / logs_relevant + values[tl_v[1]:br_v[1]+1, tl_v[0]:br_v[0]+1] += world.layers['watermap'].data[y, x] / logs_relevant it_all.iternext() diff --git a/worldengine/simulations/precipitation.py b/worldengine/simulations/precipitation.py index 36e61d4d..86bf7ca7 100644 --- a/worldengine/simulations/precipitation.py +++ b/worldengine/simulations/precipitation.py @@ -65,13 +65,13 @@ def _calculate(seed, world): #find ranges min_precip = precipitations.min() max_precip = precipitations.max() - min_temp = world.temperature['data'].min() - max_temp = world.temperature['data'].max() + min_temp = world.layers['temperature'].min() + max_temp = world.layers['temperature'].max() precip_delta = (max_precip - min_precip) temp_delta = (max_temp - min_temp) #normalize temperature and precipitation arrays - t = (world.temperature['data'] - min_temp) / temp_delta + t = (world.layers['temperature'].data - min_temp) / temp_delta p = (precipitations - min_precip) / precip_delta #modify precipitation based on temperature From 027e4faecf4ab09bcfaca376d097ff9fa60ce93d Mon Sep 17 00:00:00 2001 From: Federico Tomassetti Date: Thu, 19 Nov 2015 22:58:32 +0100 Subject: [PATCH 8/8] draw: add ocean variable in get_normalized_elevation_array --- worldengine/draw.py | 9 +++++---- worldengine/drawing_functions.py | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/worldengine/draw.py b/worldengine/draw.py index 4ce555f3..e4aa7d84 100644 --- a/worldengine/draw.py +++ b/worldengine/draw.py @@ -236,20 +236,21 @@ def get_normalized_elevation_array(world): and return a numpy array of these values ''' e = world.layers['elevation'].data + ocean = world.layers['ocean'].data - mask = numpy.ma.array(e, mask=world.layers['ocean'].data) # only land + mask = numpy.ma.array(e, mask=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.layers['ocean'].data)) # only ocean + mask = numpy.ma.array(e, mask=numpy.logical_not(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.layers['ocean'].data)] = (e[numpy.invert(world.layers['ocean'].data)] - min_elev_land) * 127 / elev_delta_land + 128 - c[world.layers['ocean'].data] = (e[world.layers['ocean'].data] - min_elev_sea) * 127 / elev_delta_sea + c[numpy.invert(ocean)] = (e[numpy.invert(ocean)] - min_elev_land) * 127 / elev_delta_land + 128 + c[ocean] = (e[ocean] - min_elev_sea) * 127 / elev_delta_sea c = numpy.rint(c).astype(dtype=numpy.int32) # proper rounding return c diff --git a/worldengine/drawing_functions.py b/worldengine/drawing_functions.py index f0063d93..d3412738 100644 --- a/worldengine/drawing_functions.py +++ b/worldengine/drawing_functions.py @@ -82,7 +82,7 @@ def _find_outer_borders(world, factor, inner_borders): #scale ocean for y in range(world.height * factor): # TODO: numpy for x in range(world.width * factor): - if world.is_ocean(int(x / factor), int(y / factor)): + if world.is_ocean((int(x / factor), int(y / factor))): _ocean[y, x] = True def is_inner_border(pos):