def write_stl_file(a_shape, filename, mode="ascii", linear_deflection=0.9, angular_deflection=0.5): """ export the shape to a STL file Be careful, the shape first need to be explicitely meshed using BRepMesh_IncrementalMesh a_shape: the topods_shape to export filename: the filename mode: optional, "ascii" by default. Can either be "binary" linear_deflection: optional, default to 0.001. Lower, more occurate mesh angular_deflection: optional, default to 0.5. Lower, more accurate_mesh """ assert not a_shape.IsNull() assert mode in ["ascii", "binary"] if os.path.isfile(filename): print("Warning: %s file already exists and will be replaced" % filename) # first mesh the shape mesh = BRepMesh_IncrementalMesh(a_shape, linear_deflection, False, angular_deflection, True) #mesh.SetDeflection(0.05) mesh.Perform() assert mesh.IsDone() stl_exporter = StlAPI_Writer() if mode == "ascii": stl_exporter.SetASCIIMode(True) else: # binary, just set the ASCII flag to False stl_exporter.SetASCIIMode(False) stl_exporter.Write(a_shape, filename) assert os.path.isfile(filename)
def write_2_stl(occtopology, stl_filepath, linear_deflection = 0.8, angle_deflection = 0.5): """ This function writes a 3D model into STL format. Parameters ---------- occtopology : OCCtopology Geometries to be written into STL. OCCtopology includes: OCCshape, OCCcompound, OCCcompsolid, OCCsolid, OCCshell, OCCface, OCCwire, OCCedge, OCCvertex stl_filepath : str The file path of the STL file. mesh_incremental_float : float, optional Default = 0.8. Returns ------- None : None The geometries are written to a STL file. """ from OCC.StlAPI import StlAPI_Writer from OCC.BRepMesh import BRepMesh_IncrementalMesh from OCC.TopoDS import TopoDS_Shape # Export to STL stl_writer = StlAPI_Writer() stl_writer.SetASCIIMode(True) occtopology = TopoDS_Shape(occtopology) mesh = BRepMesh_IncrementalMesh(occtopology, linear_deflection, True, angle_deflection, True) assert mesh.IsDone() stl_writer.Write(occtopology,stl_filepath)
def export(self, event): """ Export the current model to stl """ from OCC.StlAPI import StlAPI_Writer from OCC.BRepMesh import BRepMesh_IncrementalMesh #: TODO: All parts options = event.parameters.get('options') if not isinstance(options, ExportOptions): return False exporter = StlAPI_Writer() exporter.SetASCIIMode(not options.binary) #: Make a compound of compounds (if needed) compound = TopoDS_Compound() builder = BRep_Builder() builder.MakeCompound(compound) for part in self.parts: #: Must mesh the shape first if isinstance(part, Part): builder.Add(compound, part.proxy.shape) else: builder.Add(compound, part.proxy.shape.Shape()) #: Build the mesh mesh = BRepMesh_IncrementalMesh(compound, options.linear_deflection, options.relative, options.angular_deflection) mesh.Perform() if not mesh.IsDone(): raise ExportError("Failed to create the mesh") exporter.Write(compound, options.path)
def exportStl(self, fileName, precision=1e-5): mesh = BRepMesh_IncrementalMesh(self.wrapped, precision, True) mesh.Perform() writer = StlAPI_Writer() return writer.Write(self.wrapped, fileName)
def write_file(self): r"""Write file""" mesh = BRepMesh_IncrementalMesh( self._shape, self._line_deflection, self._is_relative, self._angular_deflection, self._in_parallel) mesh.Perform() stl_writer = StlAPI.StlAPI_Writer() stl_writer.SetASCIIMode(self._ascii_mode) stl_writer.Write(self._shape, self._filename) logger.info("Wrote STL file")
def export(self): """ Export a DeclaraCAD model from an enaml file to an STL based on the given options. Parameters ---------- options: declaracad.occ.plugin.ExportOptions """ from OCC.BRep import BRep_Builder from OCC.BRepMesh import BRepMesh_IncrementalMesh from OCC.StlAPI import StlAPI_Writer from OCC.TopoDS import TopoDS_Compound # Make a compound of compounds (if needed) compound = TopoDS_Compound() builder = BRep_Builder() builder.MakeCompound(compound) # Load the enaml model file parts = load_model(self.filename) for part in parts: # Render the part from the declaration shape = part.render() # Must mesh the shape firsts if hasattr(shape, 'Shape'): builder.Add(compound, shape.Shape()) else: builder.Add(compound, shape) #: Build the mesh exporter = StlAPI_Writer() exporter.SetASCIIMode(not self.binary) mesh = BRepMesh_IncrementalMesh( compound, self.linear_deflection, self.relative, self.angular_deflection ) mesh.Perform() if not mesh.IsDone(): raise RuntimeError("Failed to create the mesh") exporter.Write(compound, self.path) if not os.path.exists(self.path): raise RuntimeError("Failed to write shape")
def build_bounding_box(self, shape, tol=1e-6, triangulate=False, triangulate_tol=1e-1): """ Builds a bounding box around the given shape. All parameters are set to match the computed box, the deformed FFD points are reset. :param shape: the shape to compute the bounding box. :type shape: TopoDS_Shape or its subclass :param float tol: tolerance of the computed bounding box. :param bool triangulate: if True, shape is triangulated before the bouning box creation. :param float triangulate_tol: tolerance of triangulation (size of created triangles). .. note:: Every UV-Surface has to be rectangular. When a solid is created surfaces are trimmed. The trimmed part, however, is still saved inside a file. It is just *invisible* when drawn in a program. """ bbox = Bnd_Box() bbox.SetGap(tol) if triangulate: BRepMesh_IncrementalMesh(shape, triangulate_tol) brepbndlib_Add(shape, bbox, triangulate) xmin, ymin, zmin, xmax, ymax, zmax = bbox.Get() min_xyz = np.array([xmin, ymin, zmin]) max_xyz = np.array([xmax, ymax, zmax]) self.origin_box = min_xyz self.lenght_box = max_xyz - min_xyz self.reset_deformation()
def occ_triangle_mesh(event=None): # # Mesh the shape # BRepMesh_IncrementalMesh(aShape, 0.1) builder = BRep_Builder() Comp = TopoDS_Compound() builder.MakeCompound(Comp) ex = TopExp_Explorer(aShape, TopAbs_FACE) while ex.More(): F = topods_Face(ex.Current()) L = TopLoc_Location() facing = (BRep_Tool().Triangulation(F, L)).GetObject() tab = facing.Nodes() tri = facing.Triangles() for i in range(1, facing.NbTriangles() + 1): trian = tri.Value(i) #print trian index1, index2, index3 = trian.Get() for j in range(1, 4): if j == 1: M = index1 N = index2 elif j == 2: N = index3 elif j == 3: M = index2 ME = BRepBuilderAPI_MakeEdge(tab.Value(M), tab.Value(N)) if ME.IsDone(): builder.Add(Comp, ME.Edge()) ex.Next() display.DisplayShape(Comp, update=True)
def _calculate_bb_dimension(shape, tol=1e-6, triangulate=False, triangulate_tol=1e-1): """ Calculate dimensions (minima and maxima) of a box bounding the :param TopoDS_Shape shape: or a subclass such as TopoDS_Face the shape to compute the bounding box from :param float tol: tolerance of the computed bounding box :param bool triangulate: Should shape be triangulated before the boudning box is created. If ``True`` only the dimensions of the bb will take into account every part of the shape (also not *visible*) If ``False`` only the *visible* part is taken into account \*See :meth:`~params.FFDParameters.build_bounding_box` :param float triangulate_tol: tolerance of triangulation (size of created triangles) :return: coordinates of minima and maxima along XYZ :rtype: tuple """ bbox = Bnd_Box() bbox.SetGap(tol) if triangulate: BRepMesh_IncrementalMesh(shape, triangulate_tol) brepbndlib_Add(shape, bbox, triangulate) xmin, ymin, zmin, xmax, ymax, zmax = bbox.Get() xyz_min = np.array([xmin, ymin, zmin]) xyz_max = np.array([xmax, ymax, zmax]) return xyz_min, xyz_max
def _fromTopoDS(cls, shape, tol=TOL, optimal=False): ''' Constructs a bounnding box from a TopoDS_Shape ''' bbox = Bnd_Box() bbox.SetGap(tol) if optimal: raise NotImplementedError # brepbndlib_AddOptimal(shape, bbox) #this is 'exact' but expensive - not yet wrapped by PythonOCC else: mesh = BRepMesh_IncrementalMesh(shape, TOL, True) mesh.Perform() # this is adds +margin but is faster brepbndlib_Add(shape, bbox, True) return cls(bbox)
def simple_mesh(occshape, mesh_incremental_float=0.8): #TODO: figure out why is it that some surfaces do not work occshape = TopoDS_Shape(occshape) bt = BRep_Tool() BRepMesh_IncrementalMesh(occshape, mesh_incremental_float) occshape_face_list = fetch.geom_explorer(occshape, "face") occface_list = [] for occshape_face in occshape_face_list: location = TopLoc_Location() #occshape_face = modify.fix_face(occshape_face) facing = bt.Triangulation(occshape_face, location).GetObject() if facing: tab = facing.Nodes() tri = facing.Triangles() for i in range(1, facing.NbTriangles() + 1): trian = tri.Value(i) index1, index2, index3 = trian.Get() #print index1, index2, index3 pypt1 = fetch.occpt2pypt(tab.Value(index1)) pypt2 = fetch.occpt2pypt(tab.Value(index2)) pypt3 = fetch.occpt2pypt(tab.Value(index3)) #print pypt1, pypt2, pypt3 occface = make_polygon([pypt1, pypt2, pypt3]) occface_list.append(occface) return occface_list
def write_stl(shape, filename, df=0.1): from OCC.StlAPI import StlAPI_Writer import os directory = os.path.split(__name__)[0] stl_output_dir = os.path.abspath(directory) assert os.path.isdir(stl_output_dir) stl_file = os.path.join(stl_output_dir, filename) stl_writer = StlAPI_Writer() stl_writer.SetASCIIMode(False) from OCC.BRepMesh import BRepMesh_IncrementalMesh mesh = BRepMesh_IncrementalMesh(shape, df) mesh.Perform() assert mesh.IsDone() stl_writer.Write(shape, stl_file) assert os.path.isfile(stl_file)
def analyze_file(filename): step_reader = STEPControl_Reader() status = step_reader.ReadFile(str(filename)) result = None if status == IFSelect_RetDone: # check status number_of_roots = step_reader.NbRootsForTransfer() ok = False i = 1 while i <= number_of_roots and not ok: ok = step_reader.TransferRoot(i) i += 1 if (not ok): return { 'error': 'Failed to find a suitable root for the STEP file' } number_of_shapes = step_reader.NbShapes() if (number_of_shapes > 1): return {'error': 'Cannot handle more than one shape in a file'} aResShape = step_reader.Shape(1) # bounding box bbox = Bnd_Box() deflection = 0.01 BRepMesh_IncrementalMesh(aResShape, deflection) brepbndlib_Add(aResShape, bbox) xmin, ymin, zmin, xmax, ymax, zmax = bbox.Get() bounding_box = calculate_bnd_box(bbox) result = { 'x0': bounding_box['x_min'], 'x1': bounding_box['x_max'], 'y0': bounding_box['y_min'], 'y1': bounding_box['y_max'], 'z0': bounding_box['z_min'], 'z1': bounding_box['z_max'], 'length': bounding_box['x_length'], 'width': bounding_box['z_length'], 'height': bounding_box['y_length'], 'volume': calculate_volume(aResShape) } else: result = {'error': 'Cannot read file'} return result
def get_boundingbox(shape, tol=1e-6, use_mesh=True): """ return the bounding box of the TopoDS_Shape `shape` Parameters ---------- shape : TopoDS_Shape or a subclass such as TopoDS_Face the shape to compute the bounding box from tol: float tolerance of the computed boundingbox use_mesh : bool a flag that tells whether or not the shape has first to be meshed before the bbox computation. This produces more accurate results """ bbox = Bnd_Box() bbox.SetGap(tol) if use_mesh: mesh = BRepMesh_IncrementalMesh() mesh.SetParallel(True) mesh.SetShape(shape) mesh.Perform() if not mesh.IsDone(): raise AssertionError("Mesh not done.") brepbndlib_Add(shape, bbox, use_mesh) xmin, ymin, zmin, xmax, ymax, zmax = bbox.Get() return xmin, ymin, zmin, xmax, ymax, zmax, xmax - xmin, ymax - ymin, zmax - zmin
def topods_shape_reader(shape, deflection=0.001): from OCC.StlAPI import StlAPI_Writer from OCC.BRepMesh import BRepMesh_IncrementalMesh import vtk stl_writer = StlAPI_Writer() with tmpfile(suffix='.stl') as tmpf: mesh = BRepMesh_IncrementalMesh(shape, deflection) mesh.Perform() assert mesh.IsDone() stl_writer.SetASCIIMode(False) stl_writer.Write(shape, tmpf[1]) tmpf[0].flush() reader = vtk.vtkSTLReader() reader.SetFileName(tmpf[1]) reader.Update() return reader
def simple_mesh(): # # Create the shape # shape = BRepPrimAPI_MakeBox(200, 200, 200).Shape() theBox = BRepPrimAPI_MakeBox(200, 60, 60).Shape() theSphere = BRepPrimAPI_MakeSphere(gp_Pnt(100, 20, 20), 80).Shape() shape = BRepAlgoAPI_Fuse(theSphere, theBox).Shape() # # Mesh the shape # BRepMesh_IncrementalMesh(shape, 0.8) builder = BRep_Builder() comp = TopoDS_Compound() builder.MakeCompound(comp) bt = BRep_Tool() ex = TopExp_Explorer(shape, TopAbs_FACE) while ex.More(): face = topods_Face(ex.Current()) location = TopLoc_Location() facing = (bt.Triangulation(face, location)).GetObject() tab = facing.Nodes() tri = facing.Triangles() for i in range(1, facing.NbTriangles()+1): trian = tri.Value(i) index1, index2, index3 = trian.Get() for j in range(1, 4): if j == 1: m = index1 n = index2 elif j == 2: n = index3 elif j == 3: m = index2 me = BRepBuilderAPI_MakeEdge(tab.Value(m), tab.Value(n)) if me.IsDone(): builder.Add(comp, me.Edge()) ex.Next() display.EraseAll() display.DisplayShape(shape) display.DisplayShape(comp, update=True)
def makeIncrementalMesh(shape, lindefl=0.1, angdefl=.07): """ Make mesh using BRepMesh_IncrementalMesh BRepMesh_IncrementalMesh was found to have some issues with the transitions radius (basically turning it into a chamfer instead, getting rid of the actual curvature), so SMESH was then explored. lindefl = Linear Deflection Setting angdefl = Angular Deflection Setting """ try: mesh = BRepMesh_IncrementalMesh(diffuser.Shape(), lindefl, True, angdefl, False) except: print('Mesh failed') else: if args.v >= 1: print(f'\nDiffuser shape has been meshed.') return mesh
def discretize(shape, tol): """This method discretizes the OpenCascade shape. :param shape: Shape to discretize :type shape: :return: discretized face; profile coordinates; id of the surface the\ coordinates belong to :rtype: OCC.TopoDS.TopoDS_Compound; numpy.ndarray; numpy.ndarray """ BRepMesh_IncrementalMesh(shape, tol, False, 5) builder = BRep_Builder() comp = TopoDS_Compound() builder.MakeCompound(comp) bt = BRep_Tool() ex = TopExp_Explorer(shape, TopAbs_EDGE) edge_coords = np.zeros([0, 3]) edge_ids = np.zeros([0], dtype=int) edge_id = 0 while ex.More(): edge = topods_Edge(ex.Current()) location = TopLoc_Location() edging = (bt.Polygon3D(edge, location)).GetObject() tab = edging.Nodes() for i in range(1, edging.NbNodes() + 1): p = tab.Value(i) edge_coords = np.append(edge_coords, [[p.X(), p.Y(), p.Z()]], axis=0) edge_ids = np.append(edge_ids, edge_id) mv = BRepBuilderAPI_MakeVertex(p) if mv.IsDone(): builder.Add(comp, mv.Vertex()) edge_id += 1 ex.Next() edge_coords = np.round(edge_coords, 8) return edge_coords, edge_ids
def __init__(self, shape): from OCC.BRep import BRep_Tool from OCC.BRepMesh import BRepMesh_IncrementalMesh from OCC.TopAbs import TopAbs_FACE, TopAbs_VERTEX from OCC.TopExp import TopExp_Explorer from OCC.TopLoc import TopLoc_Location from OCC.TopoDS import topods_Face, topods_Vertex, TopoDS_Iterator vertices = [] # a (nested) list of vec3 triangles = [] # a (flat) list of integers normals = [] uv = [] # Mesh the shape linDeflection = 0.8 BRepMesh_IncrementalMesh(shape, linDeflection) bt = BRep_Tool() # Explore the faces of the shape # each face is triangulated, we need to collect all the parts expFac = TopExp_Explorer(shape, TopAbs_FACE) while expFac.More(): face = topods_Face(expFac.Current()) location = TopLoc_Location() facing = (bt.Triangulation(face, location)).GetObject() try: tri = facing.Triangles() nTri = facing.NbTriangles() ver = facing.Nodes() except: tri = None nTri = None ver = None # store origin of the face's local coordinates transf = face.Location().Transformation() # iterate over triangles and store indices of vertices defining each triangle # OCC uses one-based indexing for i in range(1, nTri + 1): # each triangle is defined by three points # each point is defined by its index in the list of vertices index1, index2, index3 = tri.Value(i).Get() indices = [index1, index2, index3] # python uses zero-based indexing # for each vertex of a triangle, check whether it is already known # then store it (or not) and update the index for idx in [0, 1, 2]: # read global coordinates of each point vec3 = [ ver.Value(indices[idx]).Transformed(transf).X(), ver.Value(indices[idx]).Transformed(transf).Y(), ver.Value(indices[idx]).Transformed(transf).Z() ] if vec3 not in vertices: vertices.append(vec3) indices[idx] = vertices.index(vec3) triangles.extend(indices) expFac.Next() self.shape = shape self.vertices = vertices self.triangles = triangles self.normals = normals self.uv = uv
##GNU Lesser General Public License for more details. ## ##You should have received a copy of the GNU Lesser General Public License ##along with pythonOCC. If not, see <http://www.gnu.org/licenses/>. import os from OCC.StlAPI import StlAPI_Writer from OCC.BRepPrimAPI import BRepPrimAPI_MakeTorus from OCC.BRepMesh import BRepMesh_IncrementalMesh # first, create the shape my_torus = BRepPrimAPI_MakeTorus(20., 10.).Shape() # then mesh it. This mesh is used by the STL exporter # Note : if the mesh is not performed, the STL exporter # won't do nothing mesh = BRepMesh_IncrementalMesh(my_torus, 0.9) mesh.Perform() assert mesh.IsDone() # set the directory where to output the directory = os.path.split(__name__)[0] stl_output_dir = os.path.abspath(os.path.join(directory, "models")) # make sure the path exists otherwise OCE get confused assert os.path.isdir(stl_output_dir) stl_low_resolution_file = os.path.join(stl_output_dir, "torus_low_resolution.stl") stl_exporter = StlAPI_Writer() stl_exporter.SetASCIIMode(True) # change to False if you need binary export stl_exporter.Write(my_torus, stl_low_resolution_file) # make sure the program was created
def Mesh(shape): mesh = BRepMesh_IncrementalMesh(shape, 0.6) mesh.Perform()
def analyze_file(filename): step_reader = STEPControl_Reader() status = step_reader.ReadFile(filename) result = None if status == IFSelect_RetDone: # check status number_of_roots = step_reader.NbRootsForTransfer() ok = False i = 1 while i <= number_of_roots and not ok: ok = step_reader.TransferRoot(i) i += 1 if (not ok): return { 'error': 'Failed to find a suitable root for the STEP file' } number_of_shapes = step_reader.NbShapes() if (number_of_shapes > 1): return {'error': 'Cannot handle more than one shape in a file'} aResShape = step_reader.Shape(1) # Units length = TColStd_SequenceOfAsciiString() angles = TColStd_SequenceOfAsciiString() solid_angles = TColStd_SequenceOfAsciiString() step_reader.FileUnits(length, angles, solid_angles) # bounding box bbox = Bnd_Box() deflection = 0.01 BRepMesh_IncrementalMesh(aResShape, deflection) brepbndlib_Add(aResShape, bbox) xmin, ymin, zmin, xmax, ymax, zmax = bbox.Get() bounding_box = calculate_bnd_box(bbox) bounding_cylinder = calculate_bounding_cylinder( aResShape, bounding_box) result = { 'bounding_box_volume': bounding_box['volume'], 'bounding_box_x_length': bounding_box['x_length'], 'bounding_box_y_length': bounding_box['y_length'], 'bounding_box_z_length': bounding_box['z_length'], 'mesh_volume': calculate_volume(aResShape), 'mesh_surface_area': None, 'cylinder_volume': bounding_cylinder['cylinder_volume'], 'cylinder_diameter': bounding_cylinder['radius'] * 2, 'cylinder_length': bounding_cylinder['height'], 'convex_hull_volume': None, 'euler_number': None, 'units': length.First().ToCString().lower() } else: result = {'error': 'Cannot read file'} return result