Merge branch 'Xeon0X:main' into main
This commit is contained in:
12
Enums.py
12
Enums.py
@@ -1,12 +0,0 @@
|
||||
from enum import Enum
|
||||
|
||||
class DIRECTION(Enum):
|
||||
WEST = 0
|
||||
EAST = 1
|
||||
NORTH = 2
|
||||
SOUTH = 3
|
||||
|
||||
class COLLUMN_STYLE(Enum):
|
||||
INNER = 1
|
||||
OUTER = 2
|
||||
BOTH = 3
|
||||
@@ -1,30 +1,42 @@
|
||||
import random as rd
|
||||
from Enums import COLLUMN_STYLE
|
||||
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
|
||||
from buildings.Roof import Roof
|
||||
|
||||
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.entrance = Entrance(rdata, self.foundations.vertices, DIRECTION.EAST, self.foundations.is_inner_or_outer)
|
||||
self.roof = Roof(rdata["roof"], self.foundations.polygon)
|
||||
|
||||
self.foundations = Foundations(position, 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 : Editor, materials : list[str]):
|
||||
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)
|
||||
|
||||
def gen_tile_size(self) -> int:
|
||||
# Tiles are constant square units different for each buildings
|
||||
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))
|
||||
|
||||
114
buildings/Entrance.py
Normal file
114
buildings/Entrance.py
Normal file
@@ -0,0 +1,114 @@
|
||||
import random as rd
|
||||
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,
|
||||
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.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()
|
||||
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.x != ver2.point1.x and ver1.point1.z != ver2.point1.z:
|
||||
door_vertice = rd.choice([ver1, ver2])
|
||||
elif ver1.point1.position == ver2.point1.position:
|
||||
door_vertice = ver1
|
||||
else :
|
||||
door_vertice = Vertice(ver2.point1.copy(), ver1.point2.copy())
|
||||
|
||||
else:
|
||||
door_vertice = rd.choice(oriented_vertices)
|
||||
|
||||
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.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
|
||||
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: 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
|
||||
|
||||
@@ -1,29 +1,89 @@
|
||||
from Enums import COLLUMN_STYLE
|
||||
import random as rd
|
||||
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.Rectangle import Rectangle
|
||||
from buildings.geometry.Point import Point
|
||||
from buildings.elements.Window import Window
|
||||
from buildings.elements.Balcony import Balcony
|
||||
|
||||
class Facade:
|
||||
def __init__(self, vertices : list[Vertice], height : int, 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.height = height
|
||||
self.window_size = self.get_window_size()
|
||||
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.has_inter_floor = self.has_inter_floor()
|
||||
self.balcony = self.get_balcony()
|
||||
self.has_inter_floor, self.inter_floor_border_style = self.has_inter_floor()
|
||||
self.editor, self.materials = None,None
|
||||
|
||||
def build_facade(self):
|
||||
pass
|
||||
|
||||
def get_window_size(self) -> tuple[int,int]:
|
||||
pass
|
||||
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, flip = flip)):
|
||||
self.window.build(editor, materials)
|
||||
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 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 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"}))
|
||||
|
||||
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 points.count(v.point1) >= 2:
|
||||
self.editor.placeBlock((-1,self.height,-1), material)
|
||||
if points.count(v.point2) >= 2:
|
||||
self.editor.placeBlock((self.length,self.height,-1), material)
|
||||
|
||||
|
||||
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"])
|
||||
|
||||
return Window(self.rdata["windows"] ,max_width, max_height, self.length, self.height)
|
||||
|
||||
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, self.collumn_style)
|
||||
|
||||
def build_inter_floor(self):
|
||||
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:
|
||||
pass
|
||||
return self.rdata["balcony"]["proba"] >= rd.random()
|
||||
|
||||
def has_inter_floor(self) -> bool:
|
||||
pass
|
||||
return (self.rdata["inter_floor"]["proba"] >= rd.random(), select_random(self.rdata["inter_floor"]["border_style"], INTER_FLOOR_BORDER))
|
||||
|
||||
def get_window(self) -> Window:
|
||||
pass
|
||||
def get_dimentions(self) -> tuple[int,int]:
|
||||
return ( self.vertices[0].get_height(), len(self.vertices[0]))
|
||||
|
||||
@@ -1,35 +1,31 @@
|
||||
import random as rd
|
||||
import numpy as np
|
||||
import math
|
||||
from Enums import COLLUMN_STYLE
|
||||
|
||||
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,
|
||||
position : tuple[int,int],
|
||||
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
|
||||
|
||||
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 = []
|
||||
@@ -39,23 +35,33 @@ 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+1)
|
||||
|
||||
def add_tile(self, tile : Tile):
|
||||
self.tiles.append(tile)
|
||||
|
||||
def get_polygon(self) -> Polygon:
|
||||
## The polygon is a shape of tiles representing the foundation shape
|
||||
polygon = Polygon(self.position, self.size)
|
||||
avaliable_space = (self.length_in_tiles, self.width_in_tiles)
|
||||
polygon = Polygon(self.size)
|
||||
|
||||
# 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 = self.position.x
|
||||
x_padding = 0
|
||||
for x,xsize in enumerate(self.x_distribution):
|
||||
z_padding = self.position.z
|
||||
z_padding = 0
|
||||
for z,zsize in enumerate(self.z_distribution):
|
||||
if self.matrice[x][z] == 1:
|
||||
for xi in range(xsize):
|
||||
@@ -65,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
|
||||
|
||||
@@ -110,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:
|
||||
@@ -137,8 +144,7 @@ class Foundations:
|
||||
if collumn.point1.position == compare.point1.position :
|
||||
if compare.is_outer : collumn.set_is_outer(True)
|
||||
collumns.remove(compare)
|
||||
|
||||
print(len(collumns))
|
||||
|
||||
return collumns
|
||||
|
||||
|
||||
15
buildings/Roof.py
Normal file
15
buildings/Roof.py
Normal file
@@ -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"]
|
||||
20
buildings/TODO
Normal file
20
buildings/TODO
Normal file
@@ -0,0 +1,20 @@
|
||||
Encadrement fenêtre
|
||||
toit de balcon avec/sans pilliers
|
||||
collumn style
|
||||
rembard object
|
||||
détails facade
|
||||
rdc
|
||||
toit (clim, chateau deau, pubs)
|
||||
tiles 3d
|
||||
textures object
|
||||
opti textures
|
||||
opti géométrique
|
||||
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
|
||||
angles 270
|
||||
bug entrée au milieu du O
|
||||
bug entrée dans le pillier
|
||||
center le building dans son area (ou pas)
|
||||
135
buildings/elements/Balcony.py
Normal file
135
buildings/elements/Balcony.py
Normal file
@@ -0,0 +1,135 @@
|
||||
import random as rd
|
||||
from gdpc import Editor, Block, geometry
|
||||
from utils.functions import *
|
||||
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,
|
||||
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()
|
||||
self.border_radius = self.has_border_radius()
|
||||
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)
|
||||
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]))
|
||||
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 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"]
|
||||
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 x1 > 0:
|
||||
x1 -= 1
|
||||
x2 += 1 if centered else 0
|
||||
leng = attach_points[x2] - attach_points[x1] - 1
|
||||
|
||||
if x1 == 0:
|
||||
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():
|
||||
self.append_structure(structures, x1, x2, attach_points, len_attach_points, centered)
|
||||
|
||||
if not self.has_multiple: break
|
||||
else:
|
||||
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+1
|
||||
|
||||
return structures
|
||||
|
||||
def get_attach_points(self) -> list[int]:
|
||||
# points where the structures can start/finish
|
||||
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:
|
||||
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(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]))
|
||||
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 not self.windows.ypadding > 3
|
||||
|
||||
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 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"])
|
||||
@@ -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"
|
||||
|
||||
19
buildings/elements/FacadeDetails.py
Normal file
19
buildings/elements/FacadeDetails.py
Normal file
@@ -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,int,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
|
||||
|
||||
|
||||
3
buildings/elements/FacadedetailsElt/Buttons.py
Normal file
3
buildings/elements/FacadedetailsElt/Buttons.py
Normal file
@@ -0,0 +1,3 @@
|
||||
class Buttons:
|
||||
def __init__(self):
|
||||
pass
|
||||
0
buildings/elements/FacadedetailsElt/InterFloor.py
Normal file
0
buildings/elements/FacadedetailsElt/InterFloor.py
Normal file
0
buildings/elements/FacadedetailsElt/Moldings.py
Normal file
0
buildings/elements/FacadedetailsElt/Moldings.py
Normal file
0
buildings/elements/FacadedetailsElt/Pillar.py
Normal file
0
buildings/elements/FacadedetailsElt/Pillar.py
Normal file
@@ -1,10 +1,150 @@
|
||||
import random as rd
|
||||
import math
|
||||
from gdpc import Editor, Block, geometry, Transform
|
||||
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.WindowElt.Glass import Glass
|
||||
|
||||
class Window:
|
||||
def __init__(self, size : tuple[int,int]):
|
||||
self.size = size
|
||||
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.is_alternate = self.is_alternate()
|
||||
self.border_radius = self.border_radius()
|
||||
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, materials : list[str]):
|
||||
self.editor = editor
|
||||
self.materials = materials
|
||||
with editor.pushTransform(Transform((self.padding,self.ypadding,0))):
|
||||
for g in self.windows:
|
||||
leng = len(g)
|
||||
g.build(editor, materials[1], materials[2])
|
||||
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+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"]:
|
||||
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 != 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 == 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"}))
|
||||
|
||||
def open(self):
|
||||
pass
|
||||
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
|
||||
|
||||
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 close(self):
|
||||
pass
|
||||
def alternate(self, windows : list[Glass]):
|
||||
for g in windows:
|
||||
g.reset_groups()
|
||||
leng = len(g)
|
||||
mid = g.x1 + leng//2
|
||||
|
||||
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))
|
||||
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(x = x1), Point(x2,self.height))
|
||||
|
||||
def has_multiple_windows(self):
|
||||
if self.width > self.rdata["size"]["max_width"]: return True
|
||||
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
|
||||
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,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"]
|
||||
|
||||
return (data["vertical_crossbar"] >= rd.random(), data["horizontal_crossbar"] >= rd.random())
|
||||
|
||||
def border_radius(self):
|
||||
return select_random(self.rdata["border_radius"], WINDOW_BORDER_RADIUS)
|
||||
22
buildings/elements/WindowElt/Glass.py
Normal file
22
buildings/elements/WindowElt/Glass.py
Normal file
@@ -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 __len__(self):
|
||||
return self.x2 - self.x1 + 1
|
||||
|
||||
@@ -1,14 +1,20 @@
|
||||
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,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 = None, y : int = None, z : int = None, 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
|
||||
self.z = z if z != None else self.z
|
||||
self.position = (self.x,self.y,self.z)
|
||||
self.position = (self.x,self.y,self.z)
|
||||
|
||||
def __repr__(self):
|
||||
return f"Point({self.position})"
|
||||
|
||||
def copy(self) -> 'Point':
|
||||
return Point(self.x, self.y, self.z)
|
||||
@@ -1,26 +1,27 @@
|
||||
from Enums import DIRECTION
|
||||
from gdpc import Editor, Block, geometry
|
||||
from utils.Enums import DIRECTION
|
||||
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
|
||||
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 = []
|
||||
|
||||
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
|
||||
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,16 +59,16 @@ 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()
|
||||
|
||||
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):
|
||||
@@ -75,7 +76,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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -9,6 +9,15 @@ 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):
|
||||
if y2 == None: y2 = y
|
||||
geometry.placeCuboid(editor, (self.point1.x, y, self.point1.z), (self.point2.x, y2, self.point2.z), Block(material))
|
||||
def get_height(self):
|
||||
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
|
||||
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))
|
||||
|
||||
def __repr__(self):
|
||||
return f"{type(self).__name__}\n1 : {str(self.point1)},\n2 : {str(self.point2)}"
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
return [Point(x = self.pos.x, z = self.pos.z - self.size), # north
|
||||
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
|
||||
Point(x = self.pos.x, z = self.pos.z + self.size), # south
|
||||
Point(x = self.pos.x - self.size, z = self.pos.z)] # west
|
||||
|
||||
|
||||
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 = east, 2 = south, 3 = west
|
||||
match(vertice):
|
||||
case 0 :
|
||||
return Vertice(self.north_west, self.south_west, DIRECTION.WEST)
|
||||
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.north_west, self.north_east, DIRECTION.NORTH)
|
||||
return Vertice(self.south_west.copy(), self.south_east.copy(), DIRECTION.SOUTH)
|
||||
case 3 :
|
||||
return Vertice(self.south_west, self.south_east, DIRECTION.SOUTH)
|
||||
return Vertice(self.north_west.copy(), self.south_west.copy(), DIRECTION.WEST)
|
||||
case DIRECTION.WEST :
|
||||
return self.west_vertice
|
||||
case DIRECTION.EAST :
|
||||
@@ -81,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.set_position(y = height)
|
||||
match(direction):
|
||||
case DIRECTION.WEST :
|
||||
self.west_vertice = vertice
|
||||
|
||||
@@ -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 = None):
|
||||
Rectangle.__init__(self, point1, point2)
|
||||
self.facing = facing
|
||||
|
||||
@@ -15,7 +15,10 @@ 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_size(self):
|
||||
return self.point2.x - self.point1.x + self.point2.z - self.point1.z
|
||||
|
||||
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"
|
||||
|
||||
44
main.py
44
main.py
@@ -1,28 +1,44 @@
|
||||
from gdpc import Editor, Block, geometry
|
||||
from gdpc import Editor, Block, geometry, Transform
|
||||
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 utils.functions import *
|
||||
|
||||
editor = Editor(buffering=True)
|
||||
|
||||
f = open('buildings\shapes.json')
|
||||
shapes = json.load(f)
|
||||
|
||||
# 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)
|
||||
# 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
|
||||
|
||||
#move your editor to the position you wanna build on
|
||||
transform = Transform((0,-60,110),rotation = 0)
|
||||
editor.transform.push(transform)
|
||||
|
||||
# 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"])
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# # 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"))
|
||||
|
||||
92
params.yml
92
params.yml
@@ -1 +1,91 @@
|
||||
// contains all random variables
|
||||
# contains all random variables
|
||||
buildings:
|
||||
tile_size:
|
||||
min_tile_size: 3
|
||||
max_tile_size: 12
|
||||
|
||||
foundations:
|
||||
collumn_style :
|
||||
# proportion of each style
|
||||
none: 1
|
||||
inner: 5
|
||||
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
|
||||
# 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
|
||||
border_radius:
|
||||
# proportion of each style
|
||||
none: 2
|
||||
top: 1
|
||||
top_and_bottom: 1
|
||||
|
||||
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
|
||||
size:
|
||||
min_len : 1
|
||||
max_len : 3
|
||||
min_width : 3
|
||||
multiple:
|
||||
# probability to have multiple balcony IF POSSIBLE
|
||||
# this feature need a very large facade
|
||||
proba: 1
|
||||
min_width: 5
|
||||
min_gap: 1
|
||||
details: 0.35
|
||||
border_radius:
|
||||
# proportion of each style
|
||||
none: 6
|
||||
# no difference if there is no details
|
||||
medium: 1
|
||||
full: 1
|
||||
|
||||
inter_floor:
|
||||
proba: 0.5
|
||||
border_style:
|
||||
# bloc used to fill the corner of the interfloor
|
||||
none: 1
|
||||
slab: 2
|
||||
stairs: 2
|
||||
|
||||
entrance:
|
||||
centered: 0.8
|
||||
different_facade: 0.75
|
||||
size:
|
||||
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
|
||||
|
||||
@@ -5,3 +5,4 @@ pygame==2.5.2
|
||||
scipy==1.13.1
|
||||
skan==0.11.1
|
||||
skimage==0.0
|
||||
pyyaml==6.0.1
|
||||
|
||||
28
utils/Enums.py
Normal file
28
utils/Enums.py
Normal file
@@ -0,0 +1,28 @@
|
||||
from enum import Enum
|
||||
|
||||
class DIRECTION(Enum):
|
||||
NORTH = 0
|
||||
EAST = 1
|
||||
SOUTH = 2
|
||||
WEST = 3
|
||||
|
||||
class COLLUMN_STYLE(Enum):
|
||||
NONE = 0
|
||||
INNER = 1
|
||||
OUTER = 2
|
||||
BOTH = 3
|
||||
|
||||
class WINDOW_BORDER_RADIUS(Enum):
|
||||
NONE = 0
|
||||
TOP = 1
|
||||
TOP_AND_BOTTOM = 2
|
||||
|
||||
class BALCONY_BORDER_RADIUS(Enum):
|
||||
NONE = 0
|
||||
MEDIUM = 1
|
||||
FULL = 2
|
||||
|
||||
class INTER_FLOOR_BORDER(Enum):
|
||||
NONE = 0
|
||||
SLAB = 1
|
||||
STAIRS = 2
|
||||
11
utils/JsonReader.py
Normal file
11
utils/JsonReader.py
Normal file
@@ -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
|
||||
11
utils/YamlReader.py
Normal file
11
utils/YamlReader.py
Normal file
@@ -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
|
||||
6
utils/functions.py
Normal file
6
utils/functions.py
Normal file
@@ -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()]
|
||||
Reference in New Issue
Block a user