def findHoles(self, obj, shape): import DraftGeomUtils as dgu PathLog.track('obj: {} shape: {}'.format(obj, shape)) holelist = [] tooldiameter = obj.ToolController.Proxy.getTool(obj.ToolController).Diameter PathLog.debug('search for holes larger than tooldiameter: {}: '.format(tooldiameter)) if dgu.isPlanar(shape): PathLog.debug("shape is planar") for i in range(len(shape.Edges)): candidateEdgeName = "Edge" + str(i + 1) e = shape.getElement(candidateEdgeName) if PathUtils.isDrillable(shape, e, tooldiameter): PathLog.debug('edge candidate: {} (hash {})is drillable '.format(e, e.hashCode())) x = e.Curve.Center.x y = e.Curve.Center.y diameter = e.BoundBox.XLength holelist.append({'featureName': candidateEdgeName, 'feature': e, 'x': x, 'y': y, 'd': diameter, 'enabled': True}) else: PathLog.debug("shape is not planar") for i in range(len(shape.Faces)): candidateFaceName = "Face" + str(i + 1) f = shape.getElement(candidateFaceName) if PathUtils.isDrillable(shape, f, tooldiameter): PathLog.debug('face candidate: {} is drillable '.format(f)) x = f.Surface.Center.x y = f.Surface.Center.y diameter = f.BoundBox.XLength holelist.append({'featureName': candidateFaceName, 'feature': f, 'x': x, 'y': y, 'd': diameter, 'enabled': True}) PathLog.debug("holes found: {}".format(holelist)) return holelist
def areaOpShapes(self, obj): '''areaOpShapes(obj) ... returns envelope for all base shapes or wires for Arch.Panels.''' if obj.UseComp: self.commandlist.append(Path.Command("(Compensated Tool Path. Diameter: " + str(self.radius * 2) + ")")) else: self.commandlist.append(Path.Command("(Uncompensated Tool Path)")) shapes = [] if obj.Base: # The user has selected subobjects from the base. Process each. holes = [] faces = [] for b in obj.Base: for sub in b[1]: shape = getattr(b[0].Shape, sub) if isinstance(shape, Part.Face): faces.append(shape) if numpy.isclose(abs(shape.normalAt(0, 0).z), 1): # horizontal face holes += shape.Wires[1:] else: FreeCAD.Console.PrintWarning("found a base object which is not a face. Can't continue.") return for wire in holes: f = Part.makeFace(wire, 'Part::FaceMakerSimple') drillable = PathUtils.isDrillable(self.baseobject.Shape, wire) if (drillable and obj.processCircles) or (not drillable and obj.processHoles): env = PathUtils.getEnvelope(self.baseobject.Shape, subshape=f, depthparams=self.depthparams) shapes.append((env, True)) if len(faces) > 0: profileshape = Part.makeCompound(faces) if obj.processPerimeter: env = PathUtils.getEnvelope(self.baseobject.Shape, subshape=profileshape, depthparams=self.depthparams) shapes.append((env, False)) else: # Try to build targets from the job base if hasattr(self.baseobject, "Proxy"): if isinstance(self.baseobject.Proxy, ArchPanel.PanelSheet): # process the sheet if obj.processCircles or obj.processHoles: for shape in self.baseobject.Proxy.getHoles(self.baseobject, transform=True): for wire in shape.Wires: drillable = PathUtils.isDrillable(self.baseobject.Proxy, wire) if (drillable and obj.processCircles) or (not drillable and obj.processHoles): f = Part.makeFace(wire, 'Part::FaceMakerSimple') env = PathUtils.getEnvelope(self.baseobject.Shape, subshape=f, depthparams=self.depthparams) shapes.append((env, True)) if obj.processPerimeter: for shape in self.baseobject.Proxy.getOutlines(self.baseobject, transform=True): for wire in shape.Wires: f = Part.makeFace(wire, 'Part::FaceMakerSimple') env = PathUtils.getEnvelope(self.baseobject.Shape, subshape=f, depthparams=self.depthparams) shapes.append((env, False)) PathLog.debug("%d shapes" % len(shapes)) return shapes
def findHoles(self, obj, baseobject): '''findHoles(obj, baseobject) ... inspect baseobject and identify all features that resemble a straight cricular hole.''' shape = baseobject.Shape PathLog.track('obj: {} shape: {}'.format(obj, shape)) holelist = [] features = [] # tooldiameter = obj.ToolController.Proxy.getTool(obj.ToolController).Diameter tooldiameter = None PathLog.debug('search for holes larger than tooldiameter: {}: '.format( tooldiameter)) if DraftGeomUtils.isPlanar(shape): PathLog.debug("shape is planar") for i in range(len(shape.Edges)): candidateEdgeName = "Edge" + str(i + 1) e = shape.getElement(candidateEdgeName) if PathUtils.isDrillable(shape, e, tooldiameter): PathLog.debug( 'edge candidate: {} (hash {})is drillable '.format( e, e.hashCode())) x = e.Curve.Center.x y = e.Curve.Center.y diameter = e.BoundBox.XLength holelist.append({ 'featureName': candidateEdgeName, 'feature': e, 'x': x, 'y': y, 'd': diameter, 'enabled': True }) features.append((baseobject, candidateEdgeName)) PathLog.debug("Found hole feature %s.%s" % (baseobject.Label, candidateEdgeName)) else: PathLog.debug("shape is not planar") for i in range(len(shape.Faces)): candidateFaceName = "Face" + str(i + 1) f = shape.getElement(candidateFaceName) if PathUtils.isDrillable(shape, f, tooldiameter): PathLog.debug('face candidate: {} is drillable '.format(f)) x = f.Surface.Center.x y = f.Surface.Center.y diameter = f.BoundBox.XLength holelist.append({ 'featureName': candidateFaceName, 'feature': f, 'x': x, 'y': y, 'd': diameter, 'enabled': True }) features.append((baseobject, candidateFaceName)) PathLog.debug("Found hole feature %s.%s" % (baseobject.Label, candidateFaceName)) PathLog.debug("holes found: {}".format(holelist)) return features
def addSelected(self): for sel in FreeCAD.Gui.Selection.getSelectionEx(): names = self.obj.Names positions = self.obj.Positions enabled = self.obj.Enabled diameters = self.obj.Diameters objectname = sel.ObjectName sobj = sel.Object for i, sub in enumerate(sel.SubObjects): if hasattr(sub, 'ShapeType'): if sub.ShapeType == 'Vertex': PathLog.debug("Selection is a vertex, lets drill that") names.append(objectname + '.' + sel.SubElementNames[i]) positions.append(FreeCAD.Vector(sub.X, sub.Y, 0)) enabled.append(1) diameters.append(0) elif sub.ShapeType == 'Edge': if PathUtils.isDrillable(sobj, sub): PathLog.debug( "Selection is a drillable edge, lets drill that" ) names.append(objectname + '.' + sel.SubElementNames[i]) positions.append( FreeCAD.Vector(sub.Curve.Center.x, sub.Curve.Center.y, 0)) enabled.append(1) diameters.append(sub.BoundBox.XLength) elif sub.ShapeType == 'Face': if PathUtils.isDrillable(sobj.Shape, sub): PathLog.debug( "Selection is a drillable face, lets drill that" ) names.append(objectname + '.' + sel.SubElementNames[i]) positions.append( FreeCAD.Vector(sub.Surface.Center.x, sub.Surface.Center.y, 0)) enabled.append(1) diameters.append(sub.BoundBox.XLength) self.obj.Names = names self.obj.Positions = positions self.obj.Enabled = enabled self.obj.Diameters = diameters self.updateFeatureList() FreeCAD.ActiveDocument.recompute()
def findHoles(self, obj, shape): import DraftGeomUtils as dgu PathLog.track('obj: {} shape: {}'.format(obj, shape)) holelist = [] # tooldiameter = obj.ToolController.Proxy.getTool(obj.ToolController).Diameter tooldiameter = None PathLog.debug('search for holes larger than tooldiameter: {}: '.format( tooldiameter)) if dgu.isPlanar(shape): PathLog.debug("shape is planar") for i in range(len(shape.Edges)): candidateEdgeName = "Edge" + str(i + 1) e = shape.getElement(candidateEdgeName) if PathUtils.isDrillable(shape, e, tooldiameter): PathLog.debug( 'edge candidate: {} (hash {})is drillable '.format( e, e.hashCode())) x = e.Curve.Center.x y = e.Curve.Center.y diameter = e.BoundBox.XLength holelist.append({ 'featureName': candidateEdgeName, 'feature': e, 'x': x, 'y': y, 'd': diameter, 'enabled': True }) else: PathLog.debug("shape is not planar") for i in range(len(shape.Faces)): candidateFaceName = "Face" + str(i + 1) f = shape.getElement(candidateFaceName) if PathUtils.isDrillable(shape, f, tooldiameter): PathLog.debug('face candidate: {} is drillable '.format(f)) x = f.Surface.Center.x y = f.Surface.Center.y diameter = f.BoundBox.XLength holelist.append({ 'featureName': candidateFaceName, 'feature': f, 'x': x, 'y': y, 'd': diameter, 'enabled': True }) PathLog.debug("holes found: {}".format(holelist)) return holelist
def findAllHoles(self, obj): if not self.getJob(obj): return features = [] if self.baseIsArchPanel(obj, self.baseobject): holeshapes = self.baseobject.Proxy.getHoles(self.baseobject, transform=True) tooldiameter = obj.ToolController.Proxy.getTool( obj.ToolController).Diameter for holeNr, hole in enumerate(holeshapes): PathLog.debug('Entering new HoleShape') for wireNr, wire in enumerate(hole.Wires): PathLog.debug('Entering new Wire') for edgeNr, edge in enumerate(wire.Edges): if PathUtils.isDrillable(self.baseobject, edge, tooldiameter): PathLog.debug( 'Found drillable hole edges: {}'.format(edge)) features.append( (self.baseobject, "%d.%d.%d" % (holeNr, wireNr, edgeNr))) else: features = self.findHoles(obj, self.baseobject) obj.Base = features obj.Disabled = []
def findAllHoles(self, obj): '''findAllHoles(obj) ... find all holes of all base models and assign as features.''' PathLog.track() if not self.getJob(obj): return features = [] if 1 == len(self.model) and self.baseIsArchPanel(obj, self.model[0]): panel = self.model[0] holeshapes = panel.Proxy.getHoles(panel, transform=True) tooldiameter = obj.ToolController.Proxy.getTool( obj.ToolController).Diameter for holeNr, hole in enumerate(holeshapes): PathLog.debug('Entering new HoleShape') for wireNr, wire in enumerate(hole.Wires): PathLog.debug('Entering new Wire') for edgeNr, edge in enumerate(wire.Edges): if PathUtils.isDrillable(panel, edge, tooldiameter): PathLog.debug( 'Found drillable hole edges: {}'.format(edge)) features.append( (panel, "%d.%d.%d" % (holeNr, wireNr, edgeNr))) else: for base in self.model: features.extend(self.findHoles(obj, base)) obj.Base = features obj.Disabled = []
def allow(self, doc, obj, sub): PathLog.debug('obj: {} sub: {}'.format(obj, sub)) if hasattr(obj, "Shape") and sub: shape = obj.Shape subobj = shape.getElement(sub) return PathUtils.isDrillable(shape, subobj, includePartials = True) else: return False
def allow(self, doc, obj, sub): # pylint: disable=unused-argument PathLog.debug('obj: {} sub: {}'.format(obj, sub)) if hasattr(obj, "Shape") and sub: shape = obj.Shape subobj = shape.getElement(sub) return PathUtils.isDrillable(shape, subobj, includePartials=True) else: return False
def allow(self, doc, obj, sub): PathLog.debug('obj: {} sub: {}'.format(obj, sub)) if hasattr(obj, "Shape"): obj = obj.Shape subobj = obj.getElement(sub) return PathUtils.isDrillable(obj, subobj) else: return False
def opExecute(self, obj): '''opExecute(obj) ... processes all Base features and Locations and collects them in a list of positions and radii which is then passed to circularHoleExecute(obj, holes). If no Base geometries and no Locations are present, the job's Base is inspected and all drillable features are added to Base. In this case appropriate values for depths are also calculated and assigned. Do not overwrite, implement circularHoleExecute(obj, holes) instead.''' PathLog.track() def haveLocations(self, obj): if PathOp.FeatureLocations & self.opFeatures(obj): return len(obj.Locations) != 0 return False if len(obj.Base) == 0 and not haveLocations(self, obj): features = [] if self.baseIsArchPanel(obj, self.baseobject): holeshapes = self.baseobject.Proxy.getHoles(self.baseobject, transform=True) tooldiameter = obj.ToolController.Proxy.getTool( obj.ToolController).Diameter for holeNr, hole in enumerate(holeshapes): PathLog.debug('Entering new HoleShape') for wireNr, wire in enumerate(hole.Wires): PathLog.debug('Entering new Wire') for edgeNr, edge in enumerate(wire.Edges): if PathUtils.isDrillable(self.baseobject, edge, tooldiameter): PathLog.debug( 'Found drillable hole edges: {}'.format( edge)) features.append( (self.baseobject, "%d.%d.%d" % (holeNr, wireNr, edgeNr))) else: features = self.findHoles(obj, self.baseobject) obj.Base = features obj.Disabled = [] holes = [] for base, subs in obj.Base: for sub in subs: if self.isHoleEnabled(obj, base, sub): pos = self.holePosition(obj, base, sub) if pos: holes.append({ 'x': pos.x, 'y': pos.y, 'r': self.holeDiameter(obj, base, sub) }) if haveLocations(self, obj): for location in obj.Locations: holes.append({'x': location.x, 'y': location.y, 'r': 0}) if len(holes) > 0: self.circularHoleExecute(obj, holes)
def findHoles(self, obj, baseobject): '''findHoles(obj, baseobject) ... inspect baseobject and identify all features that resemble a straight cricular hole.''' shape = baseobject.Shape PathLog.track('obj: {} shape: {}'.format(obj, shape)) holelist = [] features = [] # tooldiameter = obj.ToolController.Proxy.getTool(obj.ToolController).Diameter tooldiameter = None PathLog.debug('search for holes larger than tooldiameter: {}: '.format(tooldiameter)) if DraftGeomUtils.isPlanar(shape): PathLog.debug("shape is planar") for i in range(len(shape.Edges)): candidateEdgeName = "Edge" + str(i + 1) e = shape.getElement(candidateEdgeName) if PathUtils.isDrillable(shape, e, tooldiameter): PathLog.debug('edge candidate: {} (hash {})is drillable '.format(e, e.hashCode())) x = e.Curve.Center.x y = e.Curve.Center.y diameter = e.BoundBox.XLength holelist.append({'featureName': candidateEdgeName, 'feature': e, 'x': x, 'y': y, 'd': diameter, 'enabled': True}) features.append((baseobject, candidateEdgeName)) PathLog.debug("Found hole feature %s.%s" % (baseobject.Label, candidateEdgeName)) else: PathLog.debug("shape is not planar") for i in range(len(shape.Faces)): candidateFaceName = "Face" + str(i + 1) f = shape.getElement(candidateFaceName) if PathUtils.isDrillable(shape, f, tooldiameter): PathLog.debug('face candidate: {} is drillable '.format(f)) if hasattr(f.Surface, 'Center'): x = f.Surface.Center.x y = f.Surface.Center.y diameter = f.BoundBox.XLength else: center = f.Edges[0].Curve.Center x = center.x y = center.y diameter = f.Edges[0].Curve.Radius * 2 holelist.append({'featureName': candidateFaceName, 'feature': f, 'x': x, 'y': y, 'd': diameter, 'enabled': True}) features.append((baseobject, candidateFaceName)) PathLog.debug("Found hole feature %s.%s" % (baseobject.Label, candidateFaceName)) PathLog.debug("holes found: {}".format(holelist)) return features
def addSelected(self): for sel in FreeCAD.Gui.Selection.getSelectionEx(): names = self.obj.Names positions = self.obj.Positions enabled = self.obj.Enabled diameters = self.obj.Diameters objectname = sel.ObjectName sobj = sel.Object for i, sub in enumerate(sel.SubObjects): if hasattr(sub, 'ShapeType'): if sub.ShapeType == 'Vertex': PathLog.debug("Selection is a vertex, lets drill that") names.append(objectname+'.'+sel.SubElementNames[i]) positions.append(FreeCAD.Vector(sub.X, sub.Y, 0)) enabled.append(1) diameters.append(0) elif sub.ShapeType == 'Edge': if PathUtils.isDrillable(sobj, sub): PathLog.debug("Selection is a drillable edge, lets drill that") names.append(objectname+'.'+sel.SubElementNames[i]) positions.append(FreeCAD.Vector(sub.Curve.Center.x, sub.Curve.Center.y, 0)) enabled.append(1) diameters.append(sub.BoundBox.XLength) elif sub.ShapeType == 'Face': if PathUtils.isDrillable(sobj.Shape, sub): PathLog.debug("Selection is a drillable face, lets drill that") names.append(objectname+'.'+sel.SubElementNames[i]) positions.append(FreeCAD.Vector(sub.Surface.Center.x, sub.Surface.Center.y, 0)) enabled.append(1) diameters.append(sub.BoundBox.XLength) self.obj.Names = names self.obj.Positions = positions self.obj.Enabled = enabled self.obj.Diameters = diameters self.updateFeatureList() FreeCAD.ActiveDocument.recompute()
def opExecute(self, obj): '''opExecute(obj) ... processes all Base features and Locations and collects them in a list of positions and radii which is then passed to circularHoleExecute(obj, holes). If no Base geometries and no Locations are present, the job's Base is inspected and all drillable features are added to Base. In this case appropriate values for depths are also calculated and assigned. Do not overwrite, implement circularHoleExecute(obj, holes) instead.''' PathLog.track() def haveLocations(self, obj): if PathOp.FeatureLocations & self.opFeatures(obj): return len(obj.Locations) != 0 return False if len(obj.Base) == 0 and not haveLocations(self, obj): # Arch PanelSheet features = [] if self.baseIsArchPanel(obj, self.baseobject): holeshapes = self.baseobject.Proxy.getHoles(self.baseobject, transform=True) tooldiameter = obj.ToolController.Proxy.getTool(obj.ToolController).Diameter for holeNr, hole in enumerate(holeshapes): PathLog.debug('Entering new HoleShape') for wireNr, wire in enumerate(hole.Wires): PathLog.debug('Entering new Wire') for edgeNr, edge in enumerate(wire.Edges): if PathUtils.isDrillable(self.baseobject, edge, tooldiameter): PathLog.debug('Found drillable hole edges: {}'.format(edge)) features.append((self.baseobject, "%d.%d.%d" % (holeNr, wireNr, edgeNr))) self.setDepths(obj, None, None, self.baseobject.Shape.BoundBox) else: features = self.findHoles(obj, self.baseobject) self.setupDepthsFrom(obj, features, self.baseobject) obj.Base = features obj.Disabled = [] holes = [] for base, subs in obj.Base: for sub in subs: if self.isHoleEnabled(obj, base, sub): pos = self.holePosition(obj, base, sub) if pos: holes.append({'x': pos.x, 'y': pos.y, 'r': self.holeDiameter(obj, base, sub)}) if haveLocations(self, obj): for location in obj.Locations: holes.append({'x': location.x, 'y': location.y, 'r': 0}) if len(holes) > 0: self.circularHoleExecute(obj, holes)
def findAllHoles(self, obj): if not self.getJob(obj): return features = [] if self.baseIsArchPanel(obj, self.baseobject): holeshapes = self.baseobject.Proxy.getHoles(self.baseobject, transform=True) tooldiameter = obj.ToolController.Proxy.getTool(obj.ToolController).Diameter for holeNr, hole in enumerate(holeshapes): PathLog.debug('Entering new HoleShape') for wireNr, wire in enumerate(hole.Wires): PathLog.debug('Entering new Wire') for edgeNr, edge in enumerate(wire.Edges): if PathUtils.isDrillable(self.baseobject, edge, tooldiameter): PathLog.debug('Found drillable hole edges: {}'.format(edge)) features.append((self.baseobject, "%d.%d.%d" % (holeNr, wireNr, edgeNr))) else: features = self.findHoles(obj, self.baseobject) obj.Base = features obj.Disabled = []
def areaOpShapes(self, obj): '''areaOpShapes(obj) ... returns envelope for all base shapes or wires for Arch.Panels.''' PathLog.track() PathLog.debug("----- areaOpShapes() in PathProfileFaces.py") if obj.UseComp: self.commandlist.append( Path.Command("(Compensated Tool Path. Diameter: " + str(self.radius * 2) + ")")) else: self.commandlist.append(Path.Command("(Uncompensated Tool Path)")) shapes = [] self.profileshape = [] finalDepths = [] baseSubsTuples = [] subCount = 0 allTuples = [] if obj.Base: # The user has selected subobjects from the base. Process each. if obj.EnableRotation != 'Off': for p in range(0, len(obj.Base)): (base, subsList) = obj.Base[p] for sub in subsList: subCount += 1 shape = getattr(base.Shape, sub) if isinstance(shape, Part.Face): rtn = False (norm, surf) = self.getFaceNormAndSurf(shape) (rtn, angle, axis, praInfo) = self.faceRotationAnalysis( obj, norm, surf) if rtn is True: (clnBase, angle, clnStock, tag) = self.applyRotationalAnalysis( obj, base, angle, axis, subCount) # Verify faces are correctly oriented - InverseAngle might be necessary faceIA = getattr(clnBase.Shape, sub) (norm, surf) = self.getFaceNormAndSurf(faceIA) (rtn, praAngle, praAxis, praInfo) = self.faceRotationAnalysis( obj, norm, surf) if rtn is True: PathLog.error( translate( "Path", "Face appears misaligned after initial rotation." )) if obj.AttemptInverseAngle is True and obj.InverseAngle is False: (clnBase, clnStock, angle) = self.applyInverseAngle( obj, clnBase, clnStock, axis, angle) else: msg = translate( "Path", "Consider toggling the 'InverseAngle' property and recomputing." ) PathLog.error(msg) # title = translate("Path", 'Rotation Warning') # self.guiMessage(title, msg, False) else: PathLog.debug( "Face appears to be oriented correctly." ) tup = clnBase, sub, tag, angle, axis, clnStock else: if self.warnDisabledAxis(obj, axis) is False: PathLog.debug( str(sub) + ": No rotation used") axis = 'X' angle = 0.0 tag = base.Name + '_' + axis + str( angle).replace('.', '_') stock = PathUtils.findParentJob(obj).Stock tup = base, sub, tag, angle, axis, stock # Eif allTuples.append(tup) # Eif # Efor # Efor if subCount > 1: msg = translate('Path', "Multiple faces in Base Geometry.") + " " msg += translate( 'Path', "Depth settings will be applied to all faces.") PathLog.warning(msg) # title = translate("Path", "Depth Warning") # self.guiMessage(title, msg) (Tags, Grps) = self.sortTuplesByIndex( allTuples, 2) # return (TagList, GroupList) subList = [] for o in range(0, len(Tags)): subList = [] for (base, sub, tag, angle, axis, stock) in Grps[o]: subList.append(sub) pair = base, subList, angle, axis, stock baseSubsTuples.append(pair) # Efor else: PathLog.info( translate("Path", "EnableRotation property is 'Off'.")) stock = PathUtils.findParentJob(obj).Stock for (base, subList) in obj.Base: baseSubsTuples.append((base, subList, 0.0, 'X', stock)) # for base in obj.Base: for (base, subsList, angle, axis, stock) in baseSubsTuples: holes = [] faces = [] for sub in subsList: shape = getattr(base.Shape, sub) if isinstance(shape, Part.Face): faces.append(shape) if numpy.isclose(abs(shape.normalAt(0, 0).z), 1): # horizontal face for wire in shape.Wires[1:]: holes.append((base.Shape, wire)) else: ignoreSub = base.Name + '.' + sub msg = translate( 'Path', "Found a selected object which is not a face. Ignoring: {}" .format(ignoreSub)) PathLog.error(msg) FreeCAD.Console.PrintWarning(msg) # return for shape, wire in holes: f = Part.makeFace(wire, 'Part::FaceMakerSimple') drillable = PathUtils.isDrillable(shape, wire) if (drillable and obj.processCircles) or (not drillable and obj.processHoles): PathLog.track() # Recalculate depthparams (strDep, finDep) = self.calculateStartFinalDepths( obj, shape, stock) finalDepths.append(finDep) PathLog.debug( "Adjusted face depths strDep: {}, and finDep: {}". format(self.strDep, self.finDep)) finish_step = obj.FinishDepth.Value if hasattr( obj, "FinishDepth") else 0.0 self.depthparams = PathUtils.depth_params( clearance_height=obj.ClearanceHeight.Value, safe_height=obj.SafeHeight.Value, start_depth=strDep, # obj.StartDepth.Value, step_down=obj.StepDown.Value, z_finish_step=finish_step, final_depth=finDep, # obj.FinalDepth.Value, user_depths=None) env = PathUtils.getEnvelope( shape, subshape=f, depthparams=self.depthparams) # shapes.append((env, True)) tup = env, True, 'pathProfileFaces', angle, axis, strDep, finDep shapes.append(tup) if len(faces) > 0: profileshape = Part.makeCompound(faces) self.profileshape.append(profileshape) if obj.processPerimeter: PathLog.track() if profileshape: # Recalculate depthparams (strDep, finDep) = self.calculateStartFinalDepths( obj, profileshape, stock) finalDepths.append(finDep) PathLog.debug( "Adjusted face depths strDep: {}, and finDep: {}". format(self.strDep, self.finDep)) finish_step = obj.FinishDepth.Value if hasattr( obj, "FinishDepth") else 0.0 self.depthparams = PathUtils.depth_params( clearance_height=obj.ClearanceHeight.Value, safe_height=obj.SafeHeight.Value, start_depth=strDep, # obj.StartDepth.Value, step_down=obj.StepDown.Value, z_finish_step=finish_step, final_depth=finDep, # obj.FinalDepth.Value, user_depths=None) else: strDep = obj.StartDepth.Value finDep = obj.FinalDepth.Value try: env = PathUtils.getEnvelope( base.Shape, subshape=profileshape, depthparams=self.depthparams) except Exception: # PathUtils.getEnvelope() failed to return an object. PathLog.error( translate('Path', 'Unable to create path for face(s).')) else: # shapes.append((env, False)) tup = env, False, 'pathProfileFaces', angle, axis, strDep, finDep shapes.append(tup) else: for shape in faces: # Recalculate depthparams (strDep, finDep) = self.calculateStartFinalDepths( obj, shape, stock) finalDepths.append(finDep) finish_step = obj.FinishDepth.Value if hasattr( obj, "FinishDepth") else 0.0 self.depthparams = PathUtils.depth_params( clearance_height=obj.ClearanceHeight.Value, safe_height=obj.SafeHeight.Value, start_depth=strDep, # obj.StartDepth.Value, step_down=obj.StepDown.Value, z_finish_step=finish_step, final_depth=finDep, # obj.FinalDepth.Value, user_depths=None) env = PathUtils.getEnvelope( base.Shape, subshape=shape, depthparams=self.depthparams) tup = env, False, 'pathProfileFaces', angle, axis, strDep, finDep shapes.append(tup) # Eif # adjust FinalDepth as needed finalDepth = min(finalDepths) if obj.FinalDepth.Value < finalDepth: obj.FinalDepth.Value = finalDepth else: # Try to build targets from the job base if 1 == len(self.model) and hasattr(self.model[0], "Proxy"): if isinstance(self.model[0].Proxy, ArchPanel.PanelSheet): # process the sheet if obj.processCircles or obj.processHoles: for shape in self.model[0].Proxy.getHoles( self.model[0], transform=True): for wire in shape.Wires: drillable = PathUtils.isDrillable( self.model[0].Proxy, wire) if (drillable and obj.processCircles) or ( not drillable and obj.processHoles): f = Part.makeFace(wire, 'Part::FaceMakerSimple') env = PathUtils.getEnvelope( self.model[0].Shape, subshape=f, depthparams=self.depthparams) # shapes.append((env, True)) tup = env, True, 'pathProfileFaces', 0.0, 'X', obj.StartDepth.Value, obj.FinalDepth.Value shapes.append(tup) if obj.processPerimeter: for shape in self.model[0].Proxy.getOutlines( self.model[0], transform=True): for wire in shape.Wires: f = Part.makeFace(wire, 'Part::FaceMakerSimple') env = PathUtils.getEnvelope( self.model[0].Shape, subshape=f, depthparams=self.depthparams) # shapes.append((env, False)) tup = env, False, 'pathProfileFaces', 0.0, 'X', obj.StartDepth.Value, obj.FinalDepth.Value shapes.append(tup) self.removalshapes = shapes PathLog.debug("%d shapes" % len(shapes)) return shapes
def findHoles(self, obj, baseobject): """findHoles(obj, baseobject) ... inspect baseobject and identify all features that resemble a straight cricular hole.""" shape = baseobject.Shape PathLog.track("obj: {} shape: {}".format(obj, shape)) holelist = [] features = [] # tooldiameter = float(obj.ToolController.Proxy.getTool(obj.ToolController).Diameter) tooldiameter = None PathLog.debug("search for holes larger than tooldiameter: {}: ".format( tooldiameter)) if DraftGeomUtils.isPlanar(shape): PathLog.debug("shape is planar") for i in range(len(shape.Edges)): candidateEdgeName = "Edge" + str(i + 1) e = shape.getElement(candidateEdgeName) if PathUtils.isDrillable(shape, e, tooldiameter): PathLog.debug( "edge candidate: {} (hash {})is drillable ".format( e, e.hashCode())) x = e.Curve.Center.x y = e.Curve.Center.y diameter = e.BoundBox.XLength holelist.append({ "featureName": candidateEdgeName, "feature": e, "x": x, "y": y, "d": diameter, "enabled": True, }) features.append((baseobject, candidateEdgeName)) PathLog.debug("Found hole feature %s.%s" % (baseobject.Label, candidateEdgeName)) else: PathLog.debug("shape is not planar") for i in range(len(shape.Faces)): candidateFaceName = "Face" + str(i + 1) f = shape.getElement(candidateFaceName) if PathUtils.isDrillable(shape, f, tooldiameter): PathLog.debug("face candidate: {} is drillable ".format(f)) if hasattr(f.Surface, "Center"): x = f.Surface.Center.x y = f.Surface.Center.y diameter = f.BoundBox.XLength else: center = f.Edges[0].Curve.Center x = center.x y = center.y diameter = f.Edges[0].Curve.Radius * 2 holelist.append({ "featureName": candidateFaceName, "feature": f, "x": x, "y": y, "d": diameter, "enabled": True, }) features.append((baseobject, candidateFaceName)) PathLog.debug("Found hole feature %s.%s" % (baseobject.Label, candidateFaceName)) PathLog.debug("holes found: {}".format(holelist)) return features
def areaOpShapes(self, obj): '''areaOpShapes(obj) ... returns envelope for all base shapes or wires for Arch.Panels.''' if obj.UseComp: self.commandlist.append( Path.Command("(Compensated Tool Path. Diameter: " + str(self.radius * 2) + ")")) else: self.commandlist.append(Path.Command("(Uncompensated Tool Path)")) shapes = [] self.profileshape = [] if obj.Base: # The user has selected subobjects from the base. Process each. for base in obj.Base: holes = [] faces = [] for sub in base[1]: shape = getattr(base[0].Shape, sub) if isinstance(shape, Part.Face): faces.append(shape) if numpy.isclose(abs(shape.normalAt(0, 0).z), 1): # horizontal face for wire in shape.Wires[1:]: holes.append((base[0].Shape, wire)) else: FreeCAD.Console.PrintWarning( "found a base object which is not a face. Can't continue." ) return for shape, wire in holes: f = Part.makeFace(wire, 'Part::FaceMakerSimple') drillable = PathUtils.isDrillable(shape, wire) if (drillable and obj.processCircles) or (not drillable and obj.processHoles): env = PathUtils.getEnvelope( shape, subshape=f, depthparams=self.depthparams) PathLog.track() shapes.append((env, True)) if len(faces) > 0: profileshape = Part.makeCompound(faces) self.profileshape.append(profileshape) if obj.processPerimeter: env = PathUtils.getEnvelope(base[0].Shape, subshape=profileshape, depthparams=self.depthparams) PathLog.track() shapes.append((env, False)) else: # Try to build targets from the job base if 1 == len(self.model) and hasattr(self.model[0], "Proxy"): if isinstance(self.model[0].Proxy, ArchPanel.PanelSheet): # process the sheet if obj.processCircles or obj.processHoles: for shape in self.model[0].Proxy.getHoles( self.model[0], transform=True): for wire in shape.Wires: drillable = PathUtils.isDrillable( self.model[0].Proxy, wire) if (drillable and obj.processCircles) or ( not drillable and obj.processHoles): f = Part.makeFace(wire, 'Part::FaceMakerSimple') env = PathUtils.getEnvelope( self.model[0].Shape, subshape=f, depthparams=self.depthparams) shapes.append((env, True)) if obj.processPerimeter: for shape in self.model[0].Proxy.getOutlines( self.model[0], transform=True): for wire in shape.Wires: f = Part.makeFace(wire, 'Part::FaceMakerSimple') env = PathUtils.getEnvelope( self.model[0].Shape, subshape=f, depthparams=self.depthparams) shapes.append((env, False)) self.removalshapes = shapes PathLog.debug("%d shapes" % len(shapes)) return shapes
def execute(self, obj): PathLog.track() if not obj.Active: path = Path.Path("(inactive operation)") obj.Path = path obj.ViewObject.Visibility = False return output = "" if obj.Comment != "": output += '(' + str(obj.Comment) + ')\n' toolLoad = obj.ToolController if toolLoad is None or toolLoad.ToolNumber == 0: FreeCAD.Console.PrintError( "No Tool Controller is selected. We need a tool to build a Path." ) return else: self.vertFeed = toolLoad.VertFeed.Value self.horizFeed = toolLoad.HorizFeed.Value self.vertRapid = toolLoad.VertRapid.Value self.horizRapid = toolLoad.HorizRapid.Value tool = toolLoad.Proxy.getTool(toolLoad) if not tool or tool.Diameter == 0: FreeCAD.Console.PrintError( "No Tool found or diameter is zero. We need a tool to build a Path." ) return else: self.radius = tool.Diameter / 2 tiplength = 0.0 if obj.AddTipLength: tiplength = PathUtils.drillTipLength(tool) if len(obj.Names) == 0: parentJob = PathUtils.findParentJob(obj) if parentJob is None: return baseobject = parentJob.Base if baseobject is None: return # Arch PanelSheet if hasattr(baseobject, "Proxy"): holes = [] if isinstance(baseobject.Proxy, ArchPanel.PanelSheet): baseobject.Proxy.execute(baseobject) i = 0 holeshapes = baseobject.Proxy.getHoles(baseobject, transform=True) tooldiameter = obj.ToolController.Proxy.getTool( obj.ToolController).Diameter for holeshape in holeshapes: PathLog.debug('Entering new HoleShape') for wire in holeshape.Wires: PathLog.debug('Entering new Wire') for edge in wire.Edges: if PathUtils.isDrillable( baseobject, edge, tooldiameter): PathLog.debug( 'Found drillable hole edges: {}'. format(edge)) x = edge.Curve.Center.x y = edge.Curve.Center.y diameter = edge.BoundBox.XLength holes.append({ 'x': x, 'y': y, 'featureName': baseobject.Name + '.' + 'Drill' + str(i), 'd': diameter }) i = i + 1 else: holes = self.findHoles(obj, baseobject.Shape) for i in range(len(holes)): holes[i]['featureName'] = baseobject.Name + '.' + holes[i][ 'featureName'] names = [] positions = [] enabled = [] diameters = [] for h in holes: if len(names) == 0: self.setDepths(obj, baseobject, h) names.append(h['featureName']) positions.append(FreeCAD.Vector(h['x'], h['y'], 0)) enabled.append(1) diameters.append(h['d']) obj.Names = names obj.Positions = positions obj.Enabled = enabled obj.Diameters = diameters locations = [] output = "(Begin Drilling)\n" for i in range(len(obj.Names)): if obj.Enabled[i] > 0: locations.append({ 'x': obj.Positions[i].x, 'y': obj.Positions[i].y }) if len(locations) > 0: locations = PathUtils.sort_jobs(locations, ['x', 'y']) output += "G90 " + obj.ReturnLevel + "\n" # rapid to clearance height output += "G0 Z" + str( obj.ClearanceHeight.Value) + "F " + PathUtils.fmt( self.vertRapid) + "\n" # rapid to first hole location, with spindle still retracted: p0 = locations[0] output += "G0 X" + fmt(p0['x']) + " Y" + fmt( p0['y']) + "F " + PathUtils.fmt(self.horizRapid) + "\n" # move tool to clearance plane output += "G0 Z" + fmt( obj.ClearanceHeight.Value) + "F " + PathUtils.fmt( self.vertRapid) + "\n" pword = "" qword = "" if obj.PeckDepth.Value > 0 and obj.PeckEnabled: cmd = "G83" qword = " Q" + fmt(obj.PeckDepth.Value) elif obj.DwellTime > 0 and obj.DwellEnabled: cmd = "G82" pword = " P" + fmt(obj.DwellTime) else: cmd = "G81" for p in locations: output += cmd + \ " X" + fmt(p['x']) + \ " Y" + fmt(p['y']) + \ " Z" + fmt(obj.FinalDepth.Value - tiplength) + qword + pword + \ " R" + str(obj.RetractHeight.Value) + \ " F" + str(self.vertFeed) + "\n" \ output += "G80\n" path = Path.Path(output) obj.Path = path
def execute(self, obj): PathLog.track() output = "" if obj.Comment != "": output += '(' + str(obj.Comment)+')\n' toolLoad = obj.ToolController if toolLoad is None or toolLoad.ToolNumber == 0: FreeCAD.Console.PrintError("No Tool Controller is selected. We need a tool to build a Path.") return else: self.vertFeed = toolLoad.VertFeed.Value self.horizFeed = toolLoad.HorizFeed.Value self.vertRapid = toolLoad.VertRapid.Value self.horizRapid = toolLoad.HorizRapid.Value tool = toolLoad.Proxy.getTool(toolLoad) if not tool or tool.Diameter == 0: FreeCAD.Console.PrintError("No Tool found or diameter is zero. We need a tool to build a Path.") return else: self.radius = tool.Diameter/2 if len(obj.Names) == 0: parentJob = PathUtils.findParentJob(obj) if parentJob is None: return baseobject = parentJob.Base if baseobject is None: return # Arch PanelSheet if hasattr(baseobject, "Proxy"): holes = [] if isinstance(baseobject.Proxy, ArchPanel.PanelSheet): baseobject.Proxy.execute(baseobject) i = 0 holeshapes = baseobject.Proxy.getHoles(baseobject, transform=True) tooldiameter = obj.ToolController.Proxy.getTool(obj.ToolController).Diameter for holeshape in holeshapes: PathLog.debug('Entering new HoleShape') for wire in holeshape.Wires: PathLog.debug('Entering new Wire') for edge in wire.Edges: if PathUtils.isDrillable(baseobject, edge, tooldiameter): PathLog.debug('Found drillable hole edges: {}'.format(edge)) x = edge.Curve.Center.x y = edge.Curve.Center.y diameter = edge.BoundBox.XLength holes.append({'x': x, 'y': y, 'featureName': baseobject.Name+'.'+'Drill'+str(i), 'd': diameter}) i = i + 1 else: holes = self.findHoles(obj, baseobject.Shape) for i in range(len(holes)): holes[i]['featureName'] = baseobject.Name + '.' + holes[i]['featureName'] names = [] positions = [] enabled = [] diameters = [] for h in holes: if len(names) == 0: self.findHeights(obj, baseobject, h) names.append(h['featureName']) positions.append(FreeCAD.Vector(h['x'], h['y'], 0)) enabled.append(1) diameters.append(h['d']) obj.Names = names obj.Positions = positions obj.Enabled = enabled obj.Diameters = diameters locations = [] output = "(Begin Drilling)\n" for i in range(len(obj.Names)): if obj.Enabled[i] > 0: locations.append({'x': obj.Positions[i].x, 'y': obj.Positions[i].y}) if len(locations) > 0: locations = PathUtils.sort_jobs(locations, ['x', 'y']) output += "G90 G98\n" # rapid to clearance height output += "G0 Z" + str(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n" # rapid to first hole location, with spindle still retracted: p0 = locations[0] output += "G0 X" + fmt(p0['x']) + " Y" + fmt(p0['y']) + "F " + PathUtils.fmt(self.horizRapid) + "\n" # move tool to clearance plane output += "G0 Z" + fmt(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n" pword = "" qword = "" if obj.PeckDepth.Value > 0 and obj.PeckEnabled: cmd = "G83" qword = " Q" + fmt(obj.PeckDepth.Value) elif obj.DwellTime > 0 and obj.DwellEnabled: cmd = "G82" pword = " P" + fmt(obj.DwellTime) else: cmd = "G81" for p in locations: output += cmd + \ " X" + fmt(p['x']) + \ " Y" + fmt(p['y']) + \ " Z" + fmt(obj.FinalDepth.Value) + qword + pword + \ " R" + str(obj.RetractHeight.Value) + \ " F" + str(self.vertFeed) + "\n" \ output += "G80\n" if obj.Active: path = Path.Path(output) obj.Path = path obj.ViewObject.Visibility = True else: path = Path.Path("(inactive operation)") obj.Path = path obj.ViewObject.Visibility = False
def execute(self, obj): import Part # math #DraftGeomUtils output = "" toolLoad = obj.ToolController if toolLoad is None or toolLoad.ToolNumber == 0: FreeCAD.Console.PrintError("No Tool Controller is selected. We need a tool to build a Path.") #return else: self.vertFeed = toolLoad.VertFeed.Value self.horizFeed = toolLoad.HorizFeed.Value self.vertRapid = toolLoad.VertRapid.Value self.horizRapid = toolLoad.HorizRapid.Value tool = toolLoad.Proxy.getTool(toolLoad) if not tool or tool.Diameter == 0: FreeCAD.Console.PrintError("No Tool found or diameter is zero. We need a tool to build a Path.") return else: self.radius = tool.Diameter/2 output += "(" + obj.Label + ")" if obj.UseComp: output += "(Compensated Tool Path. Diameter: " + str(self.radius * 2) + ")" else: output += "(Uncompensated Tool Path)" if obj.Base: holes = [] faces = [] for b in obj.Base: for sub in b[1]: shape = getattr(b[0].Shape, sub) if isinstance(shape, Part.Face): faces.append(shape) if numpy.isclose(abs(shape.normalAt(0, 0).z), 1): # horizontal face holes += shape.Wires[1:] else: print ("found a base object which is not a face. Can't continue.") return profileshape = Part.makeCompound(faces) profilewire = TechDraw.findShapeOutline(profileshape, 1, Vector(0, 0, 1)) if obj.processHoles: for wire in holes: edgelist = wire.Edges edgelist = Part.__sortEdges__(edgelist) output += self._buildPathLibarea(obj, edgelist, True) if obj.processPerimeter: edgelist = profilewire.Edges edgelist = Part.__sortEdges__(edgelist) output += self._buildPathLibarea(obj, edgelist, False) else: #Try to build targets frorm the job base parentJob = PathUtils.findParentJob(obj) if parentJob is None: return baseobject = parentJob.Base if baseobject is None: return if hasattr(baseobject, "Proxy"): if isinstance(baseobject.Proxy, ArchPanel.PanelSheet): # process the sheet if obj.processPerimeter: shapes = baseobject.Proxy.getOutlines(baseobject, transform=True) for shape in shapes: for wire in shape.Wires: edgelist = wire.Edges edgelist = Part.__sortEdges__(edgelist) PathLog.debug("Processing panel perimeter. edges found: {}".format(len(edgelist))) try: output += self._buildPathLibarea(obj, edgelist, isHole=False) except: FreeCAD.Console.PrintError("Something unexpected happened. Unable to generate a contour path. Check project and tool config.") shapes = baseobject.Proxy.getHoles(baseobject, transform=True) for shape in shapes: for wire in shape.Wires: drillable = PathUtils.isDrillable(baseobject.Proxy, wire) if (drillable and obj.processCircles) or (not drillable and obj.processHoles): edgelist = wire.Edges edgelist = Part.__sortEdges__(edgelist) try: output += self._buildPathLibarea(obj, edgelist, isHole=True) except: FreeCAD.Console.PrintError("Something unexpected happened. Unable to generate a contour path. Check project and tool config.") if obj.Active: path = Path.Path(output) obj.Path = path obj.ViewObject.Visibility = True else: path = Path.Path("(inactive operation)") obj.Path = path obj.ViewObject.Visibility = False
def execute(self, obj, getsim=False): import Part if not obj.Active: path = Path.Path("(inactive operation)") obj.Path = path obj.ViewObject.Visibility = False return self.depthparams = depth_params( clearance_height=obj.ClearanceHeight.Value, safe_height=obj.SafeHeight.Value, start_depth=obj.StartDepth.Value, step_down=obj.StepDown.Value, z_finish_step=0.0, final_depth=obj.FinalDepth.Value, user_depths=None) commandlist = [] toolLoad = obj.ToolController if toolLoad is None or toolLoad.ToolNumber == 0: FreeCAD.Console.PrintError("No Tool Controller is selected. We need a tool to build a Path.") return else: self.vertFeed = toolLoad.VertFeed.Value self.horizFeed = toolLoad.HorizFeed.Value self.vertRapid = toolLoad.VertRapid.Value self.horizRapid = toolLoad.HorizRapid.Value tool = toolLoad.Proxy.getTool(toolLoad) if not tool or tool.Diameter == 0: FreeCAD.Console.PrintError("No Tool found or diameter is zero. We need a tool to build a Path.") return else: self.radius = tool.Diameter/2 commandlist.append(Path.Command("(" + obj.Label + ")")) if obj.UseComp: commandlist.append(Path.Command("(Compensated Tool Path. Diameter: " + str(self.radius * 2) + ")")) else: commandlist.append(Path.Command("(Uncompensated Tool Path)")) parentJob = PathUtils.findParentJob(obj) if parentJob is None: return baseobject = parentJob.Base if baseobject is None: return if obj.Base: # The user has selected subobjects from the base. Process each. holes = [] faces = [] for b in obj.Base: for sub in b[1]: shape = getattr(b[0].Shape, sub) if isinstance(shape, Part.Face): faces.append(shape) if numpy.isclose(abs(shape.normalAt(0, 0).z), 1): # horizontal face holes += shape.Wires[1:] else: FreeCAD.Console.PrintWarning("found a base object which is not a face. Can't continue.") return for wire in holes: f = Part.makeFace(wire, 'Part::FaceMakerSimple') drillable = PathUtils.isDrillable(baseobject.Shape, wire) if (drillable and obj.processCircles) or (not drillable and obj.processHoles): env = PathUtils.getEnvelope(baseobject.Shape, subshape=f, depthparams=self.depthparams) try: (pp, sim) = self._buildPathArea(obj, baseobject=env, isHole=True, start=None, getsim=getsim) commandlist.extend(pp.Commands) except Exception as e: FreeCAD.Console.PrintError(e) FreeCAD.Console.PrintError("Something unexpected happened. Unable to generate a contour path. Check project and tool config.") if len(faces) > 0: profileshape = Part.makeCompound(faces) if obj.processPerimeter: env = PathUtils.getEnvelope(baseobject.Shape, subshape=profileshape, depthparams=self.depthparams) try: (pp, sim) = self._buildPathArea(obj, baseobject=env, start=None, getsim=getsim) commandlist.extend(pp.Commands) except Exception as e: FreeCAD.Console.PrintError(e) FreeCAD.Console.PrintError("Something unexpected happened. Unable to generate a contour path. Check project and tool config.") else: # Try to build targets from the job base if hasattr(baseobject, "Proxy"): if isinstance(baseobject.Proxy, ArchPanel.PanelSheet): # process the sheet if obj.processPerimeter: shapes = baseobject.Proxy.getOutlines(baseobject, transform=True) for shape in shapes: for wire in shape.Wires: f = Part.makeFace(wire, 'Part::FaceMakerSimple') env = PathUtils.getEnvelope(baseobject.Shape, subshape=f, depthparams=self.depthparams) try: (pp, sim) = self._buildPathArea(obj, baseobject=env, isHole=False, start=None, getsim=getsim) commandlist.extend(pp.Commands) except Exception as e: FreeCAD.Console.PrintError(e) FreeCAD.Console.PrintError("Something unexpected happened. Unable to generate a contour path. Check project and tool config.") shapes = baseobject.Proxy.getHoles(baseobject, transform=True) for shape in shapes: for wire in shape.Wires: drillable = PathUtils.isDrillable(baseobject.Proxy, wire) if (drillable and obj.processCircles) or (not drillable and obj.processHoles): f = Part.makeFace(wire, 'Part::FaceMakerSimple') env = PathUtils.getEnvelope(baseobject.Shape, subshape=f, depthparams=self.depthparams) try: (pp, sim) = self._buildPathArea(obj, baseobject=env, isHole=True, start=None, getsim=getsim) commandlist.extend(pp.Commands) except Exception as e: FreeCAD.Console.PrintError(e) FreeCAD.Console.PrintError("Something unexpected happened. Unable to generate a contour path. Check project and tool config.") # Let's finish by rapid to clearance...just for safety commandlist.append(Path.Command("G0", {"Z": obj.ClearanceHeight.Value})) path = Path.Path(commandlist) obj.Path = path
def areaOpShapes(self, obj): '''areaOpShapes(obj) ... returns envelope for all base shapes or wires for Arch.Panels.''' PathLog.track() if obj.UseComp: self.commandlist.append( Path.Command("(Compensated Tool Path. Diameter: " + str(self.radius * 2) + ")")) else: self.commandlist.append(Path.Command("(Uncompensated Tool Path)")) shapes = [] self.profileshape = [] # pylint: disable=attribute-defined-outside-init baseSubsTuples = [] subCount = 0 allTuples = [] if obj.Base: # The user has selected subobjects from the base. Process each. if obj.EnableRotation != 'Off': for p in range(0, len(obj.Base)): (base, subsList) = obj.Base[p] for sub in subsList: subCount += 1 shape = getattr(base.Shape, sub) if isinstance(shape, Part.Face): rtn = False (norm, surf) = self.getFaceNormAndSurf(shape) (rtn, angle, axis, praInfo) = self.faceRotationAnalysis( obj, norm, surf) # pylint: disable=unused-variable if rtn is True: (clnBase, angle, clnStock, tag) = self.applyRotationalAnalysis( obj, base, angle, axis, subCount) # Verify faces are correctly oriented - InverseAngle might be necessary faceIA = getattr(clnBase.Shape, sub) (norm, surf) = self.getFaceNormAndSurf(faceIA) (rtn, praAngle, praAxis, praInfo) = self.faceRotationAnalysis( obj, norm, surf) # pylint: disable=unused-variable if rtn is True: PathLog.error( translate( "Path", "Face appears misaligned after initial rotation." )) if obj.AttemptInverseAngle is True and obj.InverseAngle is False: (clnBase, clnStock, angle) = self.applyInverseAngle( obj, clnBase, clnStock, axis, angle) else: msg = translate( "Path", "Consider toggling the 'InverseAngle' property and recomputing." ) PathLog.error(msg) else: PathLog.debug( "Face appears to be oriented correctly." ) tup = clnBase, sub, tag, angle, axis, clnStock else: if self.warnDisabledAxis(obj, axis) is False: PathLog.debug( str(sub) + ": No rotation used") axis = 'X' angle = 0.0 tag = base.Name + '_' + axis + str( angle).replace('.', '_') stock = PathUtils.findParentJob(obj).Stock tup = base, sub, tag, angle, axis, stock allTuples.append(tup) if subCount > 1: msg = translate('Path', "Multiple faces in Base Geometry.") + " " msg += translate( 'Path', "Depth settings will be applied to all faces.") PathLog.warning(msg) (Tags, Grps) = self.sortTuplesByIndex( allTuples, 2) # return (TagList, GroupList) subList = [] for o in range(0, len(Tags)): subList = [] for (base, sub, tag, angle, axis, stock) in Grps[o]: subList.append(sub) pair = base, subList, angle, axis, stock baseSubsTuples.append(pair) # Efor else: PathLog.debug( translate("Path", "EnableRotation property is 'Off'.")) stock = PathUtils.findParentJob(obj).Stock for (base, subList) in obj.Base: baseSubsTuples.append((base, subList, 0.0, 'X', stock)) # for base in obj.Base: finish_step = obj.FinishDepth.Value if hasattr( obj, "FinishDepth") else 0.0 for (base, subsList, angle, axis, stock) in baseSubsTuples: holes = [] faces = [] faceDepths = [] startDepths = [] for sub in subsList: shape = getattr(base.Shape, sub) if isinstance(shape, Part.Face): faces.append(shape) if numpy.isclose(abs(shape.normalAt(0, 0).z), 1): # horizontal face for wire in shape.Wires[1:]: holes.append((base.Shape, wire)) # Add face depth to list faceDepths.append(shape.BoundBox.ZMin) else: ignoreSub = base.Name + '.' + sub msg = translate( 'Path', "Found a selected object which is not a face. Ignoring: {}" .format(ignoreSub)) PathLog.error(msg) FreeCAD.Console.PrintWarning(msg) # Set initial Start and Final Depths and recalculate depthparams finDep = obj.FinalDepth.Value strDep = obj.StartDepth.Value if strDep > stock.Shape.BoundBox.ZMax: strDep = stock.Shape.BoundBox.ZMax startDepths.append(strDep) self.depthparams = self._customDepthParams(obj, strDep, finDep) for shape, wire in holes: f = Part.makeFace(wire, 'Part::FaceMakerSimple') drillable = PathUtils.isDrillable(shape, wire) if (drillable and obj.processCircles) or (not drillable and obj.processHoles): env = PathUtils.getEnvelope( shape, subshape=f, depthparams=self.depthparams) tup = env, True, 'pathProfileFaces', angle, axis, strDep, finDep shapes.append(tup) if len(faces) > 0: profileshape = Part.makeCompound(faces) self.profileshape.append(profileshape) if obj.processPerimeter: if obj.HandleMultipleFeatures == 'Collectively': custDepthparams = self.depthparams if obj.LimitDepthToFace is True and obj.EnableRotation != 'Off': if profileshape.BoundBox.ZMin > obj.FinalDepth.Value: finDep = profileshape.BoundBox.ZMin custDepthparams = self._customDepthParams( obj, strDep, finDep - 0.5) # only an envelope try: env = PathUtils.getEnvelope( base.Shape, subshape=profileshape, depthparams=custDepthparams) except Exception: # pylint: disable=broad-except # PathUtils.getEnvelope() failed to return an object. PathLog.error( translate( 'Path', 'Unable to create path for face(s).')) else: tup = env, False, 'pathProfileFaces', angle, axis, strDep, finDep shapes.append(tup) elif obj.HandleMultipleFeatures == 'Individually': for shape in faces: profShape = Part.makeCompound([shape]) finalDep = obj.FinalDepth.Value custDepthparams = self.depthparams if obj.Side == 'Inside': if finalDep < shape.BoundBox.ZMin: # Recalculate depthparams finalDep = shape.BoundBox.ZMin custDepthparams = self._customDepthParams( obj, strDep, finalDep - 0.5) env = PathUtils.getEnvelope( base.Shape, subshape=profShape, depthparams=custDepthparams) tup = env, False, 'pathProfileFaces', angle, axis, strDep, finalDep shapes.append(tup) # Lower high Start Depth to top of Stock startDepth = max(startDepths) if obj.StartDepth.Value > startDepth: obj.StartDepth.Value = startDepth else: # Try to build targets from the job base if 1 == len(self.model): if hasattr(self.model[0], "Proxy"): PathLog.info("hasattr() Proxy") if isinstance(self.model[0].Proxy, ArchPanel.PanelSheet): # process the sheet if obj.processCircles or obj.processHoles: for shape in self.model[0].Proxy.getHoles( self.model[0], transform=True): for wire in shape.Wires: drillable = PathUtils.isDrillable( self.model[0].Proxy, wire) if (drillable and obj.processCircles) or ( not drillable and obj.processHoles): f = Part.makeFace( wire, 'Part::FaceMakerSimple') env = PathUtils.getEnvelope( self.model[0].Shape, subshape=f, depthparams=self.depthparams) tup = env, True, 'pathProfileFaces', 0.0, 'X', obj.StartDepth.Value, obj.FinalDepth.Value shapes.append(tup) if obj.processPerimeter: for shape in self.model[0].Proxy.getOutlines( self.model[0], transform=True): for wire in shape.Wires: f = Part.makeFace(wire, 'Part::FaceMakerSimple') env = PathUtils.getEnvelope( self.model[0].Shape, subshape=f, depthparams=self.depthparams) tup = env, False, 'pathProfileFaces', 0.0, 'X', obj.StartDepth.Value, obj.FinalDepth.Value shapes.append(tup) self.removalshapes = shapes # pylint: disable=attribute-defined-outside-init PathLog.debug("%d shapes" % len(shapes)) return shapes
def execute(self, obj): import Part # math #DraftGeomUtils output = "" toolLoad = obj.ToolController if toolLoad is None or toolLoad.ToolNumber == 0: FreeCAD.Console.PrintError( "No Tool Controller is selected. We need a tool to build a Path." ) #return else: self.vertFeed = toolLoad.VertFeed.Value self.horizFeed = toolLoad.HorizFeed.Value self.vertRapid = toolLoad.VertRapid.Value self.horizRapid = toolLoad.HorizRapid.Value tool = toolLoad.Proxy.getTool(toolLoad) if not tool or tool.Diameter == 0: FreeCAD.Console.PrintError( "No Tool found or diameter is zero. We need a tool to build a Path." ) return else: self.radius = tool.Diameter / 2 output += "(" + obj.Label + ")" if obj.UseComp: output += "(Compensated Tool Path. Diameter: " + str( self.radius * 2) + ")" else: output += "(Uncompensated Tool Path)" if obj.Base: holes = [] faces = [] for b in obj.Base: for sub in b[1]: shape = getattr(b[0].Shape, sub) if isinstance(shape, Part.Face): faces.append(shape) if numpy.isclose(abs(shape.normalAt(0, 0).z), 1): # horizontal face holes += shape.Wires[1:] else: print( "found a base object which is not a face. Can't continue." ) return profileshape = Part.makeCompound(faces) profilewire = TechDraw.findShapeOutline(profileshape, 1, Vector(0, 0, 1)) if obj.processHoles: for wire in holes: edgelist = wire.Edges edgelist = Part.__sortEdges__(edgelist) output += self._buildPathLibarea(obj, edgelist, True) if obj.processPerimeter: edgelist = profilewire.Edges edgelist = Part.__sortEdges__(edgelist) output += self._buildPathLibarea(obj, edgelist, False) else: #Try to build targets frorm the job base parentJob = PathUtils.findParentJob(obj) if parentJob is None: return baseobject = parentJob.Base if baseobject is None: return if hasattr(baseobject, "Proxy"): if isinstance(baseobject.Proxy, ArchPanel.PanelSheet): # process the sheet if obj.processPerimeter: shapes = baseobject.Proxy.getOutlines(baseobject, transform=True) for shape in shapes: for wire in shape.Wires: edgelist = wire.Edges edgelist = Part.__sortEdges__(edgelist) PathLog.debug( "Processing panel perimeter. edges found: {}" .format(len(edgelist))) try: output += self._buildPathLibarea(obj, edgelist, isHole=False) except: FreeCAD.Console.PrintError( "Something unexpected happened. Unable to generate a contour path. Check project and tool config." ) shapes = baseobject.Proxy.getHoles(baseobject, transform=True) for shape in shapes: for wire in shape.Wires: drillable = PathUtils.isDrillable( baseobject.Proxy, wire) if (drillable and obj.processCircles) or ( not drillable and obj.processHoles): edgelist = wire.Edges edgelist = Part.__sortEdges__(edgelist) try: output += self._buildPathLibarea( obj, edgelist, isHole=True) except: FreeCAD.Console.PrintError( "Something unexpected happened. Unable to generate a contour path. Check project and tool config." ) if obj.Active: path = Path.Path(output) obj.Path = path obj.ViewObject.Visibility = True else: path = Path.Path("(inactive operation)") obj.Path = path obj.ViewObject.Visibility = False