Path: make cursor reflect busy
Path: fix label buy in PathProfileEdges Path: cleanup
This commit is contained in:
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user