from io import StringIO import os from os import fsencode, fsdecode import unittest import urllib.request import tempfile from pathlib import Path import pytest from build123d import BuildLine, Color, Line, Bezier, RadiusArc, Solid, Compound from build123d.importers import ( import_svg_as_buildline_code, import_brep, import_svg, import_step, import_stl, ) from build123d.geometry import Pos from build123d.exporters import ExportSVG from build123d.exporters3d import export_brep, export_step from build123d.build_enums import GeomType class ImportSVG(unittest.TestCase): def test_import_svg_as_buildline_code(self): # Create svg file with BuildLine() as test_obj: l1 = Bezier((0, 0), (0.25, -0.1), (0.5, -0.15), (1, 0)) l2 = Line(l1 @ 1, (1, 1)) l3 = RadiusArc(l2 @ 1, (0, 1), 2) l4 = Line(l3 @ 1, l1 @ 0) svg = ExportSVG() svg.add_shape(test_obj.wires()[0], "") svg.write("test.svg") # Read the svg as code buildline_code, builder_name = import_svg_as_buildline_code("test.svg") # Execute it and convert to Edges ex_locals = {} exec(buildline_code, None, ex_locals) test_obj: BuildLine = ex_locals[builder_name] found = 0 for edge in test_obj.edges(): if edge.geom_type == GeomType.BEZIER: found += 1 elif edge.geom_type == GeomType.LINE: found += 1 elif edge.geom_type == GeomType.ELLIPSE: found += 1 self.assertEqual(found, 4) os.remove("test.svg") def test_import_svg_as_buildline_code_invalid_name(self): # Create svg file with BuildLine() as test_obj: l1 = Bezier((0, 0), (0.25, -0.1), (0.5, -0.15), (1, 0)) l2 = Line(l1 @ 1, (1, 1)) l3 = RadiusArc(l2 @ 1, (0, 1), 2) l4 = Line(l3 @ 1, l1 @ 0) svg = ExportSVG() svg.add_shape(test_obj.wires()[0], "") svg.write("test!.svg") # Read the svg as code buildline_code, builder_name = import_svg_as_buildline_code("test!.svg") os.remove("test!.svg") self.assertEqual(builder_name, "builder") def test_import_svg(self): svg_file = Path(__file__).parent / "../tests/svg_import_test.svg" for tag in ["id", "label"]: # Import the svg object as a ShapeList svg = import_svg( svg_file, label_by=tag, is_inkscape_label=tag == "label", ) # Exact the shape of the plate & holes base_faces = svg.filter_by(lambda f: "base" in f.label) hole_faces = svg.filter_by(lambda f: "hole" in f.label) test_wires = svg.filter_by(lambda f: "wire" in f.label) self.assertEqual(len(list(base_faces)), 1) self.assertEqual(len(list(hole_faces)), 2) self.assertEqual(len(list(test_wires)), 1) def test_import_svg_colors(self): svg_file = StringIO( '' '' '' '' "" ) svg = import_svg(svg_file) self.assertEqual(len(svg), 3) self.assertEqual(str(svg[0].color), str(Color(0, 0, 1, 1))) self.assertEqual(str(svg[1].color), str(Color(1, 0, 0, 1))) self.assertEqual(str(svg[2].color), str(Color(0, 0, 0, 1))) class ImportBREP(unittest.TestCase): def test_bad_filename(self): with self.assertRaises(ValueError): import_brep("test.brep") class ImportSTEP(unittest.TestCase): @classmethod def setUpClass(cls): """setUpClass is a class method that is executed once for the entire test class before any of the test methods in the class are executed. It's intended for setting up expensive resources or doing tasks that are required by all tests in the class, such as downloading a large file, establishing a database connection, or starting a server. """ url = "https://raw.githubusercontent.com/tpaviot/pythonocc-demos/master/assets/models/as1-oc-214.stp" temp_dir = tempfile.gettempdir() file_path = os.path.join(temp_dir, "as1-oc-214.stp") if not os.path.exists(file_path): urllib.request.urlretrieve(url, file_path) cls.large_step_file_path = file_path def test_single_object(self): export_step(Solid.make_box(1, 1, 1), "test.step") box = import_step("test.step") self.assertTrue(isinstance(box, Solid)) def test_move_single_object(self): export_step(Solid.make_box(1, 1, 1), "test.step") box = import_step("test.step") box_moved = Pos(X=1) * box self.assertEqual(tuple(box_moved.location.position), (1, 0, 0)) def test_single_label_color(self): box_to_export = Solid.make_box(1, 1, 1) box_to_export.label = "box" box_to_export.color = Color("blue") export_step(box_to_export, "test.step") imported_box = import_step("test.step") self.assertTrue(isinstance(imported_box, Solid)) self.assertEqual(imported_box.label, "box") self.assertEqual(tuple(imported_box.color), (0, 0, 1, 1)) def test_single_label_color(self): a = Solid.make_sphere(1) a.color = Color("red") a.label = "sphere" b = Solid.make_box(1, 1, 1).locate(Pos(-1, -2, -3)) b.color = Color("blue") b.label = "box" assembly = Compound(children=[a, b]) assembly.label = "assembly" assembly.color = Color("green") export_step(assembly, "test.step") imported_assembly = import_step("test.step") self.assertTrue(isinstance(imported_assembly, Compound)) self.assertTrue(isinstance(imported_assembly.children[0], Solid)) self.assertTrue(isinstance(imported_assembly.children[1], Solid)) self.assertEqual(imported_assembly.label, "assembly") self.assertEqual(imported_assembly.children[0].label, "sphere") self.assertEqual(tuple(imported_assembly.children[0].color), (1, 0, 0, 1)) self.assertEqual(imported_assembly.children[1].label, "box") self.assertEqual(tuple(imported_assembly.children[1].color), (0, 0, 1, 1)) def test_assembly_with_oriented_parts(self): assembly = import_step(self.large_step_file_path) fused = Solid.fuse(*assembly.solids()) # If the parts where placed correctly they all touch and can be fused self.assertEqual(len(fused.solids()), 1) @pytest.mark.parametrize( "format", (Path, fsencode, fsdecode), ids=["path", "bytes", "str"] ) @pytest.mark.parametrize( "importer,file", [ (import_svg, Path(__file__).parent / "svg_import_test.svg"), (import_svg_as_buildline_code, Path(__file__).parent / "svg_import_test.svg"), (import_stl, Path(__file__).parent / "cyl_w_rect_hole.stl"), ], ids=["svg", "svg_code", "stl"], ) def test_pathlike_import(format, importer, file): file = format(file) importer(file) @pytest.mark.parametrize( "format", (Path, fsencode, fsdecode), ids=["path", "bytes", "str"] ) def test_pathlike_step(format, tmp_path): step_file = format(tmp_path / "test.step") export_step(Solid.make_box(1, 1, 1), step_file) import_step(step_file) @pytest.mark.parametrize( "format", (Path, fsencode, fsdecode), ids=["path", "bytes", "str"] ) def test_pathlike_brep(format, tmp_path): brep_file = format(tmp_path / "test.brep") export_brep(Solid.make_box(1, 1, 1), brep_file) import_brep(brep_file) if __name__ == "__main__": unittest.main()