def test_stl_importer_2_boxes(): r"""Import an iges file containing 2 distinct boxes and test topology Notes ----- This shows the current limitations of the IgesImporter as 2 boxes cannot be distinguished from one another """ # binary STL importer = StlImporter( path_from_file(__file__, "./models_in/2_boxes_binary.stl")) topo = Topo(importer.shape, return_iter=False) # assert len(topo.solids) == 2 assert len(topo.shells) == 2 assert topo.shells[0].Closed() is True assert topo.shells[1].Closed() is True assert topo.number_of_faces == 108 * 2 assert topo.number_of_edges == 162 * 2 # ascii STL importer = StlImporter( path_from_file(__file__, "./models_in/2_boxes_ascii.stl")) topo = Topo(importer.shape, return_iter=False) # assert len(topo.solids()) == 2 assert len(topo.shells) == 2 assert topo.shells[0].Closed() is True assert topo.shells[1].Closed() is True assert topo.number_of_faces == 108 * 2 assert topo.number_of_edges == 162 * 2
def convert_stl_file(stl_filename, target_folder, remove_original=True): r"""Convert a STL file (.stl) for web display Parameters ---------- stl_filename : str Full path to the STL file target_folder : str Full path to the target folder for the conversion remove_original : bool Should the input file be deleted after conversion? It should be deleted on a web platform to save disk space, but, for testing, it might be useful not to delete it. Returns ------- Nothing, it is a procedure """ if not isdir(target_folder): mkdir(target_folder) importer = StlImporter(stl_filename) converted_filename = _conversion_filename(stl_filename, target_folder, 0) converted_basenames = [basename(converted_filename)] _convert_shape(importer.shape, converted_filename) max_dim = BoundingBox(importer.shape).max_dimension _write_descriptor( max_dim, converted_basenames, _descriptor_filename(target_folder, basename(stl_filename))) if remove_original is True: remove(stl_filename)
def test_stl_importer_happy_topology(): r"""import iges file containing a box and test topology""" # binary STL importer = StlImporter(path_from_file(__file__, "./models_in/box_binary.stl")) topo = Topo(importer.shape, return_iter=False) # assert len(topo.solids()) == 1 assert len(topo.shells) == 1 assert topo.shells[0].Closed() is True # direct method on TopoDS_Shell assert len(topo.faces) == 108 assert len(topo.edges) == 162 # ascii STL importer = StlImporter(path_from_file(__file__, "./models_in/box_ascii.stl")) topo = Topo(importer.shape, return_iter=False) # assert len(topo.solids) == 1 assert len(topo.shells) == 1 assert topo.shells[0].Closed() is True assert len(topo.faces) == 108 assert len(topo.edges) == 162
def test_stl_exporter_overwrite(box_shape): r"""Happy path with a subclass of TopoDS_Shape""" filename = path_from_file(__file__, "./models_out/box.stl") exporter = StlExporter(filename) solid = shape_to_topology(box_shape) assert isinstance(solid, TopoDS_Solid) exporter.set_shape(solid) exporter.write_file() assert os.path.isfile(filename) # read the written box.stl importer = StlImporter(filename) topo = Topo(importer.shape) assert topo.number_of_shells == 1 # set a sphere and write again with same exporter sphere = BRepPrimAPI_MakeSphere(10) exporter.set_shape(sphere.Shape()) # this creates a file with a sphere only, this is STL specific exporter.write_file() # check that the file contains the sphere only importer = StlImporter(filename) topo = Topo(importer.shape) assert topo.number_of_shells == 1 # create a new exporter and overwrite with a box only filename = path_from_file(__file__, "./models_out/box.stl") exporter = StlExporter(filename) solid = shape_to_topology(box_shape) exporter.set_shape(solid) exporter.write_file() assert os.path.isfile(filename) # check the file only contains a box importer = StlImporter(filename) topo = Topo(importer.shape) assert topo.number_of_shells == 1
def handle_cad_file_open(): r"""Handle the logic of cad file opening Returns ------- path : str type_ : str iges, step, stl brep shapes: list[OCC.TopoDS.TopoDS_Shape] """ with OpenCadDialog() as open_cad_file_dialog: if open_cad_file_dialog.ShowModal() == wx.ID_OK: # cast the path from the FileDialog to st to avoid # TypeError: in method 'XSControl_Reader_ReadFile', # argument 2 of type 'char const *' path = str(open_cad_file_dialog.GetPath()) extension = extract_file_extension(path) if extension.lower() in step_extensions: type_ = "step" shapes = StepImporter(path).shapes elif extension.lower() in iges_extensions: type_ = "iges" shapes = IgesImporter(path).shapes elif extension.lower() in stl_extensions: type_ = "stl" shapes = list() shapes.append(StlImporter(path).shape) elif extension.lower() in brep_extensions: type_ = "brep" shapes = list() shapes.append(BrepImporter(path).shape) else: raise ValueError("File extension indicates a file type that " "is not supported") # return filepath + type (iges ...) + list of shapes return path, type_, shapes else: # cancel button return None, None, None
from aocutils.display.topology import shells from aocutils.display.defaults import backend from aocxchange.stl import StlImporter # from corelib.core.files import path_from_file from corelibpy import path_from_file logging.basicConfig(level=logging.DEBUG, format='%(asctime)s :: %(levelname)6s :: %(module)20s :: ' '%(lineno)3d :: %(message)s') # open/parse STL file and get the resulting TopoDS_Shape instance # filename = path_from_file(__file__, "./models_in/sample.stl") # filename = path_from_file(__file__, "./models_in/USS_Albacore.STL") filename = path_from_file(__file__, "./models_in/stl/USS_Albacore.STL") my_stl_importer = StlImporter(filename) the_shape = my_stl_importer.shape # Then display the shape backend = backend display, start_display, add_menu, add_function_to_menu = init_display(backend) # display.DisplayShape(the_shape, color='BLUE', update=True) # 1 shell to display shells(display, the_shape) # faces # faces(display, the_shape, show_numbers=False) # super slow !! display.FitAll() display.View_Iso() start_display()
def on_selected_change(self, change): """Callback function for listener""" # TODO: investigate why importing Part # at top of file causes an app crash from cadracks_core.model import Part logger.debug("Selection changed") sel = self.model.selected logger.debug("sel : %s" % sel) if not isdir(sel): # what extension ? ext = splitext(sel)[1].lower() logger.info("File extension : %s" % ext) if ext == ".py": with open(sel) as f: content = f.read() if is_valid_python(content) is True: busy_info = wx.BusyInfo( "Loading Python defined geometry ...") try: module_ = imp.load_source(sel, sel) has_shape = hasattr(module_, "__shape__") has_shapes = hasattr(module_, "__shapes__") has_anchors = hasattr(module_, "__anchors__") has_properties = hasattr(module_, "__properties__") has_assembly = hasattr(module_, "__assembly__") has_assemblies = hasattr(module_, "__assemblies__") self.erase_all() if has_shapes is True: logger.info("%s has shapeS" % sel) for i, shape in enumerate(module_.__shapes__): self.display_shape(shape, color_=colour_wx_to_occ( color_from_sequence( i, "colors"))) elif has_assembly is True: logger.info("%s has assembly" % sel) try: self.display_assembly(module_.__assembly__) self.viewer_display.FitAll() except KeyError as ke: self.erase_all() logger.exception(ke) elif has_assemblies is True: logger.info("%s has assemblies" % sel) try: self.display_assemblies(module_.__assemblies__) self.viewer_display.FitAll() except KeyError as ke: self.erase_all() logger.exception(ke) # elif has_shape is True and has_anchors is True: elif has_shape is True: if has_anchors is False: logger.info("%s has shape" % sel) self.display_shape(module_.__shape__) else: logger.info("%s has shape and anchors" % sel) p = anchorable_part_from_py_script(sel) self.display_part(p) self.viewer_display.FitAll() else: self.erase_all() logger.warning("Nothing to display") except Exception as e: logger.error(str(e)) finally: del busy_info else: # the file is not a valid Python file logger.warning("Not a valid python file") self.erase_all() elif ext in [".step", ".stp"]: self.erase_all() busy_info = wx.BusyInfo("Loading STEP ...") try: shapes = StepImporter(sel).shapes logger.info("%i shapes in %s" % (len(shapes), sel)) for shape in shapes: color_255 = (255, 255, 255) self.display_shape(shape, color_=colour_wx_to_occ(color_255), transparency=0.1) self.viewer_display.FitAll() except Exception as e: logger.error(str(e)) finally: del busy_info elif ext in [".iges", ".igs"]: self.erase_all() busy_info = wx.BusyInfo("Loading IGES ...") try: shapes = IgesImporter(sel).shapes logger.info("%i shapes in %s" % (len(shapes), sel)) for shape in shapes: color_255 = (51, 255, 255) self.display_shape(shape, color_=colour_wx_to_occ(color_255), transparency=0.1) self.viewer_display.FitAll() except Exception as e: logger.error(str(e)) finally: del busy_info elif ext == ".stl": self.erase_all() busy_info = wx.BusyInfo("Loading STL ...") try: shape = StlImporter(sel).shape color_255 = (0, 255, 0) self.display_shape(shape, color_=colour_wx_to_occ(color_255), transparency=0.1) self.viewer_display.FitAll() except Exception as e: logger.error(str(e)) finally: del busy_info elif ext == ".json": # parts library self.erase_all() is_library_file = False with open(sel) as json_file: if "metadata" in json_file.read(): is_library_file = True if is_library_file is True: busy_info = wx.BusyInfo("Loading parts library ...") try: with open(sel) as json_file: json_file_content = json.load(json_file) # print(json_file_content["data"].keys()) # find the biggest bounding box biggest_bb = [0, 0, 0] # smallest_bb = [0, 0, 0] for i, k in enumerate( json_file_content["data"].keys()): library_part = anchorable_part_from_library( sel, k) bb = BoundingBox(library_part.shape) if bb.x_span > biggest_bb[0]: biggest_bb[0] = bb.x_span # if bb.x_span < smallest_bb[0]: # smallest_bb[0] = bb.x_span if bb.y_span > biggest_bb[1]: biggest_bb[1] = bb.y_span # if bb.y_span < smallest_bb[1]: # smallest_bb[1] = bb.y_span if bb.z_span > biggest_bb[2]: biggest_bb[2] = bb.z_span # if bb.z_span < smallest_bb[2]: # smallest_bb[2] = bb.y_span biggest_dimension = max(biggest_bb) # smallest_dimension = min(smallest_bb) nb_per_row = int( math.sqrt(len( json_file_content["data"].keys()))) for i, k in enumerate( json_file_content["data"].keys()): library_part = anchorable_part_from_library( sel, k) x_pos = biggest_dimension * 2 * (i % nb_per_row) y_pos = biggest_dimension * 2 * (i // nb_per_row) # Translate using an AnchorTransformation library_part.add_matrix_generator( AnchorTransformation( Anchor(p=(0, 0, 0), u=(1, 0, 0), v=(0, 1, 0), name='a'), Anchor(p=(x_pos, y_pos, 0), u=(1, 0, 0), v=(0, 1, 0), name='b'))) self.display_part(library_part, transparency=0.2, anchor_names_height=10) pnt_message = gp_Pnt( x_pos + biggest_dimension / 5, y_pos + biggest_dimension / 5, 0) self.display_message(pnt_message, k, message_color=(1, 1, 1), height=20) self.viewer_display.FitAll() except Exception as e: logger.error(str(e)) finally: del busy_info elif ext == ".stepzip": self.erase_all() busy_info = wx.BusyInfo("Loading STEPZIP ...") try: self.display_part(anchorable_part_from_stepzip(sel), transparency=0.2) self.viewer_display.FitAll() except Exception as e: logger.error(str(e)) finally: del busy_info else: logger.error("File has an extension %s that is not " "handled by the 3D panel" % ext) self.erase_all() else: # a directory is selected self.erase_all() self.Layout() logger.debug("code change detected in 3D panel")
def test_stl_importer_happy_path(): r"""happy path""" importer = StlImporter( path_from_file(__file__, "./models_in/box_binary.stl")) assert isinstance(importer.shape, TopoDS_Shape)
def test_stl_importer_wrong_extension(): r"""wrong file format (i.e. trying to read a step file with iges importer)""" with pytest.raises(IncompatibleFileFormatException): StlImporter(path_from_file(__file__, "./models_in/aube_pleine.stp"))
def test_stl_importer_wrong_path(): r"""Wrong filename""" with pytest.raises(FileNotFoundError): StlImporter("C:/stupid-filename.bad_extension")