Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ numpy==1.9.2
Pillow==2.8.2
PyPlatec==1.4.0
protobuf==3.0.0a3
six==1.10.0
pypng==0.0.18
six==1.10.0
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
'entry_points': {
'console_scripts': ['worldengine=worldengine.cli.main:main'],
},
'install_requires': ['Pillow==2.8.2', 'PyPlatec==1.4.0',
'install_requires': ['Pillow==2.8.2', 'PyPlatec==1.4.0', 'pypng>=0.0.18',
'argparse==1.2.1', 'noise==1.2.2', 'protobuf>=2.6.0',
'numpy>=1.9.2'],
'license': 'MIT License'
Expand Down
13 changes: 7 additions & 6 deletions tests/astar_test.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import unittest
import numpy
from worldengine import astar
from worldengine.common import _equal


class TestCommon(unittest.TestCase):
Expand All @@ -11,13 +12,13 @@ def test_traversal(self):
line.fill(1.0)
test_map[10, :] = line
test_map[10, 18] = 0.0
path_data = [[0, 1], [0, 2], [0, 3], [0, 4], [0, 5], [0, 6], [0, 7], [0, 8], [0, 9],
[1, 9], [2, 9], [3, 9], [4, 9], [5, 9], [6, 9], [7, 9], [8, 9], [9, 9],
[10, 9], [11, 9], [12, 9], [13, 9], [14, 9], [15, 9], [16, 9], [17, 9],
[18, 9], [18, 10], [18, 11], [18, 12], [18, 13], [18, 14], [18, 15],
[18, 16], [18, 17], [18, 18], [18, 19], [19, 19]]
path_data = numpy.array([[0, 1], [0, 2], [0, 3], [0, 4], [0, 5], [0, 6], [0, 7], [0, 8], [0, 9],
[1, 9], [2, 9], [3, 9], [4, 9], [5, 9], [6, 9], [7, 9], [8, 9], [9, 9],
[10, 9], [11, 9], [12, 9], [13, 9], [14, 9], [15, 9], [16, 9], [17, 9],
[18, 9], [18, 10], [18, 11], [18, 12], [18, 13], [18, 14], [18, 15],
[18, 16], [18, 17], [18, 18], [18, 19], [19, 19]])
shortest_path = astar.PathFinder().find(test_map, [0, 0], [19, 19])
self.assertEqual(path_data, shortest_path)
self.assertTrue(_equal(path_data, numpy.array(shortest_path)))

if __name__ == '__main__':
unittest.main()
9 changes: 5 additions & 4 deletions tests/common_test.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import unittest
import numpy
from worldengine.common import Counter, anti_alias, array_to_matrix, get_verbose, \
matrix_min_and_max, rescale_value, set_verbose

Expand Down Expand Up @@ -59,14 +60,14 @@ def test_rescale_value(self):
self.assertAlmostEqual(10.0, rescale_value(1.0, 0.0, 1.0, -10.0, 10.0))

def test_antialias(self):
original = [[0.5, 0.12, 0.7, 0.15, 0.0],
[0.0, 0.12, 0.7, 0.7, 8.0],
[0.2, 0.12, 0.7, 0.7, 4.0]]
original = numpy.array([[0.5, 0.12, 0.7, 0.15, 0.0],
[0.0, 0.12, 0.7, 0.7, 8.0],
[0.2, 0.12, 0.7, 0.7, 4.0]])
antialiased = anti_alias(original, 1)
self.assertAlmostEquals(1.2781818181818183, antialiased[0][0])
self.assertAlmostEquals(0.4918181818181818, antialiased[1][2])

original = [[0.8]]
original = numpy.array([[0.8]])
antialiased = anti_alias(original, 10)
self.assertAlmostEquals(0.8, antialiased[0][0])

Expand Down
65 changes: 29 additions & 36 deletions tests/serialization_test.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,9 @@
import unittest
from worldengine.plates import Step, world_gen
from worldengine.world import World
from worldengine.common import _equal
import tempfile
import os
import numpy


def _sort(l):
l2 = l
l2.sort()
return l2


class TestSerialization(unittest.TestCase):

Expand All @@ -23,48 +16,48 @@ def test_pickle_serialize_unserialize(self):
w.to_pickle_file(f)
unserialized = World.from_pickle_file(f)
os.remove(f)
self.assertEqual(w.elevation['data'], unserialized.elevation['data'])
self.assertTrue(_equal(w.elevation['data'], unserialized.elevation['data']))
self.assertEqual(w.elevation['thresholds'], unserialized.elevation['thresholds'])
self.assertEqual(w.ocean, unserialized.ocean)
self.assertEqual(w.biome, unserialized.biome)
self.assertEqual(w.humidity, unserialized.humidity)
self.assertTrue(numpy.array_equiv(w.irrigation, unserialized.irrigation))
self.assertEqual(w.permeability, unserialized.permeability)
self.assertEqual(w.watermap, unserialized.watermap)
self.assertEqual(w.precipitation, unserialized.precipitation)
self.assertEqual(w.temperature, unserialized.temperature)
self.assertEqual(w.sea_depth, unserialized.sea_depth)
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))
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))
self.assertTrue(_equal(w.sea_depth, unserialized.sea_depth))
self.assertEquals(w.seed, unserialized.seed)
self.assertEquals(w.n_plates, unserialized.n_plates)
self.assertEquals(w.ocean_level, unserialized.ocean_level)
self.assertEquals(w.lake_map, unserialized.lake_map)
self.assertEquals(w.river_map, unserialized.river_map)
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.assertEquals(w.step, unserialized.step)
self.assertEqual(_sort(dir(w)), _sort(dir(unserialized)))
self.assertEqual(sorted(dir(w)), sorted(dir(unserialized)))
self.assertEqual(w, unserialized)

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.elevation['data'], unserialized.elevation['data'])
self.assertTrue(_equal(w.elevation['data'], unserialized.elevation['data']))
self.assertEqual(w.elevation['thresholds'], unserialized.elevation['thresholds'])
self.assertEqual(w.ocean, unserialized.ocean)
self.assertEqual(w.biome, unserialized.biome)
self.assertEqual(w.humidity, unserialized.humidity)
self.assertTrue(numpy.array_equiv(w.irrigation, unserialized.irrigation))
self.assertEqual(w.permeability, unserialized.permeability)
self.assertEqual(w.watermap, unserialized.watermap)
self.assertEqual(w.precipitation, unserialized.precipitation)
self.assertEqual(w.temperature, unserialized.temperature)
self.assertEqual(w.sea_depth, unserialized.sea_depth)
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))
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))
self.assertTrue(_equal(w.sea_depth, unserialized.sea_depth))
self.assertEquals(w.seed, unserialized.seed)
self.assertEquals(w.n_plates, unserialized.n_plates)
self.assertEquals(w.ocean_level, unserialized.ocean_level)
self.assertEquals(w.lake_map, unserialized.lake_map)
self.assertEquals(w.river_map, unserialized.river_map)
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.assertEquals(w.step, unserialized.step)
self.assertEqual(_sort(dir(w)), _sort(dir(unserialized)))
self.assertEqual(sorted(dir(w)), sorted(dir(unserialized)))
self.assertEqual(w, unserialized)


Expand Down
1 change: 1 addition & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ deps =
nose
protobuf
six
pypng

[testenv]
deps =
Expand Down
14 changes: 2 additions & 12 deletions worldengine/astar.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,6 @@ def get_node(self, location):
if x < 0 or x >= self.w or y < 0 or y >= self.h:
return None
d = self.m[(y * self.w) + x]

return Node(location, d, ((y * self.w) + x))

def get_adjacent_nodes(self, cur_node, destination):
Expand Down Expand Up @@ -198,14 +197,6 @@ def _handle_node(self, x, y, from_node, destination_x, destination_y):
return None


def _matrix_to_array(matrix):
array = []
for row in matrix:
for cell in row:
array.append(cell)
return array


class PathFinder:
"""Using the a* algorithm we will try to find the best path between two
points.
Expand All @@ -219,10 +210,9 @@ def find(height_map, source, destination):
sx, sy = source
dx, dy = destination
path = []
width = len(height_map[0])
height = len(height_map)
height, width = height_map.shape

graph = _matrix_to_array(height_map) # flatten array
graph = height_map.flatten('C') #flatten array (row-major)

pathfinder = AStar(SQMapHandler(graph, width, height))
start = SQLocation(sx, sy)
Expand Down
2 changes: 1 addition & 1 deletion worldengine/biome.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,6 @@ def biome_name_to_index(biome_name):

def biome_index_to_name(biome_index):
names = sorted(_BiomeMetaclass.biomes.keys())
if biome_index < 0 or biome_index >= len(names):
if not 0 <= biome_index < len(names):
raise Exception("Not found")
return names[biome_index]
10 changes: 7 additions & 3 deletions worldengine/cli/main.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import sys
from argparse import ArgumentParser
import os
import numpy
import pickle
import random
import worldengine.generation as geo
Expand Down Expand Up @@ -95,7 +96,7 @@ def generate_plates(seed, world_name, output_dir, width, height,
num_plates=num_plates)

world = World(world_name, width, height, seed, num_plates, -1.0, "plates")
world.set_elevation(array_to_matrix(elevation, width, height), None)
world.set_elevation(numpy.array(elevation).reshape(height, width), None)
world.set_plates(array_to_matrix(plates, width, height))

# Generate images
Expand Down Expand Up @@ -341,7 +342,8 @@ def main():
export_options = parser.add_argument_group(
"Export Options", "You can specify the formats you wish the generated output to be in. ")
export_options.add_argument("--export-type", dest="export_type",
help="Export to a specific format such as: BMP or PNG",
help="Export to a specific format such as: BMP or PNG" +
"See http://www.gdal.org/formats_list.html for possible formats.",
default="bmp")
export_options.add_argument("--export-bpp", dest="export_bpp", type=int,
help="Bits per pixel: 8, 16 and 32",
Expand Down Expand Up @@ -448,6 +450,7 @@ def main():
seed, args.number_of_plates, args.output_dir,
step, args.ocean_level, world_format,
args.verbose, black_and_white=args.black_and_white)

if args.grayscale_heightmap:
generate_grayscale_heightmap(world,
'%s/%s_grayscale.png' % (args.output_dir, world_name))
Expand Down Expand Up @@ -493,7 +496,8 @@ def main():
elif operation == 'export':
world = load_world(args.FILE)
print_world_info(world)
export(world, args.export_type, args.export_bpp, args.export_signed, args.export_normalize)
export(world, args.export_type, args.export_bpp, args.export_signed,
path = '%s/%s_elevation' % (args.output_dir, world_name))
else:
raise Exception(
'Unknown operation: valid operations are %s' % OPERATIONS)
Expand Down
46 changes: 38 additions & 8 deletions worldengine/common.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import sys
import copy
import numpy #for the _equal method only

# ----------------
# Global variables
Expand Down Expand Up @@ -80,32 +81,31 @@ def rescale_value(original, prev_min, prev_max, min, max):
return min + ((max - min) * f)


def anti_alias(elevation, steps):
def anti_alias(map, steps):#TODO: There is probably a bit of numpy-optimization that can be done here.
"""
Execute the anti_alias operation steps times on the given elevation map
Execute the anti_alias operation steps times on the given map
"""
width = len(elevation[0])
height = len(elevation)
height, width = map.shape

def _anti_alias_step(original):
anti_aliased = copy.deepcopy(original)
for y in range(height):
for x in range(width):
anti_aliased[y][x] = anti_alias_point(original, x, y)
anti_aliased[y, x] = anti_alias_point(original, x, y)
return anti_aliased

def anti_alias_point(original, x, y):
n = 2
tot = elevation[y][x] * 2
tot = map[y, x] * 2
for dy in range(-1, +2):
py = (y + dy) % height
for dx in range(-1, +2):
px = (x + dx) % width
n += 1
tot += original[py][px]
tot += original[py, px]
return tot / n

current = elevation
current = map
for i in range(steps):
current = _anti_alias_step(current)
return current
Expand All @@ -120,3 +120,33 @@ def array_to_matrix(array, width, height):
for x in range(width):
matrix[y].append(array[y * width + x])
return matrix

def _equal(a, b):
#recursion on subclasses of types: tuple, list, dict
#specifically checks : float, ndarray
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The _equal code doesn't seem to be used by the WE library. Can this be moved __init__.py in tests?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is also used as World.operator== - I am not sure if there are any world-comparisons in the code outside of the tests. But I guess it is worth a try and the code can be moved, yes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On second thought the removal would leave the world-class without a functioning equality-operator. At the same time it is not only usable for that class... I wouldn't feel good about moving this to the tests, I prefer it here. (I found quite a lot of functions spread over various files that are never called or even referenced... maybe it is time for a bit of cleanup, though.)

if type(a) is float and type(b) is float:#float
return(numpy.allclose(a, b))
elif type(a) is numpy.ndarray and type(b) is numpy.ndarray:#ndarray
return(numpy.array_equiv(a, b))#alternative for float-arrays: numpy.allclose(a, b[, rtol, atol])
elif isinstance(a, dict) and isinstance(b, dict):#dict
if len(a) != len(b):
return(False)
t = True
for key, val in a.items():
if key not in b:
return(False)
t = _equal(val, b[key])
if not t:
return(False)
return(t)
elif (isinstance(a, list) and isinstance(b, list)) or (isinstance(a, tuple) and isinstance(b, tuple)):#list, tuples
if len(a) != len(b):
return(False)
t = True
for vala, valb in zip(a, b):
t = _equal(vala, valb)
if not t:
return(False)
return(t)
else:#fallback
return(a == b)
Loading