Note
Go to the end to download the full example code.
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)