def test_add_quad_to_polymesh(self):
        self.mesh = openmesh.PolyMesh()
        self.vhandle = []

        # Add some vertices
        self.vhandle.append(self.mesh.add_vertex(np.array([0, 0, 0])))
        self.vhandle.append(self.mesh.add_vertex(np.array([0, 1, 0])))
        self.vhandle.append(self.mesh.add_vertex(np.array([1, 1, 0])))
        self.vhandle.append(self.mesh.add_vertex(np.array([1, 0, 0])))

        # Add one face
        face_vhandles = []
        face_vhandles.append(self.vhandle[0])
        face_vhandles.append(self.vhandle[1])
        face_vhandles.append(self.vhandle[2])
        face_vhandles.append(self.vhandle[3])

        self.mesh.add_face(face_vhandles)

        # Test setup:
        #  1 === 2
        #  |     |
        #  |     |
        #  |     |
        #  0 === 3

        # Check setup
        self.assertEqual(self.mesh.n_vertices(), 4)
        self.assertEqual(self.mesh.n_faces(), 1)
 def test_init_with_arrays(self):
     points = self.mesh.points()
     face_vertex_indices = self.mesh.face_vertex_indices()
     # init polymesh
     polymesh = openmesh.PolyMesh(points, face_vertex_indices)
     self.assertEqual(polymesh.n_vertices(), self.mesh.n_vertices())
     self.assertEqual(polymesh.n_faces(), self.mesh.n_faces())
     # init trimesh (one face will be triangulated)
     trimesh = openmesh.TriMesh(points, face_vertex_indices)
     self.assertEqual(trimesh.n_vertices(), self.mesh.n_vertices())
     self.assertEqual(trimesh.n_faces(), self.mesh.n_faces() + 1)
     # init with empty points and faces
     trimesh = openmesh.TriMesh(np.empty((0, 3)), np.empty((0, 4)))
     self.assertEqual(trimesh.n_vertices(), 0)
     self.assertEqual(trimesh.n_faces(), 0)
     # init with empty points
     trimesh = openmesh.TriMesh(np.empty((0, 3)), face_vertex_indices)
     self.assertEqual(trimesh.n_vertices(), 0)
     self.assertEqual(trimesh.n_faces(), 0)
     # init with empty faces
     trimesh = openmesh.TriMesh(points, np.empty((0, 4)))
     self.assertEqual(trimesh.n_vertices(), self.mesh.n_vertices())
     self.assertEqual(trimesh.n_faces(), 0)
     # init with points only
     trimesh = openmesh.TriMesh(points)
     self.assertEqual(trimesh.n_vertices(), self.mesh.n_vertices())
     self.assertEqual(trimesh.n_faces(), 0)
     # init with wrong points shape
     with self.assertRaises(RuntimeError):
         openmesh.TriMesh(points[:, :2])
     # init with wrong faces shape
     with self.assertRaises(RuntimeError):
         openmesh.TriMesh(points, face_vertex_indices[:, :2])
     # init with points and invalid faces
     face_vertex_indices[1] = [-1, -1, -1, -1]
     face_vertex_indices[3] = [-1, -1, -1, -1]
     polymesh = openmesh.PolyMesh(points, face_vertex_indices)
     self.assertEqual(polymesh.n_vertices(), self.mesh.n_vertices())
     self.assertEqual(polymesh.n_faces(), self.mesh.n_faces() - 2)
def makeDrainMeshPaths(path, tolerance, cpus):
    import openmesh as om

    mesh = om.PolyMesh()
    om.read_mesh(mesh, path)

    drainCurves = drainMeshPaths(mesh, tolerance, cpus)
    outfile = r'C:\Users\Christian\Desktop\drainCurves.obj'
    result = om.write_mesh(drainCurves, outfile)

    if result:
        return True
    else:
        return False
Beispiel #4
0
    def __init__(self, mesh=None):

        self.opts = {
            'color': (1., 1., 1.),
            'edgeColor': (0.5, 0.5, 0.5),
            'pointColor': (1.0, 1.0, 0.0),
            'shader': standShader,
            'smooth': True,
            'computeNormals': False,
        }

        self._attributeMap = {
            "vertex": {
                "pos": {'default_value': [0, 0, 0], 'type': 'vector3', 'is_array': True}
            },
            "face": {},
            "edge": {},
            "detail": {}
        }

        self.signals = MeshSignals()
        self._selected = False

        self.edge_colors = {
            True: (1.0, 1.0, 0.0, 1.0),
            False: (0.15, 0.15, 0.15, 1.0)
        }

        if mesh is None:
            self._mesh = openmesh.PolyMesh()
        else:
            self._mesh = mesh
        self._mesh.release_vertex_texcoords1D()
        self._mesh.release_vertex_texcoords2D()
        self._mesh.release_vertex_texcoords3D()
        self._mesh.release_vertex_colors()
        self._mesh.release_halfedge_texcoords1D()
        self._mesh.release_halfedge_texcoords2D()
        self._mesh.release_halfedge_texcoords3D()
        self._mesh.release_halfedge_normals()
        self._mesh.release_halfedge_colors()
        self._mesh.release_face_colors()
        self._mesh.release_face_texture_index()
        self._mesh.release_edge_colors()

        self.bbox = BBox()
        self._GLFaces = None
        self._flatColor = 0
        self.__view = None
Beispiel #5
0
    def run(self):
        if not self.copyData():
            return

        if self.geo.getNumFaces() == 0 or self.geo.getNumVertexes() == 0:
            return

        mesh = self.geo.getTriangulateMesh()
        v = mesh.points()
        f = mesh.face_vertex_indices()

        v, f = igl.collapse_small_triangles(v, f, 0.1)

        self.geo._mesh = openmesh.PolyMesh()
        self.geo.addVertices(v)
        self.geo.addFaces(f)
 def setUp(self):
     self.mesh = openmesh.PolyMesh()
     vh0 = self.mesh.add_vertex(np.array([0, 0, 0]))
     vh1 = self.mesh.add_vertex(np.array([1, 0, 0]))
     vh2 = self.mesh.add_vertex(np.array([1, 1, 0]))
     vh3 = self.mesh.add_vertex(np.array([0, 1, 0]))
     vh4 = self.mesh.add_vertex(np.array([2, 0, 0]))
     vh5 = self.mesh.add_vertex(np.array([3, 0, 0]))
     vh6 = self.mesh.add_vertex(np.array([3, 1, 0]))
     vh7 = self.mesh.add_vertex(np.array([2, 1, 0]))
     vh8 = self.mesh.add_vertex(np.array([4, 0, 0]))
     vh9 = self.mesh.add_vertex(np.array([5, 0, 0]))
     vh10 = self.mesh.add_vertex(np.array([5, 1, 0]))
     self.mesh.add_face(vh0, vh1, vh2, vh3)
     self.mesh.add_face(vh4, vh5, vh6)
     self.mesh.add_face(vh6, vh7, vh4)
     self.mesh.add_face(vh8, vh9, vh10)
Beispiel #7
0
 def mesh_to_openmesh(self) -> Mesh:
     """Convert the model mesh to a COMPAS mesh data structure."""
     try:
         import openmesh as om  # noqa: F401
     except ImportError:
         print('OpenMesh is not installed. Install using `pip install openmesh`.')
         raise
     vertices, faces = self.mesh_to_vertices_and_faces()
     if len(faces[0]) == 3:
         mesh = om.TriMesh()
     elif len(faces[0]) == 4:
         mesh = om.PolyMesh()
     vertex_index = {}
     for vertex in vertices:
         index = mesh.add_vertex(vertices[vertex])
         vertex_index[vertex] = index
     for face in faces:
         mesh.add_face(* [vertex_index[vertex] for vertex in face])
     return mesh
Beispiel #8
0
def colormap_vertex_color(fn,
                          v0,
                          f0,
                          scalar_field,
                          scalar_min=None,
                          scalar_max=None,
                          cmap='jet'):
    '''
    save as a *.off file. OpenMesh does not write vertex colors in obj files.
    '''
    cmap = cm.get_cmap(cmap)
    if scalar_min is None and scalar_max is None:
        field = scalar_field.copy()
    else:
        field = np.clip(scalar_field, scalar_min, scalar_max)
    m0 = field.min()
    m1 = field.max()
    field = (field - m0) / (m1 - m0)
    mesh = om.PolyMesh(v0, f0)
    vcolors = mesh.vertex_colors()
    vcolors[:, :3] = cmap(field)[:, :3]
    om.write_mesh(fn, mesh, vertex_color=True)
    def test_split_copy_polymesh(self):
        self.mesh = openmesh.PolyMesh()
        self.vhandle = []

        # Add some vertices
        self.vhandle.append(self.mesh.add_vertex(openmesh.Vec3d(0, 0, 0)))
        self.vhandle.append(self.mesh.add_vertex(openmesh.Vec3d(0, 1, 0)))
        self.vhandle.append(self.mesh.add_vertex(openmesh.Vec3d(1, 1, 0)))
        self.vhandle.append(self.mesh.add_vertex(openmesh.Vec3d(1, 0, 0)))
        self.vhandle.append(self.mesh.add_vertex(openmesh.Vec3d(0.5, 0.5, 0)))

        # Add one face
        face_vhandles = []

        face_vhandles.append(self.vhandle[0])
        face_vhandles.append(self.vhandle[1])
        face_vhandles.append(self.vhandle[2])
        face_vhandles.append(self.vhandle[3])

        fh = self.mesh.add_face(face_vhandles)

        # Test setup:
        #  1 === 2
        #  |     |
        #  |     |
        #  |     |
        #  0 === 3

        # Set property
        fprop_int = openmesh.FPropHandle()
        self.mesh.add_property(fprop_int)
        self.mesh.set_property(fprop_int, fh, 999)

        # Split face with new vertex
        self.mesh.split_copy(fh, self.vhandle[4])

        # Check setup
        for f in self.mesh.faces():
            self.assertEqual(self.mesh.property(fprop_int, f), 999)
    def test_split_copy_polymesh(self):
        self.mesh = openmesh.PolyMesh()
        self.vhandle = []

        # Add some vertices
        self.vhandle.append(self.mesh.add_vertex(np.array([0, 0, 0])))
        self.vhandle.append(self.mesh.add_vertex(np.array([0, 1, 0])))
        self.vhandle.append(self.mesh.add_vertex(np.array([1, 1, 0])))
        self.vhandle.append(self.mesh.add_vertex(np.array([1, 0, 0])))
        self.vhandle.append(self.mesh.add_vertex(np.array([0.5, 0.5, 0])))

        # Add one face
        face_vhandles = []

        face_vhandles.append(self.vhandle[0])
        face_vhandles.append(self.vhandle[1])
        face_vhandles.append(self.vhandle[2])
        face_vhandles.append(self.vhandle[3])

        fh = self.mesh.add_face(face_vhandles)

        # Test setup:
        #  1 === 2
        #  |     |
        #  |     |
        #  |     |
        #  0 === 3

        # Set property
        self.mesh.set_face_property("fprop_int", fh, 999)

        # Split face with new vertex
        self.mesh.split_copy(fh, self.vhandle[4])

        # Check setup
        for fh in self.mesh.faces():
            self.assertEqual(self.mesh.face_property("fprop_int", fh), 999)
Beispiel #11
0
    cam_data = db.calib[basename]
    cam = cam_utils.Camera(basename, cam_data['A'], cam_data['R'],
                           cam_data['T'], db.shape[0], db.shape[1])

    player_list = data[basename]

    frame_mesh_points = np.zeros((0, 3))
    frame_mesh_faces = np.zeros((0, 3))

    uvs_atlas = []
    textures_atlas = []

    cnt = 0
    for p in range(len(player_list)):
        mesh = om.PolyMesh()

        ply_name = join(opt.path_to_data, 'players', 'meshes',
                        player_list[p]['mesh'] + '.ply')
        vertex_data, face_data, _, _ = io.read_ply(ply_name)

        pointcloud, pc_colors, _ = io.ply_to_numpy(vertex_data)
        pc_centered = pointcloud - np.mean(pointcloud, axis=0)

        points2d, depth = cam.project(pointcloud)
        faces = mesh_utils.triangulate_depthmap_points(points2d,
                                                       depth,
                                                       depth_thresh=0.1)

        vertex_handle = []
        for i in range(pointcloud.shape[0]):
 def test_deletete_half_poly_mesh_cube_with_edge_status(self):
     self.mesh = openmesh.PolyMesh()
     self.vhandle = []
     
     # Add some vertices
     self.vhandle.append(self.mesh.add_vertex(openmesh.Vec3d(-1, -1,  1)))
     self.vhandle.append(self.mesh.add_vertex(openmesh.Vec3d( 1, -1,  1)))
     self.vhandle.append(self.mesh.add_vertex(openmesh.Vec3d( 1,  1,  1)))
     self.vhandle.append(self.mesh.add_vertex(openmesh.Vec3d(-1,  1,  1)))
     self.vhandle.append(self.mesh.add_vertex(openmesh.Vec3d(-1, -1, -1)))
     self.vhandle.append(self.mesh.add_vertex(openmesh.Vec3d( 1, -1, -1)))
     self.vhandle.append(self.mesh.add_vertex(openmesh.Vec3d( 1,  1, -1)))
     self.vhandle.append(self.mesh.add_vertex(openmesh.Vec3d(-1,  1, -1)))
     
     # Add six faces to form a cube
     face_vhandles = []
     face_vhandles.append(self.vhandle[0])
     face_vhandles.append(self.vhandle[1])
     face_vhandles.append(self.vhandle[2])
     face_vhandles.append(self.vhandle[3])
     self.mesh.add_face(face_vhandles)
     
     face_vhandles = []
     face_vhandles.append(self.vhandle[7])
     face_vhandles.append(self.vhandle[6])
     face_vhandles.append(self.vhandle[5])
     face_vhandles.append(self.vhandle[4])
     self.mesh.add_face(face_vhandles)
     
     face_vhandles = []
     face_vhandles.append(self.vhandle[1])
     face_vhandles.append(self.vhandle[0])
     face_vhandles.append(self.vhandle[4])
     face_vhandles.append(self.vhandle[5])
     self.mesh.add_face(face_vhandles)
     
     face_vhandles = []
     face_vhandles.append(self.vhandle[2])
     face_vhandles.append(self.vhandle[1])
     face_vhandles.append(self.vhandle[5])
     face_vhandles.append(self.vhandle[6])
     self.mesh.add_face(face_vhandles)
     
     face_vhandles = []
     face_vhandles.append(self.vhandle[3])
     face_vhandles.append(self.vhandle[2])
     face_vhandles.append(self.vhandle[6])
     face_vhandles.append(self.vhandle[7])
     self.mesh.add_face(face_vhandles)
     
     face_vhandles = []
     face_vhandles.append(self.vhandle[0])
     face_vhandles.append(self.vhandle[3])
     face_vhandles.append(self.vhandle[7])
     face_vhandles.append(self.vhandle[4])
     self.mesh.add_face(face_vhandles)
     
     # Test setup:
     #
     #    3 ======== 2
     #   /          /|
     #  /          / |      z
     # 0 ======== 1  |      |
     # |          |  |      |   y
     # |  7       |  6      |  /
     # |          | /       | /
     # |          |/        |/
     # 4 ======== 5         -------> x
     
     # Check setup
     self.assertEqual(self.mesh.n_edges(), 12)
     self.assertEqual(self.mesh.n_halfedges(), 24)
     self.assertEqual(self.mesh.n_vertices(), 8)
     self.assertEqual(self.mesh.n_faces(), 6)
     
     # =====================================================
     # Now we delete half of the mesh
     # =====================================================
     self.mesh.request_face_status()
     self.mesh.request_vertex_status()
     self.mesh.request_edge_status()
     self.mesh.request_halfedge_status()
     
     n_face_to_delete = self.mesh.n_faces() / 2
     
     # Check the variable
     self.assertEqual(n_face_to_delete, 3)
     
     for i in range(int(n_face_to_delete)):
         self.mesh.delete_face(self.mesh.face_handle(i))
         
     # =====================================================
     # Check config afterwards
     # =====================================================
     
     self.assertEqual(self.mesh.n_edges(), 12)
     self.assertEqual(self.mesh.n_halfedges(), 24)
     self.assertEqual(self.mesh.n_vertices(), 8)
     self.assertEqual(self.mesh.n_faces(), 6)
     
     # =====================================================
     # Cleanup and recheck
     # =====================================================
     
     self.mesh.garbage_collection()
     
     self.assertEqual(self.mesh.n_edges(), 10)
     self.assertEqual(self.mesh.n_halfedges(), 20)
     self.assertEqual(self.mesh.n_vertices(), 8)
     self.assertEqual(self.mesh.n_faces(), 3)
Beispiel #13
0
def split_mesh_complete(V, F, edges, ratios):
    """
    Split mesh. This is the complete version. Maybe overshoot.

    Parameters
    ----------
    V : numpy.array
    F : numpy.array
    edges : numpy.array, given in the order of the curve
    ratios : numpy.array, corresponding to rows in edges.
        p0 * (1-r) + p1 * r
    Returns
    -------
    mesh : openmesh.TriMesh
    index : list (int)
    """

    # unify the edges/ratios, make sure e[0] <= e[1]
    E = edges.copy()
    R = ratios.copy()
    M = om.PolyMesh(V, F)
    
    M.edge_property('split')
    for eh in M.edges():
        M.set_edge_property('split', eh, [])
    for i in range(R.size):
        if E[i, 0] != E[i, 1]:
            if E[i, 1] < E[i, 0]:
                E[i, 1], E[i, 0] = E[i, 0], E[i, 1]
                R[i] = 1.0 - R[i]
            vh0 = M.vertex_handle(E[i, 0])
            vh1 = M.vertex_handle(E[i, 1])
            heh = M.find_halfedge(vh0, vh1)
            assert heh.is_valid(), 'invalid input edges (row %d)'%i
            eh = M.edge_handle(heh)
            L = M.edge_property('split', eh)
            if len(L) > 0:
                # print('split the same edge several times!')
                L.append(i)
                M.set_edge_property('split', eh, L)
            else:
                M.set_edge_property('split', eh, [i])

    pts0 = V[E[:, 0], :]
    pts1 = V[E[:, 1], :]
    curve_pts = np.multiply(pts0, 1.-R[:, np.newaxis]) + \
        np.multiply(pts1, R[:, np.newaxis])

    new_index = np.empty((R.size,), 'i')
    for i in range(E.shape[0]):
        if E[i, 0] == E[i, 1]:
            new_index[i] = E[i, 0]

    for eh in M.edges():
        L = M.edge_property('split', eh)
        if L is None or len(L) == 0:
            continue
        elif len(L) == 1:
            i = L[0]
            p = curve_pts[i, :]
            heh = M.find_halfedge(M.vertex_handle(E[i, 0]),
                                  M.vertex_handle(E[i, 1]))
            eh_ = M.edge_handle(heh)
            vh = M.add_vertex(p)
            M.split_edge(eh_, vh)
            new_index[i] = vh.idx()
        else:
            heh = M.halfedge_handle(eh, 0)
            vh0 = M.from_vertex_handle(heh)
            vh1 = M.to_vertex_handle(heh)
            if vh0.idx() > vh1.idx():
                vh0, vh1 = vh1, vh0
            L.sort(key=lambda x:R[x])
            for i in L:
                p = curve_pts[i, :]
                vh = M.add_vertex(p)
                heh = M.find_halfedge(vh0, vh1)
                assert(heh.is_valid())
                eh_ = M.edge_handle(heh)
                M.split_edge(eh_, vh)
                vh0 = vh
                new_index[i] = vh.idx()

    def find_shared_face(v0, v1):
        f0 = [fh.idx() for fh in M.vf(v0)]
        f1 = [fh.idx() for fh in M.vf(v1)]
        f = list(set(f0).intersection(f1))
        if len(f) != 1:
            print(len(f))
            assert(False)
        return M.face_handle(f[0])

    for i in range(R.size-1):
        v0 = M.vertex_handle(new_index[i])
        v1 = M.vertex_handle(new_index[i+1])
        heh = M.find_halfedge(v0, v1)
        if not heh.is_valid():
            # find the face containing both vertices
            # split the face by adding edge (v0, v1)
            fh = find_shared_face(v0, v1)
            vhs = [vh for vh in M.fv(fh)]
            vs = [vh.idx() for vh in vhs]
            i0 = vs.index(v0.idx())
            i1 = vs.index(v1.idx())
            if i0 > i1:
                i0, i1 = i1, i0
            f0 = vhs[i0:i1+1]
            f1 = vhs[i1:] + vhs[:i0+1]
            M.delete_face(fh, delete_isolated_vertices=False)
            M.add_face(f0)
            M.add_face(f1)
    M.garbage_collection()
    #return M, new_index  # return polymesh

    def triangulate(M, fh):
        # using deque is an overshoot.
        vhs = [vh for vh in M.fv(fh)]
        n = len(vhs)
        if n == 3:
            return
        pts = np.empty((n, 3))
        for i in range(n):
            pts[i] = M.point(vhs[i])
        left = [i-1 for i in range(n)]
        right = [(i+1)%n for i in range(n)]
        edge_vecs = pts[right] - pts
        norm = np.linalg.norm(edge_vecs, axis=1)
        edge_vecs_norms = edge_vecs / norm[:, np.newaxis]
        minus_cosines = np.sum(edge_vecs_norms[left]*edge_vecs_norms, axis=1)
        if n == 4:
            # handle the simple case seperately.
            k = np.argmax(minus_cosines)
            f0 = [vhs[(k+i)%4] for i in range(3)]
            f1 = [vhs[(k+2+i)%4] for i in range(3)]
            M.delete_face(fh, delete_isolated_vertices=False)
            M.add_face(f0)
            M.add_face(f1)
        else:
            # find three smallest angles
            idx = sorted(np.argpartition(minus_cosines, 3)[:3])
            e0 = [i for i in range(idx[0], idx[1]+1)]
            e1 = [i for i in range(idx[1], idx[2]+1)]
            e2 = [i for i in range(idx[2]-n, idx[0]+1)]
            # rotate to make sure e0 is splitted.
            if len(e0) == 2:
                if len(e1) > 2:
                    e0, e1, e2 = e1, e2, e0
                elif len(e2) > 2:
                    e0, e1, e2 = e2, e0, e1
            M.delete_face(fh, delete_isolated_vertices=False)
            for i in range(1, len(e0)-2):
                M.add_face([vhs[i] for i in [e0[i], e0[i+1], e1[-1]]])
            for i in range(len(e1)-1):
                M.add_face([vhs[i] for i in [e1[i], e1[i+1], e0[-2]]])
            for i in range(len(e2)-1):
                M.add_face([vhs[i] for i in [e2[i], e2[i+1], e0[1]]])

    # May generate degenerated triangles if using the build-in triangulation by converting PolyMesh to TriMesh
    # Tiranulate explicitly!
    for fh in M.faces():
        triangulate(M, fh)
    M.garbage_collection()

    mesh = om.TriMesh(M.points(), M.face_vertex_indices())
    return mesh, new_index
    def test_create_poly_mesh_cube(self):
        self.mesh = openmesh.PolyMesh()
        self.vhandle = []

        # Add some vertices
        self.vhandle.append(self.mesh.add_vertex(np.array([-1, -1, 1])))
        self.vhandle.append(self.mesh.add_vertex(np.array([1, -1, 1])))
        self.vhandle.append(self.mesh.add_vertex(np.array([1, 1, 1])))
        self.vhandle.append(self.mesh.add_vertex(np.array([-1, 1, 1])))
        self.vhandle.append(self.mesh.add_vertex(np.array([-1, -1, -1])))
        self.vhandle.append(self.mesh.add_vertex(np.array([1, -1, -1])))
        self.vhandle.append(self.mesh.add_vertex(np.array([1, 1, -1])))
        self.vhandle.append(self.mesh.add_vertex(np.array([-1, 1, -1])))

        # Add six faces to form a cube
        face_vhandles = []
        face_vhandles.append(self.vhandle[0])
        face_vhandles.append(self.vhandle[1])
        face_vhandles.append(self.vhandle[2])
        face_vhandles.append(self.vhandle[3])
        self.mesh.add_face(face_vhandles)

        face_vhandles = []
        face_vhandles.append(self.vhandle[7])
        face_vhandles.append(self.vhandle[6])
        face_vhandles.append(self.vhandle[5])
        face_vhandles.append(self.vhandle[4])
        self.mesh.add_face(face_vhandles)

        face_vhandles = []
        face_vhandles.append(self.vhandle[1])
        face_vhandles.append(self.vhandle[0])
        face_vhandles.append(self.vhandle[4])
        face_vhandles.append(self.vhandle[5])
        self.mesh.add_face(face_vhandles)

        face_vhandles = []
        face_vhandles.append(self.vhandle[2])
        face_vhandles.append(self.vhandle[1])
        face_vhandles.append(self.vhandle[5])
        face_vhandles.append(self.vhandle[6])
        self.mesh.add_face(face_vhandles)

        face_vhandles = []
        face_vhandles.append(self.vhandle[3])
        face_vhandles.append(self.vhandle[2])
        face_vhandles.append(self.vhandle[6])
        face_vhandles.append(self.vhandle[7])
        self.mesh.add_face(face_vhandles)

        face_vhandles = []
        face_vhandles.append(self.vhandle[0])
        face_vhandles.append(self.vhandle[3])
        face_vhandles.append(self.vhandle[7])
        face_vhandles.append(self.vhandle[4])
        self.mesh.add_face(face_vhandles)

        # Test setup:
        #
        #    3 ======== 2
        #   /          /|
        #  /          / |      z
        # 0 ======== 1  |      |
        # |          |  |      |   y
        # |  7       |  6      |  /
        # |          | /       | /
        # |          |/        |/
        # 4 ======== 5         -------> x

        # Check setup
        self.assertEqual(self.mesh.n_edges(), 12)
        self.assertEqual(self.mesh.n_halfedges(), 24)
        self.assertEqual(self.mesh.n_vertices(), 8)
        self.assertEqual(self.mesh.n_faces(), 6)