-
Alexander Dielen authoredAlexander Dielen authored
test_trimesh_collapse.py 17.65 KiB
import unittest
import openmesh
import numpy as np
class Collapse(unittest.TestCase):
def setUp(self):
self.mesh = openmesh.TriMesh()
self.vhandle = []
def test_collapse_quad_with_center(self):
# 0--------1
# |\ /|
# | \ / |
# | \ / |
# | 2 |
# | / \ |
# | / \ |
# 3--------4
# Add some vertices
self.vhandle.append(self.mesh.add_vertex(np.array([0, 0, 0])))
self.vhandle.append(self.mesh.add_vertex(np.array([2, 0, 0])))
self.vhandle.append(self.mesh.add_vertex(np.array([1, 1, 0])))
self.vhandle.append(self.mesh.add_vertex(np.array([0, 2, 0])))
self.vhandle.append(self.mesh.add_vertex(np.array([2, 2, 0])))
# Add four faces
face_vhandles = []
face_vhandles.append(self.vhandle[0])
face_vhandles.append(self.vhandle[2])
face_vhandles.append(self.vhandle[1])
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[2])
self.mesh.add_face(face_vhandles)
face_vhandles = []
face_vhandles.append(self.vhandle[4])
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[4])
face_vhandles.append(self.vhandle[1])
face_vhandles.append(self.vhandle[2])
self.mesh.add_face(face_vhandles)
# Get the halfedge
v2v1 = self.mesh.find_halfedge(self.vhandle[2], self.vhandle[1])
self.assertTrue(v2v1.is_valid())
self.assertTrue(self.mesh.is_collapse_ok(v2v1))
# Execute it as a crash test
self.mesh.collapse(v2v1)
def test_collapse_tetrahedron_complex(self):
# 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 four faces
face_vhandles = []
face_vhandles.append(self.vhandle[0])
face_vhandles.append(self.vhandle[1])
face_vhandles.append(self.vhandle[2])
self.mesh.add_face(face_vhandles)
face_vhandles = []
face_vhandles.append(self.vhandle[0])
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[2])
face_vhandles.append(self.vhandle[1])
face_vhandles.append(self.vhandle[3])
self.mesh.add_face(face_vhandles)
face_vhandles = []
face_vhandles.append(self.vhandle[3])
face_vhandles.append(self.vhandle[1])
face_vhandles.append(self.vhandle[0])
self.mesh.add_face(face_vhandles)
v0v1 = self.mesh.halfedge_handle(0)
v1v0 = self.mesh.opposite_halfedge_handle(v0v1)
v1vL = self.mesh.next_halfedge_handle(v0v1)
vLv1 = self.mesh.opposite_halfedge_handle(v1vL)
vLv0 = self.mesh.next_halfedge_handle(v1vL)
v0vL = self.mesh.opposite_halfedge_handle(vLv0)
vLvR = self.mesh.next_halfedge_handle(v0vL)
vRvL = self.mesh.opposite_halfedge_handle(vLvR)
v0vR = self.mesh.next_halfedge_handle(v1v0)
vRv0 = self.mesh.opposite_halfedge_handle(v0vR)
vRv1 = self.mesh.next_halfedge_handle(v0vR)
v1vR = self.mesh.opposite_halfedge_handle(vRv1)
v0 = self.mesh.from_vertex_handle(v0v1)
v1 = self.mesh.to_vertex_handle(v0v1)
vL = self.mesh.to_vertex_handle(self.mesh.next_halfedge_handle(v0v1))
vR = self.mesh.to_vertex_handle(self.mesh.next_halfedge_handle(v1v0))
# ===================================================================
# Check preconditions
# ===================================================================
self.assertTrue(self.mesh.is_collapse_ok(v0v1))
self.assertTrue(self.mesh.is_collapse_ok(v1v0))
# Test the Vertex indices
self.assertEqual(v0.idx(), 0)
self.assertEqual(v1.idx(), 1)
self.assertEqual(vL.idx(), 2)
self.assertEqual(vR.idx(), 3)
# Check the halfedges
self.assertEqual(v0v1.idx(), 0)
self.assertEqual(v1v0.idx(), 1)
self.assertEqual(v1vL.idx(), 2)
self.assertEqual(vLv1.idx(), 3)
self.assertEqual(vLv0.idx(), 4)
self.assertEqual(v0vL.idx(), 5)
self.assertEqual(vLvR.idx(), 6)
self.assertEqual(vRvL.idx(), 7)
self.assertEqual(vRv0.idx(), 8)
self.assertEqual(v0vR.idx(), 9)
self.assertEqual(v1vR.idx(), 10)
self.assertEqual(vRv1.idx(), 11)
# ===================================================================
# Execute collapse
# ===================================================================
self.mesh.collapse(v0v1)
# ===================================================================
# Check configuration afterwards
# ===================================================================
# Now the configuration should look like this:
# The numbers at the side denote the halfedges
# 1
# / \
# / \
# // \\
# 3/2 11\10
# // \\
# / 6--> \
# 2 ----------- 3
# <--7
self.assertEqual(self.mesh.n_faces(), 4)
# Check if the right vertices got deleted
self.assertTrue(self.mesh.is_deleted(self.mesh.face_handle(0)))
self.assertFalse(self.mesh.is_deleted(self.mesh.face_handle(1)))
self.assertFalse(self.mesh.is_deleted(self.mesh.face_handle(2)))
self.assertTrue(self.mesh.is_deleted(self.mesh.face_handle(3)))
# Check the vertices of the two remaining faces
fh_1 = self.mesh.face_handle(1)
fh_2 = self.mesh.face_handle(2)
fv_it = self.mesh.fv(fh_1)
self.assertEqual(next(fv_it).idx(), 1)
self.assertEqual(next(fv_it).idx(), 2)
self.assertEqual(next(fv_it).idx(), 3)
fv_it = self.mesh.fv(fh_2)
self.assertEqual(next(fv_it).idx(), 2)
self.assertEqual(next(fv_it).idx(), 1)
self.assertEqual(next(fv_it).idx(), 3)
# Get the first halfedge of face 1
fh_1_he = self.mesh.halfedge_handle(fh_1)
self.assertEqual(fh_1_he.idx(), 11)
self.assertEqual(self.mesh.to_vertex_handle(fh_1_he).idx(), 1)
next_he = self.mesh.next_halfedge_handle(fh_1_he)
self.assertEqual(next_he.idx(), 2)
self.assertEqual(self.mesh.to_vertex_handle(next_he).idx(), 2)
next_he = self.mesh.next_halfedge_handle(next_he)
self.assertEqual(next_he.idx(), 6)
self.assertEqual(self.mesh.to_vertex_handle(next_he).idx(), 3)
# Get the first halfedge of face 2
fh_2_he = self.mesh.halfedge_handle(fh_2)
self.assertEqual(fh_2_he.idx(), 7)
self.assertEqual(self.mesh.to_vertex_handle(fh_2_he).idx(), 2)
next_he = self.mesh.next_halfedge_handle(fh_2_he)
self.assertEqual(next_he.idx(), 3)
self.assertEqual(self.mesh.to_vertex_handle(next_he).idx(), 1)
next_he = self.mesh.next_halfedge_handle(next_he)
self.assertEqual(next_he.idx(), 10)
self.assertEqual(self.mesh.to_vertex_handle(next_he).idx(), 3)
# Vertex 1 outgoing
voh_it = self.mesh.voh(self.mesh.vertex_handle(1))
self.assertEqual(next(voh_it).idx(), 10)
self.assertEqual(next(voh_it).idx(), 2)
with self.assertRaises(StopIteration):
next(voh_it)
# Vertex 2 outgoing
voh_it = self.mesh.voh(self.mesh.vertex_handle(2))
self.assertEqual(next(voh_it).idx(), 3)
self.assertEqual(next(voh_it).idx(), 6)
with self.assertRaises(StopIteration):
next(voh_it)
# Vertex 2 outgoing
voh_it = self.mesh.voh(self.mesh.vertex_handle(3))
self.assertEqual(next(voh_it).idx(), 11)
self.assertEqual(next(voh_it).idx(), 7)
with self.assertRaises(StopIteration):
next(voh_it)
# ===================================================================
# Cleanup
# ===================================================================
self.mesh.garbage_collection()
# ===================================================================
# Check configuration afterwards
# ===================================================================
# Now the configuration should look like this:
# The numbers at the side denote the halfedges
# 0
# / \
# / \
# // \\
# 4/5 0\1
# // \\
# / 3--> \
# 2 ----------- 1
# <--2
self.assertEqual(self.mesh.n_faces(), 2)
# Check the vertices of the two remaining faces
fh_0 = self.mesh.face_handle(0)
fh_1 = self.mesh.face_handle(1)
fv_it = self.mesh.fv(fh_0)
self.assertEqual(next(fv_it).idx(), 2)
self.assertEqual(next(fv_it).idx(), 1)
self.assertEqual(next(fv_it).idx(), 0)
fv_it = self.mesh.fv(fh_1)
self.assertEqual(next(fv_it).idx(), 1)
self.assertEqual(next(fv_it).idx(), 2)
self.assertEqual(next(fv_it).idx(), 0)
# Get the first halfedge of face 1
fh_0_he = self.mesh.halfedge_handle(fh_0)
self.assertEqual(fh_0_he.idx(), 5)
self.assertEqual(self.mesh.to_vertex_handle(fh_0_he).idx(), 2)
next_he = self.mesh.next_halfedge_handle(fh_0_he)
self.assertEqual(next_he.idx(), 3)
self.assertEqual(self.mesh.to_vertex_handle(next_he).idx(), 1)
next_he = self.mesh.next_halfedge_handle(next_he)
self.assertEqual(next_he.idx(), 0)
self.assertEqual(self.mesh.to_vertex_handle(next_he).idx(), 0)
# Get the first halfedge of face 1
fh_1_he = self.mesh.halfedge_handle(fh_1)
self.assertEqual(fh_1_he.idx(), 1)
self.assertEqual(self.mesh.to_vertex_handle(fh_1_he).idx(), 1)
next_he = self.mesh.next_halfedge_handle(fh_1_he)
self.assertEqual(next_he.idx(), 2)
self.assertEqual(self.mesh.to_vertex_handle(next_he).idx(), 2)
next_he = self.mesh.next_halfedge_handle(next_he)
self.assertEqual(next_he.idx(), 4)
self.assertEqual(self.mesh.to_vertex_handle(next_he).idx(), 0)
# Vertex 0 outgoing
voh_it = self.mesh.voh(self.mesh.vertex_handle(0))
self.assertEqual(next(voh_it).idx(), 1)
self.assertEqual(next(voh_it).idx(), 5)
with self.assertRaises(StopIteration):
next(voh_it)
# Vertex 1 outgoing
voh_it = self.mesh.voh(self.mesh.vertex_handle(1))
self.assertEqual(next(voh_it).idx(), 0)
self.assertEqual(next(voh_it).idx(), 2)
with self.assertRaises(StopIteration):
next(voh_it)
# Vertex 2 outgoing
voh_it = self.mesh.voh(self.mesh.vertex_handle(2))
self.assertEqual(next(voh_it).idx(), 3)
self.assertEqual(next(voh_it).idx(), 4)
with self.assertRaises(StopIteration):
next(voh_it)
self.assertFalse(self.mesh.is_collapse_ok(self.mesh.halfedge_handle(0)))
self.assertFalse(self.mesh.is_collapse_ok(self.mesh.halfedge_handle(1)))
self.assertFalse(self.mesh.is_collapse_ok(self.mesh.halfedge_handle(2)))
self.assertFalse(self.mesh.is_collapse_ok(self.mesh.halfedge_handle(3)))
self.assertFalse(self.mesh.is_collapse_ok(self.mesh.halfedge_handle(4)))
self.assertFalse(self.mesh.is_collapse_ok(self.mesh.halfedge_handle(5)))
def test_collapse_tetrahedron(self):
# Add some vertices
self.vhandle.append(self.mesh.add_vertex(np.array([ 0, 0, 0])))
self.vhandle.append(self.mesh.add_vertex(np.array([ 1, 0, 0])))
self.vhandle.append(self.mesh.add_vertex(np.array([ 0, -1, 0])))
self.vhandle.append(self.mesh.add_vertex(np.array([ 0, 1, 0])))
self.vhandle.append(self.mesh.add_vertex(np.array([-1, 0, 0])))
# Add six faces
face_vhandles = []
face_vhandles.append(self.vhandle[0])
face_vhandles.append(self.vhandle[4])
face_vhandles.append(self.vhandle[2])
self.mesh.add_face(face_vhandles)
face_vhandles = []
face_vhandles.append(self.vhandle[3])
face_vhandles.append(self.vhandle[4])
face_vhandles.append(self.vhandle[0])
self.mesh.add_face(face_vhandles)
face_vhandles = []
face_vhandles.append(self.vhandle[2])
face_vhandles.append(self.vhandle[4])
face_vhandles.append(self.vhandle[3])
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[0])
self.mesh.add_face(face_vhandles)
face_vhandles = []
face_vhandles.append(self.vhandle[0])
face_vhandles.append(self.vhandle[1])
face_vhandles.append(self.vhandle[3])
self.mesh.add_face(face_vhandles)
# =============================================
# Collapse halfedge from 0 to 4
# =============================================
heh_collapse1 = self.mesh.halfedge_handle(0)
self.assertEqual(self.mesh.to_vertex_handle(heh_collapse1).idx(), 4)
self.assertEqual(self.mesh.from_vertex_handle(heh_collapse1).idx(), 0)
self.assertTrue(self.mesh.is_collapse_ok(heh_collapse1))
self.mesh.collapse(heh_collapse1)
heh_collapse2 = self.mesh.halfedge_handle(2)
self.assertEqual(self.mesh.to_vertex_handle(heh_collapse2).idx(), 2)
self.assertEqual(self.mesh.from_vertex_handle(heh_collapse2).idx(), 4)
self.assertTrue(self.mesh.is_collapse_ok(heh_collapse2))
self.mesh.collapse(heh_collapse2)
heh_collapse3 = self.mesh.halfedge_handle(6)
self.assertEqual(self.mesh.to_vertex_handle(heh_collapse3).idx(), 2)
self.assertEqual(self.mesh.from_vertex_handle(heh_collapse3).idx(), 3)
self.assertFalse(self.mesh.is_collapse_ok(heh_collapse3))
def test_large_collapse_halfedge(self):
# Add some vertices
self.vhandle.append(self.mesh.add_vertex(np.array([ 0, 1, 0])))
self.vhandle.append(self.mesh.add_vertex(np.array([ 1, 0, 0])))
self.vhandle.append(self.mesh.add_vertex(np.array([ 2, 1, 0])))
self.vhandle.append(self.mesh.add_vertex(np.array([ 0, -1, 0])))
self.vhandle.append(self.mesh.add_vertex(np.array([ 2, -1, 0])))
self.vhandle.append(self.mesh.add_vertex(np.array([-1, 0, 0])))
self.vhandle.append(self.mesh.add_vertex(np.array([ 3, 0, 0])))
# Add six faces
face_vhandles = []
face_vhandles.append(self.vhandle[0])
face_vhandles.append(self.vhandle[5])
face_vhandles.append(self.vhandle[1])
self.mesh.add_face(face_vhandles)
face_vhandles = []
face_vhandles.append(self.vhandle[1])
face_vhandles.append(self.vhandle[5])
face_vhandles.append(self.vhandle[3])
self.mesh.add_face(face_vhandles)
face_vhandles = []
face_vhandles.append(self.vhandle[0])
face_vhandles.append(self.vhandle[1])
face_vhandles.append(self.vhandle[2])
self.mesh.add_face(face_vhandles)
face_vhandles = []
face_vhandles.append(self.vhandle[1])
face_vhandles.append(self.vhandle[3])
face_vhandles.append(self.vhandle[4])
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[4])
self.mesh.add_face(face_vhandles)
face_vhandles = []
face_vhandles.append(self.vhandle[2])
face_vhandles.append(self.vhandle[4])
face_vhandles.append(self.vhandle[6])
self.mesh.add_face(face_vhandles)
# Test setup:
# 0 ==== 2
# / \ /|\
# / \ / | \
# 5 --- 1 | 6
# \ / \ | /
# \ / \|/
# 3 ==== 4
# =============================================
# Collapse halfedge from 1 to 4
# =============================================
heh_collapse = openmesh.HalfedgeHandle()
for he in self.mesh.halfedges():
if self.mesh.from_vertex_handle(he).idx() == 1 and self.mesh.to_vertex_handle(he).idx() == 4:
heh_collapse = he
# Check our halfedge
self.assertEqual(self.mesh.to_vertex_handle(heh_collapse).idx(), 4)
self.assertEqual(self.mesh.from_vertex_handle(heh_collapse).idx(), 1)
self.assertTrue(self.mesh.is_collapse_ok(heh_collapse))
# Remember the end vertices
vh_from = self.mesh.from_vertex_handle(heh_collapse)
vh_to = self.mesh.to_vertex_handle(heh_collapse)
# Collapse it
self.mesh.collapse(heh_collapse)
self.assertTrue(self.mesh.is_deleted(vh_from))
self.assertFalse(self.mesh.is_deleted(vh_to))
if __name__ == '__main__':
suite = unittest.TestLoader().loadTestsFromTestCase(Collapse)
unittest.TextTestRunner(verbosity=2).run(suite)