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)]
Beispiel #4
0
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)