Module mola

This is where the module documentation goes

Expand source code
"""
This is where the module documentation goes
"""
from .core_box import *
from .core_edge import *
from .core_face import *
from .core_grid import *
from .core_mesh import *
from .core_vertex import *
from .graph import *
from .grid_factory import *
from .io import *
from .mesh_factory import *
from .mesh_marching_cubes import *
from .mesh_subdivision import *
from .slicer import *
from .utils_color import *
from .utils_face import *
from .utils_math import *
from .utils_mesh import *
from .utils_poly import *
from .utils_vertex import *

__all__ = [name for name in dir() if not name.startswith('_')]

Sub-modules

mola.colab2D
mola.colab3D
mola.core_box
mola.core_edge
mola.core_face
mola.core_grid
mola.core_mesh
mola.core_vertex
mola.graph
mola.grid_factory
mola.io
mola.mesh_factory
mola.mesh_marching_cubes
mola.mesh_subdivision
mola.module_blender
mola.module_compas
mola.module_processing
mola.module_rhino
mola.slicer
mola.utils_color
mola.utils_face
mola.utils_math
mola.utils_mesh
mola.utils_poly
mola.utils_vertex

Functions

def color_faces_by_area(faces)

Assigns a color to all the faces by area, from smallest (red) to biggest (purple).

Expand source code
def color_faces_by_area(faces):
    """
    Assigns a color to all the faces by area,
    from smallest (red) to biggest (purple).
    """
    color_faces_by_function(faces, utils_face.face_area)
def color_faces_by_compactness(faces)

Assigns a color to all the faces by compactness (area/perimeter), from smallest (red) to biggest (purple).

Expand source code
def color_faces_by_compactness(faces):
    """
    Assigns a color to all the faces by compactness (area/perimeter),
    from smallest (red) to biggest (purple).
    """
    color_faces_by_function(faces, utils_face.face_compactness)
def color_faces_by_curvature(faces)

Assigns a color to all the faces by curvature (require topological meshinformation), from smallest (red) to biggest (purple).

Expand source code
def color_faces_by_curvature(faces):
    """
    Assigns a color to all the faces by curvature (require topological meshinformation),
    from smallest (red) to biggest (purple).
    """
    color_faces_by_function(faces, utils_face.face_curvature)
def color_faces_by_function(faces, faceFunction, do_grayscale=False)

Assigns a color to all the faces by face-function which has to return a float value for a face as argument, from smallest (red) to biggest (purple).

Arguments:

faces: list of faces to color faceFunction : one of the functions ByCurvature, ByArea, etc.


Optional Arguments:

do_grayscale: Boolean

Expand source code
def color_faces_by_function(faces, faceFunction, do_grayscale=False):
    """
    Assigns a color to all the faces by face-function which has to return a float value for a face as argument,
    from smallest (red) to biggest (purple).

    Arguments:
    ----------
    faces: list of faces to color
    faceFunction : one of the functions `ByCurvature`, `ByArea`, etc.
    ----------
    Optional Arguments:
    ----------
    do_grayscale: Boolean
    """
    values = []
    for face in faces:
        values.append(faceFunction(face))
    valueMin = min(values)
    valueMax = max(values)
    for i, face in enumerate(faces):
        h = utils_math.math_map(values[i],valueMin, valueMax, 0.0, 1.0)
        face.color = color_hue_to_rgb(h, do_grayscale)
def color_faces_by_horizontal_angle(faces)
Expand source code
def color_faces_by_horizontal_angle(faces):
    color_faces_by_function(faces, utils_face.face_angle_horizontal)
def color_faces_by_map(faces, colors)
Expand source code
def color_faces_by_map(faces, colors):
    if len(faces) > len(colors):
        print('not enough colors for all the faces')
        return
    for f,c in zip(faces, colors):
        f.color = c
def color_faces_by_perimeter(faces)

Assigns a color to all the faces by perimeter, from smallest (red) to biggest (purple).

Expand source code
def color_faces_by_perimeter(faces):
    """
    Assigns a color to all the faces by perimeter,
    from smallest (red) to biggest (purple).
    """
    color_faces_by_function(faces, utils_face.face_perimeter)
def color_faces_by_vertical_angle(faces)

Assigns a color to all the faces by verticality, from smallest (red) to biggest (purple).

Expand source code
def color_faces_by_vertical_angle(faces):
    """
    Assigns a color to all the faces by verticality,
    from smallest (red) to biggest (purple).
    """
    color_faces_by_function(faces, utils_face.face_angle_vertical)
def color_hue_to_rgb(hue, do_grayscale)

Converts a color defined as Hue (HSV, saturation and value assumed to be 100%) into red, green and blue and returns (r,g,b,1)

Expand source code
def color_hue_to_rgb(hue, do_grayscale):
    """
    Converts a color defined as Hue (HSV, saturation and value assumed to be 100%) into red, green and blue
    and returns (r,g,b,1)
    """
    if do_grayscale:
        return (hue, hue, hue, 1)
    else:
        hue = utils_math.math_map(hue, 0.0, 1.0, 0.0, 0.8) #limit hue red-red to red-magenta
        col = colorsys.hsv_to_rgb(hue, 1, 1)
        return (col[0], col[1], col[2], 1) # alpha = 100 %
def color_map(values=[], colors=[(1, 0, 0.5), (0, 0.5, 1)])

Maps a value to a color on a custom spectrum. The values will be remapped from 0 to 1, the first color will be at 0, the last at 1 and all other colors evenly spread between.

Arguments:

values : list of floats the list of values to be mapped colors : list of (r,g,b) tuples the colors along the spectrum

Expand source code
def color_map(values=[], colors=[(1,0,0.5),(0,0.5,1)]):
    """
    Maps a value to a color on a custom spectrum.
    The values will be remapped from 0 to 1, the first color will be at 0, the
    last at 1 and all other colors evenly spread between.

    Arguments:
    ----------
    values : list of floats
        the list of values to be mapped
    colors : list of (r,g,b) tuples
        the colors along the spectrum
    """
    value_min = min(values)
    value_max = max(values)
    values_mapped = [utils_math.math_map(v, value_min, value_max, 0.0, 0.999) for v in values]
    interval = 1.0 / (len(colors) - 1)
    output_colors = []
    for v in values_mapped:
        lower_ix = int(floor(v * (len(colors)-1)))
        upper_ix = lower_ix + 1
        rv = (v - (lower_ix * interval)) / interval
        r = (1 - rv) * colors[lower_ix][0] + rv * colors[upper_ix][0]
        g = (1 - rv) * colors[lower_ix][1] + rv * colors[upper_ix][1]
        b = (1 - rv) * colors[lower_ix][2] + rv * colors[upper_ix][2]
        output_colors.append((r,g,b,1))
    return output_colors
def construct_box(x1, y1, z1, x2, y2, z2)

Creates and returns a mesh box with six quad faces.

Arguments:

x1,y1,z1 : float
The coordinates of the bottom left front corner
x2,y2,z2 : float
The coordinates of the top right back corner

Expand source code
def construct_box(x1,y1,z1,x2,y2,z2):
    """
    Creates and returns a mesh box with six quad faces.

    Arguments:
    ----------
    x1,y1,z1 : float<br>
        The coordinates of the bottom left front corner<br>
    x2,y2,z2 : float<br>
        The coordinates of the top right back corner<br>
    """
    mesh = Mesh()
    v1 = Vertex(x1, y1, z1)
    v2 = Vertex(x1, y2, z1)
    v3 = Vertex(x2, y2, z1)
    v4 = Vertex(x2, y1, z1)
    v5 = Vertex(x1, y1, z2)
    v6 = Vertex(x1, y2, z2)
    v7 = Vertex(x2, y2, z2)
    v8 = Vertex(x2, y1, z2)
    mesh.vertices = [v1, v2, v3, v4, v5, v6, v7, v8]
    f1 = Face([v1, v2, v3, v4])
    f2 = Face([v8, v7, v6, v5])
    f3 = Face([v4, v3, v7, v8])
    f4 = Face([v3, v2, v6, v7])
    f5 = Face([v2, v1, v5, v6])
    f6 = Face([v1, v4, v8, v5])
    mesh.faces = [f1, f2, f3, f4, f5, f6]
    mesh.update_topology()
    return mesh
def construct_circle(radius, segments, z=0)
Expand source code
def construct_circle(radius, segments, z=0):
    vertices = []
    deltaAngle = math.pi * 2.0 / segments
    for i in range(segments):
        cAngle = i * deltaAngle
        vertices.append(Vertex(math.cos(cAngle) * radius, math.sin(cAngle) * radius, z))
    return vertices
def construct_cone(z1, z2, radius1, radius2, nSegments, capBottom=True, capTop=True)

Creates and returns a conic cylinder.

Expand source code
def construct_cone(z1, z2, radius1, radius2, nSegments, capBottom=True, capTop=True):
    """
    Creates and returns a conic cylinder.
    """
    delaAngle = math.radians(360.0 / nSegments)
    angle = 0
    verticesBottom = []
    verticesTop = []
    for i in range(nSegments):
        x1 = radius1 * math.cos(angle)
        y1 = radius1 * math.sin(angle)
        verticesBottom.append(Vertex(x1, y1, z1))
        x2 = radius2 * math.cos(angle)
        y2 = radius2 * math.sin(angle)
        verticesTop.append(Vertex(x2, y2, z2))
        angle += delaAngle

    mesh = Mesh()
    mesh.vertices.extend(verticesBottom)
    mesh.vertices.extend(verticesTop)
    for i in range(nSegments):
        i2 = (i + 1) % nSegments
        mesh.faces.append(Face([verticesBottom[i],verticesBottom[i2],verticesTop[i2],verticesTop[i]]))
    if capBottom:
        # centerBottom = Vertex(0, 0, z1)
        # mesh.vertices.append(centerBottom)
        # for i in range(nSegments):
        #     i2=(i+1)%nSegments
        #     mesh.faces.append(Face([verticesBottom[i2],verticesBottom[i],centerBottom]))
        mesh.faces.append(Face(list(reversed(verticesBottom))))
    if capTop:
        # centerTop=Vertex(0,0,z2)
        # mesh.vertices.append(centerTop)
        # for i in range(nSegments):
        #     i2=(i+1)%nSegments
        #     mesh.faces.append(Face([verticesTop[i],verticesTop[i2],centerTop]))
        mesh.faces.append(Face(verticesTop))
    mesh.update_topology()
    return mesh
def construct_dodecahedron(radius=1, cx=0, cy=0, cz=0)

Constructs a dodecaheron mesh.

Optional Arguments:

radius : float The radius of the containing sphere cx,cy,cz : float The coordinates of the center point.

Expand source code
def construct_dodecahedron(radius=1, cx=0,cy=0,cz=0):
    """
    Constructs a dodecaheron mesh.

    Optional Arguments:
    ----------
    radius : float
        The radius of the containing sphere
    cx,cy,cz : float
        The coordinates of the center point.
    """
    mesh = Mesh()
    phi = (1 + 5 ** 0.5) / 2
    mesh.vertices = [Vertex( 1, 1, 1),
                Vertex( 1, 1,-1),
                Vertex( 1,-1, 1),
                Vertex( 1,-1,-1),
                Vertex(-1, 1, 1),
                Vertex(-1, 1,-1),
                Vertex(-1,-1, 1),
                Vertex(-1,-1,-1),
                Vertex(0,-phi,-1/phi),
                Vertex(0,-phi, 1/phi),
                Vertex(0, phi,-1/phi),
                Vertex(0, phi, 1/phi),
                Vertex(-phi,-1/phi,0),
                Vertex(-phi, 1/phi,0),
                Vertex( phi,-1/phi,0),
                Vertex( phi, 1/phi,0),
                Vertex(-1/phi,0,-phi),
                Vertex( 1/phi,0,-phi),
                Vertex(-1/phi,0, phi),
                Vertex( 1/phi,0, phi)]

    for i in range(len(mesh.vertices)):
        mesh.vertices[i] = utils_vertex.vertex_scale(mesh.vertices[i], radius)
        mesh.vertices[i] = utils_vertex.vertex_add(mesh.vertices[i], Vertex(cx,cy,cz))
    indices = [2,9,6,18,19,
               4,11,0,19,18,
               18,6,12,13,4,
               19,0,15,14,2,
               4,13,5,10,11,
               14,15,1,17,3,
               1,15,0,11,10,
               3,17,16,7,8,
               2,14,3,8,9,
               6,9,8,7,12,
               1,10,5,16,17,
               12,7,16,5,13]

    for i in range(0, len(indices), 5):
        f = Face([mesh.vertices[indices[i]],
                  mesh.vertices[indices[i + 1]],
                  mesh.vertices[indices[i + 2]],
                  mesh.vertices[indices[i + 3]],
                  mesh.vertices[indices[i + 4]]])
        mesh.faces.append(f)
    mesh.update_topology()
    return mesh
def construct_icosahedron(radius=1, cx=0, cy=0, cz=0)

Creates and returns a mesh in the form of an icosahedron.

Optional Arguments:

radius : float The radius of the containing sphere. cx,cy,cz : float The coordinates of the center point.

Expand source code
def construct_icosahedron(radius=1,cx=0,cy=0,cz=0):
    """
    Creates and returns a mesh in the form of an icosahedron.

    Optional Arguments:
    ----------
    radius : float
        The radius of the containing sphere.
    cx,cy,cz : float
        The coordinates of the center point.
    """
    mesh = Mesh()
    phi = (1 + 5 ** 0.5) / 2
    coordA = 1 / (2 * math.sin(2 * math.pi / 5))
    coordB = phi / (2 * math.sin(2 * math.pi / 5))
    mesh.vertices = [Vertex(0, -coordA, coordB),
                Vertex(coordB, 0, coordA),
                Vertex(coordB, 0, -coordA),
                Vertex(-coordB, 0, -coordA),
                Vertex(-coordB, 0, coordA),
                Vertex(-coordA, coordB, 0),
                Vertex(coordA, coordB, 0),
                Vertex(coordA, -coordB, 0),
                Vertex(-coordA, -coordB, 0),
                Vertex(0, -coordA, -coordB),
                Vertex(0, coordA, -coordB),
                Vertex(0, coordA, coordB)]

    for i in range(len(mesh.vertices)):
        mesh.vertices[i] = utils_vertex.vertex_scale(mesh.vertices[i], radius)
        mesh.vertices[i] = utils_vertex.vertex_add(mesh.vertices[i], Vertex(cx,cy,cz))

    indices = [1, 2, 6, 1, 7, 2, 3, 4, 5, 4, 3, 8, 6, 5, 11, 5, 6, 10, 9, 10, 2, 10, 9, 3, 7, 8, 9, 8, 7, 0, 11, 0, 1, 0, 11, 4, 6, 2, 10, 1, 6, 11, 3, 5, 10, 5, 4, 11, 2, 7, 9, 7, 1, 0, 3, 9, 8, 4, 8, 0]
    faces = []

    for i in range(0,len(indices),3):
        f = Face([mesh.vertices[indices[i]], mesh.vertices[indices[i + 1]], mesh.vertices[indices[i + 2]]])
        faces.append(f)
    mesh.faces = faces
    mesh.update_topology()
    return mesh
def construct_octahedron(edgeLen=1, cx=0, cy=0, cz=0)
Expand source code
def construct_octahedron(edgeLen=1, cx=0, cy=0, cz=0):
    mesh = Mesh()
    #make vertices
    mesh.vertices = [Vertex(0, 0, edgeLen/2),
                     Vertex(-edgeLen/2, 0, 0),
                     Vertex(0, -edgeLen/2, 0),
                     Vertex(edgeLen/2, 0, 0),
                     Vertex(0, edgeLen/2, 0),
                     Vertex(0, 0, -edgeLen/2)]

    #move center to desired coordinates
    center = Vertex(cx, cy, cz)
    for v in mesh.vertices:
        v.add(center)

    #construct triangular faces
    f1 = Face([mesh.vertices[0], mesh.vertices[1], mesh.vertices[2]])
    f2 = Face([mesh.vertices[0], mesh.vertices[2], mesh.vertices[3]])
    f3 = Face([mesh.vertices[0], mesh.vertices[3], mesh.vertices[4]])
    f4 = Face([mesh.vertices[0], mesh.vertices[4], mesh.vertices[1]])
    f5 = Face([mesh.vertices[5], mesh.vertices[2], mesh.vertices[1]])
    f6 = Face([mesh.vertices[5], mesh.vertices[3], mesh.vertices[2]])
    f7 = Face([mesh.vertices[5], mesh.vertices[4], mesh.vertices[3]])
    f8 = Face([mesh.vertices[5], mesh.vertices[1], mesh.vertices[4]])

    mesh.faces = [f1,f2,f3,f4,f5,f6,f7,f8]
    mesh.update_topology()
    return mesh
def construct_rhombic_dodecahedron(edge_length=1, cx=0, cy=0, cz=0)
Expand source code
def construct_rhombic_dodecahedron(edge_length=1, cx=0, cy=0, cz=0):
    mesh = Mesh()
    #make vertices
    mesh.vertices = [Vertex(0,  0, 2 * edge_length),
                     Vertex(-edge_length, edge_length, edge_length),
                     Vertex(-edge_length, -edge_length, edge_length),
                     Vertex(edge_length, -edge_length, edge_length),
                     Vertex(edge_length, edge_length, edge_length),
                     Vertex(-2 * edge_length, 0, 0),
                     Vertex(0, -2*edge_length, 0),
                     Vertex(2 * edge_length, 0, 0),
                     Vertex(0, 2 * edge_length, 0),
                     Vertex(-edge_length, edge_length, -edge_length),
                     Vertex(-edge_length, -edge_length, -edge_length),
                     Vertex(edge_length, -edge_length, -edge_length),
                     Vertex(edge_length, edge_length, -edge_length),
                     Vertex(0, 0, -2 * edge_length)]

    #move center to desired coordinates
    center = Vertex(cx, cy, cz)
    for v in mesh.vertices:
        v.add(center)

    #construct quad faces
    f1 = Face([mesh.vertices[0],mesh.vertices[2],mesh.vertices[5],mesh.vertices[1]])
    f2 = Face([mesh.vertices[0],mesh.vertices[3],mesh.vertices[6],mesh.vertices[2]])
    f3 = Face([mesh.vertices[0],mesh.vertices[4],mesh.vertices[7],mesh.vertices[3]])
    f4 = Face([mesh.vertices[0],mesh.vertices[1],mesh.vertices[8],mesh.vertices[4]])
    f5 = Face([mesh.vertices[2],mesh.vertices[6],mesh.vertices[10],mesh.vertices[5]])
    f6 = Face([mesh.vertices[3],mesh.vertices[7],mesh.vertices[11],mesh.vertices[6]])
    f7 = Face([mesh.vertices[4],mesh.vertices[8],mesh.vertices[12],mesh.vertices[7]])
    f8 = Face([mesh.vertices[1],mesh.vertices[5],mesh.vertices[9],mesh.vertices[8]])
    f9 = Face([mesh.vertices[10],mesh.vertices[13],mesh.vertices[9],mesh.vertices[5]])
    f10 = Face([mesh.vertices[11],mesh.vertices[13],mesh.vertices[10],mesh.vertices[6]])
    f11 = Face([mesh.vertices[12],mesh.vertices[13],mesh.vertices[11],mesh.vertices[7]])
    f12 = Face([mesh.vertices[9],mesh.vertices[13],mesh.vertices[12],mesh.vertices[8]])

    mesh.faces = [f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f11,f12]
    mesh.update_topology()
    return mesh
def construct_single_face(vertices)

Creates and returns a single face mesh from the vertices.

Arguments:

vertices : list of mola.core.Vertex The vertices describing the face

Expand source code
def construct_single_face(vertices):
    """
    Creates and returns a single face mesh from the vertices.

    Arguments:
    ----------
    vertices : list of mola.core.Vertex
        The vertices describing the face
    """
    mesh = Mesh()
    mesh.vertices = vertices
    mesh.faces = [Face(vertices)]
    mesh.update_topology()
    return mesh
def construct_tetrahedron(size=1, cx=0, cy=0, cz=0)

Constructs a tetrahedron mesh.

Optional Arguments:

side : float The edge length of the tetrahedron cx,cy,cz : float The coordinates of the center point.

Expand source code
def construct_tetrahedron(size=1,cx=0,cy=0,cz=0):
    """
    Constructs a tetrahedron mesh.

    Optional Arguments:
    ----------
    side : float
        The edge length of the tetrahedron
    cx,cy,cz : float
        The coordinates of the center point.
    """

    mesh = Mesh()
    coord = 1 / math.sqrt(2)
    mesh.vertices = [Vertex(+1, 0, -coord),
                     Vertex(-1, 0, -coord),
                     Vertex(0, +1, +coord),
                     Vertex(0, -1, +coord)]

    for i in range(len(mesh.vertices)):
        mesh.vertices[i] = utils_vertex.vertex_scale(mesh.vertices[i], size / 2)
        mesh.vertices[i] = utils_vertex.vertex_add(mesh.vertices[i], Vertex(cx, cy, cz))

    f1 = Face([mesh.vertices[0], mesh.vertices[1], mesh.vertices[2]])
    f2 = Face([mesh.vertices[1], mesh.vertices[0], mesh.vertices[3]])
    f3 = Face([mesh.vertices[2], mesh.vertices[3], mesh.vertices[0]])
    f4 = Face([mesh.vertices[3], mesh.vertices[2], mesh.vertices[1]])

    mesh.faces = [f1, f2, f3, f4]
    mesh.update_topology()
    return mesh
def construct_torus(ringRadius, tubeRadius, ringN=16, tubeN=16)

Constructs a torus mesh.

Arguments:

ringRadius : float the big radius of the axis tubeRadius : float radius of the the tube along the axis

Optional Arguments:

ringN : int resolution along the ring tubeN : int resolution along the tube

Expand source code
def construct_torus(ringRadius, tubeRadius, ringN = 16, tubeN = 16):
    """
    Constructs a torus mesh.

    Arguments:
    ----------
    ringRadius : float
        the big radius of the axis
    tubeRadius : float
        radius of the the tube along the axis

    Optional Arguments:
    ----------
    ringN : int
        resolution along the ring
    tubeN : int
        resolution along the tube
    """
    mesh = Mesh()
    theta = 2 * math.pi / ringN
    phi = 2 * math.pi / tubeN

    for i in range (ringN):
        for j in range (tubeN):
            mesh.vertices.append(_torus_vertex(ringRadius, tubeRadius, phi * j, theta * i))

    for i in range(ringN):
        ii = (i + 1) % ringN
        for j in range(tubeN):
            jj = (j + 1) % tubeN
            a = i  * tubeN + j
            b = ii * tubeN + j
            c = ii * tubeN + jj
            d = i  * tubeN + jj
            f = Face([mesh.vertices[k] for k in [a, b, c, d]])
            mesh.faces.append(f)
    mesh.update_topology()
    return mesh
def export_obj(mesh, fileNameOBJ, exportColors=True, exportGroups=True, weldVertices=True)
Expand source code
def export_obj(mesh,fileNameOBJ,exportColors=True,exportGroups=True,weldVertices=True):
    export_obj_faces(mesh.faces,fileNameOBJ,exportColors,exportGroups,weldVertices)
def export_obj_faces(faces, fileNameOBJ, exportColors=True, exportGroups=True, weldVertices=True)

Exports the faces as an Alias wavefront obj file.

Arguments:

faces : list of mola.core.Face The face to be measured fileNameOBJ : String The path and filename for the *.obj mesh file

Expand source code
def export_obj_faces(faces,fileNameOBJ,exportColors=True,exportGroups=True,weldVertices=True):
    """
    Exports the faces as an Alias wavefront obj file.

    Arguments:
    ----------
    faces : list of mola.core.Face
        The face to be measured
    fileNameOBJ : String
        The path and filename for the *.obj mesh file
    """
    file = open(fileNameOBJ, "w")
    if exportColors:
        fileNameMTL = ntpath.basename(fileNameOBJ) + ".mtl"
        file.write("mtllib ./" + fileNameMTL + "\n")
        fileMTL = open(fileNameOBJ + ".mtl", "w")
        materials = {}

    if exportGroups:
        faces.sort(key = lambda x: x.group)

    vertexCount = 0
    vertices = {}
    currentGroup = None

    for face in faces:
        if exportGroups and face.group != currentGroup:
            file.write("g " + str(face.group) + "\n")
            currentGroup = face.group
        if exportColors:
            materials[__strColor(face.color)] = face.color
            file.write("usemtl material" + __strColor(face.color) + "\n")
        faceString = "f"

        if weldVertices:
            for p in face.vertices:
                ptuple = (p.x,p.y,p.z)
                if ptuple in vertices:
                    faceString += " " + str(vertices[ptuple])
                else:
                    vertexCount += 1
                    faceString += " "+str(vertexCount)
                    vertices[ptuple] = vertexCount
                    file.write("v " + str(p.x) + " " + str(p.y) + " " + str(p.z) + "\n")
        else:
            for p in face.vertices:
                vertexCount += 1
                faceString += " " + str(vertexCount)
                file.write("v " + str(p.x) + " " + str(p.y) + " " + str(p.z) + "\n")

        faceString += "\n"
        file.write(faceString)
    file.close()

    if exportColors:
        for mat in materials.values():
            fileMTL.write("newmtl material" + __strColor(mat) + "\n")
            fileMTL.write("Kd " + str(mat[0]) + " " + str(mat[1]) + " " + str(mat[2]) + "\n")
        fileMTL.close()
def face_angle_horizontal(face)

Returns the azimuth, the orientation of the face around the z-axis in the XY-plane

Arguments:

face : mola.Face The face to be measured

Expand source code
def face_angle_horizontal(face):
    """
    Returns the azimuth, the orientation of the face around the z-axis in the XY-plane

    Arguments:
    ----------
    face : mola.Face
            The face to be measured
    """
    n = face_normal(face)
    return math.atan2(n.y, n.x)
def face_angle_vertical(f)

Returns the altitude, 0 if the face is vertical, -Pi/2 if it faces downwards, +Pi/2 if it faces upwards.

Arguments:

face : mola.Face The face to be measured

Expand source code
def face_angle_vertical(f):
    """
    Returns the altitude, 0 if the face is vertical, -Pi/2 if it faces downwards, +Pi/2 if it faces upwards.

    Arguments:
    ----------
    face : mola.Face
            The face to be measured
    """
    n = face_normal(f)
    #nXY = Vertex(n.x, n.y, 0.0)
    #return vecUtils.angle(n, nXY)
    # alternative, probably less computationally intense:
    return math.asin(n.z)
def face_area(face)

Returns the area of a face, for quads that of two triangles.

Arguments:

face : mola.Face The face to be measured

Expand source code
def face_area(face):
    """
    Returns the area of a face, for quads that of two triangles.

    Arguments:
    ----------
    face : mola.Face
            The face to be measured
    """
    if(len(face.vertices) == 3):
        return utils_vertex.triangle_area(face.vertices[0], face.vertices[1], face.vertices[2])
    else:
        return utils_vertex.triangle_area(face.vertices[0], face.vertices[1], face.vertices[2]) + utils_vertex.triangle_area(face.vertices[2], face.vertices[3], face.vertices[0])
def face_center(face)

Returns the center point (type Vertex) of a face. Note: not the center of gravity, just the average of its vertices.

Arguments:

face : mola.Face The face to be measured

Expand source code
def face_center(face):
    """
    Returns the center point (type Vertex) of a face.
    Note: not the center of gravity, just the average of its vertices.

    Arguments:
    ----------
    face : mola.Face
            The face to be measured
    """
    return utils_vertex.vertices_list_center(face.vertices)
def face_compactness(face)

Returns the compactness of a face as the ratio between area and perimeter.

Arguments:

face : mola.Face The face to be measured

Expand source code
def face_compactness(face):
    """
    Returns the compactness of a face as the ratio between area and perimeter.

    Arguments:
    ----------
    face : mola.Face
            The face to be measured
    """
    return face_area(face) / face_perimeter(face)
def face_copy_properties(faceParent, faceChild)

Copies the properties (color,group,…) of faceParent to faceChild.

Arguments:

faceParent : mola.Face The face to copy the properties From. faceChild : mola.Face The face to copy the properties To.

Expand source code
def face_copy_properties(faceParent,faceChild):
    """
    Copies the properties (color,group,...) of faceParent to faceChild.

    Arguments:
    ----------
    faceParent : mola.Face
                 The face to copy the properties From.
    faceChild : mola.Face
                 The face to copy the properties To.
    """
    faceChild.group = faceParent.group
    faceChild.color = faceParent.color
def face_curvature(face)

Returns the local curvature of a mesh face, by measuring the angle to the neighbour faces.

Arguments:

face : mola.Face The face to be measured

Expand source code
def face_curvature(face):
    """
    Returns the local curvature of a mesh face, by measuring the angle to the neighbour faces.

    Arguments:
    ----------
    face : mola.Face
        The face to be measured
    """
    facenormal = face_normal(face)
    sumD = 0
    vPrev = face.vertices[-1]
    num_faces = 1
    for v in face.vertices:
        edge = v.edge_adjacent_to_vertex(vPrev)
        if edge != None:
            nbFace = edge.face1
            if edge.face1 == face:
                nbFace = edge.face2
            if nbFace != None:
                num_faces += 1
                nbNormal = face_normal(nbFace)
                sumD += utils_vertex.vertex_distance(nbNormal,facenormal)
        vPrev = v
    return sumD / num_faces
def face_normal(face)

Returns the normal of a face, a vector of length 1 perpendicular to the plane of the triangle.

Arguments:

face : mola.Face the face to get the normal from

Expand source code
def face_normal(face):
    """
    Returns the normal of a face, a vector of length 1 perpendicular to the plane of the triangle.

    Arguments:
    ----------
    face : mola.Face
        the face to get the normal from
    """
    return utils_vertex.triangle_normal(face.vertices[0], face.vertices[1], face.vertices[2])
def face_perimeter(face)

Returns the perimeter of a face as the sum of all the edges' lengths.

Arguments:

face : mola.Face The face to be measured

Expand source code
def face_perimeter(face):
    """
    Returns the perimeter of a face as the sum of all the edges' lengths.

    Arguments:
    ----------
    face : mola.Face
            The face to be measured
    """
    sum = 0
    for i in range(len(face.vertices)):
        v1 = face.vertices[i]
        v2 = face.vertices[(i + 1) % len(face.vertices)]
        sum += utils_vertex.vertex_distance(v1,v2)
    return sum
def face_scale(face, factor=1.0, origin=None)
Expand source code
def face_scale(face, factor=1.0, origin=None):
    if origin is None:
        for v in face.vertices:
            v.scale(factor)
    else:
        for v in face.vertices:
            delta = v - origin
            delta.scale(factor)
            v.x = origin.x + delta.x
            v.y = origin.y + delta.y
            v.z = origin.z + delta.z
    return face
def floor(...)

floor(x)

Return the floor of x as an Integral. This is the largest integer <= x.

def grid_set_values_at_borders(grid, value)
Expand source code
def grid_set_values_at_borders(grid, value):
    for i in range(grid.nx):
        for j in range(grid.ny):
            for k in range(grid.nz):
                if (i==0 or i==grid.nx-1):
                    grid.set_value_at_xyz(value,i,j,k)
                elif (j==0 or j==grid.ny-1):
                    grid.set_value_at_xyz(value,i,j,k)
                elif (k==0 or k==grid.nz-1):
                    grid.set_value_at_xyz(value,i,j,k)
def grid_set_values_sinusoids(grid, freq_x=18.84955592153876, freq_y=18.84955592153876, freq_z=18.84955592153876)
Expand source code
def grid_set_values_sinusoids(grid, freq_x=6*math.pi, freq_y=6*math.pi, freq_z=6*math.pi):
    for i in range(grid.nx):
        for j in range(grid.ny):
            for k in range(grid.nz):
                vx = math.sin(i/grid.nx * freq_x)
                vy = math.sin(j/grid.ny * freq_y)
                vz = math.sin(k/grid.nz * freq_z)
                v = utils_math.math_map((vx+vy+vz),-3.0,3.0,-1.0,1.0)
                grid.set_value_at_xyz(v,i,j,k)
def import_obj(filename)

Loads a Wavefront OBJ file.

Expand source code
def import_obj(filename):
    """Loads a Wavefront OBJ file. """
    mesh = Mesh()
    group = ""
    for line in open(filename, "r"):
        if line.startswith('#'): continue
        values = line.split()
        if not values: continue
        if values[0] == 'g':
            group=values[1]
        elif values[0] == 'v':
            v = [float(c) for c in values[1 : 4]]
            #v = map(float, values[1:4])
            mesh.vertices.append(Vertex(v[0],v[1],v[2]))
        elif values[0] == 'f':
            face = Face([])
            face.group = group
            for v in values[1:]:
                w = v.split('/')
                vertex = mesh.vertices[int(w[0]) - 1]
                face.vertices.append(vertex)
            mesh.faces.append(face)
    return mesh
def import_obj_faces(filename)

Loads a Wavefront OBJ file.

Expand source code
def import_obj_faces(filename):
    """Loads a Wavefront OBJ file. """
    return import_obj(filename).faces
def marching_cubes(nX, nY, nZ, values, iso, scale_to_canvas=False)
Expand source code
def marching_cubes(nX,nY,nZ,values,iso, scale_to_canvas=False):
    mesh =  Mesh()
    nYZ = nY * nZ
    index = 0
    n =[0]*8
    switcher = {
        0:lambda: Vertex(x + _v(n[0], n[1], iso), y + 1, z),
        1:lambda: Vertex(x + 1, y + _v(n[2], n[1], iso), z),
        2:lambda: Vertex(x + _v(n[3], n[2], iso), y, z),
        3:lambda: Vertex(x, y + _v(n[3], n[0], iso), z),
        4:lambda: Vertex(x + _v(n[4], n[5], iso), y + 1, z + 1),
        5:lambda: Vertex(x + 1, y + _v(n[6], n[5], iso), z + 1),
        6:lambda: Vertex(x + _v(n[7], n[6], iso), y, z + 1),
        7:lambda: Vertex(x, y + _v(n[7], n[4], iso), z + 1),
        8:lambda: Vertex(x, y + 1, z + _v(n[0], n[4], iso)),
        9:lambda: Vertex(x + 1, y + 1, z + _v(n[1], n[5], iso)),
        10:lambda: Vertex(x, y, z + _v(n[3], n[7], iso)),
        11:lambda: Vertex(x + 1, y, z + _v(n[2], n[6], iso))
    }
    for x in range(nX - 1):
        for y in range(nY - 1):
            for z in range(nZ - 1):
                caseNumber = 0
                index = z + y * nZ + x * nYZ
                # collecting the values
                n[0] = values[index + nZ]# 0,1,0
                n[1] = values[index + nYZ + nZ]#1,1,0
                n[2] = values[index + nYZ]# 1,0,0
                n[3] = values[index]# 0,0,0
                n[4] = values[index + nZ + 1]# 0,1,1
                n[5] = values[index + nYZ + nZ + 1]# 1,1,1
                n[6] = values[index + nYZ + 1]# 1,0,1
                n[7] = values[index + 1]# 0,0,1
                for i in range(7,-1,-1):
                    if n[i] > iso:
                        caseNumber+=1
                    if i > 0:
                        caseNumber = caseNumber << 1
                # collecting the faces
                offset = caseNumber * 15
                for i in range(offset,offset + 15,3):
                    if _faces[i] > -1:
                        vs=[]
                        for j in range(i,i+3):
                            v = switcher[_faces[j]]()
                            mesh.vertices.append(v)
                            vs.append(v)
                            if len(vs) == 3:
                                mesh.faces.append(Face(vs))

    mesh.update_topology()
    if(scale_to_canvas):
        mesh.translate(-nX/2.0,-nY/2.0,-nZ/2.0)
        sc = 20.0/max(nX,nY)
        mesh.scale(sc,sc,sc)

    return mesh
def marching_cubes_from_grid(grid, iso)
Expand source code
def marching_cubes_from_grid(grid,iso):
    return marching_cubes(grid.nx,grid.ny,grid.nz,grid.values,iso,grid.scale_to_canvas)
def math_determinant(a, b, c, d, e, f, g, h, i)

returns the determinant of the 9 values of a 3 x 3 matrix

Expand source code
def math_determinant(a, b, c, d, e, f, g, h, i):
    """
    returns the determinant of the 9 values of a 3 x 3 matrix
    """
    return (a * e * i - a * f * h - b * d * i + b * f * g + c * d * h - c * e * g)
def math_map(value, fromMin, fromMax, toMin, toMax)

Maps a value from one range to another. Arguments:


value : value to be mapped fromMin : lower bound of the value's current range fromMax : upper bound of the value's current range toMin : lower bound of the value's target range toMax : upper bound of the value's target range

Expand source code
def math_map(value, fromMin, fromMax, toMin, toMax):
    """
    Maps a value from one range to another.
    Arguments:
    ----------
    value : value to be mapped
    fromMin : lower bound of the value's current range
    fromMax : upper bound of the value's current range
    toMin : lower bound of the value's target range
    toMax : upper bound of the value's target range
    """
    delta = fromMax - fromMin
    if delta == 0 : return 0
    return toMin + ((toMax - toMin) / delta) * (value - fromMin)
def math_map_list(values, toMin=0, toMax=1)

Maps the values of a list from a minimum value to a maximum value. Arguments:


values : list to be mapped

Optional Arguments:

toMin : minimum value of the list's target range (default = 0) toMax : maximum value of the list's target range (default = 1)

Expand source code
def math_map_list(values,toMin=0,toMax=1):
    """
    Maps the values of a list from a minimum value to a maximum value.
    Arguments:
    ----------
    values : list to be mapped

    Optional Arguments:
    ----------
    toMin : minimum value of the list's target range (default = 0)
    toMax : maximum value of the list's target range (default = 1)
    """
    minValue=min(values)
    maxValue=max(values)
    delta=maxValue-minValue
    deltaTarget=toMax-toMin
    return list(map(lambda x: toMin+deltaTarget*(x-minValue)/delta, values))
def mesh_smooth_laplacian(mesh, factor=0.3)
Expand source code
def mesh_smooth_laplacian(mesh, factor=0.3):
    smoothed = mesh.copy()
    #smoothed.update_topology()
    for i,v in enumerate(mesh.vertices):
        adjacent_vertices = [e.other_vertex(v) for e in v.edges]
        v_sum = Vertex()
        [v_sum.add(av) for av in adjacent_vertices]
        v_sum.divide(len(adjacent_vertices))
        delta = v_sum - v
        sv = smoothed.vertices[i]
        delta.scale(factor)
        sv.add(delta)
    return smoothed
def normal_edge_2d(vprev, v)
Expand source code
def normal_edge_2d(vprev, v):
    vec1 = utils_vertex.vertex_subtract(v, vprev)
    vec1 = utils_vertex.vertex_unitize(vec1)
    return utils_vertex.vertex_rotate_2D_90(vec1)
def normal_edge_2d_non_unified(vprev, v)
Expand source code
def normal_edge_2d_non_unified(vprev, v):
    vec1 = utils_vertex.vertex_subtract(v, vprev)
    return utils_vertex.vertex_rotate_2D_90(vec1)
def normal_vertex_2d(vprev, v, vnext)
Expand source code
def normal_vertex_2d(vprev, v, vnext):
    vec1 = utils_vertex.vertex_subtract(v, vprev)
    vec1 = utils_vertex.vertex_unitize(vec1)
    vec2 = utils_vertex.vertex_subtract(vnext, v)
    vec2 = utils_vertex.vertex_unitize(vec2)
    n = utils_vertex.vertex_add(vec1, vec2)
    n = utils_vertex.vertex_scale(n, 0.5)
    n = utils_vertex.vertex_rotate_2D_90(n)
    #t=n.x
    #n.x=-n.y
    #n.y=t
    return n
def offset(mesh, offset=1, doclose=True)
Expand source code
def offset(mesh,offset=1,doclose=True):
    newMesh=Mesh()
    # calculate vertex normals
    for vertex in mesh.vertices:
        vertex.vertex = Vertex(0,0,0)
        vertex.nfaces = 0
    for face in mesh.faces:
        normal = utils_face.face_normal(face)
        for vertex in face.vertices:
            vertex.vertex.add(normal)
            vertex.nfaces += 1
    for vertex in mesh.vertices:
        vertex.vertex.scale(offset / vertex.nfaces)
        vertex.vertex.add(vertex)
    # create faces
    for face in mesh.faces:
        offsetVertices = []
        for vertex in face.vertices:
            offsetVertices.append(vertex.vertex)
        offsetVertices.reverse()
        newFace = Face(offsetVertices)
        newMesh.faces.append(newFace)
        newMesh.faces.append(face)
    # create sides
    if doclose:
        for edge in mesh.edges:
            if edge.face1 == None or edge.face2 == None:
                offsetVertices = [edge.v1, edge.v2, edge.v2.vertex, edge.v1.vertex]
                if edge.face2 == None:
                    offsetVertices.reverse()
                newFace = Face(offsetVertices)
                newMesh.faces.append(newFace)
    newMesh.update_topology()
    return newMesh
def slice(mesh, z)
Expand source code
def slice(mesh,z):
    edges=[]
    for face in mesh.faces:
        if len(face.vertices)==4:
            edge=sliceTriangle((face.vertices[0],face.vertices[1],face.vertices[2]),z)
            if edge!=None:
                edges.append(edge)
            edge=sliceTriangle((face.vertices[2],face.vertices[3],face.vertices[0]),z)
            if edge!=None:
                edges.append(edge)
        if len(face.vertices)==3:
            edge=sliceTriangle(face.vertices,z)
            if edge!=None:
                edges.append(edge)
    return edges
def sliceTriangle(_vertices, z)
Expand source code
def sliceTriangle(_vertices,z):
    intersections=[]
    vPrev=_vertices[-1]
    for v in _vertices:
        intersection=sliceWithZ(vPrev,v,z)
        if intersection!=None:
            intersections.append(intersection)
        vPrev=v
    if len(intersections)==2:
        dX=intersections[0].x-intersections[1].x
        dY=intersections[0].y-intersections[1].y
        if dX!=0 or dY!=0:
            return Edge(intersections[0],intersections[1])
    return None
def sliceWithZ(v1, v2, z)
Expand source code
def sliceWithZ(v1,v2,z):
    if v1.z==z: return Vertex(v1.x,v1.y,z)
    if v1.z<=z and v2.z<=z:
        return None
    if v1.z>=z and v2.z>=z:
        return None
    dX=v2.x-v1.x
    dY=v2.y-v1.y
    dZ=v2.z-v1.z
    if dZ==0:return None
    f=(z-v1.z)/dZ
    return Vertex(f*dX+v1.x,f*dY+v1.y,z)
def subdivide_catmull_2d(vertices)
Expand source code
def subdivide_catmull_2d(vertices):
    newNodes = []
    for i in range(len(vertices)):
        a = vertices[i]
        newNodes.append(Vertex(a.x,a.y,a.z))
        b = vertices[(i + 1) % len(vertices)]
        center = utils_vertex.vertex_add(a, b)
        newNodes.append(utils_vertex.vertex_scale(center,0.5))
    newNodes2 = []
    for i in range(len(newNodes)):
        iPrev = i - 1
        if iPrev < 0:
            iPrev = len(newNodes) - 1
        iNext = i + 1
        if iNext >= len(newNodes):
            iNext = 0
        a = newNodes[iPrev]
        b = newNodes[i]
        c = newNodes[iNext]
        average = Vertex()
        # [average.add(v) for v in [a,b,b,c]]
        average.add(a)
        average.add(b)
        average.add(b)
        average.add(c)
        average.divide(4.0)
        # average = utils_vertex.vertex_add(average,a)
        # average = utils_vertex.vertex_add(average,b)
        # average = utils_vertex.vertex_add(average,b)
        # average = utils_vertex.vertex_add(average,c)
        # average /= 4
        # average = utils_vertex.vertex_divide(average,4.0)
        newNodes2.append(average)
    return newNodes2
def subdivide_custom_triface_extrude_tapered_nonU(face, height=0.0, fraction=0.5, doCap=True)

Extrudes a triangular face tapered like a window by creating an offset face and quads between every original edge and the corresponding new edge. The vertices of the new edge which corresponds to the shortest edge of the triangle are moved closer to the later, while preserving the offset from its other edges

Arguments:

face : mola.core.Face The face to be extruded height : float The distance of the new face to the original face, default 0 fraction : float The relative offset distance, 0: original vertex, 1: center point default 0.5 (halfway)

Expand source code
def subdivide_custom_triface_extrude_tapered_nonU(face, height=0.0, fraction=0.5,doCap=True):
    """
    Extrudes a triangular face tapered like a window by creating an
    offset face and quads between every original edge and the
    corresponding new edge. The vertices of the new edge which corresponds 
    to the shortest edge of the triangle are moved closer to the later,
    while preserving the offset from its other edges 

    Arguments:
    ----------
    face : mola.core.Face
        The face to be extruded
    height : float
        The distance of the new face to the original face, default 0
    fraction : float
        The relative offset distance, 0: original vertex, 1: center point
        default 0.5 (halfway)
    """

    center_vertex = utils_face.face_center(face)
    normal = utils_face.face_normal(face)
    scaled_normal = utils_vertex.vertex_scale(normal, height)

    minD = 9999999999999999
    for i in range(len(face.vertices)-1):
        n1 = face.vertices[i]
        for j in range(i+1,len(face.vertices)):

            n2 = face.vertices[j]
            d = (n2.x-n1.x)**2.0 + (n2.y - n1.y)**2.0 + (n2.z - n1.z)**2.0
            if d<minD:
                minD = d
                shortF_st = i
                shortF_end = j

    other = 3 - shortF_st - shortF_end
    n_other = face.vertices[other]
    betw_other = utils_vertex.vertex_subtract(center_vertex, n_other)
    betw_other = utils_vertex.vertex_scale(betw_other, fraction)
    nn_other = utils_vertex.vertex_add(n_other, betw_other)
    nn_other = utils_vertex.vertex_add(nn_other, scaled_normal)

    # calculate new vertex positions
    new_vertices = []
    for i in range(len(face.vertices)):
        n1 = face.vertices[i]
        betw = utils_vertex.vertex_subtract(center_vertex, n1)
        betw = utils_vertex.vertex_scale(betw, fraction)
        nn = utils_vertex.vertex_add(n1, betw)
        nn = utils_vertex.vertex_add(nn, scaled_normal) 

        if i==shortF_st or i==shortF_end:
            vec = utils_vertex.vertex_subtract(n1, nn_other)
            vec = utils_vertex.vertex_scale(vec, 0.25)
            nn = utils_vertex.vertex_add(nn, vec)

        new_vertices.append(nn)

    new_faces = []
    # create the quads along the edges
    num = len(face.vertices)
    for i in range(num):
        n1 = face.vertices[i]
        n2 = face.vertices[(i + 1) % num]
        n3 = new_vertices[(i + 1) % num]
        n4 = new_vertices[i]
        new_face = Face([n1,n2,n3,n4])
        new_faces.append(new_face)

    # create the closing cap face
    if doCap:
        cap_face = Face(new_vertices)
        new_faces.append(cap_face)

    for new_face in new_faces:
        utils_face.face_copy_properties(face,new_face)

    return new_faces
def subdivide_face_extrude(face, height=0.0, capBottom=False, capTop=True)

Extrudes the face straight by distance height.

Arguments:

face : mola.core.Face The face to be extruded height : float The extrusion distance, default 0 capBottom : bool Toggle if bottom face (original face) should be created, default False capTop : bool Toggle if top face (extrusion face) should be created, default True

Expand source code
def subdivide_face_extrude(face, height=0.0, capBottom=False, capTop=True):
    """
    Extrudes the face straight by distance height.

    Arguments:
    ----------
    face : mola.core.Face
        The face to be extruded
    height : float
        The extrusion distance, default 0
    capBottom : bool
        Toggle if bottom face (original face) should be created, default False
    capTop : bool
        Toggle if top face (extrusion face) should be created, default True
    """
    normal=utils_face.face_normal(face)
    normal=utils_vertex.vertex_scale(normal,height)
    # calculate vertices
    new_vertices=[]
    for i in range(len(face.vertices)):
        new_vertices.append(utils_vertex.vertex_add(face.vertices[i], normal))
    # faces
    new_faces=[]
    if capBottom:
        new_faces.append(face)
    for i in range(len(face.vertices)):
        i2=i+1
        if i2>=len(face.vertices):
            i2=0
        v0=face.vertices[i]
        v1=face.vertices[i2]
        v2=new_vertices[i2]
        v3=new_vertices[i]
        new_faces.append(Face([v0,v1,v2,v3]))
    if capTop:
        new_faces.append(Face(new_vertices))
    for new_face in new_faces:
        utils_face.face_copy_properties(face,new_face)
    return new_faces
def subdivide_face_extrude_tapered(face, height=0.0, fraction=0.5, doCap=True)

Extrudes the face tapered like a window by creating an offset face and quads between every original edge and the corresponding new edge.

Arguments:

face : mola.core.Face The face to be extruded height : float The distance of the new face to the original face, default 0 fraction : float The relative offset distance, 0: original vertex, 1: center point default 0.5 (halfway)

Expand source code
def subdivide_face_extrude_tapered(face, height=0.0, fraction=0.5,doCap=True):
    """
    Extrudes the face tapered like a window by creating an
    offset face and quads between every original edge and the
    corresponding new edge.

    Arguments:
    ----------
    face : mola.core.Face
        The face to be extruded
    height : float
        The distance of the new face to the original face, default 0
    fraction : float
        The relative offset distance, 0: original vertex, 1: center point
        default 0.5 (halfway)
    """
    center_vertex = utils_face.face_center(face)
    normal = utils_face.face_normal(face)
    scaled_normal = utils_vertex.vertex_scale(normal, height)

    # calculate new vertex positions
    new_vertices = []
    for i in range(len(face.vertices)):
        n1 = face.vertices[i]
        betw = utils_vertex.vertex_subtract(center_vertex, n1)
        betw = utils_vertex.vertex_scale(betw, fraction)
        nn = utils_vertex.vertex_add(n1, betw)
        nn = utils_vertex.vertex_add(nn, scaled_normal)
        new_vertices.append(nn)

    new_faces = []
    # create the quads along the edges
    num = len(face.vertices)
    for i in range(num):
        n1 = face.vertices[i]
        n2 = face.vertices[(i + 1) % num]
        n3 = new_vertices[(i + 1) % num]
        n4 = new_vertices[i]
        new_face = Face([n1,n2,n3,n4])
        new_faces.append(new_face)

    # create the closing cap face
    if doCap:
        cap_face = Face(new_vertices)
        new_faces.append(cap_face)

    for new_face in new_faces:
        utils_face.face_copy_properties(face,new_face)
    return new_faces
def subdivide_face_extrude_to_point(face, point)

Extrudes the face to a point by creating a triangular face from each edge to the point.

Arguments:

face : mola.core.Face The face to be extruded point : mola.core.Vertex The point to extrude to

Expand source code
def subdivide_face_extrude_to_point(face, point):
    """
    Extrudes the face to a point by creating a
    triangular face from each edge to the point.

    Arguments:
    ----------
    face : mola.core.Face
        The face to be extruded
    point : mola.core.Vertex
        The point to extrude to
    """
    numV = len(face.vertices)
    faces = []
    for i in range(numV):
        v1 = face.vertices[i]
        v2 = face.vertices[(i + 1) % numV]
        f = Face([v1, v2, point])
        utils_face.face_copy_properties(face, f)
        faces.append(f)
    return faces
def subdivide_face_extrude_to_point_center(face, height=0.0)

Extrudes the face to the center point moved by height normal to the face and creating a triangular face from each edge to the point.

Arguments:

face : mola.core.Face The face to be extruded height : float The distance of the new point to the face center, default 0

Expand source code
def subdivide_face_extrude_to_point_center(face, height=0.0):
    """
    Extrudes the face to the center point moved by height
    normal to the face and creating a triangular face from
    each edge to the point.

    Arguments:
    ----------
    face : mola.core.Face
        The face to be extruded
    height : float
        The distance of the new point to the face center, default 0
    """
    normal = utils_face.face_normal(face)
    normal = utils_vertex.vertex_scale(normal,height)
    center = utils_face.face_center(face)
    center = utils_vertex.vertex_add(center,normal)
    return subdivide_face_extrude_to_point(face,center)
def subdivide_face_offset_planar(face, offsets)
Expand source code
def subdivide_face_offset_planar(face,offsets):
    newPts = []
    for i in range(len(face.vertices)):
        iP = i - 1
        if(iP < 0):
            iP = len(face.vertices)-1
        iN = (i + 1) % len(face.vertices)
        v0 = face.vertices[iP]
        v1 = face.vertices[i]
        v2 = face.vertices[iN]
        newPts.append(utils_vertex.vertex_offset_point(v0, v1, v2, offsets[iP], offsets[i]))
    f = Face(newPts)
    utils_face.face_copy_properties(face, f)
    return f
def subdivide_face_split_frame(face, w)

Creates an offset frame with quad corners. Works only with convex shapes.

Arguments:

face : mola.core.Face The face to be split w : float The width of the offset frame

Expand source code
def subdivide_face_split_frame(face, w):
    """
    Creates an offset frame with quad corners. Works only with convex shapes.

    Arguments:
    ----------
    face : mola.core.Face
        The face to be split
    w : float
        The width of the offset frame
    """
    faces = []
    innerVertices = []
    for i in range(len(face.vertices)):
      if(i == 0):
        vp = face.vertices[len(face.vertices)-1]
      else:
        vp = face.vertices[i - 1]
      v = face.vertices[i]
      vn = face.vertices[(i + 1) % len(face.vertices)]
      vnn = face.vertices[(i + 2) % len(face.vertices)]

      th1 = utils_vertex.vertex_angle_triangle(vp,v,vn)
      th2 = utils_vertex.vertex_angle_triangle(v,vn,vnn)

      w1 = w / math.sin(th1)
      w2 = w / math.sin(th2)

      vs1 = _vertices_frame(v, vn, w1, w2)
      vs2 = _vertices_frame(_vertices_frame(vp, v, w1, w1)[2], _vertices_frame(vn, vnn, w2, w2)[1], w1, w2)
      innerVertices.append(vs2[1])
      f1 = Face([vs1[0], vs2[0], vs2[1], vs1[1]])
      utils_face.face_copy_properties(face, f1)
      f2 = Face([vs1[1], vs2[1], vs2[2], vs1[2]])
      utils_face.face_copy_properties(face, f2)
      faces.extend([f1, f2])
    fInner = Face(innerVertices)
    utils_face.face_copy_properties(face, fInner)
    faces.append(fInner)
    return faces
def subdivide_face_split_grid(face, nU, nV)

splits a triangle, quad or a rectangle into a regular grid

Expand source code
def subdivide_face_split_grid(face,nU,nV):
    """
    splits a triangle, quad or a rectangle into a regular grid
    """
    if len(face.vertices) > 4:
        print('too many vertices')
        return face

    if len(face.vertices) == 4:
        vsU1 = _vertices_between(face.vertices[0], face.vertices[1], nU)
        vsU2 = _vertices_between(face.vertices[3], face.vertices[2], nU)
        gridVertices = []
        for u in range(len(vsU1)):
            gridVertices.append(_vertices_between(vsU1[u], vsU2[u], nV))
        faces = []
        for u in range(len(vsU1) - 1):
            vs1 = gridVertices[u]
            vs2 = gridVertices[u + 1]
            for v in range(len(vs1) - 1):
                #f = Face([vs1[v], vs1[v + 1], vs2[v + 1], vs2[v]])
                f = Face([vs1[v], vs2[v], vs2[v + 1], vs1[v + 1]])
                utils_face.face_copy_properties(face, f)
                faces.append(f)
        return faces

    if len(face.vertices) == 3:
        vsU1 = _vertices_between(face.vertices[0], face.vertices[1], nU)
        vsU2 = _vertices_between(face.vertices[0], face.vertices[2], nU)
        gridVertices = []
        for u in range(1, len(vsU1)):
            gridVertices.append(_vertices_between(vsU1[u], vsU2[u], nV))
        faces = []
        # triangles
        v0 = face.vertices[0]
        vs1 = gridVertices[0]
        for v in range(len(vs1) - 1):
            f = Face([v0,vs1[v],vs1[v + 1]])
            utils_face.face_copy_properties(face, f)
            faces.append(f)
        for u in range(len(gridVertices) - 1):
            vs1 = gridVertices[u]
            vs2 = gridVertices[u + 1]
            for v in range(len(vs1) - 1):
                f = Face([vs1[v],vs1[v + 1], vs2[v + 1], vs2[v]])
                utils_face.face_copy_properties(face, f)
                faces.append(f)
        return faces
def subdivide_face_split_offset(face, offset)
Expand source code
def subdivide_face_split_offset(face,offset):
    offsets = [offset] * len(face.vertices)
    return subdivide_face_split_offsets(face, offsets)
def subdivide_face_split_offsets(face, offsets)
Expand source code
def subdivide_face_split_offsets(face,offsets):
    offsetFace = subdivide_face_offset_planar(face,offsets)
    nOffsetFaces = 0
    for o in offsets:
        if(abs(o) > 0):
            nOffsetFaces += 1
    faces = []
    for i in range(len(face.vertices)):
        if(abs(offsets[i]) > 0):
            i2 = (i + 1) % len(face.vertices)
            f = Face([face.vertices[i], face.vertices[i2], offsetFace.vertices[i2], offsetFace.vertices[i]])
            utils_face.face_copy_properties(face, f)
            faces.append(f)
    faces.append(offsetFace)
    for f in faces:
        if(utils_face.face_area(f) < 0):
            f.vertices.reverse()
    return faces
def subdivide_face_split_rel(face, direction, split)

Splits face in given direction.

Arguments:

face : mola.core.Face The face to be split direction : integer (-1 or 0) split : float Position of the split relative to initial face points (0 to 1)

Expand source code
def subdivide_face_split_rel(face, direction, split):
    """
    Splits face in given direction.

    Arguments:
    ----------
    face : mola.core.Face
        The face to be split
    direction : integer (-1 or 0)
    split : float
        Position of the split relative to initial face points (0 to 1)
    """
    return subdivide_face_split_rel_multiple(face, direction, [split])
def subdivide_face_split_rel_free_quad(face, indexEdge, split1, split2)

Splits a quad in two new quads through the points specified by relative position along the edge.

Arguments:

face : mola.core.Face The face to be extruded indexEdge : int direction of split, 0: 0->2, 1: 1->3 split1, split2 : float relative position of split on each edge (0..1)

Expand source code
def subdivide_face_split_rel_free_quad(face, indexEdge,  split1,  split2):
    """
    Splits a quad in two new quads through the points specified
    by relative position along the edge.

    Arguments:
    ----------
    face : mola.core.Face
        The face to be extruded
    indexEdge : int
        direction of split, 0: 0->2, 1: 1->3
    split1, split2 : float
        relative position of split on each edge (0..1)
    """
    # only works with quads, therefore return original face if triangular
    if len(face.vertices) != 4:
        return face

    # constrain indexEdge to be either 0 or 1
    indexEdge = indexEdge%2

    indexEdge1 = (indexEdge + 1) % len(face.vertices)
    indexEdge2 = (indexEdge + 2) % len(face.vertices)
    indexEdge3 = (indexEdge + 3) % len(face.vertices)
    p1 = utils_vertex.vertex_between_rel(face.vertices[indexEdge], face.vertices[indexEdge1], split1)
    p2 = utils_vertex.vertex_between_rel(face.vertices[indexEdge2 ], face.vertices[indexEdge3], split2)
    faces = []
    if indexEdge == 0:
        f1 = Face([face.vertices[0], p1, p2, face.vertices[3]])
        f2 = Face([p1, face.vertices[1], face.vertices[2], p2])
        utils_face.face_copy_properties(face, f1)
        utils_face.face_copy_properties(face, f2)
        faces.extend([f1, f2])
    elif indexEdge == 1:
        f1 = Face([face.vertices[0], face.vertices[1], p1, p2])
        f2 = Face([p2, p1, face.vertices[2], face.vertices[3]])
        utils_face.face_copy_properties(face,f1)
        utils_face.face_copy_properties(face,f2)
        faces.extend([f1, f2])
    return faces
def subdivide_face_split_rel_multiple(face, direction, splits)
Expand source code
def subdivide_face_split_rel_multiple(face, direction, splits):
    sA = []
    sA.append(face.vertices[direction])
    lA = face.vertices[direction + 1]
    sB = []
    sB.append(face.vertices[direction + 3])
    lB = face.vertices[(direction + 2) % len(face.vertices)]

    for i in range(len(splits)):
        sA.append(utils_vertex.vertex_between_rel(sA[0], lA,splits[i]))
        sB.append(utils_vertex.vertex_between_rel(sB[0], lB,splits[i]))
    sA.append(lA)
    sB.append(lB)

    result = []
    for i in range(len(splits) + 1):
        if(dir == 1):
            f = Face([sB[i], sA[i], sA[i+1], sB[i+1]])
            utils_face.face_copy_properties(face, f)
            result.append(f)
        else:
            f = Face([sB[i], sB[i+1], sA[i+1], sA[i]])
            utils_face.face_copy_properties(face, f)
            result.append(f)
    return result
def subdivide_face_split_roof(face, height)

Extrudes a pitched roof

Arguments:

face : mola.core.Face The face to be extruded height : mola.core.Vertex Th height of the roof

Expand source code
def subdivide_face_split_roof(face, height):
    """
    Extrudes a pitched roof

    Arguments:
    ----------
    face : mola.core.Face
        The face to be extruded
    height : mola.core.Vertex
        Th height of the roof
    """
    faces = []
    normal = utils_face.face_normal(face)
    normal = utils_vertex.vertex_scale(normal,height)
    if len(face.vertices) == 4:
        ev1 = utils_vertex.vertex_center(face.vertices[0], face.vertices[1])
        ev1 = utils_vertex.vertex_add(ev1, normal)
        ev2 = utils_vertex.vertex_center(face.vertices[2], face.vertices[3])
        ev2 = utils_vertex.vertex_add(ev2, normal)

        faces.append(Face([face.vertices[0], face.vertices[1], ev1]))
        faces.append(Face([face.vertices[1], face.vertices[2], ev2, ev1]))
        faces.append(Face([face.vertices[2], face.vertices[3], ev2]))
        faces.append(Face([face.vertices[3], face.vertices[0], ev1, ev2]))

        for f in faces:
            utils_face.face_copy_properties(face,f)
        return faces

    elif len(face.vertices) == 3:
        ev1 = utils_vertex.vertex_center(face.vertices[0], face.vertices[1])
        ev1 = utils_vertex.vertex_add(ev1, normal)
        ev2 = utils_vertex.vertex_center(face.vertices[1], face.vertices[2])
        ev2 = utils_vertex.vertex_add(ev2, normal)

        faces.append(Face([face.vertices[0], face.vertices[1], ev1]))
        faces.append(Face([face.vertices[1], ev2, ev1]))
        faces.append(Face([face.vertices[1], face.vertices[2], ev2]))
        faces.append(Face([face.vertices[2], face.vertices[0], ev1, ev2]))

        for f in faces:
            utils_face.face_copy_properties(face, f)
        return faces
    return [face]
def subdivide_mesh(mesh, values=[])
Expand source code
def subdivide_mesh(mesh,values=[]):
    for face in mesh.faces:
        face.vertex=utils_face.center(face)
    for edge in mesh.edges:
        edge.vertex = edge.center()
    for vertex in mesh.vertices:
        vertex.vertex = Vertex(vertex.x,vertex.y,vertex.z)
    if len(values)>0:
        _translate_face_vertices(mesh,values)
    return _collect_new_faces(mesh)
def subdivide_mesh_catmull(mesh, values=[])
Expand source code
def subdivide_mesh_catmull(mesh, values=[]):
    _catmullVertices(mesh)
    if len(values)>0:
        _translate_face_vertices(mesh,values)
    return _collect_new_faces(mesh)
def subdivide_mesh_extrude_tapered(mesh, heights, fractions, doCaps)
Expand source code
def subdivide_mesh_extrude_tapered(mesh,heights,fractions,doCaps):
    new_mesh = Mesh()
    for face,height,fraction,doCap in zip(mesh.faces,heights,fractions,doCaps):
        new_mesh.faces.extend(subdivide_face_extrude_tapered(face,height,fraction,doCap))
    new_mesh.update_topology()
    return new_mesh
def subdivide_mesh_extrude_to_point_center(mesh, heights, doExtrudes)
Expand source code
def subdivide_mesh_extrude_to_point_center(mesh,heights,doExtrudes):
    new_mesh = Mesh()
    for face,height,doExtrude in zip(mesh.faces,heights,doExtrudes):
        if doExtrude:
            new_mesh.faces.extend(subdivide_face_extrude_to_point_center(face,height))
        else:
            new_mesh.faces.append(face)
    new_mesh.update_topology()
    return new_mesh
def triangle_area(v1, v2, v3)

Returns the area of the triangle from 3 vertices

Arguments:

v1, v2, v3 : mola.Vertex vertices of the triangle

Expand source code
def triangle_area(v1,v2,v3):
    """
    Returns the area of the triangle from 3 vertices

    Arguments:
    ----------
    v1, v2, v3 : mola.Vertex
        vertices of the triangle
    """
    return triangle_coords_area(v1.x, v1.y, v1.z, v2.x, v2.y, v2.z, v3.x, v3.y, v3.z)
def triangle_coords_area(xa, ya, za, xb, yb, zb, xc, yc, zc)

Returns the area of the triangle from 9 coordinates

Arguments:

xa, ya, za : float coordinates of vertex a xb, yb, zb : float coordinates of vertex b xc, yc, zc : float coordinates of vertex c

Expand source code
def triangle_coords_area(xa, ya, za, xb, yb, zb, xc, yc, zc):
    """
    Returns the area of the triangle from 9 coordinates

    Arguments:
    ----------
    xa, ya, za : float
        coordinates of vertex a
    xb, yb, zb : float
        coordinates of vertex b
    xc, yc, zc : float
        coordinates of vertex c
    """
    return 0.5 * math.sqrt(math.pow(utils_math.math_determinant(xa, xb, xc, ya, yb, yc, 1, 1, 1), 2) + math.pow(utils_math.math_determinant(ya, yb, yc, za, zb, zc, 1, 1, 1), 2) + math.pow(utils_math.math_determinant(za, zb, zc, xa, xb, xc, 1, 1, 1), 2))
def triangle_normal(v1, v2, v3)

Returns the normal of a triangle defined by 3 vertices. The normal is a vector of length 1 perpendicular to the plane of the triangle.

Arguments:

v1, v2, v3 : mola.Vertex the vertices get the normal from

Expand source code
def triangle_normal(v1,v2,v3):
    """
    Returns the normal of a triangle defined by 3 vertices.
    The normal is a vector of length 1 perpendicular to the plane of the triangle.

    Arguments:
    ----------
    v1, v2, v3 : mola.Vertex
        the vertices get the normal from
    """
    v = v2-v1
    u = v3-v1
    crossProduct=vertex_cross(v, u)
    return vertex_unitize(crossProduct)
def vertex_add(v1, v2)

adds the position vector of v2 to the position vector of v1 and returns the result as a new Vertex.

Expand source code
def vertex_add(v1,v2):
    """
    adds the position vector of v2 to the position vector of v1
    and returns the result as a new Vertex.
    """
    return Vertex(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z)
def vertex_angle(v1, v2)
Expand source code
def vertex_angle(v1,v2):
    a = vertex_unitize(v1)
    b = vertex_unitize(v2)
    f = vertex_dot(a, b)
    f = min(1, max(-1, f))
    return math.acos(f)
def vertex_angle_triangle(vPrevious, v, vNext)
Expand source code
def vertex_angle_triangle(vPrevious,v,vNext):
    #law of cosines
    vvn = vertex_distance(v, vNext)
    vvp = vertex_distance(vPrevious, v)
    vnvp = vertex_distance(vNext, vPrevious)
    return math.acos((vvn * vvn + vvp * vvp - vnvp * vnvp) / (2 * vvn * vvp))
def vertex_between_abs(v1, v2, dis)

finds a position vector between v1 and v2 by an absolute distance value from v1 and returns the result as a new Vertex.

Expand source code
def vertex_between_abs(v1, v2, dis):
    """
    finds a position vector between v1 and v2 by an absolute distance value from v1
    and returns the result as a new Vertex.
    """
    d = vertex_distance(v1,v2)
    return vertex_between_rel(v1, v2, dis / d)
def vertex_between_rel(v1, v2, factor)

finds a position vector between v1 and v2 by a factor (0.0 to 1.0 corresponds to v1 to v2) and returns the result as a new Vertex.

Expand source code
def vertex_between_rel(v1, v2, factor):
    """
    finds a position vector between v1 and v2 by a factor (0.0 to 1.0 corresponds to v1 to v2)
    and returns the result as a new Vertex.
    """
    return Vertex((v2.x - v1.x) * factor + v1.x, (v2.y - v1.y) * factor + v1.y, (v2.z - v1.z) * factor + v1.z)
def vertex_center(v1, v2)

Returns the center of a line defined by two vertices.

Arguments:

v1, v2 : mola.Vertex start and end points of the line

Returns:

mola.Vertex the center point of the line

Expand source code
def vertex_center(v1,v2):
    """
    Returns the center of a line defined by two vertices.

    Arguments:
    ----------
    v1, v2 : mola.Vertex
        start and end points of the line

    Returns:
    --------
    mola.Vertex
        the center point of the line
    """

    return Vertex((v1.x+v2.x)/2,(v1.y+v2.y)/2,(v1.z+v2.z)/2)
def vertex_cross(v1, v2)

returns the cross product of v1 and v2 as a new Vertex.

Expand source code
def vertex_cross(v1,v2):
    """
    returns the cross product of v1 and v2 as a new Vertex.
    """
    return Vertex(v1.y * v2.z - v2.y * v1.z, v1.z * v2.x - v2.z * v1.x, v1.x * v2.y - v2.x * v1.y)
def vertex_distance(v1, v2)

returns the distance between v1 and v2.

Expand source code
def vertex_distance(v1,v2):
    """
    returns the distance between v1 and v2.
    """
    dX = v2.x - v1.x
    dY = v2.y - v1.y
    dZ = v2.z - v1.z
    return math.sqrt(dX*dX+dY*dY+dZ*dZ)
def vertex_divide(v, factor)

scales the position vector of a Vertex by a factor (division) and returns the result as a new Vertex.

Expand source code
def vertex_divide(v,factor):
    """
    scales the position vector of a Vertex by a factor (division)
    and returns the result as a new Vertex.
    """
    return Vertex(v.x / factor, v.y / factor, v.z / factor)
def vertex_dot(v1, v2)

returns the dot product of v1 and v2.

Expand source code
def vertex_dot(v1,v2):
    """
    returns the dot product of v1 and v2.
    """
    return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z
def vertex_length(v)

returns the length of the position vector of a Vertex, the distance from the origin (0,0,0).

Expand source code
def vertex_length(v):
    """
    returns the length of the position vector of a Vertex,
    the distance from the origin (0,0,0).
    """
    return math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z)
def vertex_line_line_intersection(a, b, c, d)

Returns the intersection of two lines in 2D as a new Vertex.

Arguments:

a,b,c,d: mola.Vertex a,b are the endpoints of line1 c,d are the endpoints of line2

Expand source code
def vertex_line_line_intersection(a,b,c,d):
    """
    Returns the intersection of two lines in 2D as a new Vertex.

    Arguments:
    ----------
    a,b,c,d: mola.Vertex
             a,b are the endpoints of line1
             c,d are the endpoints of line2
    """
    deltaABX = b.x - a.x
    deltaABY = b.y - a.y
    deltaDCX = d.x - c.x
    deltaDCY = d.y - c.y
    denominator = deltaABX * deltaDCY - deltaABY * deltaDCX
    if denominator == 0:
        return None
    numerator = (a.y - c.y) * deltaDCX - (a.x - c.x) * deltaDCY
    r = numerator / denominator
    x = a.x + r * deltaABX
    y = a.y + r * deltaABY
    return Vertex(x,y,0)
def vertex_offset_line(v1, v2, offset)
Expand source code
def vertex_offset_line(v1, v2, offset):
    v = vertex_subtract(v2, v1)
    v = vertex_unitize(v)
    v = vertex_scale(v,offset)
    t = v.x
    v.x = -v.y
    v.y = t
    v.z = 0
    return Vertex(vertex_add(v1, v), vertex_add(v2, v))
def vertex_offset_point(v1, v2, v3, offset1, offset2)
Expand source code
def vertex_offset_point(v1, v2, v3, offset1, offset2):
    line1 = vertex_offset_line(v1, v2, offset1)
    line2 = vertex_offset_line(v2, v3, offset2)
    return vertex_line_line_intersection(line1.x,line1.y,line2.x,line2.y)
def vertex_rotate_2D_90(vertex)
Expand source code
def vertex_rotate_2D_90(vertex):
    return Vertex(-vertex.y, vertex.x, vertex.z)
def vertex_scale(v, factor)

scales the position vector of a Vertex by a factor (multiplication) and returns the result as a new Vertex.

Expand source code
def vertex_scale(v,factor):
    """
    scales the position vector of a Vertex by a factor (multiplication)
    and returns the result as a new Vertex.
    """
    return Vertex(v.x * factor, v.y * factor, v.z * factor)
def vertex_subtract(v1, v2)

subtracts the position vector of v2 from the position vector of v1 and returns the result as a new Vertex.

Expand source code
def vertex_subtract(v1,v2):
    """
    subtracts the position vector of v2 from the position vector of v1
    and returns the result as a new Vertex.
    """
    return Vertex(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z)
def vertex_unitize(v)

returns a Vertex of the same direction and of unit length 1

Expand source code
def vertex_unitize(v):
    """
    returns a Vertex of the same direction
    and of unit length 1
    """
    l = vertex_length(v)
    if l == 0:
        return v
    return vertex_scale(v,1/l)
def vertices_list_area(vertices)

Returns the area of a face from a list of 3 or 4 vertices

Expand source code
def vertices_list_area(vertices):
    """
    Returns the area of a face from a list of 3 or 4 vertices
    """
    if len(vertices) == 3:
        return triangle_area(vertices[0],vertices[1],vertices[2])
    # could be made generic for n-gons, triangle fan?
    elif len(vertices) == 4:
        a1 = triangle_area(vertices[0], vertices[1], vertices[2])
        a2 = triangle_area(vertices[2], vertices[3], vertices[0])
        return a1 + a2
def vertices_list_center(vertices)

Returns the center point (type Vertex) of a list of vertices. Note: not the center of gravity, just the average of the vertices.

Arguments:

vertices : list of mola.Vertex The list of vertices to be measured

Expand source code
def vertices_list_center(vertices):
    """
    Returns the center point (type Vertex) of a list of vertices.
    Note: not the center of gravity, just the average of the vertices.

    Arguments:
    ----------
    vertices : list of mola.Vertex
            The list of vertices to be measured
    """
    n = len(vertices)
    cx = sum([v.x for v in vertices]) / n
    cy = sum([v.y for v in vertices]) / n
    cz = sum([v.z for v in vertices]) / n
    return Vertex(cx,cy,cz)
def vertices_list_normal(vertices)

Returns the normal of a triangle defined by 3 vertices. The normal is a vector of length 1 perpendicular to the plane of the triangle.

Arguments:

vertices : list the list of vertices get the normal from (first 3 will be used)

Expand source code
def vertices_list_normal(vertices):
    """
    Returns the normal of a triangle defined by 3 vertices.
    The normal is a vector of length 1 perpendicular to the plane of the triangle.

    Arguments:
    ----------
    vertices : list
        the list of vertices get the normal from (first 3 will be used)
    """
    return normalFromTriangle(vertices[0], vertices[1], vertices[2])
def weldVertices(edges)
Expand source code
def weldVertices(edges):
    dictVertices={}
    for edge in edges:
        tuple=(edge.v1.x,edge.v1.y)
        if tuple in dictVertices:
            edge.v1=dictVertices[tuple]
        else:
            dictVertices[tuple]=edge.v1
        edge.v1.edges.append(edge)

        tuple=(edge.v2.x,edge.v2.y)
        if tuple in dictVertices:
            edge.v2=dictVertices[tuple]
        else:
            dictVertices[tuple]=edge.v2
        edge.v2.edges.append(edge)

Classes

class Box (x1=inf, y1=inf, z1=inf, x2=-inf, y2=-inf, z2=-inf)

A Box is defined by by two opposite corners with x,y,z coordinates. Mostly used for getting the bounding box of a set of points.

Attributes

x1, y1, z1 : float
The coordinates of the bottom left front corner.
x2, y2, z2 : float
The coordinates of the top right back corner.
Expand source code
class Box:
    """A `Box` is defined by by two opposite corners with x,y,z coordinates.
    Mostly used for getting the bounding box of a set of points.

    Attributes
    ----------
    x1, y1, z1 : float
        The coordinates of the bottom left front corner.
    x2, y2, z2 : float
        The coordinates of the top right back corner.
    """
    def __init__(self, x1=float('inf'), y1=float('inf'), z1=float('inf'), x2=-float('inf'), y2=-float('inf'), z2=-float('inf')):
        self.x1 = x1
        self.y1 = y1
        self.z1 = z1
        self.x2 = x2
        self.y2 = y2
        self.z2 = z2

    def dim_x(self):
        """
        Returns the Box's extent in X direction.
        """
        return self.x2 - self.x1

    def dim_y(self):
        """
        Returns the Box's extent in Y direction.
        """
        return self.y2 - self.y1

    def dim_z(self):
        """
        Returns the Box's extent in Z direction.
        """
        return self.z2 - self.z1

    def center(self):
        """
        returns the Box's center as a Vertex() object
        """
        return Vertex((self.x2+self.x1)/2.0,(self.y2+self.y1)/2.0,(self.z2+self.z1)/2.0)

    def add_point(self,x,y,z):
        """
        adds a point to the bounding box,
        increases the box's size if the point is outside.
        """
        self.x1 = min(x,self.x1)
        self.y1 = min(y,self.y1)
        self.z1 = min(z,self.z1)
        self.x2 = max(x,self.x2)
        self.y2 = max(y,self.y2)
        self.z2 = max(z,self.z2)

Methods

def add_point(self, x, y, z)

adds a point to the bounding box, increases the box's size if the point is outside.

Expand source code
def add_point(self,x,y,z):
    """
    adds a point to the bounding box,
    increases the box's size if the point is outside.
    """
    self.x1 = min(x,self.x1)
    self.y1 = min(y,self.y1)
    self.z1 = min(z,self.z1)
    self.x2 = max(x,self.x2)
    self.y2 = max(y,self.y2)
    self.z2 = max(z,self.z2)
def center(self)

returns the Box's center as a Vertex() object

Expand source code
def center(self):
    """
    returns the Box's center as a Vertex() object
    """
    return Vertex((self.x2+self.x1)/2.0,(self.y2+self.y1)/2.0,(self.z2+self.z1)/2.0)
def dim_x(self)

Returns the Box's extent in X direction.

Expand source code
def dim_x(self):
    """
    Returns the Box's extent in X direction.
    """
    return self.x2 - self.x1
def dim_y(self)

Returns the Box's extent in Y direction.

Expand source code
def dim_y(self):
    """
    Returns the Box's extent in Y direction.
    """
    return self.y2 - self.y1
def dim_z(self)

Returns the Box's extent in Z direction.

Expand source code
def dim_z(self):
    """
    Returns the Box's extent in Z direction.
    """
    return self.z2 - self.z1
class Edge (v1, v2)
Expand source code
class Edge:
    def __init__(self, v1, v2):
        self.v1 = v1
        self.v2 = v2
        self.face1 = None
        self.face2 = None

    def __str__(self):
        return "from " + str(self.v1)+" to "+ str(self.v2)

    def center(self):
        """
        returns the midpoint on an edge as a Vertex() object
        """
        return Vertex((self.v2.x+self.v1.x)/2.0,(self.v2.y+self.v1.y)/2.0,(self.v2.z+self.v1.z)/2.0)

    def other_vertex(self,vertex):
        """
        if `vertex` is one of the end points of this edge,
        it returns the Vertex at the other end point.
        """
        if self.v1 is vertex:
            return self.v2
        if self.v2 is vertex:
            return self.v1
        return None

Methods

def center(self)

returns the midpoint on an edge as a Vertex() object

Expand source code
def center(self):
    """
    returns the midpoint on an edge as a Vertex() object
    """
    return Vertex((self.v2.x+self.v1.x)/2.0,(self.v2.y+self.v1.y)/2.0,(self.v2.z+self.v1.z)/2.0)
def other_vertex(self, vertex)

if vertex is one of the end points of this edge, it returns the Vertex at the other end point.

Expand source code
def other_vertex(self,vertex):
    """
    if `vertex` is one of the end points of this edge,
    it returns the Vertex at the other end point.
    """
    if self.v1 is vertex:
        return self.v2
    if self.v2 is vertex:
        return self.v1
    return None
class Face (vertices=None)

A Face is the surface between a set of vertices.

Attributes

vertices : list
A list of Vertex objects defining the Face.
color : tuple (r, g, b, a)
The color of the face (0..1).
group : integer
The group index the Face belongs to.
Expand source code
class Face:
    """A `Face` is the surface between a set of vertices.

    Attributes
    ----------
    vertices : list
        A list of `Vertex` objects defining the `Face`.
    color : tuple (r, g, b, a)
        The color of the face (0..1).
    group : integer
        The group index the `Face` belongs to.
    """

    def __init__(self, vertices=None):
        if (vertices == None):
            self.vertices = []
        else:
            self.vertices = vertices
        self.color = (1,1,1,1)
        self.group = 0

    def area(self):
        """
        Returns the area of the face.
        """
        if(len(self.vertices) == 3):
            return utils_vertex.triangle_area(self.vertices[0], self.vertices[1], self.vertices[2])
        else:
            return utils_vertex.triangle_area(self.vertices[0], self.vertices[1], self.vertices[2]) + utils_vertex.triangle_area(self.vertices[2], self.vertices[3], self.vertices[0])

    def perimeter(self):
        """
        Returns the perimeter of the face as the sum of all the edges' lengths.
        """
        sum = 0
        for i in range(len(self.vertices)):
            v1 = self.vertices[i]
            v2 = self.vertices[(i + 1) % len(self.vertices)]
            sum += utils_vertex.vertex_distance(v1,v2)
        return sum

    def compactness(self):
        """
        Returns the compactness of the face as the ratio between area and perimeter.
        """
        return self.area() / self.perimeter()

    def angle_horizontal(self):
        """
        Returns the azimuth, the orientation of the face around the z-axis in the XY-plane
        """
        n = self.normal()
        return math.atan2(n.y, n.x)

    def angle_vertical(self):
        """
        Returns the altitude, 0 if the face is vertical, -Pi/2 if it faces downwards, +Pi/2 if it faces upwards.
        """
        n = self.normal()
        #nXY = Vertex(n.x, n.y, 0.0)
        #return vecUtils.angle(n, nXY)
        # alternative, probably less computationally intense:
        return math.asin(n.z)

    def curvature(self):
        """
        Returns the local curvature of a mesh face, by measuring the angle to the neighbour faces.
        """
        facenormal = self.normal()
        sumD = 0
        vPrev = self.vertices[-1]
        num_faces = 1
        for v in self.vertices:
            edge = v.edge_adjacent_to_vertex(vPrev)
            if edge != None:
                nbFace = edge.face1
                if edge.face1 == self:
                    nbFace = edge.face2
                if nbFace != None:
                    num_faces += 1
                    nbNormal = utils_face.face_normal(nbFace)
                    sumD += utils_vertex.vertex_distance(nbNormal,facenormal)
            vPrev = v
        return sumD / num_faces

    def center(self):
        """
        Returns the center point (type Vertex) of the face.
        Note: not the center of gravity, just the average of its vertices.
        """
        return utils_vertex.vertices_list_center(self.vertices)

    def normal(self):
        """
        Returns the normal of the face, a vector of length 1 perpendicular to the plane of the triangle.
        """
        return utils_vertex.triangle_normal(self.vertices[0], self.vertices[1], self.vertices[2])

Methods

def angle_horizontal(self)

Returns the azimuth, the orientation of the face around the z-axis in the XY-plane

Expand source code
def angle_horizontal(self):
    """
    Returns the azimuth, the orientation of the face around the z-axis in the XY-plane
    """
    n = self.normal()
    return math.atan2(n.y, n.x)
def angle_vertical(self)

Returns the altitude, 0 if the face is vertical, -Pi/2 if it faces downwards, +Pi/2 if it faces upwards.

Expand source code
def angle_vertical(self):
    """
    Returns the altitude, 0 if the face is vertical, -Pi/2 if it faces downwards, +Pi/2 if it faces upwards.
    """
    n = self.normal()
    #nXY = Vertex(n.x, n.y, 0.0)
    #return vecUtils.angle(n, nXY)
    # alternative, probably less computationally intense:
    return math.asin(n.z)
def area(self)

Returns the area of the face.

Expand source code
def area(self):
    """
    Returns the area of the face.
    """
    if(len(self.vertices) == 3):
        return utils_vertex.triangle_area(self.vertices[0], self.vertices[1], self.vertices[2])
    else:
        return utils_vertex.triangle_area(self.vertices[0], self.vertices[1], self.vertices[2]) + utils_vertex.triangle_area(self.vertices[2], self.vertices[3], self.vertices[0])
def center(self)

Returns the center point (type Vertex) of the face. Note: not the center of gravity, just the average of its vertices.

Expand source code
def center(self):
    """
    Returns the center point (type Vertex) of the face.
    Note: not the center of gravity, just the average of its vertices.
    """
    return utils_vertex.vertices_list_center(self.vertices)
def compactness(self)

Returns the compactness of the face as the ratio between area and perimeter.

Expand source code
def compactness(self):
    """
    Returns the compactness of the face as the ratio between area and perimeter.
    """
    return self.area() / self.perimeter()
def curvature(self)

Returns the local curvature of a mesh face, by measuring the angle to the neighbour faces.

Expand source code
def curvature(self):
    """
    Returns the local curvature of a mesh face, by measuring the angle to the neighbour faces.
    """
    facenormal = self.normal()
    sumD = 0
    vPrev = self.vertices[-1]
    num_faces = 1
    for v in self.vertices:
        edge = v.edge_adjacent_to_vertex(vPrev)
        if edge != None:
            nbFace = edge.face1
            if edge.face1 == self:
                nbFace = edge.face2
            if nbFace != None:
                num_faces += 1
                nbNormal = utils_face.face_normal(nbFace)
                sumD += utils_vertex.vertex_distance(nbNormal,facenormal)
        vPrev = v
    return sumD / num_faces
def normal(self)

Returns the normal of the face, a vector of length 1 perpendicular to the plane of the triangle.

Expand source code
def normal(self):
    """
    Returns the normal of the face, a vector of length 1 perpendicular to the plane of the triangle.
    """
    return utils_vertex.triangle_normal(self.vertices[0], self.vertices[1], self.vertices[2])
def perimeter(self)

Returns the perimeter of the face as the sum of all the edges' lengths.

Expand source code
def perimeter(self):
    """
    Returns the perimeter of the face as the sum of all the edges' lengths.
    """
    sum = 0
    for i in range(len(self.vertices)):
        v1 = self.vertices[i]
        v2 = self.vertices[(i + 1) % len(self.vertices)]
        sum += utils_vertex.vertex_distance(v1,v2)
    return sum
class Graph (neighbours, gm=None)

basic graph class. edge-weighted graphs should implement different weightFunction

Expand source code
class Graph:
    ''' basic graph class. edge-weighted graphs should implement different weightFunction'''
    def __init__(self, neighbours, gm=None):
        self.neighbours = neighbours
        self.weight_function = lambda a, b : 1

    def get_neighbours(self, u):
        return self.neighbours[u]

    def size(self):
        return len(self.neighbours)

    def weight(self, index1, index2):
        return self.weight_function(index1, index2)

    @classmethod
    def from_grid_2d(cls, nx, ny, nbs8=False, continuous=False):
        gm = GridManager(nx,ny)
        neighbours = [0] * gm.length
        for i in range(gm.length):
            neighbours[i] = gm.get_neighbors_2d(i, nbs8, continuous)
        return cls(neighbours)

    @classmethod
    def from_hex_grid_2d(cls, nx, ny,continuous=False):
        gm = GridManager(nx, ny)
        neighbours = [0] * gm.length
        for i in range(gm.length):
            neighbours[i] = gm.get_neighbors_hex_2d(i, continuous)
        return cls(neighbours)

    @classmethod
    def from_grid_3d(cls, nx, ny, nz, mode=3, continuous=False):
        gm = GridManager(nx, ny, nz)
        neighbours = [0] * gm.length
        for i in range(gm.length):
            neighbours[i] = gm.get_neighbors_3d(i, mode, continuous)
        return cls(neighbours)

    @classmethod
    def from_mesh_faces(cls, mesh):
        faceIds = {}
        neighbours = [0] * len(mesh.faces)
        for index, face in enumerate(mesh.faces):
            faceIds[face] = index
        for index, face in enumerate(mesh.faces):
            nbs = []
            v0 = face.vertices[-1]
            for v1 in face.vertices:
                nbFace = mesh.getFaceAdjacentToVertices(v1, v0)
                nbs.append(faceIds[nbFace])
                v0 = v1
            neighbours[index] = nbs
        return cls(neighbours)

    def from_mesh_edges(self,mesh):
        pass

    def from_mesh_vertices(self,mesh):
        pass

Static methods

def from_grid_2d(nx, ny, nbs8=False, continuous=False)
Expand source code
@classmethod
def from_grid_2d(cls, nx, ny, nbs8=False, continuous=False):
    gm = GridManager(nx,ny)
    neighbours = [0] * gm.length
    for i in range(gm.length):
        neighbours[i] = gm.get_neighbors_2d(i, nbs8, continuous)
    return cls(neighbours)
def from_grid_3d(nx, ny, nz, mode=3, continuous=False)
Expand source code
@classmethod
def from_grid_3d(cls, nx, ny, nz, mode=3, continuous=False):
    gm = GridManager(nx, ny, nz)
    neighbours = [0] * gm.length
    for i in range(gm.length):
        neighbours[i] = gm.get_neighbors_3d(i, mode, continuous)
    return cls(neighbours)
def from_hex_grid_2d(nx, ny, continuous=False)
Expand source code
@classmethod
def from_hex_grid_2d(cls, nx, ny,continuous=False):
    gm = GridManager(nx, ny)
    neighbours = [0] * gm.length
    for i in range(gm.length):
        neighbours[i] = gm.get_neighbors_hex_2d(i, continuous)
    return cls(neighbours)
def from_mesh_faces(mesh)
Expand source code
@classmethod
def from_mesh_faces(cls, mesh):
    faceIds = {}
    neighbours = [0] * len(mesh.faces)
    for index, face in enumerate(mesh.faces):
        faceIds[face] = index
    for index, face in enumerate(mesh.faces):
        nbs = []
        v0 = face.vertices[-1]
        for v1 in face.vertices:
            nbFace = mesh.getFaceAdjacentToVertices(v1, v0)
            nbs.append(faceIds[nbFace])
            v0 = v1
        neighbours[index] = nbs
    return cls(neighbours)

Methods

def from_mesh_edges(self, mesh)
Expand source code
def from_mesh_edges(self,mesh):
    pass
def from_mesh_vertices(self, mesh)
Expand source code
def from_mesh_vertices(self,mesh):
    pass
def get_neighbours(self, u)
Expand source code
def get_neighbours(self, u):
    return self.neighbours[u]
def size(self)
Expand source code
def size(self):
    return len(self.neighbours)
def weight(self, index1, index2)
Expand source code
def weight(self, index1, index2):
    return self.weight_function(index1, index2)
class GraphAnalyser (graph)

works with graphs which provide 3 methods: size(), getNeighbours(), and weight() this class stores all distances in order to allow a fast calculation of path to predefined starting points usage: construct a Graphanalyser 1. compute distance to a list of starting points 2. getShortest Path from end point to those starting point

Expand source code
class GraphAnalyser:
    """
    works with graphs which provide 3 methods: size(), getNeighbours(), and weight()
    this class stores all distances in order to allow a fast calculation of path to predefined starting points
    usage: construct a Graphanalyser
    1. compute distance to a list of starting points
    2. getShortest Path from end point to those starting point
    """
    def __init__(self,graph):
        self.n = graph.size()
        self.graph = graph
        self.dist = [1000000] * self.n
        self.pred = [-1] * self.n

    def compute_distance_to_nodes(self,startIndexes):
        pq = PriorityQueue()
        for i in startIndexes:
            self.dist[i] = 0
            pq.put((0,i))
        while not pq.empty():
            u = pq.get()[1]
            nbs = self.graph.get_neighbours(u)
            for v in nbs:
                d = self.dist[u] + self.graph.weight(u,v)
                if d < self.dist[v]:
                    self.dist[v] = d
                    self.pred[v] = u
                    pq.put((d, v))

    def shortest_path(self,v):
        p = []
        while v != -1:
            p.append(v)
            v = self.pred[v]
        return p

    def compute_traffic_and_centrality(self,nodes):
        n = self.n
        self.traffic = [0] * n
        self.centrality = [0] * n
        for i in range(len(nodes) - 1):
            startI = nodes[i]
            self.dist = [100000] * n
            self.pred = [-1] * n
            self.compute_distance_to_nodes([startI])
            for j in range(i,len(nodes)):
                endI = nodes[j]
                if endI != startI:
                    self.centrality[startI] += self.dist[endI]
                    self.centrality[endI] += self.dist[endI]
                    path = self.shortest_path(endI)
                    for ii in path:
                        cI = path[ii]
                        self.traffic[cI] += 1

Methods

def compute_distance_to_nodes(self, startIndexes)
Expand source code
def compute_distance_to_nodes(self,startIndexes):
    pq = PriorityQueue()
    for i in startIndexes:
        self.dist[i] = 0
        pq.put((0,i))
    while not pq.empty():
        u = pq.get()[1]
        nbs = self.graph.get_neighbours(u)
        for v in nbs:
            d = self.dist[u] + self.graph.weight(u,v)
            if d < self.dist[v]:
                self.dist[v] = d
                self.pred[v] = u
                pq.put((d, v))
def compute_traffic_and_centrality(self, nodes)
Expand source code
def compute_traffic_and_centrality(self,nodes):
    n = self.n
    self.traffic = [0] * n
    self.centrality = [0] * n
    for i in range(len(nodes) - 1):
        startI = nodes[i]
        self.dist = [100000] * n
        self.pred = [-1] * n
        self.compute_distance_to_nodes([startI])
        for j in range(i,len(nodes)):
            endI = nodes[j]
            if endI != startI:
                self.centrality[startI] += self.dist[endI]
                self.centrality[endI] += self.dist[endI]
                path = self.shortest_path(endI)
                for ii in path:
                    cI = path[ii]
                    self.traffic[cI] += 1
def shortest_path(self, v)
Expand source code
def shortest_path(self,v):
    p = []
    while v != -1:
        p.append(v)
        v = self.pred[v]
    return p
class Grid (nx, ny, nz=1, values=None, scale_to_canvas=False)

A GridManager is taking care of getting and setting values and retrieving neighbors in an orthogonal grid of either 2 or 3 dimension.

Attributes

nx, ny, nz : int
The number of elements in x,y and z direction.
Expand source code
class Grid(GridManager):
    def __init__(self, nx, ny, nz=1, values=None, scale_to_canvas=False):
        super().__init__(nx, ny, nz)
        # self.nx = nx
        # self.ny = ny
        # self.nz = nz
        # self.nyz = ny * nz
        self.scale_to_canvas = scale_to_canvas;
        if values is None:
            self.values = [0] * nx * ny * nz
        else:
            self.values = values

    def set_value_at_xyz(self, value, x, y, z=0):
        self.values[self.get_index(x, y, z)] = value

    def get_value_at_xyz(self, x, y, z=0):
        return self.values[self.get_index(x, y, z)]

    def set_value_at_index(self, value, index):
        self.values[index] = value

    def get_value_at_index(self, index):
        return self.values[index]

    def shortest_path(self, startindex, endindex, obstaclevalue):
        # TODO
        return []

    def quad_mesh(self, functionIn, functionOut):
        faces = []
        for x in range(self.nx):
            for y in range(self.ny):
                for z in range(self.nz):
                    index=self.get_index(x,y,z)
                    if functionIn(self.values[index]):
                        # (x,y) (x1,y) (x1,y1) (x,y1)
                        if x == self.nx - 1 or functionOut(self.get_value_at_xyz(x + 1, y, z)):
                            v1 = Vertex(x + 1, y, z)
                            v2 = Vertex(x + 1, y + 1, z)
                            v3 = Vertex(x + 1, y + 1, z + 1)
                            v4 = Vertex(x + 1, y, z + 1)
                            faces.append(Face([v1, v2, v3, v4]))
                        if x == 0 or functionOut(self.get_value_at_xyz(x-1,y,z)):
                            v1 = Vertex(x, y + 1, z)
                            v2 = Vertex(x, y, z)
                            v3 = Vertex(x, y, z + 1)
                            v4 = Vertex(x, y + 1, z + 1)
                            faces.append(Face([v1, v2, v3, v4]))
                        if y == self.ny - 1 or functionOut(self.get_value_at_xyz(x, y + 1, z)):
                            v1 = Vertex(x + 1, y + 1, z)
                            v2 = Vertex(x, y + 1, z)
                            v3 = Vertex(x, y + 1, z + 1)
                            v4 = Vertex(x + 1, y + 1, z + 1)
                            faces.append(Face([v1, v2, v3, v4]))
                        if y == 0 or functionOut(self.get_value_at_xyz(x, y - 1, z)):
                            v1 = Vertex(x, y, z)
                            v2 = Vertex(x + 1, y, z)
                            v3 = Vertex(x + 1, y, z + 1)
                            v4 = Vertex(x, y, z + 1)
                            faces.append(Face([v1, v2, v3, v4]))
                        if z==self.nz-1 or functionOut(self.get_value_at_xyz(x, y, z + 1)):
                            v1 = Vertex(x, y, z + 1)
                            v2 = Vertex(x + 1, y, z + 1)
                            v3 = Vertex(x + 1, y + 1, z + 1)
                            v4 = Vertex(x, y + 1, z + 1)
                            faces.append(Face([v1, v2, v3, v4]))
                        if z == 0 or functionOut(self.get_value_at_xyz(x, y, z - 1)):
                            v1 = Vertex(x, y + 1, z)
                            v2 = Vertex(x + 1, y + 1, z)
                            v3 = Vertex(x + 1, y, z)
                            v4 = Vertex(x, y, z)
                            faces.append(Face([v1, v2, v3, v4]))
        mesh = Mesh()
        mesh.faces = faces
        mesh.update_topology()
        if (self.scale_to_canvas):
            mesh.translate(-self.nx/2.0,-self.ny/2.0,-self.nz/2.0)
            sc = 20.0/max(self.nx,self.ny)
            mesh.scale(sc,sc,sc)
        return mesh

Ancestors

Subclasses

Methods

def get_value_at_index(self, index)
Expand source code
def get_value_at_index(self, index):
    return self.values[index]
def get_value_at_xyz(self, x, y, z=0)
Expand source code
def get_value_at_xyz(self, x, y, z=0):
    return self.values[self.get_index(x, y, z)]
def quad_mesh(self, functionIn, functionOut)
Expand source code
def quad_mesh(self, functionIn, functionOut):
    faces = []
    for x in range(self.nx):
        for y in range(self.ny):
            for z in range(self.nz):
                index=self.get_index(x,y,z)
                if functionIn(self.values[index]):
                    # (x,y) (x1,y) (x1,y1) (x,y1)
                    if x == self.nx - 1 or functionOut(self.get_value_at_xyz(x + 1, y, z)):
                        v1 = Vertex(x + 1, y, z)
                        v2 = Vertex(x + 1, y + 1, z)
                        v3 = Vertex(x + 1, y + 1, z + 1)
                        v4 = Vertex(x + 1, y, z + 1)
                        faces.append(Face([v1, v2, v3, v4]))
                    if x == 0 or functionOut(self.get_value_at_xyz(x-1,y,z)):
                        v1 = Vertex(x, y + 1, z)
                        v2 = Vertex(x, y, z)
                        v3 = Vertex(x, y, z + 1)
                        v4 = Vertex(x, y + 1, z + 1)
                        faces.append(Face([v1, v2, v3, v4]))
                    if y == self.ny - 1 or functionOut(self.get_value_at_xyz(x, y + 1, z)):
                        v1 = Vertex(x + 1, y + 1, z)
                        v2 = Vertex(x, y + 1, z)
                        v3 = Vertex(x, y + 1, z + 1)
                        v4 = Vertex(x + 1, y + 1, z + 1)
                        faces.append(Face([v1, v2, v3, v4]))
                    if y == 0 or functionOut(self.get_value_at_xyz(x, y - 1, z)):
                        v1 = Vertex(x, y, z)
                        v2 = Vertex(x + 1, y, z)
                        v3 = Vertex(x + 1, y, z + 1)
                        v4 = Vertex(x, y, z + 1)
                        faces.append(Face([v1, v2, v3, v4]))
                    if z==self.nz-1 or functionOut(self.get_value_at_xyz(x, y, z + 1)):
                        v1 = Vertex(x, y, z + 1)
                        v2 = Vertex(x + 1, y, z + 1)
                        v3 = Vertex(x + 1, y + 1, z + 1)
                        v4 = Vertex(x, y + 1, z + 1)
                        faces.append(Face([v1, v2, v3, v4]))
                    if z == 0 or functionOut(self.get_value_at_xyz(x, y, z - 1)):
                        v1 = Vertex(x, y + 1, z)
                        v2 = Vertex(x + 1, y + 1, z)
                        v3 = Vertex(x + 1, y, z)
                        v4 = Vertex(x, y, z)
                        faces.append(Face([v1, v2, v3, v4]))
    mesh = Mesh()
    mesh.faces = faces
    mesh.update_topology()
    if (self.scale_to_canvas):
        mesh.translate(-self.nx/2.0,-self.ny/2.0,-self.nz/2.0)
        sc = 20.0/max(self.nx,self.ny)
        mesh.scale(sc,sc,sc)
    return mesh
def set_value_at_index(self, value, index)
Expand source code
def set_value_at_index(self, value, index):
    self.values[index] = value
def set_value_at_xyz(self, value, x, y, z=0)
Expand source code
def set_value_at_xyz(self, value, x, y, z=0):
    self.values[self.get_index(x, y, z)] = value
def shortest_path(self, startindex, endindex, obstaclevalue)
Expand source code
def shortest_path(self, startindex, endindex, obstaclevalue):
    # TODO
    return []

Inherited members

class GridManager (nx, ny, nz=1)

A GridManager is taking care of getting and setting values and retrieving neighbors in an orthogonal grid of either 2 or 3 dimension.

Attributes

nx, ny, nz : int
The number of elements in x,y and z direction.
Expand source code
class GridManager:
    """
    A `GridManager` is taking care of getting and setting values and
    retrieving neighbors in an orthogonal grid of either 2 or 3 dimension.

    Attributes
    ----------
    nx, ny, nz : int
        The number of elements in x,y and z direction.
    """
    def __init__(self, nx, ny, nz=1):
        self.nx = nx
        self.ny = ny
        self.nz = nz
        self.length = nx * ny * nz
        self.nyz = ny * nz

    def get_index(self, x, y, z=0):
        """
        returns the value at position x,y,z
        """
        return x * self.nyz + y * self.nz + z

    def get_x(self,index):
        """
        returns the X coordinate of a specific index
        """
        return index // self.nyz

    def get_y(self,index):
        """
        returns the Y coordinate of a specific index
        """
        return (index // self.nz) % self.ny

    def get_z(self,index):
        """
        returns the Z coordinate of a specific index
        """
        return index % self.nz

    def get_neighbors_hex_2d(self,index,continuous=False):
        """
        returns the 6 neighbor indices of a cell in a hexagonal grid
        set `continuous` to `True` to get torus topology (left edge stitched to right and top to bottom)
        """
        nbs = []
        x = self.get_x(index)
        y = self.get_y(index)
        if not continuous:
            if x < self.nx - 1:
                nbs.append(self.get_index(x + 1, y))
            if x > 0:
                nbs.append(self.get_index(x - 1, y))
            if y > 0:
                nbs.append(self.get_index(x, y - 1))
            if y < self.ny - 1:
                nbs.append(self.get_index(x, y + 1))
            if y % 2 == 0:
                if x < self.nx - 1 and y < self.ny - 1:
                    nbs.append(self.get_index(x + 1, y + 1))
                if x < self.nx - 1 and y > 0:
                    nbs.append(self.get_index(x + 1, y - 1))
            else:
                if x > 0 and y < self.ny - 1:
                    nbs.append(self.get_index(x - 1, y + 1))
                if x > 0 and y > 0:
                    nbs.append(self.get_index(x - 1, y - 1))
        else:
            xNext = x + 1 if x < self.nx - 1 else 0
            xPrev = x - 1 if x > 0 else self.nx - 1
            yNext = y + 1 if y < self.ny - 1 else 0
            yPrev = y - 1 if y > 0 else self.ny - 1
            nbs.append(self.get_index(xNext, y))
            nbs.append(self.get_index(xPrev, y))
            nbs.append(self.get_index(x, yPrev))
            nbs.append(self.get_index(x, yNext))
            if y % 2 == 0:
                nbs.append(self.get_index(xNext, yNext))
                nbs.append(self.get_index(xNext, yPrev))
            else:
                nbs.append(self.get_index(xPrev, yNext))
                nbs.append(self.get_index(xPrev, yPrev))
        return nbs

    def get_neighbors_2d(self,index,nbs8=False,continuous=False):
        """
        returns the neighbor indices of a cell in an orthogonal grid
        set `nbs8` to `True` to get 8 neighbors, default is 4
        set `continuous` to `True` to get torus topology (left edge stitched to right and top to bottom)
        """
        nbs = []
        x = self.get_x(index)
        y = self.get_y(index)
        if not continuous:
            if x < self.nx - 1:
                nbs.append(self.get_index(x + 1, y))
            if nbs8:
                if x < self.nx - 1 and y < self.ny - 1:
                    nbs.append(self.get_index(x + 1, y + 1))
            if y < self.ny - 1:
                nbs.append(self.get_index(x, y + 1))
            if nbs8:
                if x > 0 and y < self.ny - 1:
                    nbs.append(self.get_index(x - 1, y + 1))
            if x > 0:
                nbs.append(self.get_index(x - 1, y))
            if nbs8:
                if x > 0 and y > 0:
                    nbs.append(self.get_index(x - 1, y - 1))
            if y > 0:
                nbs.append(self.get_index(x, y - 1))
            if nbs8:
                if x < self.nx - 1 and y > 0:
                    nbs.append(self.get_index(x + 1, y - 1))
        else:
            xPrev = x - 1 if x > 0 else self.nx - 1
            xNext = x + 1 if x < self.nx - 1 else 0
            yPrev = y - 1 if y > 0 else self.ny - 1
            yNext = y + 1 if y < self.ny - 1 else 0
            nbs.append(self.get_index(xNext, y))
            if nbs8:
                nbs.append(self.get_index(xNext, yNext))
            nbs.append(self.get_index(x, yNext))
            if nbs8:
                nbs.append(self.get_index(xPrev, yNext))
            nbs.append(self.get_index(xPrev, y))
            if nbs8:
                nbs.append(self.get_index(xPrev, yPrev))
            nbs.append(self.get_index(x, yPrev))
            if nbs8:
                nbs.append(self.get_index(xNext, yPrev))
        return nbs

    def get_neighbors_3d(self, index, mode=3, continuous=False):
        nbs = []
        x = self.get_x(index)
        y = self.get_y(index)
        z = self.get_z(index)

        # mode: neighbourhood type
        # 1 :  6 nbs, shared face
        # 2 : 18 nbs, shared face or edge
        # 3 : 26 nbs, shared face, edge or vertex
        if not mode:
            mode==3
        if mode<1:
            mode==1
        if mode>3:
            mode==3

        # precalculate distances
        # dists = [1, math.sqrt(2), math.sqrt(3)]

        # create a list of directions with x,y and z offsets
        directions = []
        for i in range(-1,2):
            for j in range(-1,2):
                for k in range(-1,2):
                    l = [i,j,k]
                    s = sum([abs(v) for v in l])
                    # check for neighbourhood type
                    if s > 0 and s <= mode:
                        directions.append(l)

        for d in directions:
            ex = x + d[0]
            ey = y + d[1]
            ez = z + d[2]
            if continuous:
                ex = ex % self.nx
                ey = ey % self.ny
                ez = ez % self.nz
            if 0 <= ex < self.nx and 0 <= ey < self.ny and 0 <= ez < self.nz:
                nbs.append(self.get_index(ex,ey,ez))

        return nbs

Subclasses

Methods

def get_index(self, x, y, z=0)

returns the value at position x,y,z

Expand source code
def get_index(self, x, y, z=0):
    """
    returns the value at position x,y,z
    """
    return x * self.nyz + y * self.nz + z
def get_neighbors_2d(self, index, nbs8=False, continuous=False)

returns the neighbor indices of a cell in an orthogonal grid set nbs8 to True to get 8 neighbors, default is 4 set continuous to True to get torus topology (left edge stitched to right and top to bottom)

Expand source code
def get_neighbors_2d(self,index,nbs8=False,continuous=False):
    """
    returns the neighbor indices of a cell in an orthogonal grid
    set `nbs8` to `True` to get 8 neighbors, default is 4
    set `continuous` to `True` to get torus topology (left edge stitched to right and top to bottom)
    """
    nbs = []
    x = self.get_x(index)
    y = self.get_y(index)
    if not continuous:
        if x < self.nx - 1:
            nbs.append(self.get_index(x + 1, y))
        if nbs8:
            if x < self.nx - 1 and y < self.ny - 1:
                nbs.append(self.get_index(x + 1, y + 1))
        if y < self.ny - 1:
            nbs.append(self.get_index(x, y + 1))
        if nbs8:
            if x > 0 and y < self.ny - 1:
                nbs.append(self.get_index(x - 1, y + 1))
        if x > 0:
            nbs.append(self.get_index(x - 1, y))
        if nbs8:
            if x > 0 and y > 0:
                nbs.append(self.get_index(x - 1, y - 1))
        if y > 0:
            nbs.append(self.get_index(x, y - 1))
        if nbs8:
            if x < self.nx - 1 and y > 0:
                nbs.append(self.get_index(x + 1, y - 1))
    else:
        xPrev = x - 1 if x > 0 else self.nx - 1
        xNext = x + 1 if x < self.nx - 1 else 0
        yPrev = y - 1 if y > 0 else self.ny - 1
        yNext = y + 1 if y < self.ny - 1 else 0
        nbs.append(self.get_index(xNext, y))
        if nbs8:
            nbs.append(self.get_index(xNext, yNext))
        nbs.append(self.get_index(x, yNext))
        if nbs8:
            nbs.append(self.get_index(xPrev, yNext))
        nbs.append(self.get_index(xPrev, y))
        if nbs8:
            nbs.append(self.get_index(xPrev, yPrev))
        nbs.append(self.get_index(x, yPrev))
        if nbs8:
            nbs.append(self.get_index(xNext, yPrev))
    return nbs
def get_neighbors_3d(self, index, mode=3, continuous=False)
Expand source code
def get_neighbors_3d(self, index, mode=3, continuous=False):
    nbs = []
    x = self.get_x(index)
    y = self.get_y(index)
    z = self.get_z(index)

    # mode: neighbourhood type
    # 1 :  6 nbs, shared face
    # 2 : 18 nbs, shared face or edge
    # 3 : 26 nbs, shared face, edge or vertex
    if not mode:
        mode==3
    if mode<1:
        mode==1
    if mode>3:
        mode==3

    # precalculate distances
    # dists = [1, math.sqrt(2), math.sqrt(3)]

    # create a list of directions with x,y and z offsets
    directions = []
    for i in range(-1,2):
        for j in range(-1,2):
            for k in range(-1,2):
                l = [i,j,k]
                s = sum([abs(v) for v in l])
                # check for neighbourhood type
                if s > 0 and s <= mode:
                    directions.append(l)

    for d in directions:
        ex = x + d[0]
        ey = y + d[1]
        ez = z + d[2]
        if continuous:
            ex = ex % self.nx
            ey = ey % self.ny
            ez = ez % self.nz
        if 0 <= ex < self.nx and 0 <= ey < self.ny and 0 <= ez < self.nz:
            nbs.append(self.get_index(ex,ey,ez))

    return nbs
def get_neighbors_hex_2d(self, index, continuous=False)

returns the 6 neighbor indices of a cell in a hexagonal grid set continuous to True to get torus topology (left edge stitched to right and top to bottom)

Expand source code
def get_neighbors_hex_2d(self,index,continuous=False):
    """
    returns the 6 neighbor indices of a cell in a hexagonal grid
    set `continuous` to `True` to get torus topology (left edge stitched to right and top to bottom)
    """
    nbs = []
    x = self.get_x(index)
    y = self.get_y(index)
    if not continuous:
        if x < self.nx - 1:
            nbs.append(self.get_index(x + 1, y))
        if x > 0:
            nbs.append(self.get_index(x - 1, y))
        if y > 0:
            nbs.append(self.get_index(x, y - 1))
        if y < self.ny - 1:
            nbs.append(self.get_index(x, y + 1))
        if y % 2 == 0:
            if x < self.nx - 1 and y < self.ny - 1:
                nbs.append(self.get_index(x + 1, y + 1))
            if x < self.nx - 1 and y > 0:
                nbs.append(self.get_index(x + 1, y - 1))
        else:
            if x > 0 and y < self.ny - 1:
                nbs.append(self.get_index(x - 1, y + 1))
            if x > 0 and y > 0:
                nbs.append(self.get_index(x - 1, y - 1))
    else:
        xNext = x + 1 if x < self.nx - 1 else 0
        xPrev = x - 1 if x > 0 else self.nx - 1
        yNext = y + 1 if y < self.ny - 1 else 0
        yPrev = y - 1 if y > 0 else self.ny - 1
        nbs.append(self.get_index(xNext, y))
        nbs.append(self.get_index(xPrev, y))
        nbs.append(self.get_index(x, yPrev))
        nbs.append(self.get_index(x, yNext))
        if y % 2 == 0:
            nbs.append(self.get_index(xNext, yNext))
            nbs.append(self.get_index(xNext, yPrev))
        else:
            nbs.append(self.get_index(xPrev, yNext))
            nbs.append(self.get_index(xPrev, yPrev))
    return nbs
def get_x(self, index)

returns the X coordinate of a specific index

Expand source code
def get_x(self,index):
    """
    returns the X coordinate of a specific index
    """
    return index // self.nyz
def get_y(self, index)

returns the Y coordinate of a specific index

Expand source code
def get_y(self,index):
    """
    returns the Y coordinate of a specific index
    """
    return (index // self.nz) % self.ny
def get_z(self, index)

returns the Z coordinate of a specific index

Expand source code
def get_z(self,index):
    """
    returns the Z coordinate of a specific index
    """
    return index % self.nz
class HexGrid (nx, ny, nz=1, values=None)

A GridManager is taking care of getting and setting values and retrieving neighbors in an orthogonal grid of either 2 or 3 dimension.

Attributes

nx, ny, nz : int
The number of elements in x,y and z direction.
Expand source code
class HexGrid(Grid):
    def __init__(self, nx, ny, nz=1, values=None):
        super().__init__(nx, ny, nz, values)
        # self.ny = nx
        # self.ny = ny
        # self.nz = nz
        # self.nyz = ny * nz
        # if values == None:
        #     self.values = [0] * nx * ny * nz
        self.dimy = math.sqrt(3) * 0.5

    def get_position(self, x, y, z=0):
        return [x + (y % 2) * 0.5, y * self.dimy, z]

Ancestors

Methods

def get_position(self, x, y, z=0)
Expand source code
def get_position(self, x, y, z=0):
    return [x + (y % 2) * 0.5, y * self.dimy, z]

Inherited members

class Mesh

A mesh describes a 3D surface made of Vertices connected by Faces.

Attributes

vertices : list
The list of Vertex objects in the mesh.
faces : list
The list of Face objects in the mesh.
edges : list
The list of edges in the mesh.
Expand source code
class Mesh:
    """A mesh describes a 3D surface made of Vertices connected by Faces.

    Attributes
    ----------
    vertices : list
        The list of `Vertex` objects in the mesh.
    faces : list
        The list of `Face` objects in the mesh.
    edges : list
        The list of edges in the mesh.
    """
    def __init__(self):
        self.vertices = []
        self.faces = []
        self.edges = []

    def scale(self, sx, sy, sz):
        """
        scales a mesh by adding multiplying
        the position of its vertices by sx, sy and sz.
        """
        #vs = Vertex(sx, sy, sz)
        for v in self.vertices:
            v.x *= sx
            v.y *= sy
            v.z *= sz

    def translate(self, tx, ty, tz):
        """
        translates a mesh by adding tx,ty and tz
        to the position of the vertices.
        """
        vt = Vertex(tx, ty, tz)
        for v in self.vertices:
            v.add(vt)

    def bounding_box(self):
        """
        returns the bounding box of this mesh as a Box() object
        """
        box = Box()
        for f in self.faces:
            for v in f.vertices:
                box.add_point(v.x,v.y,v.z)
        return box

    def center(self):
        """
        Returns the center of the Mesh as a Vertex() object
        Note: not the center of gravity, just the average of its vertices.
        """
        return self.bounding_box().center()

    def edge_adjacent_to_vertices(self, v1, v2):
        for edge in v1.edges:
            if edge.v2 == v2 or edge.v1 == v2:
                return edge
        return None

    def face_adjacent_to_vertices(self, v1, v2):
        edge = v1.edge_adjacent_to_vertex(v2)
        if edge != None:
            if edge.v1 == v1:
                return edge.face1
            else:
                return edge.face2
        return None

    def add_vertex(self, x, y, z=0):
        v = Vertex(x,y,z)
        self.vertices.append(v)
        return v

    def add_face(self, vertices):
        f = Face(vertices)
        self.faces.append(f)
        return f

    def face_properties(self,face_analyse):
        values=[]
        for face in self.faces:
            values.append(face_analyse(face))
        return values

    def weld_vertices(self):
        weldedVertices = {}
        self.vertices = []
        for f in self.faces:
            for i in range(len(f.vertices)):
                v = f.vertices[i]
                vtuple = (v.x, v.y, v.z)
                if vtuple in weldedVertices:
                    f.vertices[i] = weldedVertices[vtuple]
                else:
                    weldedVertices[vtuple] = v
        self.vertices = [v for v in weldedVertices.values()]

    def update_edges(self):
        self.edges = []
        for v in self.vertices:
            v.edges = []
        for f in self.faces:
            v1 = f.vertices[-1]
            for v2 in f.vertices:
                edge = v1.edge_adjacent_to_vertex(v2)
                if edge == None:
                    edge = Edge(v1,v2)
                    v1.edges.append(edge)
                    v2.edges.append(edge)
                    self.edges.append(edge)
                if edge.v1 == v1:
                    edge.face1 = f
                else:
                    edge.face2 = f
                v1 = v2

    def update_topology(self):
        self.weld_vertices()
        self.update_edges()

    def copy(self):
        meshcopy = Mesh()

        # if mesh has no topolgy constructed
        if len(self.edges) == 0:
            for f in self.faces:
                vs = [Vertex(v.x,v.y,v.z) for v in f.vertices]
                for nv,ov in zip(vs, f.vertices):
                    nv.fix = ov.fix
                    nv.generation = ov.generation
                nf = meshcopy.add_face(vs)
                utils_face.face_copy_properties(f,nf)
        else:
            meshcopy.vertices = [Vertex(v.x,v.y,v.z) for v in self.vertices]
            for nv,ov in zip(meshcopy.vertices, self.vertices):
                nv.fix = ov.fix
                nv.generation = ov.generation

            for f in self.faces:
                vs = [meshcopy.vertices[self.vertices.index(v)] for v in f.vertices]
                nf = meshcopy.add_face(vs)
                utils_face.face_copy_properties(f,nf)
            
            for e in self.edges:
                iv1 = self.vertices.index(e.v1)
                iv2 = self.vertices.index(e.v1)
                ie1 = self.faces.index(e.face1)
                ie2 = self.faces.index(e.face2)
                v1c = meshcopy.vertices[iv1]
                v2c = meshcopy.vertices[iv2]
                edge = Edge(v1c,v2c)
                v1c.edges.append(edge)
                v2c.edges.append(edge)
                meshcopy.edges.append(edge)
                edge.face1 = meshcopy.faces[ie1]
                edge.face2 = meshcopy.faces[ie2]

        return meshcopy

Methods

def add_face(self, vertices)
Expand source code
def add_face(self, vertices):
    f = Face(vertices)
    self.faces.append(f)
    return f
def add_vertex(self, x, y, z=0)
Expand source code
def add_vertex(self, x, y, z=0):
    v = Vertex(x,y,z)
    self.vertices.append(v)
    return v
def bounding_box(self)

returns the bounding box of this mesh as a Box() object

Expand source code
def bounding_box(self):
    """
    returns the bounding box of this mesh as a Box() object
    """
    box = Box()
    for f in self.faces:
        for v in f.vertices:
            box.add_point(v.x,v.y,v.z)
    return box
def center(self)

Returns the center of the Mesh as a Vertex() object Note: not the center of gravity, just the average of its vertices.

Expand source code
def center(self):
    """
    Returns the center of the Mesh as a Vertex() object
    Note: not the center of gravity, just the average of its vertices.
    """
    return self.bounding_box().center()
def copy(self)
Expand source code
def copy(self):
    meshcopy = Mesh()

    # if mesh has no topolgy constructed
    if len(self.edges) == 0:
        for f in self.faces:
            vs = [Vertex(v.x,v.y,v.z) for v in f.vertices]
            for nv,ov in zip(vs, f.vertices):
                nv.fix = ov.fix
                nv.generation = ov.generation
            nf = meshcopy.add_face(vs)
            utils_face.face_copy_properties(f,nf)
    else:
        meshcopy.vertices = [Vertex(v.x,v.y,v.z) for v in self.vertices]
        for nv,ov in zip(meshcopy.vertices, self.vertices):
            nv.fix = ov.fix
            nv.generation = ov.generation

        for f in self.faces:
            vs = [meshcopy.vertices[self.vertices.index(v)] for v in f.vertices]
            nf = meshcopy.add_face(vs)
            utils_face.face_copy_properties(f,nf)
        
        for e in self.edges:
            iv1 = self.vertices.index(e.v1)
            iv2 = self.vertices.index(e.v1)
            ie1 = self.faces.index(e.face1)
            ie2 = self.faces.index(e.face2)
            v1c = meshcopy.vertices[iv1]
            v2c = meshcopy.vertices[iv2]
            edge = Edge(v1c,v2c)
            v1c.edges.append(edge)
            v2c.edges.append(edge)
            meshcopy.edges.append(edge)
            edge.face1 = meshcopy.faces[ie1]
            edge.face2 = meshcopy.faces[ie2]

    return meshcopy
def edge_adjacent_to_vertices(self, v1, v2)
Expand source code
def edge_adjacent_to_vertices(self, v1, v2):
    for edge in v1.edges:
        if edge.v2 == v2 or edge.v1 == v2:
            return edge
    return None
def face_adjacent_to_vertices(self, v1, v2)
Expand source code
def face_adjacent_to_vertices(self, v1, v2):
    edge = v1.edge_adjacent_to_vertex(v2)
    if edge != None:
        if edge.v1 == v1:
            return edge.face1
        else:
            return edge.face2
    return None
def face_properties(self, face_analyse)
Expand source code
def face_properties(self,face_analyse):
    values=[]
    for face in self.faces:
        values.append(face_analyse(face))
    return values
def scale(self, sx, sy, sz)

scales a mesh by adding multiplying the position of its vertices by sx, sy and sz.

Expand source code
def scale(self, sx, sy, sz):
    """
    scales a mesh by adding multiplying
    the position of its vertices by sx, sy and sz.
    """
    #vs = Vertex(sx, sy, sz)
    for v in self.vertices:
        v.x *= sx
        v.y *= sy
        v.z *= sz
def translate(self, tx, ty, tz)

translates a mesh by adding tx,ty and tz to the position of the vertices.

Expand source code
def translate(self, tx, ty, tz):
    """
    translates a mesh by adding tx,ty and tz
    to the position of the vertices.
    """
    vt = Vertex(tx, ty, tz)
    for v in self.vertices:
        v.add(vt)
def update_edges(self)
Expand source code
def update_edges(self):
    self.edges = []
    for v in self.vertices:
        v.edges = []
    for f in self.faces:
        v1 = f.vertices[-1]
        for v2 in f.vertices:
            edge = v1.edge_adjacent_to_vertex(v2)
            if edge == None:
                edge = Edge(v1,v2)
                v1.edges.append(edge)
                v2.edges.append(edge)
                self.edges.append(edge)
            if edge.v1 == v1:
                edge.face1 = f
            else:
                edge.face2 = f
            v1 = v2
def update_topology(self)
Expand source code
def update_topology(self):
    self.weld_vertices()
    self.update_edges()
def weld_vertices(self)
Expand source code
def weld_vertices(self):
    weldedVertices = {}
    self.vertices = []
    for f in self.faces:
        for i in range(len(f.vertices)):
            v = f.vertices[i]
            vtuple = (v.x, v.y, v.z)
            if vtuple in weldedVertices:
                f.vertices[i] = weldedVertices[vtuple]
            else:
                weldedVertices[vtuple] = v
    self.vertices = [v for v in weldedVertices.values()]
class PriorityQueue (maxsize=0)

Variant of Queue that retrieves open entries in priority order (lowest first).

Entries are typically tuples of the form: (priority number, data).

Expand source code
class PriorityQueue(Queue):
    '''Variant of Queue that retrieves open entries in priority order (lowest first).

    Entries are typically tuples of the form:  (priority number, data).
    '''

    def _init(self, maxsize):
        self.queue = []

    def _qsize(self):
        return len(self.queue)

    def _put(self, item):
        heappush(self.queue, item)

    def _get(self):
        return heappop(self.queue)

Ancestors

  • queue.Queue
class SinusFunction (frequency, amplitude=1, phase=0, offset=0)
Expand source code
class SinusFunction(object):
    def __init__(self, frequency, amplitude=1, phase=0, offset=0):
        self.frequency = frequency
        self.amplitude = amplitude
        self.phase = phase
        self.offset = offset

    def getValue(self,value):
        return math.sin(self.frequency * value + self.phase) * self.amplitude + self.offset

Methods

def getValue(self, value)
Expand source code
def getValue(self,value):
    return math.sin(self.frequency * value + self.phase) * self.amplitude + self.offset
class Vertex (x=0, y=0, z=0)

A Vertex defines a point in space.

Attributes

x, y, z : float
The coordinates of the Vertex.
fix : boolean
Flag to set a Vertex to be fixed or not.
generation : integer
Number in what generation of subdivision the face was created.
edges : list
List of edges connected to the Vertex.
Expand source code
class Vertex:
    """A Vertex defines a point in space.

    Attributes
    ----------
    x, y, z : float
        The coordinates of the `Vertex`.
    fix : boolean
        Flag to set a Vertex to be fixed or not.
    generation : integer
        Number in what generation of subdivision the face was created.
    edges : list
        List of edges connected to the `Vertex`.
    """
    def __init__(self, x=0, y=0, z=0):
        self.x = x
        self.y = y
        self.z = z
        self.fix = False
        self.generation = 0
        self.edges = []

    def __str__(self):
        """
        Returns a string representation of the Vertex ("x.xx y.yy z.zz")
        """
        return ' '.join([str(v) for v in [self.x,self.y,self.z]])

    def __repr__(self):
        return 'Vertex('+','.join([str(v) for v in [self.x,self.y,self.z]])+')'

    def __eq__(self, other):
        """
        Compares this `Vertex` to another `Vertex`. Returns true if all their 3 coordinates are equal.
        """
        if isinstance(other, self.__class__):
            return (self.x == other.x) and (self.y == other.y) and (self.z == other.z)
        else:
            return False

    def edge_adjacent_to_vertex(self, v):
        """
        Returns the edge connecting this `Vertex` to another `Vertex` or `None` if there's none.

        Arguments:
        ----------
        v : mola.Vertex
            The other Vertex
        """
        for edge in self.edges:
            if edge.v2 is v or edge.v1 is v:
                return edge
        return None

    def add(self, vertex):
        """
        adds the position vector of another Vertex to
        the position vector of this Vertex.
        """
        self.x += vertex.x
        self.y += vertex.y
        self.z += vertex.z
        return self

    def subtract(self, vertex):
        """
        subtracts the position vector of another Vertex from
        the position vector of this Vertex.
        """
        self.x -= vertex.x
        self.y -= vertex.y
        self.z -= vertex.z
        return self

    def scale(self, factor):
        """
        scales the position vector of this Vertex
        by a factor (multiplication).
        """
        self.x *= factor
        self.y *= factor
        self.z *= factor
        return self

    def divide(self, factor):
        """
        scales the position vector of this Vertex
        by a factor (division).
        """
        self.x /= factor
        self.y /= factor
        self.z /= factor
        return self

    def length(self):
        """
        returns the length of the position vector,
        the distance from the origin (0,0,0).
        """
        return math.sqrt(self.x**2 + self.y**2 + self.z**2)

    def unitize(self):
        """
        returns a vector of the same direction
        but of unit length 1
        """
        l = self.length()
        if l==0: return self
        return self.divide(l)

    def __add__(self, other):
        vector = Vertex(self.x, self.y, self.z)
        return vector.add(other)

    def __sub__(self, other):
        vector = Vertex(self.x, self.y, self.z)
        return vector.subtract(other)

    def __mul__(self, factor):
        vector = Vertex(self.x, self.y, self.z)
        return vector.scale(factor)

    # for python 3
    def __truediv__(self, factor):
        vector = Vertex(self.x, self.y, self.z)
        return vector.divide(factor)

    # for python 2
    def __div__(self, factor):
        vector = Vertex(self.x, self.y, self.z)
        return vector.divide(factor)

Methods

def add(self, vertex)

adds the position vector of another Vertex to the position vector of this Vertex.

Expand source code
def add(self, vertex):
    """
    adds the position vector of another Vertex to
    the position vector of this Vertex.
    """
    self.x += vertex.x
    self.y += vertex.y
    self.z += vertex.z
    return self
def divide(self, factor)

scales the position vector of this Vertex by a factor (division).

Expand source code
def divide(self, factor):
    """
    scales the position vector of this Vertex
    by a factor (division).
    """
    self.x /= factor
    self.y /= factor
    self.z /= factor
    return self
def edge_adjacent_to_vertex(self, v)

Returns the edge connecting this Vertex to another Vertex or None if there's none.

Arguments:

v : mola.Vertex The other Vertex

Expand source code
def edge_adjacent_to_vertex(self, v):
    """
    Returns the edge connecting this `Vertex` to another `Vertex` or `None` if there's none.

    Arguments:
    ----------
    v : mola.Vertex
        The other Vertex
    """
    for edge in self.edges:
        if edge.v2 is v or edge.v1 is v:
            return edge
    return None
def length(self)

returns the length of the position vector, the distance from the origin (0,0,0).

Expand source code
def length(self):
    """
    returns the length of the position vector,
    the distance from the origin (0,0,0).
    """
    return math.sqrt(self.x**2 + self.y**2 + self.z**2)
def scale(self, factor)

scales the position vector of this Vertex by a factor (multiplication).

Expand source code
def scale(self, factor):
    """
    scales the position vector of this Vertex
    by a factor (multiplication).
    """
    self.x *= factor
    self.y *= factor
    self.z *= factor
    return self
def subtract(self, vertex)

subtracts the position vector of another Vertex from the position vector of this Vertex.

Expand source code
def subtract(self, vertex):
    """
    subtracts the position vector of another Vertex from
    the position vector of this Vertex.
    """
    self.x -= vertex.x
    self.y -= vertex.y
    self.z -= vertex.z
    return self
def unitize(self)

returns a vector of the same direction but of unit length 1

Expand source code
def unitize(self):
    """
    returns a vector of the same direction
    but of unit length 1
    """
    l = self.length()
    if l==0: return self
    return self.divide(l)