def test_split(self): for fn in ['2D/ChuteHolderPrint.DXF', '2D/tray-easy1.dxf', '2D/sliding-base.dxf', '2D/wrench.dxf', '2D/spline_1.dxf']: p = g.get_mesh(fn) # make sure something was loaded assert len(p.root) > 0 # split by connected split = p.split() # make sure split parts have same area as source assert g.np.isclose(p.area, sum(i.area for i in split)) # make sure concatenation doesn't break that assert g.np.isclose(p.area, g.np.sum(split).area) # check that cache didn't screw things up for s in split: assert len(s.root) == 1 assert len(s.path_valid) == len(s.paths) assert len(s.paths) == len(s.discrete) assert s.path_valid.sum() == len(s.polygons_closed) g.check_path2D(s)
def test_section(self): mesh = g.get_mesh('tube.obj') # check the CCW correctness with a normal in both directions for sign in [1.0, -1.0]: # get a cross section of the tube section = mesh.section(plane_origin=mesh.center_mass, plane_normal=[0.0, sign, 0.0]) # Path3D -> Path2D planar, T = section.to_planar() # tube should have one closed polygon assert len(planar.polygons_full) == 1 polygon = planar.polygons_full[0] # closed polygon should have one interior assert len(polygon.interiors) == 1 # the exterior SHOULD be counterclockwise assert g.trimesh.path.util.is_ccw( polygon.exterior.coords) # the interior should NOT be counterclockwise assert not g.trimesh.path.util.is_ccw( polygon.interiors[0].coords) # should be a valid Path2D g.check_path2D(planar)
def test_circle_pattern(self): from trimesh.path import creation pattern = creation.circle_pattern(pattern_radius=1.0, circle_radius=0.1, count=4) assert len(pattern.entities) == 4 assert len(pattern.polygons_closed) == 4 assert len(pattern.polygons_full) == 4 # should be a valid Path2D g.check_path2D(pattern)
def test_circle(self): from trimesh.path import creation circle = creation.circle(radius=1.0, center=(1.0, 1.0)) # it's a discrete circle assert g.np.isclose(circle.area, g.np.pi, rtol=0.01) # should be centered at 0 assert g.np.allclose(circle.polygons_full[0].centroid, [1.0, 1.0], atol=1e-3) assert len(circle.entities) == 1 assert len(circle.polygons_closed) == 1 assert len(circle.polygons_full) == 1 # should be a valid Path2D g.check_path2D(circle)
def test_multiroot(self): """ Test a Path2D object containing polygons nested in the interiors of other polygons. """ inner = g.trimesh.creation.annulus(r_min=.5, r_max=0.6, height=1.0) outer = g.trimesh.creation.annulus(r_min=.9, r_max=1.0, height=1.0) m = inner + outer s = m.section(plane_normal=[0, 0, 1], plane_origin=[0, 0, 0]) p = s.to_planar()[0] assert len(p.polygons_closed) == 4 assert len(p.polygons_full) == 2 assert len(p.root) == 2 g.check_path2D(p)
def test_multiroot(self): """ Test a Path2D object containing polygons nested in the interiors of other polygons. """ inner = g.trimesh.creation.annulus(r_min=.5, r_max=.6) outer = g.trimesh.creation.annulus(r_min=.9, r_max=1.0) m = inner + outer s = m.section(plane_normal=[0, 0, 1], plane_origin=[0, 0, 0]) p = s.to_planar()[0] assert len(p.polygons_closed) == 4 assert len(p.polygons_full) == 2 assert len(p.root) == 2 g.check_path2D(p)
def test_circle(self): from trimesh.path import creation circle = creation.circle(radius=1.0) # it's a discrete circle assert g.np.isclose(circle.area, g.np.pi, rtol=0.01) # should be centered at 0 assert g.np.allclose( circle.polygons_full[0].centroid, [ 0.0, 0.0], atol=1e-3) assert len(circle.entities) == 1 assert len(circle.polygons_closed) == 1 assert len(circle.polygons_full) == 1 # should be a valid Path2D g.check_path2D(circle)
def test_rect(self): from trimesh.path import creation # create a single rectangle pattern = creation.rectangle([[0, 0], [2, 3]]) assert len(pattern.entities) == 1 assert len(pattern.polygons_closed) == 1 assert len(pattern.polygons_full) == 1 assert g.np.isclose(pattern.area, 6.0) # should be a valid Path2D g.check_path2D(pattern) # make 10 untouching rectangles pattern = creation.rectangle(g.np.arange(40).reshape((-1, 2, 2))) assert len(pattern.entities) == 10 assert len(pattern.polygons_closed) == 10 assert len(pattern.polygons_full) == 10 # should be a valid Path2D g.check_path2D(pattern)
def test_rect(self): from trimesh.path import creation # create a single rectangle pattern = creation.rectangle([[0, 0], [2, 3]]) assert len(pattern.entities) == 1 assert len(pattern.polygons_closed) == 1 assert len(pattern.polygons_full) == 1 assert g.np.isclose(pattern.area, 6.0) # should be a valid Path2D g.check_path2D(pattern) # make 10 untouching rectangles pattern = creation.rectangle( g.np.arange(40).reshape((-1, 2, 2))) assert len(pattern.entities) == 10 assert len(pattern.polygons_closed) == 10 assert len(pattern.polygons_full) == 10 # should be a valid Path2D g.check_path2D(pattern)
def test_discrete(self): for d in g.get_2D(): # store md5 before requesting passive functions md5 = d.md5() # make sure various methods return # basically the same bounds atol = d.scale / 1000 for dis, pa, pl in zip(d.discrete, d.paths, d.polygons_closed): # bounds of discrete version of path bd = g.np.array([g.np.min(dis, axis=0), g.np.max(dis, axis=0)]) # bounds of polygon version of path bl = g.np.reshape(pl.bounds, (2, 2)) # try bounds of included entities from path pad = g.np.vstack([d.entities[i].discrete(d.vertices) for i in pa]) bp = g.np.array([g.np.min(pad, axis=0), g.np.max(pad, axis=0)]) assert g.np.allclose(bd, bl, atol=atol) assert g.np.allclose(bl, bp, atol=atol) # run some checks g.check_path2D(d) # copying shouldn't touch original file copied = d.copy() # these operations shouldn't have mutated anything! assert d.md5() == md5 # copy should have saved the metadata assert set(copied.metadata.keys()) == set(d.metadata.keys()) # file_name should be populated, and if we have a DXF file # the layer field should be populated with layer names if d.metadata['file_name'][-3:] == 'dxf': assert len(d.layers) == len(d.entities) for path in d.paths: verts = d.discretize_path(path) dists = g.np.sum((g.np.diff(verts, axis=0))**2, axis=1)**.5 if not g.np.all(dists > g.tol_path.zero): raise ValueError('{} had zero distance in discrete!', d.metadata['file_name']) circuit_dist = g.trimesh.util.euclidean(verts[0], verts[-1]) circuit_test = circuit_dist < g.tol_path.merge if not circuit_test: g.log.error('On file %s First and last vertex distance %f', d.metadata['file_name'], circuit_dist) assert circuit_test is_ccw = g.trimesh.path.util.is_ccw(verts) if not is_ccw: g.log.error('discrete %s not ccw!', d.metadata['file_name']) for i in range(len(d.paths)): assert d.polygons_closed[i].is_valid assert d.polygons_closed[i].area > g.tol_path.zero export_dict = d.export(file_type='dict') to_dict = d.to_dict() assert isinstance(to_dict, dict) assert isinstance(export_dict, dict) assert len(to_dict) == len(export_dict) export_svg = d.export(file_type='svg') # NOQA simple = d.simplify() # NOQA split = d.split() g.log.info('Split %s into %d bodies, checking identifiers', d.metadata['file_name'], len(split)) for body in split: body.identifier if len(d.root) == 1: d.apply_obb() # store the X values of bounds ori = d.bounds.copy() # apply a translation d.apply_translation([10, 0]) # X should have translated by 10.0 assert g.np.allclose(d.bounds[:, 0] - 10, ori[:, 0]) # Y should not have moved assert g.np.allclose(d.bounds[:, 1], ori[:, 1]) if len(d.polygons_full) > 0 and len(d.vertices) < 150: g.log.info('Checking medial axis on %s', d.metadata['file_name']) m = d.medial_axis() assert len(m.entities) > 0 # shouldn't crash d.fill_gaps() # transform to first quadrant d.rezero() # run process manually d.process()