Path: lgtm Cleanup

This commit is contained in:
brad
2019-06-08 18:55:44 -05:00
parent 58608df237
commit 4cbdf78836
7 changed files with 169 additions and 144 deletions

View File

@@ -30,7 +30,6 @@ import PathScripts.PathGeom as PathGeom
import TechDraw
import math
import numpy
import sys
from DraftGeomUtils import geomType
from FreeCAD import Vector
@@ -44,13 +43,15 @@ if False:
PathLog.trackModule(PathLog.thisModule())
else:
PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
#FreeCAD.setLogLevel('Path.Area', 0)
def translate(context, text, disambig=None):
return QtCore.QCoreApplication.translate(context, text, disambig)
UserInput = None
def waiting_effects(function):
def new_function(*args, **kwargs):
if not FreeCAD.GuiUp:
@@ -60,7 +61,7 @@ def waiting_effects(function):
try:
res = function(*args, **kwargs)
# don't catch exceptions - want to know where they are coming from ....
#except Exception as e:
# except Exception as e:
# raise e
# print("Error {}".format(e.args[0]))
finally:
@@ -148,7 +149,7 @@ def isDrillable(obj, candidate, tooldiameter=None, includePartials=False):
PathLog.debug("candidate is a circle")
v0 = edge.Vertexes[0].Point
v1 = edge.Vertexes[1].Point
#check if the cylinder seam is vertically aligned. Eliminate tilted holes
# check if the cylinder seam is vertically aligned. Eliminate tilted holes
if (numpy.isclose(v1.sub(v0).x, 0, rtol=1e-05, atol=1e-06)) and \
(numpy.isclose(v1.sub(v0).y, 0, rtol=1e-05, atol=1e-06)):
drillable = True
@@ -160,7 +161,7 @@ def isDrillable(obj, candidate, tooldiameter=None, includePartials=False):
# object. This eliminates extruded circles but allows
# actual holes.
if obj.isInside(lsp, 1e-6, False) or obj.isInside(lep, 1e-6, False):
PathLog.track("inside check failed. lsp: {} lep: {}".format(lsp,lep))
PathLog.track("inside check failed. lsp: {} lep: {}".format(lsp, lep))
drillable = False
# eliminate elliptical holes
elif not hasattr(face.Surface, "Radius"):
@@ -168,15 +169,15 @@ def isDrillable(obj, candidate, tooldiameter=None, includePartials=False):
drillable = False
else:
if tooldiameter is not None:
drillable = face.Surface.Radius >= tooldiameter/2
drillable = face.Surface.Radius >= tooldiameter / 2
else:
drillable = True
elif type(face.Surface) == Part.Plane and PathGeom.pointsCoincide(face.Surface.Axis, FreeCAD.Vector(0,0,1)):
elif type(face.Surface) == Part.Plane and PathGeom.pointsCoincide(face.Surface.Axis, FreeCAD.Vector(0, 0, 1)):
if len(face.Edges) == 1 and type(face.Edges[0].Curve) == Part.Circle:
center = face.Edges[0].Curve.Center
if obj.isInside(center, 1e-6, False):
if tooldiameter is not None:
drillable = face.Edges[0].Curve.Radius >= tooldiameter/2
drillable = face.Edges[0].Curve.Radius >= tooldiameter / 2
else:
drillable = True
else:
@@ -189,12 +190,12 @@ def isDrillable(obj, candidate, tooldiameter=None, includePartials=False):
else:
PathLog.debug("Has Radius, Circle")
if tooldiameter is not None:
drillable = edge.Curve.Radius >= tooldiameter/2
drillable = edge.Curve.Radius >= tooldiameter / 2
if not drillable:
FreeCAD.Console.PrintMessage(
"Found a drillable hole with diameter: {}: "
"too small for the current tool with "
"diameter: {}".format(edge.Curve.Radius*2, tooldiameter))
"Found a drillable hole with diameter: {}: "
"too small for the current tool with "
"diameter: {}".format(edge.Curve.Radius * 2, tooldiameter))
else:
drillable = True
PathLog.debug("candidate is drillable: {}".format(drillable))
@@ -204,7 +205,8 @@ def isDrillable(obj, candidate, tooldiameter=None, includePartials=False):
# fixme set at 4 decimal places for testing
def fmt(val): return format(val, '.4f')
def fmt(val):
return format(val, '.4f')
def segments(poly):
@@ -235,6 +237,7 @@ def loopdetect(obj, edge1, edge2):
loopwire = next(x for x in loop)[1]
return loopwire
def horizontalEdgeLoop(obj, edge):
'''horizontalEdgeLoop(obj, edge) ... returns a wire in the horizontal plane, if that is the only horizontal wire the given edge is a part of.'''
h = edge.hashCode()
@@ -244,6 +247,7 @@ def horizontalEdgeLoop(obj, edge):
return loops[0]
return None
def horizontalFaceLoop(obj, face, faceList=None):
'''horizontalFaceLoop(obj, face, faceList=None) ... returns a list of face names which form the walls of a vertical hole face is a part of.
All face names listed in faceList must be part of the hole for the solution to be returned.'''
@@ -256,8 +260,8 @@ def horizontalFaceLoop(obj, face, faceList=None):
for wire in wires:
hashes = [e.hashCode() for e in wire.Edges]
#find all faces that share a an edge with the wire and are vertical
faces = ["Face%d"%(i+1) for i,f in enumerate(obj.Shape.Faces) if any(e.hashCode() in hashes for e in f.Edges) and PathGeom.isVertical(f)]
# find all faces that share a an edge with the wire and are vertical
faces = ["Face%d" % (i + 1) for i, f in enumerate(obj.Shape.Faces) if any(e.hashCode() in hashes for e in f.Edges) and PathGeom.isVertical(f)]
if faceList and not all(f in faces for f in faceList):
continue
@@ -265,7 +269,7 @@ def horizontalFaceLoop(obj, face, faceList=None):
# verify they form a valid hole by getting the outline and comparing
# the resulting XY footprint with that of the faces
comp = Part.makeCompound([obj.Shape.getElement(f) for f in faces])
outline = TechDraw.findShapeOutline(comp, 1, FreeCAD.Vector(0,0,1))
outline = TechDraw.findShapeOutline(comp, 1, FreeCAD.Vector(0, 0, 1))
# findShapeOutline always returns closed wires, by removing the
# trace-backs single edge spikes don't contriubte to the bound box
@@ -284,6 +288,7 @@ def horizontalFaceLoop(obj, face, faceList=None):
return faces
return None
def filterArcs(arcEdge):
'''filterArcs(Edge) -used to split arcs that over 180 degrees. Returns list '''
PathLog.track()
@@ -302,10 +307,8 @@ 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)
@@ -345,10 +348,6 @@ def getEnvelope(partshape, subshape=None, depthparams=None):
'''
PathLog.track(partshape, subshape, depthparams)
# if partshape.Volume == 0.0: #Not a 3D object
# return None
zShift = 0
if subshape is not None:
if isinstance(subshape, Part.Face):
@@ -360,7 +359,6 @@ def getEnvelope(partshape, subshape=None, depthparams=None):
PathLog.debug("About to section with params: {}".format(area.getParams()))
sec = area.makeSections(heights=[0.0], project=True)[0].getShape()
# zShift = partshape.BoundBox.ZMin - subshape.BoundBox.ZMin
PathLog.debug('partshapeZmin: {}, subshapeZMin: {}, zShift: {}'.format(partshape.BoundBox.ZMin, subshape.BoundBox.ZMin, zShift))
else:
@@ -371,9 +369,7 @@ def getEnvelope(partshape, subshape=None, depthparams=None):
# If depthparams are passed, use it to calculate bottom and height of
# envelope
if depthparams is not None:
# eLength = float(stockheight)-partshape.BoundBox.ZMin
eLength = depthparams.safe_height - depthparams.final_depth
#envelopeshape = sec.extrude(FreeCAD.Vector(0, 0, eLength))
zShift = depthparams.final_depth - sec.BoundBox.ZMin
PathLog.debug('boundbox zMIN: {} elength: {} zShift {}'.format(partshape.BoundBox.ZMin, eLength, zShift))
else:
@@ -467,6 +463,7 @@ def GetJobs(jobname=None):
return [job for job in PathJob.Instances() if job.Name == jobname]
return PathJob.Instances()
def addToJob(obj, jobname=None):
'''adds a path object to a job
obj = obj
@@ -492,6 +489,7 @@ def addToJob(obj, jobname=None):
job.Proxy.addOperation(obj)
return job
def rapid(x=None, y=None, z=None):
""" Returns gcode string to perform a rapid move."""
retstr = "G00"
@@ -583,11 +581,11 @@ def helicalPlunge(plungePos, rampangle, destZ, startZ, toold, plungeR, horizFeed
raise Exception("Helical plunging requires a position!")
return None
helixX = plungePos.x + toold/2 * plungeR
helixX = plungePos.x + toold / 2 * plungeR
helixY = plungePos.y
helixCirc = math.pi * toold * plungeR
dzPerRev = math.sin(rampangle/180. * math.pi) * helixCirc
dzPerRev = math.sin(rampangle / 180. * math.pi) * helixCirc
# Go to the start of the helix position
helixCmds += rapid(helixX, helixY)
@@ -595,7 +593,7 @@ def helicalPlunge(plungePos, rampangle, destZ, startZ, toold, plungeR, horizFeed
# Helix as required to get to the requested depth
lastZ = startZ
curZ = max(startZ-dzPerRev, destZ)
curZ = max(startZ - dzPerRev, destZ)
done = False
while not done:
done = (curZ == destZ)
@@ -604,7 +602,7 @@ def helicalPlunge(plungePos, rampangle, destZ, startZ, toold, plungeR, horizFeed
# Use two half-helixes; FreeCAD renders that correctly,
# and it fits with the other code breaking up 360-degree arcs
helixCmds += arc(plungePos.x, plungePos.y, helixX, helixY, helixX - toold * plungeR, helixY, horizFeed, ez=(curZ + lastZ)/2., ccw=True)
helixCmds += arc(plungePos.x, plungePos.y, helixX, helixY, helixX - toold * plungeR, helixY, horizFeed, ez=(curZ + lastZ) / 2., ccw=True)
helixCmds += arc(plungePos.x, plungePos.y, helixX - toold * plungeR, helixY, helixX, helixY, horizFeed, ez=curZ, ccw=True)
lastZ = curZ
curZ = max(curZ - dzPerRev, destZ)
@@ -641,7 +639,7 @@ def rampPlunge(edge, rampangle, destZ, startZ):
ePoint = edge.Vertexes[-1].Point
rampDist = edge.Length
rampDZ = math.sin(rampangle/180. * math.pi) * rampDist
rampDZ = math.sin(rampangle / 180. * math.pi) * rampDist
rampCmds += rapid(sPoint.x, sPoint.y)
rampCmds += rapid(z=startZ)
@@ -649,7 +647,7 @@ def rampPlunge(edge, rampangle, destZ, startZ):
# Ramp down to the requested depth
# FIXME: This might be an arc, so handle that as well
curZ = max(startZ-rampDZ, destZ)
curZ = max(startZ - rampDZ, destZ)
done = False
while not done:
done = (curZ == destZ)
@@ -699,7 +697,7 @@ def sort_jobs(locations, keys, attractors=[]):
def find_closest(location_list, location, dist):
q = PriorityQueue()
for i,j in enumerate(location_list):
for i, j in enumerate(location_list):
# prevent dictionary comparison by inserting the index
q.put((dist(j, location) + weight(j), i, j))
@@ -720,6 +718,7 @@ def sort_jobs(locations, keys, attractors=[]):
return out
def guessDepths(objshape, subs=None):
"""
takes an object shape and optional list of subobjects and returns a depth_params
@@ -751,6 +750,7 @@ def guessDepths(objshape, subs=None):
return depth_params(clearance, safe, start, 1.0, 0.0, final, user_depths=None, equalstep=False)
def drillTipLength(tool):
"""returns the length of the drillbit tip."""
if tool.CuttingEdgeAngle == 180 or tool.CuttingEdgeAngle == 0.0 or tool.Diameter == 0.0:
@@ -760,13 +760,14 @@ def drillTipLength(tool):
PathLog.error(translate("Path", "Invalid Cutting Edge Angle %.2f, must be >0° and <=180°") % tool.CuttingEdgeAngle)
return 0.0
theta = math.radians(tool.CuttingEdgeAngle)
length = (tool.Diameter/2) / math.tan(theta/2)
length = (tool.Diameter / 2) / math.tan(theta / 2)
if length < 0:
PathLog.error(translate("Path", "Cutting Edge Angle (%.2f) results in negative tool tip length") % tool.CuttingEdgeAngle)
return 0.0
return length
class depth_params:
class depth_params(object):
'''calculates the intermediate depth values for various operations given the starting, ending, and stepdown parameters
(self, clearance_height, safe_height, start_depth, step_down, z_finish_depth, final_depth, [user_depths=None], equalstep=False)
@@ -821,7 +822,7 @@ class depth_params:
@property
def safe_height(self):
"""
Height of top of raw stock material. Rapid moves above safe height are
Height of top of raw stock material. Rapid moves above safe height are
assumed to be safe within an operation. May not be safe between
operations or tool changes.
All moves below safe height except retraction should be at feed rate.
@@ -922,5 +923,3 @@ class depth_params:
return depths
else:
return [stop] + depths