Skip to content

Mesh

a 3D mesh consisting of vertices and faces with optional colors and texture coordinates

vertices instance-attribute

vertices: List[float]

faces instance-attribute

faces: List[int]

colors class-attribute instance-attribute

colors: List[int] = field(default_factory=list)

textureCoordinates class-attribute instance-attribute

textureCoordinates: List[float] = field(
    default_factory=list
)

vertexNormals class-attribute instance-attribute

vertexNormals: List[float] = field(default_factory=list)

vertices_count property

vertices_count: int

get the number of vertices in the mesh

texture_coordinates_count property

texture_coordinates_count: int

get the number of texture coordinates in the mesh

area property writable

area: float

volume property writable

volume: float

calculate_area

calculate_area() -> float

calculate total surface area of the mesh

Source code in src/specklepy/objects/geometry/mesh.py
def calculate_area(self) -> float:
    """
    calculate total surface area of the mesh
    """
    total_area = 0.0
    face_index = 0
    i = 0

    while i < len(self.faces):
        vertex_count = self.faces[i]
        if vertex_count >= 3:
            face_vertices = self.get_face_vertices(face_index)
            for j in range(1, vertex_count - 1):
                v0 = face_vertices[0]
                v1 = face_vertices[j]
                v2 = face_vertices[j + 1]
                a = [v1.x - v0.x, v1.y - v0.y, v1.z - v0.z]
                b = [v2.x - v0.x, v2.y - v0.y, v2.z - v0.z]
                cx = a[1] * b[2] - a[2] * b[1]
                cy = a[2] * b[0] - a[0] * b[2]
                cz = a[0] * b[1] - a[1] * b[0]
                area = 0.5 * (cx * cx + cy * cy + cz * cz) ** 0.5
                total_area += area
        i += vertex_count + 1
        face_index += 1

    return total_area

calculate_volume

calculate_volume() -> float

calculate volume of the mesh if it is closed

Source code in src/specklepy/objects/geometry/mesh.py
def calculate_volume(self) -> float:
    """
    calculate volume of the mesh if it is closed
    """
    if not self.is_closed():
        return 0.0

    total_volume = 0.0
    face_index = 0
    i = 0
    while i < len(self.faces):
        vertex_count = self.faces[i]
        if vertex_count >= 3:
            face_vertices = self.get_face_vertices(face_index)
            v0 = face_vertices[0]
            for j in range(1, vertex_count - 1):
                v1 = face_vertices[j]
                v2 = face_vertices[j + 1]
                a = [v0.x, v0.y, v0.z]
                b = [v1.x - v0.x, v1.y - v0.y, v1.z - v0.z]
                c = [v2.x - v0.x, v2.y - v0.y, v2.z - v0.z]
                cx = b[1] * c[2] - b[2] * c[1]
                cy = b[2] * c[0] - b[0] * c[2]
                cz = b[0] * c[1] - b[1] * c[0]
                v = (a[0] * cx + a[1] * cy + a[2] * cz) / 6.0
                total_volume += v
        i += vertex_count + 1
        face_index += 1

    return abs(total_volume)

get_point

get_point(index: int) -> Point

get vertex at index as a Point object

Source code in src/specklepy/objects/geometry/mesh.py
def get_point(self, index: int) -> Point:
    """
    get vertex at index as a Point object
    """
    if index < 0 or index >= self.vertices_count:
        raise IndexError(f"Vertex index {index} out of range")

    index *= 3
    return Point(
        x=self.vertices[index],
        y=self.vertices[index + 1],
        z=self.vertices[index + 2],
        units=self.units,
    )

get_points

get_points() -> List[Point]

get all vertices as Point objects

Source code in src/specklepy/objects/geometry/mesh.py
def get_points(self) -> List[Point]:
    """
    get all vertices as Point objects
    """
    return [self.get_point(i) for i in range(self.vertices_count)]

get_texture_coordinate

get_texture_coordinate(index: int) -> Tuple[float, float]

get texture coordinate at index

Source code in src/specklepy/objects/geometry/mesh.py
def get_texture_coordinate(self, index: int) -> Tuple[float, float]:
    """
    get texture coordinate at index
    """
    if index < 0 or index >= self.texture_coordinates_count:
        raise IndexError(f"Texture coordinate index {index} out of range")

    index *= 2
    return (self.textureCoordinates[index], self.textureCoordinates[index + 1])

get_face_vertices

get_face_vertices(face_index: int) -> List[Point]

get the vertices of a specific face

Source code in src/specklepy/objects/geometry/mesh.py
def get_face_vertices(self, face_index: int) -> List[Point]:
    """
    get the vertices of a specific face
    """
    i = 0
    current_face = 0

    while i < len(self.faces):
        if current_face == face_index:
            vertex_count = self.faces[i]
            vertices = []
            for j in range(vertex_count):
                vertex_index = self.faces[i + j + 1]
                if vertex_index >= self.vertices_count:
                    raise IndexError(f"Vertex index {vertex_index} out of range")
                vertices.append(self.get_point(vertex_index))
            return vertices

        vertex_count = self.faces[i]
        i += vertex_count + 1
        current_face += 1

    raise IndexError(f"Face index {face_index} out of range")

is_closed

is_closed() -> bool

check if the mesh is closed (verifying each edge appears twice)

Source code in src/specklepy/objects/geometry/mesh.py
def is_closed(self) -> bool:
    """
    check if the mesh is closed (verifying each edge appears twice)
    """
    edge_counts = {}

    i = 0
    while i < len(self.faces):
        vertex_count = self.faces[i]
        for j in range(vertex_count):
            v1 = self.faces[i + 1 + j]
            v2 = self.faces[i + 1 + ((j + 1) % vertex_count)]
            edge = tuple(sorted([v1, v2]))
            edge_counts[edge] = edge_counts.get(edge, 0) + 1

        i += vertex_count + 1

    return all(count == 2 for count in edge_counts.values())