Add grid generation
50
main.py
@@ -3,17 +3,23 @@ import random
|
||||
import gdpc.exceptions
|
||||
|
||||
from world_maker.world_maker import *
|
||||
from world_maker.Skeleton import Skeleton, transpose_form_heightmap, simplify_coordinates
|
||||
from networks.geometry.Point3D import Point3D
|
||||
from networks.roads_2.Road import Road
|
||||
from world_maker.District import Road as Road_grid
|
||||
from House import *
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
rectangle_house_mountain, rectangle_building, skeleton_highway, skeleton_mountain = world_maker()
|
||||
rectangle_house_mountain, rectangle_building, skeleton_highway, skeleton_mountain, road_grid = world_maker()
|
||||
|
||||
editor = Editor(buffering=True)
|
||||
buildArea = editor.getBuildArea()
|
||||
|
||||
print(skeleton_mountain.lines)
|
||||
set_roads(skeleton_mountain)
|
||||
set_roads(skeleton_highway)
|
||||
set_roads_grids(road_grid)
|
||||
|
||||
blocks = {
|
||||
"wall": "blackstone",
|
||||
@@ -43,6 +49,46 @@ def main():
|
||||
house.build()
|
||||
|
||||
|
||||
def set_roads_grids(road_grid: Road_grid):
|
||||
for i in range(len(road_grid)):
|
||||
if road_grid[i].border:
|
||||
for j in range(len(road_grid)):
|
||||
# Same line
|
||||
if (road_grid[i].position.x == road_grid[j].position.x and road_grid[i].position.y != road_grid[j].position.y) or (road_grid[i].position.x != road_grid[j].position.x and road_grid[i].position.y == road_grid[j].position.y):
|
||||
point_1 = transpose_form_heightmap(
|
||||
'./world_maker/data/heightmap.png', (road_grid[i].position.x, road_grid[i].position.y))
|
||||
point_2 = transpose_form_heightmap(
|
||||
'./world_maker/data/heightmap.png', (road_grid[j].position.x, road_grid[j].position.y))
|
||||
Road(
|
||||
[Point3D(point_1[0], point_1[1], point_1[2]), Point3D(point_2[0], point_2[1], point_2[2])], 9)
|
||||
|
||||
|
||||
def set_roads(skeleton: Skeleton):
|
||||
# Parsing
|
||||
print("[Roads] Start parsing...")
|
||||
for i in range(len(skeleton.lines)):
|
||||
print(f"[Roads] Parsing skeleton {i+1}/{len(skeleton.lines)}.")
|
||||
for j in range(len(skeleton.lines[i])):
|
||||
xyz = transpose_form_heightmap('./world_maker/data/heightmap.png',
|
||||
skeleton.coordinates[skeleton.lines[i][j]])
|
||||
skeleton.lines[i][j] = xyz
|
||||
|
||||
print("[Roads] Start simplification...")
|
||||
# Simplification
|
||||
for i in range(len(skeleton.lines)):
|
||||
print(f"[Roads] Simplify skelton {i+1}/{len(skeleton.lines)}")
|
||||
skeleton.lines[i] = simplify_coordinates(skeleton.lines[i], 10)
|
||||
|
||||
print("[Roads] Start generation...")
|
||||
for i in range(len(skeleton.lines)):
|
||||
print(f"[Roads] Generating roads {i+1}/{len(skeleton.lines)}.")
|
||||
if len(skeleton.lines[i]) >= 4:
|
||||
Road(Point3D.from_arrays(skeleton.lines[i]), 25)
|
||||
else:
|
||||
print(
|
||||
f"[Roads] Ignore roads {i+1} with {len(skeleton.lines[i])} coordinates between {skeleton.lines[i][1]} and {skeleton.lines[i][-1]}.")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
|
||||
@@ -28,6 +28,9 @@ class Polyline:
|
||||
self.length_polyline = len(self.points_array)
|
||||
|
||||
if self.length_polyline < 4:
|
||||
print(self.length_polyline)
|
||||
print(self.points_array)
|
||||
print(self.output_points)
|
||||
raise ValueError("The list must contain at least 4 elements.")
|
||||
|
||||
self.vectors = [None] * self.length_polyline # v
|
||||
|
||||
@@ -22,6 +22,8 @@ class Segment3D:
|
||||
|
||||
>>> Segment3D(Point3D(0, 0, 0), Point3D(10, 10, 15))
|
||||
"""
|
||||
start = self.start.copy()
|
||||
end = self.end.copy()
|
||||
self.output_points.append(start.copy())
|
||||
dx = abs(self.end.x - self.start.x)
|
||||
dy = abs(self.end.y - self.start.y)
|
||||
|
||||
@@ -4,6 +4,8 @@ from networks.geometry.Polyline import Polyline
|
||||
|
||||
from networks.geometry.Point3D import Point3D
|
||||
from networks.geometry.Point2D import Point2D
|
||||
from networks.geometry.Segment2D import Segment2D
|
||||
from networks.geometry.Segment3D import Segment3D
|
||||
from networks.geometry.Circle import Circle
|
||||
from Enums import LINE_THICKNESS_MODE
|
||||
from gdpc import Block, Editor
|
||||
@@ -11,21 +13,45 @@ from gdpc import Block, Editor
|
||||
|
||||
class Road:
|
||||
def __init__(self, coordinates: List[Point3D], width: int):
|
||||
self.coordinates = coordinates
|
||||
self.coordinates = self._remove_collinear_points(coordinates)
|
||||
self.output_block = []
|
||||
# with open(road_configuration) as f:
|
||||
# self.road_configuration = json.load(f)
|
||||
# self.width = self.road_configuration["width"]
|
||||
self.width = width
|
||||
self.polyline_height = None
|
||||
self.polyline_total_line_output = None
|
||||
self.segment_total_line_output = None
|
||||
self.index_factor = 0
|
||||
|
||||
if len(self._remove_collinear_points(self.coordinates)) >= 4:
|
||||
self.polyline = Polyline(Point3D.to_2d(coordinates, 'y'))
|
||||
self.polyline_total_line_output = [
|
||||
[] for _ in range(len(self.polyline.total_line_output))]
|
||||
self.index_factor = 0
|
||||
|
||||
self._projection()
|
||||
self._surface()
|
||||
self._projection_polyline()
|
||||
|
||||
if len(self.coordinates) == 2:
|
||||
self.segment_total_line_output = Segment2D(
|
||||
Point3D.to_2d([self.coordinates[0]], 'y')[0], Point3D.to_2d([self.coordinates[1]], 'y')[0]).segment_thick(self.width, LINE_THICKNESS_MODE.MIDDLE)
|
||||
self._projection_segment()
|
||||
self.place()
|
||||
|
||||
@staticmethod
|
||||
def _remove_collinear_points(points):
|
||||
output_points = [points[0]]
|
||||
|
||||
for i in range(1, len(points) - 1):
|
||||
if isinstance(points[0], Point3D):
|
||||
if not Point2D.collinear(
|
||||
Point3D.to_2d([points[i-1]], 'y')[0], Point3D.to_2d([points[i]], 'y')[0], Point3D.to_2d([points[i+1]], 'y')[0]):
|
||||
output_points.append(points[i])
|
||||
else:
|
||||
if not Point2D.collinear(points[i-1], points[i], points[i+1]):
|
||||
output_points.append(points[i])
|
||||
|
||||
output_points.append(points[-1])
|
||||
return output_points
|
||||
|
||||
def _surface(self):
|
||||
# Segments
|
||||
@@ -60,7 +86,7 @@ class Road:
|
||||
(Point3D.insert_3d([circle.points_thick[j]], 'y', [
|
||||
self.polyline_total_line_output[nearest[0]].y])[0].coordinates, Block("white_concrete")))
|
||||
|
||||
def _projection(self):
|
||||
def _projection_polyline(self):
|
||||
nearest_points_to_reference = []
|
||||
for i in range(len(self.coordinates)):
|
||||
# nearest_points_to_reference.append(Point3D.insert_3d([Point3D.to_2d([self.coordinates[i]], 'y')[0].nearest(
|
||||
@@ -70,6 +96,7 @@ class Road:
|
||||
nearest_points_to_reference.append(
|
||||
Point2D(index, self.coordinates[i].y))
|
||||
|
||||
if len(self._remove_collinear_points(nearest_points_to_reference)) >= 4:
|
||||
self.polyline_height = Polyline(nearest_points_to_reference)
|
||||
|
||||
self.index_factor = len(
|
||||
@@ -79,8 +106,20 @@ class Road:
|
||||
self.polyline_total_line_output[i] = Point3D(
|
||||
self.polyline.total_line_output[i].x, self.polyline_height.total_line_output[round(i*self.index_factor)].y, self.polyline.total_line_output[i].y)
|
||||
|
||||
self.polyline_total_line_output = self.polyline_total_line_output[0].optimized_path(
|
||||
self.polyline_total_line_output)
|
||||
self._surface()
|
||||
self.place()
|
||||
# self.polyline_total_line_output = self.polyline_total_line_output[0].optimized_path(
|
||||
# self.polyline_total_line_output)
|
||||
|
||||
def _projection_segment(self):
|
||||
s = Segment3D(
|
||||
self.coordinates[0], self.coordinates[1])
|
||||
|
||||
reference = s.segment()
|
||||
|
||||
for i in range(len(self.segment_total_line_output)):
|
||||
self.output_block.append(((
|
||||
self.segment_total_line_output[i].x, reference[self.segment_total_line_output[i].nearest(Point3D.to_2d(reference, 'y'), True)[0]].y, self.segment_total_line_output[i].y), Block("black_concrete")))
|
||||
|
||||
def place(self):
|
||||
editor = Editor(buffering=True)
|
||||
@@ -3,11 +3,11 @@ from collections import Counter
|
||||
from typing import List, Union
|
||||
|
||||
import numpy as np
|
||||
from gdpc import Editor
|
||||
from PIL import Image, ImageDraw
|
||||
from skan.csr import skeleton_to_csgraph
|
||||
from skimage.morphology import skeletonize
|
||||
|
||||
from gdpc import Editor
|
||||
from networks.geometry.Point3D import Point3D
|
||||
|
||||
|
||||
def handle_import_image(image: Union[str, Image]) -> Image:
|
||||
@@ -16,6 +16,51 @@ def handle_import_image(image: Union[str, Image]) -> Image:
|
||||
return image
|
||||
|
||||
|
||||
def transpose_form_heightmap(heightmap: Union[str, Image], coordinates):
|
||||
heightmap = handle_import_image(heightmap).convert('L')
|
||||
|
||||
editor = Editor()
|
||||
xMin = (editor.getBuildArea().begin).x
|
||||
zMin = (editor.getBuildArea().begin).z
|
||||
|
||||
return (coordinates[0] + xMin, heightmap.getpixel(
|
||||
(coordinates[0], coordinates[-1])), coordinates[-1] + zMin)
|
||||
|
||||
|
||||
def simplify_coordinates(coordinates, epsilon):
|
||||
if len(coordinates) < 3:
|
||||
return coordinates
|
||||
|
||||
# Find the point with the maximum distance
|
||||
max_distance = 0
|
||||
max_index = 0
|
||||
end_index = len(coordinates) - 1
|
||||
|
||||
for i in range(1, end_index):
|
||||
distance = Point3D(coordinates[i][0], coordinates[i][1], coordinates[i][2]).distance(
|
||||
Point3D(coordinates[0][0], coordinates[0][1], coordinates[0][2]))
|
||||
if distance > max_distance:
|
||||
max_distance = distance
|
||||
max_index = i
|
||||
|
||||
simplified_coordinates = []
|
||||
|
||||
# If the maximum distance is greater than epsilon, recursively simplify
|
||||
if max_distance > epsilon:
|
||||
rec_results1 = simplify_coordinates(coordinates[:max_index+1], epsilon)
|
||||
rec_results2 = simplify_coordinates(coordinates[max_index:], epsilon)
|
||||
|
||||
# Combine the simplified sub-results
|
||||
simplified_coordinates.extend(rec_results1[:-1])
|
||||
simplified_coordinates.extend(rec_results2)
|
||||
else:
|
||||
# The maximum distance is less than epsilon, retain the endpoints
|
||||
simplified_coordinates.append(coordinates[0])
|
||||
simplified_coordinates.append(coordinates[end_index])
|
||||
|
||||
return simplified_coordinates
|
||||
|
||||
|
||||
class Skeleton:
|
||||
def __init__(self, data: np.ndarray = None):
|
||||
self.lines = []
|
||||
@@ -26,19 +71,6 @@ class Skeleton:
|
||||
if data is not None:
|
||||
self.set_skeleton(data)
|
||||
|
||||
def transpose_form_heightmap(heightmap: Union[str, Image], coordinates):
|
||||
|
||||
heightmap = handle_import_image(heightmap).convert('L')
|
||||
|
||||
editor = Editor()
|
||||
xMin = (editor.getBuildArea().begin).x
|
||||
zMin = (editor.getBuildArea().begin).z
|
||||
|
||||
coordinates_final = []
|
||||
|
||||
return coordinates_final(coordinates[0] + xMin, heightmap.getpixel(
|
||||
(coordinates[0], coordinates[2]))[0], coordinates[2] + zMin)
|
||||
|
||||
def set_skeleton(self, data: np.ndarray):
|
||||
print("[Skeleton] Start skeletonization...")
|
||||
binary_skeleton = skeletonize(data, method="lee")
|
||||
|
||||
|
Before Width: | Height: | Size: 396 B After Width: | Height: | Size: 344 B |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 5.6 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 707 B After Width: | Height: | Size: 843 B |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 750 B After Width: | Height: | Size: 876 B |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 900 B After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 813 B |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 2.4 KiB |
@@ -1,35 +1,43 @@
|
||||
from world_maker.World import World
|
||||
from PIL import Image
|
||||
from world_maker.data_analysis import (get_data,filter_negative, rectangle_2D_to_3D, skeleton_mountain_map, highway_map, filter_sobel, skeleton_highway_map, \
|
||||
from world_maker.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 world_maker.City import City
|
||||
from world_maker.Position import Position
|
||||
from random import randint
|
||||
from world_maker.pack_rectangle import generate_building
|
||||
|
||||
|
||||
def world_maker():
|
||||
world = World()
|
||||
heightmap, watermap, treemap = get_data(world)
|
||||
filter_sobel("./world_maker/data/heightmap.png").save('./world_maker/data/sobelmap.png')
|
||||
filter_sobel(
|
||||
"./world_maker/data/heightmap.png").save('./world_maker/data/sobelmap.png')
|
||||
smooth_sobel_water_map = smooth_sobel_water()
|
||||
skeleton_highway = skeleton_highway_map(highway_map())
|
||||
city = City()
|
||||
city.generate_district()
|
||||
city.loop_expend_district()
|
||||
city.district_draw_map()
|
||||
city.district_generate_road()
|
||||
road_grid = city.district_generate_road()
|
||||
image_mountain_map = city.get_district_mountain_map()
|
||||
road = city.draw_roads(4)
|
||||
road.save('./world_maker/data/roadmap.png')
|
||||
subtract_map(smooth_sobel_water_map, 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')
|
||||
subtract_map(smooth_sobel_water_map, 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 = 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_map, 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')
|
||||
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_map, 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')
|
||||
rectangle_mountain = rectangle_2D_to_3D(rectangle_mountain)
|
||||
return rectangle_mountain, rectangle_building, skeleton_highway, skeleton_mountain
|
||||
return rectangle_mountain, rectangle_building, skeleton_highway, skeleton_mountain, road_grid
|
||||
|
||||