From 604cfaf77966a589ac0af1799573f66a034fdcdb Mon Sep 17 00:00:00 2001 From: Russell Johnson <47639332+Russ4262@users.noreply.github.com> Date: Wed, 21 Oct 2020 22:32:13 -0500 Subject: [PATCH 1/6] Path: Apply missing `CutMode` setting when `CutPattern = Offset` The `CutMode` toggle had no effect. This fix applies the `CutMode` toggle when the `CutPattern = Offset`. The indicated `CutMode` may not be accurate depending on the situation, but the toggle will change the cut direction as intended. --- .../Path/PathScripts/PathSurfaceSupport.py | 52 ++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/src/Mod/Path/PathScripts/PathSurfaceSupport.py b/src/Mod/Path/PathScripts/PathSurfaceSupport.py index 7f73747280..3ff57cf7db 100644 --- a/src/Mod/Path/PathScripts/PathSurfaceSupport.py +++ b/src/Mod/Path/PathScripts/PathSurfaceSupport.py @@ -33,6 +33,7 @@ from PySide import QtCore import Path import PathScripts.PathLog as PathLog import PathScripts.PathUtils as PathUtils +import PathScripts.PathOpTools as PathOpTools import math # lazily loaded modules @@ -383,15 +384,64 @@ class PathGeometryGenerator: wires = list() shape = self.shape offset = 0.0 # Start right at the edge of cut area + direction = 0 + loop_cnt = 0 + + def _get_direction(w): + if PathOpTools._isWireClockwise(w): + return 1 + return -1 + + def _reverse_wire(w): + rev_list = list() + for e in w.Edges: + rev_list.append(PathUtils.reverseEdge(e)) + rev_list.reverse() + # return Part.Wire(Part.__sortEdges__(rev_list)) + return Part.Wire(rev_list) + while True: offsetArea = PathUtils.getOffsetArea(shape, offset, plane=self.wpc) if not offsetArea: # Area fully consumed break + + # set initial cut direction + if direction == 0: + first_face_wire = offsetArea.Faces[0].Wires[0] + direction = _get_direction(first_face_wire) + if self.obj.CutMode == 'Climb': + if direction == 1: + direction = -1 + else: + if direction == -1: + direction = 1 + + # Correct cut direction for `Conventional` cuts + if self.obj.CutMode == 'Conventional': + if loop_cnt == 1: + direction = direction * -1 + + # process each wire within face for f in offsetArea.Faces: + wire_cnt = 0 for w in f.Wires: - wires.append(w) + use_direction = direction + if wire_cnt > 0: + # swap direction for internal features + use_direction = direction * -1 + wire_direction = _get_direction(w) + # Process wire + if wire_direction == use_direction: + # direction is correct + wires.append(w) + else: + # incorrect direction, so reverse wire + rw = _reverse_wire(w) + wires.append(rw) + offset -= self.cutOut + loop_cnt += 1 return wires # Eclass From dea85bc99907cdb9559aa350e724383e9efd4dd8 Mon Sep 17 00:00:00 2001 From: Russell Johnson <47639332+Russ4262@users.noreply.github.com> Date: Tue, 27 Oct 2020 15:52:28 -0500 Subject: [PATCH 2/6] Path: Some LGTM cleanup --- .../Path/PathScripts/PathSurfaceSupport.py | 24 ++++--------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/src/Mod/Path/PathScripts/PathSurfaceSupport.py b/src/Mod/Path/PathScripts/PathSurfaceSupport.py index 3ff57cf7db..ebee5b9acb 100644 --- a/src/Mod/Path/PathScripts/PathSurfaceSupport.py +++ b/src/Mod/Path/PathScripts/PathSurfaceSupport.py @@ -226,7 +226,6 @@ class PathGeometryGenerator: def _Line(self): GeoSet = list() centRot = FreeCAD.Vector(0.0, 0.0, 0.0) # Bottom left corner of face/selection/model - cAng = math.atan(self.deltaX / self.deltaY) # BoundaryBox angle # Create end points for set of lines to intersect with cross-section face pntTuples = list() @@ -474,7 +473,6 @@ class ProcessSelectedFaces: # Setup STL, model type, and bound box containers for each model in Job for m in range(0, len(JOB.Model.Group)): - M = JOB.Model.Group[m] self.modelSTLs.append(False) self.profileShapes.append(False) @@ -797,8 +795,6 @@ class ProcessSelectedFaces: PathLog.debug('Processing avoid faces.') cont = True isHole = False - outFCS = list() - intFEAT = list() outFCS, intFEAT = self.findUnifiedRegions(VDS) if self.obj.InternalFeaturesCut: @@ -1318,11 +1314,10 @@ def pathGeomToLinesPointSet(obj, compGeoShp, cutClimb, toolDiam, closedGap, gaps if chkGap is True: if gap < obj.GapThreshold.Value: - b = inLine.pop() # pop off 'BRK' marker + inLine.pop() # pop off 'BRK' marker (vA, vB) = inLine.pop() # pop off previous line segment for combining with current tup = (vA, tup[1]) closedGap = True - True if closedGap else False # used closedGap for LGTM else: gap = round(gap, 6) if gap < gaps[0]: @@ -1417,7 +1412,7 @@ def pathGeomToZigzagPointSet(obj, compGeoShp, cutClimb, toolDiam, closedGap, gap if chkGap: if gap < obj.GapThreshold.Value: - b = inLine.pop() # pop off 'BRK' marker + inLine.pop() # pop off 'BRK' marker (vA, vB) = inLine.pop() # pop off previous line segment for combining with current if dirFlg == 1: tup = (vA, tup[1]) @@ -1887,7 +1882,6 @@ class FindUnifiedRegions: def _groupEdgesByLength(self): PathLog.debug('_groupEdgesByLength()') - cont = True threshold = self.geomToler grp = list() processLast = False @@ -1909,7 +1903,6 @@ class FindUnifiedRegions: actvItem = DATA[actvIdx][0] # 0 index is length grp.append(actvIdx) idxCnt -= 1 - noMatch = True while idxCnt > 0: tstIdx = indexes[0] @@ -1922,7 +1915,6 @@ class FindUnifiedRegions: indexes.pop(0) idxCnt -= 1 grp.append(tstIdx) - noMatch = False else: if len(grp) > 1: # grp.sort() @@ -1939,7 +1931,6 @@ class FindUnifiedRegions: def _identifySharedEdgesByLength(self, grp): PathLog.debug('_identifySharedEdgesByLength()') holds = list() - cont = True specialIndexes = [] threshold = self.geomToler @@ -1949,7 +1940,6 @@ class FindUnifiedRegions: # Sort edgeData data self.edgeData.sort(key=keyFirst) DATA = self.edgeData - lenDATA = len(DATA) lenGrp = len(grp) while lenGrp > 0: @@ -2000,10 +1990,7 @@ class FindUnifiedRegions: PathLog.debug('_extractWiresFromEdges()') DATA = self.edgeData holds = list() - lastEdge = None - lastIdx = None firstEdge = None - isWire = False cont = True connectedEdges = [] connectedIndexes = [] @@ -2086,8 +2073,6 @@ class FindUnifiedRegions: # Put holds indexes back in search stack if notConnected: holds.append(actvIdx) - if idxCnt == 0: - lastLoop = True holds.extend(indexes) indexes = holds idxCnt = len(indexes) @@ -2101,7 +2086,6 @@ class FindUnifiedRegions: numLoops = len(LOOPS) PathLog.debug(' -numLoops: {}.'.format(numLoops)) if numLoops > 0: - FACES = list() for li in range(0, numLoops): Edges = LOOPS[li] #for e in Edges: @@ -2576,11 +2560,11 @@ class OCL_Tool(): # Engraver or V-bit cutter # OCL -> ConeCutter::ConeCutter(diameter, angle, length) if (self.diameter == -1.0 or - self.cutEdgeAngle == -1.0 or self.cutEdgeHeight == -1.0): + self.cuttingEdgeAngle == -1.0 or self.cutEdgeHeight == -1.0): return self.oclTool = self.ocl.ConeCutter( self.diameter, - self.cutEdgeAngle/2., + self.cuttingEdgeAngle, self.cutEdgeHeight + self.lengthOffset ) From 4c558f1a30a0d7b69e036dee57221e600379e14d Mon Sep 17 00:00:00 2001 From: Russell Johnson <47639332+Russ4262@users.noreply.github.com> Date: Tue, 27 Oct 2020 23:57:36 -0500 Subject: [PATCH 3/6] Path: Restructure code to fix `closedGap` LGTM issue --- src/Mod/Path/PathScripts/PathSurface.py | 13 ++- .../Path/PathScripts/PathSurfaceSupport.py | 104 +++++++++--------- src/Mod/Path/PathScripts/PathWaterline.py | 9 +- 3 files changed, 66 insertions(+), 60 deletions(-) diff --git a/src/Mod/Path/PathScripts/PathSurface.py b/src/Mod/Path/PathScripts/PathSurface.py index fdc76a717a..8f751d0d0e 100644 --- a/src/Mod/Path/PathScripts/PathSurface.py +++ b/src/Mod/Path/PathScripts/PathSurface.py @@ -496,8 +496,8 @@ class ObjectSurface(PathOp.ObjectOp): # set cut mode; reverse as needed if obj.CutMode == 'Climb': self.CutClimb = True - if obj.CutPatternReversed is True: - if self.CutClimb is True: + if obj.CutPatternReversed: + if self.CutClimb: self.CutClimb = False else: self.CutClimb = True @@ -919,9 +919,11 @@ class ObjectSurface(PathOp.ObjectOp): elif obj.CutPattern in ['Line', 'Spiral', 'ZigZag']: stpOvr = list() if obj.CutPattern == 'Line': - PNTSET = PathSurfaceSupport.pathGeomToLinesPointSet(obj, pathGeom, self.CutClimb, self.toolDiam, self.closedGap, self.gaps) + # PNTSET = PathSurfaceSupport.pathGeomToLinesPointSet(obj, pathGeom, self.CutClimb, self.toolDiam, self.closedGap, self.gaps) + PNTSET = PathSurfaceSupport.pathGeomToLinesPointSet(self, obj, pathGeom) elif obj.CutPattern == 'ZigZag': - PNTSET = PathSurfaceSupport.pathGeomToZigzagPointSet(obj, pathGeom, self.CutClimb, self.toolDiam, self.closedGap, self.gaps) + # PNTSET = PathSurfaceSupport.pathGeomToZigzagPointSet(obj, pathGeom, self.CutClimb, self.toolDiam, self.closedGap, self.gaps) + PNTSET = PathSurfaceSupport.pathGeomToZigzagPointSet(self, obj, pathGeom) elif obj.CutPattern == 'Spiral': PNTSET = PathSurfaceSupport.pathGeomToSpiralPointSet(obj, pathGeom) @@ -938,7 +940,8 @@ class ObjectSurface(PathOp.ObjectOp): elif obj.CutPattern in ['Circular', 'CircularZigZag']: # PNTSET is list, by stepover. # Each stepover is a list containing arc/loop descriptions, (sp, ep, cp) - PNTSET = PathSurfaceSupport.pathGeomToCircularPointSet(obj, pathGeom, self.CutClimb, self.toolDiam, self.closedGap, self.gaps, self.tmpCOM) + # PNTSET = PathSurfaceSupport.pathGeomToCircularPointSet(obj, pathGeom, self.CutClimb, self.toolDiam, self.closedGap, self.gaps, self.tmpCOM) + PNTSET = PathSurfaceSupport.pathGeomToCircularPointSet(self, obj, pathGeom) for so in range(0, len(PNTSET)): stpOvr = list() diff --git a/src/Mod/Path/PathScripts/PathSurfaceSupport.py b/src/Mod/Path/PathScripts/PathSurfaceSupport.py index ebee5b9acb..3ba5c2078d 100644 --- a/src/Mod/Path/PathScripts/PathSurfaceSupport.py +++ b/src/Mod/Path/PathScripts/PathSurfaceSupport.py @@ -1253,8 +1253,8 @@ def _makeSTL(model, obj, ocl, model_type=None): # Functions to convert path geometry into line/arc segments for OCL input or directly to g-code -def pathGeomToLinesPointSet(obj, compGeoShp, cutClimb, toolDiam, closedGap, gaps): - '''pathGeomToLinesPointSet(obj, compGeoShp)... +def pathGeomToLinesPointSet(self, obj, compGeoShp): + '''pathGeomToLinesPointSet(self, obj, compGeoShp)... Convert a compound set of sequential line segments to directionally-oriented collinear groupings.''' PathLog.debug('pathGeomToLinesPointSet()') # Extract intersection line segments for return value as list() @@ -1268,7 +1268,7 @@ def pathGeomToLinesPointSet(obj, compGeoShp, cutClimb, toolDiam, closedGap, gaps edg0 = compGeoShp.Edges[0] p1 = (edg0.Vertexes[0].X, edg0.Vertexes[0].Y) p2 = (edg0.Vertexes[1].X, edg0.Vertexes[1].Y) - if cutClimb is True: + if self.CutClimb is True: tup = (p2, p1) lst = FreeCAD.Vector(p1[0], p1[1], 0.0) else: @@ -1291,43 +1291,43 @@ def pathGeomToLinesPointSet(obj, compGeoShp, cutClimb, toolDiam, closedGap, gaps inLine.append('BRK') chkGap = True else: - if cutClimb is True: + if self.CutClimb is True: inLine.reverse() LINES.append(inLine) # Save inLine segments lnCnt += 1 inLine = list() # reset collinear container - if cutClimb is True: + if self.CutClimb is True: sp = cp # FreeCAD.Vector(v1[0], v1[1], 0.0) else: sp = ep - if cutClimb is True: + if self.CutClimb is True: tup = (v2, v1) - if chkGap is True: - gap = abs(toolDiam - lst.sub(ep).Length) + if chkGap: + gap = abs(self.toolDiam - lst.sub(ep).Length) lst = cp else: tup = (v1, v2) - if chkGap is True: - gap = abs(toolDiam - lst.sub(cp).Length) + if chkGap: + gap = abs(self.toolDiam - lst.sub(cp).Length) lst = ep - if chkGap is True: + if chkGap: if gap < obj.GapThreshold.Value: inLine.pop() # pop off 'BRK' marker (vA, vB) = inLine.pop() # pop off previous line segment for combining with current tup = (vA, tup[1]) - closedGap = True + self.closedGap = True else: gap = round(gap, 6) - if gap < gaps[0]: - gaps.insert(0, gap) - gaps.pop() + if gap < self.gaps[0]: + self.gaps.insert(0, gap) + self.gaps.pop() inLine.append(tup) # Efor lnCnt += 1 - if cutClimb is True: + if self.CutClimb is True: inLine.reverse() LINES.append(inLine) # Save inLine segments @@ -1353,8 +1353,8 @@ def pathGeomToLinesPointSet(obj, compGeoShp, cutClimb, toolDiam, closedGap, gaps return LINES -def pathGeomToZigzagPointSet(obj, compGeoShp, cutClimb, toolDiam, closedGap, gaps): - '''_pathGeomToZigzagPointSet(obj, compGeoShp)... +def pathGeomToZigzagPointSet(self, obj, compGeoShp): + '''_pathGeomToZigzagPointSet(self, obj, compGeoShp)... Convert a compound set of sequential line segments to directionally-oriented collinear groupings with a ZigZag directional indicator included for each collinear group.''' PathLog.debug('_pathGeomToZigzagPointSet()') @@ -1366,7 +1366,7 @@ def pathGeomToZigzagPointSet(obj, compGeoShp, cutClimb, toolDiam, closedGap, gap ec = len(compGeoShp.Edges) dirFlg = 1 - if cutClimb: + if self.CutClimb: dirFlg = -1 edg0 = compGeoShp.Edges[0] @@ -1393,7 +1393,7 @@ def pathGeomToZigzagPointSet(obj, compGeoShp, cutClimb, toolDiam, closedGap, gap if iC: inLine.append('BRK') chkGap = True - gap = abs(toolDiam - lst.sub(cp).Length) + gap = abs(self.toolDiam - lst.sub(cp).Length) else: chkGap = False if dirFlg == -1: @@ -1418,12 +1418,12 @@ def pathGeomToZigzagPointSet(obj, compGeoShp, cutClimb, toolDiam, closedGap, gap tup = (vA, tup[1]) else: tup = (tup[0], vB) - closedGap = True + self.closedGap = True else: gap = round(gap, 6) - if gap < gaps[0]: - gaps.insert(0, gap) - gaps.pop() + if gap < self.gaps[0]: + self.gaps.insert(0, gap) + self.gaps.pop() inLine.append(tup) # Efor lnCnt += 1 @@ -1436,7 +1436,7 @@ def pathGeomToZigzagPointSet(obj, compGeoShp, cutClimb, toolDiam, closedGap, gap PathLog.debug('Line count is ODD: {}.'.format(lnCnt)) dirFlg = -1 * dirFlg if not obj.CutPatternReversed: - if cutClimb: + if self.CutClimb: dirFlg = -1 * dirFlg if obj.CutPatternReversed: @@ -1470,8 +1470,8 @@ def pathGeomToZigzagPointSet(obj, compGeoShp, cutClimb, toolDiam, closedGap, gap return LINES -def pathGeomToCircularPointSet(obj, compGeoShp, cutClimb, toolDiam, closedGap, gaps, COM): - '''pathGeomToCircularPointSet(obj, compGeoShp)... +def pathGeomToCircularPointSet(self, obj, compGeoShp): + '''pathGeomToCircularPointSet(self, obj, compGeoShp)... Convert a compound set of arcs/circles to a set of directionally-oriented arc end points and the corresponding center point.''' # Extract intersection line segments for return value as list() @@ -1498,11 +1498,11 @@ def pathGeomToCircularPointSet(obj, compGeoShp, cutClimb, toolDiam, closedGap, g segEI.append(ei) isSame = True pnt = FreeCAD.Vector(edg.Vertexes[0].X, edg.Vertexes[0].Y, 0.0) - sameRad = pnt.sub(COM).Length + sameRad = pnt.sub(self.tmpCOM).Length else: # Check if arc is co-radial to current SEGS pnt = FreeCAD.Vector(edg.Vertexes[0].X, edg.Vertexes[0].Y, 0.0) - if abs(sameRad - pnt.sub(COM).Length) > 0.00001: + if abs(sameRad - pnt.sub(self.tmpCOM).Length) > 0.00001: isSame = False if isSame is True: @@ -1514,7 +1514,7 @@ def pathGeomToCircularPointSet(obj, compGeoShp, cutClimb, toolDiam, closedGap, g segEI = [ei] isSame = True pnt = FreeCAD.Vector(edg.Vertexes[0].X, edg.Vertexes[0].Y, 0.0) - sameRad = pnt.sub(COM).Length + sameRad = pnt.sub(self.tmpCOM).Length # Process trailing `segEI` data, if available if isSame is True: stpOvrEI.append(['A', segEI, False]) @@ -1531,9 +1531,9 @@ def pathGeomToCircularPointSet(obj, compGeoShp, cutClimb, toolDiam, closedGap, g for i in range(0, len(EI)): ei = EI[i] # edge index E = compGeoShp.Edges[ei] # edge object - if abs(COM.y - E.Vertexes[0].Y) < 0.00001: + if abs(self.tmpCOM.y - E.Vertexes[0].Y) < 0.00001: startOnAxis.append((i, ei, E.Vertexes[0])) - elif abs(COM.y - E.Vertexes[1].Y) < 0.00001: + elif abs(self.tmpCOM.y - E.Vertexes[1].Y) < 0.00001: endOnAxis.append((i, ei, E.Vertexes[1])) # Look for connections between startOnAxis and endOnAxis arcs. Consolidate data when connected @@ -1556,7 +1556,7 @@ def pathGeomToCircularPointSet(obj, compGeoShp, cutClimb, toolDiam, closedGap, g # Construct arc data tuples for OCL dirFlg = 1 - if not cutClimb: # True yields Climb when set to Conventional + if not self.CutClimb: # True yields Climb when set to Conventional dirFlg = -1 # Cycle through stepOver data @@ -1569,28 +1569,28 @@ def pathGeomToCircularPointSet(obj, compGeoShp, cutClimb, toolDiam, closedGap, g # space = obj.SampleInterval.Value / 10.0 # space = 0.000001 - space = toolDiam * 0.005 # If too small, OCL will fail to scan the loop + space = self.toolDiam * 0.005 # If too small, OCL will fail to scan the loop # p1 = FreeCAD.Vector(v1.X, v1.Y, v1.Z) p1 = FreeCAD.Vector(v1.X, v1.Y, 0.0) # z=0.0 for waterline; z=v1.Z for 3D Surface - rad = p1.sub(COM).Length + rad = p1.sub(self.tmpCOM).Length spcRadRatio = space/rad if spcRadRatio < 1.0: tolrncAng = math.asin(spcRadRatio) else: tolrncAng = 0.99999998 * math.pi - EX = COM.x + (rad * math.cos(tolrncAng)) + EX = self.tmpCOM.x + (rad * math.cos(tolrncAng)) EY = v1.Y - space # rad * math.sin(tolrncAng) sp = (v1.X, v1.Y, 0.0) ep = (EX, EY, 0.0) - cp = (COM.x, COM.y, 0.0) + cp = (self.tmpCOM.x, self.tmpCOM.y, 0.0) if dirFlg == 1: arc = (sp, ep, cp) else: arc = (ep, sp, cp) # OCL.Arc(firstPnt, lastPnt, centerPnt, dir=True(CCW direction)) ARCS.append(('L', dirFlg, [arc])) - else: # SO[0] == 'A' A = Arc + elif SO[0] == 'A': # A = Arc # PathLog.debug("SO[0] == 'Arc'") PRTS = list() EI = SO[1] # list of corresponding Edges indexes @@ -1598,13 +1598,13 @@ def pathGeomToCircularPointSet(obj, compGeoShp, cutClimb, toolDiam, closedGap, g chkGap = False lst = None - if CONN: + if CONN: # Connected edges(arcs) (iE, iS) = CONN v1 = compGeoShp.Edges[iE].Vertexes[0] v2 = compGeoShp.Edges[iS].Vertexes[1] sp = (v1.X, v1.Y, 0.0) ep = (v2.X, v2.Y, 0.0) - cp = (COM.x, COM.y, 0.0) + cp = (self.tmpCOM.x, self.tmpCOM.y, 0.0) if dirFlg == 1: arc = (sp, ep, cp) lst = ep @@ -1623,38 +1623,38 @@ def pathGeomToCircularPointSet(obj, compGeoShp, cutClimb, toolDiam, closedGap, g EI.pop(iEi) if len(EI) > 0: PRTS.append('BRK') - chkGap = True + # chkGap = True cnt = 0 for ei in EI: if cnt > 0: PRTS.append('BRK') - chkGap = True + # chkGap = True v1 = compGeoShp.Edges[ei].Vertexes[0] v2 = compGeoShp.Edges[ei].Vertexes[1] sp = (v1.X, v1.Y, 0.0) ep = (v2.X, v2.Y, 0.0) - cp = (COM.x, COM.y, 0.0) + cp = (self.tmpCOM.x, self.tmpCOM.y, 0.0) if dirFlg == 1: arc = (sp, ep, cp) - if chkGap is True: - gap = abs(toolDiam - gapDist(lst, sp)) # abs(toolDiam - lst.sub(sp).Length) + if chkGap and False: + gap = abs(self.toolDiam - gapDist(lst, sp)) # abs(self.toolDiam - lst.sub(sp).Length) lst = ep else: arc = (ep, sp, cp) # OCL.Arc(firstPnt, lastPnt, centerPnt, dir=True(CCW direction)) - if chkGap is True: - gap = abs(toolDiam - gapDist(lst, ep)) # abs(toolDiam - lst.sub(ep).Length) + if chkGap and False: + gap = abs(self.toolDiam - gapDist(lst, ep)) # abs(self.toolDiam - lst.sub(ep).Length) lst = sp - if chkGap is True: + if chkGap and False: if gap < obj.GapThreshold.Value: PRTS.pop() # pop off 'BRK' marker (vA, vB, vC) = PRTS.pop() # pop off previous arc segment for combining with current arc = (vA, arc[1], vC) - closedGap = True + self.closedGap = True else: gap = round(gap, 6) - if gap < gaps[0]: - gaps.insert(0, gap) - gaps.pop() + if gap < self.gaps[0]: + self.gaps.insert(0, gap) + self.gaps.pop() PRTS.append(arc) cnt += 1 diff --git a/src/Mod/Path/PathScripts/PathWaterline.py b/src/Mod/Path/PathScripts/PathWaterline.py index a314f70893..34d1abffb8 100644 --- a/src/Mod/Path/PathScripts/PathWaterline.py +++ b/src/Mod/Path/PathScripts/PathWaterline.py @@ -1441,11 +1441,14 @@ class ObjectWaterline(PathOp.ObjectOp): self.showDebugObject(pathGeom, 'PathGeom_{}'.format(round(csHght, 2))) if cutPattern == 'Line': - pntSet = PathSurfaceSupport.pathGeomToLinesPointSet(obj, pathGeom, self.CutClimb, self.toolDiam, self.closedGap, self.gaps) + # pntSet = PathSurfaceSupport.pathGeomToLinesPointSet(obj, pathGeom, self.CutClimb, self.toolDiam, self.closedGap, self.gaps) + pntSet = PathSurfaceSupport.pathGeomToLinesPointSet(self, obj, pathGeom) elif cutPattern == 'ZigZag': - pntSet = PathSurfaceSupport.pathGeomToZigzagPointSet(obj, pathGeom, self.CutClimb, self.toolDiam, self.closedGap, self.gaps) + # pntSet = PathSurfaceSupport.pathGeomToZigzagPointSet(obj, pathGeom, self.CutClimb, self.toolDiam, self.closedGap, self.gaps) + pntSet = PathSurfaceSupport.pathGeomToZigzagPointSet(self, obj, pathGeom) elif cutPattern in ['Circular', 'CircularZigZag']: - pntSet = PathSurfaceSupport.pathGeomToCircularPointSet(obj, pathGeom, self.CutClimb, self.toolDiam, self.closedGap, self.gaps, self.tmpCOM) + # pntSet = PathSurfaceSupport.pathGeomToCircularPointSet(obj, pathGeom, self.CutClimb, self.toolDiam, self.closedGap, self.gaps, self.tmpCOM) + pntSet = PathSurfaceSupport.pathGeomToCircularPointSet(self, obj, pathGeom) elif cutPattern == 'Spiral': pntSet = PathSurfaceSupport.pathGeomToSpiralPointSet(obj, pathGeom) From 220bf0e3968dd16be8925230d3bf4a68bb44513e Mon Sep 17 00:00:00 2001 From: Russell Johnson <47639332+Russ4262@users.noreply.github.com> Date: Tue, 27 Oct 2020 23:59:25 -0500 Subject: [PATCH 4/6] Path: Fix cut direction when `CutPatternReversed` is true for `Circular` --- src/Mod/Path/PathScripts/PathSurfaceSupport.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Mod/Path/PathScripts/PathSurfaceSupport.py b/src/Mod/Path/PathScripts/PathSurfaceSupport.py index 3ba5c2078d..50964cdabc 100644 --- a/src/Mod/Path/PathScripts/PathSurfaceSupport.py +++ b/src/Mod/Path/PathScripts/PathSurfaceSupport.py @@ -1488,6 +1488,12 @@ def pathGeomToCircularPointSet(self, obj, compGeoShp): Y = (ep[1] - sp[1])**2 return math.sqrt(X + Y) # the 'z' value is zero in both points + if obj.CutPatternReversed: + if self.CutClimb: + self.CutClimb = False + else: + self.CutClimb = True + # Separate arc data into Loops and Arcs for ei in range(0, ec): edg = compGeoShp.Edges[ei] From b94cbb617edad3e3519e2b75cf802ce8604d784c Mon Sep 17 00:00:00 2001 From: Russell Johnson <47639332+Russ4262@users.noreply.github.com> Date: Wed, 28 Oct 2020 13:09:02 -0500 Subject: [PATCH 5/6] Path: Fix unsorted arc order for circular cut pattern in some cases --- .../Path/PathScripts/PathSurfaceSupport.py | 28 +++++++++++++------ 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/src/Mod/Path/PathScripts/PathSurfaceSupport.py b/src/Mod/Path/PathScripts/PathSurfaceSupport.py index 50964cdabc..6eae4328eb 100644 --- a/src/Mod/Path/PathScripts/PathSurfaceSupport.py +++ b/src/Mod/Path/PathScripts/PathSurfaceSupport.py @@ -1488,6 +1488,16 @@ def pathGeomToCircularPointSet(self, obj, compGeoShp): Y = (ep[1] - sp[1])**2 return math.sqrt(X + Y) # the 'z' value is zero in both points + def dist_to_cent(item): + # Sort incoming arcs by distance to center + # item: edge type, direction flag, parts tuple + # parts: start tuple, end tuple, center tuple + s = item[2][0][0] + p1 = FreeCAD.Vector(s[0], s[1], 0.0) + e = item[2][0][2] + p2 = FreeCAD.Vector(e[0], e[1], 0.0) + return p1.sub(p2).Length + if obj.CutPatternReversed: if self.CutClimb: self.CutClimb = False @@ -1565,6 +1575,9 @@ def pathGeomToCircularPointSet(self, obj, compGeoShp): if not self.CutClimb: # True yields Climb when set to Conventional dirFlg = -1 + # Declare center point of circle pattern + cp = (self.tmpCOM.x, self.tmpCOM.y, 0.0) + # Cycle through stepOver data for so in range(0, len(stpOvrEI)): SO = stpOvrEI[so] @@ -1590,7 +1603,6 @@ def pathGeomToCircularPointSet(self, obj, compGeoShp): sp = (v1.X, v1.Y, 0.0) ep = (EX, EY, 0.0) - cp = (self.tmpCOM.x, self.tmpCOM.y, 0.0) if dirFlg == 1: arc = (sp, ep, cp) else: @@ -1610,7 +1622,6 @@ def pathGeomToCircularPointSet(self, obj, compGeoShp): v2 = compGeoShp.Edges[iS].Vertexes[1] sp = (v1.X, v1.Y, 0.0) ep = (v2.X, v2.Y, 0.0) - cp = (self.tmpCOM.x, self.tmpCOM.y, 0.0) if dirFlg == 1: arc = (sp, ep, cp) lst = ep @@ -1629,28 +1640,27 @@ def pathGeomToCircularPointSet(self, obj, compGeoShp): EI.pop(iEi) if len(EI) > 0: PRTS.append('BRK') - # chkGap = True + chkGap = True cnt = 0 for ei in EI: if cnt > 0: PRTS.append('BRK') - # chkGap = True + chkGap = True v1 = compGeoShp.Edges[ei].Vertexes[0] v2 = compGeoShp.Edges[ei].Vertexes[1] sp = (v1.X, v1.Y, 0.0) ep = (v2.X, v2.Y, 0.0) - cp = (self.tmpCOM.x, self.tmpCOM.y, 0.0) if dirFlg == 1: arc = (sp, ep, cp) - if chkGap and False: + if chkGap: gap = abs(self.toolDiam - gapDist(lst, sp)) # abs(self.toolDiam - lst.sub(sp).Length) lst = ep else: arc = (ep, sp, cp) # OCL.Arc(firstPnt, lastPnt, centerPnt, dir=True(CCW direction)) - if chkGap and False: + if chkGap: gap = abs(self.toolDiam - gapDist(lst, ep)) # abs(self.toolDiam - lst.sub(ep).Length) lst = sp - if chkGap and False: + if chkGap: if gap < obj.GapThreshold.Value: PRTS.pop() # pop off 'BRK' marker (vA, vB, vC) = PRTS.pop() # pop off previous arc segment for combining with current @@ -1673,6 +1683,8 @@ def pathGeomToCircularPointSet(self, obj, compGeoShp): dirFlg = -1 * dirFlg # Efor + ARCS.sort(key=dist_to_cent, reverse=obj.CutPatternReversed) + return ARCS def pathGeomToSpiralPointSet(obj, compGeoShp): From 70473ab422c9f600336af0471b63e6f197ce34de Mon Sep 17 00:00:00 2001 From: Russell Johnson <47639332+Russ4262@users.noreply.github.com> Date: Fri, 6 Nov 2020 17:05:30 -0600 Subject: [PATCH 6/6] Path: Fix missing variable declaration for rotational scan Missing default logical choice within `if...:` block. Reported in forum at https://forum.freecadweb.org/viewtopic.php?style=3&f=15&t=44473&start=60#p412303 --- src/Mod/Path/PathScripts/PathSurface.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Mod/Path/PathScripts/PathSurface.py b/src/Mod/Path/PathScripts/PathSurface.py index 8f751d0d0e..015fdbb579 100644 --- a/src/Mod/Path/PathScripts/PathSurface.py +++ b/src/Mod/Path/PathScripts/PathSurface.py @@ -1806,6 +1806,9 @@ class ObjectSurface(PathOp.ObjectOp): lo = ocl.Line(p2, p1) else: lo = ocl.Line(p1, p2) + else: + # default to line-object + lo = ocl.Line(p1, p2) else: lo = ocl.Line(p1, p2) # line-object