Path: make cursor reflect busy

Path: fix label buy in PathProfileEdges

Path: cleanup
This commit is contained in:
sliptonic
2017-05-10 13:44:31 -05:00
committed by wmayer
parent 7bccfff0de
commit 29130de609
4 changed files with 82 additions and 53 deletions

View File

@@ -23,15 +23,14 @@
# ***************************************************************************
import FreeCAD
#from FreeCAD import Vector
import Path
import PathScripts.PathLog as PathLog
from PathScripts import PathUtils
from PathScripts.PathUtils import depth_params
from PySide import QtCore
#import TechDraw
import ArchPanel
import Part
from PathScripts.PathUtils import waiting_effects
LOG_MODULE = 'PathContour'
PathLog.setLevel(PathLog.Level.INFO, LOG_MODULE)
@@ -123,15 +122,15 @@ class ObjectContour:
obj.ClearanceHeight = 10.0
obj.SafeHeight = 8.0
@waiting_effects
def _buildPathArea(self, obj, baseobject, start=None):
PathLog.track()
profile = Path.Area()
profile.setPlane(Part.makeCircle(10))
profile.add(baseobject)
profileparams = {'Fill': 0,
'Coplanar' : 0}
'Coplanar': 0}
if obj.UseComp is False:
profileparams['Offset'] = 0.0
@@ -219,17 +218,14 @@ class ObjectContour:
for shape in shapes:
f = Part.makeFace([shape], 'Part::FaceMakerSimple')
thickness = baseobject.Group[0].Source.Thickness
contourshape = f.extrude(FreeCAD.Vector(0,0, thickness))
contourshape = f.extrude(FreeCAD.Vector(0, 0, thickness))
try:
commandlist.extend(self._buildPathArea(obj, contourshape).Commands)
except Exception as e:
print(e)
FreeCAD.Console.PrintError("Something unexpected happened. Unable to generate a contour path. Check project and tool config.")
else:
#fixbase = baseobject.Shape.copy()
#fixbase.fix(0.00001, 0.00001, 0.00001)
env = PathUtils.getEnvelope(baseobject.Shape, obj.StartDepth)
try:
commandlist.extend(self._buildPathArea(obj, env).Commands)
except Exception as e:

View File

@@ -30,6 +30,7 @@ from PathScripts import PathUtils
import Part
from FreeCAD import Vector
import PathScripts.PathLog as PathLog
from PathScripts.PathUtils import waiting_effects
LOG_MODULE = 'PathMillFace'
PathLog.setLevel(PathLog.Level.INFO, LOG_MODULE)
@@ -158,6 +159,7 @@ class ObjectFace:
return self.getStock(o)
return None
@waiting_effects
def _buildPathArea(self, obj, baseobject):
"""build the face path using PathArea"""
from PathScripts.PathUtils import depth_params
@@ -170,28 +172,27 @@ class ObjectFace:
stepover = (self.radius * 2) * (float(obj.StepOver)/100)
pocketparams = {'Fill': 0,
'Coplanar' : 0,
'PocketMode': 4,
'SectionCount': -1,
'Angle': obj.ZigZagAngle,
'FromCenter': (obj.StartAt == "Center"),
'PocketStepover': stepover,
'PocketExtraOffset': obj.PassExtension.Value }
'Coplanar': 0,
'PocketMode': 4,
'SectionCount': -1,
'Angle': obj.ZigZagAngle,
'FromCenter': (obj.StartAt == "Center"),
'PocketStepover': stepover,
'PocketExtraOffset': obj.PassExtension.Value}
depthparams = depth_params(
clearance_height = obj.ClearanceHeight.Value,
rapid_safety_space = obj.SafeHeight.Value,
start_depth = obj.StartDepth.Value,
step_down = obj.StepDown,
z_finish_step = obj.FinishDepth.Value,
final_depth = obj.FinalDepth.Value,
user_depths = None)
clearance_height=obj.ClearanceHeight.Value,
rapid_safety_space=obj.SafeHeight.Value,
start_depth=obj.StartDepth.Value,
step_down=obj.StepDown,
z_finish_step=obj.FinishDepth.Value,
final_depth=obj.FinalDepth.Value,
user_depths=None)
boundary.setParams(**pocketparams)
sections = boundary.makeSections(mode=0, project=False, heights=depthparams.get_depths())
shapelist = [sec.getShape() for sec in sections]
params = {'shapes': shapelist,
'feedrate': self.horizFeed,
'feedrate_v': self.vertFeed,
@@ -204,7 +205,6 @@ class ObjectFace:
# else:
# params['orientation'] = 0
PathLog.debug("Generating Path with params: {}".format(params))
pp = Path.fromShapes(**params)
@@ -277,8 +277,6 @@ class ObjectFace:
print(e)
FreeCAD.Console.PrintWarning(translate("PathMillFace", "The selected settings did not produce a valid path.\n"))
#FreeCAD.Console.PrintError("Something unexpected happened. Unable to generate a contour path. Check project and tool config.")
if obj.Active:
path = Path.Path(commandlist)
obj.Path = path
@@ -368,7 +366,6 @@ class CommandPathMillFace:
FreeCADGui.doCommand('obj.StartDepth = ' + str(ztop + 1))
FreeCADGui.doCommand('obj.FinalDepth =' + str(ztop))
FreeCADGui.doCommand('obj.ZigZagAngle = 45.0')
#FreeCADGui.doCommand('obj.UseZigZag = True')
FreeCADGui.doCommand('PathScripts.PathUtils.addToJob(obj)')
FreeCADGui.doCommand('obj.ToolController = PathScripts.PathUtils.findToolController(obj)')
snippet = '''
@@ -469,7 +466,6 @@ class TaskPanel:
self.form.boundaryShape.setCurrentIndex(index)
self.form.boundaryShape.blockSignals(False)
index = self.form.offsetpattern.findText(
self.obj.OffsetPattern, QtCore.Qt.MatchFixedString)
if index >= 0:
@@ -614,8 +610,6 @@ class TaskPanel:
self.form.boundaryShape.currentIndexChanged.connect(self.getFields)
self.form.stepOverPercent.editingFinished.connect(self.getFields)
self.form.offsetpattern.currentIndexChanged.connect(self.getFields)
#self.form.useZigZag.clicked.connect(self.getFields)
#self.form.zigZagUnidirectional.clicked.connect(self.getFields)
self.form.zigZagAngle.editingFinished.connect(self.getFields)
self.form.uiToolController.currentIndexChanged.connect(self.getFields)

View File

@@ -28,6 +28,7 @@ from PathScripts import PathUtils
from PathScripts.PathUtils import depth_params
from DraftGeomUtils import findWires
import PathScripts.PathLog as PathLog
from PathScripts.PathUtils import waiting_effects
"""Path Profile from Edges Object and Command"""
@@ -107,8 +108,7 @@ class ObjectProfile:
return None
def onChanged(self, obj, prop):
if prop == "UserLabel":
obj.Label = obj.UserLabel + " :" + obj.ToolDescription
pass
def addprofilebase(self, obj, ss, sub=""):
baselist = obj.Base
@@ -144,6 +144,7 @@ class ObjectProfile:
obj.Base = baselist
self.execute(obj)
@waiting_effects
def _buildPathLibarea(self, obj, edgelist):
import PathScripts.PathKurveUtils as PathKurveUtils
# import math

View File

@@ -31,13 +31,30 @@ import PathScripts
from PathScripts import PathJob
import numpy
import PathLog
#from math import pi
from FreeCAD import Vector
import Path
from PySide import QtCore
from PySide import QtGui
LOG_MODULE = 'PathUtils'
PathLog.setLevel(PathLog.Level.INFO, LOG_MODULE)
#PathLog.trackModule('PathUtils')
# PathLog.trackModule('PathUtils')
def waiting_effects(function):
def new_function(*args, **kwargs):
QtGui.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor)
res = None
try:
res = function(*args, **kwargs)
except Exception as e:
raise e
print("Error {}".format(e.args[0]))
finally:
QtGui.QApplication.restoreOverrideCursor()
return res
return new_function
def cleanedges(splines, precision):
'''cleanedges([splines],precision). Convert BSpline curves, Beziers, to arcs that can be used for cnc paths.
@@ -74,8 +91,10 @@ def cleanedges(splines, precision):
return edges
def curvetowire(obj, steps):
'''adapted from DraftGeomUtils, because the discretize function changed a bit '''
points = obj.copy().discretize(Distance=eval('steps'))
p0 = points[0]
edgelist = []
@@ -85,6 +104,7 @@ def curvetowire(obj, steps):
p0 = p
return edgelist
def isDrillable(obj, candidate, tooldiameter=None):
PathLog.track('obj: {} candidate: {} tooldiameter {}'.format(obj, candidate, tooldiameter))
drillable = False
@@ -99,13 +119,13 @@ def isDrillable(obj, candidate, tooldiameter=None):
v1 = edge.Vertexes[1].Point
if (v1.sub(v0).x == 0) and (v1.sub(v0).y == 0):
# vector of top center
lsp = Vector(face.BoundBox.Center.x,face.BoundBox.Center.y, face.BoundBox.ZMax)
lsp = Vector(face.BoundBox.Center.x, face.BoundBox.Center.y, face.BoundBox.ZMax)
# vector of bottom center
lep = Vector(face.BoundBox.Center.x,face.BoundBox.Center.y, face.BoundBox.ZMin)
lep = Vector(face.BoundBox.Center.x, face.BoundBox.Center.y, face.BoundBox.ZMin)
if obj.isInside(lsp, 0, False) or obj.isInside(lep, 0, False):
drillable = False
# eliminate elliptical holes
elif not hasattr(face.Surface, "Radius"): #abs(face.BoundBox.XLength - face.BoundBox.YLength) > 0.05:
elif not hasattr(face.Surface, "Radius"):
drillable = False
else:
if tooldiameter is not None:
@@ -116,7 +136,7 @@ def isDrillable(obj, candidate, tooldiameter=None):
for edge in candidate.Edges:
if isinstance(edge.Curve, Part.Circle) and edge.isClosed():
PathLog.debug("candidate is a circle or ellipse")
if not hasattr(edge.Curve, "Radius"): #bbdiff > 0.05:
if not hasattr(edge.Curve, "Radius"):
PathLog.debug("No radius. Ellipse.")
drillable = False
else:
@@ -128,13 +148,16 @@ def isDrillable(obj, candidate, tooldiameter=None):
PathLog.debug("candidate is drillable: {}".format(drillable))
return drillable
# fixme set at 4 decimal places for testing
def fmt(val): return format(val, '.4f')
def segments(poly):
''' A sequence of (x,y) numeric coordinates pairs '''
return zip(poly, poly[1:] + [poly[0]])
def loopdetect(obj, edge1, edge2):
'''
Returns a loop wire that includes the two edges.
@@ -149,15 +172,16 @@ def loopdetect(obj, edge1, edge2):
for wire in obj.Shape.Wires:
for e in wire.Edges:
if e.hashCode() == edge1.hashCode():
candidates.append((wire.hashCode(),wire))
candidates.append((wire.hashCode(), wire))
if e.hashCode() == edge2.hashCode():
candidates.append((wire.hashCode(),wire))
loop = set([x for x in candidates if candidates.count(x) > 1]) #return the duplicate item
candidates.append((wire.hashCode(), wire))
loop = set([x for x in candidates if candidates.count(x) > 1]) # return the duplicate item
if len(loop) != 1:
return None
loopwire = next(x for x in loop)[1]
return loopwire
def filterArcs(arcEdge):
'''filterArcs(Edge) -used to split arcs that over 180 degrees. Returns list '''
s = arcEdge
@@ -175,10 +199,10 @@ def filterArcs(arcEdge):
arcstpt = s.valueAt(s.FirstParameter)
arcmid = s.valueAt(
(s.LastParameter - s.FirstParameter) * 0.5 + s.FirstParameter)
arcquad1 = s.valueAt((s.LastParameter - s.FirstParameter)
* 0.25 + s.FirstParameter) # future midpt for arc1
arcquad2 = s.valueAt((s.LastParameter - s.FirstParameter)
* 0.75 + s.FirstParameter) # future midpt for arc2
arcquad1 = s.valueAt((s.LastParameter - s.FirstParameter) *
0.25 + s.FirstParameter) # future midpt for arc1
arcquad2 = s.valueAt((s.LastParameter - s.FirstParameter) *
0.75 + s.FirstParameter) # future midpt for arc2
arcendpt = s.valueAt(s.LastParameter)
# reconstruct with 2 arcs
arcseg1 = Part.ArcOfCircle(arcstpt, arcquad1, arcmid)
@@ -194,6 +218,7 @@ def filterArcs(arcEdge):
pass
return splitlist
def getEnvelope(partshape, stockheight=None):
'''
getEnvelop(partshape, stockheight=None)
@@ -211,6 +236,7 @@ def getEnvelope(partshape, stockheight=None):
else:
return sec.extrude(FreeCAD.Vector(0, 0, partshape.BoundBox.ZMax))
def getEnvelopeTD(partshape, stockheight=None):
'''
getEnvelopTD(partshape, stockheight=None)
@@ -222,12 +248,13 @@ def getEnvelopeTD(partshape, stockheight=None):
stockheight = float
'''
import TechDraw
sec = Part.Face(TechDraw.findShapeOutline(partshape, 1 , FreeCAD.Vector(0,0,1)))
sec = Part.Face(TechDraw.findShapeOutline(partshape, 1, FreeCAD.Vector(0, 0, 1)))
if stockheight is not None:
return sec.extrude(FreeCAD.Vector(0, 0, stockheight))
else:
return sec.extrude(FreeCAD.Vector(0, 0, partshape.BoundBox.ZMax))
def reverseEdge(e):
if geomType(e) == "Circle":
arcstpt = e.valueAt(e.FirstParameter)
@@ -242,6 +269,7 @@ def reverseEdge(e):
return newedge
def changeTool(obj, job):
tlnum = 0
for p in job.Group:
@@ -257,6 +285,7 @@ def changeTool(obj, job):
if g == obj:
return tlnum
def getToolControllers(obj):
'''returns all the tool controllers'''
controllers = []
@@ -272,6 +301,7 @@ def getToolControllers(obj):
controllers.append(g)
return controllers
def findToolController(obj, name=None):
'''returns a tool controller with a given name.
If no name is specified, returns the first controller.
@@ -279,7 +309,7 @@ def findToolController(obj, name=None):
PathLog.track('name: {}'.format(name))
c = None
#First check if a user has selected a tool controller in the tree. Return the first one and remove all from selection
# First check if a user has selected a tool controller in the tree. Return the first one and remove all from selection
for sel in FreeCADGui.Selection.getSelectionEx():
if hasattr(sel.Object, 'Proxy'):
if isinstance(sel.Object.Proxy, PathScripts.PathLoadTool.LoadTool):
@@ -294,16 +324,16 @@ def findToolController(obj, name=None):
if len(controllers) == 0:
return None
#If there's only one in the job, use it.
# If there's only one in the job, use it.
if len(controllers) == 1:
if name is None or name == controllers[0].Label:
tc = controllers[0]
else:
tc = None
elif name is not None: #More than one, make the user choose.
elif name is not None: # More than one, make the user choose.
tc = [i for i in controllers if i.Label == name][0]
else:
#form = FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/Path/DlgTCChooser.ui")
# form = FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/Path/DlgTCChooser.ui")
form = FreeCADGui.PySideUic.loadUi(":/panels/DlgTCChooser.ui")
mylist = [i.Label for i in controllers]
form.uiToolController.addItems(mylist)
@@ -314,6 +344,7 @@ def findToolController(obj, name=None):
tc = [i for i in controllers if i.Label == form.uiToolController.currentText()][0]
return tc
def findParentJob(obj):
'''retrieves a parent job object for an operation or other Path object'''
PathLog.track()
@@ -326,7 +357,8 @@ def findParentJob(obj):
return grandParent
return None
def GetJobs(jobname = None):
def GetJobs(jobname=None):
'''returns all jobs in the current document. If name is given, returns that job'''
PathLog.track()
jobs = []
@@ -340,7 +372,8 @@ def GetJobs(jobname = None):
jobs.append(o)
return jobs
def addToJob(obj, jobname = None):
def addToJob(obj, jobname=None):
'''adds a path object to a job
obj = obj
jobname = None'''
@@ -360,7 +393,7 @@ def addToJob(obj, jobname = None):
elif len(jobs) == 1:
job = jobs[0]
else:
#form = FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/Path/DlgJobChooser.ui")
# form = FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/Path/DlgJobChooser.ui")
form = FreeCADGui.PySideUic.loadUi(":/panels/DlgJobChooser.ui")
mylist = [i.Name for i in jobs]
form.cboProject.addItems(mylist)
@@ -376,6 +409,7 @@ def addToJob(obj, jobname = None):
job.Group = g
return job
def rapid(x=None, y=None, z=None):
""" Returns gcode string to perform a rapid move."""
retstr = "G00"
@@ -390,6 +424,7 @@ def rapid(x=None, y=None, z=None):
return ""
return retstr + "\n"
def feed(x=None, y=None, z=None, horizFeed=0, vertFeed=0):
""" Return gcode string to perform a linear feed."""
global feedxy
@@ -410,6 +445,7 @@ def feed(x=None, y=None, z=None, horizFeed=0, vertFeed=0):
return ""
return retstr + "\n"
def arc(cx, cy, sx, sy, ex, ey, horizFeed=0, ez=None, ccw=False):
"""
Return gcode string to perform an arc.
@@ -446,6 +482,7 @@ def arc(cx, cy, sx, sy, ex, ey, horizFeed=0, ez=None, ccw=False):
return retstr + "\n"
def helicalPlunge(plungePos, rampangle, destZ, startZ, toold, plungeR, horizFeed):
"""
Return gcode string to perform helical entry move.
@@ -492,6 +529,7 @@ def helicalPlunge(plungePos, rampangle, destZ, startZ, toold, plungeR, horizFeed
return helixCmds
def rampPlunge(edge, rampangle, destZ, startZ):
"""
Return gcode string to linearly ramp down to milling level.