Пример #1
0
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
Пример #2
0
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)
Пример #3
0
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
Пример #4
0
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
Пример #5
0
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
Пример #6
0
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()
Пример #7
0
    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")
Пример #8
0
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)
Пример #9
0
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"))
Пример #10
0
def test_stl_importer_wrong_path():
    r"""Wrong filename"""
    with pytest.raises(FileNotFoundError):
        StlImporter("C:/stupid-filename.bad_extension")