def setUp(self): rows, cols = 3, 4 self.base_color = np.empty((rows, cols, 3), dtype=np.uint8) self.metallic_roughness = np.empty((rows, cols, 3), dtype=np.uint8) self.vertices = np.column_stack([ Vector3f(0, 0, 0), Vector3f(1, 0, 0), Vector3f(0, 1, 0), Vector3f(1, 1, 0) ]) self.normals = np.column_stack([Vector3f(0, 0, 1)] * 4) self.uv_coords = np.column_stack( [Vector2f(0, 0), Vector2f(1, 0), Vector2f(0, 1), Vector2f(1, 1)]) self.temp_directory = tempfile.mkdtemp() self.indices = np.array([0, 1, 2, 1, 3, 2], dtype=np.uint32) self.mesh = TexturedMesh( self.indices, self.vertices, self.normals, self.uv_coords, self.base_color, self.metallic_roughness, )
def test_center(self): """ Test center function """ box = Box3d(corner1=Vector3f(2, 4, 6), corner2=Vector3f(0, 2, 3)) expected_center = Vector3f(1, 3, 4.5) np.testing.assert_array_almost_equal(box.center(), expected_center)
def test_bounds(self): points = np.array([[0.6, 0.1, -0.1], [1.1, 2.1, 3.1], [1.3, 2.2, 3.4]]) min_corner = Vector3f(-1, -2, -3) vg = VoxelGrid(0.5, min_corner=min_corner, points=points) bounds = vg.bounds() expected_bounds = Box3d(Vector3f(0.5, 0, -0.5), Vector3f(1.5, 2.5, 3.5)) self.assertAlmostEquals(bounds, expected_bounds)
def setUp(self): self.vertices = np.column_stack([ Vector3f(0, 0, 0), Vector3f(1, 0, 0), Vector3f(0, 1, 0), Vector3f(1, 1, 0) ]) self.normals = np.column_stack([Vector3f(0, 0, 1)] * 4) self.indices = np.array([0, 1, 2, 1, 3, 2], dtype=np.uint32) self.mesh = Mesh(self.indices, self.vertices, self.normals)
def test_vertex_normals(self): """Test that we can calculate normals.""" normals = Mesh.estimate_normals(self.indices, self.vertices) expected = np.column_stack([ Vector3f(0, 0, 1), Vector3f(0, 0, 1), Vector3f(0, 0, 1), Vector3f(0, 0, 1) ]) np.testing.assert_array_equal(normals, expected)
def test_add_colored_material(self): mesh = TexturedMesh.example() model = GltfModel.from_textured_mesh(mesh) index = model.add_colored_material("my_material", Vector3f(0.5, 0.5, 0.5), 0.0, 0.95) self.assertEqual(index, 1) index = model.add_colored_material("another_material", Vector3f(0.75, 0.75, 0.75), 0.1, 0.7) self.assertEqual(index, 2)
def test_merge_quadrant_meshes(self): """Test merging 4 quads that (could be) result of subdivision.""" indices = np.array([0, 1, 2, 1, 3, 2], dtype=np.uint32) # 2 7 3 # 4 6 8 # 0 5 1 vertices = np.column_stack([ Vector3f(0, 0, 0), Vector3f(1, 1, 1), Vector3f(2, 2, 2), Vector3f(3, 3, 3), Vector3f(4, 4, 4), Vector3f(5, 5, 5), Vector3f(6, 6, 6), Vector3f(7, 7, 7), Vector3f(8, 8, 8), ]) args = self.normals, self.uv_coords, self.base_color, self.metallic_roughness mesh0 = TexturedMesh(indices, vertices[:, [0, 5, 4, 6]], *args) mesh1 = TexturedMesh(indices, vertices[:, [5, 1, 6, 8]], *args) mesh2 = TexturedMesh(indices, vertices[:, [4, 6, 2, 7]], *args) mesh3 = TexturedMesh(indices, vertices[:, [6, 8, 7, 3]], *args) mesh = TexturedMesh.merge_quadrant_meshes(mesh0, mesh1, mesh2, mesh3) self.assertEqual(mesh.num_indices(), 4 * 3 * 2) self.assertEqual(mesh.num_vertices(), 9) expected_indices = ([0, 5, 4, 5, 6, 4] + [5, 1, 6, 1, 8, 6] + [4, 6, 2, 6, 7, 2] + [6, 8, 7, 8, 3, 7]) np.testing.assert_array_equal(mesh.indices(), expected_indices) np.testing.assert_array_equal(mesh.vertices(), vertices)
def __init__(self, voxel_size=1, min_corner=None, points=None): """ Constructor Inputs: voxel_size (float) - length of one side of a voxel (assumed square) min_corner (Vector3f) - the minimum corner of voxel grid in local coordinates (default = [0,0,0]). points (Nx3 vector of float) - initial 3D points to insert into the grid. colors Exceptions: ValueError - if a point in <points> is less than the min_corner on any axis is added ValueError - if voxel_size <= 0 """ if (voxel_size <= 0): raise ValueError("voxel_size must be > 0") self._scale = 1 / voxel_size # store inverse voxel size for efficiency self._min_corner = min_corner if min_corner is not None else Vector3f( 0, 0, 0) self._voxels_3d = np.zeros((0, 3)) # voxels in Nx3 array format self._size_x, self._size_y = 0, 0 # x, y size of voxel space if points is not None: self.add_points(points)
def test_cleanup(self): """Check removing triangles with long edges, and (0,0,0) vertices.""" indices = np.array([0, 1, 2, 1, 3, 2], dtype=np.uint32) vertices = np.column_stack([ Vector3f(0, 0, 0), Vector3f(1, 0, 0), Vector3f(0, 1, 0), Vector3f(100, 100, 0), ]) mesh = Mesh(indices, vertices, self.normals) mesh.cleanup_long_edges(threshold=10) self.assertEqual(mesh.num_indices(), 3) np.testing.assert_array_equal(mesh.indices(), [0, 1, 2]) mesh.cleanup_edges_to_origin() self.assertEqual(mesh.num_indices(), 0)
def setUp(self): # create sample bounding box, meshes, and voxel grid objects self.bounds = Box3d([-1.5, -2.2, 3], [4, 4.1, 6.5]) textured_mesh = self.bounds.to_textured_mesh() self.meshes = GltfModel.from_textured_mesh(textured_mesh) points = np.array([[0.1, 0.1, 0.1], [1.1, 1.1, 1.1], [1.3, 1.2, 1.4]]) self.voxels = VoxelGrid(0.5, min_corner=Vector3f(0, 0, 0), points=points) # and pose rot = np.array([[1, 0, 0], [0, 0, -1], [0, 1, 0]], dtype=float) trans = Vector3f(1, 1, 1) self.pose = Pose3(rot, trans) # Create temporary outout directory. self.temp_directory = tempfile.mkdtemp()
def test_constructor(self): """ Creates a simple voxel grid and checks its attributes. """ expected_min_corner = Vector3f(-5.1, -6.2, -7.5) vg = VoxelGrid(0.2, expected_min_corner) self.assertAlmostEqual(vg.voxel_size, 0.2) np.testing.assert_array_equal(vg.min_corner, expected_min_corner)
def test_cube(self): """Check generation of a cube mesh.""" rows, cols = 4, 24 base_color = np.empty((rows, cols, 3), dtype=np.uint8) metallic_roughness = np.empty((rows, cols, 3), dtype=np.uint8) mesh = TexturedMesh.cube(base_color, metallic_roughness) # Check indices indices = mesh.indices() self.assertEqual(indices.shape, (6 * 6, )) np.testing.assert_array_equal(indices[:6], [0, 1, 2, 1, 3, 2]) np.testing.assert_array_equal(indices[-6:], [20, 21, 22, 21, 23, 22]) # Check 3D mesh vertices = mesh.vertices() self.assertEqual(vertices.shape, (3, 4 * 6)) # Check BACK, where y = -1 np.testing.assert_array_equal( vertices[:, :4], np.column_stack([ Vector3f(+1, -1, +1), Vector3f(-1, -1, +1), Vector3f(+1, +1, +1), Vector3f(-1, +1, +1), ]), ) # Check LEFT, FRONT, RIGHT, UP np.testing.assert_array_equal(vertices[0, 4:8], (-1, -1, -1, -1)) np.testing.assert_array_equal(vertices[2, 8:12], (-1, -1, -1, -1)) np.testing.assert_array_equal(vertices[0, 12:16], (1, 1, 1, 1)) np.testing.assert_array_equal(vertices[1, 16:20], (1, 1, 1, 1)) # Check DOWN, where Z = -1 np.testing.assert_array_equal( vertices[:, -4:], np.column_stack([ Vector3f(-1, -1, +1), Vector3f(+1, -1, +1), Vector3f(-1, -1, -1), Vector3f(+1, -1, -1), ]), ) # check cpp_normals normals = mesh.normals() # normals for BACK, LEFT, FRONT, RIGHT, UP, DOWN dir = [(0, 0, -1), (1, 0, 0), (0, 0, 1), (-1, 0, 0), (0, -1, 0), (0, 1, 0)] for j in range(6): np.testing.assert_array_equal(normals[:, j * 4], dir[j]) # Check texture coordinates uv_coords = mesh.uv_coords() np.testing.assert_array_almost_equal( uv_coords[:, :4], [[0, 1 / 6.0, 0, 1 / 6.0], [1, 1, 0, 0]]) np.testing.assert_array_equal(np.min(uv_coords, axis=1), [0, 0]) np.testing.assert_array_equal(np.max(uv_coords, axis=1), [1, 1])
def test_min_corner_offset(self): """ Test with a non-zero min_corner. """ points = np.array([[0.1, 0.1, 0.1], [1.1, 2.1, 3.1], [1.3, 2.2, 3.4]]) vg = VoxelGrid(1, min_corner=Vector3f(-1, -2, -3), points=points) centers = vg.voxel_centers() expected_centers = np.array([[0.5, 0.5, 0.5], [1.5, 2.5, 3.5]]) np.testing.assert_array_almost_equal(centers, expected_centers)
def test_constructor_with_points(self): """ Tests voxel_centers. Verifies that multiple points in the same voxel are deduplicated. """ points = np.array([[0.1, 0.1, 0.1], [1.1, 1.1, 1.1], [1.3, 1.2, 1.4]]) vg = VoxelGrid(0.5, min_corner=Vector3f(0, 0, 0), points=points) centers = vg.voxel_centers() expected_centers = np.array([[0.25, 0.25, 0.25], [1.25, 1.25, 1.25]]) np.testing.assert_array_almost_equal(centers, expected_centers)
def test_min_corner_check(self): """ Test adding point less than min_corner. """ points = np.array([[0.1, 0.1, 0.1], [1.1, 2.1, 3.1], [1.3, 2.2, 3.4], [0, 0, -3.1]]) self.assertRaises(ValueError, VoxelGrid, voxel_size=1, min_corner=Vector3f(-1, -2, -3), points=points)
def _check_mesh_helper(self, mesh): ''' Checks structure of Mesh or TexturedMesh ''' # Check indices indices = mesh.indices() self.assertEqual(indices.shape, (6 * 6, )) np.testing.assert_array_equal(indices[:6], [0, 1, 2, 0, 2, 3]) np.testing.assert_array_equal(indices[-6:], [20, 21, 22, 20, 22, 23]) # Check 3D mesh vertices = mesh.vertices() self.assertEqual(vertices.shape, (3, 4 * 6)) # Check BACK, where y = -1 np.testing.assert_array_equal( vertices[:, :4], np.column_stack( [ Vector3f(0, 0, 1), Vector3f(1, 0, 1), Vector3f(1, 1, 1), Vector3f(0, 1, 1) ] ) ) # Check right, back, left up np.testing.assert_array_equal(vertices[0, 4:8], (1, 1, 1, 1)) np.testing.assert_array_equal(vertices[2, 8:12], (0, 0, 0, 0)) np.testing.assert_array_equal(vertices[0, 12:16], (0, 0, 0, 0)) np.testing.assert_array_equal(vertices[1, 16:20], (1, 1, 1, 1)) # Check bottom np.testing.assert_array_equal( vertices[:, -4:], np.column_stack( [ Vector3f(0, 0, 0), Vector3f(1, 0, 0), Vector3f(1, 0, 1), Vector3f(0, 0, 1) ] ) ) # check cpp_normals normals = mesh.normals() # normals for front, right, back, left, top, bot dir = [ (0, 0, 1), (1, 0, 0), (0, 0, -1), (-1, 0, 0), (0, 1, 0), (0, -1, 0) ] for j in range(6): np.testing.assert_array_equal(normals[:, j * 4], dir[j])
def test_random_points(self): """ Make three random points and verify the bounding box's corners are correct """ point1 = Vector3f(-1, -2, -3) point2 = Vector3f(0, 2, 1) point3 = Vector3f(1, 2, 3) points = np.column_stack([point1, point2, point3]) box = ComputeBbox().from_point_cloud(points) corners = box.corners() corners_target = np.column_stack([ [-1.0, -2.0, 3.0], [1.0, -2.0, 3.0], [1.0, 2.0, 3.0], [-1.0, 2.0, 3.0], [-1.0, -2.0, -3.0], [1.0, -2.0, -3.0], [1.0, 2.0, -3.0], [-1.0, 2.0, -3.0], ]) np.testing.assert_array_equal(corners, corners_target)
def test_from_mesh(self): """Make a mesh and verify the bounding box's corners are correct.""" indices = np.array([0, 1, 2, 1, 3, 2, 2, 3, 4], dtype=np.uint32) vertices = np.column_stack( [ Vector3f(0, 0, 0), Vector3f(1, 0, 0), Vector3f(0, 1, 0), Vector3f(1, 1, 0), Vector3f(1, 1, 1), ] ) normals = np.column_stack([Vector3f(0, 0, 1)] * 5) self.assertEqual(vertices.shape, normals.shape) self.assertEqual(indices.shape, (9,)) mesh = Mesh(indices, vertices, normals) box = ComputeBbox().from_mesh(mesh) corners = box.corners() corners_target = np.column_stack( [ [0.0, 0.0, 1.0], [1.0, 0.0, 1.0], [1.0, 1.0, 1.0], [0.0, 1.0, 1.0], [0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [1.0, 1.0, 0.0], [0.0, 1.0, 0.0], ] ) np.testing.assert_array_equal(corners, corners_target)
def test_voxel_io(self): """Test reading and writing voxel objects.""" points = np.array([[0.1, 0.1, 0.1], [1.1, 1.1, 1.1], [1.3, 1.2, 1.4]]) vg = VoxelGrid(0.5, min_corner=Vector3f(0, 0, 0), points=points) po = ProjectObject.gen_voxels_object(id="foobar", voxels=vg, pose=self.pose, category="chair") self.assertIsInstance(self.temp_directory, str) po_xml = po.save(self.temp_directory) po2 = ProjectObject.load("voxels", po_xml, self.temp_directory) self.assertTrue(po2.almost_equal(po))
def test_add_points(self): """ Add additional points to an initial set. Checks that redundant voxels are counted only once. """ points = np.array([[0.1, 0.1, 0.1], [1.1, 2.1, 3.1], [1.3, 2.2, 3.4]]) vg = VoxelGrid(1, min_corner=Vector3f(-1, -2, -3), points=points) points2 = np.array([[0.2, 0.2, 0.3], [2, 2, 2], [4, 4, 4]]) vg.add_points(points2) centers = vg.voxel_centers() expected_centers = np.array([[0.5, 0.5, 0.5], [2.5, 2.5, 2.5], [1.5, 2.5, 3.5], [4.5, 4.5, 4.5]]) np.testing.assert_array_almost_equal(centers, expected_centers)
def test_file_io(self): """ Test round trip writing and reading a simple h5 file. """ temp_directory = tempfile.mkdtemp() filename = os.path.join(temp_directory, "test.h5") points = np.array([[0.1, 0.1, 0.1], [1.1, 2.1, 3.1], [1.3, 2.2, 3.4]]) voxel_size = 0.5 min_corner = Vector3f(-1, -2, -3) vg = VoxelGrid(voxel_size, min_corner=min_corner, points=points) # test writing vg.save(filename) self.assertTrue(os.path.isfile(filename)) # test reading vg2 = VoxelGrid.from_file(filename) self.assertAlmostEquals(voxel_size, vg2.voxel_size) np.testing.assert_array_almost_equal(vg.min_corner, vg2.min_corner) shutil.rmtree(temp_directory)
def test_Vector3f(self): vector = Vector3f(1, 2, 3) self.assertEqual(vector.shape, (3, )) self.assertEqual(vector.dtype, np.float32)
def test_merge(self): box1 = Box3d(corner1=Vector3f(0, 1, 0), corner2=Vector3f(1, 2, 1)) box2 = Box3d(corner1=Vector3f(1, 0, 0), corner2=Vector3f(2, 1, 2)) merged = Box3d.merge([box1, box2]) np.testing.assert_array_equal(merged.min_corner, Vector3(0, 0, 0)) np.testing.assert_array_equal(merged.max_corner, Vector3(2, 2, 2))
def test_volume(self): """Test computation of box volume""" box = Box3d(corner1=Vector3f(2, 4, 6), corner2=Vector3f(0, 2, 3)) self.assertEqual(box.volume(), 12)