From 0cebc2e9f39921daa9c11d4808f4aa4a505ac5fb Mon Sep 17 00:00:00 2001 From: Aleksei S Date: Wed, 14 Feb 2018 14:03:57 +0100 Subject: [PATCH] Added plugin for reading cad files with .step file extension CURA-4891 --- plugins/STEPReader/StepReader.py | 109 +++++++++++++++++++++++++++++++ plugins/STEPReader/__init__.py | 20 ++++++ plugins/STEPReader/plugin.json | 8 +++ plugins/STEPReader/stl.py | 71 ++++++++++++++++++++ 4 files changed, 208 insertions(+) create mode 100644 plugins/STEPReader/StepReader.py create mode 100644 plugins/STEPReader/__init__.py create mode 100644 plugins/STEPReader/plugin.json create mode 100644 plugins/STEPReader/stl.py diff --git a/plugins/STEPReader/StepReader.py b/plugins/STEPReader/StepReader.py new file mode 100644 index 0000000000..1e1481b600 --- /dev/null +++ b/plugins/STEPReader/StepReader.py @@ -0,0 +1,109 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Uranium is released under the terms of the LGPLv3 or higher. + +from UM.Mesh.MeshReader import MeshReader +from UM.Mesh.MeshBuilder import MeshBuilder +from UM.Logger import Logger +from UM.Scene.SceneNode import SceneNode +from UM.Job import Job + + +from os.path import abspath, join, dirname + +import OCC.GProp +import OCC.BRepGProp + + +import OCC.BRep +import OCC.IFSelect +import OCC.Interface +import OCC.STEPControl +import OCC.TopoDS + +import OCC.BRepBuilderAPI +import OCC.gp +import OCC.TopoDS + +from OCC.gp import gp_Pnt + +from .stl import StlExporter + +from aocutils.analyze.bounds import BoundingBox + + +class STEPReader(MeshReader): + def __init__(self): + super(STEPReader, self).__init__() + self._supported_extensions = [".step"] + + def read(self, file_name): + + mesh_builder = MeshBuilder() + mesh_builder.setFileName(file_name) + scene_node = SceneNode() + + self._shapes = list() + + stepcontrol_reader = OCC.STEPControl.STEPControl_Reader() + status = stepcontrol_reader.ReadFile(file_name) + + if status == OCC.IFSelect.IFSelect_RetDone: + stepcontrol_reader.PrintCheckLoad(False, OCC.IFSelect.IFSelect_ItemsByEntity) + nb_roots = stepcontrol_reader.NbRootsForTransfer() + + if nb_roots == 0: + return None + + stepcontrol_reader.PrintCheckTransfer(False, OCC.IFSelect.IFSelect_ItemsByEntity) + + self._number_of_shapes = stepcontrol_reader.NbShapes() + + for n in range(1, nb_roots + 1): + ok = stepcontrol_reader.TransferRoot(n) + if ok: + a_shape = stepcontrol_reader.Shape(n) + if a_shape.IsNull(): + return None + else: + self._shapes.append(a_shape) + + step_ = abspath(join(dirname(__file__), "./test_model.stl")) + + self.shape_to_stl(a_shape, step_, scale=1., ascii_mode_=True, factor_=4000., use_min_dim_=False) + + return scene_node + + def shape_to_stl(self, shape_, stl_file_, scale, ascii_mode_, factor_, use_min_dim_): + + exporter = StlExporter(filename=stl_file_, ascii_mode=ascii_mode_) + shape_ = self.scale_uniform(shape_, gp_Pnt(0, 0, 0), scale, False) + + self.createMesh(shape_, factor=factor_, use_min_dim=use_min_dim_) + + exporter.set_shape(shape_) + exporter.write_file() + + + def initSceneNode(self, m_shape): + print() + + + def createMesh(self,shape, factor=4000., use_min_dim=False): + bb = BoundingBox(shape) + if use_min_dim: + linear_deflection = bb.min_dimension / factor + + OCC.BRepMesh.BRepMesh_IncrementalMesh(shape, linear_deflection) + else: + linear_deflection = bb.max_dimension / factor + + OCC.BRepMesh.BRepMesh_IncrementalMesh(shape, linear_deflection) + + def scale_uniform(self, brep, pnt, factor, copy=False): + + trns = OCC.gp.gp_Trsf() + trns.SetScale(pnt, factor) + brep_trns = OCC.BRepBuilderAPI.BRepBuilderAPI_Transform(brep, trns, copy) + brep_trns.Build() + + return brep_trns.Shape() \ No newline at end of file diff --git a/plugins/STEPReader/__init__.py b/plugins/STEPReader/__init__.py new file mode 100644 index 0000000000..da1a17cdab --- /dev/null +++ b/plugins/STEPReader/__init__.py @@ -0,0 +1,20 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Uranium is released under the terms of the LGPLv3 or higher. + +from . import StepReader + +from UM.i18n import i18nCatalog +i18n_catalog = i18nCatalog("uranium") + +def getMetaData(): + return { + "mesh_reader": [ + { + "extension": "step", + "description": i18n_catalog.i18nc("@item:inlistbox", "STEP File") + } + ] + } + +def register(app): + return { "mesh_reader": StepReader.STEPReader() } diff --git a/plugins/STEPReader/plugin.json b/plugins/STEPReader/plugin.json new file mode 100644 index 0000000000..90d7deaec4 --- /dev/null +++ b/plugins/STEPReader/plugin.json @@ -0,0 +1,8 @@ +{ + "name": "STEP Reader", + "author": "Ultimaker B.V.", + "version": "1.0.0", + "description": "Provides support for reading STEP files.", + "api": 4, + "i18n-catalog": "uranium" +} diff --git a/plugins/STEPReader/stl.py b/plugins/STEPReader/stl.py new file mode 100644 index 0000000000..2476ed9786 --- /dev/null +++ b/plugins/STEPReader/stl.py @@ -0,0 +1,71 @@ + +from __future__ import print_function + +import logging + +import OCC.StlAPI +import OCC.TopoDS + +import aocxchange.exceptions +import aocxchange.extensions +import aocxchange.utils +import aocxchange.checks + +logger = logging.getLogger(__name__) + + +class StlImporter(object): + def __init__(self, filename): + logger.info("StlImporter instantiated with filename : %s" % filename) + + aocxchange.checks.check_importer_filename(filename, aocxchange.extensions.stl_extensions) + self._filename = filename + self._shape = None + + logger.info("Reading file ....") + self.read_file() + + def read_file(self): + stl_reader = OCC.StlAPI.StlAPI_Reader() + shape = OCC.TopoDS.TopoDS_Shape() + print(self._filename) + stl_reader.Read(shape, self._filename) + self._shape = shape + + @property + def shape(self): + r"""Shape""" + if self._shape.IsNull(): + raise AssertionError("Error: the shape is NULL") + else: + return self._shape + + +class StlExporter(object): + def __init__(self, filename=None, ascii_mode=False): + logger.info("StlExporter instantiated with filename : %s" % filename) + logger.info("StlExporter ascii : %s" % str(ascii_mode)) + + aocxchange.checks.check_exporter_filename(filename, + aocxchange.extensions.stl_extensions) + aocxchange.checks.check_overwrite(filename) + + self._shape = None # only one shape can be exported + self._ascii_mode = ascii_mode + self._filename = filename + + def set_shape(self, a_shape): + aocxchange.checks.check_shape(a_shape) + + self._shape = a_shape + + def write_file(self): + + stl_writer = OCC.StlAPI.StlAPI_Writer() + + try: + stl_writer.Write(self._shape, self._filename, self._ascii_mode) + except TypeError: + stl_writer.SetASCIIMode(self._ascii_mode) + stl_writer.Write(self._shape, self._filename) +