Change root file path and added rectangle 2D to 3D

This commit is contained in:
NichiHachi
2024-06-15 21:40:19 +02:00
parent 8195396a04
commit fb00b927cb
13 changed files with 105 additions and 61 deletions

View File

@@ -1,8 +1,8 @@
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 import numpy as np
@@ -28,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)]
@@ -105,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):
@@ -115,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]:
@@ -138,8 +137,9 @@ class City:
""" """
roads = [] roads = []
for district in self.districts: for district in self.districts:
district.generate_roads(self.map_data) if district.type != "mountain":
roads.extend(district.roads) district.generate_roads(self.map_data)
roads.extend(district.roads)
return roads return roads
def point_in_which_district(self, point: Union[Position, tuple[int, int]]) -> int: def point_in_which_district(self, point: Union[Position, tuple[int, int]]) -> int:
@@ -164,16 +164,44 @@ class City:
array = np.array([[True if self.map_data[y][x] in district_id else False for x in range(len(self.map_data[0]))] 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))]) for y in range(len(self.map_data))])
image = Image.fromarray(array) image = Image.fromarray(array)
image.save('./data/mountain_map.png') image.save('./world_maker/data/mountain_map.png')
return image 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

@@ -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
@@ -216,7 +216,7 @@ class Skeleton:
def road_area(self, name: str, radius: int = 10) -> Image: def road_area(self, name: str, radius: int = 10) -> Image:
print("[Skeleton] Start mapping the road area...") print("[Skeleton] Start mapping the road area...")
heightmap = Image.open("data/heightmap.png") heightmap = Image.open("./world_maker/data/heightmap.png")
width, height = heightmap.size width, height = heightmap.size
road_area_map = Image.new("L", (width, height), 0) road_area_map = Image.new("L", (width, height), 0)
road_area_map_draw = ImageDraw.Draw(road_area_map) road_area_map_draw = ImageDraw.Draw(road_area_map)
@@ -236,7 +236,7 @@ class Skeleton:
circle_coords = (z - radius, x - radius, z + radius, x + radius) circle_coords = (z - radius, x - radius, z + radius, x + radius)
road_area_map_draw.ellipse(circle_coords, fill=255) road_area_map_draw.ellipse(circle_coords, fill=255)
road_area_map.save("data/"+name) road_area_map.save("./world_maker/data/"+name)
print("[Skeleton] Road area mapping completed.") print("[Skeleton] Road area mapping completed.")
return road_area_map return road_area_map

Binary file not shown.

Before

Width:  |  Height:  |  Size: 759 B

After

Width:  |  Height:  |  Size: 969 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -4,15 +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 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
@@ -181,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)
@@ -192,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
@@ -210,45 +211,45 @@ 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') -> Skeleton: 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) skeleton.road_area('skeleton_highway_area.png', 10)
return skeleton return skeleton
def skeleton_mountain_map(image: Union[str, Image] = './data/mountain_map.png') -> Skeleton: def skeleton_mountain_map(image: Union[str, Image] = './world_maker/data/mountain_map.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() skeleton.parse_graph()
heightmap_skeleton = skeleton.map() heightmap_skeleton = skeleton.map()
heightmap_skeleton.save('./data/skeleton_mountain.png') heightmap_skeleton.save('./world_maker/data/skeleton_mountain.png')
skeleton.road_area('skeleton_mountain_area.png',3) skeleton.road_area('skeleton_mountain_area.png',3)
return skeleton 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] = './data/sobelmap.png') -> Image: def detect_mountain(image: Union[str, Image] = './world_maker/data/sobelmap.png') -> Image:
image = handle_import_image(image) image = handle_import_image(image)
sobel = np.array(image) sobel = np.array(image)
pixels = sobel.reshape((-1, 1)) pixels = sobel.reshape((-1, 1))
@@ -272,3 +273,20 @@ def detect_mountain(image: Union[str, Image] = './data/sobelmap.png') -> Image:
print(f"[Data Analysis] The center of the mountain is at ({cX}, {cY})") print(f"[Data Analysis] The center of the mountain is at ({cX}, {cY})")
return (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')
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 += np.array(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):
@@ -27,7 +29,7 @@ class Bin:
best_spot_empty_area = empty_area best_spot_empty_area = empty_area
if best_spot is not None: if best_spot is not None:
self.rectangles.append((best_spot, (best_spot[0]+rectangle.width, best_spot[1]+rectangle.height))) self.rectangles.append((best_spot, (best_spot[0] + rectangle.width, best_spot[1] + rectangle.height)))
self.update_grid(rectangle, *best_spot) self.update_grid(rectangle, *best_spot)
return True return True
@@ -72,19 +74,16 @@ def pack_rectangles(rectangles, grid):
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:int = 25):
width = random.randint(10, max_width)
height = random.randint(10, max_width)
return Rectangle(width, height) return Rectangle(width, height)
def pack_rectangles(grid): def pack_rectangles(grid, min_width: int = 10, max_width: int = 25):
bin = Bin(grid) bin = Bin(grid)
while True: while True:
rectangle = generate_rectangle() rectangle = generate_rectangle(min_width, max_width)
if not bin.place_rectangle(rectangle): if not bin.place_rectangle(rectangle):
break break
print(len(bin.rectangles)) print(len(bin.rectangles))
@@ -101,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,6 +1,6 @@
import World import World
from PIL import Image from PIL import Image
from data_analysis import get_data,filter_negative, skeleton_mountain_map, highway_map, filter_sobel, skeleton_highway_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 smooth_sobel_water, subtract_map, detect_mountain
from City import City from City import City
from Position import Position from Position import Position
@@ -10,26 +10,24 @@ 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()
mountain_coo = detect_mountain() city.generate_district()
city.add_district(Position(mountain_coo[0], mountain_coo[1]), "mountain")
city.add_district(Position(200, 200), "zdz")
city.add_district(Position(300, 300), "cool")
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_mountain_map = city.get_district_mountain_map() image_mountain_map = city.get_district_mountain_map()
road = city.draw_roads(Image.new('RGB', (401, 401)), 4) road = city.draw_roads(4)
road.save('./data/roadmap.png') road.save('./world_maker/data/roadmap.png')
subtract_map(smooth_sobel_water, road).save('./data/roadmap2.png') subtract_map(smooth_sobel_water, road).save('./world_maker/data/city_map.png')
subtract_map('./data/roadmap2.png', './data/skeleton_highway_area.png').save('./data/roadmap2.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('./data/roadmap2.png', './data/mountain_map.png').save('./data/roadmap2.png') subtract_map('./world_maker/data/city_map.png', './world_maker/data/mountain_map.png').save('./world_maker/data/city_map.png')
generate_building('./data/roadmap2.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) skeleton_mountain_map(image_mountain_map)
subtract_map('./data/mountain_map.png','./data/skeleton_mountain_area.png').save('./data/mountain_map.png') 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('./data/mountain_map.png')).save('./data/mountain_map.png') subtract_map(smooth_sobel_water, filter_negative('./world_maker/data/mountain_map.png')).save('./world_maker/data/mountain_map.png')
generate_building('./data/mountain_map.png') rectangle_mountain = generate_building('./world_maker/data/mountain_map.png')