def Write(self, path): if len(self.shapes)>0: u = self.shapes[0] for s in self.shapes[1:]: u = BRepAlgoAPI_Fuse(u, s).Shape() write_stl_file(u, path, mode=self.mode, linear_deflection=self.linear_deflection, angular_deflection=self.angular_deflection)
def main(): vertices = [gp_Pnt(p[0], p[1], p[2]) for p in mesh['vertices']] oFaces = [] builder = BRep_Builder() shell = TopoDS_Shell() builder.MakeShell(shell) for face in mesh['faces']: edges = [] face.reverse() for i in range(len(face)): cur = face[i] nxt = face[(i + 1) % len(face)] segment = GC_MakeSegment(vertices[cur], vertices[nxt]) edges.append(BRepBuilderAPI_MakeEdge(segment.Value())) wire = BRepBuilderAPI_MakeWire() for edge in edges: wire.Add(edge.Edge()) oFace = BRepBuilderAPI_MakeFace(wire.Wire()) builder.Add(shell, oFace.Shape()) write_stl_file(shell, "./cube_binding.stl")
def generate_stl(self, filename): """ Export the .stl CAD for the propeller with shaft. :param string filename: path (with the file extension) where to store the .stl CAD for the propeller and shaft :raises RuntimeError: if the solid assembling of blades is not completed successfully """ write_stl_file(self.sewed_full_body, filename)
def drawShape(self, shape): shape_precision, wire_precision = self.precision if is_edge(shape): pass elif is_wire(shape): pass else: #solid or shell print("export shape %s to STL start", str(self.shapeNum).zfill(3)) shape_hash = "exp_%s_shape" % str(self.shapeNum).zfill(3) shape_full_path = os.path.join(self._path, shape_hash + '.stl') write_stl_file(shape, shape_full_path, "ascii", shape_precision/4, 0.5/4) print("export shape %s to STL done", str(self.shapeNum).zfill(3)) self.shapeNum += 1
def exportFaces(self, topoDS_Assembly, topoDS_Compound, index): folder = self.folder + "/compound" + str(index) + "_faces" os.system("mkdir " + folder) # outFile = open(folder + "/faces.x3d", "w") self.dataStruct["compounds"].append("compound" + str(index) + "_faces") # self.printStart(outFile) for index, TopAbs_face in enumerate( topoDS_Assembly.faces_from_solids(topoDS_Compound)): color = Quantity_Color(random.random(), random.random(), random.random(), Quantity_TOC_RGB) tesselator = ShapeTesselator(TopAbs_face) tesselator.Compute(True) write_stl_file(TopAbs_face, folder + "/faces_" + str(index) + ".stl")
def exportSTL(cadObj, filename, linear_deflection=0.01, angular_deflection=0.5): compound = None if isinstance(cadObj, (_Assembly, _Part)): compound = cadObj.compound() elif isinstance(cadObj, TopoDS_Compound): compound = cadObj elif isinstance(cadObj, (cq.Shape, cq.Workplane)): compound = Part(cadObj).compound() else: print("Unsupported CAD object %s, convert to Assembly or Part" % type(cadObj)) if compound is not None: write_stl_file(compound, filename, linear_deflection=linear_deflection, angular_deflection=angular_deflection)
def importStep(self): if (self.display): self.display.EraseAll() assembly = readStepFile(self.path + self.name) os.system("mkdir " + self.folder) write_stl_file( assembly, self.folder + "/assembly_" + self.name.split('.')[0] + ".stl") topoDS_Assembly = TopologyExplorer(assembly) self.exportCompounds(topoDS_Assembly) for compound in topoDS_Assembly.solids(): color = Quantity_Color(random.random(), random.random(), random.random(), Quantity_TOC_RGB) if (self.display): self.display.DisplayColoredShape(compound, color) if (self.display): self.display.FitAll() configFile = open('config.json', "w") json.dump(self.dataStruct, configFile) print("end")
def exportCompounds(self, topoDS_Assembly, writeFaces=False): self.dataStruct["path"] = self.path + self.folder # outFile = open(folder + "/assembly_" + self.name.split('.')[0] +".x3d", "w") self.dataStruct["assemblyFile"] = "assembly_" + self.name.split( '.')[0] + ".x3d" self.dataStruct["compounds"] = [] # self.printStart(outFile) for index, topoDS_compound in enumerate(topoDS_Assembly.solids()): color = Quantity_Color(random.random(), random.random(), random.random(), Quantity_TOC_RGB) tesselator = ShapeTesselator(topoDS_compound) tesselator.Compute(True) ouputString = tesselator.ExportShapeToX3DIndexedFaceSet() write_stl_file( topoDS_compound, self.folder + "/compound_" + str(index) + "_" + self.name.split('.')[0] + ".stl") # self.exportObj(coords) # normals = ouputString.split("<Normal vector='")[1].split(" '></Normal>")[0].split(" ") # normals = [float(item) for item in normals] # print(len(normals)) # self.printHeader(outFile) # print(ouputString, file = outFile) # self.printFooter(outFile) self.exportFaces(topoDS_Assembly, topoDS_compound, index)
def test_stl_binary(self): stl_binary_filename = get_test_fullname("sample_binary.stl") write_stl_file(A_TOPODS_SHAPE, stl_binary_filename, mode="binary") self.assertTrue(os.path.isfile(stl_binary_filename))
def test_stl_ascii(self): stl_ascii_filename = get_test_fullname("sample_ascii.stl") write_stl_file(A_TOPODS_SHAPE, stl_ascii_filename, mode="ascii") self.assertTrue(os.path.isfile(stl_ascii_filename))
##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 OCCT.BRepPrimAPI import BRepPrimAPI_MakeTorus from OCC.Extend.DataExchange import write_stl_file # first, create the shape my_torus = BRepPrimAPI_MakeTorus(20., 10.).Shape() # set the directory where to output the stl_output_dir = os.path.abspath(os.path.join("..", "assets", "models")) # make sure the path exists otherwise OCE get confused if not os.path.isdir(stl_output_dir): raise AssertionError("wrong path provided") stl_low_resolution_file = os.path.join(stl_output_dir, "torus_default_resolution.stl") write_stl_file(my_torus, stl_low_resolution_file) # then we change the mesh resolution, and export as binary stl_high_resolution_file = os.path.join(stl_output_dir, "torus_high_resolution.stl") # we set the format to binary write_stl_file(my_torus, stl_low_resolution_file, mode="binary", linear_deflection=0.5, angular_deflection=0.3)
def export_stl_selected(self): comp = self.make_comp_selcted() stlname = create_tempnum(self.rootname, self.tmpdir, ".stl") write_stl_file(comp, stlname)
chf = BRepFilletAPI_MakeChamfer(box) # chf.Build() fil = BRepFilletAPI_MakeFillet(box) fil.SetFilletShape(ChFi3d_Rational) par = TColgp_Array1OfPnt2d(1, 2) par.SetValue(1, gp_Pnt2d(-1000, 10)) par.SetValue(2, gp_Pnt2d(1000, 10)) top = TopExp_Explorer(box, TopAbs_EDGE) fil.Add(par, top.Current()) top.Next() fil.Add(par, top.Current()) top.Next() fil.Add(par, top.Current()) write_step_file(box, obj.tmpdir + "box.stp") write_step_file(fil.Shape(), obj.tmpdir + "box_fillet.stp", "AP214IS") write_stl_file(fil.Shape(), obj.tmpdir + "box_fillet.stl") write_stl_file_mesh1(fil.Shape(), obj.tmpdir + "box_fillet_mesh1.stl", linear_deflection=0.1E-1, angular_deflection=0.1E-1) write_stl_file_mesh2(fil.Shape(), obj.tmpdir + "box_fillet_mesh2.stl", linear_deflection=0.1E-1, angular_deflection=0.1E-1) obj.display.DisplayShape(fil.Shape()) obj.display.DisplayShape(axs.Location()) obj.show()
def test_stl_binary(self): write_stl_file(A_TOPODS_SHAPE, get_test_fullname("sample_binary.stl"), mode="binary")
def test_stl_ascii(self): write_stl_file(A_TOPODS_SHAPE, get_test_fullname("sample_ascii.stl"), mode="ascii")
def construct_fitter(input_file): print("fitting", input_file) obj_mesh = trimesh.load(input_file) print(len(obj_mesh.faces)) if len(obj_mesh.faces) > 15000: sobj_mesh = obj_mesh.simplify_quadratic_decimation( len(obj_mesh.faces) // 20) else: sobj_mesh = obj_mesh print(len(sobj_mesh.faces)) print(sobj_mesh.scale) sobj_mesh.apply_scale(286 / sobj_mesh.scale) print(sobj_mesh.scale) trimesh.repair.fix_inversion(sobj_mesh) def get_simplified_slice(sobj_mesh): nice_slice = sobj_mesh.section(plane_origin=sobj_mesh.centroid + np.array([0, 0, 30]), plane_normal=[0.55, 0, 1]) sobj_mesh.visual.face_colors = [255, 170, 120, 255] simp_slice = nice_slice.to_planar()[0].simplify_spline() return simp_slice, nice_slice simp_slice, nice_slice = get_simplified_slice(sobj_mesh) total_y_rotation = 0 rotation_deg_interval = 5 from scipy.spatial.transform import Rotation as R r = R.from_euler('xyz', [[0, rotation_deg_interval, 0]], degrees=True) trans_mat = r.as_matrix() full_trans_mat = np.eye(4) full_trans_mat[:3, :3] = trans_mat # if not working, try rotating the image while len(simp_slice.entities) != 1 or len(nice_slice.entities) != 1: sobj_mesh.apply_transform(full_trans_mat) simp_slice, nice_slice = get_simplified_slice(sobj_mesh) total_y_rotation += rotation_deg_interval if total_y_rotation != 0: # add one more for good measure r = R.from_euler('xyz', [[0, rotation_deg_interval / 2, 0]], degrees=True) trans_mat = r.as_matrix() full_trans_mat = np.eye(4) full_trans_mat[:3, :3] = trans_mat sobj_mesh.apply_transform(full_trans_mat) simp_slice, nice_slice = get_simplified_slice(sobj_mesh) total_y_rotation += rotation_deg_interval node_list = simp_slice.entities[0].nodes ordered_vertices = np.array( [simp_slice.vertices[p] for p in simp_slice.entities[0].points]) ordered_vertices *= 1.15 print('total y rotation:', total_y_rotation) RADIUS = 1.2 def filletEdges(ed1, ed2): f = ChFi2d_AnaFilletAlgo() f.Init(ed1, ed2, gp_Pln()) f.Perform(RADIUS - 0.4) return f.Result(ed1, ed2) def make_vertices(vertices, close_loop=False, smooth_vertices=False): if smooth_vertices: filter_vec = np.array([0.2, 0.6, 0.2]) else: filter_vec = np.array([0, 1, 0]) pnts = [] prev_coords = None for i in range(len(vertices)): if i == 0: if close_loop: row = np.array( [vertices[-1], vertices[i], vertices[i + 1]]) coords_list = row.T.dot(filter_vec) else: edge_filter_vec = filter_vec[1:] edge_filter_vec[0] += filter_vec[0] coords_list = vertices[i:i + 2].T.dot(edge_filter_vec) elif i == len(vertices) - 1: if close_loop: row = np.array([vertices[i - 1], vertices[i], vertices[0]]) coords_list = row.T.dot(filter_vec) else: edge_filter_vec = filter_vec[:-1] edge_filter_vec[-1] += filter_vec[-1] coords_list = vertices[i - 1:i + 1].T.dot(edge_filter_vec) else: coords_list = vertices[i - 1:i + 2].T.dot(filter_vec) # print(coords_list) coords_list = list(coords_list) # raise Exception if prev_coords is None or coords_list != prev_coords: # print(coords_list) pnts.append(gp_Pnt(coords_list[0], coords_list[1], 0)) prev_coords = coords_list return pnts def vertices_to_edges(pnts): edges = [ BRepBuilderAPI_MakeEdge(pnts[i - 1], pnts[i]).Edge() for i in range(1, len(pnts)) ] return edges def edges_to_fillets(edges): fillets = [] for i in range(1, len(edges)): try: fillets.append(filletEdges(edges[i - 1], edges[i])) except Exception: print(i - 1) print(edges[i - 1]) print(edges[i]) raise Exception return fillets def make_wire(edges, fillets=None): # the wire # print("adding wire") makeWire = BRepBuilderAPI_MakeWire() makeWire.Add(edges[0]) if fillets is None: for edge in edges[1:]: makeWire.Add(edge) else: for fillet, edge in zip(fillets, edges[1:]): makeWire.Add(fillet) makeWire.Add(edge) # print("build wire") makeWire.Build() # print("make wire") try: wire = makeWire.Wire() except RuntimeError as e: print(type(makeWire)) raise e return wire def make_pipe(wire, p1, p2): # the pipe if p2 is not None: direction_coords = np.array(p2.XYZ().Coord()) - np.array( p1.XYZ().Coord()) direction_coords /= np.linalg.norm(direction_coords) direction = gp_Dir(*list(direction_coords)) else: direction = gp_Dir(1, 0, 0) # print(p1.XYZ().Coord(), p2.XYZ().Coord()) circle = gp_Circ(gp_Ax2(p1, direction), RADIUS) profile_edge = BRepBuilderAPI_MakeEdge(circle).Edge() profile_wire = BRepBuilderAPI_MakeWire(profile_edge).Wire() profile_face = BRepBuilderAPI_MakeFace(profile_wire).Face() pipe = BRepOffsetAPI_MakePipe(wire, profile_face).Shape() return pipe def filter_vertices(pnts, close_loop): good_pnts = [] if close_loop: pnts.extend(pnts[:2]) else: good_pnts = pnts[:2] for i in range(2, len(pnts)): # print("testing vertices:", pnts[i-2].XYZ().Coord(), pnts[i-1].XYZ().Coord(), pnts[i].XYZ().Coord()) good_pnts.append(pnts[i]) continue matrix = np.array([ pnts[i - 2].XYZ().Coord(), pnts[i - 1].XYZ().Coord(), pnts[i].XYZ().Coord() ]) np.savetxt('filter_vertices.txt', matrix) import subprocess cmd = subprocess.run( ["python", "test_point.py", "filter_vertices.txt"], capture_output=True) stdout = cmd.stdout.decode() # bytes => str if 'good' in stdout: print("good point", i) good_pnts.append(pnts[i]) else: print(stdout) return good_pnts def compose_wire(pnts, close_loop=False, smooth_vertices=False, add_fillets=True): # print("makevert") pnts = make_vertices(pnts, close_loop, smooth_vertices) print("filtvert") pnts = filter_vertices(pnts, close_loop) # close the loop if close_loop: pnts.append(pnts[0]) # the edges print("makeedge with", len(pnts), "vertices") edges = vertices_to_edges(pnts) # [:len(pnts)//4]) if add_fillets: print("makefillets") fillets = edges_to_fillets(edges) print("makewire") if add_fillets: wire = make_wire(edges, fillets) else: wire = make_wire(edges, fillets=None) return wire, pnts def compose_pipe(vertices, close_loop=False, smooth_vertices=False, add_fillets=True): wire, pnts = compose_wire(vertices, close_loop, smooth_vertices, add_fillets) pipe = make_pipe(wire, pnts[0], pnts[1]) return pipe def render_pipe(pipe): my_renderer = JupyterRenderer(compute_normals_mode=NORMAL.CLIENT_SIDE) my_renderer.DisplayShape(pipe, shape_color="blue", topo_level="Face", quality=1.) # default quality print(my_renderer) from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakeSphere def make_sphere(centre, radius): pnt = gp_Pnt(*list(centre)) sphere = BRepPrimAPI_MakeSphere(pnt, radius).Shape() return sphere # In[7]: wire, pnts = compose_wire(ordered_vertices, close_loop=False, smooth_vertices=True) pipe = make_pipe(wire, pnts[0], pnts[1]) recovered_vertices = np.array([pnt.XYZ().Coord() for pnt in pnts]) recovered_vertices.mean(axis=0), recovered_vertices.max( axis=0), recovered_vertices.min(axis=0) # In[8]: # def create_handles """ make new ring that is scaled up version of original atan2(3/4), -atan2(3/4) atan(3/-2) + pi, -(atan(3/-2) + pi) find vertex with greatest normalized dot product with [3,4,0] in +y, use as cutoffs with above and below zero then add even vertices from cutoffs to max x and min x points in bigger """ y_axis_flip = np.array([1, -1, 1]) ur_angle = np.array([7, 3, 0]) dr_angle = ur_angle * y_axis_flip angle_prods = recovered_vertices.dot(ur_angle) / np.linalg.norm( recovered_vertices, axis=1) ur_vertex = recovered_vertices[angle_prods.argmax()] angle_prods = recovered_vertices.dot(dr_angle) / np.linalg.norm( recovered_vertices, axis=1) dr_vertex = recovered_vertices[angle_prods.argmax()] ul_angle = np.array([-3, 3, 0]) dr_angle = ul_angle * y_axis_flip angle_prods = recovered_vertices.dot(ul_angle) / np.linalg.norm( recovered_vertices, axis=1) ul_vertex = recovered_vertices[angle_prods.argmax()] angle_prods = recovered_vertices.dot(dr_angle) / np.linalg.norm( recovered_vertices, axis=1) dl_vertex = recovered_vertices[angle_prods.argmax()] print(ur_vertex, ul_vertex) exp_vertices = recovered_vertices * 1.15 upper_verts = exp_vertices[exp_vertices[:, 1] > 0] upper_verts = upper_verts[upper_verts[:, 0] >= ul_vertex[0]] upper_verts = upper_verts[upper_verts[:, 0] <= ur_vertex[0]] upper_verts = upper_verts[upper_verts[:, 0].argsort()] lower_verts = exp_vertices[exp_vertices[:, 1] < 0] lower_verts = lower_verts[lower_verts[:, 0] >= ul_vertex[0]] lower_verts = lower_verts[lower_verts[:, 0] <= ur_vertex[0]] lower_verts = lower_verts[lower_verts[:, 0].argsort()] ul_verts = np.array([ul_vertex, upper_verts[0]]) ur_verts = np.array([ur_vertex, upper_verts[-1]])[::-1] dl_verts = np.array([dl_vertex, lower_verts[0]]) dr_verts = np.array([dr_vertex, lower_verts[-1]])[::-1] u_pipe = compose_pipe(upper_verts, close_loop=False, smooth_vertices=False) l_pipe = compose_pipe(lower_verts, close_loop=False, smooth_vertices=False) ul_pipe = compose_pipe(ul_verts, close_loop=False, smooth_vertices=False, add_fillets=False) ur_pipe = compose_pipe(ur_verts, close_loop=False, smooth_vertices=False, add_fillets=False) dl_pipe = compose_pipe(dl_verts, close_loop=False, smooth_vertices=False, add_fillets=False) dr_pipe = compose_pipe(dr_verts, close_loop=False, smooth_vertices=False, add_fillets=False) ul_sphere = make_sphere(upper_verts[0], RADIUS) ur_sphere = make_sphere(upper_verts[-1], RADIUS) dl_sphere = make_sphere(lower_verts[0], RADIUS) dr_sphere = make_sphere(lower_verts[-1], RADIUS) from OCC.Core.TopoDS import TopoDS_Compound from OCC.Core.BRep import BRep_Builder aCompound = TopoDS_Compound() aBuilder = BRep_Builder() aBuilder.MakeCompound(aCompound) aBuilder.Add(aCompound, pipe) aBuilder.Add(aCompound, u_pipe) aBuilder.Add(aCompound, l_pipe) aBuilder.Add(aCompound, ul_pipe) aBuilder.Add(aCompound, ur_pipe) aBuilder.Add(aCompound, dl_pipe) aBuilder.Add(aCompound, dr_pipe) aBuilder.Add(aCompound, ul_sphere) aBuilder.Add(aCompound, ur_sphere) aBuilder.Add(aCompound, dl_sphere) aBuilder.Add(aCompound, dr_sphere) from OCC.Extend.DataExchange import write_stl_file output_file = '.'.join(input_file.split('.')[:-1]) + '_fitter' output_stl = output_file + '.stl' output_obj = output_file + '_bracket.obj' write_stl_file(aCompound, output_stl) print("Written to", output_stl) output_mesh = trimesh.load_mesh(output_stl) output_mesh = output_mesh.simplify_quadratic_decimation( len(output_mesh.faces) // 25) trimesh.repair.fix_inversion(output_mesh) def create_trans_mat(x, y, z): r = R.from_euler('xyz', [[x, y, z]], degrees=True) trans_mat = r.as_matrix() full_trans_mat = np.eye(4) full_trans_mat[:3, :3] = trans_mat return full_trans_mat full_trans_mat = create_trans_mat(0, 0, -90) output_mesh.apply_transform(full_trans_mat) # add bracket brac_mesh = trimesh.load_mesh('3d_files/bracket_insert_bent.STL') brac_mesh = brac_mesh.simplify_quadratic_decimation( len(brac_mesh.faces) // 2) print(len(brac_mesh.faces)) trimesh.repair.fix_inversion(brac_mesh) full_trans_mat = create_trans_mat(-90, 10, 180) brac_mesh.apply_transform(full_trans_mat) brac_mesh.vertices = brac_mesh.vertices * 0.86 + np.array([35, 10, 35]) brac_fitter = trimesh.util.concatenate([brac_mesh, output_mesh]) brac_fitter.apply_transform(np.diag(np.array([-1, 1, 1, 1]))) brac_fitter.export(output_obj) print("Written to", output_obj) return output_obj
def write_stl_by_shapes(shapes, convert_stl_path): return write_stl_file(shapes, convert_stl_path, 'binary', 0.03, 0.5)
import numpy as np from OCC.Core.gp import gp_Pnt from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakeBox from OCC.Extend.DataExchange import write_iges_file, write_step_file, write_stl_file from OCCUtils.Construct import make_box shp = make_box(gp_Pnt(-50, -50, -50), 100, 100, 100) write_iges_file(shp, "box.iges") write_step_file(shp, "box.stp") write_stl_file(shp, "box.stl")