103: Surface mesh

This script demonstrates how to use the Easy3D SurfaceMesh class:

  • Initialize a SurfaceMesh from vertices and vertex indices of the faces.

  • Iterate all the faces, query the number of its vertices and print them.

  • Iterate all the vertices, query the number of its incident vertices and print them.

  • Iterate all the edges, print the two end vertices and two incident faces of each face.

  • Iterate all the halfedges, print its source and target vertices and its two incident faces.

It seems most Python users will only use this class for visualization, thus a lot of editing operations for SurfaceMesh have not been exposed to Python. Please let me know if you do need editing a mesh in Python.

Mesh 'Unit cube' has 8 vertices and 8 faces.
------- Iterate all the faces ------
Face 0 has 4 vertices
The incident vertices are: 0 3 2 1
The incident vertices are: 0 3 2 1
The incident halfedges are: 6 0 2 4
The incident halfedges are: 6 0 2 4
Face 1 has 4 vertices
The incident vertices are: 4 5 6 7
The incident vertices are: 4 5 6 7
The incident halfedges are: 14 8 10 12
The incident halfedges are: 14 8 10 12
Face 2 has 4 vertices
The incident vertices are: 0 4 7 3
The incident vertices are: 0 4 7 3
The incident halfedges are: 1 16 15 18
The incident halfedges are: 1 16 15 18
Face 3 has 4 vertices
The incident vertices are: 1 2 6 5
The incident vertices are: 1 2 6 5
The incident halfedges are: 22 5 20 11
The incident halfedges are: 22 5 20 11
Face 4 has 3 vertices
The incident vertices are: 0 1 5
The incident vertices are: 0 1 5
The incident halfedges are: 24 7 23
The incident halfedges are: 24 7 23
Face 5 has 3 vertices
The incident vertices are: 0 5 4
The incident vertices are: 0 5 4
The incident halfedges are: 17 25 9
The incident halfedges are: 17 25 9
Face 6 has 3 vertices
The incident vertices are: 2 3 7
The incident vertices are: 2 3 7
The incident halfedges are: 26 3 19
The incident halfedges are: 26 3 19
Face 7 has 3 vertices
The incident vertices are: 2 7 6
The incident vertices are: 2 7 6
The incident halfedges are: 21 27 13
The incident halfedges are: 21 27 13
------- Iterate all the vertices ------
Vertex 0 (-0.5, -0.5, -0.5) has 4 adjacent vertices
The incident vertices are: 5 4 3 1
The incident vertices are: 5 4 3 1
The incident halfedges are: 25 16 0 7
The incident halfedges are: 25 16 0 7
The incident faces are: 5 2 0 4
The incident faces are: 5 2 0 4
Vertex 1 (0.5, -0.5, -0.5) has 3 adjacent vertices
The incident vertices are: 5 0 2
The incident vertices are: 5 0 2
The incident halfedges are: 23 6 5
The incident halfedges are: 23 6 5
The incident faces are: 4 0 3
The incident faces are: 4 0 3
Vertex 2 (0.5, 0.5, -0.5) has 4 adjacent vertices
The incident vertices are: 7 6 1 3
The incident vertices are: 7 6 1 3
The incident halfedges are: 27 20 4 3
The incident halfedges are: 27 20 4 3
The incident faces are: 7 3 0 6
The incident faces are: 7 3 0 6
Vertex 3 (-0.5, 0.5, -0.5) has 3 adjacent vertices
The incident vertices are: 7 2 0
The incident vertices are: 7 2 0
The incident halfedges are: 19 2 1
The incident halfedges are: 19 2 1
The incident faces are: 6 0 2
The incident faces are: 6 0 2
Vertex 4 (-0.5, -0.5, 0.5) has 3 adjacent vertices
The incident vertices are: 0 5 7
The incident vertices are: 0 5 7
The incident halfedges are: 17 8 15
The incident halfedges are: 17 8 15
The incident faces are: 5 1 2
The incident faces are: 5 1 2
Vertex 5 (0.5, -0.5, 0.5) has 4 adjacent vertices
The incident vertices are: 4 0 1 6
The incident vertices are: 4 0 1 6
The incident halfedges are: 9 24 22 10
The incident halfedges are: 9 24 22 10
The incident faces are: 5 4 3 1
The incident faces are: 5 4 3 1
Vertex 6 (0.5, 0.5, 0.5) has 3 adjacent vertices
The incident vertices are: 2 7 5
The incident vertices are: 2 7 5
The incident halfedges are: 21 12 11
The incident halfedges are: 21 12 11
The incident faces are: 7 1 3
The incident faces are: 7 1 3
Vertex 7 (-0.5, 0.5, 0.5) has 4 adjacent vertices
The incident vertices are: 6 2 3 4
The incident vertices are: 6 2 3 4
The incident halfedges are: 13 26 18 14
The incident halfedges are: 13 26 18 14
The incident faces are: 7 6 2 1
The incident faces are: 7 6 2 1
------- Iterate all the edges ------
Edge 0: vertex 3 - vertex 0
The two incident faces: face 0 - face 2
Edge 1: vertex 2 - vertex 3
The two incident faces: face 0 - face 6
Edge 2: vertex 1 - vertex 2
The two incident faces: face 0 - face 3
Edge 3: vertex 0 - vertex 1
The two incident faces: face 0 - face 4
Edge 4: vertex 5 - vertex 4
The two incident faces: face 1 - face 5
Edge 5: vertex 6 - vertex 5
The two incident faces: face 1 - face 3
Edge 6: vertex 7 - vertex 6
The two incident faces: face 1 - face 7
Edge 7: vertex 4 - vertex 7
The two incident faces: face 1 - face 2
Edge 8: vertex 4 - vertex 0
The two incident faces: face 2 - face 5
Edge 9: vertex 3 - vertex 7
The two incident faces: face 2 - face 6
Edge 10: vertex 6 - vertex 2
The two incident faces: face 3 - face 7
Edge 11: vertex 1 - vertex 5
The two incident faces: face 3 - face 4
Edge 12: vertex 0 - vertex 5
The two incident faces: face 4 - face 5
Edge 13: vertex 2 - vertex 7
The two incident faces: face 6 - face 7
------- Iterate all the halfedges ------
Halfedge 0: vertex 0 -> vertex 3
Halfedge 0 -> face 0. Opposite halfedge 1 -> face 2
Halfedge 1: vertex 3 -> vertex 0
Halfedge 1 -> face 2. Opposite halfedge 0 -> face 0
Halfedge 2: vertex 3 -> vertex 2
Halfedge 2 -> face 0. Opposite halfedge 3 -> face 6
Halfedge 3: vertex 2 -> vertex 3
Halfedge 3 -> face 6. Opposite halfedge 2 -> face 0
Halfedge 4: vertex 2 -> vertex 1
Halfedge 4 -> face 0. Opposite halfedge 5 -> face 3
Halfedge 5: vertex 1 -> vertex 2
Halfedge 5 -> face 3. Opposite halfedge 4 -> face 0
Halfedge 6: vertex 1 -> vertex 0
Halfedge 6 -> face 0. Opposite halfedge 7 -> face 4
Halfedge 7: vertex 0 -> vertex 1
Halfedge 7 -> face 4. Opposite halfedge 6 -> face 0
Halfedge 8: vertex 4 -> vertex 5
Halfedge 8 -> face 1. Opposite halfedge 9 -> face 5
Halfedge 9: vertex 5 -> vertex 4
Halfedge 9 -> face 5. Opposite halfedge 8 -> face 1
Halfedge 10: vertex 5 -> vertex 6
Halfedge 10 -> face 1. Opposite halfedge 11 -> face 3
Halfedge 11: vertex 6 -> vertex 5
Halfedge 11 -> face 3. Opposite halfedge 10 -> face 1
Halfedge 12: vertex 6 -> vertex 7
Halfedge 12 -> face 1. Opposite halfedge 13 -> face 7
Halfedge 13: vertex 7 -> vertex 6
Halfedge 13 -> face 7. Opposite halfedge 12 -> face 1
Halfedge 14: vertex 7 -> vertex 4
Halfedge 14 -> face 1. Opposite halfedge 15 -> face 2
Halfedge 15: vertex 4 -> vertex 7
Halfedge 15 -> face 2. Opposite halfedge 14 -> face 1
Halfedge 16: vertex 0 -> vertex 4
Halfedge 16 -> face 2. Opposite halfedge 17 -> face 5
Halfedge 17: vertex 4 -> vertex 0
Halfedge 17 -> face 5. Opposite halfedge 16 -> face 2
Halfedge 18: vertex 7 -> vertex 3
Halfedge 18 -> face 2. Opposite halfedge 19 -> face 6
Halfedge 19: vertex 3 -> vertex 7
Halfedge 19 -> face 6. Opposite halfedge 18 -> face 2
Halfedge 20: vertex 2 -> vertex 6
Halfedge 20 -> face 3. Opposite halfedge 21 -> face 7
Halfedge 21: vertex 6 -> vertex 2
Halfedge 21 -> face 7. Opposite halfedge 20 -> face 3
Halfedge 22: vertex 5 -> vertex 1
Halfedge 22 -> face 3. Opposite halfedge 23 -> face 4
Halfedge 23: vertex 1 -> vertex 5
Halfedge 23 -> face 4. Opposite halfedge 22 -> face 3
Halfedge 24: vertex 5 -> vertex 0
Halfedge 24 -> face 4. Opposite halfedge 25 -> face 5
Halfedge 25: vertex 0 -> vertex 5
Halfedge 25 -> face 5. Opposite halfedge 24 -> face 4
Halfedge 26: vertex 7 -> vertex 2
Halfedge 26 -> face 6. Opposite halfedge 27 -> face 7
Halfedge 27: vertex 2 -> vertex 7
Halfedge 27 -> face 7. Opposite halfedge 26 -> face 6

# -------------------------------------------------------------------------------
# Adding Easy3D Python Bindings to the System Path
# -------------------------------------------------------------------------------
# This is required if the bindings are not installed via `pip` but are located in
# a local build directory. For building and installing Python bindings of Easy3D,
# please refer to: https://github.com/LiangliangNan/Easy3D/blob/main/README.md
# -------------------------------------------------------------------------------
import sys
sys.path.append("../../cmake-build-release/lib/python")  # Update this path to point to your Easy3D build directory.

import easy3d

# The `easy3d.initialize(False)` function initializes the Easy3D library.
# Use `True` to enable detailed logging, which is useful for debugging.
easy3d.initialize(False)

# -------------------------------------------------------------------------------
# Creating a SurfaceMesh
# -------------------------------------------------------------------------------
# In this tutorial, let's create a water-tight and consistently oriented unit cube.
vertices = [   # Vertices of a unit cube.
    [-0.5, -0.5, -0.5], [0.5, -0.5, -0.5], [0.5, 0.5, -0.5], [-0.5, 0.5, -0.5],
    [-0.5, -0.5,  0.5], [0.5, -0.5,  0.5], [0.5, 0.5,  0.5], [-0.5, 0.5,  0.5],
]
# You can also use Numpy array (don't forget "import numpy")
# vertices = numpy.array([
#     [-0.5, -0.5, -0.5], [0.5, -0.5, -0.5], [0.5, 0.5, -0.5], [-0.5, 0.5, -0.5],
#     [-0.5, -0.5,  0.5], [0.5, -0.5,  0.5], [0.5, 0.5,  0.5], [-0.5, 0.5,  0.5],
# ])

indices = [  # Indices of the faces (this cube has both triangle and rectangle faces).
    # Each element denotes the vertex indices of a face.
    # The SurfaceMesh class supports general polygonal meshes, and thus the faces
    # can have different numbers of vertex indices.
    [0, 3, 2, 1],    [4, 5, 6, 7],  [0, 4, 7, 3],
    [1, 2, 6, 5],    [0, 1, 5],    [0, 5, 4],    [2, 3, 7],    [2, 7, 6],
]

# You can also use Numpy array (don't forget "import numpy")
# indices = numpy.array([
#     [0, 3, 2, 1],    [4, 5, 6, 7],  [0, 4, 7, 3],
#     [1, 2, 6, 5],    [0, 1, 5],    [0, 5, 4],    [2, 3, 7],    [2, 7, 6],
# ], dtype=object)

# In case you want to represent the cube be a set of triangles (thus to create a triangle mesh), you can provide
# a 1D array of unsigned/signed integers, with each consecutive three indices representing a triangle face.
# indices = numpy.array([    # Indices for the 12 triangles (2 per face).
#     # Each consecutive 3 indices denote the vertex indices of a triangle face.
#     0, 2, 1,    0, 3, 2,    4, 5, 6,    4, 6, 7,    0, 7, 3,    0, 4, 7,
#     1, 2, 6,    1, 6, 5,    0, 1, 5,    0, 5, 4,    2, 3, 7,    2, 7, 6,
# ], dtype=numpy.uint32)

# Initialize a `SurfaceMesh` object with the vertices and indices.
mesh = easy3d.SurfaceMesh(vertices, indices)

# Set a name for this mesh.
mesh.set_name("Unit cube")
print(f"Mesh '{mesh.name()}' has {mesh.n_vertices()} vertices and {mesh.n_faces()} faces.")

print("------- Iterate all the faces ------")
for f in mesh.faces():
    # print the number of its vertices
    print(f"Face {f.idx()} has {mesh.valence(f)} vertices")
    # iterate all vertices of this face
    vcir = easy3d.SurfaceMesh.VertexAroundFaceCirculator(mesh, f)
    vertex_indices = [v.idx() for v in vcir]    # Collect all its vertex indices and print them in a single line
    print(f"The incident vertices are: {' '.join(map(str, vertex_indices))}")
    # alternative to VertexAroundFaceCirculator, one can use mesh.vertices(f) to access all vertices incident to this face
    vertex_indices = [v.idx() for v in mesh.vertices(f)]
    print(f"The incident vertices are: {' '.join(map(str, vertex_indices))}")
    # iterate all halfedges of this face
    hcir = easy3d.SurfaceMesh.HalfedgeAroundFaceCirculator(mesh, f)
    halfedge_indices = [h.idx() for h in hcir]    # Collect all its halfedges indices and print them in a single line
    print(f"The incident halfedges are: {' '.join(map(str, halfedge_indices))}")
    # alternative to HalfedgeAroundFaceCirculator, one can use mesh.halfedges(f) to access all halfedges incident to this face
    halfedge_indices = [h.idx() for h in mesh.halfedges(f)]
    print(f"The incident halfedges are: {' '.join(map(str, halfedge_indices))}")

print("------- Iterate all the vertices ------")
for v in mesh.vertices():
    #  print the number of its adjacent vertices
    print(f"Vertex {v.idx()} ({mesh.position(v).x}, {mesh.position(v).y}, {mesh.position(v).z}) has {mesh.valence(v)} adjacent vertices")
    # iterate all vertices incident to this vertex
    vcir = easy3d.SurfaceMesh.VertexAroundVertexCirculator(mesh, v)
    vertex_indices = [v.idx() for v in vcir]    # Collect indices of all incident vertices and print them in a single line
    print(f"The incident vertices are: {' '.join(map(str, vertex_indices))}")
    # alternative to VertexAroundVertexCirculator, one can use mesh.vertices(v) to access all vertices incident to this vertex
    vertex_indices = [v.idx() for v in mesh.vertices(v)]
    print(f"The incident vertices are: {' '.join(map(str, vertex_indices))}")
    # iterate all halfedges incident to this vertex
    hcir = easy3d.SurfaceMesh.HalfedgeAroundVertexCirculator(mesh, v)
    halfedge_indices = [h.idx() for h in hcir]    # Collect indices of all incident halfedges and print them in a single line
    print(f"The incident halfedges are: {' '.join(map(str, halfedge_indices))}")
    # alternative to HalfedgeAroundVertexCirculator, one can use mesh.halfedges(v) to access all halfedges incident to this vertex
    halfedge_indices = [h.idx() for h in mesh.halfedges(v)]
    print(f"The incident halfedges are: {' '.join(map(str, halfedge_indices))}")
    # iterate all faces incident to this vertex
    fcir = easy3d.SurfaceMesh.FaceAroundVertexCirculator(mesh, v)
    face_indices = [f.idx() for f in fcir]    # Collect indices of all incident faces and print them in a single line
    print(f"The incident faces are: {' '.join(map(str, face_indices))}")
    # alternative to FaceAroundVertexCirculator, one can use mesh.faces(v) to access all faces incident to this vertex
    face_indices = [f.idx() for f in mesh.faces(v)]
    print(f"The incident faces are: {' '.join(map(str, face_indices))}")

print("------- Iterate all the edges ------")
for e in mesh.edges():
    # print the indices of the two end vertices
    print(f"Edge {e.idx()}: vertex {mesh.vertex(e, 0).idx()} - vertex {mesh.vertex(e, 1).idx()}")
    # print the indices of the two incident faces
    print(f"The two incident faces: face {mesh.face(e, 0).idx()} - face {mesh.face(e, 1).idx()}")

print("------- Iterate all the halfedges ------")
for h in mesh.halfedges():
    #  print its vertices
    print(f"Halfedge {h.idx()}: vertex {mesh.source(h).idx()} -> vertex {mesh.target(h).idx()}")
    #  print the incident face and that incident to its opposite
    print(f"Halfedge {h.idx()} -> face {mesh.face(h).idx()}. Opposite halfedge {mesh.opposite(h).idx()} -> face {mesh.face(mesh.opposite(h)).idx()}")



# # Uncomment the following line to visualize the model (overlaid with edges and vertices)
# viewer = easy3d.Viewer("Easy3D Viewer")
# viewer.add_model(mesh)
# mesh.renderer().get_lines_drawable("edges").set_visible(True)       # Ensure the wireframe is visible.
# mesh.renderer().get_points_drawable("vertices").set_visible(True)   # Ensure the vertices is visible.
# viewer.run()

Total running time of the script: (0 minutes 0.052 seconds)

Gallery generated by Sphinx-Gallery