From e6d66cc18ec92a983e3086c8b40ed50d32613a7d Mon Sep 17 00:00:00 2001 From: KAymeric Date: Wed, 15 May 2024 23:17:55 +0200 Subject: [PATCH 01/17] start windows --- buildings/Building.py | 2 +- buildings/Facade.py | 35 +++++++++++++++---- buildings/Foundations.py | 11 +++--- buildings/elements/Window.py | 60 +++++++++++++++++++++++++++++++-- buildings/geometry/Polygon.py | 4 +-- buildings/geometry/Rectangle.py | 7 ++-- buildings/geometry/Tile.py | 2 +- buildings/geometry/Vertice.py | 4 +-- main.py | 41 +++++++++++++++++----- params.yml | 37 +++++++++++++++++++- requirements.txt | 1 + Enums.py => utils/Enums.py | 1 + utils/JsonReader.py | 11 ++++++ utils/YamlReader.py | 11 ++++++ 14 files changed, 195 insertions(+), 32 deletions(-) rename Enums.py => utils/Enums.py (92%) create mode 100644 utils/JsonReader.py create mode 100644 utils/YamlReader.py diff --git a/buildings/Building.py b/buildings/Building.py index befeb87..5a7b740 100644 --- a/buildings/Building.py +++ b/buildings/Building.py @@ -1,5 +1,5 @@ import random as rd -from Enums import COLLUMN_STYLE +from utils.Enums import COLLUMN_STYLE from buildings.Foundations import Foundations from buildings.Facade import Facade diff --git a/buildings/Facade.py b/buildings/Facade.py index 25b07ad..a4bddce 100644 --- a/buildings/Facade.py +++ b/buildings/Facade.py @@ -1,23 +1,46 @@ -from Enums import COLLUMN_STYLE +import random as rd +from utils.Enums import COLLUMN_STYLE, DIRECTION +from gdpc import Editor from buildings.geometry.Vertice import Vertice from buildings.geometry.Rectangle import Rectangle from buildings.elements.Window import Window class Facade: - def __init__(self, vertices : list[Vertice], height : int, is_inner_or_outer : COLLUMN_STYLE): + def __init__(self, rdata, vertices : list[Vertice], height : int, lenght : int, is_inner_or_outer : COLLUMN_STYLE): + self.rdata = rdata self.vertices = vertices self.is_inner_or_outer = is_inner_or_outer self.height = height + self.lenght = lenght self.window_size = self.get_window_size() self.window = self.get_window() self.has_balcony = self.has_balcony() self.has_inter_floor = self.has_inter_floor() - def build_facade(self): - pass + def build(self, editor : Editor, materials : list[str], y : int): + padding = 0 + if self.is_inner_or_outer == COLLUMN_STYLE.OUTER or self.is_inner_or_outer == COLLUMN_STYLE.BOTH: + padding = 1 + + for vertice in self.vertices: + xpadding, zpadding = 0, 0 + if vertice.facing == DIRECTION.NORTH or vertice.facing == DIRECTION.SOUTH: + xpadding = padding + else: zpadding = padding + + vertice.fill(editor, materials[0], y, y + self.height, xpadding = xpadding, zpadding = zpadding) + self.window.build(editor, vertice, self.height, y, materials) def get_window_size(self) -> tuple[int,int]: - pass + max_width = self.lenght + max_height = min(self.height, self.rdata["windows"]["size"]["max_height"]) + if self.is_inner_or_outer == COLLUMN_STYLE.OUTER or self.is_inner_or_outer == COLLUMN_STYLE.BOTH: + max_width -= 2 + + return ( + rd.randint(self.rdata["windows"]["size"]["min_width"],max_width), + rd.randint(self.rdata["windows"]["size"]["min_height"],max_height) + ) def has_balcony(self) -> bool: pass @@ -26,4 +49,4 @@ class Facade: pass def get_window(self) -> Window: - pass \ No newline at end of file + return Window(self.rdata["windows"] ,self.window_size) \ No newline at end of file diff --git a/buildings/Foundations.py b/buildings/Foundations.py index b36c610..76c5eab 100644 --- a/buildings/Foundations.py +++ b/buildings/Foundations.py @@ -1,7 +1,7 @@ import random as rd import numpy as np import math -from Enums import COLLUMN_STYLE +from utils.Enums import COLLUMN_STYLE from buildings.geometry.Tile import Tile from buildings.geometry.Polygon import Polygon from buildings.geometry.Point import Point @@ -54,9 +54,9 @@ class Foundations: # this bullshit is to create tiles from the matrice and the distribution x_padding = self.position.x - for x,xsize in enumerate(self.x_distribution): + for x,xsize in utils.Enumerate(self.x_distribution): z_padding = self.position.z - for z,zsize in enumerate(self.z_distribution): + for z,zsize in utils.Enumerate(self.z_distribution): if self.matrice[x][z] == 1: for xi in range(xsize): for zi in range(zsize): @@ -131,14 +131,13 @@ class Foundations: return self._suppr_doubblons_collumns(collumns) def _suppr_doubblons_collumns(self, collumns : list[Collumn]): - for index,collumn in enumerate(collumns): + for index,collumn in utils.Enumerate(collumns): if index == len(collumns)-1: break for compare in collumns[index+1:]: if collumn.point1.position == compare.point1.position : if compare.is_outer : collumn.set_is_outer(True) collumns.remove(compare) - - print(len(collumns)) + return collumns \ No newline at end of file diff --git a/buildings/elements/Window.py b/buildings/elements/Window.py index 81edaff..dfd15de 100644 --- a/buildings/elements/Window.py +++ b/buildings/elements/Window.py @@ -1,7 +1,63 @@ +import random as rd +import math +from gdpc import Editor, Block, geometry +from utils.Enums import DIRECTION +from buildings.geometry.Vertice import Vertice + class Window: - def __init__(self, size : tuple[int,int]): - self.size = size + def __init__(self, rdata, size : tuple[int,int]): + self.rdata = rdata + self.width, self.height = size + self.is_grounded = self.is_grounded() + self.has_multiple_windows = self.has_multiple_windows() + self.padding = 0 + def build(self, editor : Editor, vertice : Vertice, height : int, y : int, materials : list[str]): + self.padding = (vertice.get_size() - self.width)//2 + if not self.is_grounded: y += (height - self.height)//2 + + if self.has_multiple_windows: self.build_multiple_windows(editor, vertice, self.padding, self.height, y, materials) + else : vertice.fill(editor, materials[1], y, y + self.height, xpadding = self.padding, zpadding = self.padding) + + def build_multiple_windows(self, editor : Editor, vertice : Vertice, padding : int, height : int, y : int, materials : list[str]): + slices = rd.randint(2, self.width//self.rdata["size"]["min_width"]) + windows_count = math.ceil(slices/2) + inter_count = slices - windows_count + window_size = rd.randint(self.rdata["size"]["min_width"], self.width-inter_count // windows_count) + inter_size = (self.width - window_size*windows_count) // inter_count + + revert, switching = slices % 2 == 0, math.ceil(slices/2) + is_revert, gap = False, 0 + for i in range(1,slices+1): + modulo = i % 2 + if revert and i == switching: is_revert = True + + # kepp a spacing between windows, "is revert" is used to keep symetry + if modulo == 0 or (modulo == 1 and is_revert): + #set the values to orient windows in x or z axis + xpadding,xlen,zpadding,zlen = 0,0,0,0 + if vertice.facing == DIRECTION.NORTH or vertice.facing == DIRECTION.SOUTH: + xpadding,xlen = self.padding + gap, window_size + else: zpadding,zlen = self.padding + gap, window_size + + geometry.placeCuboid(editor, + (vertice.point1.x+xpadding, y, vertice.point1.z+zpadding), + (vertice.point1.x+xpadding+xlen, y+self.height, vertice.point1.z+zpadding+zlen), + Block(materials[1])) + gap += window_size + else : + gap += inter_size + + def is_grounded(self): + # if the window is grounded or if there is a padding between the window and the ground + if self.rdata["grounded"] >= rd.random(): return True + return False + + def has_multiple_windows(self): + if self.width > self.rdata["size"]["max_width"]: return True + if self.width >= self.rdata["multiple"]["min_width"]: + if self.rdata["multiple"]["proba"] >= rd.random(): return True + return False def open(self): pass diff --git a/buildings/geometry/Polygon.py b/buildings/geometry/Polygon.py index 9e7ea8e..16a03bd 100644 --- a/buildings/geometry/Polygon.py +++ b/buildings/geometry/Polygon.py @@ -1,4 +1,4 @@ -from Enums import DIRECTION +from utils.Enums import DIRECTION from gdpc import Editor, Block, geometry from buildings.geometry.Tile import Tile from buildings.geometry.Point import Point @@ -70,7 +70,7 @@ class Polygon: def set_vertices_and_neighbors(self, tiles : list[Tile], vertices : list[Vertice]): for tile in tiles: targets = tile.get_neighbors_coords() - for vertice_num,target in enumerate(targets): + for vertice_num,target in utils.Enumerate(targets): has_neighbor = self._has_neighbor(target, tiles) if not has_neighbor: vertice = tile.get_vertice(vertice_num) diff --git a/buildings/geometry/Rectangle.py b/buildings/geometry/Rectangle.py index 8c7ea24..784d1fc 100644 --- a/buildings/geometry/Rectangle.py +++ b/buildings/geometry/Rectangle.py @@ -9,6 +9,9 @@ class Rectangle: def get_position(self): return (self.point1.position, self.point2.position) - def fill(self,editor : Editor, material : str, y : int, y2 : int = None): + def fill(self,editor : Editor, material : str, y : int, y2 : int = None, xpadding : int = 0, zpadding : int = 0): + if self.point2.x - self.point1.x < 2*xpadding: xpadding = 0 + if self.point2.z - self.point1.z < 2*zpadding: zpadding = 0 if y2 == None: y2 = y - geometry.placeCuboid(editor, (self.point1.x, y, self.point1.z), (self.point2.x, y2, self.point2.z), Block(material)) + + geometry.placeCuboid(editor, (self.point1.x+xpadding, y, self.point1.z+zpadding), (self.point2.x-xpadding, y2, self.point2.z-zpadding), Block(material)) diff --git a/buildings/geometry/Tile.py b/buildings/geometry/Tile.py index f1e2167..de864da 100644 --- a/buildings/geometry/Tile.py +++ b/buildings/geometry/Tile.py @@ -1,5 +1,5 @@ from gdpc import Editor, Block, geometry -from Enums import DIRECTION +from utils.Enums import DIRECTION from buildings.geometry.Point import Point from buildings.geometry.Vertice import Vertice diff --git a/buildings/geometry/Vertice.py b/buildings/geometry/Vertice.py index df58b40..edca28a 100644 --- a/buildings/geometry/Vertice.py +++ b/buildings/geometry/Vertice.py @@ -1,9 +1,9 @@ -from Enums import DIRECTION +from utils.Enums import DIRECTION from buildings.geometry.Point import Point from buildings.geometry.Rectangle import Rectangle class Vertice(Rectangle): - def __init__(self, point1 : Point, point2 : Point, facing : str): + def __init__(self, point1 : Point, point2 : Point, facing : DIRECTION): Rectangle.__init__(self, point1, point2) self.facing = facing diff --git a/main.py b/main.py index 818d02d..3020b3a 100644 --- a/main.py +++ b/main.py @@ -1,22 +1,45 @@ from gdpc import Editor, Block, geometry import networks.curve as curve import numpy as np -import json +from utils.JsonReader import JsonReader +from utils.YamlReader import YamlReader from buildings.Building import Building +from buildings.geometry.Vertice import Vertice +from buildings.geometry.Point import Point +from utils.Enums import DIRECTION,COLLUMN_STYLE +from buildings.Facade import Facade + editor = Editor(buffering=True) -f = open('buildings\shapes.json') -shapes = json.load(f) +f = JsonReader('buildings\shapes.json') +shapes = f.data + +y = YamlReader('params.yml') +random_data = y.data + +geometry.placeCuboid(editor, (0,-60,-5), (100,-45,-5), Block("air")) + +x = 0 +facade = [] +for i in range(3,13): + facade.append(Facade(random_data["buildings"]["facade"],[Vertice(Point(x,0,-5), Point(x+i,0,-5), DIRECTION.NORTH)],i,i,COLLUMN_STYLE.NONE)) + x += i+2 + +for f in facade: + f.build(editor, ["stone_bricks", "glass_pane"], -60) # F = Foundations((0,0), (20,20), shapes[0]['matrice']) # F.polygon.fill_polygon(editor, "stone", -60) -geometry.placeCuboid(editor, (-10,-60,-10), (85,-55,85), Block("air")) -B = Building((0,0), (75,75), shapes[7]['matrice']) -B.foundations.polygon.fill_vertice(editor, "pink_wool", -60) -for collumn in B.foundations.collumns: - collumn.fill(editor, "white_concrete", -60, -55) -B.foundations.polygon.fill_polygon(editor, "white_concrete", -60) + +# geometry.placeCuboid(editor, (-10,-60,-10), (85,-55,85), Block("air")) +# B = Building((0,0), (75,75), shapes[7]['matrice']) +# B.foundations.polygon.fill_vertice(editor, "pink_wool", -60) +# for collumn in B.foundations.collumns: +# collumn.fill(editor, "white_concrete", -60, -55) +# B.foundations.polygon.fill_polygon(editor, "white_concrete", -60) + + # # Get a block # block = editor.getBlock((0,48,0)) diff --git a/params.yml b/params.yml index f879b5d..d5a3875 100644 --- a/params.yml +++ b/params.yml @@ -1 +1,36 @@ -// contains all random variables +# contains all random variables +buildings: + tile_size: + min_tile_size: 3 + max_tile_size: 12 + + foudations: + collumn_style : + # proportion of each style + - none: 1 + - inner: 1 + - outer: 1 + - both: 1 + floor: + min_height: 4 + max_height: 7 + + facade: + windows: + size: + min_height: 2 + max_height: 6 + min_width: 1 + max_width: 12 + crossbars: + min_height_for_vertical_crossbar: 3 + vertical_crossbar: 0.25 + min_width_for_horizontal_crossbar: 3 + horizontal_crossbar: 0.25 + grounded: 0.5 + multiple: + # min size and probability of multiple windows on the same vertice + min_width: 5 + proba: 0.5 + inter_floor: 0.5 + balcony: 0.25 \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 1ef7339..346c05f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,3 +2,4 @@ gdpc==7.1.0 matplotlib==3.8.2 numpy==1.26.4 scipy==1.13.0 +pyyaml==6.0.1 diff --git a/Enums.py b/utils/Enums.py similarity index 92% rename from Enums.py rename to utils/Enums.py index 33c7487..37a15fa 100644 --- a/Enums.py +++ b/utils/Enums.py @@ -7,6 +7,7 @@ class DIRECTION(Enum): SOUTH = 3 class COLLUMN_STYLE(Enum): + NONE = 0 INNER = 1 OUTER = 2 BOTH = 3 \ No newline at end of file diff --git a/utils/JsonReader.py b/utils/JsonReader.py new file mode 100644 index 0000000..c2b462c --- /dev/null +++ b/utils/JsonReader.py @@ -0,0 +1,11 @@ +import json + +class JsonReader: + def __init__(self, json_file): + self.data = self._load_json(json_file) + + def _load_json(self, json_file : str): + f = open(json_file) + js = json.load(f) + + return js \ No newline at end of file diff --git a/utils/YamlReader.py b/utils/YamlReader.py new file mode 100644 index 0000000..4b2e883 --- /dev/null +++ b/utils/YamlReader.py @@ -0,0 +1,11 @@ +import yaml + +class YamlReader: + def __init__(self, yaml_file): + self.data = self._load_yaml(yaml_file) + + def _load_yaml(self, yaml_file : str): + with open(yaml_file, 'r') as stream: + data_loaded = yaml.safe_load(stream) + + return data_loaded \ No newline at end of file From fb6206c52f39e7f9279f895dfc4cb1772cef5257 Mon Sep 17 00:00:00 2001 From: AKreuzer Date: Sun, 19 May 2024 18:11:32 +0200 Subject: [PATCH 02/17] add windows, multiple windows, alternate window patern and vertical crossbars --- buildings/Facade.py | 7 ++- buildings/elements/Window.py | 104 ++++++++++++++++++++++++++-------- buildings/geometry/Vertice.py | 2 +- main.py | 9 ++- params.yml | 4 +- 5 files changed, 94 insertions(+), 32 deletions(-) diff --git a/buildings/Facade.py b/buildings/Facade.py index a4bddce..daaa962 100644 --- a/buildings/Facade.py +++ b/buildings/Facade.py @@ -42,11 +42,12 @@ class Facade: rd.randint(self.rdata["windows"]["size"]["min_height"],max_height) ) + def get_window(self) -> Window: + return Window(self.rdata["windows"] ,self.window_size) + def has_balcony(self) -> bool: pass def has_inter_floor(self) -> bool: pass - - def get_window(self) -> Window: - return Window(self.rdata["windows"] ,self.window_size) \ No newline at end of file + \ No newline at end of file diff --git a/buildings/elements/Window.py b/buildings/elements/Window.py index dfd15de..f44623c 100644 --- a/buildings/elements/Window.py +++ b/buildings/elements/Window.py @@ -2,6 +2,7 @@ import random as rd import math from gdpc import Editor, Block, geometry from utils.Enums import DIRECTION +from buildings.geometry.Point import Point from buildings.geometry.Vertice import Vertice class Window: @@ -10,44 +11,91 @@ class Window: self.width, self.height = size self.is_grounded = self.is_grounded() self.has_multiple_windows = self.has_multiple_windows() + self.is_alternate = self.is_alternate() + self.has_vertical_crossbar, self.has_horizontal_crossbar = self.has_crossbars() self.padding = 0 + self.editor, self.materials = None,None def build(self, editor : Editor, vertice : Vertice, height : int, y : int, materials : list[str]): - self.padding = (vertice.get_size() - self.width)//2 + self.editor = editor + self.materials = materials + + len = vertice.get_size() + self.padding = (len - self.width)//2 + self.width = len - self.padding*2 + self.is_alternate = True if not self.is_grounded: y += (height - self.height)//2 - if self.has_multiple_windows: self.build_multiple_windows(editor, vertice, self.padding, self.height, y, materials) - else : vertice.fill(editor, materials[1], y, y + self.height, xpadding = self.padding, zpadding = self.padding) + if self.has_multiple_windows: self.build_multiple_windows(vertice, y) + else : + xpadding, zpadding = self.padding, self.padding + if vertice.facing == DIRECTION.NORTH or vertice.facing == DIRECTION.SOUTH: zpadding = 0 + else: xpadding = 0 + + self.place_glasses(Point(vertice.point1.x+xpadding, y, vertice.point1.z+zpadding), + Point(vertice.point2.x-xpadding, y+self.height, vertice.point2.z-zpadding)) - def build_multiple_windows(self, editor : Editor, vertice : Vertice, padding : int, height : int, y : int, materials : list[str]): - slices = rd.randint(2, self.width//self.rdata["size"]["min_width"]) - windows_count = math.ceil(slices/2) + def build_multiple_windows(self, vertice : Vertice, y : int): + slices = rd.randint(3, self.width//self.rdata["size"]["min_width"]) + mid = math.ceil(slices/2) + windows_count = mid inter_count = slices - windows_count - window_size = rd.randint(self.rdata["size"]["min_width"], self.width-inter_count // windows_count) + window_size = rd.randint(self.rdata["size"]["min_width"], (self.width-inter_count) // windows_count) inter_size = (self.width - window_size*windows_count) // inter_count - revert, switching = slices % 2 == 0, math.ceil(slices/2) - is_revert, gap = False, 0 + is_even= slices % 2 == 0 + is_window, gap = True, 0 + remainder = self.width - (window_size*windows_count + inter_size*inter_count) for i in range(1,slices+1): - modulo = i % 2 - if revert and i == switching: is_revert = True + wsize,isize = window_size, inter_size + if is_even and i == mid: wsize, isize = wsize*2, isize*2 + if i == mid: wsize, isize = wsize + remainder, isize + remainder # kepp a spacing between windows, "is revert" is used to keep symetry - if modulo == 0 or (modulo == 1 and is_revert): + if is_window: #set the values to orient windows in x or z axis xpadding,xlen,zpadding,zlen = 0,0,0,0 if vertice.facing == DIRECTION.NORTH or vertice.facing == DIRECTION.SOUTH: - xpadding,xlen = self.padding + gap, window_size - else: zpadding,zlen = self.padding + gap, window_size + xpadding,xlen = self.padding + gap, wsize-1 + else: zpadding,zlen = self.padding + gap, wsize-1 - geometry.placeCuboid(editor, - (vertice.point1.x+xpadding, y, vertice.point1.z+zpadding), - (vertice.point1.x+xpadding+xlen, y+self.height, vertice.point1.z+zpadding+zlen), - Block(materials[1])) - gap += window_size + self.place_glasses(Point(vertice.point1.x+xpadding, y, vertice.point1.z+zpadding), + Point(vertice.point1.x+xpadding+xlen, y+self.height, vertice.point1.z+zpadding+zlen)) + gap += wsize else : - gap += inter_size - + gap += isize + + is_window = not is_window + + def place_glasses(self, pos1 : Point, pos2 : Point): + + xlen, zlen = pos2.x - pos1.x, pos2.z - pos1.z + len = xlen + zlen + if self.is_alternate: + mid = len//2 + 1 + + is_block, is_even = False, len % 2 == 1 # yeah the result isn't actually even but it's because either xlen or zlen is 1, we want to know of the other result is even + for x in range(xlen+1): + for z in range(zlen+1): + if is_even and (x+z) == mid: is_block = not is_block # to keep symetry + id = 1 if not is_block else 2 + geometry.placeCuboid(self.editor,(pos1.x+x,pos1.y,pos1.z+z),(pos1.x+x,pos2.y,pos1.z+z),Block(self.materials[id])) + is_block = not is_block + + else: + geometry.placeCuboid(self.editor,pos1.position,pos2.position,Block(self.materials[1])) + + self.build_crossbars(pos1, pos2, len) + + + def build_crossbars(self, pos1 : Point, pos2 : Point, len : int): + if self.has_vertical_crossbar and self.height >= self.rdata["crossbars"]["min_height_for_vertical_crossbar"]: + print(pos1.x,pos2.x) + y = self.height//2 + geometry.placeCuboid(self.editor,(pos1.x,pos1.y+y,pos1.z),(pos2.x,pos2.y-y,pos2.z),Block(self.materials[3])) + if self.has_horizontal_crossbar and len >= self.rdata["crossbars"]["min_width_for_horizontal_crossbar"]: + pass + def is_grounded(self): # if the window is grounded or if there is a padding between the window and the ground if self.rdata["grounded"] >= rd.random(): return True @@ -56,11 +104,17 @@ class Window: def has_multiple_windows(self): if self.width > self.rdata["size"]["max_width"]: return True if self.width >= self.rdata["multiple"]["min_width"]: + return True if self.rdata["multiple"]["proba"] >= rd.random(): return True return False - def open(self): - pass + def is_alternate(self): + # if the window alternate between glass_blocks and glass_panes + if self.rdata["alternate"] >= rd.random(): return True + return False - def close(self): - pass \ No newline at end of file + def has_crossbars(self): + # if the window has crossbars + data = self.rdata["crossbars"] + + return (data["vertical_crossbar"] >= rd.random(), data["horizontal_crossbar"] >= rd.random()) \ No newline at end of file diff --git a/buildings/geometry/Vertice.py b/buildings/geometry/Vertice.py index edca28a..6740e7a 100644 --- a/buildings/geometry/Vertice.py +++ b/buildings/geometry/Vertice.py @@ -17,5 +17,5 @@ class Vertice(Rectangle): Point(x = self.point2.x, z = self.point2.z + 1)] def get_size(self): - return self.point2.x - self.point1.x + self.point2.z - self.point1.z + return self.point2.x - self.point1.x + self.point2.z - self.point1.z + 1 \ No newline at end of file diff --git a/main.py b/main.py index 3020b3a..ecf046d 100644 --- a/main.py +++ b/main.py @@ -1,4 +1,4 @@ -from gdpc import Editor, Block, geometry +from gdpc import Editor, Block, geometry, Transform import networks.curve as curve import numpy as np from utils.JsonReader import JsonReader @@ -18,8 +18,12 @@ shapes = f.data y = YamlReader('params.yml') random_data = y.data +transform = Transform((-2,0,-5),rotation = 3) +editor.transform.push(transform) + geometry.placeCuboid(editor, (0,-60,-5), (100,-45,-5), Block("air")) + x = 0 facade = [] for i in range(3,13): @@ -27,7 +31,8 @@ for i in range(3,13): x += i+2 for f in facade: - f.build(editor, ["stone_bricks", "glass_pane"], -60) + f.build(editor, ["stone_bricks","glass_pane","glass","cobblestone_wall"], -60) + # F = Foundations((0,0), (20,20), shapes[0]['matrice']) # F.polygon.fill_polygon(editor, "stone", -60) diff --git a/params.yml b/params.yml index d5a3875..c35e466 100644 --- a/params.yml +++ b/params.yml @@ -28,7 +28,9 @@ buildings: min_width_for_horizontal_crossbar: 3 horizontal_crossbar: 0.25 grounded: 0.5 - multiple: + # alternate between block and pane + alternate: 0.5 + multiple: # min size and probability of multiple windows on the same vertice min_width: 5 proba: 0.5 From 7071b0a81c3372fe1390255d2d2129acacd78013 Mon Sep 17 00:00:00 2001 From: AKreuzer Date: Mon, 20 May 2024 20:47:12 +0200 Subject: [PATCH 03/17] Update to use gdpc Transform (simplifies a lot) --- buildings/Building.py | 2 +- buildings/Facade.py | 46 +++++++------------ buildings/Foundations.py | 20 ++++---- buildings/elements/Window.py | 81 +++++++++++++++------------------ buildings/geometry/Polygon.py | 5 +- buildings/geometry/Rectangle.py | 5 +- buildings/geometry/Tile.py | 25 +++++----- buildings/geometry/Vertice.py | 2 +- main.py | 4 +- utils/Enums.py | 8 ++-- 10 files changed, 84 insertions(+), 114 deletions(-) diff --git a/buildings/Building.py b/buildings/Building.py index 5a7b740..5df0fc1 100644 --- a/buildings/Building.py +++ b/buildings/Building.py @@ -17,7 +17,7 @@ class Building: is_inner_or_outer = COLLUMN_STYLE.BOTH - self.foundations = Foundations(position, size, matrice, tile_size, is_collumn_full_tile, is_inner_or_outer) + self.foundations = Foundations(size, matrice, tile_size, is_collumn_full_tile, is_inner_or_outer) self.facade = Facade(self.foundations.vertices, floor_height, is_inner_or_outer) def gen_tile_size(self) -> int: diff --git a/buildings/Facade.py b/buildings/Facade.py index daaa962..e542bb1 100644 --- a/buildings/Facade.py +++ b/buildings/Facade.py @@ -1,49 +1,35 @@ import random as rd -from utils.Enums import COLLUMN_STYLE, DIRECTION -from gdpc import Editor +from utils.Enums import COLLUMN_STYLE +from gdpc import Editor, Transform from buildings.geometry.Vertice import Vertice -from buildings.geometry.Rectangle import Rectangle from buildings.elements.Window import Window class Facade: - def __init__(self, rdata, vertices : list[Vertice], height : int, lenght : int, is_inner_or_outer : COLLUMN_STYLE): + def __init__(self, rdata, vertices : list[Vertice], height : int, length : int, is_inner_or_outer : COLLUMN_STYLE): self.rdata = rdata self.vertices = vertices self.is_inner_or_outer = is_inner_or_outer self.height = height - self.lenght = lenght - self.window_size = self.get_window_size() + self.length = length + self.padding = 0 self.window = self.get_window() self.has_balcony = self.has_balcony() self.has_inter_floor = self.has_inter_floor() - def build(self, editor : Editor, materials : list[str], y : int): - padding = 0 - if self.is_inner_or_outer == COLLUMN_STYLE.OUTER or self.is_inner_or_outer == COLLUMN_STYLE.BOTH: - padding = 1 - + def build(self, editor : Editor, materials : list[str]): for vertice in self.vertices: - xpadding, zpadding = 0, 0 - if vertice.facing == DIRECTION.NORTH or vertice.facing == DIRECTION.SOUTH: - xpadding = padding - else: zpadding = padding - - vertice.fill(editor, materials[0], y, y + self.height, xpadding = xpadding, zpadding = zpadding) - self.window.build(editor, vertice, self.height, y, materials) - - def get_window_size(self) -> tuple[int,int]: - max_width = self.lenght - max_height = min(self.height, self.rdata["windows"]["size"]["max_height"]) - if self.is_inner_or_outer == COLLUMN_STYLE.OUTER or self.is_inner_or_outer == COLLUMN_STYLE.BOTH: - max_width -= 2 - - return ( - rd.randint(self.rdata["windows"]["size"]["min_width"],max_width), - rd.randint(self.rdata["windows"]["size"]["min_height"],max_height) - ) + vertice.fill(editor, materials[0], self.height, xpadding = self.padding, zpadding = self.padding) + with editor.pushTransform(Transform(vertice.point1.position,rotation = vertice.facing.value)): + self.window.build(editor, vertice.get_len(), self.height, materials) def get_window(self) -> Window: - return Window(self.rdata["windows"] ,self.window_size) + if self.is_inner_or_outer == COLLUMN_STYLE.OUTER or self.is_inner_or_outer == COLLUMN_STYLE.BOTH: + self.padding = 1 + + max_width = self.length-2*self.padding + max_height = min(self.height, self.rdata["windows"]["size"]["max_height"]) + + return Window(self.rdata["windows"] ,max_width, max_height) def has_balcony(self) -> bool: pass diff --git a/buildings/Foundations.py b/buildings/Foundations.py index 76c5eab..51a365e 100644 --- a/buildings/Foundations.py +++ b/buildings/Foundations.py @@ -11,8 +11,7 @@ from buildings.elements.Collumn import Collumn class Foundations: # TODO : gérer les collones sur les tiles trop petites et les colones 1tile/2 + fulltile - def __init__(self, - position : tuple[int,int], + def __init__(self, size : tuple[int, int], matrice : list[list[int]], tile_size : int, @@ -25,11 +24,8 @@ class Foundations: self.is_collumn_full_tile = is_collumn_full_tile self.is_inner_or_outer = is_inner_or_outer - x,z = position - self.position = Point(x = x, z = z) self.size = size - self.length = size[0] - self.width = size[1] + self.length, self.width = size self.matrice = matrice self.tiles = [] self.vertices = [] @@ -45,7 +41,7 @@ class Foundations: def get_polygon(self) -> Polygon: ## The polygon is a shape of tiles representing the foundation shape - polygon = Polygon(self.position, self.size) + polygon = Polygon(self.size) avaliable_space = (self.length_in_tiles, self.width_in_tiles) # we save the distribution, usefull for the next steps @@ -53,10 +49,10 @@ class Foundations: self.z_distribution = self.get_distribution(len(self.matrice[0]), avaliable_space[1]) # this bullshit is to create tiles from the matrice and the distribution - x_padding = self.position.x - for x,xsize in utils.Enumerate(self.x_distribution): - z_padding = self.position.z - for z,zsize in utils.Enumerate(self.z_distribution): + x_padding = 0 + for x,xsize in enumerate(self.x_distribution): + z_padding = 0 + for z,zsize in enumerate(self.z_distribution): if self.matrice[x][z] == 1: for xi in range(xsize): for zi in range(zsize): @@ -131,7 +127,7 @@ class Foundations: return self._suppr_doubblons_collumns(collumns) def _suppr_doubblons_collumns(self, collumns : list[Collumn]): - for index,collumn in utils.Enumerate(collumns): + for index,collumn in enumerate(collumns): if index == len(collumns)-1: break for compare in collumns[index+1:]: if collumn.point1.position == compare.point1.position : diff --git a/buildings/elements/Window.py b/buildings/elements/Window.py index f44623c..395cc5c 100644 --- a/buildings/elements/Window.py +++ b/buildings/elements/Window.py @@ -1,14 +1,14 @@ import random as rd import math -from gdpc import Editor, Block, geometry -from utils.Enums import DIRECTION +from gdpc import Editor, Block, geometry, Transform +from utils.Enums import COLLUMN_STYLE from buildings.geometry.Point import Point from buildings.geometry.Vertice import Vertice class Window: - def __init__(self, rdata, size : tuple[int,int]): + def __init__(self, rdata, max_width : int, max_height : int): self.rdata = rdata - self.width, self.height = size + self.width, self.height = self.get_size(max_width, max_height) self.is_grounded = self.is_grounded() self.has_multiple_windows = self.has_multiple_windows() self.is_alternate = self.is_alternate() @@ -16,26 +16,22 @@ class Window: self.padding = 0 self.editor, self.materials = None,None - def build(self, editor : Editor, vertice : Vertice, height : int, y : int, materials : list[str]): + def build(self, editor : Editor, facade_len : int, facade_height : int, materials : list[str]): self.editor = editor self.materials = materials - len = vertice.get_size() - self.padding = (len - self.width)//2 - self.width = len - self.padding*2 + # correction to avoid asymetry + self.padding = (facade_len - self.width)//2 + self.width = facade_len - self.padding*2 + self.is_alternate = True - if not self.is_grounded: y += (height - self.height)//2 + if not self.is_grounded: editor.transform @= Transform((0,(facade_height-self.height)//2,0)) - if self.has_multiple_windows: self.build_multiple_windows(vertice, y) - else : - xpadding, zpadding = self.padding, self.padding - if vertice.facing == DIRECTION.NORTH or vertice.facing == DIRECTION.SOUTH: zpadding = 0 - else: xpadding = 0 - - self.place_glasses(Point(vertice.point1.x+xpadding, y, vertice.point1.z+zpadding), - Point(vertice.point2.x-xpadding, y+self.height, vertice.point2.z-zpadding)) + if self.has_multiple_windows: self.build_multiple_windows() + else : + self.place_glasses(self.padding, self.width+self.padding) - def build_multiple_windows(self, vertice : Vertice, y : int): + def build_multiple_windows(self): slices = rd.randint(3, self.width//self.rdata["size"]["min_width"]) mid = math.ceil(slices/2) windows_count = mid @@ -53,46 +49,41 @@ class Window: # kepp a spacing between windows, "is revert" is used to keep symetry if is_window: - #set the values to orient windows in x or z axis - xpadding,xlen,zpadding,zlen = 0,0,0,0 - if vertice.facing == DIRECTION.NORTH or vertice.facing == DIRECTION.SOUTH: - xpadding,xlen = self.padding + gap, wsize-1 - else: zpadding,zlen = self.padding + gap, wsize-1 - - self.place_glasses(Point(vertice.point1.x+xpadding, y, vertice.point1.z+zpadding), - Point(vertice.point1.x+xpadding+xlen, y+self.height, vertice.point1.z+zpadding+zlen)) + x= self.padding + gap + self.place_glasses(x, x+wsize) gap += wsize else : gap += isize is_window = not is_window - def place_glasses(self, pos1 : Point, pos2 : Point): - - xlen, zlen = pos2.x - pos1.x, pos2.z - pos1.z - len = xlen + zlen + def place_glasses(self, x1 : int, x2 : int): + len = x2 - x1 if self.is_alternate: - mid = len//2 + 1 + mid = x1 + len//2 - is_block, is_even = False, len % 2 == 1 # yeah the result isn't actually even but it's because either xlen or zlen is 1, we want to know of the other result is even - for x in range(xlen+1): - for z in range(zlen+1): - if is_even and (x+z) == mid: is_block = not is_block # to keep symetry - id = 1 if not is_block else 2 - geometry.placeCuboid(self.editor,(pos1.x+x,pos1.y,pos1.z+z),(pos1.x+x,pos2.y,pos1.z+z),Block(self.materials[id])) - is_block = not is_block + is_block, is_even = False, len % 2 == 0 + for x in range(x1,x2): + if is_even and x == mid: is_block = not is_block # to keep symetry + id = 1 if not is_block else 2 + geometry.placeCuboid(self.editor,(x,0,0),(x,self.height,0),Block(self.materials[id])) + is_block = not is_block else: - geometry.placeCuboid(self.editor,pos1.position,pos2.position,Block(self.materials[1])) + geometry.placeCuboid(self.editor,(x1,0,0),(x2,self.height,0),Block(self.materials[1])) - self.build_crossbars(pos1, pos2, len) - - - def build_crossbars(self, pos1 : Point, pos2 : Point, len : int): + self.build_crossbars(x1, x2-1, len) + + def get_size(self, max_width : int ,max_height : int) -> tuple[int,int]: + return ( + rd.randint(self.rdata["size"]["min_width"],max_width), + rd.randint(self.rdata["size"]["min_height"],max_height) + ) + + def build_crossbars(self, x1 : int, x2 : int, len : int): if self.has_vertical_crossbar and self.height >= self.rdata["crossbars"]["min_height_for_vertical_crossbar"]: - print(pos1.x,pos2.x) y = self.height//2 - geometry.placeCuboid(self.editor,(pos1.x,pos1.y+y,pos1.z),(pos2.x,pos2.y-y,pos2.z),Block(self.materials[3])) + geometry.placeCuboid(self.editor,(x1,y,0),(x2,self.height-y,0),Block(self.materials[3])) if self.has_horizontal_crossbar and len >= self.rdata["crossbars"]["min_width_for_horizontal_crossbar"]: pass diff --git a/buildings/geometry/Polygon.py b/buildings/geometry/Polygon.py index 16a03bd..4783523 100644 --- a/buildings/geometry/Polygon.py +++ b/buildings/geometry/Polygon.py @@ -6,8 +6,7 @@ from buildings.geometry.Rectangle import Rectangle from buildings.geometry.Vertice import Vertice class Polygon: - def __init__(self, position : Point, size: tuple[int,int]): - self.position = position + def __init__(self, size: tuple[int,int]): self.size = size self.shape = [] self.vertices = [] @@ -70,7 +69,7 @@ class Polygon: def set_vertices_and_neighbors(self, tiles : list[Tile], vertices : list[Vertice]): for tile in tiles: targets = tile.get_neighbors_coords() - for vertice_num,target in utils.Enumerate(targets): + for vertice_num,target in enumerate(targets): has_neighbor = self._has_neighbor(target, tiles) if not has_neighbor: vertice = tile.get_vertice(vertice_num) diff --git a/buildings/geometry/Rectangle.py b/buildings/geometry/Rectangle.py index 784d1fc..a199982 100644 --- a/buildings/geometry/Rectangle.py +++ b/buildings/geometry/Rectangle.py @@ -9,9 +9,8 @@ class Rectangle: def get_position(self): return (self.point1.position, self.point2.position) - def fill(self,editor : Editor, material : str, y : int, y2 : int = None, xpadding : int = 0, zpadding : int = 0): + def fill(self,editor : Editor, material : str, y : int = None, xpadding : int = 0, zpadding : int = 0): if self.point2.x - self.point1.x < 2*xpadding: xpadding = 0 if self.point2.z - self.point1.z < 2*zpadding: zpadding = 0 - if y2 == None: y2 = y - geometry.placeCuboid(editor, (self.point1.x+xpadding, y, self.point1.z+zpadding), (self.point2.x-xpadding, y2, self.point2.z-zpadding), Block(material)) + geometry.placeCuboid(editor, (self.point1.x+xpadding, 0, self.point1.z+zpadding), (self.point2.x-xpadding, y, self.point2.z-zpadding), Block(material)) diff --git a/buildings/geometry/Tile.py b/buildings/geometry/Tile.py index de864da..45f6370 100644 --- a/buildings/geometry/Tile.py +++ b/buildings/geometry/Tile.py @@ -27,15 +27,14 @@ class Tile: self.north_vertice = None self.south_vertice = None - def fill(self, editor : Editor, material : str, y : int, y2 : int = None) -> list[Point]: - if y2 == None: y2 = y - geometry.placeCuboid(editor, (self.pos.x, y, self.pos.z), (self.pos.x+self.size-1, y2, self.pos.z+self.size-1), Block(material)) + def fill(self, editor : Editor, material : str, y : int = 0) -> list[Point]: + geometry.placeCuboid(editor, (self.pos.x, 0, self.pos.z), (self.pos.x+self.size-1, y, self.pos.z+self.size-1), Block(material)) def get_neighbors_coords(self): - return [Point(x = self.pos.x - self.size, z = self.pos.z), # west - Point(x = self.pos.x + self.size, z = self.pos.z), # east - Point(x = self.pos.x, z = self.pos.z - self.size), # north - Point(x = self.pos.x, z = self.pos.z + self.size)] # south + return [Point(x = self.pos.x, z = self.pos.z - self.size), # north + Point(x = self.pos.x - self.size, z = self.pos.z), # west + Point(x = self.pos.x, z = self.pos.z + self.size), # south + Point(x = self.pos.x + self.size, z = self.pos.z)] # east def get_neighbor(self, direction) -> Point: @@ -62,16 +61,16 @@ class Tile: def get_vertice(self,vertice : int|DIRECTION) -> Vertice: # gives the corresponding vertice : - # 0 = west, 1 = east, 2 = north, 3 = south + # 0 = north, 1 = west, 2 = south, 3 = east match(vertice): case 0 : - return Vertice(self.north_west, self.south_west, DIRECTION.WEST) - case 1 : - return Vertice(self.north_east, self.south_east, DIRECTION.EAST) - case 2 : return Vertice(self.north_west, self.north_east, DIRECTION.NORTH) - case 3 : + case 1 : + return Vertice(self.north_west, self.south_west, DIRECTION.WEST) + case 2 : return Vertice(self.south_west, self.south_east, DIRECTION.SOUTH) + case 3 : + return Vertice(self.north_east, self.south_east, DIRECTION.EAST) case DIRECTION.WEST : return self.west_vertice case DIRECTION.EAST : diff --git a/buildings/geometry/Vertice.py b/buildings/geometry/Vertice.py index 6740e7a..c576af5 100644 --- a/buildings/geometry/Vertice.py +++ b/buildings/geometry/Vertice.py @@ -16,6 +16,6 @@ class Vertice(Rectangle): return [Point(x = self.point1.x, z = self.point1.z - 1), Point(x = self.point2.x, z = self.point2.z + 1)] - def get_size(self): + def get_len(self): return self.point2.x - self.point1.x + self.point2.z - self.point1.z + 1 \ No newline at end of file diff --git a/main.py b/main.py index ecf046d..c6dd711 100644 --- a/main.py +++ b/main.py @@ -18,7 +18,7 @@ shapes = f.data y = YamlReader('params.yml') random_data = y.data -transform = Transform((-2,0,-5),rotation = 3) +transform = Transform((0,-60,0),rotation = 0) editor.transform.push(transform) geometry.placeCuboid(editor, (0,-60,-5), (100,-45,-5), Block("air")) @@ -31,7 +31,7 @@ for i in range(3,13): x += i+2 for f in facade: - f.build(editor, ["stone_bricks","glass_pane","glass","cobblestone_wall"], -60) + f.build(editor, ["stone_bricks","glass_pane","glass","cobblestone_wall"]) # F = Foundations((0,0), (20,20), shapes[0]['matrice']) diff --git a/utils/Enums.py b/utils/Enums.py index 37a15fa..66c55b9 100644 --- a/utils/Enums.py +++ b/utils/Enums.py @@ -1,10 +1,10 @@ from enum import Enum class DIRECTION(Enum): - WEST = 0 - EAST = 1 - NORTH = 2 - SOUTH = 3 + NORTH = 0 + WEST = 1 + SOUTH = 2 + EAST = 3 class COLLUMN_STYLE(Enum): NONE = 0 From e47c8cf7ce5172b5302770dcb9eb424a70a33c70 Mon Sep 17 00:00:00 2001 From: KAymeric Date: Sun, 26 May 2024 01:37:06 +0200 Subject: [PATCH 04/17] windows full features --- buildings/Facade.py | 17 ++++++++++--- buildings/elements/Balcony.py | 4 +++ buildings/elements/Window.py | 47 +++++++++++++++++++++-------------- main.py | 13 ++++++---- params.yml | 13 +++++++--- utils/Enums.py | 7 +++++- utils/functions.py | 6 +++++ 7 files changed, 75 insertions(+), 32 deletions(-) create mode 100644 buildings/elements/Balcony.py create mode 100644 utils/functions.py diff --git a/buildings/Facade.py b/buildings/Facade.py index e542bb1..ea53ae7 100644 --- a/buildings/Facade.py +++ b/buildings/Facade.py @@ -1,6 +1,6 @@ import random as rd from utils.Enums import COLLUMN_STYLE -from gdpc import Editor, Transform +from gdpc import Editor, Block, geometry, Transform from buildings.geometry.Vertice import Vertice from buildings.elements.Window import Window @@ -15,11 +15,16 @@ class Facade: self.window = self.get_window() self.has_balcony = self.has_balcony() self.has_inter_floor = self.has_inter_floor() + self.editor, self.materials = None,None - def build(self, editor : Editor, materials : list[str]): + def build(self, editor : Editor, materials : list[str]): + self.editor = editor + self.materials = materials + for vertice in self.vertices: vertice.fill(editor, materials[0], self.height, xpadding = self.padding, zpadding = self.padding) with editor.pushTransform(Transform(vertice.point1.position,rotation = vertice.facing.value)): + self.build_inter_floor(vertice) self.window.build(editor, vertice.get_len(), self.height, materials) def get_window(self) -> Window: @@ -31,9 +36,13 @@ class Facade: return Window(self.rdata["windows"] ,max_width, max_height) + def build_inter_floor(self, vertice : Vertice): + if self.has_inter_floor: + geometry.placeCuboid(self.editor,(0,self.height,-1),(self.length,self.height,-1),Block(self.materials[4], {"facing": "south", "half": "top"})) + def has_balcony(self) -> bool: - pass + return self.rdata["balcony"] >= rd.random() def has_inter_floor(self) -> bool: - pass + return self.rdata["inter_floor"] >= rd.random() \ No newline at end of file diff --git a/buildings/elements/Balcony.py b/buildings/elements/Balcony.py new file mode 100644 index 0000000..55691ab --- /dev/null +++ b/buildings/elements/Balcony.py @@ -0,0 +1,4 @@ +class Balcony: + def __init__(self, length, width): + self.length = length + self.width = width \ No newline at end of file diff --git a/buildings/elements/Window.py b/buildings/elements/Window.py index 395cc5c..4d211da 100644 --- a/buildings/elements/Window.py +++ b/buildings/elements/Window.py @@ -1,7 +1,8 @@ import random as rd import math from gdpc import Editor, Block, geometry, Transform -from utils.Enums import COLLUMN_STYLE +from utils.Enums import COLLUMN_STYLE, BORDER_RADIUS +from utils.functions import * from buildings.geometry.Point import Point from buildings.geometry.Vertice import Vertice @@ -13,6 +14,7 @@ class Window: self.has_multiple_windows = self.has_multiple_windows() self.is_alternate = self.is_alternate() self.has_vertical_crossbar, self.has_horizontal_crossbar = self.has_crossbars() + self.border_radius = self.border_radius() self.padding = 0 self.editor, self.materials = None,None @@ -24,12 +26,12 @@ class Window: self.padding = (facade_len - self.width)//2 self.width = facade_len - self.padding*2 - self.is_alternate = True if not self.is_grounded: editor.transform @= Transform((0,(facade_height-self.height)//2,0)) + editor.transform @= Transform((self.padding,0,0)) if self.has_multiple_windows: self.build_multiple_windows() else : - self.place_glasses(self.padding, self.width+self.padding) + self.place_glasses(0, self.width) def build_multiple_windows(self): slices = rd.randint(3, self.width//self.rdata["size"]["min_width"]) @@ -48,9 +50,8 @@ class Window: if i == mid: wsize, isize = wsize + remainder, isize + remainder # kepp a spacing between windows, "is revert" is used to keep symetry - if is_window: - x= self.padding + gap - self.place_glasses(x, x+wsize) + if is_window: + self.place_glasses(gap, gap+wsize) gap += wsize else : gap += isize @@ -70,9 +71,10 @@ class Window: is_block = not is_block else: - geometry.placeCuboid(self.editor,(x1,0,0),(x2,self.height,0),Block(self.materials[1])) + geometry.placeCuboid(self.editor,(x1,0,0),(x2-1,self.height,0),Block(self.materials[1])) self.build_crossbars(x1, x2-1, len) + if len > 1: self.build_border_radius(x1, x2-1) def get_size(self, max_width : int ,max_height : int) -> tuple[int,int]: return ( @@ -83,29 +85,38 @@ class Window: def build_crossbars(self, x1 : int, x2 : int, len : int): if self.has_vertical_crossbar and self.height >= self.rdata["crossbars"]["min_height_for_vertical_crossbar"]: y = self.height//2 - geometry.placeCuboid(self.editor,(x1,y,0),(x2,self.height-y,0),Block(self.materials[3])) + geometry.placeCuboid(self.editor,(x1,y,0),(x2,y,0),Block(self.materials[3])) if self.has_horizontal_crossbar and len >= self.rdata["crossbars"]["min_width_for_horizontal_crossbar"]: - pass + x = len//2 + geometry.placeCuboid(self.editor,(x1+x,0,0),(x2-x,self.height,0),Block(self.materials[3], {"up" : "true"})) + + def build_border_radius(self, x1 : int, x2 : int): + if self.border_radius != BORDER_RADIUS.NONE: + self.editor.placeBlock((x1,self.height,0),Block(self.materials[4], {"facing": "west", "half": "top"})) + self.editor.placeBlock((x2,self.height,0),Block(self.materials[4], {"facing": "east", "half": "top"})) + if self.border_radius == BORDER_RADIUS.TOP_AND_BOTTOM: + self.editor.placeBlock((x1,0,0),Block(self.materials[4], {"facing": "west"})) + self.editor.placeBlock((x2,0,0),Block(self.materials[4], {"facing": "east"})) def is_grounded(self): # if the window is grounded or if there is a padding between the window and the ground - if self.rdata["grounded"] >= rd.random(): return True - return False + return self.rdata["grounded"] >= rd.random() def has_multiple_windows(self): if self.width > self.rdata["size"]["max_width"]: return True - if self.width >= self.rdata["multiple"]["min_width"]: - return True - if self.rdata["multiple"]["proba"] >= rd.random(): return True - return False + elif self.width >= self.rdata["multiple"]["min_width"]: + return self.rdata["multiple"]["proba"] >= rd.random() + else : return False def is_alternate(self): # if the window alternate between glass_blocks and glass_panes - if self.rdata["alternate"] >= rd.random(): return True - return False + return self.rdata["alternate"] >= rd.random() def has_crossbars(self): # if the window has crossbars data = self.rdata["crossbars"] - return (data["vertical_crossbar"] >= rd.random(), data["horizontal_crossbar"] >= rd.random()) \ No newline at end of file + return (data["vertical_crossbar"] >= rd.random(), data["horizontal_crossbar"] >= rd.random()) + + def border_radius(self): + return select_random(self.rdata["border_radius"], BORDER_RADIUS) \ No newline at end of file diff --git a/main.py b/main.py index c6dd711..9dd676e 100644 --- a/main.py +++ b/main.py @@ -7,9 +7,11 @@ from buildings.Building import Building from buildings.geometry.Vertice import Vertice from buildings.geometry.Point import Point -from utils.Enums import DIRECTION,COLLUMN_STYLE +from utils.Enums import DIRECTION,COLLUMN_STYLE,BORDER_RADIUS from buildings.Facade import Facade +from utils.functions import * + editor = Editor(buffering=True) f = JsonReader('buildings\shapes.json') @@ -18,20 +20,21 @@ shapes = f.data y = YamlReader('params.yml') random_data = y.data -transform = Transform((0,-60,0),rotation = 0) + +transform = Transform((0,-60,-5),rotation = 0) editor.transform.push(transform) -geometry.placeCuboid(editor, (0,-60,-5), (100,-45,-5), Block("air")) +geometry.placeCuboid(editor, (0,0,-1), (100,15,1), Block("air")) x = 0 facade = [] for i in range(3,13): - facade.append(Facade(random_data["buildings"]["facade"],[Vertice(Point(x,0,-5), Point(x+i,0,-5), DIRECTION.NORTH)],i,i,COLLUMN_STYLE.NONE)) + facade.append(Facade(random_data["buildings"]["facade"],[Vertice(Point(x,0,0), Point(x+i,0,0), DIRECTION.NORTH)],i,i,COLLUMN_STYLE.NONE)) x += i+2 for f in facade: - f.build(editor, ["stone_bricks","glass_pane","glass","cobblestone_wall"]) + f.build(editor, ["stone_bricks","glass_pane","glass","cobblestone_wall","stone_brick_stairs"]) # F = Foundations((0,0), (20,20), shapes[0]['matrice']) diff --git a/params.yml b/params.yml index c35e466..7cd9afc 100644 --- a/params.yml +++ b/params.yml @@ -7,10 +7,10 @@ buildings: foudations: collumn_style : # proportion of each style - - none: 1 - - inner: 1 - - outer: 1 - - both: 1 + none: 1 + inner: 1 + outer: 1 + both: 1 floor: min_height: 4 max_height: 7 @@ -34,5 +34,10 @@ buildings: # min size and probability of multiple windows on the same vertice min_width: 5 proba: 0.5 + border_radius: + # proportion of each style + none: 2 + top: 1 + top_and_bottom: 1 inter_floor: 0.5 balcony: 0.25 \ No newline at end of file diff --git a/utils/Enums.py b/utils/Enums.py index 66c55b9..4da1c62 100644 --- a/utils/Enums.py +++ b/utils/Enums.py @@ -10,4 +10,9 @@ class COLLUMN_STYLE(Enum): NONE = 0 INNER = 1 OUTER = 2 - BOTH = 3 \ No newline at end of file + BOTH = 3 + +class BORDER_RADIUS(Enum): + NONE = 0 + TOP = 1 + TOP_AND_BOTTOM = 2 \ No newline at end of file diff --git a/utils/functions.py b/utils/functions.py new file mode 100644 index 0000000..aec47f8 --- /dev/null +++ b/utils/functions.py @@ -0,0 +1,6 @@ +from enum import Enum +import random as rd + +def select_random(rdata : dict, enum : Enum) -> Enum: + # select a random value of the dict according to his coef and return the corresponding value in the enum + return enum[rd.choice([elt for elt,num in rdata.items() for _ in range(num)]).upper()] \ No newline at end of file From 33b34108e591224a03b00a6b593e63d052d0b857 Mon Sep 17 00:00:00 2001 From: AKreuzer Date: Sun, 26 May 2024 15:28:47 +0200 Subject: [PATCH 05/17] start balcony --- buildings/Facade.py | 8 +++++++- buildings/elements/Balcony.py | 13 +++++++++++-- params.yml | 10 +++++++++- utils/Enums.py | 2 +- 4 files changed, 28 insertions(+), 5 deletions(-) diff --git a/buildings/Facade.py b/buildings/Facade.py index ea53ae7..715e88d 100644 --- a/buildings/Facade.py +++ b/buildings/Facade.py @@ -3,6 +3,7 @@ from utils.Enums import COLLUMN_STYLE from gdpc import Editor, Block, geometry, Transform from buildings.geometry.Vertice import Vertice from buildings.elements.Window import Window +from buildings.elements.Balcony import Balcony class Facade: def __init__(self, rdata, vertices : list[Vertice], height : int, length : int, is_inner_or_outer : COLLUMN_STYLE): @@ -36,7 +37,12 @@ class Facade: return Window(self.rdata["windows"] ,max_width, max_height) - def build_inter_floor(self, vertice : Vertice): + def get_balcony(self) -> Balcony: + len = rd.randint(self.rdata["balcony"]["size"]["min_len"], self.rdata["balcony"]["size"]["max_len"]) + max_width = self.length-2*self.padding + return Balcony(len, max_width, self.window) + + def build_inter_floor(self): if self.has_inter_floor: geometry.placeCuboid(self.editor,(0,self.height,-1),(self.length,self.height,-1),Block(self.materials[4], {"facing": "south", "half": "top"})) diff --git a/buildings/elements/Balcony.py b/buildings/elements/Balcony.py index 55691ab..fb13129 100644 --- a/buildings/elements/Balcony.py +++ b/buildings/elements/Balcony.py @@ -1,4 +1,13 @@ +import random as rd +from buildings.elements.Window import Window + class Balcony: - def __init__(self, length, width): + def __init__(self, rdata, length : int, max_width : int, windows : Window): + self.rdata = rdata self.length = length - self.width = width \ No newline at end of file + self.max_width = max_width + self.windows = windows + + def has_multiple_balcony(self): + if self.max_width < self.rdata["balcony"]["multiple"]["min_width"]: return False + return self.rdata["balcony"]["multiple"]["proba"] >= rd.random() \ No newline at end of file diff --git a/params.yml b/params.yml index 7cd9afc..687615f 100644 --- a/params.yml +++ b/params.yml @@ -40,4 +40,12 @@ buildings: top: 1 top_and_bottom: 1 inter_floor: 0.5 - balcony: 0.25 \ No newline at end of file + balcony: + proba : 0.25 + size: + min_len : 1 + max_len : 3 + min_width : 3 + multiple: + min_width: 5 + proba: 0.5 \ No newline at end of file diff --git a/utils/Enums.py b/utils/Enums.py index 4da1c62..2927857 100644 --- a/utils/Enums.py +++ b/utils/Enums.py @@ -15,4 +15,4 @@ class COLLUMN_STYLE(Enum): class BORDER_RADIUS(Enum): NONE = 0 TOP = 1 - TOP_AND_BOTTOM = 2 \ No newline at end of file + TOP_AND_BOTTOM = 2 \ No newline at end of file From 1371be413226731fabcf3a8b3d6ff96a17c3a98d Mon Sep 17 00:00:00 2001 From: AKreuzer Date: Mon, 27 May 2024 22:52:09 +0200 Subject: [PATCH 06/17] hotfix number 46 and optimization number 956 on windows --- buildings/Facade.py | 22 +++-- buildings/elements/Balcony.py | 16 +++- buildings/elements/Glass.py | 22 +++++ buildings/elements/Window.py | 163 ++++++++++++++++++-------------- buildings/geometry/Rectangle.py | 4 + buildings/geometry/Vertice.py | 2 +- main.py | 2 +- 7 files changed, 145 insertions(+), 86 deletions(-) create mode 100644 buildings/elements/Glass.py diff --git a/buildings/Facade.py b/buildings/Facade.py index 715e88d..63b3fa9 100644 --- a/buildings/Facade.py +++ b/buildings/Facade.py @@ -6,12 +6,11 @@ from buildings.elements.Window import Window from buildings.elements.Balcony import Balcony class Facade: - def __init__(self, rdata, vertices : list[Vertice], height : int, length : int, is_inner_or_outer : COLLUMN_STYLE): + def __init__(self, rdata, vertices : list[Vertice], is_inner_or_outer : COLLUMN_STYLE): self.rdata = rdata self.vertices = vertices self.is_inner_or_outer = is_inner_or_outer - self.height = height - self.length = length + self.height, self.length = self.get_dimentions() self.padding = 0 self.window = self.get_window() self.has_balcony = self.has_balcony() @@ -25,8 +24,8 @@ class Facade: for vertice in self.vertices: vertice.fill(editor, materials[0], self.height, xpadding = self.padding, zpadding = self.padding) with editor.pushTransform(Transform(vertice.point1.position,rotation = vertice.facing.value)): - self.build_inter_floor(vertice) - self.window.build(editor, vertice.get_len(), self.height, materials) + self.window.build(editor, materials) + self.build_inter_floor() def get_window(self) -> Window: if self.is_inner_or_outer == COLLUMN_STYLE.OUTER or self.is_inner_or_outer == COLLUMN_STYLE.BOTH: @@ -35,20 +34,23 @@ class Facade: max_width = self.length-2*self.padding max_height = min(self.height, self.rdata["windows"]["size"]["max_height"]) - return Window(self.rdata["windows"] ,max_width, max_height) + return Window(self.rdata["windows"] ,max_width, max_height, self.length, self.height) def get_balcony(self) -> Balcony: - len = rd.randint(self.rdata["balcony"]["size"]["min_len"], self.rdata["balcony"]["size"]["max_len"]) max_width = self.length-2*self.padding - return Balcony(len, max_width, self.window) + return Balcony(self.rdata["balcony"], max_width, self.window) def build_inter_floor(self): if self.has_inter_floor: - geometry.placeCuboid(self.editor,(0,self.height,-1),(self.length,self.height,-1),Block(self.materials[4], {"facing": "south", "half": "top"})) + geometry.placeCuboid(self.editor,(0,self.height,0),(self.length-1,self.height,0),Block(self.materials[0])) + geometry.placeCuboid(self.editor,(0,self.height,-1),(self.length-1,self.height,-1),Block(self.materials[4], {"facing": "south", "half": "top"})) def has_balcony(self) -> bool: - return self.rdata["balcony"] >= rd.random() + return self.rdata["balcony"]["proba"] >= rd.random() def has_inter_floor(self) -> bool: return self.rdata["inter_floor"] >= rd.random() + + def get_dimentions(self) -> tuple[int]: + return ( self.vertices[0].get_height(), self.vertices[0].get_len()) \ No newline at end of file diff --git a/buildings/elements/Balcony.py b/buildings/elements/Balcony.py index fb13129..f5d8d18 100644 --- a/buildings/elements/Balcony.py +++ b/buildings/elements/Balcony.py @@ -2,12 +2,20 @@ import random as rd from buildings.elements.Window import Window class Balcony: - def __init__(self, rdata, length : int, max_width : int, windows : Window): + def __init__(self, rdata, max_width : int, windows : Window): self.rdata = rdata - self.length = length self.max_width = max_width self.windows = windows + self.length = self.get_len() + self.has_multiple = self.has_multiple_balcony() - def has_multiple_balcony(self): + def follow_window(self) -> bool: + pass + + + def has_multiple_balcony(self) -> bool: if self.max_width < self.rdata["balcony"]["multiple"]["min_width"]: return False - return self.rdata["balcony"]["multiple"]["proba"] >= rd.random() \ No newline at end of file + return self.rdata["balcony"]["multiple"]["proba"] >= rd.random() + + def get_len(self) -> int: + return rd.randint(self.rdata["balcony"]["size"]["min_len"], self.rdata["balcony"]["size"]["max_len"]) \ No newline at end of file diff --git a/buildings/elements/Glass.py b/buildings/elements/Glass.py new file mode 100644 index 0000000..b7e1be3 --- /dev/null +++ b/buildings/elements/Glass.py @@ -0,0 +1,22 @@ +from gdpc import Editor +from buildings.geometry.Vertice import Vertice + +class Glass: + def __init__(self, x1 : int, x2 : int, group1 : list[Vertice], group2 : list[Vertice] = None): + self.x1, self.x2 = x1, x2 + self.group1, self.group2 = group1, group2 + + + def build(self, editor : Editor, material1 : str, material2 : str): + for elt in self.group1: + elt.fill(editor, material1) + if self.group2 is None: return + for elt in self.group2: + elt.fill(editor, material2) + + def reset_groups(self): + self.group1, self.group2 = [], [] + + def get_len(self): + return self.x2 - self.x1 + 1 + \ No newline at end of file diff --git a/buildings/elements/Window.py b/buildings/elements/Window.py index 4d211da..6719db7 100644 --- a/buildings/elements/Window.py +++ b/buildings/elements/Window.py @@ -5,83 +5,31 @@ from utils.Enums import COLLUMN_STYLE, BORDER_RADIUS from utils.functions import * from buildings.geometry.Point import Point from buildings.geometry.Vertice import Vertice +from buildings.elements.Glass import Glass class Window: - def __init__(self, rdata, max_width : int, max_height : int): + def __init__(self, rdata, max_width : int, max_height : int, facade_len : int, facade_height : int): self.rdata = rdata self.width, self.height = self.get_size(max_width, max_height) self.is_grounded = self.is_grounded() - self.has_multiple_windows = self.has_multiple_windows() self.is_alternate = self.is_alternate() - self.has_vertical_crossbar, self.has_horizontal_crossbar = self.has_crossbars() self.border_radius = self.border_radius() - self.padding = 0 + self.has_multiple = self.has_multiple_windows() + self.has_vertical_crossbar, self.has_horizontal_crossbar = self.has_crossbars() + self.padding, self.ypadding = self.get_padding(facade_len, facade_height) + self.windows = self.get_windows() self.editor, self.materials = None,None - def build(self, editor : Editor, facade_len : int, facade_height : int, materials : list[str]): + def build(self, editor : Editor, materials : list[str]): self.editor = editor self.materials = materials - - # correction to avoid asymetry - self.padding = (facade_len - self.width)//2 - self.width = facade_len - self.padding*2 - - if not self.is_grounded: editor.transform @= Transform((0,(facade_height-self.height)//2,0)) - editor.transform @= Transform((self.padding,0,0)) - - if self.has_multiple_windows: self.build_multiple_windows() - else : - self.place_glasses(0, self.width) - - def build_multiple_windows(self): - slices = rd.randint(3, self.width//self.rdata["size"]["min_width"]) - mid = math.ceil(slices/2) - windows_count = mid - inter_count = slices - windows_count - window_size = rd.randint(self.rdata["size"]["min_width"], (self.width-inter_count) // windows_count) - inter_size = (self.width - window_size*windows_count) // inter_count - - is_even= slices % 2 == 0 - is_window, gap = True, 0 - remainder = self.width - (window_size*windows_count + inter_size*inter_count) - for i in range(1,slices+1): - wsize,isize = window_size, inter_size - if is_even and i == mid: wsize, isize = wsize*2, isize*2 - if i == mid: wsize, isize = wsize + remainder, isize + remainder - - # kepp a spacing between windows, "is revert" is used to keep symetry - if is_window: - self.place_glasses(gap, gap+wsize) - gap += wsize - else : - gap += isize - - is_window = not is_window - - def place_glasses(self, x1 : int, x2 : int): - len = x2 - x1 - if self.is_alternate: - mid = x1 + len//2 - - is_block, is_even = False, len % 2 == 0 - for x in range(x1,x2): - if is_even and x == mid: is_block = not is_block # to keep symetry - id = 1 if not is_block else 2 - geometry.placeCuboid(self.editor,(x,0,0),(x,self.height,0),Block(self.materials[id])) - is_block = not is_block - - else: - geometry.placeCuboid(self.editor,(x1,0,0),(x2-1,self.height,0),Block(self.materials[1])) - - self.build_crossbars(x1, x2-1, len) - if len > 1: self.build_border_radius(x1, x2-1) - - def get_size(self, max_width : int ,max_height : int) -> tuple[int,int]: - return ( - rd.randint(self.rdata["size"]["min_width"],max_width), - rd.randint(self.rdata["size"]["min_height"],max_height) - ) - + with editor.pushTransform(Transform((self.padding,self.ypadding,0))): + for g in self.windows: + len = g.get_len() + g.build(editor, materials[1], materials[2]) + self.build_crossbars(g.x1, g.x2, len) + if len > 1: self.build_border_radius(g.x1, g.x2) + def build_crossbars(self, x1 : int, x2 : int, len : int): if self.has_vertical_crossbar and self.height >= self.rdata["crossbars"]["min_height_for_vertical_crossbar"]: y = self.height//2 @@ -97,10 +45,64 @@ class Window: if self.border_radius == BORDER_RADIUS.TOP_AND_BOTTOM: self.editor.placeBlock((x1,0,0),Block(self.materials[4], {"facing": "west"})) self.editor.placeBlock((x2,0,0),Block(self.materials[4], {"facing": "east"})) - - def is_grounded(self): - # if the window is grounded or if there is a padding between the window and the ground - return self.rdata["grounded"] >= rd.random() + + + def get_windows(self) -> list[Glass]: + windows = [] + if not self.has_multiple: windows = [Glass(0,self.width-1,[self.create_window(0, self.width)])] + else: windows = self.get_multiple_windows() + if self.is_alternate: self.alternate(windows) + + return windows + + def get_multiple_windows(self) -> list[Glass]: + windows = [] + slices = rd.randint(3, self.width//self.rdata["size"]["min_width"]) + mid = math.ceil(slices/2) + windows_count = mid + inter_count = slices - windows_count + window_size = rd.randint(self.rdata["size"]["min_width"], (self.width-inter_count) // windows_count) + inter_size = (self.width - window_size*windows_count) // inter_count + + is_even= slices % 2 == 0 + is_window, gap = True, 0 + remainder = self.width - (window_size*windows_count + inter_size*inter_count) + if windows_count % 2 == 1 and inter_count % 2 == 1: + inter_count -= 1 + remainder += inter_size + is_even = not is_even + print(window_size,windows_count,inter_size,inter_count,remainder,self.width,"\n\n") + for i in range(1,slices+1): + wsize,isize = window_size, inter_size + if is_even and i == mid: wsize, isize = wsize*2, isize*2 + if i == mid: wsize, isize = wsize + remainder, isize + remainder + + if is_window: + windows.append(Glass(gap, gap+wsize-1,[self.create_window(gap, wsize)])) + gap += wsize + else : + gap += isize + + is_window = not is_window + + return windows + + def alternate(self, windows : list[Glass]): + for g in windows: + g.reset_groups() + len = g.get_len() + mid = g.x1 + len//2 + + is_block, is_even = False, len % 2 == 0 + for x in range(g.x1,g.x2+1): + if is_even and x == mid: is_block = not is_block # to keep symetry + if is_block: g.group2.append(self.create_window(x)) + else : g.group1.append(self.create_window(x)) + is_block = not is_block + + def create_window(self, x1 : int, length : int = None) -> Vertice: + x2 = x1 if length is None else x1 + length -1 + return Vertice(Point(x1,0,0), Point(x2,self.height,0)) def has_multiple_windows(self): if self.width > self.rdata["size"]["max_width"]: return True @@ -112,6 +114,27 @@ class Window: # if the window alternate between glass_blocks and glass_panes return self.rdata["alternate"] >= rd.random() + + def get_size(self, max_width : int ,max_height : int) -> tuple[int,int]: + return ( + rd.randint(self.rdata["size"]["min_width"],max_width), + rd.randint(self.rdata["size"]["min_height"],max_height) + ) + + def get_padding(self, facade_len : int, facade_height : int) -> tuple[int]: + padding,ypadding = 0,0 + if not self.is_grounded: ypadding = (facade_height - self.height)//2 + + # correction to avoid asymetry + padding = (facade_len - self.width)//2 + self.width = facade_len - padding*2 + + return (padding, ypadding) + + def is_grounded(self): + # if the window is grounded or if there is a padding between the window and the ground + return self.rdata["grounded"] >= rd.random() + def has_crossbars(self): # if the window has crossbars data = self.rdata["crossbars"] diff --git a/buildings/geometry/Rectangle.py b/buildings/geometry/Rectangle.py index a199982..827ba41 100644 --- a/buildings/geometry/Rectangle.py +++ b/buildings/geometry/Rectangle.py @@ -9,8 +9,12 @@ class Rectangle: def get_position(self): return (self.point1.position, self.point2.position) + def get_height(self): + return self.point2.y - self.point1.y + 1 + def fill(self,editor : Editor, material : str, y : int = None, xpadding : int = 0, zpadding : int = 0): if self.point2.x - self.point1.x < 2*xpadding: xpadding = 0 if self.point2.z - self.point1.z < 2*zpadding: zpadding = 0 + if y is None: y = self.point2.y geometry.placeCuboid(editor, (self.point1.x+xpadding, 0, self.point1.z+zpadding), (self.point2.x-xpadding, y, self.point2.z-zpadding), Block(material)) diff --git a/buildings/geometry/Vertice.py b/buildings/geometry/Vertice.py index c576af5..691f6b5 100644 --- a/buildings/geometry/Vertice.py +++ b/buildings/geometry/Vertice.py @@ -3,7 +3,7 @@ from buildings.geometry.Point import Point from buildings.geometry.Rectangle import Rectangle class Vertice(Rectangle): - def __init__(self, point1 : Point, point2 : Point, facing : DIRECTION): + def __init__(self, point1 : Point, point2 : Point, facing : DIRECTION = None): Rectangle.__init__(self, point1, point2) self.facing = facing diff --git a/main.py b/main.py index 9dd676e..55c4506 100644 --- a/main.py +++ b/main.py @@ -30,7 +30,7 @@ geometry.placeCuboid(editor, (0,0,-1), (100,15,1), Block("air")) x = 0 facade = [] for i in range(3,13): - facade.append(Facade(random_data["buildings"]["facade"],[Vertice(Point(x,0,0), Point(x+i,0,0), DIRECTION.NORTH)],i,i,COLLUMN_STYLE.NONE)) + facade.append(Facade(random_data["buildings"]["facade"],[Vertice(Point(x,0,0), Point(x+i,i,0), DIRECTION.NORTH)],COLLUMN_STYLE.NONE)) x += i+2 for f in facade: From 52501658939680ff352d2187b620dce33bc0b56d Mon Sep 17 00:00:00 2001 From: AKreuzer Date: Tue, 28 May 2024 20:12:20 +0200 Subject: [PATCH 07/17] start balcony --- buildings/Facade.py | 2 +- buildings/elements/Balcony.py | 40 +++++++++++++++++++++++++++++++---- buildings/elements/Glass.py | 4 ++-- buildings/elements/Window.py | 15 +++++++------ buildings/geometry/Vertice.py | 4 ++-- params.yml | 5 ++++- 6 files changed, 53 insertions(+), 17 deletions(-) diff --git a/buildings/Facade.py b/buildings/Facade.py index 63b3fa9..7dfc960 100644 --- a/buildings/Facade.py +++ b/buildings/Facade.py @@ -52,5 +52,5 @@ class Facade: return self.rdata["inter_floor"] >= rd.random() def get_dimentions(self) -> tuple[int]: - return ( self.vertices[0].get_height(), self.vertices[0].get_len()) + return ( self.vertices[0].get_height(), len(self.vertices[0])) \ No newline at end of file diff --git a/buildings/elements/Balcony.py b/buildings/elements/Balcony.py index f5d8d18..f8c3b9a 100644 --- a/buildings/elements/Balcony.py +++ b/buildings/elements/Balcony.py @@ -1,17 +1,49 @@ import random as rd +from buildings.geometry.Point import Point +from buildings.geometry.Vertice import Vertice from buildings.elements.Window import Window class Balcony: - def __init__(self, rdata, max_width : int, windows : Window): + def __init__(self, rdata, windows : Window): self.rdata = rdata - self.max_width = max_width self.windows = windows self.length = self.get_len() self.has_multiple = self.has_multiple_balcony() + self.follow_window = self.follow_window() + def get_structures(self) -> list[Vertice]: + attach_points = self.get_attach_points() + len_attach_points = len(attach_points) + min_wid = self.rdata["balcony"]["size"]["min_width"] + growth_chance = self.rdata["balcony"]["growth"] + midpoint = len_attach_points//2 + x1,x2 = midpoint, len_attach_points - midpoint + + structures = [] + while True: + x1 -= 1 + x2 += 1 + if x1 < 0 : break + if attach_points[x2] - attach_points[x1] + 1 < min_wid: continue + if growth_chance < rd.random(): + structures.append(self.create_structure(attach_points[x1], attach_points[x2])) + if not self.has_multiple: break + + + def get_attach_points(self) -> list[int]: + points = [i for i in range(self.max_width)] + if self.follow_window: + for w in self.windows.windows: + for i in range(w.x1, w.x2+1): + points.remove(i) + + return points + + def create_structure(self, x1 : int, x2 : int) -> Vertice: + return Vertice(Point(x1,0,0), Point(x2,0,self.length-1)) + def follow_window(self) -> bool: - pass - + return self.windows.ypadding > 3 def has_multiple_balcony(self) -> bool: if self.max_width < self.rdata["balcony"]["multiple"]["min_width"]: return False diff --git a/buildings/elements/Glass.py b/buildings/elements/Glass.py index b7e1be3..e9f40ee 100644 --- a/buildings/elements/Glass.py +++ b/buildings/elements/Glass.py @@ -16,7 +16,7 @@ class Glass: def reset_groups(self): self.group1, self.group2 = [], [] - - def get_len(self): + + def __len__(self): return self.x2 - self.x1 + 1 \ No newline at end of file diff --git a/buildings/elements/Window.py b/buildings/elements/Window.py index 6719db7..953d074 100644 --- a/buildings/elements/Window.py +++ b/buildings/elements/Window.py @@ -25,10 +25,10 @@ class Window: self.materials = materials with editor.pushTransform(Transform((self.padding,self.ypadding,0))): for g in self.windows: - len = g.get_len() + leng = len(g) g.build(editor, materials[1], materials[2]) - self.build_crossbars(g.x1, g.x2, len) - if len > 1: self.build_border_radius(g.x1, g.x2) + self.build_crossbars(g.x1, g.x2, leng) + if leng > 1: self.build_border_radius(g.x1, g.x2) def build_crossbars(self, x1 : int, x2 : int, len : int): if self.has_vertical_crossbar and self.height >= self.rdata["crossbars"]["min_height_for_vertical_crossbar"]: @@ -67,11 +67,12 @@ class Window: is_even= slices % 2 == 0 is_window, gap = True, 0 remainder = self.width - (window_size*windows_count + inter_size*inter_count) + if windows_count % 2 == 1 and inter_count % 2 == 1: inter_count -= 1 remainder += inter_size is_even = not is_even - print(window_size,windows_count,inter_size,inter_count,remainder,self.width,"\n\n") + for i in range(1,slices+1): wsize,isize = window_size, inter_size if is_even and i == mid: wsize, isize = wsize*2, isize*2 @@ -90,10 +91,10 @@ class Window: def alternate(self, windows : list[Glass]): for g in windows: g.reset_groups() - len = g.get_len() - mid = g.x1 + len//2 + leng = len(g) + mid = g.x1 + leng//2 - is_block, is_even = False, len % 2 == 0 + is_block, is_even = False, leng % 2 == 0 for x in range(g.x1,g.x2+1): if is_even and x == mid: is_block = not is_block # to keep symetry if is_block: g.group2.append(self.create_window(x)) diff --git a/buildings/geometry/Vertice.py b/buildings/geometry/Vertice.py index 691f6b5..08e1057 100644 --- a/buildings/geometry/Vertice.py +++ b/buildings/geometry/Vertice.py @@ -15,7 +15,7 @@ class Vertice(Rectangle): case DIRECTION.EAST | DIRECTION.WEST: return [Point(x = self.point1.x, z = self.point1.z - 1), Point(x = self.point2.x, z = self.point2.z + 1)] - - def get_len(self): + + def __len__(self): return self.point2.x - self.point1.x + self.point2.z - self.point1.z + 1 \ No newline at end of file diff --git a/params.yml b/params.yml index 687615f..39dfa29 100644 --- a/params.yml +++ b/params.yml @@ -42,10 +42,13 @@ buildings: inter_floor: 0.5 balcony: proba : 0.25 + growth: 0.8 # [growth]% chance to have min_width + 1 balcony length, [growth**2]% chance to have min_width + 2 balcony length, etc size: min_len : 1 max_len : 3 min_width : 3 multiple: + # probability to have multiple balcony IF POSSIBLE + proba: 0.5 min_width: 5 - proba: 0.5 \ No newline at end of file + min_gap: 0 \ No newline at end of file From 0e5305525d0d30ca57416f047ac9b8ec993696b5 Mon Sep 17 00:00:00 2001 From: AKreuzer Date: Thu, 30 May 2024 17:32:20 +0200 Subject: [PATCH 08/17] balcony fucked --- buildings/Facade.py | 8 +++++-- buildings/elements/Balcony.py | 42 +++++++++++++++++++++++++++-------- 2 files changed, 39 insertions(+), 11 deletions(-) diff --git a/buildings/Facade.py b/buildings/Facade.py index 7dfc960..af0143e 100644 --- a/buildings/Facade.py +++ b/buildings/Facade.py @@ -14,6 +14,7 @@ class Facade: self.padding = 0 self.window = self.get_window() self.has_balcony = self.has_balcony() + self.balcony = self.get_balcony() self.has_inter_floor = self.has_inter_floor() self.editor, self.materials = None,None @@ -26,6 +27,7 @@ class Facade: with editor.pushTransform(Transform(vertice.point1.position,rotation = vertice.facing.value)): self.window.build(editor, materials) self.build_inter_floor() + if self.has_balcony: self.balcony.build(editor, materials) def get_window(self) -> Window: if self.is_inner_or_outer == COLLUMN_STYLE.OUTER or self.is_inner_or_outer == COLLUMN_STYLE.BOTH: @@ -36,7 +38,8 @@ class Facade: return Window(self.rdata["windows"] ,max_width, max_height, self.length, self.height) - def get_balcony(self) -> Balcony: + def get_balcony(self) -> Balcony|None: + if not self.has_balcony: return None max_width = self.length-2*self.padding return Balcony(self.rdata["balcony"], max_width, self.window) @@ -44,8 +47,9 @@ class Facade: if self.has_inter_floor: geometry.placeCuboid(self.editor,(0,self.height,0),(self.length-1,self.height,0),Block(self.materials[0])) geometry.placeCuboid(self.editor,(0,self.height,-1),(self.length-1,self.height,-1),Block(self.materials[4], {"facing": "south", "half": "top"})) - + def has_balcony(self) -> bool: + return True return self.rdata["balcony"]["proba"] >= rd.random() def has_inter_floor(self) -> bool: diff --git a/buildings/elements/Balcony.py b/buildings/elements/Balcony.py index f8c3b9a..9d9edd0 100644 --- a/buildings/elements/Balcony.py +++ b/buildings/elements/Balcony.py @@ -1,34 +1,58 @@ import random as rd +from gdpc import Editor, Block, geometry, Transform from buildings.geometry.Point import Point from buildings.geometry.Vertice import Vertice from buildings.elements.Window import Window class Balcony: - def __init__(self, rdata, windows : Window): + def __init__(self, rdata, max_width : int, windows : Window): self.rdata = rdata self.windows = windows + self.max_width = max_width self.length = self.get_len() self.has_multiple = self.has_multiple_balcony() self.follow_window = self.follow_window() + self.structure = self.get_structures() + + def build(self, editor : Editor, materials : list[str]): + for s in self.structure: + s.fill(editor, materials[0]) def get_structures(self) -> list[Vertice]: attach_points = self.get_attach_points() len_attach_points = len(attach_points) - min_wid = self.rdata["balcony"]["size"]["min_width"] - growth_chance = self.rdata["balcony"]["growth"] + min_wid = self.rdata["size"]["min_width"] -1 + min_gap = self.rdata["multiple"]["min_gap"] + growth_chance = self.rdata["growth"] midpoint = len_attach_points//2 x1,x2 = midpoint, len_attach_points - midpoint structures = [] + centered = True while True: x1 -= 1 - x2 += 1 - if x1 < 0 : break - if attach_points[x2] - attach_points[x1] + 1 < min_wid: continue + x2 += 1 if centered else 0 + leng = attach_points[x2] - attach_points[x1] - 1 + + if x1 == 0: + if leng >= min_wid: structures.append(self.create_structure(attach_points[x1], attach_points[x2])) + break + if leng < min_wid: continue + if growth_chance < rd.random(): structures.append(self.create_structure(attach_points[x1], attach_points[x2])) + if not centered: + structures.append(self.create_structure(attach_points[len_attach_points-x1], attach_points[len_attach_points-x2])) + if not self.has_multiple: break + else: + if x1-min_wid < min_gap: break + gap = rd.randint(min_gap, x1-min_wid) + x2 = x1-gap + x1 = x2-min_wid + + return structures def get_attach_points(self) -> list[int]: points = [i for i in range(self.max_width)] @@ -46,8 +70,8 @@ class Balcony: return self.windows.ypadding > 3 def has_multiple_balcony(self) -> bool: - if self.max_width < self.rdata["balcony"]["multiple"]["min_width"]: return False - return self.rdata["balcony"]["multiple"]["proba"] >= rd.random() + if self.max_width < self.rdata["multiple"]["min_width"]: return False + return self.rdata["multiple"]["proba"] >= rd.random() def get_len(self) -> int: - return rd.randint(self.rdata["balcony"]["size"]["min_len"], self.rdata["balcony"]["size"]["max_len"]) \ No newline at end of file + return rd.randint(self.rdata["size"]["min_len"], self.rdata["size"]["max_len"]) \ No newline at end of file From c3fc592f844f7d04c257f1e6ccc94dd16fc53ddb Mon Sep 17 00:00:00 2001 From: KAymeric Date: Tue, 4 Jun 2024 19:07:50 +0200 Subject: [PATCH 09/17] some critical fixes on balcony --- buildings/elements/Balcony.py | 8 +++++--- main.py | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/buildings/elements/Balcony.py b/buildings/elements/Balcony.py index 9d9edd0..fcab85e 100644 --- a/buildings/elements/Balcony.py +++ b/buildings/elements/Balcony.py @@ -20,8 +20,8 @@ class Balcony: def get_structures(self) -> list[Vertice]: attach_points = self.get_attach_points() - len_attach_points = len(attach_points) - min_wid = self.rdata["size"]["min_width"] -1 + len_attach_points = len(attach_points)-1 + min_wid = self.rdata["size"]["min_width"] min_gap = self.rdata["multiple"]["min_gap"] growth_chance = self.rdata["growth"] midpoint = len_attach_points//2 @@ -32,6 +32,7 @@ class Balcony: while True: x1 -= 1 x2 += 1 if centered else 0 + print(x1,x2, attach_points) leng = attach_points[x2] - attach_points[x1] - 1 if x1 == 0: @@ -46,6 +47,7 @@ class Balcony: if not self.has_multiple: break else: + print(x1,min_wid, min_gap) if x1-min_wid < min_gap: break gap = rd.randint(min_gap, x1-min_wid) x2 = x1-gap @@ -64,7 +66,7 @@ class Balcony: return points def create_structure(self, x1 : int, x2 : int) -> Vertice: - return Vertice(Point(x1,0,0), Point(x2,0,self.length-1)) + return Vertice(Point(x1,0,0), Point(x2,0,-self.length+1)) def follow_window(self) -> bool: return self.windows.ypadding > 3 diff --git a/main.py b/main.py index 55c4506..45fe8f5 100644 --- a/main.py +++ b/main.py @@ -24,7 +24,7 @@ random_data = y.data transform = Transform((0,-60,-5),rotation = 0) editor.transform.push(transform) -geometry.placeCuboid(editor, (0,0,-1), (100,15,1), Block("air")) +geometry.placeCuboid(editor, (0,0,-3), (100,15,1), Block("air")) x = 0 From a4561c4ccbc0c681e8bcbc0043bf53646c0a5f01 Mon Sep 17 00:00:00 2001 From: AKreuzer Date: Wed, 5 Jun 2024 02:10:01 +0200 Subject: [PATCH 10/17] balcony fixed --- buildings/TODO | 11 +++++++ buildings/elements/Balcony.py | 56 ++++++++++++++++++++++++----------- params.yml | 8 +++-- 3 files changed, 55 insertions(+), 20 deletions(-) create mode 100644 buildings/TODO diff --git a/buildings/TODO b/buildings/TODO new file mode 100644 index 0000000..5c50d3d --- /dev/null +++ b/buildings/TODO @@ -0,0 +1,11 @@ +Encadrement fenêtre +toit de balcon avec/sans pilliers +border radius balcon +collumn style +détails facade +rdc +toit +tiles 3d +opti géométrique +opti textures +opti gdpc \ No newline at end of file diff --git a/buildings/elements/Balcony.py b/buildings/elements/Balcony.py index fcab85e..6f1bc1f 100644 --- a/buildings/elements/Balcony.py +++ b/buildings/elements/Balcony.py @@ -10,13 +10,30 @@ class Balcony: self.windows = windows self.max_width = max_width self.length = self.get_len() - self.has_multiple = self.has_multiple_balcony() + self.has_multiple = self.has_multiple() + self.has_details = self.has_details() self.follow_window = self.follow_window() self.structure = self.get_structures() + self.editor, self.materials = None,None def build(self, editor : Editor, materials : list[str]): + self.editor = editor + self.materials = materials for s in self.structure: s.fill(editor, materials[0]) + self.build_rembard(s) + self.build_details(s) + + def build_rembard(self, s : Vertice): + geometry.placeCuboid(self.editor,(s.point1.x,1,-1),(s.point1.x,1,-self.length),Block(self.materials[3])) + geometry.placeCuboid(self.editor,(s.point2.x,1,-1),(s.point2.x,1,-self.length),Block(self.materials[3])) + geometry.placeCuboid(self.editor,(s.point1.x,1,-self.length),(s.point2.x,1,-self.length),Block(self.materials[3])) + + def build_details(self, s : Vertice): + if not self.has_details: return + geometry.placeCuboid(self.editor,(s.point1.x,0,-1),(s.point1.x,0,-self.length),Block(self.materials[4], {"facing": "east", "half": "top"})) + geometry.placeCuboid(self.editor,(s.point2.x,0,-1),(s.point2.x,0,-self.length),Block(self.materials[4], {"facing": "west", "half": "top"})) + geometry.placeCuboid(self.editor,(s.point1.x,0,-self.length),(s.point2.x,0,-self.length),Block(self.materials[4], {"facing": "south", "half": "top"})) def get_structures(self) -> list[Vertice]: attach_points = self.get_attach_points() @@ -29,51 +46,56 @@ class Balcony: structures = [] centered = True - while True: + while x1 > 0: x1 -= 1 x2 += 1 if centered else 0 - print(x1,x2, attach_points) leng = attach_points[x2] - attach_points[x1] - 1 if x1 == 0: - if leng >= min_wid: structures.append(self.create_structure(attach_points[x1], attach_points[x2])) + if leng >= min_wid: self.append_structure(structures, x1, x2, attach_points, len_attach_points, centered) break if leng < min_wid: continue if growth_chance < rd.random(): - structures.append(self.create_structure(attach_points[x1], attach_points[x2])) - if not centered: - structures.append(self.create_structure(attach_points[len_attach_points-x1], attach_points[len_attach_points-x2])) + self.append_structure(structures, x1, x2, attach_points, len_attach_points, centered) if not self.has_multiple: break else: - print(x1,min_wid, min_gap) - if x1-min_wid < min_gap: break - gap = rd.randint(min_gap, x1-min_wid) + centered = False + if attach_points[x1]-min_wid < min_gap: break + gap = rd.randint(min_gap, attach_points[x1]-min_wid) x2 = x1-gap - x1 = x2-min_wid - - + x1 = x2-min_wid+1 + return structures def get_attach_points(self) -> list[int]: points = [i for i in range(self.max_width)] if self.follow_window: + pad = self.windows.padding for w in self.windows.windows: - for i in range(w.x1, w.x2+1): + for i in range(pad+w.x1, pad+w.x2+1): points.remove(i) return points def create_structure(self, x1 : int, x2 : int) -> Vertice: - return Vertice(Point(x1,0,0), Point(x2,0,-self.length+1)) + return Vertice(Point(x1,0,0), Point(x2,0,-self.length)) + + def append_structure(self, structures : list[Vertice], x1 : int, x2 : int, attach_points : list[int], len_attach_points : int, centered : bool): + structures.append(self.create_structure(attach_points[x1], attach_points[x2])) + if not centered: + structures.append(self.create_structure(attach_points[len_attach_points-x1], attach_points[len_attach_points-x2])) def follow_window(self) -> bool: - return self.windows.ypadding > 3 + return not self.windows.ypadding > 3 - def has_multiple_balcony(self) -> bool: + def has_multiple(self) -> bool: if self.max_width < self.rdata["multiple"]["min_width"]: return False return self.rdata["multiple"]["proba"] >= rd.random() + def has_details(self) -> bool: + return self.rdata["details"] >= rd.random() + def get_len(self) -> int: return rd.randint(self.rdata["size"]["min_len"], self.rdata["size"]["max_len"]) \ No newline at end of file diff --git a/params.yml b/params.yml index 39dfa29..c59eb99 100644 --- a/params.yml +++ b/params.yml @@ -42,13 +42,15 @@ buildings: inter_floor: 0.5 balcony: proba : 0.25 - growth: 0.8 # [growth]% chance to have min_width + 1 balcony length, [growth**2]% chance to have min_width + 2 balcony length, etc + growth: 0.5 # [growth]% chance to have min_width + 1 balcony length, [growth**2]% chance to have min_width + 2 balcony length, etc size: min_len : 1 max_len : 3 min_width : 3 multiple: # probability to have multiple balcony IF POSSIBLE - proba: 0.5 + # this feature need a very large facade + proba: 1 min_width: 5 - min_gap: 0 \ No newline at end of file + min_gap: 1 + details: 0.35 \ No newline at end of file From 536c71d3724d936d31ef29a33117578aab3ec6dc Mon Sep 17 00:00:00 2001 From: AKreuzer Date: Thu, 6 Jun 2024 12:40:35 +0200 Subject: [PATCH 11/17] balcony details and start facade details --- buildings/elements/Balcony.py | 30 ++++++++++++++++++++++++++++- buildings/elements/FacadeDetails.py | 19 ++++++++++++++++++ buildings/elements/Window.py | 8 ++++---- main.py | 4 ++-- params.yml | 8 +++++++- utils/Enums.py | 9 +++++++-- 6 files changed, 68 insertions(+), 10 deletions(-) create mode 100644 buildings/elements/FacadeDetails.py diff --git a/buildings/elements/Balcony.py b/buildings/elements/Balcony.py index 6f1bc1f..cc11be8 100644 --- a/buildings/elements/Balcony.py +++ b/buildings/elements/Balcony.py @@ -1,5 +1,7 @@ import random as rd -from gdpc import Editor, Block, geometry, Transform +from gdpc import Editor, Block, geometry +from utils.functions import * +from utils.Enums import BALCONY_BORDER_RADIUS from buildings.geometry.Point import Point from buildings.geometry.Vertice import Vertice from buildings.elements.Window import Window @@ -12,6 +14,7 @@ class Balcony: self.length = self.get_len() self.has_multiple = self.has_multiple() self.has_details = self.has_details() + self.border_radius = self.has_border_radius() self.follow_window = self.follow_window() self.structure = self.get_structures() self.editor, self.materials = None,None @@ -23,6 +26,7 @@ class Balcony: s.fill(editor, materials[0]) self.build_rembard(s) self.build_details(s) + self.build_border_radius(s) def build_rembard(self, s : Vertice): geometry.placeCuboid(self.editor,(s.point1.x,1,-1),(s.point1.x,1,-self.length),Block(self.materials[3])) @@ -34,8 +38,27 @@ class Balcony: geometry.placeCuboid(self.editor,(s.point1.x,0,-1),(s.point1.x,0,-self.length),Block(self.materials[4], {"facing": "east", "half": "top"})) geometry.placeCuboid(self.editor,(s.point2.x,0,-1),(s.point2.x,0,-self.length),Block(self.materials[4], {"facing": "west", "half": "top"})) geometry.placeCuboid(self.editor,(s.point1.x,0,-self.length),(s.point2.x,0,-self.length),Block(self.materials[4], {"facing": "south", "half": "top"})) + + def build_border_radius(self, s : Vertice): + if self.border_radius == BALCONY_BORDER_RADIUS.NONE: return + + geometry.placeCuboid(self.editor,(s.point1.x,0,-self.length),(s.point1.x,1,-self.length),Block("air")) + geometry.placeCuboid(self.editor,(s.point2.x,0,-self.length),(s.point2.x,1,-self.length),Block("air")) + self.editor.placeBlock((s.point1.x+1,1,-self.length+1), Block(self.materials[3])) + self.editor.placeBlock((s.point2.x-1,1,-self.length+1), Block(self.materials[3])) + + if self.has_details: + self.editor.placeBlock((s.point1.x,0,-self.length+1), Block(self.materials[4], {"facing": "south", "half": "top"})) + self.editor.placeBlock((s.point1.x+1,0,-self.length), Block(self.materials[4], {"facing": "east", "half": "top"})) + self.editor.placeBlock((s.point2.x,0,-self.length+1), Block(self.materials[4], {"facing": "south", "half": "top"})) + self.editor.placeBlock((s.point2.x-1,0,-self.length), Block(self.materials[4], {"facing": "west", "half": "top"})) + + if self.border_radius == BALCONY_BORDER_RADIUS.FULL: + self.editor.placeBlock((s.point1.x+1,0,-self.length+1), Block(self.materials[4], {"facing": "east", "half": "top"})) + self.editor.placeBlock((s.point2.x-1,0,-self.length+1), Block(self.materials[4], {"facing": "west", "half": "top"})) def get_structures(self) -> list[Vertice]: + # structures are the base shape of the balcony attach_points = self.get_attach_points() len_attach_points = len(attach_points)-1 min_wid = self.rdata["size"]["min_width"] @@ -70,6 +93,7 @@ class Balcony: return structures def get_attach_points(self) -> list[int]: + # points where the structures can start/finish points = [i for i in range(self.max_width)] if self.follow_window: pad = self.windows.padding @@ -97,5 +121,9 @@ class Balcony: def has_details(self) -> bool: return self.rdata["details"] >= rd.random() + def has_border_radius(self) -> bool: + if self.length < 2: return BALCONY_BORDER_RADIUS.NONE + return select_random(self.rdata["border_radius"], BALCONY_BORDER_RADIUS) + def get_len(self) -> int: return rd.randint(self.rdata["size"]["min_len"], self.rdata["size"]["max_len"]) \ No newline at end of file diff --git a/buildings/elements/FacadeDetails.py b/buildings/elements/FacadeDetails.py new file mode 100644 index 0000000..9770cdc --- /dev/null +++ b/buildings/elements/FacadeDetails.py @@ -0,0 +1,19 @@ +from buildings.geometry.Vertice import Vertice + +class FacadeDetails: + def __init__(self,rdata , zones : list[Vertice]): + self.zones = zones + self.sizes = self.get_sizes() + + def get_sizes(self) -> list[tuple[int]]: + # foreach different zone sizes in self.zones, we will gen different details + sizes = [] + center_for_symetry = len(self.zones) // 2 + for zone in self.zones: + size = zone.point2.position - zone.point1.position + if size not in sizes : + sizes.append(size) + + return sizes + + \ No newline at end of file diff --git a/buildings/elements/Window.py b/buildings/elements/Window.py index 953d074..4028158 100644 --- a/buildings/elements/Window.py +++ b/buildings/elements/Window.py @@ -1,7 +1,7 @@ import random as rd import math from gdpc import Editor, Block, geometry, Transform -from utils.Enums import COLLUMN_STYLE, BORDER_RADIUS +from utils.Enums import WINDOW_BORDER_RADIUS from utils.functions import * from buildings.geometry.Point import Point from buildings.geometry.Vertice import Vertice @@ -39,10 +39,10 @@ class Window: geometry.placeCuboid(self.editor,(x1+x,0,0),(x2-x,self.height,0),Block(self.materials[3], {"up" : "true"})) def build_border_radius(self, x1 : int, x2 : int): - if self.border_radius != BORDER_RADIUS.NONE: + if self.border_radius != WINDOW_BORDER_RADIUS.NONE: self.editor.placeBlock((x1,self.height,0),Block(self.materials[4], {"facing": "west", "half": "top"})) self.editor.placeBlock((x2,self.height,0),Block(self.materials[4], {"facing": "east", "half": "top"})) - if self.border_radius == BORDER_RADIUS.TOP_AND_BOTTOM: + if self.border_radius == WINDOW_BORDER_RADIUS.TOP_AND_BOTTOM: self.editor.placeBlock((x1,0,0),Block(self.materials[4], {"facing": "west"})) self.editor.placeBlock((x2,0,0),Block(self.materials[4], {"facing": "east"})) @@ -143,4 +143,4 @@ class Window: return (data["vertical_crossbar"] >= rd.random(), data["horizontal_crossbar"] >= rd.random()) def border_radius(self): - return select_random(self.rdata["border_radius"], BORDER_RADIUS) \ No newline at end of file + return select_random(self.rdata["border_radius"], WINDOW_BORDER_RADIUS) \ No newline at end of file diff --git a/main.py b/main.py index 45fe8f5..116d074 100644 --- a/main.py +++ b/main.py @@ -7,7 +7,7 @@ from buildings.Building import Building from buildings.geometry.Vertice import Vertice from buildings.geometry.Point import Point -from utils.Enums import DIRECTION,COLLUMN_STYLE,BORDER_RADIUS +from utils.Enums import DIRECTION,COLLUMN_STYLE,WINDOW_BORDER_RADIUS from buildings.Facade import Facade from utils.functions import * @@ -42,7 +42,7 @@ for f in facade: # geometry.placeCuboid(editor, (-10,-60,-10), (85,-55,85), Block("air")) # B = Building((0,0), (75,75), shapes[7]['matrice']) -# B.foundations.polygon.fill_vertice(editor, "pink_wool", -60) +# B.foundations.polygon.fill_vertice(editor, "pink_wool", -60) # for collumn in B.foundations.collumns: # collumn.fill(editor, "white_concrete", -60, -55) # B.foundations.polygon.fill_polygon(editor, "white_concrete", -60) diff --git a/params.yml b/params.yml index c59eb99..cd6b099 100644 --- a/params.yml +++ b/params.yml @@ -53,4 +53,10 @@ buildings: proba: 1 min_width: 5 min_gap: 1 - details: 0.35 \ No newline at end of file + details: 0.35 + border_radius: + # proportion of each style + none: 6 + # no difference if there is no details + medium: 1 + full: 1 \ No newline at end of file diff --git a/utils/Enums.py b/utils/Enums.py index 2927857..3a33d02 100644 --- a/utils/Enums.py +++ b/utils/Enums.py @@ -12,7 +12,12 @@ class COLLUMN_STYLE(Enum): OUTER = 2 BOTH = 3 -class BORDER_RADIUS(Enum): +class WINDOW_BORDER_RADIUS(Enum): NONE = 0 TOP = 1 - TOP_AND_BOTTOM = 2 \ No newline at end of file + TOP_AND_BOTTOM = 2 + +class BALCONY_BORDER_RADIUS(Enum): + NONE = 0 + MEDIUM = 1 + FULL = 2 \ No newline at end of file From de3950d376b2f57189ff465865e482b70b18a6d5 Mon Sep 17 00:00:00 2001 From: AKreuzer Date: Tue, 11 Jun 2024 03:06:06 +0200 Subject: [PATCH 12/17] corrections corners bugs, clean tree structure and start entrance --- buildings/Building.py | 19 ++++--- buildings/Entrance.py | 0 buildings/Facade.py | 52 ++++++++++++++----- buildings/Foundations.py | 33 ++++++++---- buildings/TODO | 4 +- buildings/elements/Balcony.py | 10 ++-- buildings/elements/Collumn.py | 3 ++ .../elements/FacadedetailsElt/Buttons.py | 3 ++ .../elements/FacadedetailsElt/InterFloor.py | 0 .../elements/FacadedetailsElt/Moldings.py | 0 buildings/elements/FacadedetailsElt/Pillar.py | 0 buildings/elements/Window.py | 7 ++- buildings/elements/{ => WindowElt}/Glass.py | 0 buildings/geometry/Point.py | 9 ++-- buildings/geometry/Polygon.py | 13 ++--- buildings/geometry/Rectangle.py | 5 +- buildings/geometry/Tile.py | 7 +-- buildings/geometry/Vertice.py | 3 ++ main.py | 38 +++++--------- params.yml | 22 ++++++-- utils/Enums.py | 11 ++-- 21 files changed, 153 insertions(+), 86 deletions(-) create mode 100644 buildings/Entrance.py create mode 100644 buildings/elements/FacadedetailsElt/Buttons.py create mode 100644 buildings/elements/FacadedetailsElt/InterFloor.py create mode 100644 buildings/elements/FacadedetailsElt/Moldings.py create mode 100644 buildings/elements/FacadedetailsElt/Pillar.py rename buildings/elements/{ => WindowElt}/Glass.py (100%) diff --git a/buildings/Building.py b/buildings/Building.py index 5df0fc1..2b6729b 100644 --- a/buildings/Building.py +++ b/buildings/Building.py @@ -1,30 +1,33 @@ import random as rd -from utils.Enums import COLLUMN_STYLE from buildings.Foundations import Foundations from buildings.Facade import Facade class Building: - def __init__(self, position : tuple[int,int], size : tuple[int, int], matrice : list[list[int]]): + def __init__(self,rdata, position : tuple[int,int], size : tuple[int, int], matrice : list[list[int]], floors : int): self.position = position self.length, self.width = size self.matrice = matrice + self.floors = floors # Generate every random components here - is_collumn_full_tile = bool(rd.getrandbits(1)) - is_inner_or_outer = rd.choice(list(COLLUMN_STYLE)) tile_size = self.gen_tile_size() - floor_height = rd.randint(4, 7) - is_inner_or_outer = COLLUMN_STYLE.BOTH + self.foundations = Foundations(rdata["foundations"], size, matrice, tile_size,) + self.facade = Facade(rdata["facade"], self.foundations.vertices, self.foundations.is_inner_or_outer) - self.foundations = Foundations(size, matrice, tile_size, is_collumn_full_tile, is_inner_or_outer) - self.facade = Facade(self.foundations.vertices, floor_height, is_inner_or_outer) + def build(self, editor, materials : list[str]): + for y in range(self.floors): + with editor.pushTransform((self.position[0], y*(self.foundations.floor_height+1), self.position[1])): + self.foundations.build(editor, materials) + self.facade.build(editor, materials) def gen_tile_size(self) -> int: # Tiles are constant square units different for each buildings + return self.length smaller_side = min(self.length, self.width) # area is too small, will work but not very well + if smaller_side <= 5 : return smaller_side if smaller_side <= 15 : return smaller_side // 5 return rd.randint(3, smaller_side // len(self.matrice)) diff --git a/buildings/Entrance.py b/buildings/Entrance.py new file mode 100644 index 0000000..e69de29 diff --git a/buildings/Facade.py b/buildings/Facade.py index af0143e..eab9e98 100644 --- a/buildings/Facade.py +++ b/buildings/Facade.py @@ -1,36 +1,64 @@ import random as rd -from utils.Enums import COLLUMN_STYLE +from utils.functions import * +from utils.Enums import COLLUMN_STYLE,DIRECTION,INTER_FLOOR_BORDER from gdpc import Editor, Block, geometry, Transform from buildings.geometry.Vertice import Vertice +from buildings.geometry.Point import Point from buildings.elements.Window import Window from buildings.elements.Balcony import Balcony class Facade: - def __init__(self, rdata, vertices : list[Vertice], is_inner_or_outer : COLLUMN_STYLE): + def __init__(self, rdata, vertices : list[Vertice], collumn_style : COLLUMN_STYLE): self.rdata = rdata self.vertices = vertices - self.is_inner_or_outer = is_inner_or_outer + self.collumn_style = collumn_style self.height, self.length = self.get_dimentions() self.padding = 0 self.window = self.get_window() self.has_balcony = self.has_balcony() self.balcony = self.get_balcony() - self.has_inter_floor = self.has_inter_floor() + self.has_inter_floor, self.inter_floor_border_style = self.has_inter_floor() self.editor, self.materials = None,None def build(self, editor : Editor, materials : list[str]): self.editor = editor self.materials = materials + points = sum([[vertice.point1, vertice.point2] for vertice in self.vertices], []) for vertice in self.vertices: + flip=(vertice.facing == DIRECTION.WEST or vertice.facing == DIRECTION.SOUTH, False, False) vertice.fill(editor, materials[0], self.height, xpadding = self.padding, zpadding = self.padding) - with editor.pushTransform(Transform(vertice.point1.position,rotation = vertice.facing.value)): + with editor.pushTransform(Transform(vertice.point1.position,rotation = vertice.facing.value, flip = flip)): self.window.build(editor, materials) - self.build_inter_floor() + if self.has_inter_floor: self.build_inter_floor() if self.has_balcony: self.balcony.build(editor, materials) + self.correct_corners(points,vertice) + + def correct_corners(self,points : list[Point], v : Vertice): + if self.padding == 0: + if self.window.border_radius != 0 and self.window.width == self.length: + if v.point1 in points: + self.editor.placeBlock((0,self.window.ypadding,0), Block(self.materials[8])) + self.editor.placeBlock((0,self.window.ypadding+self.window.height,0), Block(self.materials[8], {"type": "top"})) + if v.point2 in points: + self.editor.placeBlock((self.length-1,self.window.ypadding,0), Block(self.materials[8])) + self.editor.placeBlock((self.length-1,self.window.ypadding+self.window.height,0), Block(self.materials[8], {"type": "top"})) + + if self.has_inter_floor: + material = Block("air") + if self.inter_floor_border_style == INTER_FLOOR_BORDER.SLAB: + material = Block(self.materials[8], {"type": "top"}) + elif self.inter_floor_border_style == INTER_FLOOR_BORDER.STAIRS: + material = Block(self.materials[4], {"facing": "south", "half": "top"}) + + if v.point1 in points: + self.editor.placeBlock((-1,self.height,-1), material) + if v.point2 in points: + self.editor.placeBlock((self.length,self.height,-1), material) + def get_window(self) -> Window: - if self.is_inner_or_outer == COLLUMN_STYLE.OUTER or self.is_inner_or_outer == COLLUMN_STYLE.BOTH: + if self.collumn_style.value >= 2: # collumn_style >= 2 = outer collumns self.padding = 1 max_width = self.length-2*self.padding @@ -41,19 +69,17 @@ class Facade: def get_balcony(self) -> Balcony|None: if not self.has_balcony: return None max_width = self.length-2*self.padding - return Balcony(self.rdata["balcony"], max_width, self.window) + return Balcony(self.rdata["balcony"], max_width, self.window, self.collumn_style) def build_inter_floor(self): - if self.has_inter_floor: - geometry.placeCuboid(self.editor,(0,self.height,0),(self.length-1,self.height,0),Block(self.materials[0])) - geometry.placeCuboid(self.editor,(0,self.height,-1),(self.length-1,self.height,-1),Block(self.materials[4], {"facing": "south", "half": "top"})) + geometry.placeCuboid(self.editor,(self.padding,self.height,0),(self.length-1-self.padding,self.height,0),Block(self.materials[0])) + geometry.placeCuboid(self.editor,(self.padding,self.height,-1),(self.length-1-self.padding,self.height,-1),Block(self.materials[4], {"facing": "south", "half": "top"})) def has_balcony(self) -> bool: - return True return self.rdata["balcony"]["proba"] >= rd.random() def has_inter_floor(self) -> bool: - return self.rdata["inter_floor"] >= rd.random() + return (self.rdata["inter_floor"]["proba"] >= rd.random(), select_random(self.rdata["inter_floor"]["border_style"], INTER_FLOOR_BORDER)) def get_dimentions(self) -> tuple[int]: return ( self.vertices[0].get_height(), len(self.vertices[0])) diff --git a/buildings/Foundations.py b/buildings/Foundations.py index 51a365e..419f051 100644 --- a/buildings/Foundations.py +++ b/buildings/Foundations.py @@ -1,28 +1,28 @@ import random as rd import numpy as np import math + from utils.Enums import COLLUMN_STYLE +from utils.functions import * from buildings.geometry.Tile import Tile from buildings.geometry.Polygon import Polygon from buildings.geometry.Point import Point -from buildings.geometry.Rectangle import Rectangle from buildings.elements.Collumn import Collumn class Foundations: - # TODO : gérer les collones sur les tiles trop petites et les colones 1tile/2 + fulltile + # TODO : gérer les collones sur les tiles trop petites et les colones 1tile/2 def __init__(self, + rdata, size : tuple[int, int], matrice : list[list[int]], - tile_size : int, - is_collumn_full_tile : bool, - is_inner_or_outer : COLLUMN_STYLE): + tile_size : int): # Foundations are the base of the building, they are made of tiles and based on a matrice # Random components self.tile_size = tile_size - self.is_collumn_full_tile = is_collumn_full_tile - self.is_inner_or_outer = is_inner_or_outer + self.is_inner_or_outer = select_random(rdata["collumn_style"], COLLUMN_STYLE) + self.floor_height = rd.randint(rdata["floor"]["min_height"], rdata["floor"]["max_height"])-1 self.size = size self.length, self.width = size @@ -35,6 +35,17 @@ class Foundations: self.z_distribution = [] self.polygon = self.get_polygon() self.collumns = self.get_columns() + + def build(self, editor, materials : list[str]): + self.polygon.fill(editor, materials[5],0) + self.polygon.fill(editor, materials[6], self.floor_height) + self.build_collumns(editor, materials) + + def build_collumns(self, editor, materials : list[str]): + for collumn in self.collumns: + if collumn.is_outer and self.is_inner_or_outer == COLLUMN_STYLE.INNER: continue + if not collumn.is_outer and self.is_inner_or_outer == COLLUMN_STYLE.OUTER: continue + collumn.fill(editor, materials[7], self.floor_height) def add_tile(self, tile : Tile): self.tiles.append(tile) @@ -42,11 +53,10 @@ class Foundations: def get_polygon(self) -> Polygon: ## The polygon is a shape of tiles representing the foundation shape polygon = Polygon(self.size) - avaliable_space = (self.length_in_tiles, self.width_in_tiles) # we save the distribution, usefull for the next steps - self.x_distribution = self.get_distribution(len(self.matrice), avaliable_space[0]) - self.z_distribution = self.get_distribution(len(self.matrice[0]), avaliable_space[1]) + self.x_distribution = self.get_distribution(len(self.matrice), self.length_in_tiles) + self.z_distribution = self.get_distribution(len(self.matrice[0]), self.width_in_tiles) # this bullshit is to create tiles from the matrice and the distribution x_padding = 0 @@ -61,7 +71,7 @@ class Foundations: z_padding += zsize * self.tile_size x_padding += xsize * self.tile_size - polygon.set_vertices_and_neighbors(self.tiles, self.vertices) + polygon.set_vertices_and_neighbors(self.tiles, self.vertices, self.floor_height) polygon.compress(self.tiles, self.vertices) return polygon @@ -106,6 +116,7 @@ class Foundations: return sizes def get_columns(self) -> list[Collumn]: + if self.is_inner_or_outer == COLLUMN_STYLE.NONE: return [] collumns = [] for tile in self.tiles: diff --git a/buildings/TODO b/buildings/TODO index 5c50d3d..2b34928 100644 --- a/buildings/TODO +++ b/buildings/TODO @@ -2,10 +2,12 @@ Encadrement fenêtre toit de balcon avec/sans pilliers border radius balcon collumn style +rembard object détails facade rdc toit tiles 3d -opti géométrique +textures object opti textures +opti géométrique opti gdpc \ No newline at end of file diff --git a/buildings/elements/Balcony.py b/buildings/elements/Balcony.py index cc11be8..f2aeb65 100644 --- a/buildings/elements/Balcony.py +++ b/buildings/elements/Balcony.py @@ -1,16 +1,17 @@ import random as rd from gdpc import Editor, Block, geometry from utils.functions import * -from utils.Enums import BALCONY_BORDER_RADIUS +from utils.Enums import BALCONY_BORDER_RADIUS,COLLUMN_STYLE from buildings.geometry.Point import Point from buildings.geometry.Vertice import Vertice from buildings.elements.Window import Window class Balcony: - def __init__(self, rdata, max_width : int, windows : Window): + def __init__(self, rdata, max_width : int, windows : Window, collumn_style : COLLUMN_STYLE): self.rdata = rdata self.windows = windows self.max_width = max_width + self.collumn_style = collumn_style self.length = self.get_len() self.has_multiple = self.has_multiple() self.has_details = self.has_details() @@ -94,7 +95,8 @@ class Balcony: def get_attach_points(self) -> list[int]: # points where the structures can start/finish - points = [i for i in range(self.max_width)] + padding = 0 if self.collumn_style.value < 2 else 1 # collumn_style < 2 = no outer collumns + points = [i + padding for i in range(self.max_width)] if self.follow_window: pad = self.windows.padding for w in self.windows.windows: @@ -104,7 +106,7 @@ class Balcony: return points def create_structure(self, x1 : int, x2 : int) -> Vertice: - return Vertice(Point(x1,0,0), Point(x2,0,-self.length)) + return Vertice(Point(x = x1), Point(x = x2,z = -self.length)) def append_structure(self, structures : list[Vertice], x1 : int, x2 : int, attach_points : list[int], len_attach_points : int, centered : bool): structures.append(self.create_structure(attach_points[x1], attach_points[x2])) diff --git a/buildings/elements/Collumn.py b/buildings/elements/Collumn.py index 6fd7c1e..40e644d 100644 --- a/buildings/elements/Collumn.py +++ b/buildings/elements/Collumn.py @@ -8,4 +8,7 @@ class Collumn(Rectangle): def set_is_outer(self, is_outer : bool): self.is_outer = is_outer + + def __repr__(self): + return super().__repr__() + f"\nIs outer : {self.is_outer}\n\n" \ No newline at end of file diff --git a/buildings/elements/FacadedetailsElt/Buttons.py b/buildings/elements/FacadedetailsElt/Buttons.py new file mode 100644 index 0000000..3436a95 --- /dev/null +++ b/buildings/elements/FacadedetailsElt/Buttons.py @@ -0,0 +1,3 @@ +class Buttons: + def __init__(self): + pass \ No newline at end of file diff --git a/buildings/elements/FacadedetailsElt/InterFloor.py b/buildings/elements/FacadedetailsElt/InterFloor.py new file mode 100644 index 0000000..e69de29 diff --git a/buildings/elements/FacadedetailsElt/Moldings.py b/buildings/elements/FacadedetailsElt/Moldings.py new file mode 100644 index 0000000..e69de29 diff --git a/buildings/elements/FacadedetailsElt/Pillar.py b/buildings/elements/FacadedetailsElt/Pillar.py new file mode 100644 index 0000000..e69de29 diff --git a/buildings/elements/Window.py b/buildings/elements/Window.py index 4028158..75d355e 100644 --- a/buildings/elements/Window.py +++ b/buildings/elements/Window.py @@ -5,7 +5,7 @@ from utils.Enums import WINDOW_BORDER_RADIUS from utils.functions import * from buildings.geometry.Point import Point from buildings.geometry.Vertice import Vertice -from buildings.elements.Glass import Glass +from buildings.elements.WindowElt.Glass import Glass class Window: def __init__(self, rdata, max_width : int, max_height : int, facade_len : int, facade_height : int): @@ -31,7 +31,7 @@ class Window: if leng > 1: self.build_border_radius(g.x1, g.x2) def build_crossbars(self, x1 : int, x2 : int, len : int): - if self.has_vertical_crossbar and self.height >= self.rdata["crossbars"]["min_height_for_vertical_crossbar"]: + if self.has_vertical_crossbar and self.height+1 >= self.rdata["crossbars"]["min_height_for_vertical_crossbar"]: y = self.height//2 geometry.placeCuboid(self.editor,(x1,y,0),(x2,y,0),Block(self.materials[3])) if self.has_horizontal_crossbar and len >= self.rdata["crossbars"]["min_width_for_horizontal_crossbar"]: @@ -46,7 +46,6 @@ class Window: self.editor.placeBlock((x1,0,0),Block(self.materials[4], {"facing": "west"})) self.editor.placeBlock((x2,0,0),Block(self.materials[4], {"facing": "east"})) - def get_windows(self) -> list[Glass]: windows = [] if not self.has_multiple: windows = [Glass(0,self.width-1,[self.create_window(0, self.width)])] @@ -103,7 +102,7 @@ class Window: def create_window(self, x1 : int, length : int = None) -> Vertice: x2 = x1 if length is None else x1 + length -1 - return Vertice(Point(x1,0,0), Point(x2,self.height,0)) + return Vertice(Point(x = x1), Point(x2,self.height)) def has_multiple_windows(self): if self.width > self.rdata["size"]["max_width"]: return True diff --git a/buildings/elements/Glass.py b/buildings/elements/WindowElt/Glass.py similarity index 100% rename from buildings/elements/Glass.py rename to buildings/elements/WindowElt/Glass.py diff --git a/buildings/geometry/Point.py b/buildings/geometry/Point.py index b8020ec..88c6be7 100644 --- a/buildings/geometry/Point.py +++ b/buildings/geometry/Point.py @@ -1,14 +1,17 @@ class Point: - def __init__(self, x : int = None, y : int = None, z : int = None, p : tuple[int] = None): + def __init__(self, x : int = 0, y : int = 0, z : int = 0, p : tuple[int] = None): if p != None: x,y,z = p self.x = x self.y = y self.z = z self.position = (x,y,z) - def set_position(self, x : int = None, y : int = None, z : int = None, p : tuple[int] = None): + def set_position(self, x : int = 0, y : int = 0, z : int = 0, p : tuple[int] = None): if p != None: x,y,z = p self.x = x if x != None else self.x self.y = y if y != None else self.y self.z = z if z != None else self.z - self.position = (self.x,self.y,self.z) \ No newline at end of file + self.position = (self.x,self.y,self.z) + + def __repr__(self): + return f"Point({self.position})" \ No newline at end of file diff --git a/buildings/geometry/Polygon.py b/buildings/geometry/Polygon.py index 4783523..4afb6b8 100644 --- a/buildings/geometry/Polygon.py +++ b/buildings/geometry/Polygon.py @@ -1,5 +1,5 @@ from utils.Enums import DIRECTION -from gdpc import Editor, Block, geometry +from gdpc import Editor, Block, geometry, Transform from buildings.geometry.Tile import Tile from buildings.geometry.Point import Point from buildings.geometry.Rectangle import Rectangle @@ -11,10 +11,11 @@ class Polygon: self.shape = [] self.vertices = [] - def fill_polygon(self, editor : Editor, material : str, y : int, y2 : int = None): - if y2 == None: y2 = y + def fill(self, editor : Editor, material : str, y : int = 0, y2 : int = None): + if y2 == None: y2 = 0 for rect in self.shape: - rect.fill(editor, material, y, y2) + with editor.pushTransform(Transform((0,y,0))): + rect.fill(editor, material, y2) def fill_vertice(self, editor : Editor, material : str, y : int, y2 : int = None): if y2 == None: y2 = y @@ -66,7 +67,7 @@ class Polygon: if len(remaining_vertices) == 0: self.vertices.append(current) - def set_vertices_and_neighbors(self, tiles : list[Tile], vertices : list[Vertice]): + def set_vertices_and_neighbors(self, tiles : list[Tile], vertices : list[Vertice], height : int): for tile in tiles: targets = tile.get_neighbors_coords() for vertice_num,target in enumerate(targets): @@ -74,7 +75,7 @@ class Polygon: if not has_neighbor: vertice = tile.get_vertice(vertice_num) vertices.append(vertice) - tile.set_vertice(DIRECTION(vertice_num), vertice) + tile.set_vertice(DIRECTION(vertice_num), vertice, height) else : tile.set_neighbor(vertice_num, has_neighbor) diff --git a/buildings/geometry/Rectangle.py b/buildings/geometry/Rectangle.py index 827ba41..47a7a4f 100644 --- a/buildings/geometry/Rectangle.py +++ b/buildings/geometry/Rectangle.py @@ -10,7 +10,7 @@ class Rectangle: return (self.point1.position, self.point2.position) def get_height(self): - return self.point2.y - self.point1.y + 1 + return self.point2.y - self.point1.y def fill(self,editor : Editor, material : str, y : int = None, xpadding : int = 0, zpadding : int = 0): if self.point2.x - self.point1.x < 2*xpadding: xpadding = 0 @@ -18,3 +18,6 @@ class Rectangle: if y is None: y = self.point2.y geometry.placeCuboid(editor, (self.point1.x+xpadding, 0, self.point1.z+zpadding), (self.point2.x-xpadding, y, self.point2.z-zpadding), Block(material)) + + def __repr__(self): + return f"{type(self).__name__}\n1 : {str(self.point1)},\n2 : {str(self.point2)}" \ No newline at end of file diff --git a/buildings/geometry/Tile.py b/buildings/geometry/Tile.py index 45f6370..37c5059 100644 --- a/buildings/geometry/Tile.py +++ b/buildings/geometry/Tile.py @@ -32,9 +32,9 @@ class Tile: def get_neighbors_coords(self): return [Point(x = self.pos.x, z = self.pos.z - self.size), # north - Point(x = self.pos.x - self.size, z = self.pos.z), # west + Point(x = self.pos.x + self.size, z = self.pos.z), # east Point(x = self.pos.x, z = self.pos.z + self.size), # south - Point(x = self.pos.x + self.size, z = self.pos.z)] # east + Point(x = self.pos.x - self.size, z = self.pos.z)] # west def get_neighbor(self, direction) -> Point: @@ -80,8 +80,9 @@ class Tile: case DIRECTION.SOUTH : return self.south_vertice - def set_vertice(self, direction : DIRECTION, vertice : Vertice): + def set_vertice(self, direction : DIRECTION, vertice : Vertice, height : int): self.has_vertice = True + vertice.point2.y = height match(direction): case DIRECTION.WEST : self.west_vertice = vertice diff --git a/buildings/geometry/Vertice.py b/buildings/geometry/Vertice.py index 08e1057..ca26622 100644 --- a/buildings/geometry/Vertice.py +++ b/buildings/geometry/Vertice.py @@ -18,4 +18,7 @@ class Vertice(Rectangle): def __len__(self): return self.point2.x - self.point1.x + self.point2.z - self.point1.z + 1 + + def __repr__(self): + return super().__repr__() + f"\nFacing : {self.facing} \n\n" \ No newline at end of file diff --git a/main.py b/main.py index 116d074..45a620d 100644 --- a/main.py +++ b/main.py @@ -5,11 +5,6 @@ from utils.JsonReader import JsonReader from utils.YamlReader import YamlReader from buildings.Building import Building -from buildings.geometry.Vertice import Vertice -from buildings.geometry.Point import Point -from utils.Enums import DIRECTION,COLLUMN_STYLE,WINDOW_BORDER_RADIUS -from buildings.Facade import Facade - from utils.functions import * editor = Editor(buffering=True) @@ -20,32 +15,23 @@ shapes = f.data y = YamlReader('params.yml') random_data = y.data +# transform = Transform((0,-60,-20),rotation = 0) +# editor.transform.push(transform) +# for i in range(4): +# with editor.pushTransform(Transform(rotation = i)): +# geometry.placeCuboid(editor, (0,0,0), (0,3,5), Block("stone")) -transform = Transform((0,-60,-5),rotation = 0) +transform = Transform((0,-60,80),rotation = 0) editor.transform.push(transform) -geometry.placeCuboid(editor, (0,0,-3), (100,15,1), Block("air")) +geometry.placeCuboid(editor, (-5,0,-8), (170,25,25), Block("air")) -x = 0 -facade = [] -for i in range(3,13): - facade.append(Facade(random_data["buildings"]["facade"],[Vertice(Point(x,0,0), Point(x+i,i,0), DIRECTION.NORTH)],COLLUMN_STYLE.NONE)) - x += i+2 - -for f in facade: - f.build(editor, ["stone_bricks","glass_pane","glass","cobblestone_wall","stone_brick_stairs"]) - - -# F = Foundations((0,0), (20,20), shapes[0]['matrice']) -# F.polygon.fill_polygon(editor, "stone", -60) - -# geometry.placeCuboid(editor, (-10,-60,-10), (85,-55,85), Block("air")) -# B = Building((0,0), (75,75), shapes[7]['matrice']) -# B.foundations.polygon.fill_vertice(editor, "pink_wool", -60) -# for collumn in B.foundations.collumns: -# collumn.fill(editor, "white_concrete", -60, -55) -# B.foundations.polygon.fill_polygon(editor, "white_concrete", -60) +padd = 0 +for i in range(4,13): + building = Building(random_data["buildings"], (padd, 0), (i,i), shapes[0]['matrice'], 3) + building.build(editor, ["stone_bricks","glass_pane","glass","cobblestone_wall","stone_brick_stairs","oak_planks","white_concrete","cobblestone","stone_brick_slab"]) + padd += i + 10 diff --git a/params.yml b/params.yml index cd6b099..6ed391a 100644 --- a/params.yml +++ b/params.yml @@ -4,7 +4,7 @@ buildings: min_tile_size: 3 max_tile_size: 12 - foudations: + foundations: collumn_style : # proportion of each style none: 1 @@ -16,6 +16,7 @@ buildings: max_height: 7 facade: + windows: size: min_height: 2 @@ -39,7 +40,7 @@ buildings: none: 2 top: 1 top_and_bottom: 1 - inter_floor: 0.5 + balcony: proba : 0.25 growth: 0.5 # [growth]% chance to have min_width + 1 balcony length, [growth**2]% chance to have min_width + 2 balcony length, etc @@ -59,4 +60,19 @@ buildings: none: 6 # no difference if there is no details medium: 1 - full: 1 \ No newline at end of file + full: 1 + + Entrance: + centered: 0.8 + different_facade: 0.75 + size: + min_height: 5 + max_height: 9 + + inter_floor: + proba: 0.5 + border_style: + # bloc used to fill the corner of the interfloor + none: 1 + slab: 2 + stairs: 2 \ No newline at end of file diff --git a/utils/Enums.py b/utils/Enums.py index 3a33d02..a40fcbe 100644 --- a/utils/Enums.py +++ b/utils/Enums.py @@ -2,9 +2,9 @@ from enum import Enum class DIRECTION(Enum): NORTH = 0 - WEST = 1 + EAST = 1 SOUTH = 2 - EAST = 3 + WEST = 3 class COLLUMN_STYLE(Enum): NONE = 0 @@ -20,4 +20,9 @@ class WINDOW_BORDER_RADIUS(Enum): class BALCONY_BORDER_RADIUS(Enum): NONE = 0 MEDIUM = 1 - FULL = 2 \ No newline at end of file + FULL = 2 + +class INTER_FLOOR_BORDER(Enum): + NONE = 0 + SLAB = 1 + STAIRS = 2 \ No newline at end of file From 919b8f8aaba21c5aee0b5426f1ba7c1ba1f790b7 Mon Sep 17 00:00:00 2001 From: KAymeric Date: Wed, 12 Jun 2024 22:59:24 +0200 Subject: [PATCH 13/17] start door placement --- buildings/Entrance.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/buildings/Entrance.py b/buildings/Entrance.py index e69de29..37a98c8 100644 --- a/buildings/Entrance.py +++ b/buildings/Entrance.py @@ -0,0 +1,28 @@ +import random as rd +from utils.Enums import DIRECTION +from buildings.geometry.Vertice import Vertice + +class Entrance: + def __init__(self, rdata, vertices : list[Vertice], direction : DIRECTION): + self.vertices = vertices + self.direction = direction + self.rdata = rdata + self.is_centered = self.is_centered() + self.door_vertices = self.get_door_vertices() + + def is_centered(self) -> bool: + return rd.random() <= self.rdata["centered"] + + def get_door_vertices(self) -> Vertice: + oriented_vertices = self.get_oriented_vertices() + + def get_oriented_vertices(self) -> list[Vertice]: + # get the most off-centered vertices that are in the same direction as self.direction + same_direction_vertices = sorted([v for v in self.vertices if v.direction == self.direction], + lambda v: v.point1.z if self.direction.value % 2 == 0 else v.point1.x, # if direction is north or south, sort by x, else sort by z + reverse = self.direction == DIRECTION.NORTH or self.direction == DIRECTION.WEST) # if direction is north or west, sort in reverse + extremum = same_direction_vertices[0] + return [v for v in same_direction_vertices if + (v.poin1.x == extremum.point1.x and self.direction.value % 2 == 0) or + (v.point1.z == extremum.point1.z and self.direction.value % 2 == 1)] + \ No newline at end of file From 22f6362e063599c6eb17d85ba7b5d35a9bc2e9f7 Mon Sep 17 00:00:00 2001 From: AKreuzer Date: Thu, 13 Jun 2024 12:43:33 +0200 Subject: [PATCH 14/17] place entrance (not fied) --- buildings/Building.py | 10 ++++++--- buildings/Entrance.py | 43 +++++++++++++++++++++++++++++++------- buildings/Facade.py | 8 +++---- buildings/TODO | 9 +++++--- buildings/geometry/Tile.py | 6 +++--- main.py | 17 ++++++++------- params.yml | 18 ++++++++-------- 7 files changed, 73 insertions(+), 38 deletions(-) diff --git a/buildings/Building.py b/buildings/Building.py index 2b6729b..ac91246 100644 --- a/buildings/Building.py +++ b/buildings/Building.py @@ -1,6 +1,9 @@ import random as rd +from utils.Enums import DIRECTION +from gdpc import Editor, Block, geometry from buildings.Foundations import Foundations from buildings.Facade import Facade +from buildings.Entrance import Entrance class Building: def __init__(self,rdata, position : tuple[int,int], size : tuple[int, int], matrice : list[list[int]], floors : int): @@ -14,16 +17,17 @@ class Building: self.foundations = Foundations(rdata["foundations"], size, matrice, tile_size,) self.facade = Facade(rdata["facade"], self.foundations.vertices, self.foundations.is_inner_or_outer) + self.entrance = Entrance(rdata, self.foundations.vertices, DIRECTION.EAST, self.foundations.is_inner_or_outer) - def build(self, editor, materials : list[str]): + def build(self, editor : Editor, materials : list[str]): for y in range(self.floors): with editor.pushTransform((self.position[0], y*(self.foundations.floor_height+1), self.position[1])): self.foundations.build(editor, materials) - self.facade.build(editor, materials) + if y == 0: self.entrance.build(editor, materials) + else : self.facade.build(editor, materials) def gen_tile_size(self) -> int: # Tiles are constant square units different for each buildings - return self.length smaller_side = min(self.length, self.width) # area is too small, will work but not very well diff --git a/buildings/Entrance.py b/buildings/Entrance.py index 37a98c8..2ee7ee4 100644 --- a/buildings/Entrance.py +++ b/buildings/Entrance.py @@ -1,28 +1,55 @@ import random as rd -from utils.Enums import DIRECTION +from gdpc import Editor, Block, geometry +from utils.Enums import DIRECTION,COLLUMN_STYLE from buildings.geometry.Vertice import Vertice +from buildings.Facade import Facade class Entrance: - def __init__(self, rdata, vertices : list[Vertice], direction : DIRECTION): + def __init__(self, rdata, vertices : list[Vertice], direction : DIRECTION, collumn_style : COLLUMN_STYLE): self.vertices = vertices self.direction = direction self.rdata = rdata + self.collumn_style = collumn_style self.is_centered = self.is_centered() - self.door_vertices = self.get_door_vertices() + self.door_vertice, self.facade = self.get_door_and_facade() + + def build(self, editor : Editor, materials : list[str]): + self.facade.build(editor, materials) + self.door_vertice.fill(editor, materials[0]) def is_centered(self) -> bool: - return rd.random() <= self.rdata["centered"] + return rd.random() <= self.rdata["entrance"]["centered"] - def get_door_vertices(self) -> Vertice: + def get_door_and_facade(self) -> tuple[Vertice, Facade]: oriented_vertices = self.get_oriented_vertices() + facade_vertices = self.vertices.copy() + door_vertice = None + + if self.is_centered: + oriented_vertices.sort(key = lambda v: v.point1.x if self.direction.value % 2 == 0 else v.point1.z) # if direction is north or south, sort by x, else sort by z + mid = len(oriented_vertices) // 2 + ver1, ver2 = oriented_vertices[mid], oriented_vertices[-mid-1] + if ver1.point1.position == ver2.point1.position: + door_vertice = ver1 + else : + door_vertice = Vertice(ver2.point1, ver1.point2) + facade_vertices.remove(ver2) + facade_vertices.remove(ver1) + + else: + door_vertice = rd.choice(oriented_vertices) + facade_vertices.remove(door_vertice) + + facade = Facade(self.rdata["facade"], facade_vertices, self.collumn_style) + return(door_vertice, facade) def get_oriented_vertices(self) -> list[Vertice]: # get the most off-centered vertices that are in the same direction as self.direction - same_direction_vertices = sorted([v for v in self.vertices if v.direction == self.direction], - lambda v: v.point1.z if self.direction.value % 2 == 0 else v.point1.x, # if direction is north or south, sort by x, else sort by z + same_direction_vertices = sorted([v for v in self.vertices if v.facing == self.direction], + key = lambda v: v.point1.z if self.direction.value % 2 == 0 else v.point1.x, # if direction is north or south, sort by x, else sort by z reverse = self.direction == DIRECTION.NORTH or self.direction == DIRECTION.WEST) # if direction is north or west, sort in reverse extremum = same_direction_vertices[0] return [v for v in same_direction_vertices if - (v.poin1.x == extremum.point1.x and self.direction.value % 2 == 0) or + (v.point1.x == extremum.point1.x and self.direction.value % 2 == 0) or (v.point1.z == extremum.point1.z and self.direction.value % 2 == 1)] \ No newline at end of file diff --git a/buildings/Facade.py b/buildings/Facade.py index eab9e98..27d195e 100644 --- a/buildings/Facade.py +++ b/buildings/Facade.py @@ -37,10 +37,10 @@ class Facade: def correct_corners(self,points : list[Point], v : Vertice): if self.padding == 0: if self.window.border_radius != 0 and self.window.width == self.length: - if v.point1 in points: + if points.count(v.point1) >= 2: self.editor.placeBlock((0,self.window.ypadding,0), Block(self.materials[8])) self.editor.placeBlock((0,self.window.ypadding+self.window.height,0), Block(self.materials[8], {"type": "top"})) - if v.point2 in points: + if points.count(v.point2) >= 2: self.editor.placeBlock((self.length-1,self.window.ypadding,0), Block(self.materials[8])) self.editor.placeBlock((self.length-1,self.window.ypadding+self.window.height,0), Block(self.materials[8], {"type": "top"})) @@ -51,9 +51,9 @@ class Facade: elif self.inter_floor_border_style == INTER_FLOOR_BORDER.STAIRS: material = Block(self.materials[4], {"facing": "south", "half": "top"}) - if v.point1 in points: + if points.count(v.point1) >= 2: self.editor.placeBlock((-1,self.height,-1), material) - if v.point2 in points: + if points.count(v.point2) >= 2: self.editor.placeBlock((self.length,self.height,-1), material) diff --git a/buildings/TODO b/buildings/TODO index 2b34928..59fac34 100644 --- a/buildings/TODO +++ b/buildings/TODO @@ -1,13 +1,16 @@ Encadrement fenêtre toit de balcon avec/sans pilliers -border radius balcon collumn style rembard object détails facade rdc -toit +toit (clim, chateau deau, pubs) tiles 3d textures object opti textures opti géométrique -opti gdpc \ No newline at end of file +opti gdpc +pilliers quand trop de fenêtres + pas de pilliers si tile trop petite +limitateur taille +facade lisses/ immeubles collés +matrices pré-distribués \ No newline at end of file diff --git a/buildings/geometry/Tile.py b/buildings/geometry/Tile.py index 37c5059..24d5f64 100644 --- a/buildings/geometry/Tile.py +++ b/buildings/geometry/Tile.py @@ -61,16 +61,16 @@ class Tile: def get_vertice(self,vertice : int|DIRECTION) -> Vertice: # gives the corresponding vertice : - # 0 = north, 1 = west, 2 = south, 3 = east + # 0 = north, 1 = east, 2 = south, 3 = west match(vertice): case 0 : return Vertice(self.north_west, self.north_east, DIRECTION.NORTH) case 1 : - return Vertice(self.north_west, self.south_west, DIRECTION.WEST) + return Vertice(self.north_east, self.south_east, DIRECTION.EAST) case 2 : return Vertice(self.south_west, self.south_east, DIRECTION.SOUTH) case 3 : - return Vertice(self.north_east, self.south_east, DIRECTION.EAST) + return Vertice(self.north_west, self.south_west, DIRECTION.WEST) case DIRECTION.WEST : return self.west_vertice case DIRECTION.EAST : diff --git a/main.py b/main.py index 45a620d..666b717 100644 --- a/main.py +++ b/main.py @@ -21,25 +21,26 @@ random_data = y.data # with editor.pushTransform(Transform(rotation = i)): # geometry.placeCuboid(editor, (0,0,0), (0,3,5), Block("stone")) -transform = Transform((0,-60,80),rotation = 0) +transform = Transform((0,-60,110),rotation = 0) editor.transform.push(transform) -geometry.placeCuboid(editor, (-5,0,-8), (170,25,25), Block("air")) +geometry.placeCuboid(editor, (-5,0,-8), (60,10,70), Block("air")) +buildings = [] +buildings.append(Building(random_data["buildings"], (0, 0), (20,20), shapes[0]['matrice'], 1)) +buildings.append(Building(random_data["buildings"], (25, 0), (30,30), shapes[5]['matrice'], 1)) +buildings.append(Building(random_data["buildings"], (0, 35), (30,30), shapes[6]['matrice'], 1)) +buildings.append(Building(random_data["buildings"], (35, 35), (20,20), shapes[7]['matrice'], 1)) -padd = 0 -for i in range(4,13): - building = Building(random_data["buildings"], (padd, 0), (i,i), shapes[0]['matrice'], 3) +for building in buildings : building.build(editor, ["stone_bricks","glass_pane","glass","cobblestone_wall","stone_brick_stairs","oak_planks","white_concrete","cobblestone","stone_brick_slab"]) - padd += i + 10 - # # Get a block # block = editor.getBlock((0,48,0)) # # Place a block -#editor.placeBlock((0 , 5, 0), Block("stone")) +# editor.placeBlock((0 , 5, 0), Block("stone")) # # Build a cube # geometry.placeCuboid(editor, (458, 92, 488), (468, 99, 471), Block("oak_planks")) diff --git a/params.yml b/params.yml index 6ed391a..35ac334 100644 --- a/params.yml +++ b/params.yml @@ -8,7 +8,7 @@ buildings: collumn_style : # proportion of each style none: 1 - inner: 1 + inner: 5 outer: 1 both: 1 floor: @@ -62,17 +62,17 @@ buildings: medium: 1 full: 1 - Entrance: - centered: 0.8 - different_facade: 0.75 - size: - min_height: 5 - max_height: 9 - inter_floor: proba: 0.5 border_style: # bloc used to fill the corner of the interfloor none: 1 slab: 2 - stairs: 2 \ No newline at end of file + stairs: 2 + + entrance: + centered: 0.8 + different_facade: 0.75 + size: + min_height: 5 + max_height: 9 \ No newline at end of file From e3dc4ba79abf58d49f9cdaf802879df825f6b58b Mon Sep 17 00:00:00 2001 From: KAymeric Date: Thu, 13 Jun 2024 22:47:50 +0200 Subject: [PATCH 15/17] list index out of range lmao --- buildings/Entrance.py | 36 ++++++++++++++++++++++++++---------- buildings/TODO | 3 ++- params.yml | 4 +++- 3 files changed, 31 insertions(+), 12 deletions(-) diff --git a/buildings/Entrance.py b/buildings/Entrance.py index 2ee7ee4..be9a6d2 100644 --- a/buildings/Entrance.py +++ b/buildings/Entrance.py @@ -29,12 +29,17 @@ class Entrance: oriented_vertices.sort(key = lambda v: v.point1.x if self.direction.value % 2 == 0 else v.point1.z) # if direction is north or south, sort by x, else sort by z mid = len(oriented_vertices) // 2 ver1, ver2 = oriented_vertices[mid], oriented_vertices[-mid-1] - if ver1.point1.position == ver2.point1.position: + + if ver1.point1.x != ver2.point1.x and ver1.point1.z != ver2.point1.z: + door_vertice = rd.choice(ver1, ver2) + facade_vertices.remove(door_vertice) + elif ver1.point1.position == ver2.point1.position: door_vertice = ver1 + facade_vertices.remove(door_vertice) else : door_vertice = Vertice(ver2.point1, ver1.point2) + facade_vertices.remove(ver1) facade_vertices.remove(ver2) - facade_vertices.remove(ver1) else: door_vertice = rd.choice(oriented_vertices) @@ -44,12 +49,23 @@ class Entrance: return(door_vertice, facade) def get_oriented_vertices(self) -> list[Vertice]: - # get the most off-centered vertices that are in the same direction as self.direction - same_direction_vertices = sorted([v for v in self.vertices if v.facing == self.direction], - key = lambda v: v.point1.z if self.direction.value % 2 == 0 else v.point1.x, # if direction is north or south, sort by x, else sort by z - reverse = self.direction == DIRECTION.NORTH or self.direction == DIRECTION.WEST) # if direction is north or west, sort in reverse - extremum = same_direction_vertices[0] - return [v for v in same_direction_vertices if - (v.point1.x == extremum.point1.x and self.direction.value % 2 == 0) or - (v.point1.z == extremum.point1.z and self.direction.value % 2 == 1)] + # Get all the vertice that can contain the door + + # if direction is north or south, compare by x, else compare by z + compare = lambda v: (v.point1.x,v.point1.z) if self.direction.value % 2 == 0 else (v.point1.z,v.point1.x) + # if direction is north or west, the most off_centered is the maximum, else it is the minimum + off_centered = lambda p1,p2: max(p1,p2) if self.direction == DIRECTION.NORTH or self.direction == DIRECTION.WEST else min(p1,p2) + + oriented_vertices = [] + for v in self.vertices: + if v.facing != self.direction: continue + oriented_vertices.append(v) + sortby,position = compare(v) + for ov in oriented_vertices: + ov_sorted, ov_position = compare(ov) + if position == ov_position: + if off_centered(sortby,ov_sorted) == sortby: oriented_vertices.remove(ov) + else: oriented_vertices.remove(v) + + return oriented_vertices \ No newline at end of file diff --git a/buildings/TODO b/buildings/TODO index 59fac34..00ca18d 100644 --- a/buildings/TODO +++ b/buildings/TODO @@ -13,4 +13,5 @@ opti gdpc pilliers quand trop de fenêtres + pas de pilliers si tile trop petite limitateur taille facade lisses/ immeubles collés -matrices pré-distribués \ No newline at end of file +matrices pré-distribués +angles 270 \ No newline at end of file diff --git a/params.yml b/params.yml index 35ac334..eba5527 100644 --- a/params.yml +++ b/params.yml @@ -75,4 +75,6 @@ buildings: different_facade: 0.75 size: min_height: 5 - max_height: 9 \ No newline at end of file + max_height: 9 + door: + \ No newline at end of file From d95ae00fde50578244cf366b0b7e314bfd32b9bb Mon Sep 17 00:00:00 2001 From: AKreuzer Date: Fri, 14 Jun 2024 03:22:16 +0200 Subject: [PATCH 16/17] no style but entrance and roof added --- buildings/Building.py | 9 +++- buildings/Entrance.py | 75 +++++++++++++++++++++++------ buildings/Facade.py | 9 ++-- buildings/Foundations.py | 2 +- buildings/Roof.py | 15 ++++++ buildings/TODO | 4 +- buildings/elements/Balcony.py | 6 ++- buildings/elements/FacadeDetails.py | 2 +- buildings/elements/Window.py | 9 +++- buildings/geometry/Point.py | 9 ++-- buildings/geometry/Polygon.py | 11 +++-- buildings/geometry/Tile.py | 10 ++-- main.py | 2 +- params.yml | 11 +++++ 14 files changed, 133 insertions(+), 41 deletions(-) create mode 100644 buildings/Roof.py diff --git a/buildings/Building.py b/buildings/Building.py index ac91246..32ea625 100644 --- a/buildings/Building.py +++ b/buildings/Building.py @@ -4,6 +4,7 @@ from gdpc import Editor, Block, geometry from buildings.Foundations import Foundations from buildings.Facade import Facade from buildings.Entrance import Entrance +from buildings.Roof import Roof class Building: def __init__(self,rdata, position : tuple[int,int], size : tuple[int, int], matrice : list[list[int]], floors : int): @@ -18,10 +19,14 @@ class Building: self.foundations = Foundations(rdata["foundations"], size, matrice, tile_size,) self.facade = Facade(rdata["facade"], self.foundations.vertices, self.foundations.is_inner_or_outer) self.entrance = Entrance(rdata, self.foundations.vertices, DIRECTION.EAST, self.foundations.is_inner_or_outer) + self.roof = Roof(rdata["roof"], self.foundations.polygon) def build(self, editor : Editor, materials : list[str]): - for y in range(self.floors): - with editor.pushTransform((self.position[0], y*(self.foundations.floor_height+1), self.position[1])): + for y in range(self.floors+1): + with editor.pushTransform((self.position[0], y*(self.foundations.floor_height+1) -1, self.position[1])): + if y == self.floors: + self.roof.build(editor, materials) + break self.foundations.build(editor, materials) if y == 0: self.entrance.build(editor, materials) else : self.facade.build(editor, materials) diff --git a/buildings/Entrance.py b/buildings/Entrance.py index be9a6d2..c82d38b 100644 --- a/buildings/Entrance.py +++ b/buildings/Entrance.py @@ -5,24 +5,55 @@ from buildings.geometry.Vertice import Vertice from buildings.Facade import Facade class Entrance: - def __init__(self, rdata, vertices : list[Vertice], direction : DIRECTION, collumn_style : COLLUMN_STYLE): - self.vertices = vertices + def __init__(self, + rdata, + vertices : list[Vertice], + direction : DIRECTION, + collumn_style : COLLUMN_STYLE): + self.vertices = self.correct_vertices(vertices) self.direction = direction self.rdata = rdata self.collumn_style = collumn_style self.is_centered = self.is_centered() self.door_vertice, self.facade = self.get_door_and_facade() + self.door_width, self.door_height, self.padding, self.ypadding = self.get_door_dimention() + self.editor, self.materials = None,None def build(self, editor : Editor, materials : list[str]): - self.facade.build(editor, materials) - self.door_vertice.fill(editor, materials[0]) + self.editor = editor + self.materials = materials + self.correct_facade() + with self.editor.pushTransform((0,1,0)): + self.facade.build(self.editor, self.materials) + self.build_door() + + def build_door(self): + # self.padding is the padding from the door to the facade, padding is the padding from the door+self.padding to the end of the vertice + padding = (len(self.door_vertice) - (self.padding*2 + self.door_width // 2)) // 2 + self.door_vertice.fill(self.editor, self.materials[0], + y = self.door_height+self.ypadding, + xpadding = padding, + zpadding = padding) + # padding is now the padding from the door to the end of the vertice + padding += self.padding + self.door_vertice.fill(self.editor, "air", + y = self.door_height, + xpadding = padding, + zpadding = padding) + + def correct_facade(self): + self.facade.has_balcony = False + + def correct_vertices(self, vertices : list[Vertice]) -> list[Vertice]: + for v in vertices: + v.point2.set_position(y=v.point2.y-1) + return vertices def is_centered(self) -> bool: return rd.random() <= self.rdata["entrance"]["centered"] def get_door_and_facade(self) -> tuple[Vertice, Facade]: oriented_vertices = self.get_oriented_vertices() - facade_vertices = self.vertices.copy() door_vertice = None if self.is_centered: @@ -31,41 +62,53 @@ class Entrance: ver1, ver2 = oriented_vertices[mid], oriented_vertices[-mid-1] if ver1.point1.x != ver2.point1.x and ver1.point1.z != ver2.point1.z: - door_vertice = rd.choice(ver1, ver2) - facade_vertices.remove(door_vertice) + door_vertice = rd.choice([ver1, ver2]) elif ver1.point1.position == ver2.point1.position: door_vertice = ver1 - facade_vertices.remove(door_vertice) else : - door_vertice = Vertice(ver2.point1, ver1.point2) - facade_vertices.remove(ver1) - facade_vertices.remove(ver2) + door_vertice = Vertice(ver2.point1.copy(), ver1.point2.copy()) else: door_vertice = rd.choice(oriented_vertices) - facade_vertices.remove(door_vertice) - facade = Facade(self.rdata["facade"], facade_vertices, self.collumn_style) + facade = Facade(self.rdata["facade"], self.vertices, self.collumn_style) return(door_vertice, facade) def get_oriented_vertices(self) -> list[Vertice]: # Get all the vertice that can contain the door # if direction is north or south, compare by x, else compare by z - compare = lambda v: (v.point1.x,v.point1.z) if self.direction.value % 2 == 0 else (v.point1.z,v.point1.x) + compare = lambda v: (v.point1.z,v.point1.x) if self.direction.value % 2 == 0 else (v.point1.x,v.point1.z) # if direction is north or west, the most off_centered is the maximum, else it is the minimum off_centered = lambda p1,p2: max(p1,p2) if self.direction == DIRECTION.NORTH or self.direction == DIRECTION.WEST else min(p1,p2) oriented_vertices = [] for v in self.vertices: if v.facing != self.direction: continue - oriented_vertices.append(v) sortby,position = compare(v) + alreadyset = False for ov in oriented_vertices: ov_sorted, ov_position = compare(ov) if position == ov_position: if off_centered(sortby,ov_sorted) == sortby: oriented_vertices.remove(ov) - else: oriented_vertices.remove(v) + else: alreadyset = True + if not alreadyset: oriented_vertices.append(v) return oriented_vertices + + def get_door_dimention(self) -> tuple[int,int,int,int]: # return width, height, padding, ypadding + max_width = len(self.door_vertice) - 2 + max_height = self.door_vertice.get_height() - 1 + + door_width = rd.randint(self.rdata["entrance"]["door"]["size"]["min_width"], self.rdata["entrance"]["door"]["size"]["max_width"]) + door_height = rd.randint(self.rdata["entrance"]["door"]["size"]["min_height"], self.rdata["entrance"]["door"]["size"]["max_height"]) + xpadding = rd.randint(1, self.rdata["entrance"]["door"]["padding"]["max"]) + ypadding = rd.randint(1, self.rdata["entrance"]["door"]["padding"]["max_top"]) + + if door_width > max_width: door_width = max_width + if door_height > max_height: door_height = max_height + if xpadding*2 + door_width > max_width: xpadding += (max_width - (xpadding*2 + door_width)-1)//2 + if ypadding + door_height > max_height: ypadding += max_height - (ypadding + door_height) + + return door_width,door_height,xpadding,ypadding \ No newline at end of file diff --git a/buildings/Facade.py b/buildings/Facade.py index 27d195e..f1da338 100644 --- a/buildings/Facade.py +++ b/buildings/Facade.py @@ -8,7 +8,10 @@ from buildings.elements.Window import Window from buildings.elements.Balcony import Balcony class Facade: - def __init__(self, rdata, vertices : list[Vertice], collumn_style : COLLUMN_STYLE): + def __init__(self, + rdata, + vertices : list[Vertice], + collumn_style : COLLUMN_STYLE): self.rdata = rdata self.vertices = vertices self.collumn_style = collumn_style @@ -60,7 +63,7 @@ class Facade: def get_window(self) -> Window: if self.collumn_style.value >= 2: # collumn_style >= 2 = outer collumns self.padding = 1 - + max_width = self.length-2*self.padding max_height = min(self.height, self.rdata["windows"]["size"]["max_height"]) @@ -81,6 +84,6 @@ class Facade: def has_inter_floor(self) -> bool: return (self.rdata["inter_floor"]["proba"] >= rd.random(), select_random(self.rdata["inter_floor"]["border_style"], INTER_FLOOR_BORDER)) - def get_dimentions(self) -> tuple[int]: + def get_dimentions(self) -> tuple[int,int]: return ( self.vertices[0].get_height(), len(self.vertices[0])) \ No newline at end of file diff --git a/buildings/Foundations.py b/buildings/Foundations.py index 419f051..e6003a8 100644 --- a/buildings/Foundations.py +++ b/buildings/Foundations.py @@ -45,7 +45,7 @@ class Foundations: for collumn in self.collumns: if collumn.is_outer and self.is_inner_or_outer == COLLUMN_STYLE.INNER: continue if not collumn.is_outer and self.is_inner_or_outer == COLLUMN_STYLE.OUTER: continue - collumn.fill(editor, materials[7], self.floor_height) + collumn.fill(editor, materials[7], self.floor_height+1) def add_tile(self, tile : Tile): self.tiles.append(tile) diff --git a/buildings/Roof.py b/buildings/Roof.py new file mode 100644 index 0000000..7036a87 --- /dev/null +++ b/buildings/Roof.py @@ -0,0 +1,15 @@ +import random as rd +from buildings.geometry.Polygon import Polygon + +class Roof: + def __init__(self,rdata, polygon : Polygon): + self.rdata = rdata + self.polygon = polygon + self.has_rembard = self.has_rembard() + + def build(self, editor, materials : list[str]): + self.polygon.fill(editor, materials[0]) + if self.has_rembard: self.polygon.fill_vertice(editor, materials[9],1) + + def has_rembard(self): + return rd.random() <= self.rdata["rembard"] diff --git a/buildings/TODO b/buildings/TODO index 00ca18d..838d7e4 100644 --- a/buildings/TODO +++ b/buildings/TODO @@ -14,4 +14,6 @@ pilliers quand trop de fenêtres + pas de pilliers si tile trop petite limitateur taille facade lisses/ immeubles collés matrices pré-distribués -angles 270 \ No newline at end of file +angles 270 +bug entrée au milieu du O +bug entrée dans le pillier \ No newline at end of file diff --git a/buildings/elements/Balcony.py b/buildings/elements/Balcony.py index f2aeb65..42defca 100644 --- a/buildings/elements/Balcony.py +++ b/buildings/elements/Balcony.py @@ -7,7 +7,11 @@ from buildings.geometry.Vertice import Vertice from buildings.elements.Window import Window class Balcony: - def __init__(self, rdata, max_width : int, windows : Window, collumn_style : COLLUMN_STYLE): + def __init__(self, + rdata, + max_width : int, + windows : Window, + collumn_style : COLLUMN_STYLE): self.rdata = rdata self.windows = windows self.max_width = max_width diff --git a/buildings/elements/FacadeDetails.py b/buildings/elements/FacadeDetails.py index 9770cdc..069963e 100644 --- a/buildings/elements/FacadeDetails.py +++ b/buildings/elements/FacadeDetails.py @@ -5,7 +5,7 @@ class FacadeDetails: self.zones = zones self.sizes = self.get_sizes() - def get_sizes(self) -> list[tuple[int]]: + def get_sizes(self) -> list[tuple[int,int,int]]: # foreach different zone sizes in self.zones, we will gen different details sizes = [] center_for_symetry = len(self.zones) // 2 diff --git a/buildings/elements/Window.py b/buildings/elements/Window.py index 75d355e..5a2739e 100644 --- a/buildings/elements/Window.py +++ b/buildings/elements/Window.py @@ -8,7 +8,12 @@ from buildings.geometry.Vertice import Vertice from buildings.elements.WindowElt.Glass import Glass class Window: - def __init__(self, rdata, max_width : int, max_height : int, facade_len : int, facade_height : int): + def __init__(self, + rdata, + max_width : int, + max_height : int, + facade_len : int, + facade_height : int): self.rdata = rdata self.width, self.height = self.get_size(max_width, max_height) self.is_grounded = self.is_grounded() @@ -121,7 +126,7 @@ class Window: rd.randint(self.rdata["size"]["min_height"],max_height) ) - def get_padding(self, facade_len : int, facade_height : int) -> tuple[int]: + def get_padding(self, facade_len : int, facade_height : int) -> tuple[int,int]: padding,ypadding = 0,0 if not self.is_grounded: ypadding = (facade_height - self.height)//2 diff --git a/buildings/geometry/Point.py b/buildings/geometry/Point.py index 88c6be7..7300d8b 100644 --- a/buildings/geometry/Point.py +++ b/buildings/geometry/Point.py @@ -1,12 +1,12 @@ class Point: - def __init__(self, x : int = 0, y : int = 0, z : int = 0, p : tuple[int] = None): + def __init__(self, x : int = 0, y : int = 0, z : int = 0, p : tuple[int,int,int] = None): if p != None: x,y,z = p self.x = x self.y = y self.z = z self.position = (x,y,z) - def set_position(self, x : int = 0, y : int = 0, z : int = 0, p : tuple[int] = None): + def set_position(self, x : int = None, y : int = None, z : int = None, p : tuple[int,int,int] = None): if p != None: x,y,z = p self.x = x if x != None else self.x self.y = y if y != None else self.y @@ -14,4 +14,7 @@ class Point: self.position = (self.x,self.y,self.z) def __repr__(self): - return f"Point({self.position})" \ No newline at end of file + return f"Point({self.position})" + + def copy(self) -> 'Point': + return Point(self.x, self.y, self.z) \ No newline at end of file diff --git a/buildings/geometry/Polygon.py b/buildings/geometry/Polygon.py index 4afb6b8..92dfbc3 100644 --- a/buildings/geometry/Polygon.py +++ b/buildings/geometry/Polygon.py @@ -18,9 +18,10 @@ class Polygon: rect.fill(editor, material, y2) def fill_vertice(self, editor : Editor, material : str, y : int, y2 : int = None): - if y2 == None: y2 = y + if y2 == None: y2 = 0 for vertice in self.vertices: - vertice.fill(editor, Block(material), y, y2) + with editor.pushTransform(Transform((0,y,0))): + vertice.fill(editor, material, y2) def compress(self, tiles : list[Tile], vertices : list[Vertice]): remaining_tiles = tiles.copy() @@ -58,9 +59,9 @@ class Polygon: has_next2 = self._has_next(neighbors[1], current.facing, remaining_vertices) if has_next1: - current = Vertice(has_next1.point1, current.point2, current.facing) + current = Vertice(has_next1.point1.copy(), current.point2.copy(), current.facing) elif has_next2: - current = Vertice(current.point1, has_next2.point2, current.facing) + current = Vertice(current.point1.copy(), has_next2.point2.copy(), current.facing) else: self.vertices.append(current) current = remaining_vertices.pop() @@ -89,7 +90,7 @@ class Polygon: for tile in new_line: remaining_tiles.remove(tile) line = new_line - def _has_neighbor(self, target : tuple[int], tiles : list[Tile]) -> bool|Tile: + def _has_neighbor(self, target : Point, tiles : list[Tile]) -> bool|Tile: for tile in tiles: if tile.pos.position == target.position: return tile diff --git a/buildings/geometry/Tile.py b/buildings/geometry/Tile.py index 24d5f64..e1b6174 100644 --- a/buildings/geometry/Tile.py +++ b/buildings/geometry/Tile.py @@ -64,13 +64,13 @@ class Tile: # 0 = north, 1 = east, 2 = south, 3 = west match(vertice): case 0 : - return Vertice(self.north_west, self.north_east, DIRECTION.NORTH) + return Vertice(self.north_west.copy(), self.north_east.copy(), DIRECTION.NORTH) case 1 : - return Vertice(self.north_east, self.south_east, DIRECTION.EAST) + return Vertice(self.north_east.copy(), self.south_east.copy(), DIRECTION.EAST) case 2 : - return Vertice(self.south_west, self.south_east, DIRECTION.SOUTH) + return Vertice(self.south_west.copy(), self.south_east.copy(), DIRECTION.SOUTH) case 3 : - return Vertice(self.north_west, self.south_west, DIRECTION.WEST) + return Vertice(self.north_west.copy(), self.south_west.copy(), DIRECTION.WEST) case DIRECTION.WEST : return self.west_vertice case DIRECTION.EAST : @@ -82,7 +82,7 @@ class Tile: def set_vertice(self, direction : DIRECTION, vertice : Vertice, height : int): self.has_vertice = True - vertice.point2.y = height + vertice.point2.set_position(y = height) match(direction): case DIRECTION.WEST : self.west_vertice = vertice diff --git a/main.py b/main.py index 666b717..750e688 100644 --- a/main.py +++ b/main.py @@ -33,7 +33,7 @@ buildings.append(Building(random_data["buildings"], (0, 35), (30,30), shapes[6][ buildings.append(Building(random_data["buildings"], (35, 35), (20,20), shapes[7]['matrice'], 1)) for building in buildings : - building.build(editor, ["stone_bricks","glass_pane","glass","cobblestone_wall","stone_brick_stairs","oak_planks","white_concrete","cobblestone","stone_brick_slab"]) + building.build(editor, ["stone_bricks","glass_pane","glass","cobblestone_wall","stone_brick_stairs","oak_planks","white_concrete","cobblestone","stone_brick_slab","iron_bars"]) # # Get a block diff --git a/params.yml b/params.yml index eba5527..5ce03f5 100644 --- a/params.yml +++ b/params.yml @@ -77,4 +77,15 @@ buildings: min_height: 5 max_height: 9 door: + size: + min_height: 2 + max_height: 4 + min_width: 1 + max_width: 3 + padding: + max: 2 + max_top: 2 + + roof: + rembard: 0.5 \ No newline at end of file From fdc93e0cb6b525918d46c0107207cf64e888e586 Mon Sep 17 00:00:00 2001 From: AKreuzer Date: Fri, 14 Jun 2024 03:28:48 +0200 Subject: [PATCH 17/17] some comments --- buildings/TODO | 3 ++- main.py | 26 ++++++++++++-------------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/buildings/TODO b/buildings/TODO index 838d7e4..43f622d 100644 --- a/buildings/TODO +++ b/buildings/TODO @@ -16,4 +16,5 @@ facade lisses/ immeubles collés matrices pré-distribués angles 270 bug entrée au milieu du O -bug entrée dans le pillier \ No newline at end of file +bug entrée dans le pillier +center le building dans son area (ou pas) \ No newline at end of file diff --git a/main.py b/main.py index 750e688..059a03a 100644 --- a/main.py +++ b/main.py @@ -9,31 +9,29 @@ from utils.functions import * editor = Editor(buffering=True) +# get every differents buildings shapes f = JsonReader('buildings\shapes.json') shapes = f.data +# get the random data for the buildings y = YamlReader('params.yml') random_data = y.data -# transform = Transform((0,-60,-20),rotation = 0) -# editor.transform.push(transform) -# for i in range(4): -# with editor.pushTransform(Transform(rotation = i)): -# geometry.placeCuboid(editor, (0,0,0), (0,3,5), Block("stone")) - +#move your editor to the position you wanna build on transform = Transform((0,-60,110),rotation = 0) editor.transform.push(transform) -geometry.placeCuboid(editor, (-5,0,-8), (60,10,70), Block("air")) +# clear the area you build on +geometry.placeCuboid(editor, (-5,0,-8), (25,100,25), Block("air")) + +# create a building at the relative position 0,0 with 20 blocks length and 20 blocks width, with a normal shape and 10 floors +building = Building(random_data["buildings"], (0, 0), (20,20), shapes[0]['matrice'], 10) +# build it with your custom materials +building.build(editor, ["stone_bricks","glass_pane","glass","cobblestone_wall","stone_brick_stairs","oak_planks","white_concrete","cobblestone","stone_brick_slab","iron_bars"]) + + -buildings = [] -buildings.append(Building(random_data["buildings"], (0, 0), (20,20), shapes[0]['matrice'], 1)) -buildings.append(Building(random_data["buildings"], (25, 0), (30,30), shapes[5]['matrice'], 1)) -buildings.append(Building(random_data["buildings"], (0, 35), (30,30), shapes[6]['matrice'], 1)) -buildings.append(Building(random_data["buildings"], (35, 35), (20,20), shapes[7]['matrice'], 1)) -for building in buildings : - building.build(editor, ["stone_bricks","glass_pane","glass","cobblestone_wall","stone_brick_stairs","oak_planks","white_concrete","cobblestone","stone_brick_slab","iron_bars"]) # # Get a block