示例#1
0
def generate_edges(icosahedron, divs, main_displacement, roughness):
    """
    Return a list of edges along each face of the icosahedron
    """
    # If theres an easier way to express edges, we can generalise the solution and increase the resolution of the system
    # Edges that connect the icosahedron together

    edges = get_icosahedron_edges()
    # This stage generates the edges, need to do another generation to fill out triangles
    final_edges = {}
    for i in edges:

        final_edges[i] = [icosahedron[i[0]], icosahedron[i[1]]]
        # Reset starting displacement for each edge

        displacement = main_displacement

        # This needs to be moved to its own function
        for divisions in range(divs):
            displacement *= 2 ** -roughness
            n = 1
            for j in range(len(final_edges[i]) - 1):
                mid = math_helper.get_midpoint(final_edges[i][n - 1], final_edges[i][n])
                mag = math_helper.get_mag(mid)
                scale = random.uniform(mag - displacement, mag + displacement) / mag

                a = mid[0] * scale
                b = mid[1] * scale
                c = mid[2] * scale

                final_edges[i].insert(n, [a, b, c])

                n += 2

        # Create the reverse edge
        final_edges[(i[1], i[0])] = list(reversed(final_edges[i]))

    return final_edges
示例#2
0
def generate_surface(divs, edges, roughness=0, displacement=0):
    """
    Modified version of the midpoint displacement algorithm, or diamond square algorithm,
    made to work with a triangular section of terrian (Face of an icosahedron).

    divs: The number of divisions required on the face
    edges: Edges of the face, can be single points for corners or entire edge.
          Other values will cause an exception
          [[Edge from A to B], [Edge from B to C], [Edge from C to A]]
          where each edge is an array of [x, y, z] coordinates
            B
            |\
            | \
            |  \
            |   \
            |    \
            |_____\
            A      C
            AB - [[0,0] -> [0,n]]
            BC - [[0,n] -> [n,0]]
            CA - [[n,0] -> [0,0]]

    roughness: Controls the decay of surface displacement over successive steps
    displacement: Controls the magnitude of the change in surface
    Returns the generated surface as a triangular array
    """

    max_points = 2 ** divs + 1
    surface = []
    for i in range(max_points):
        surface.append([])
        for j in range(max_points - i):
            surface[i].append(None)

    # AB
    if len(edges[0]) == 1 and len(edges[1]) == 1 and len(edges[2]):
        # A
        surface[0][0] = edges[0][0]
        # B
        surface[0][max_points-1] = edges[1][0]
        # C
        surface[max_points-1][0] = edges[2][0]

    elif len(edges[0]) == max_points and len(edges[1]) == max_points and len(edges[2]) == max_points:
        # AB
        for i in range(0, max_points):
            surface[0][i] = edges[0][i]
        # BC
        for i in range(0, max_points):
            # TODO - This one is iterating backwards
            surface[max_points - 1 - i][i] = edges[1][i]
        # CA
        for i in range(0, max_points):
            surface[max_points - 1 - i][0] = edges[2][i]

    else:
        raise Exception('Incorrect number of points in edge, should be either entire edge or single point')

    step = max_points

    for d in range(divs):
        # Control the displacement decay of the algorithm
        displacement *= 2 ** -roughness
        step //= 2
        for i, x in enumerate(range(0, max_points, step)):
            for j, y in enumerate(range(0, len(surface[x]), step)):
                if surface[x][y] is None:
                    # TODO - Could use a diagram
                    # Select points to calculate the midpoint, the nearest points within the grid are dependant on
                    # the current step size and the parity on the x axis.
                    # The nearest point is then either horizontal line, vertical line or a diagonal line

                    # Horizontal line
                    if j % 2 == 0:
                        upper = surface[x + step][y]
                        lower = surface[x - step][y]

                    else:
                        # Vertical line
                        if i % 2 == 0:
                            upper = surface[x][y + step]
                            lower = surface[x][y - step]

                        # Diagonal line
                        else:
                            upper = surface[x + step][y - step]
                            lower = surface[x - step][y + step]

                    # Find the x,y,z midpoint between the two points
                    mid = math_helper.get_midpoint(upper, lower)
                    # Find the magnitude of the vector
                    mag = math_helper.get_mag(mid)
                    # Scale the vector around its current position and normalize it
                    scale = random.uniform(mag - displacement, mag + displacement) / mag
                    a = mid[0] * scale
                    b = mid[1] * scale
                    c = mid[2] * scale

                    surface[x][y] = [a, b, c]
    return surface