From 61d578bb6163419fa28bdf81142705f8a660ffc5 Mon Sep 17 00:00:00 2001 From: Patrick Felixberger Date: Mon, 16 Mar 2020 18:30:30 +0100 Subject: [PATCH] Code clean up --- src/Mod/Path/PathScripts/PathAreaOp.py | 1 + src/Mod/Path/PathScripts/PathDrilling.py | 6 ++-- src/Mod/Path/PathScripts/PathPocketBase.py | 1 + src/Mod/Path/PathScripts/PathPocketShape.py | 37 +++++++++++++++++++- src/Mod/Path/PathScripts/PathProfileBase.py | 3 ++ src/Mod/Path/PathScripts/PathProfileFaces.py | 12 +++++++ 6 files changed, 57 insertions(+), 3 deletions(-) diff --git a/src/Mod/Path/PathScripts/PathAreaOp.py b/src/Mod/Path/PathScripts/PathAreaOp.py index 0ff68a1dd0..b63d7f5974 100644 --- a/src/Mod/Path/PathScripts/PathAreaOp.py +++ b/src/Mod/Path/PathScripts/PathAreaOp.py @@ -3,6 +3,7 @@ # *************************************************************************** # * * # * Copyright (c) 2017 sliptonic * +# * Copyright (c) 2020 russ4262 (Russell Johnson) * # * * # * This program is free software; you can redistribute it and/or modify * # * it under the terms of the GNU Lesser General Public License (LGPL) * diff --git a/src/Mod/Path/PathScripts/PathDrilling.py b/src/Mod/Path/PathScripts/PathDrilling.py index f3d6e4d8fb..7d1a9dddda 100644 --- a/src/Mod/Path/PathScripts/PathDrilling.py +++ b/src/Mod/Path/PathScripts/PathDrilling.py @@ -3,6 +3,8 @@ # *************************************************************************** # * * # * Copyright (c) 2014 Yorik van Havre * +# * Copyright (c) 2020 russ4262 (Russell Johnson) * +# * Copyright (c) 2020 Schildkroet * # * * # * This program is free software; you can redistribute it and/or modify * # * it under the terms of the GNU Lesser General Public License (LGPL) * @@ -43,8 +45,6 @@ __title__ = "Path Drilling Operation" __author__ = "sliptonic (Brad Collette)" __url__ = "http://www.freecadweb.org" __doc__ = "Path Drilling operation." -__contributors__ = "russ4262 (Russell Johnson), IMBack!" -__created__ = "2014" PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) # PathLog.trackModule(PathLog.thisModule()) @@ -221,7 +221,9 @@ def Create(name, obj=None): '''Create(name) ... Creates and returns a Drilling operation.''' if obj is None: obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", name) + obj.Proxy = ObjectDrilling(obj, name) if obj.Proxy: obj.Proxy.findAllHoles(obj) + return obj diff --git a/src/Mod/Path/PathScripts/PathPocketBase.py b/src/Mod/Path/PathScripts/PathPocketBase.py index 211f8ebe9f..ba3582f6b8 100644 --- a/src/Mod/Path/PathScripts/PathPocketBase.py +++ b/src/Mod/Path/PathScripts/PathPocketBase.py @@ -3,6 +3,7 @@ # *************************************************************************** # * * # * Copyright (c) 2017 sliptonic * +# * Copyright (c) 2020 russ4262 (Russell Johnson) * # * * # * This program is free software; you can redistribute it and/or modify * # * it under the terms of the GNU Lesser General Public License (LGPL) * diff --git a/src/Mod/Path/PathScripts/PathPocketShape.py b/src/Mod/Path/PathScripts/PathPocketShape.py index 419ac921d0..16fb8035dc 100644 --- a/src/Mod/Path/PathScripts/PathPocketShape.py +++ b/src/Mod/Path/PathScripts/PathPocketShape.py @@ -3,6 +3,7 @@ # *************************************************************************** # * * # * Copyright (c) 2017 sliptonic * +# * Copyright (c) 2020 russ4262 (Russell Johnson) * # * Copyright (c) 2020 Schildkroet * # * * # * This program is free software; you can redistribute it and/or modify * @@ -41,7 +42,7 @@ __author__ = "sliptonic (Brad Collette)" __url__ = "http://www.freecadweb.org" __doc__ = "Class and implementation of shape based Pocket operation." -PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) +PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule()) # PathLog.trackModule(PathLog.thisModule()) @@ -61,11 +62,14 @@ def endPoints(edgeOrWire): cnt = len([p2 for p2 in pts if PathGeom.pointsCoincide(p, p2)]) if 1 == cnt: unique.append(p) + return unique + pfirst = edgeOrWire.valueAt(edgeOrWire.FirstParameter) plast = edgeOrWire.valueAt(edgeOrWire.LastParameter) if PathGeom.pointsCoincide(pfirst, plast): return None + return [pfirst, plast] @@ -74,6 +78,7 @@ def includesPoint(p, pts): for pt in pts: if PathGeom.pointsCoincide(p, pt): return True + return False @@ -84,8 +89,10 @@ def selectOffsetWire(feature, wires): dist = feature.distToShape(w)[0] if closest is None or dist > closest[0]: # pylint: disable=unsubscriptable-object closest = (dist, w) + if closest is not None: return closest[1] + return None @@ -112,6 +119,7 @@ def extendWire(feature, wire, length): edges.append(Part.Edge(Part.LineSegment(endPts[1], ePts[0]))) edges.extend(offset.Edges) edges.append(Part.Edge(Part.LineSegment(endPts[0], ePts[1]))) + return Part.Wire(edges) return None @@ -146,6 +154,7 @@ class Extension(object): wire = Part.Wire([e0, e1, e2, e3]) self.wire = wire return wire + return extendWire(feature, Part.Wire([e0]), self.length.Value) def _getEdgeNumbers(self): @@ -153,6 +162,7 @@ class Extension(object): numbers = [nr for nr in self.sub[5:-1].split(',')] else: numbers = [self.sub[4:]] + PathLog.debug("_getEdgeNumbers() -> %s" % numbers) return numbers @@ -167,8 +177,10 @@ class Extension(object): poffMinus = p0 - 0.01 * normal if not self.obj.Shape.isInside(poffPlus, 0.005, True): return normal + if not self.obj.Shape.isInside(poffMinus, 0.005, True): return normal.negative() + return None def _getDirection(self, wire): @@ -179,6 +191,7 @@ class Extension(object): normal = tangent.cross(FreeCAD.Vector(0, 0, 1)) if PathGeom.pointsCoincide(normal, FreeCAD.Vector(0, 0, 0)): return None + return self._getDirectedNormal(e0.valueAt(midparam), normal.normalize()) def getWire(self): @@ -207,6 +220,7 @@ class Extension(object): r = circle.Radius - self.length.Value else: r = circle.Radius + self.length.Value + # assuming the offset produces a valid circle - go for it if r > 0: e3 = Part.makeCircle(r, circle.Center, circle.Axis, edge.FirstParameter * 180 / math.pi, edge.LastParameter * 180 / math.pi) @@ -215,7 +229,9 @@ class Extension(object): e0 = Part.makeLine(edge.valueAt(edge.FirstParameter), e3.valueAt(e3.FirstParameter)) e2 = Part.makeLine(edge.valueAt(edge.LastParameter), e3.valueAt(e3.LastParameter)) return Part.Wire([e0, edge, e2, e3]) + return Part.Wire([e3]) + # the extension is bigger than the hole - so let's just cover the whole hole if endPoints(edge): # if the resulting arc is smaller than the radius, create a pie slice @@ -224,6 +240,7 @@ class Extension(object): e0 = Part.makeLine(center, edge.valueAt(edge.FirstParameter)) e2 = Part.makeLine(edge.valueAt(edge.LastParameter), center) return Part.Wire([e0, edge, e2]) + PathLog.track() return Part.Wire([edge]) @@ -232,8 +249,10 @@ class Extension(object): direction = self._getDirection(sub) if direction is None: return None + # return self._extendEdge(feature, edge, direction) return self._extendEdge(feature, edges[0], direction) + return extendWire(feature, sub, self.length.Value) @@ -315,6 +334,7 @@ class ObjectPocket(PathPocketBase.ObjectPocket): PathLog.debug(' -e.isClosed()') clsd.append(edg) planar = True + # Attempt to create planar faces and select that with smallest area for use as pocket base if planar is True: planar = False @@ -328,11 +348,14 @@ class ObjectPocket(PathPocketBase.ObjectPocket): else: if trans is True: mFF.translate(FreeCAD.Vector(0, 0, face.BoundBox.ZMin - mFF.BoundBox.ZMin)) + if FreeCAD.ActiveDocument.getObject(fName): FreeCAD.ActiveDocument.removeObject(fName) + tmpFace = FreeCAD.ActiveDocument.addObject('Part::Feature', fName).Shape = mFF tmpFace = FreeCAD.ActiveDocument.getObject(fName) tmpFace.purgeTouched() + if minArea == 0.0: minArea = tmpFace.Shape.Face1.Area useFace = fName @@ -343,8 +366,10 @@ class ObjectPocket(PathPocketBase.ObjectPocket): useFace = fName else: FreeCAD.ActiveDocument.removeObject(fName) + if useFace != 'useFaceName': self.useTempJobClones(useFace) + return (planar, useFace) def clasifySub(self, bs, sub): @@ -357,12 +382,15 @@ class ObjectPocket(PathPocketBase.ObjectPocket): # it's a flat horizontal face self.horiz.append(face) return True + elif PathGeom.isHorizontal(face.Surface.Axis): PathLog.debug(' -isHorizontal()') self.vert.append(face) return True + else: return False + elif type(face.Surface) == Part.Cylinder and PathGeom.isVertical(face.Surface.Axis): PathLog.debug('type() == Part.Cylinder') # vertical cylinder wall @@ -374,11 +402,13 @@ class ObjectPocket(PathPocketBase.ObjectPocket): disk.translate(FreeCAD.Vector(0, 0, face.BoundBox.ZMin - disk.BoundBox.ZMin)) self.horiz.append(disk) return True + else: PathLog.debug(' -none isClosed()') # partial cylinder wall self.vert.append(face) return True + elif type(face.Surface) == Part.SurfaceOfExtrusion: # extrusion wall PathLog.debug('type() == Part.SurfaceOfExtrusion') @@ -397,6 +427,7 @@ class ObjectPocket(PathPocketBase.ObjectPocket): # self.guiMessage(title, msg, False) else: PathLog.error(translate("Path", "Failed to create a planar face from edges in {}.".format(sub))) + else: PathLog.debug(' -type(face.Surface): {}'.format(type(face.Surface))) return False @@ -417,6 +448,7 @@ class ObjectPocket(PathPocketBase.ObjectPocket): # First, check all subs collectively for loop of faces if len(subsList) > 2: (isLoop, norm, surf) = self.checkForFacesLoop(base, subsList) + if isLoop is True: PathLog.info("Common Surface.Axis or normalAt() value found for loop faces.") rtn = False @@ -459,6 +491,7 @@ class ObjectPocket(PathPocketBase.ObjectPocket): stock = PathUtils.findParentJob(obj).Stock tup = base, subsList, angle, axis, stock # Eif + allTuples.append(tup) baseSubsTuples.append(tup) # Eif @@ -612,6 +645,7 @@ class ObjectPocket(PathPocketBase.ObjectPocket): shpZMin = -1 * shpZMin else: face.translate(FreeCAD.Vector(0.0, 0.0, -1 * clrnc)) + if obj.LimitDepthToFace is True and obj.EnableRotation != 'Off': if shpZMin > obj.FinalDepth.Value: afD = shpZMin @@ -620,6 +654,7 @@ class ObjectPocket(PathPocketBase.ObjectPocket): sD = afD + 1.0 else: face.translate(FreeCAD.Vector(0, 0, obj.FinalDepth.Value - shpZMin)) + extent = FreeCAD.Vector(0, 0, sD - afD + clrnc) extShp = face.removeSplitter().extrude(extent) self.removalshapes.append((extShp, False, 'pathPocketShape', useAngle, axis, sD, afD)) diff --git a/src/Mod/Path/PathScripts/PathProfileBase.py b/src/Mod/Path/PathScripts/PathProfileBase.py index e12a94aa30..07d7cb793d 100644 --- a/src/Mod/Path/PathScripts/PathProfileBase.py +++ b/src/Mod/Path/PathScripts/PathProfileBase.py @@ -4,6 +4,7 @@ # * * # * Copyright (c) 2017 sliptonic * # * Copyright (c) 2020 Schildkroet * +# * Copyright (c) 2020 russ4262 (Russell Johnson) * # * * # * This program is free software; you can redistribute it and/or modify * # * it under the terms of the GNU Lesser General Public License (LGPL) * @@ -91,6 +92,7 @@ class ObjectProfile(PathAreaOp.ObjectOp): def areaOpOnDocumentRestored(self, obj): for prop in ['UseComp', 'JoinType']: self.areaOpOnChanged(obj, prop) + self.setOpEditorProperties(obj) def areaOpAreaParams(self, obj, isHole): @@ -133,6 +135,7 @@ class ObjectProfile(PathAreaOp.ObjectOp): params['orientation'] = 0 else: params['orientation'] = 1 + if not obj.UseComp: if direction == 'CCW': params['orientation'] = 1 diff --git a/src/Mod/Path/PathScripts/PathProfileFaces.py b/src/Mod/Path/PathScripts/PathProfileFaces.py index 371c56eee4..ee57887332 100644 --- a/src/Mod/Path/PathScripts/PathProfileFaces.py +++ b/src/Mod/Path/PathScripts/PathProfileFaces.py @@ -3,6 +3,7 @@ # *************************************************************************** # * * # * Copyright (c) 2014 Yorik van Havre * +# * Copyright (c) 2020 russ4262 (Russell Johnson) * # * Copyright (c) 2020 Schildkroet * # * * # * This program is free software; you can redistribute it and/or modify * @@ -70,6 +71,7 @@ class ObjectProfile(PathProfileBase.ObjectProfile): if not hasattr(obj, 'HandleMultipleFeatures'): obj.addProperty('App::PropertyEnumeration', 'HandleMultipleFeatures', 'Profile', QtCore.QT_TRANSLATE_NOOP('PathPocket', 'Choose how to process multiple Base Geometry features.')) + obj.HandleMultipleFeatures = ['Collectively', 'Individually'] self.initRotationOp(obj) @@ -156,17 +158,21 @@ class ObjectProfile(PathProfileBase.ObjectProfile): 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 @@ -191,6 +197,7 @@ class ObjectProfile(PathProfileBase.ObjectProfile): 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: @@ -205,6 +212,7 @@ class ObjectProfile(PathProfileBase.ObjectProfile): 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) @@ -235,6 +243,7 @@ class ObjectProfile(PathProfileBase.ObjectProfile): else: tup = env, False, 'pathProfileFaces', angle, axis, strDep, finDep shapes.append(tup) + elif obj.HandleMultipleFeatures == 'Individually': for shape in faces: profShape = Part.makeCompound([shape]) @@ -245,6 +254,7 @@ class ObjectProfile(PathProfileBase.ObjectProfile): # 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) @@ -253,6 +263,7 @@ class ObjectProfile(PathProfileBase.ObjectProfile): 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"): @@ -311,5 +322,6 @@ def Create(name, obj=None): '''Create(name) ... Creates and returns a Profile based on faces operation.''' if obj is None: obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", name) + obj.Proxy = ObjectProfile(obj, name) return obj