def kastenroof(walls, roofwalls, currentheight, roofheight, texture, texture2=None): """ Creates a flat roof with a box on top. Parameters ----------- walls : procedural_city_generation.building_generation.Walls object Walls object after cuts roofwalls : procedural_city_generation.building_generation.Walls object Walls object prior to cuts currentheight : float Current height, Z coordinate of the base of the roof roofheight : float Height of the roof itself texture : procedural_city_generation.building_generation.Texture object texture2 (optional): procedural_city_generation.building_generation.Texture object Will default to texture if not specified Returns ----------- - list<procedural_city_generation.building_generation.Polygon3D object> """ #Texture2 is optional: if not given it will be texture1 texture2 = texture2 if texture2 else texture #TODO: Move numeric values to conf. #Box is a scaled down version of the roofwalls box = scaletransform(roofwalls, random.uniform(0.07, 0.14)) if not roofwalls.l == 4: #Constructs a box with 4 sides if the box did not have 4 sides a, b = box.vertices[0], box.vertices[1] n = (b - a) n = np.array([-n[1], n[0], 0]) box = Walls(np.array([a, b, b + n, a + n]), 4) #Checks if every vertex of the box is "inside" the roof polygon so that the box does not float. #If this is not the case for every vertex, then just a flat roof is built for vert in box.vertices: if not p_in_poly(walls, vert): return [ Polygon3D(walls.vertices + np.array([0, 0, currentheight]), [range(walls.l)], texture) ] #List of the walls and the top of the box and the flat roof return [ buildwalls(box, currentheight, currentheight + roofheight, texture2), Polygon3D(box.vertices + np.array([0, 0, currentheight + roofheight]), [range(4)], texture2), Polygon3D(walls.vertices + np.array([0, 0, currentheight]), [range(walls.l)], texture) ]
def buildledge(walls, bottom, top, texture): """ Creates one ledge Polygon object with shared vertices in the shape of the walls object Parameters ---------- walls : procedural_city_generation.building_generation.Walls object bottom : float z coordinate of the bottom of the walls top : float z coordinate of the top of the walls texture : procedural_city_generation.building_generation.Texture object Returns ------- procedural_city_generation.building_generation.Polygon3D object Example ---------- >>>w=Walls([[0, 0, 0], [0, 1, 0], [1, 1, 0]], 3) >>>p= buildlege( w , 1, 2, some_tex) >>>p.verts [[0, 0, 1], [0, 1, 1], [1, 1, 1], [0, 0, 2], [0, 1, 2], [1, 1, 2]] >>>p.faces [[1, 0, 3, 4], [2, 1, 4, 5], [2, 0, 3, 5], [0, 1, 2], [3, 4, 5]] """ verts = np.concatenate((walls.vertices + np.array([0, 0, bottom]), walls.vertices + np.array([0, 0, top]))) faces = [[i + 1, i, i + walls.l, i + 1 + walls.l] for i in range(walls.l - 1)] faces.extend([[walls.l - 1, 0, walls.l, 2 * walls.l - 1], range(walls.l), range(walls.l, 2 * walls.l)]) return Polygon3D(verts, faces, texture)
def houseroof(walls, currentheight, roofheight, texture): """Creates a "classic" roof with two triangles and two rectangles. Used only for houses and assumes that the house has 4 sides. Parameters ----------- walls : procedural_city_generation.building_generation.Walls object currentheight : float Current height, Z coordinate of the base of the roof roofheight : float Height of the roof itself texture : procedural_city_generation.building_generation.Texture object Returns ------- list<procedural_city_generation.building_generation.Polygon3D object> """ #Differentiation: the shorter of the first two walls is to be cut in half if not np.linalg.norm(np.diff(walls.getWalls()[0], axis=0)) < np.linalg.norm( np.diff(walls.getWalls()[1], axis=0)): walls = Walls(np.roll(walls.vertices, 1, axis=0), walls.l) h_low = np.array([0, 0, currentheight]) h_high = h_low + np.array([0, 0, roofheight]) #The gable coordinates c1, c2 = sum(walls.getWalls()[0] / 2), sum(walls.getWalls()[2] / 2) #Verts are the vertices of the wall and the vertices of the gable verts = [x + h_low for x in walls.vertices] + [c1 + h_high, c2 + h_high] #Faces are two rectangles and two triangles faces = [(0, 1, 5, 4), (3, 2, 5, 4), (0, 3, 4), (1, 2, 5)] return [Polygon3D(verts, faces, texture)]
def flat_polygon(walls, height, texture): """ Creates a flat Polygon with the shape of the walls at the given height Parameters ---------- walls : procedural_city_generation.building_generation.Walls object height : float Z coordinate of the polygon to be created texture : procedural_city_generation.building_generation.Texture object Returns ------- procedural_city_generation.building_generation.Polygon3D object """ return Polygon3D(walls.vertices+np.array([0, 0, height]), [range(walls.l)], texture)
def get_windows(walls, list_of_currentheights, floorheight, windowwidth, windowheight, windowdist, texture): """ Creates a Polygon3D Object containing the coordinates to all windows of a building Parameters ---------- walls : procedural_city_generation.building_generation.Walls Object list_of_currentheights : list<float> Which has one entry for each z-coordinate of a row of windows to be created. This always means the 'bottom' of each floor. floorheight : float Floorheight of the building, used to calculate center of each floor where windows are to be built windowwidth : float Width of each window windowheight : float Height of each window windowdist : float Distance between two windows if more than one window fits on the wall Returns: -------- procedural_city_generation.building_generation.Polygon3D object with shared vertices """ nc = len(list_of_currentheights) #Start off as empty list verts = [] #Counts number of faces nfaces = 0 for wall in walls.getWalls(): #l = Length of wall l = np.linalg.norm(np.diff(wall, axis=0)) # If at least one window fits into the wall: if l > windowwidth: v = wall[1] - wall[0] vn = v / np.linalg.norm(v) h = np.array([0, 0, windowheight / 2]) #Creates a stencil, which, when added to the center point of # a window, is a numpy array with shape 4 describing the #window's coordinates stencil = np.array([(-windowwidth / 2 * vn) - h, (windowwidth / 2 * vn) - h, (windowwidth / 2 * vn) + h, (-windowwidth / 2 * vn) + h]) #Stencil for each currentheight in list_of_currentheights stencilarray = np.array([ stencil + np.array([0, 0, curr_h + floorheight / 2]) for curr_h in list_of_currentheights ]) #If at least one window plus the distance between two windows fits on this wall n = int(l / (windowwidth + windowdist)) if n > 0: #Then, build a window for the amount of windows that fit on this wall nfaces += n * nc for i in range(n): center_of_window = wall[0] + ((i + 1) / (n + 1)) * v verts.extend( np.reshape(stencilarray + center_of_window, (nc * 4, 3))) #Else build one window in the center of the wall elif l / windowwidth > 1: nfaces += nc verts.extend( np.reshape(stencilarray + (wall[0] + (0.5 * v)), (nc * 4, 3))) #Each window has 4 vertices. faces = [range(4 * x, 4 * x + 4) for x in range(nfaces)] return Polygon3D(verts, faces, texture)