def Execute(op,obj): # pylint: disable=global-statement global sceneGraph global topZ sceneGraph = FreeCADGui.ActiveDocument.ActiveView.getSceneGraph() Console.PrintMessage("*** Adaptive toolpath processing started...\n") #hide old toolpaths during recalculation obj.Path = Path.Path("(Calculating...)") #store old visibility state job = op.getJob(obj) oldObjVisibility = obj.ViewObject.Visibility oldJobVisibility = job.ViewObject.Visibility obj.ViewObject.Visibility = False job.ViewObject.Visibility = False FreeCADGui.updateGui() try: helixDiameter = obj.HelixDiameterLimit.Value topZ = op.stock.Shape.BoundBox.ZMax obj.Stopped = False obj.StopProcessing = False if obj.Tolerance < 0.001: obj.Tolerance = 0.001 pathArray = [] for base, subs in obj.Base: for sub in subs: shape = base.Shape.getElement(sub) for edge in shape.Edges: pathArray.append([discretize(edge)]) #pathArray=connectEdges(edges) path2d = convertTo2d(pathArray) stockPaths = [] if op.stock.StockType == "CreateCylinder": stockPaths.append([discretize(op.stock.Shape.Edges[0])]) else: stockBB = op.stock.Shape.BoundBox v=[] v.append(FreeCAD.Vector(stockBB.XMin,stockBB.YMin,0)) v.append(FreeCAD.Vector(stockBB.XMax,stockBB.YMin,0)) v.append(FreeCAD.Vector(stockBB.XMax,stockBB.YMax,0)) v.append(FreeCAD.Vector(stockBB.XMin,stockBB.YMax,0)) v.append(FreeCAD.Vector(stockBB.XMin,stockBB.YMin,0)) stockPaths.append([v]) stockPath2d = convertTo2d(stockPaths) opType = area.AdaptiveOperationType.ClearingInside if obj.OperationType == "Clearing": if obj.Side == "Outside": opType = area.AdaptiveOperationType.ClearingOutside else: opType = area.AdaptiveOperationType.ClearingInside else: # profiling if obj.Side == "Outside": opType = area.AdaptiveOperationType.ProfilingOutside else: opType = area.AdaptiveOperationType.ProfilingInside keepToolDownRatio = 3.0 if hasattr(obj, 'KeepToolDownRatio'): keepToolDownRatio = float(obj.KeepToolDownRatio) # put here all properties that influence calculation of adaptive base paths, inputStateObject = { "tool": float(op.tool.Diameter), "tolerance": float(obj.Tolerance), "geometry" : path2d, "stockGeometry": stockPath2d, "stepover" : float(obj.StepOver), "effectiveHelixDiameter": float(helixDiameter), "operationType": obj.OperationType, "side": obj.Side, "forceInsideOut" : obj.ForceInsideOut, "keepToolDownRatio": keepToolDownRatio, "stockToLeave": float(obj.StockToLeave) } inputStateChanged = False adaptiveResults = None if obj.AdaptiveOutputState != None and obj.AdaptiveOutputState != "": adaptiveResults = obj.AdaptiveOutputState if json.dumps(obj.AdaptiveInputState) != json.dumps(inputStateObject): inputStateChanged = True adaptiveResults = None # progress callback fn, if return true it will stop processing def progressFn(tpaths): for path in tpaths: #path[0] contains the MotionType, #path[1] contains list of points if path[0] == area.AdaptiveMotionType.Cutting: sceneDrawPath(path[1],(0,0,1)) else: sceneDrawPath(path[1],(1,0,1)) FreeCADGui.updateGui() return obj.StopProcessing start = time.time() if inputStateChanged or adaptiveResults is None: a2d = area.Adaptive2d() a2d.stepOverFactor = 0.01*obj.StepOver a2d.toolDiameter = float(op.tool.Diameter) a2d.helixRampDiameter = helixDiameter a2d.keepToolDownDistRatio = keepToolDownRatio a2d.stockToLeave =float(obj.StockToLeave) a2d.tolerance = float(obj.Tolerance) a2d.forceInsideOut = obj.ForceInsideOut a2d.opType = opType # EXECUTE results = a2d.Execute(stockPath2d,path2d,progressFn) # need to convert results to python object to be JSON serializable adaptiveResults = [] for result in results: adaptiveResults.append({ "HelixCenterPoint": result.HelixCenterPoint, "StartPoint": result.StartPoint, "AdaptivePaths": result.AdaptivePaths, "ReturnMotionType": result.ReturnMotionType }) # GENERATE GenerateGCode(op,obj,adaptiveResults,helixDiameter) if not obj.StopProcessing: Console.PrintMessage("*** Done. Elapsed time: %f sec\n\n" %(time.time()-start)) obj.AdaptiveOutputState = adaptiveResults obj.AdaptiveInputState=inputStateObject else: Console.PrintMessage("*** Processing cancelled (after: %f sec).\n\n" %(time.time()-start)) finally: obj.ViewObject.Visibility = oldObjVisibility job.ViewObject.Visibility = oldJobVisibility sceneClean()
def compute(self): self.motions = [] trsf = trsf_from_Ax2(self.ax) trsf_inv = trsf.Inverted() mt = BRepBuilderAPI_Transform(self.face, trsf) face_transformed = mt.Shape() tess = OCC.Core.Tesselator.ShapeTesselator(face_transformed) tess.Compute(compute_edges=True, mesh_quality=self.tesselation_mesh_quality) vertices = [] initialized = False for i_edge in range(tess.ObjGetEdgeCount()): for i_vertex in range(tess.ObjEdgeGetVertexCount(i_edge)): x, y, z = tess.GetEdgeVertex(i_edge, i_vertex) if not initialized: initialized = True v_new = gp_Vec(x, y, z) v_old = v_new need_vertex = True else: v_old = v_new v_new = gp_Vec(x, y, z) need_vertex = True if need_vertex: vertices.append(tess.GetEdgeVertex(i_edge, i_vertex)) a2d = area.Adaptive2d() a2d.tolerance = self.tolerance a2d.opType = area.AdaptiveOperationType.ClearingInside a2d.stockToLeave = self.stockToLeave a2d.toolDiameter = self.tool_diameter a2d.helixRampDiameter = self.helix_diameter a2d.stepOverFactor = self.step_over_factor def callback(something): return False # True stops processing stock_path = [[[-1000, -1000], [1000, -1000], [1000, 1000], [-1000, 1000]]] path = [vertices] a2d_output = a2d.Execute(stock_path, path, callback) self.comp = TopoDS_Compound() builder = BRep_Builder() builder.MakeCompound(self.comp) edges = [] mw = BRepBuilderAPI_MakeWire() x = 0 y = 0 print("len(a2d_output):", len(a2d_output)) regions = [] for region in a2d_output: need_depth_to_depth_link = False for i_depth, current_z_cut in enumerate(self.cut_depths): motions_region_i = [] print("helix center point") x, y = region.HelixCenterPoint # peek at first point motion_type, path_i = region.AdaptivePaths[0] x_peek, y_peek = path_i[0] ax = gp_Ax2(gp_Pnt(x, y, current_z_cut), gp_Dir(0, 0, 1), gp_Dir(x_peek - x, y_peek - y, 0)) cyl = gp_Cylinder(gp_Ax3(ax), self.helix_diameter / 2.0) if i_depth == 0: dv = self.z_clearance - self.cut_depths[i_depth] else: dv = self.cut_depths[i_depth - 1] - self.cut_depths[i_depth] dv_du = tan(radians(self.helix_angle)) du = dv / dv_du dt = du / cos(radians(self.helix_angle)) aLine2d = gp_Lin2d(gp_Pnt2d(-du, dv), gp_Dir2d(du, -dv)) segment = GCE2d_MakeSegment(aLine2d, 0, dt) helixEdge = BRepBuilderAPI_MakeEdge( segment.Value(), Geom_CylindricalSurface(cyl)).Edge() curve = BRepAdaptor_Curve(helixEdge) v0 = gp_Vec(curve.Value(curve.FirstParameter()).XYZ()) v1 = gp_Vec(curve.Value(curve.LastParameter()).XYZ()) if need_depth_to_depth_link: # go up to clearance plane v_next = gp_Vec(v_now.X(), v_now.Y(), self.z_clearance) me = BRepBuilderAPI_MakeEdge(gp_Pnt(v_now.XYZ()), gp_Pnt(v_next.XYZ())) mt = BRepBuilderAPI_Transform(me.Edge(), trsf_inv) motions_region_i.append( Adaptive2dMotion(self, mt.Shape(), self.rapid_feedrate)) mw.Add(me.Edge()) builder.Add(self.comp, me.Edge()) v_now = v_next # go to helix start xy v_next = gp_Vec(v0.X(), v0.Y(), v_now.Z()) me = BRepBuilderAPI_MakeEdge(gp_Pnt(v_now.XYZ()), gp_Pnt(v_next.XYZ())) mt = BRepBuilderAPI_Transform(me.Edge(), trsf_inv) motions_region_i.append( Adaptive2dMotion(self, mt.Shape(), self.rapid_feedrate)) mw.Add(me.Edge()) builder.Add(self.comp, me.Edge()) v_now = v_next # go to helix start xyz v_next = v0 me = BRepBuilderAPI_MakeEdge(gp_Pnt(v_now.XYZ()), gp_Pnt(v_next.XYZ())) mt = BRepBuilderAPI_Transform(me.Edge(), trsf_inv) motions_region_i.append( Adaptive2dMotion(self, mt.Shape(), self.rapid_feedrate)) mw.Add(me.Edge()) builder.Add(self.comp, me.Edge()) v_now = v_next need_depth_to_depth_link = True mw.Add(helixEdge) builder.Add(self.comp, helixEdge) mt = BRepBuilderAPI_Transform(helixEdge, trsf_inv) motions_region_i.append( Adaptive2dMotion(self, mt.Shape(), self.plunge_feedrate)) v_now = v1 # add circle at bottom aLin2d = gp_Lin2d(gp_Pnt2d(0, 0), gp_Dir2d(du, 0)) dt = 2 * pi segment = GCE2d_MakeSegment(aLin2d, 0, dt) circleEdge = BRepBuilderAPI_MakeEdge( segment.Value(), Geom_CylindricalSurface(cyl)).Edge() mw.Add(circleEdge) builder.Add(self.comp, circleEdge) mt = BRepBuilderAPI_Transform(circleEdge, trsf_inv) motions_region_i.append( Adaptive2dMotion(self, mt.Shape(), self.plunge_feedrate)) curve = BRepAdaptor_Curve(circleEdge) v1 = gp_Vec(curve.Value(curve.LastParameter()).XYZ()) v_now = v1 PATH_TYPE = { 0: "Cutting", 1: "LinkClear", 2: "LinkNotClear", 3: "LinkClearAtPrevPass" } for path_type, points in region.AdaptivePaths: if PATH_TYPE[path_type] == "Cutting": # handle the first point x, y = points[0] # choose feedrate if (v_now.Z() - current_z_cut) > 1e-3: feedrate = self.rapid_feedrate else: feedrate = self.milling_feedrate v_next = gp_Vec(x, y, v_now.Z()) if (v_now - v_next).Magnitude() > 1e-6: me = BRepBuilderAPI_MakeEdge( gp_Pnt(v_now.XYZ()), gp_Pnt(v_next.XYZ())) mt = BRepBuilderAPI_Transform(me.Edge(), trsf_inv) motions_region_i.append( Adaptive2dMotion(self, mt.Shape(), feedrate)) mw.Add(me.Edge()) builder.Add(self.comp, me.Edge()) v_now = v_next if v_now.Z() != current_z_cut: v_next = gp_Vec(x, y, current_z_cut) me = BRepBuilderAPI_MakeEdge( gp_Pnt(v_now.XYZ()), gp_Pnt(v_next.XYZ())) mt = BRepBuilderAPI_Transform(me.Edge(), trsf_inv) motions_region_i.append( Adaptive2dMotion(self, mt.Shape(), self.plunge_feedrate)) v_now = v_next mw.Add(me.Edge()) builder.Add(self.comp, me.Edge()) # handle the rest of the points for x, y in points[1:]: v_next = gp_Vec(x, y, current_z_cut) if (v_now - v_next).Magnitude() > 1e-6: me = BRepBuilderAPI_MakeEdge( gp_Pnt(v_now.XYZ()), gp_Pnt(v_next.XYZ())) mt = BRepBuilderAPI_Transform( me.Edge(), trsf_inv) motions_region_i.append( Adaptive2dMotion(self, mt.Shape(), self.milling_feedrate)) v_now = v_next mw.Add(me.Edge()) builder.Add(self.comp, me.Edge()) elif (PATH_TYPE[path_type] == "LinkClear") or (PATH_TYPE[path_type] == "LinkNotClear"): if (PATH_TYPE[path_type] == "LinkClear"): z = current_z_cut + self.z_link_clear else: z = self.z_clearance if v_now.Z() != z: if v_now.Z() >= z: feedrate = self.plunge_feedrate else: feedrate = self.rapid_feedrate v_next = gp_Vec(v_now.X(), v_now.Y(), z) me = BRepBuilderAPI_MakeEdge( gp_Pnt(v_now.XYZ()), gp_Pnt(v_next.XYZ())) mt = BRepBuilderAPI_Transform(me.Edge(), trsf_inv) motions_region_i.append( Adaptive2dMotion(self, mt.Shape(), self.plunge_feedrate)) v_now = v_next mw.Add(me.Edge()) builder.Add(self.comp, me.Edge()) if len(points) > 0: # go to each point for x, y in points[1:]: v_next = gp_Vec(x, y, z) me = BRepBuilderAPI_MakeEdge( gp_Pnt(v_now.XYZ()), gp_Pnt(v_next.XYZ())) mt = BRepBuilderAPI_Transform( me.Edge(), trsf_inv) motions_region_i.append( Adaptive2dMotion(self, mt.Shape(), self.rapid_feedrate)) v_now = v_next mw.Add(me.Edge()) builder.Add(self.comp, me.Edge()) else: raise Warning("path type not implemented") self.motions.append(motions_region_i) mt = BRepBuilderAPI_Transform(mw.Wire(), trsf_inv) self.wire = mt.Shape() return self.wire