def from_polygons(cls, polygons: List[compas.geometry.Polygon]) -> 'BRep': """Construct a BRep from a set of polygons. Parameters ---------- polygons : list[:class:`~compas.geometry.Polygon`] Returns ------- :class:`~compas_occ.brep.BRep` """ shell = TopoDS_Shell() builder = BRep_Builder() builder.MakeShell(shell) for points in polygons: if len(points) == 3: builder.Add(shell, triangle_to_face(points)) elif len(points) == 4: builder.Add(shell, quad_to_face(points)) else: builder.Add(shell, ngon_to_face(points)) brep = BRep() brep.shape = shell return brep
def from_mesh(cls, mesh: compas.datastructures.Mesh) -> 'BRep': """Construct a BRep from a COMPAS mesh. Parameters ---------- mesh : :class:`~compas.datastructures.Mesh` Returns ------- :class:`~compas_occ.brep.BRep` """ shell = TopoDS_Shell() builder = BRep_Builder() builder.MakeShell(shell) for face in mesh.faces(): points = mesh.face_coordinates(face) if len(points) == 3: builder.Add(shell, triangle_to_face(points)) elif len(points) == 4: builder.Add(shell, quad_to_face(points)) else: builder.Add(shell, ngon_to_face(points)) brep = BRep() brep.shape = shell return brep
def compas_mesh_to_occ_shell(mesh: Mesh) -> TopoDS_Shell: """Convert a general COMPAS mesh to an OCC shell. Parameters ---------- mesh : :class:`~compas.datastructures.Mesh` A COMPAS mesh data structure. Returns ------- TopoDS_Shell """ # https://github.com/tpaviot/pythonocc-demos/blob/master/examples/core_geometry_geomplate.py shell = TopoDS_Shell() builder = BRep_Builder() builder.MakeShell(shell) for face in mesh.faces(): points = mesh.face_coordinates(face) if len(points) == 3: builder.Add(shell, triangle_to_face(points)) elif len(points) == 4: builder.Add(shell, quad_to_face(points)) else: builder.Add(shell, ngon_to_face(points)) return shell
def _unify_compound(proto): builder = BRep_Builder() comp = TopoDS_Compound() builder.MakeCompound(comp) explorer = TopExp_Explorer() explorer.Init(proto.Shape(), TopAbs_SOLID) while explorer.More(): builder.Add(comp, _unify_solid(Shape(explorer.Current())).Solid()) explorer.Next() explorer.Init(proto.Shape(), TopAbs_SHELL, TopAbs_SOLID) while explorer.More(): builder.Add(comp, _unify_shell(Shape(explorer.Current())).Shell()) explorer.Next() faces = [] explorer.Init(proto.Shape(), TopAbs_FACE, TopAbs_SHELL) while explorer.More(): faces.append(Shape(explorer.Current())) explorer.Next() faces_new = _unify_faces_array(faces) for f in faces_new: builder.Add(comp, f.Shape()) return Shape(comp)
def export_file(self): builder = BRep_Builder() compound = TopoDS_Compound() builder.MakeCompound(compound) builder.Add(compound, self.b1) builder.Add(compound, self.b2) builder.Add(compound, make_polygon(self.pts)) self.export_stp(compound)
def export_file(self): builder = BRep_Builder() compound = TopoDS_Compound() builder.MakeCompound(compound) builder.Add(compound, self.b1) builder.Add(compound, self.b2) builder.Add(compound, make_polygon(self.pts)) write_step_file(compound, "./tmp/test.stp")
def create_compound(nodes): aRes = TopoDS_Compound() aBuilder = BRep_Builder() aBuilder.MakeCompound(aRes) for n in nodes: aBuilder.Add(aRes, n.solid()) return aRes
def write_target_edges(self,filename): comp = TopoDS_Compound() builder = BRep_Builder() builder.MakeCompound(comp) for shape in self.target_edges: builder.Add(comp, shape) breptools_Write(comp,filename)
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)) 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 AddVerticesToScene(self, pnt_list, vertex_color, vertex_width=5): """ shp is a list of gp_Pnt """ vertices_list = [] # will be passed to pythreejs BB = BRep_Builder() compound = TopoDS_Compound() BB.MakeCompound(compound) for vertex in pnt_list: vertex_to_add = BRepBuilderAPI_MakeVertex(vertex).Shape() BB.Add(compound, vertex_to_add) vertices_list.append([vertex.X(), vertex.Y(), vertex.Z()]) # map the Points and the AIS_PointCloud # and to the dict of shapes, to have a mapping between meshes and shapes point_cloud_id = "%s" % uuid.uuid4().hex self._shapes[point_cloud_id] = compound vertices_list = np.array(vertices_list, dtype=np.float32) attributes = { "position": BufferAttribute(vertices_list, normalized=False) } mat = PointsMaterial(color=vertex_color, sizeAttenuation=True, size=vertex_width) geom = BufferGeometry(attributes=attributes) points = Points(geometry=geom, material=mat, name=point_cloud_id) return points
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 face_mesh_triangle(comp=TopoDS_Shape(), isR=0.1, thA=0.1): # Mesh the shape BRepMesh_IncrementalMesh(comp, isR, True, thA, True) bild1 = BRep_Builder() comp1 = TopoDS_Compound() bild1.MakeCompound(comp1) bt = BRep_Tool() ex = TopExp_Explorer(comp, TopAbs_FACE) while ex.More(): face = topods_Face(ex.Current()) location = TopLoc_Location() facing = bt.Triangulation(face, location) tab = facing.Nodes() tri = facing.Triangles() print(facing.NbTriangles(), facing.NbNodes()) 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(): bild1.Add(comp1, me.Edge()) ex.Next() return comp1
def compas_quadmesh_to_occ_shell(mesh: Mesh) -> TopoDS_Shell: """Convert a COMPAS quad mesh to an OCC shell. Parameters ---------- mesh : :class:`~compas.datastructures.Mesh` A COMPAS mesh data structure with quad faces. Returns ------- TopoDS_Shell Raises ------ AssertionError If the input mesh is not a quad mesh. """ assert mesh.is_quadmesh(), "The input mesh is not a quad mesh." shell = TopoDS_Shell() builder = BRep_Builder() builder.MakeShell(shell) for face in mesh.faces(): points = mesh.face_coordinates(face) builder.Add(shell, quad_to_face(points)) return shell
def __init__(self, faces): topods_shell = TopoDS_Shell() builder = BRep_Builder() builder.MakeShell(topods_shell) for face in faces: builder.Add(topods_shell, face.object) self._shell = Shell(topods_shell)
def make_comp_selcted(self): bild = BRep_Builder() comp = TopoDS_Compound() bild.MakeCompound(comp) for shp in self.selected_shape: print(shp) bild.Add(comp, shp) return comp
def export_stp_selected(self): if self.touch == True: builder = BRep_Builder() compound = TopoDS_Compound() builder.MakeCompound(compound) for shp in self.selected_shape: print(shp) builder.Add(compound, shp) self.export_stp(compound)
class GenCompound(object): def __init__(self): self.builder = BRep_Builder() self.compound = TopoDS_Compound() self.builder.MakeCompound(self.compound) def add_shapes(self, shps=[]): for shp in shps: self.builder.Add(self.compound, shp)
def __init__(self, shapes): topods_compound = TopoDS_Compound() builder = BRep_Builder() builder.MakeCompound(topods_compound) for shape in shapes: shape = Shape.to_shape(shape) if isinstance(shape, Shape): builder.Add(topods_compound, shape.object) self._cp = Compound(topods_compound)
def compound(self): """ Create and returns a compound from the _shapes list""" # Create a compound compound = TopoDS_Compound() brep_builder = BRep_Builder() brep_builder.MakeCompound(compound) # Populate the compound for shape in self._shapes: brep_builder.Add(compound, shape) return compound
def read_iges_file(filename, return_as_shapes=False, verbosity=False, visible_only=False): """ read the IGES file and returns a compound filename: the file path return_as_shapes: optional, False by default. If True returns a list of shapes, else returns a single compound verbosity: optionl, False by default. """ if not os.path.isfile(filename): raise FileNotFoundError("%s not found." % filename) iges_reader = IGESControl_Reader() iges_reader.SetReadVisible(visible_only) status = iges_reader.ReadFile(filename) _shapes = [] if status == IFSelect_RetDone: # check status if verbosity: failsonly = False iges_reader.PrintCheckLoad(failsonly, IFSelect_ItemsByEntity) iges_reader.PrintCheckTransfer(failsonly, IFSelect_ItemsByEntity) iges_reader.TransferRoots() nbr = iges_reader.NbRootsForTransfer() for n in range(1, nbr + 1): nbs = iges_reader.NbShapes() if nbs == 0: print("At least one shape in IGES cannot be transfered") elif nbr == 1 and nbs == 1: a_res_shape = iges_reader.Shape(1) if a_res_shape.IsNull(): print("At least one shape in IGES cannot be transferred") else: _shapes.append(a_res_shape) else: for i in range(1, nbs + 1): a_shape = iges_reader.Shape(i) if a_shape.IsNull(): print( "At least one shape in STEP cannot be transferred") else: _shapes.append(a_shape) # if not return as shapes # create a compound and store all shapes if not return_as_shapes: builder = BRep_Builder() compound = TopoDS_Compound() builder.MakeCompound(compound) for s in _shapes: builder.Add(compound, s) _shapes = compound return _shapes
def to_shell(self): """ Create a shell from the face. :return: The shell. :rtype: afem.topology.entities.Shell """ topods_shell = TopoDS_Shell() builder = BRep_Builder() builder.MakeShell(topods_shell) builder.Add(topods_shell, self.object) return Shell(topods_shell)
def by_face(face): """ Create a shell from a face. :param afem.topology.entities.Face face: The face. :return: The shell. :rtype: afem.topology.entities.Shell """ topods_shell = TopoDS_Shell() builder = BRep_Builder() builder.MakeShell(topods_shell) builder.Add(topods_shell, face.object) return Shell(topods_shell)
def make_compound(parts): """ Takes a list of parts and returns a TopoDS_Compound from the parts' shapes. :param parts: A list of Part instances :return: a TopoDS_Compound from all of the parts' shapes """ compound = TopoDS_Compound() builder = BRep_Builder() builder.MakeCompound(compound) for part in parts: builder.Add(compound, part._shape) return compound
def read_step_file(filename, return_as_shapes=False, verbosity=True): """ read the STEP file and returns a compound filename: the file path return_as_shapes: optional, False by default. If True returns a list of shapes, else returns a single compound verbosity: optional, False by default. """ if not os.path.isfile(filename): raise FileNotFoundError("%s not found." % filename) step_reader = STEPControl_Reader() status = step_reader.ReadFile(filename) if status == IFSelect_RetDone: # check status if verbosity: failsonly = False step_reader.PrintCheckLoad(failsonly, IFSelect_ItemsByEntity) step_reader.PrintCheckTransfer(failsonly, IFSelect_ItemsByEntity) shapes_to_return = [] for root_num in range(1, step_reader.NbRootsForTransfer() + 1): transfer_result = step_reader.TransferRoot(root_num) if not transfer_result: raise AssertionError("Transfer failed.") shape = step_reader.Shape(root_num) if shape.IsNull(): raise AssertionError("Shape is null.") shapes_to_return.append(shape) if return_as_shapes: return shapes_to_return builder = BRep_Builder() compound_shape = TopoDS_Compound() builder.MakeCompound(compound_shape) for shape in shapes_to_return: builder.Add(compound_shape, shape) return compound_shape else: raise AssertionError("Error: can't read file.")
def list_of_shapes_to_compound(list_of_shapes): """ takes a list of shape in input, gather all shapes into one compound returns the compund and a boolean, True if all shapes were added to the compund, False otherwise """ all_shapes_converted = True the_compound = TopoDS_Compound() the_builder = BRep_Builder() the_builder.MakeCompound(the_compound) for shp in list_of_shapes: # first ensure the shape is not Null if shp.IsNull(): all_shapes_converted = False continue else: the_builder.Add(the_compound, shp) return the_compound, all_shapes_converted
def by_shapes(shapes): """ Create a new compound from a collection of shapes. :param collections.Sequence(afem.topology.entities.Shape) shapes: The shapes. :return: The new compound. :rtype: afem.topology.entities.Compound """ topods_compound = TopoDS_Compound() builder = BRep_Builder() builder.MakeCompound(topods_compound) for shape in shapes: if isinstance(shape, Shape): builder.Add(topods_compound, shape.object) return Compound(topods_compound)
def simple_mesh(): # # Create the 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 compound(self): """ Create and returns a compound from the _shapes list Returns ------- TopoDS_Compound Notes ----- Importing an iges box results in: 0 solid 0 shell 6 faces 24 edges """ # Create a compound compound = TopoDS_Compound() brep_builder = BRep_Builder() brep_builder.MakeCompound(compound) # Populate the compound for shape in self._shapes: brep_builder.Add(compound, shape) return compound
def startBottle(startOnly=True): # minus the neck fillet, shelling & threads partName = "Bottle-start" # The points we'll use to create the profile of the bottle's body aPnt1 = gp_Pnt(-width / 2.0, 0, 0) aPnt2 = gp_Pnt(-width / 2.0, -thickness / 4.0, 0) aPnt3 = gp_Pnt(0, -thickness / 2.0, 0) aPnt4 = gp_Pnt(width / 2.0, -thickness / 4.0, 0) aPnt5 = gp_Pnt(width / 2.0, 0, 0) aArcOfCircle = GC_MakeArcOfCircle(aPnt2, aPnt3, aPnt4) aSegment1 = GC_MakeSegment(aPnt1, aPnt2) aSegment2 = GC_MakeSegment(aPnt4, aPnt5) # Could also construct the line edges directly using the points # instead of the resulting line. aEdge1 = BRepBuilderAPI_MakeEdge(aSegment1.Value()) aEdge2 = BRepBuilderAPI_MakeEdge(aArcOfCircle.Value()) aEdge3 = BRepBuilderAPI_MakeEdge(aSegment2.Value()) # Create a wire out of the edges aWire = BRepBuilderAPI_MakeWire(aEdge1.Edge(), aEdge2.Edge(), aEdge3.Edge()) # Quick way to specify the X axis xAxis = gp_OX() # Set up the mirror aTrsf = gp_Trsf() aTrsf.SetMirror(xAxis) # Apply the mirror transformation aBRespTrsf = BRepBuilderAPI_Transform(aWire.Wire(), aTrsf) # Get the mirrored shape back out of the transformation # and convert back to a wire aMirroredShape = aBRespTrsf.Shape() # A wire instead of a generic shape now aMirroredWire = topods.Wire(aMirroredShape) # Combine the two constituent wires mkWire = BRepBuilderAPI_MakeWire() mkWire.Add(aWire.Wire()) mkWire.Add(aMirroredWire) myWireProfile = mkWire.Wire() # The face that we'll sweep to make the prism myFaceProfile = BRepBuilderAPI_MakeFace(myWireProfile) # We want to sweep the face along the Z axis to the height aPrismVec = gp_Vec(0, 0, height) myBody = BRepPrimAPI_MakePrism(myFaceProfile.Face(), aPrismVec) # Add fillets to all edges through the explorer mkFillet = BRepFilletAPI_MakeFillet(myBody.Shape()) anEdgeExplorer = TopExp_Explorer(myBody.Shape(), TopAbs_EDGE) while anEdgeExplorer.More(): anEdge = topods.Edge(anEdgeExplorer.Current()) mkFillet.Add(thickness / 12.0, anEdge) anEdgeExplorer.Next() myBody = mkFillet.Shape() # Create the neck of the bottle neckLocation = gp_Pnt(0, 0, height) neckAxis = gp_DZ() neckAx2 = gp_Ax2(neckLocation, neckAxis) myNeckRadius = thickness / 4.0 myNeckHeight = height / 10.0 mkCylinder = BRepPrimAPI_MakeCylinder(neckAx2, myNeckRadius, myNeckHeight) myBody = BRepAlgoAPI_Fuse(myBody, mkCylinder.Shape()) if startOnly: # quit here uid = win.getNewPartUID(myBody.Shape(), name=partName) win.redraw() return partName = "Bottle-complete" # Our goal is to find the highest Z face and remove it faceToRemove = None zMax = -1 # We have to work our way through all the faces to find the highest Z face aFaceExplorer = TopExp_Explorer(myBody.Shape(), TopAbs_FACE) while aFaceExplorer.More(): aFace = topods.Face(aFaceExplorer.Current()) if face_is_plane(aFace): aPlane = geom_plane_from_face(aFace) # We want the highest Z face, so compare this to the previous faces aPnt = aPlane.Location() aZ = aPnt.Z() if aZ > zMax: zMax = aZ faceToRemove = aFace aFaceExplorer.Next() facesToRemove = TopTools_ListOfShape() facesToRemove.Append(faceToRemove) myBody = BRepOffsetAPI_MakeThickSolid(myBody.Shape(), facesToRemove, -thickness / 50.0, 0.001) # Set up our surfaces for the threading on the neck neckAx2_Ax3 = gp_Ax3(neckLocation, gp_DZ()) aCyl1 = Geom_CylindricalSurface(neckAx2_Ax3, myNeckRadius * 0.99) aCyl2 = Geom_CylindricalSurface(neckAx2_Ax3, myNeckRadius * 1.05) # Set up the curves for the threads on the bottle's neck aPnt = gp_Pnt2d(2.0 * math.pi, myNeckHeight / 2.0) aDir = gp_Dir2d(2.0 * math.pi, myNeckHeight / 4.0) anAx2d = gp_Ax2d(aPnt, aDir) aMajor = 2.0 * math.pi aMinor = myNeckHeight / 10.0 anEllipse1 = Geom2d_Ellipse(anAx2d, aMajor, aMinor) anEllipse2 = Geom2d_Ellipse(anAx2d, aMajor, aMinor / 4.0) anArc1 = Geom2d_TrimmedCurve(anEllipse1, 0, math.pi) anArc2 = Geom2d_TrimmedCurve(anEllipse2, 0, math.pi) anEllipsePnt1 = anEllipse1.Value(0) anEllipsePnt2 = anEllipse1.Value(math.pi) aSegment = GCE2d_MakeSegment(anEllipsePnt1, anEllipsePnt2) # Build edges and wires for threading anEdge1OnSurf1 = BRepBuilderAPI_MakeEdge(anArc1, aCyl1) anEdge2OnSurf1 = BRepBuilderAPI_MakeEdge(aSegment.Value(), aCyl1) anEdge1OnSurf2 = BRepBuilderAPI_MakeEdge(anArc2, aCyl2) anEdge2OnSurf2 = BRepBuilderAPI_MakeEdge(aSegment.Value(), aCyl2) threadingWire1 = BRepBuilderAPI_MakeWire(anEdge1OnSurf1.Edge(), anEdge2OnSurf1.Edge()) threadingWire2 = BRepBuilderAPI_MakeWire(anEdge1OnSurf2.Edge(), anEdge2OnSurf2.Edge()) # Compute the 3D representations of the edges/wires breplib.BuildCurves3d(threadingWire1.Shape()) breplib.BuildCurves3d(threadingWire2.Shape()) # Create the surfaces of the threading aTool = BRepOffsetAPI_ThruSections(True) aTool.AddWire(threadingWire1.Wire()) aTool.AddWire(threadingWire2.Wire()) aTool.CheckCompatibility(False) myThreading = aTool.Shape() # Build the resulting compound aRes = TopoDS_Compound() aBuilder = BRep_Builder() aBuilder.MakeCompound(aRes) aBuilder.Add(aRes, myBody.Shape()) aBuilder.Add(aRes, myThreading) uid = win.getNewPartUID(aRes, name=partName) win.redraw()
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