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 cornerExpand 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 theFace
. 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
toTrue
to get 8 neighbors, default is 4 setcontinuous
toTrue
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
toTrue
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 anotherVertex
orNone
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)