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