def test_lookat(self): """ Test the "look at points" function """ # original points ori = np.array([[-1, -1], [1, -1], [1, 1], [-1, 1]]) for i in range(10): # set the extents to be random but positive extents = g.random() * 10 points = g.trimesh.util.stack_3D(ori.copy() * extents) fov = g.np.array([20, 50]) # offset the points by a random amount offset = (g.random(3) - 0.5) * 100 T = g.trimesh.scene.cameras.look_at(points + offset, fov) # check using trig check = (points.ptp(axis=0)[:2] / 2.0) / \ g.np.tan(np.radians(fov / 2)) check += points[:, 2].mean() # Z should be the same as maximum trig option assert np.linalg.inv(T)[2, 3] >= check.max() # just run to test other arguments # TODO(unknown): find the way to test it correctly g.trimesh.scene.cameras.look_at(points, fov, center=points[0]) g.trimesh.scene.cameras.look_at(points, fov, distance=1)
def test_svg(self): from trimesh.path.segments import to_svg # create some 2D segments seg = g.random((1000, 2, 2)) # make one of the segments a duplicate seg[0] = seg[-1] # create an SVG path string svg = to_svg(seg, merge=False) # should be one move and one line per segment assert svg.count('M') == len(seg) assert svg.count('L') == len(seg) # try with a transform svg = to_svg(seg, matrix=g.np.eye(3), merge=False) assert svg.count('M') == len(seg) assert svg.count('L') == len(seg) # remove the duplicate segments svg = to_svg(seg, matrix=g.np.eye(3), merge=True) assert svg.count('M') < len(seg) assert svg.count('L') < len(seg) try: to_svg(g.random((100, 2, 3))) except ValueError: return raise ValueError('to_svg accepted wrong input!')
def test_lookat(self): """ Test the "look at points" function """ # original points ori = np.array([[-1, -1], [1, -1], [1, 1], [-1, 1]]) for i in range(10): # set the extents to be random but positive extents = g.random() * 10 points = g.trimesh.util.stack_3D(ori.copy() * extents) fov = g.np.array([20, 50]) # offset the points by a random amount offset = (g.random(3) - 0.5) * 100 T = g.trimesh.scene.cameras.look_at(points + offset, fov) # check using trig check = (points.ptp(axis=0)[:2] / 2.0) / \ g.np.tan(np.radians(fov / 2)) check += points[:, 2].mean() # Z should be the same as maximum trig option assert np.linalg.inv(T)[2, 3] >= check.max() # just run to test other arguments # TODO(unknown): find the way to test it correctly g.trimesh.scene.cameras.look_at(points, fov, center=points[0]) g.trimesh.scene.cameras.look_at(points, fov, distance=1)
def test_svg(self): from trimesh.path.segments import to_svg # create some 2D segments seg = g.random((1000, 2, 2)) # create an SVG path string svg = to_svg(seg) # should be one move and one line per segment assert svg.count('M') == len(seg) assert svg.count('L') == len(seg) try: to_svg(g.random((100, 2, 3))) except ValueError: return raise ValueError('to_svg accepted wrong input!')
def test_truncated(self, count=10): # create some random triangles tri = g.random((count, 3, 3)) m = g.trimesh.creation.truncated_prisms(tri) split = m.split() assert m.body_count == count assert len(split) == count assert all(s.volume > 0 for s in split)
def test_resample(self): from trimesh.path.segments import length, resample # create some random segments seg = g.random((1000, 2, 3)) # set a maximum segment length maxlen = 0.1 # one of the original segments should be longer than maxlen assert (length(seg, summed=False) > maxlen).any() # resample to be all shorter than maxlen res = resample(seg, maxlen=maxlen) # check lengths of the resampled result assert (length(res, summed=False) < maxlen).all() # make sure overall length hasn't changed assert g.np.isclose(length(res), length(seg))
def test_extrude(self): from trimesh.path.segments import extrude # hand tuned segments manual = g.np.column_stack((g.np.zeros( (3, 2)), [[0, 1], [0, -1], [1, 2]])).reshape((-1, 2, 2)) for seg in [manual, g.random((10, 2, 2))]: height = 1.22 v, f = extrude(segments=seg, height=height) # load extrusion as mesh mesh = g.trimesh.Trimesh(vertices=v, faces=f) # load line segments as path path = g.trimesh.load_path(seg) # compare area of mesh with source path assert g.np.isclose(mesh.area, path.length * height)
def test_bounds_tree(self): # test r-tree intersections for dimension in (2, 3): # create some (n, 2, 3) bounds bounds = g.np.array( [[i.min(axis=0), i.max(axis=0)] for i in [g.random((4, dimension)) for i in range(10)]]) tree = g.trimesh.util.bounds_tree(bounds) for i, b in enumerate(bounds): assert i in set(tree.intersection(b.ravel())) # construct tree with per-row bounds tree = g.trimesh.util.bounds_tree( bounds.reshape((-1, dimension * 2))) for i, b in enumerate(bounds): assert i in set(tree.intersection(b.ravel()))
def test_kmeans(self, cluster_count=5, points_per_cluster=100): """ Test K-means clustering """ clustered = [] for i in range(cluster_count): # use repeatable random- ish coordinatez clustered.append(g.random((points_per_cluster, 3)) + (i * 10.0)) clustered = g.np.vstack(clustered) # run k- means clustering on our nicely separated data centroids, klabel = g.trimesh.points.k_means(points=clustered, k=cluster_count) # reshape to make sure all groups have the same index variance = klabel.reshape( (cluster_count, points_per_cluster)).ptp(axis=1) assert len(centroids) == cluster_count assert (variance == 0).all()
def test_kmeans(self, cluster_count=5, points_per_cluster=100): """ Test K-means clustering """ clustered = [] for i in range(cluster_count): # use repeatable random- ish coordinatez clustered.append( g.random((points_per_cluster, 3)) + (i * 10.0)) clustered = g.np.vstack(clustered) # run k- means clustering on our nicely separated data centroids, klabel = g.trimesh.points.k_means(points=clustered, k=cluster_count) # reshape to make sure all groups have the same index variance = klabel.reshape( (cluster_count, points_per_cluster)).ptp( axis=1) assert len(centroids) == cluster_count assert (variance == 0).all()
def check_nearest_point_function(self, fun): # def plot_tri(tri, color='g'): # plottable = g.np.vstack((tri, tri[0])) # plt.plot(plottable[:, 0], plottable[:, 1], color=color) def points_on_circle(count): theta = g.np.linspace(0, g.np.pi * 2, count + 1)[:count] s = g.np.column_stack((theta, [g.np.pi / 2] * count)) t = g.trimesh.util.spherical_to_vector(s) return t # generate some pseudorandom triangles # use our random to avoid spurious failures triangles = g.random((100, 3, 3)) - 0.5 # put them on- plane triangles[:, :, 2] = 0.0 # make one of the triangles equilaterial triangles[-1] = points_on_circle(3) # a circle of points surrounding the triangle query = points_on_circle(63) * 2 # set the points up in space query[:, 2] = 10 # a circle of points inside-ish the triangle query = g.np.vstack((query, query * .1)) # loop through each triangle for triangle in triangles: # create a mesh with one triangle mesh = g.Trimesh(**g.trimesh.triangles.to_kwargs([triangle])) result, result_distance, result_tid = fun(mesh, query) polygon = g.Polygon(triangle[:, 0:2]) polygon_buffer = polygon.buffer(1e-5) # all of the points returned should be on the triangle we're # querying assert all(polygon_buffer.intersects( g.Point(i)) for i in result[:, 0:2]) # see what distance shapely thinks the nearest point # is for the 2D triangle and the query points distance_shapely = g.np.array([polygon.distance(g.Point(i)) for i in query[:, :2]]) # see what distance our function returned for the nearest point distance_ours = ((query[:, :2] - result[:, :2]) ** 2).sum(axis=1) ** .5 # how far was our distance from the one shapely gave distance_test = g.np.abs(distance_shapely - distance_ours) # NOQA # we should have calculated the same distance as shapely assert g.np.allclose(distance_ours, distance_shapely) # now check to make sure closest point doesn't depend on # the frame, IE the results should be the same after # any rigid transform # chop query off to same length as triangles assert len(query) > len(triangles) query = query[:len(triangles)] # run the closest point query as a corresponding query close = g.trimesh.triangles.closest_point(triangles=triangles, points=query) # distance between closest point and query point # this should stay the same regardless of frame distance = g.np.linalg.norm(close - query, axis=1) for T in g.transforms: # transform the query points points = g.trimesh.transform_points(query, T) # transform the triangles we're checking tri = g.trimesh.transform_points( triangles.reshape((-1, 3)), T).reshape((-1, 3, 3)) # run the closest point check check = g.trimesh.triangles.closest_point(triangles=tri, points=points) check_distance = g.np.linalg.norm(check - points, axis=1) # should be the same in any frame assert g.np.allclose(check_distance, distance) return result, result_distance
def check_nearest_point_function(self, fun): # def plot_tri(tri, color='g'): # plottable = g.np.vstack((tri, tri[0])) # plt.plot(plottable[:, 0], plottable[:, 1], color=color) def points_on_circle(count): theta = g.np.linspace(0, g.np.pi * 2, count + 1)[:count] s = g.np.column_stack((theta, [g.np.pi / 2] * count)) t = g.trimesh.util.spherical_to_vector(s) return t # generate some pseudorandom triangles # use our random to avoid spurious failures triangles = g.random((100, 3, 3)) - 0.5 # put them on- plane triangles[:, :, 2] = 0.0 # make one of the triangles equilaterial triangles[-1] = points_on_circle(3) # a circle of points surrounding the triangle query = points_on_circle(63) * 2 # set the points up in space query[:, 2] = 10 # a circle of points inside-ish the triangle query = g.np.vstack((query, query * .1)) # loop through each triangle for triangle in triangles: # create a mesh with one triangle mesh = g.Trimesh(**g.trimesh.triangles.to_kwargs([triangle])) result, result_distance, result_tid = fun(mesh, query) polygon = g.Polygon(triangle[:, 0:2]) polygon_buffer = polygon.buffer(1e-5) # all of the points returned should be on the triangle we're # querying assert all(polygon_buffer.intersects( g.Point(i)) for i in result[:, 0:2]) # see what distance shapely thinks the nearest point # is for the 2D triangle and the query points distance_shapely = g.np.array([polygon.distance(g.Point(i)) for i in query[:, :2]]) # see what distance our function returned for the nearest point distance_ours = ((query[:, :2] - result[:, :2]) ** 2).sum(axis=1) ** .5 # how far was our distance from the one shapely gave distance_test = g.np.abs(distance_shapely - distance_ours) # NOQA # we should have calculated the same distance as shapely assert g.np.allclose(distance_ours, distance_shapely) # now check to make sure closest point doesn't depend on # the frame, IE the results should be the same after # any rigid transform # chop query off to same length as triangles assert len(query) > len(triangles) query = query[:len(triangles)] # run the closest point query as a corresponding query close = g.trimesh.triangles.closest_point(triangles=triangles, points=query) # distance between closest point and query point # this should stay the same regardless of frame distance = g.np.linalg.norm(close - query, axis=1) for T in g.transforms: # transform the query points points = g.trimesh.transform_points(query, T) # transform the triangles we're checking tri = g.trimesh.transform_points( triangles.reshape((-1, 3)), T).reshape((-1, 3, 3)) # run the closest point check check = g.trimesh.triangles.closest_point(triangles=tri, points=points) check_distance = g.np.linalg.norm(check - points, axis=1) # should be the same in any frame assert g.np.allclose(check_distance, distance) return result, result_distance