def test_sample(self): """ Test random sampling of polygons """ p = g.Point([0, 0]).buffer(1.0) count = 100 s = g.trimesh.path.polygons.sample(p, count=count) assert len(s) <= count assert s.shape[1] == 2 radius = (s ** 2).sum(axis=1).max() assert radius < (1.0 + 1e-8) # test Path2D sample wiring path = g.trimesh.load_path(p) s = path.sample(count=count) assert len(s) <= count assert s.shape[1] == 2 radius = (s ** 2).sum(axis=1).max() assert radius < (1.0 + 1e-8) # try getting OBB of samples T, extents = g.trimesh.path.polygons.polygon_obb(s) # OBB of samples should be less than diameter of circle diameter = g.np.reshape(p.bounds, (2, 2)).ptp(axis=0).max() assert (extents <= diameter).all() # test sampling with multiple bodies for i in range(3): assert g.np.isclose(path.area, p.area * (i + 1)) path = path + g.trimesh.load_path( g.Point([(i + 2) * 2, 0]).buffer(1.0)) s = path.sample(count=count) assert s.shape[1] == 2
def test_rasterize(self): test_radius = 1.0 test_pitch = test_radius / 10.0 polygon = g.Point([0, 0]).buffer(test_radius) (offset, grid, grid_points) = g.trimesh.path.polygons.rasterize_polygon( polygon=polygon, pitch=test_pitch) assert g.trimesh.util.is_shape(grid_points, (-1, 2)) grid_radius = (grid_points**2).sum(axis=1)**.5 pixel_diagonal = (test_pitch * (2.0**.5)) / 2.0 contained = grid_radius <= (test_radius + pixel_diagonal) assert contained.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 test_extrusion(self): if not has_triangle: return transform = g.trimesh.transformations.random_rotation_matrix() polygon = g.Point([0, 0]).buffer(.5) e = g.trimesh.primitives.Extrusion(polygon=polygon, transform=transform) # will create an inflated version of the extrusion b = e.buffer(.1) assert b.to_mesh().volume > e.to_mesh().volume assert b.contains(e.vertices).all() # try making it smaller b = e.buffer(-.1) assert b.to_mesh().volume < e.to_mesh().volume assert e.contains(b.vertices).all() # try with negative height e = g.trimesh.primitives.Extrusion(polygon=polygon, height=-1.0, transform=transform) assert e.to_mesh().volume > 0.0 # will create an inflated version of the extrusion b = e.buffer(.1) assert b.to_mesh().volume > e.to_mesh().volume assert b.contains(e.vertices).all() # try making it smaller b = e.buffer(-.1) assert b.to_mesh().volume < e.to_mesh().volume assert e.contains(b.vertices).all() # try with negative height and transform transform = [[1., 0., 0., -0.], [0., 1., 0., 0.], [-0., -0., -1., -0.], [0., 0., 0., 1.]] e = g.trimesh.primitives.Extrusion(polygon=polygon, height=-1.0, transform=transform) assert e.to_mesh().volume > 0.0 for T in g.transforms: current = e.copy().apply_transform(T) # get the special case OBB calculation for extrusions obb = current.bounding_box_oriented # check to make sure shortcutted OBB is the right size assert g.np.isclose(obb.volume, current.to_mesh().bounding_box_oriented.volume) # use OBB transform to project vertices of extrusion to plane points = g.trimesh.transform_points( current.vertices, g.np.linalg.inv(obb.primitive.transform)) # half extents of calculated oriented bounding box half = (g.np.abs(obb.primitive.extents) / 2.0) + 1e-3 # every vertex should be inside OBB assert (points > -half).all() assert (points < half).all() assert current.direction.shape == (3, ) assert current.origin.shape == (3, )