def test_different_from(): """verify that `BSPNode.different_from` has the expected behavior Get a list of planes. Split the object using the first plane, then for each of the other planes, split the object, check if the plane is far enough away given the config, then assert that `BSPNode.different_from` returns the correct value. This skips any splits that fail. """ config = Configuration.config print() mesh = trimesh.primitives.Sphere(radius=50) tree = bsp_tree.BSPTree(mesh) root = tree.nodes[0] normal = trimesh.unitize(np.random.rand(3)) planes = bsp_tree.get_planes(mesh, normal) base_node = copy.deepcopy(root) base_node = bsp_node.split(base_node, planes[0]) for plane in planes[1:]: # smaller origin offset, should not be different test_node = copy.deepcopy(root) test_node = bsp_node.split(test_node, plane) if abs((plane[0] - planes[0][0]) @ planes[0][1]) > config.different_origin_th: assert base_node.different_from(test_node) else: assert not base_node.different_from(test_node) # smaller angle difference, should not be different test_node = copy.deepcopy(root) random_vector = trimesh.unitize(np.random.rand(3)) axis = np.cross(random_vector, planes[0][1]) rotation = trimesh.transformations.rotation_matrix(np.pi / 11, axis) normal = trimesh.transform_points(planes[0][1][None, :], rotation)[0] test_plane = (planes[0][0], normal) test_node = bsp_node.split(test_node, test_plane) assert not base_node.different_from(test_node) # larger angle difference, should be different test_node = copy.deepcopy(root) random_vector = trimesh.unitize(np.random.rand(3)) axis = np.cross(random_vector, planes[0][1]) rotation = trimesh.transformations.rotation_matrix(np.pi / 9, axis) normal = trimesh.transform_points(planes[0][1][None, :], rotation)[0] test_plane = (planes[0][0], normal) test_node = bsp_node.split(test_node, test_plane) assert base_node.different_from(test_node)
def test_align(self): log.info('Testing vector alignment') target = np.array([0, 0, 1]) for i in range(100): vector = trimesh.unitize(np.random.random(3) - .5) T = trimesh.geometry.align_vectors(vector, target) result = np.dot(T, np.append(vector, 1))[0:3] aligned = np.abs(result - target).sum() < TOL_ZERO self.assertTrue(aligned)
def test_align(self): log.info('Testing vector alignment') target = np.array([0,0,1]) for i in range(100): vector = trimesh.unitize(np.random.random(3) - .5) T = trimesh.geometry.align_vectors(vector, target) result = np.dot(T, np.append(vector, 1))[0:3] aligned = np.abs(result-target).sum() < TOL_ZERO self.assertTrue(aligned)
def test_unitize_multi(self): vectors = np.ones(self.test_dim) vectors[0] = [0, 0, 0] vectors, valid = trimesh.unitize(vectors, check_valid=True) assert not valid[0] assert valid[1:].all() length = np.sum(vectors[1:]**2, axis=1)**.5 assert np.allclose(length, 1.0)
def test_unitize_multi(self): vectors = np.ones(self.test_dim) vectors[0] = [0, 0, 0] vectors, valid = trimesh.unitize(vectors, check_valid=True) assert not valid[0] assert valid[1:].all() length = np.sum(vectors[1:] ** 2, axis=1) ** .5 assert np.allclose(length, 1.0)
def test_unitize_multi(self): vectors = np.ones(self.test_dim) vectors[0] = [0, 0, 0] vectors, valid = trimesh.unitize(vectors, check_valid=True) self.assertFalse(valid[0]) self.assertTrue(np.all(valid[1:])) length = np.sum(vectors[1:]**2, axis=1)**2 length_check = np.abs(length - 1.0) < TOL_ZERO self.assertTrue(np.all(length_check))
def test_unitize_multi(self): vectors = np.ones(self.test_dim) vectors[0] = [0,0,0] vectors, valid = trimesh.unitize(vectors, check_valid=True) self.assertFalse(valid[0]) self.assertTrue(np.all(valid[1:])) length = np.sum(vectors[1:] ** 2, axis=1) ** 2 length_check = np.abs(length - 1.0) < TOL_ZERO self.assertTrue(np.all(length_check))
def test_horn(self): log.info('Testing absolute orientation') for i in range(10): points_A = (np.random.random(self.test_dim) - .5) * 100 angle = 4*np.pi*(np.random.random() - .5) vector = trimesh.unitize(np.random.random(3) - .5) offset = 100*(np.random.random(3)-.5) T = trimesh.transformations.rotation_matrix(angle, vector) T[0:3,3] = offset points_B = trimesh.points.transform_points(points_A, T) M, error = trimesh.points.absolute_orientation(points_A, points_B, return_error=True) self.assertTrue(np.all(error < TOL_ZERO))
def test_hemisphere(self): v = trimesh.unitize(np.random.random((10000, 3)) - .5) v[0] = [0, 1, 0] v[1] = [1, 0, 0] v[2] = [0, 0, 1] v = np.column_stack((v, -v)).reshape((-1, 3)) resigned = trimesh.util.vector_hemisphere(v) check = (abs(np.diff(resigned.reshape((-1, 2, 3)), axis=1).sum(axis=2)) < trimesh.constants.tol.zero).all() self.assertTrue(check)
def test_get_planes(config): """verify that for the default bunny mesh, which is a single part, all planes returned by `bsp_tree.get_planes` cut through the mesh (they have a good cross section) """ mesh = trimesh.load(config.mesh, validate=True) for i in range(100): normal = trimesh.unitize(np.random.rand(3)) planes = bsp_tree.get_planes(mesh, normal) for origin, normal in planes: path3d = mesh.section(plane_origin=origin, plane_normal=normal) assert path3d is not None
def test_horn(self): log.info('Testing absolute orientation') for i in range(10): points_A = (np.random.random(self.test_dim) - .5) * 100 angle = 4 * np.pi * (np.random.random() - .5) vector = trimesh.unitize(np.random.random(3) - .5) offset = 100 * (np.random.random(3) - .5) T = trimesh.transformations.rotation_matrix(angle, vector) T[0:3, 3] = offset points_B = trimesh.transformations.transform_points(points_A, T) M, error = trimesh.points.absolute_orientation( points_A, points_B, return_error=True) self.assertTrue(np.all(error < TOL_ZERO))
def camera_to_rays(camera): """ Convert a trimesh.scene.Camera object to ray origins and direction vectors. Parameters -------------- camera : trimesh.scene.Camera Camera with transform defined Returns -------------- origins : (n, 3) float Ray origins in space vectors : (n, 3) float Ray direction unit vectors angles : (n, 2) float Ray spherical coordinate angles in radians """ # radians of half the field of view half = np.radians(camera.fov / 2.0) # scale it down by two pixels to keep image under resolution half *= (camera.resolution - 2) / camera.resolution # get FOV angular bounds in radians # create an evenly spaced list of angles angles = trimesh.util.grid_linspace(bounds=[-half, half], count=camera.resolution) # turn the angles into unit vectors vectors = trimesh.unitize( np.column_stack((np.sin(angles), np.ones(len(angles))))) # flip the camera transform to change sign of Z transform = np.dot(camera.transform, trimesh.geometry.align_vectors([1, 0, 0], [-1, 0, 0])) # apply the rotation to the direction vectors vectors = trimesh.transform_points(vectors, transform, translate=False) # camera origin is single point, extract from transform origin = trimesh.transformations.translation_from_matrix(transform) # tile it into corresponding list of ray vectorsy origins = np.ones_like(vectors) * origin return origins, vectors, angles
def random_rotate(mesh): mesh = mesh.copy() angle_rad = np.random.rand() * 2 * np.pi direction = trimesh.unitize(np.random.rand(3)) rot = trimesh.transformations.rotation_matrix(angle_rad, direction, [0, 0, 0]) return mesh.apply_transform(rot)