Merge pull request #9 from NichiHachi/main

Building generation and District "smart" spawn
This commit is contained in:
Xeon0X
2024-06-15 21:57:43 +02:00
committed by GitHub
22 changed files with 211 additions and 63 deletions

View File

@@ -1,9 +1,10 @@
from District import District, Road from District import District, Road
from Position import Position from Position import Position
from PIL import Image from PIL import Image
import random from random import randint
from data_analysis import handle_import_image from data_analysis import handle_import_image, detect_mountain
from typing import Union from typing import Union
import numpy as np
class City: class City:
@@ -27,8 +28,8 @@ class City:
""" """
Initialize the maps of the city. It reads the heightmap and watermap images and converts them into 2D lists. Initialize the maps of the city. It reads the heightmap and watermap images and converts them into 2D lists.
""" """
heightmap = Image.open('./data/heightmap.png').convert('L') heightmap = Image.open('./world_maker/data/heightmap.png').convert('L')
watermap = Image.open('./data/watermap.png').convert('L') watermap = Image.open('./world_maker/data/watermap.png').convert('L')
width, height = heightmap.size width, height = heightmap.size
self.map_data = [[-1 if watermap.getpixel((x, y)) > 0 else 0 for x in range(width)] for y in range(height)] self.map_data = [[-1 if watermap.getpixel((x, y)) > 0 else 0 for x in range(width)] for y in range(height)]
self.height_map = [[heightmap.getpixel((x, y)) for x in range(width)] for y in range(height)] self.height_map = [[heightmap.getpixel((x, y)) for x in range(width)] for y in range(height)]
@@ -104,7 +105,7 @@ class City:
""" """
width, height = len(self.map_data[0]), len(self.map_data) width, height = len(self.map_data[0]), len(self.map_data)
img = Image.new('RGB', (width, height)) img = Image.new('RGB', (width, height))
colors = {id_district: (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)) colors = {id_district: (randint(0, 255), randint(0, 255), randint(0, 255))
for id_district in range(1, len(self.districts) + 1)} for id_district in range(1, len(self.districts) + 1)}
for y in range(height): for y in range(height):
@@ -114,19 +115,18 @@ class City:
else: else:
img.putpixel((x, y), colors[self.map_data[y][x]]) img.putpixel((x, y), colors[self.map_data[y][x]])
img.save('./data/district.png') img.save('./world_maker/data/district.png')
print("[City] District map created.") print("[City] District map created.")
def draw_roads(self, image: Union[str, Image], size: int = 1) -> Image: def draw_roads(self, size_road: int = 1) -> Image:
""" """
Draw the roads of the city on the image. Draw the roads of the city on the image.
:param size: :param size:
:param image: The image to draw the roads on.
""" """
image = handle_import_image(image) image = Image.new('RGB', Image.open('./world_maker/data/heightmap.png').size)
for district in self.districts: for district in self.districts:
district.draw_roads(image, size) district.draw_roads(image, size_road)
return image return image
def district_generate_road(self) -> list[Road]: def district_generate_road(self) -> list[Road]:
@@ -137,17 +137,71 @@ class City:
""" """
roads = [] roads = []
for district in self.districts: for district in self.districts:
if district.type != "mountain":
district.generate_roads(self.map_data) district.generate_roads(self.map_data)
roads.extend(district.roads) roads.extend(district.roads)
return roads return roads
def point_in_which_district(self, point: Union[Position, tuple[int, int]]) -> int:
"""
Get the index of the district in which the point is located.
:param point: The point to check.
:return: The index of the district in which the point is located.
"""
if isinstance(point, Position):
point = (point.x, point.y)
return self.map_data[point[1]][point[0]]
def get_district_mountain_map(self) -> Image:
"""
Get the map of a district.
:param district_id: The id of the district.
:return: The map of the district.
"""
district_id = [district.tile_id for district in self.districts if district.type == "mountain"]
array = np.array([[True if self.map_data[y][x] in district_id else False for x in range(len(self.map_data[0]))]
for y in range(len(self.map_data))])
image = Image.fromarray(array)
image.save('./world_maker/data/mountain_map.png')
return image
def generate_district(self):
image = handle_import_image('./world_maker/data/smooth_sobel_watermap.png').convert('L')
array = np.array(image)
mountain_coo = detect_mountain()
self.add_district(Position(mountain_coo[0], mountain_coo[1]), "mountain")
print("[City] District added.")
remove_circle_data(array, mountain_coo)
area = get_area_array(array)
sizeX, sizeY = len(array[0]), len(array)
while area > sizeX * sizeY * 0.1:
x, y = randint(0, sizeX - 1), randint(0, sizeY - 1)
if array[y][x]:
self.add_district(Position(x, y))
remove_circle_data(array, (x, y))
area = get_area_array(array)
print("[City] District added.")
def remove_circle_data(array, center, radius=100):
y_indices, x_indices = np.indices(array.shape)
dist_sq = (y_indices - center[1]) ** 2 + (x_indices - center[0]) ** 2
mask = dist_sq <= radius ** 2
array[mask] = False
def get_area_array(array) -> int:
return np.sum(array)
if __name__ == '__main__': if __name__ == '__main__':
city = City() city = City()
for i in range(10): for i in range(10):
city.add_district(Position(random.randint(0, 400), random.randint(0, 400))) city.add_district(Position(randint(0, 400), randint(0, 400)))
city.loop_expend_district() city.loop_expend_district()
city.district_draw_map() city.district_draw_map()
city.district_generate_road() city.district_generate_road()
image = city.draw_roads(Image.new('RGB', (401, 401)), 4) image = city.draw_roads(Image.new('RGB', (401, 401)), 4)
image.save('./data/roadmap.png') image.save('./world_maker/data/roadmap.png')

View File

@@ -3,6 +3,7 @@ from typing import Union
from random import randint from random import randint
from PIL import Image from PIL import Image
class Road: class Road:
def __init__(self, position: Position, id_height: int, id_width: int, border: bool = False): def __init__(self, position: Position, id_height: int, id_width: int, border: bool = False):
self.position: Position = position self.position: Position = position
@@ -58,7 +59,7 @@ class District:
return (0 <= point_new.x < len(map_data[0]) and return (0 <= point_new.x < len(map_data[0]) and
0 <= point_new.y < len(map_data) and 0 <= point_new.y < len(map_data) and
map_data[point_new.y][point_new.x] == 0 and map_data[point_new.y][point_new.x] == 0 and
(self.type == "Mountain" or (self.type == "mountain" or
abs(height_map[point_new.y][point_new.x] - height_map[point.y][point.x]) < 2)) abs(height_map[point_new.y][point_new.x] - height_map[point.y][point.x]) < 2))
def is_point_inside(self, point: Position, map_data) -> bool: def is_point_inside(self, point: Position, map_data) -> bool:

View File

@@ -3,7 +3,7 @@ import numpy as np
from skimage.morphology import skeletonize from skimage.morphology import skeletonize
from skan.csr import skeleton_to_csgraph from skan.csr import skeleton_to_csgraph
from collections import Counter from collections import Counter
from PIL import Image from PIL import Image, ImageDraw
import random import random
@@ -158,7 +158,7 @@ class Skeleton:
# xzDistance = (max(buildRect.end[0], buildRect.begin[0]) - min(buildRect.end[0], buildRect.begin[0]), # xzDistance = (max(buildRect.end[0], buildRect.begin[0]) - min(buildRect.end[0], buildRect.begin[0]),
# max(buildRect.end[1], buildRect.begin[1]) - min(buildRect.end[1], buildRect.begin[1])) # max(buildRect.end[1], buildRect.begin[1]) - min(buildRect.end[1], buildRect.begin[1]))
heightmap = Image.open("data/heightmap.png").convert('RGB') heightmap = Image.open("./world_maker/data/heightmap.png").convert('RGB')
# roadsArea = Image.new("L", xzDistance, 0) # roadsArea = Image.new("L", xzDistance, 0)
# width, height = heightmap.size # width, height = heightmap.size
@@ -213,3 +213,30 @@ class Skeleton:
# ) # )
print("[Skeleton] Mapping completed.") print("[Skeleton] Mapping completed.")
return heightmap # , roadsArea return heightmap # , roadsArea
def road_area(self, name: str, radius: int = 10) -> Image:
print("[Skeleton] Start mapping the road area...")
heightmap = Image.open("./world_maker/data/heightmap.png")
width, height = heightmap.size
road_area_map = Image.new("L", (width, height), 0)
road_area_map_draw = ImageDraw.Draw(road_area_map)
# Lines
for i in range(len(self.lines)):
for j in range(len(self.lines[i])):
z = self.coordinates[self.lines[i][j]][0]
x = self.coordinates[self.lines[i][j]][2]
circle_coords = (z - radius, x - radius, z + radius, x + radius)
road_area_map_draw.ellipse(circle_coords, fill=255)
# Centers
for i in range(len(self.centers)):
z = self.coordinates[self.centers[i]][0]
x = self.coordinates[self.centers[i]][2]
circle_coords = (z - radius, x - radius, z + radius, x + radius)
road_area_map_draw.ellipse(circle_coords, fill=255)
road_area_map.save("./world_maker/data/"+name)
print("[Skeleton] Road area mapping completed.")
return road_area_map

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 696 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@@ -4,14 +4,16 @@ import numpy as np
from scipy import ndimage from scipy import ndimage
from Skeleton import Skeleton from Skeleton import Skeleton
from typing import Union from typing import Union
from random import randint
import cv2
def get_data(world: World): def get_data(world: World):
print("[Data Analysis] Generating data...") print("[Data Analysis] Generating data...")
heightmap, watermap, treemap = world.getData() heightmap, watermap, treemap = world.getData()
heightmap.save('./data/heightmap.png') heightmap.save('./world_maker/data/heightmap.png')
watermap.save('./data/watermap.png') watermap.save('./world_maker/data/watermap.png')
treemap.save('./data/treemap.png') treemap.save('./world_maker/data/treemap.png')
print("[Data Analysis] Data generated.") print("[Data Analysis] Data generated.")
return heightmap, watermap, treemap return heightmap, watermap, treemap
@@ -22,13 +24,14 @@ def handle_import_image(image: Union[str, Image]) -> Image:
return image return image
def filter_negative(image: Image) -> Image: def filter_negative(image: Union[str, Image]) -> Image:
""" """
Invert the colors of an image. Invert the colors of an image.
Args: Args:
image (image): image to filter image (image): image to filter
""" """
image = handle_import_image(image)
return Image.fromarray(np.invert(np.array(image))) return Image.fromarray(np.invert(np.array(image)))
@@ -179,9 +182,9 @@ def filter_remove_details(image: Union[str, Image], n: int = 20) -> Image:
def highway_map() -> Image: def highway_map() -> Image:
print("[Data Analysis] Generating highway map...") print("[Data Analysis] Generating highway map...")
smooth_sobel = filter_smooth("./data/sobelmap.png", 1) smooth_sobel = filter_smooth("./world_maker/data/sobelmap.png", 1)
negative_smooth_sobel = filter_negative(smooth_sobel) negative_smooth_sobel = filter_negative(smooth_sobel)
negative_smooth_sobel_water = subtract_map(negative_smooth_sobel, './data/watermap.png') negative_smooth_sobel_water = subtract_map(negative_smooth_sobel, './world_maker/data/watermap.png')
array_sobel_water = np.array(negative_smooth_sobel_water) array_sobel_water = np.array(negative_smooth_sobel_water)
array_sobel_water = ndimage.binary_erosion(array_sobel_water, iterations=12) array_sobel_water = ndimage.binary_erosion(array_sobel_water, iterations=12)
array_sobel_water = ndimage.binary_dilation(array_sobel_water, iterations=5) array_sobel_water = ndimage.binary_dilation(array_sobel_water, iterations=5)
@@ -190,7 +193,7 @@ def highway_map() -> Image:
array_sobel_water = filter_smooth_array(array_sobel_water, 6) array_sobel_water = filter_smooth_array(array_sobel_water, 6)
image = Image.fromarray(array_sobel_water) image = Image.fromarray(array_sobel_water)
image_no_details = filter_remove_details(image, 15) image_no_details = filter_remove_details(image, 15)
image_no_details.save('./data/highwaymap.png') image_no_details.save('./world_maker/data/highwaymap.png')
print("[Data Analysis] Highway map generated.") print("[Data Analysis] Highway map generated.")
return image_no_details return image_no_details
@@ -208,27 +211,82 @@ def create_volume(surface: np.ndarray, heightmap: np.ndarray, make_it_flat: bool
def convert_2D_to_3D(image: Union[str, Image], make_it_flat: bool = False) -> np.ndarray: def convert_2D_to_3D(image: Union[str, Image], make_it_flat: bool = False) -> np.ndarray:
image = handle_import_image(image) image = handle_import_image(image)
heightmap = Image.open('./data/heightmap.png').convert('L') heightmap = Image.open('./world_maker/data/heightmap.png').convert('L')
heightmap = np.array(heightmap) heightmap = np.array(heightmap)
surface = np.array(image) surface = np.array(image)
volume = create_volume(surface, heightmap, make_it_flat) volume = create_volume(surface, heightmap, make_it_flat)
return volume return volume
def skeleton_highway_map(image: Union[str, Image] = './data/highwaymap.png'): def skeleton_highway_map(image: Union[str, Image] = './world_maker/data/highwaymap.png') -> Skeleton:
image_array = convert_2D_to_3D(image, True) image_array = convert_2D_to_3D(image, True)
skeleton = Skeleton(image_array) skeleton = Skeleton(image_array)
skeleton.parse_graph(True) skeleton.parse_graph(True)
heightmap_skeleton = skeleton.map() heightmap_skeleton = skeleton.map()
heightmap_skeleton.save('./data/skeleton_highway.png') heightmap_skeleton.save('./world_maker/data/skeleton_highway.png')
skeleton.road_area('skeleton_highway_area.png', 10)
return skeleton
def skeleton_mountain_map(image: Union[str, Image] = './world_maker/data/mountain_map.png') -> Skeleton:
image_array = convert_2D_to_3D(image, True)
skeleton = Skeleton(image_array)
skeleton.parse_graph()
heightmap_skeleton = skeleton.map()
heightmap_skeleton.save('./world_maker/data/skeleton_mountain.png')
skeleton.road_area('skeleton_mountain_area.png', 3)
return skeleton
def smooth_sobel_water() -> Image: def smooth_sobel_water() -> Image:
watermap = handle_import_image("./data/watermap.png") watermap = handle_import_image("./world_maker/data/watermap.png")
watermap = filter_negative(filter_remove_details(filter_negative(watermap), 5)) watermap = filter_negative(filter_remove_details(filter_negative(watermap), 5))
sobel = handle_import_image("./data/sobelmap.png") sobel = handle_import_image("./world_maker/data/sobelmap.png")
sobel = filter_remove_details(filter_smooth(sobel, 1), 2) sobel = filter_remove_details(filter_smooth(sobel, 1), 2)
group = group_map(watermap, sobel) group = group_map(watermap, sobel)
group = filter_negative(group) group = filter_negative(group)
group.save('./data/smooth_sobel_watermap.png') group.save('./world_maker/data/smooth_sobel_watermap.png')
return group return group
def detect_mountain(image: Union[str, Image] = './world_maker/data/sobelmap.png') -> Image:
image = handle_import_image(image)
sobel = np.array(image)
pixels = sobel.reshape((-1, 1))
pixels = np.float32(pixels)
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 100, 0.2)
k = 3
_, labels, centers = cv2.kmeans(pixels, k, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS)
centers = np.uint8(centers)
segmented_image = centers[labels.flatten()]
segmented_image = segmented_image.reshape(sobel.shape)
mountain = segmented_image == segmented_image.max()
contours, _ = cv2.findContours(mountain.astype(np.uint8), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
max_contour = max(contours, key=cv2.contourArea)
M = cv2.moments(max_contour)
cX = int(M["m10"] / M["m00"])
cY = int(M["m01"] / M["m00"])
print(f"[Data Analysis] The center of the mountain is at ({cX}, {cY})")
return (cX, cY)
def rectangle_2D_to_3D(rectangle: list[tuple[tuple[int, int], tuple[int, int]]],
height_min: int = 6, height_max: int = 10) \
-> list[tuple[tuple[int, int, int], tuple[int, int, int]]]:
image = handle_import_image('./world_maker/data/heightmap.png').convert('L')
new_rectangle = []
for rect in rectangle:
start, end = rect
avg_height = 0
for x in range(start[0], end[0]):
for y in range(start[1], end[1]):
avg_height += image.getpixel((x, y))
avg_height = int(avg_height / ((end[0] - start[0]) * (end[1] - start[1])))
new_rectangle.append(
((start[0], avg_height, start[1]), (end[0], avg_height + randint(height_min, height_max), end[1])))
return new_rectangle

View File

@@ -2,6 +2,8 @@ from PIL import Image
import numpy as np import numpy as np
from typing import Union from typing import Union
from data_analysis import handle_import_image from data_analysis import handle_import_image
from random import randint
class Rectangle: class Rectangle:
def __init__(self, width, height): def __init__(self, width, height):
@@ -18,7 +20,7 @@ class Bin:
best_spot = None best_spot = None
best_spot_empty_area = float('inf') best_spot_empty_area = float('inf')
for i in range(len(self.grid[0]) - rectangle.width + 1): # Swap usage of x and y for i in range(len(self.grid[0]) - rectangle.width + 1):
for j in range(len(self.grid) - rectangle.height + 1): for j in range(len(self.grid) - rectangle.height + 1):
if self.can_place(rectangle, i, j): if self.can_place(rectangle, i, j):
empty_area = self.calculate_empty_area(rectangle, i, j) empty_area = self.calculate_empty_area(rectangle, i, j)
@@ -37,21 +39,21 @@ class Bin:
empty_area = 0 empty_area = 0
for rect_x in range(x, x + rectangle.width): for rect_x in range(x, x + rectangle.width):
for rect_y in range(y, y + rectangle.height): for rect_y in range(y, y + rectangle.height):
if self.grid[rect_y][rect_x]: # Swap usage of x and y if self.grid[rect_y][rect_x]:
empty_area += 1 empty_area += 1
return empty_area return empty_area
def can_place(self, rectangle, x, y): def can_place(self, rectangle, x, y):
for rect_x in range(x, x + rectangle.width): for rect_x in range(x, x + rectangle.width):
for rect_y in range(y, y + rectangle.height): for rect_y in range(y, y + rectangle.height):
if not self.grid[rect_y][rect_x]: # Swap usage of x and y if not self.grid[rect_y][rect_x]:
return False return False
return True return True
def update_grid(self, rectangle, x, y): def update_grid(self, rectangle, x, y):
for rect_x in range(x, x + rectangle.width): for rect_x in range(x, x + rectangle.width):
for rect_y in range(y, y + rectangle.height): for rect_y in range(y, y + rectangle.height):
self.grid[rect_y][rect_x] = False # Swap usage of x and y self.grid[rect_y][rect_x] = False
def pack_rectangles(rectangles, grid): def pack_rectangles(rectangles, grid):
@@ -62,36 +64,30 @@ def pack_rectangles(rectangles, grid):
for bin in bins: for bin in bins:
if bin.place_rectangle(rectangle): if bin.place_rectangle(rectangle):
break break
else: # No break, meaning rectangle couldn't be placed in any bin else:
new_bin = Bin(grid) new_bin = Bin(grid)
if new_bin.place_rectangle(rectangle): if new_bin.place_rectangle(rectangle):
bins.append(new_bin) bins.append(new_bin)
else: else:
return False # If a rectangle can't be placed even in a new bin, return False return False
return True # If all rectangles can be placed, return True return True
import random def generate_rectangle(min_width: int = 10, max_width: int = 25):
width = randint(min_width, max_width)
height = randint(min_width, max_width)
def generate_rectangle(max_width, max_height):
width = random.randint(6, 20)
height = random.randint(6, 20)
return Rectangle(width, height) return Rectangle(width, height)
def pack_rectangles(grid): def pack_rectangles(grid, min_width: int = 10, max_width: int = 25):
max_width = len(grid[0])
max_height = len(grid)
bin = Bin(grid) bin = Bin(grid)
while True: while True:
rectangle = generate_rectangle(max_width // 2, max_height // 2) rectangle = generate_rectangle(min_width, max_width)
if not bin.place_rectangle(rectangle): if not bin.place_rectangle(rectangle):
break # Stop when a rectangle can't be placed break
print(len(bin.rectangles)) print(len(bin.rectangles))
return bin.rectangles # Return the list of rectangles that were placed return bin.rectangles
def draw_rectangles(rectangles, grid): def draw_rectangles(rectangles, grid):
@@ -104,12 +100,13 @@ def draw_rectangles(rectangles, grid):
return image return image
def generate_building(image: Union[str, Image] = './data/roadmap2.png'): def generate_building(image: Union[str, Image], min_width: int = 10, max_width: int = 25):
image = handle_import_image(image).convert('L') image = handle_import_image(image).convert('L')
grid = np.array(image) grid = np.array(image)
rectangles = pack_rectangles(grid) rectangles = pack_rectangles(grid, min_width, max_width)
draw_rectangles(rectangles, grid).save('./data/building.png') draw_rectangles(rectangles, grid).save('./world_maker/data/building.png')
return rectangles return rectangles
if __name__ == '__main__': if __name__ == '__main__':
generate_building() generate_building()

View File

@@ -1,22 +1,33 @@
import World import World
from PIL import Image from PIL import Image
from data_analysis import get_data, highway_map, filter_sobel, skeleton_highway_map, smooth_sobel_water, subtract_map from data_analysis import get_data,filter_negative, rectangle_2D_to_3D, skeleton_mountain_map, highway_map, filter_sobel, skeleton_highway_map, \
smooth_sobel_water, subtract_map, detect_mountain
from City import City from City import City
from Position import Position from Position import Position
from random import randint from random import randint
from pack_rectangle import generate_building
if __name__ == '__main__': if __name__ == '__main__':
#world = World.World() #world = World.World()
#heightmap, watermap, treemap = get_data(world) #heightmap, watermap, treemap = get_data(world)
#filter_sobel("./data/heightmap.png").save('./data/sobelmap.png') #filter_sobel("./world_maker/data/heightmap.png").save('./world_maker/data/sobelmap.png')
smooth_sobel_water = smooth_sobel_water() smooth_sobel_water = smooth_sobel_water()
#skeleton_highway_map(highway_map()) skeleton_highway_map(highway_map())
city = City() city = City()
for i in range(10): city.generate_district()
city.add_district(Position(randint(0, 400), randint(0, 400)))
city.loop_expend_district() city.loop_expend_district()
city.district_draw_map() city.district_draw_map()
city.district_generate_road() city.district_generate_road()
road = city.draw_roads(Image.new('RGB', (401, 401)), 4) image_mountain_map = city.get_district_mountain_map()
road.save('./data/roadmap.png') road = city.draw_roads(4)
subtract_map(smooth_sobel_water, road).save('./data/roadmap2.png') road.save('./world_maker/data/roadmap.png')
subtract_map(smooth_sobel_water, road).save('./world_maker/data/city_map.png')
subtract_map('./world_maker/data/city_map.png', './world_maker/data/skeleton_highway_area.png').save('./world_maker/data/city_map.png')
subtract_map('./world_maker/data/city_map.png', './world_maker/data/mountain_map.png').save('./world_maker/data/city_map.png')
rectangle_building = generate_building('./world_maker/data/city_map.png')
rectangle_building = rectangle_2D_to_3D(rectangle_building)
skeleton_mountain_map(image_mountain_map)
subtract_map('./world_maker/data/mountain_map.png', './world_maker/data/skeleton_mountain_area.png').save('./world_maker/data/mountain_map.png')
subtract_map(smooth_sobel_water, filter_negative('./world_maker/data/mountain_map.png')).save('./world_maker/data/mountain_map.png')
rectangle_mountain = generate_building('./world_maker/data/mountain_map.png')