From 96422713359121506ce929efcb7618f3d42d669e Mon Sep 17 00:00:00 2001 From: Russell Johnson <47639332+Russ4262@users.noreply.github.com> Date: Thu, 16 Apr 2020 12:53:17 -0500 Subject: [PATCH] Path: Optimization for open edges update Remove required usage of DocObject creation, in lieu of Part geometry usage - the preferred method. Limit DocObject creation to debugging mode only. Remove dependency on Draft module. Drawback is top edge must be selected, and Final Depth set appropriately when using profiling open edges. --- src/Mod/Path/PathScripts/PathProfileEdges.py | 336 ++++++++----------- 1 file changed, 132 insertions(+), 204 deletions(-) diff --git a/src/Mod/Path/PathScripts/PathProfileEdges.py b/src/Mod/Path/PathScripts/PathProfileEdges.py index 515e0de5dd..26ee36d541 100644 --- a/src/Mod/Path/PathScripts/PathProfileEdges.py +++ b/src/Mod/Path/PathScripts/PathProfileEdges.py @@ -34,7 +34,6 @@ import PySide # lazily loaded modules from lazy_loader.lazy_loader import LazyLoader -Draft = LazyLoader('Draft', globals(), 'Draft') Part = LazyLoader('Part', globals(), 'Part') DraftGeomUtils = LazyLoader('DraftGeomUtils', globals(), 'DraftGeomUtils') @@ -51,6 +50,7 @@ __title__ = "Path Profile Edges Operation" __author__ = "sliptonic (Brad Collette)" __url__ = "http://www.freecadweb.org" __doc__ = "Path Profile operation based on edges." +__contributors__ = "russ4262 (Russell Johnson)" class ObjectProfile(PathProfileBase.ObjectProfile): @@ -69,8 +69,10 @@ class ObjectProfile(PathProfileBase.ObjectProfile): '''areaOpShapes(obj) ... returns envelope for all wires formed by the base edges.''' PathLog.track() - self.tmpGrp = FreeCAD.ActiveDocument.addObject('App::DocumentObjectGroup', 'tmpDebugGrp') - tmpGrpNm = self.tmpGrp.Name + inaccessible = translate('PathProfileEdges', 'The selected edge(s) are inaccessible. If multiple, re-ordering selection might work.') + if PathLog.getLevel(PathLog.thisModule()) == 4: + self.tmpGrp = FreeCAD.ActiveDocument.addObject('App::DocumentObjectGroup', 'tmpDebugGrp') + tmpGrpNm = self.tmpGrp.Name self.JOB = PathUtils.findParentJob(obj) self.offsetExtra = abs(obj.OffsetExtra.Value) @@ -104,7 +106,7 @@ class ObjectProfile(PathProfileBase.ObjectProfile): # f = Part.makeFace(wire, 'Part::FaceMakerSimple') # if planar error, Comment out previous line, uncomment the next two (origWire, flatWire) = self._flattenWire(obj, wire, obj.FinalDepth.Value) - f = origWire.Shape.Wires[0] + f = origWire.Wires[0] if f is not False: # shift the compound to the bottom of the base object for proper sectioning zShift = zMin - f.BoundBox.ZMin @@ -113,7 +115,7 @@ class ObjectProfile(PathProfileBase.ObjectProfile): env = PathUtils.getEnvelope(base.Shape, subshape=f, depthparams=self.depthparams) shapes.append((env, False)) else: - PathLog.error(translate('PathProfileEdges', 'The selected edge(s) are inaccessible.')) + PathLog.error(inaccessible) else: if self.JOB.GeometryTolerance.Value == 0.0: msg = self.JOB.Label + '.GeometryTolerance = 0.0.' @@ -121,76 +123,64 @@ class ObjectProfile(PathProfileBase.ObjectProfile): PathLog.error(msg) else: cutWireObjs = False - (origWire, flatWire) = self._flattenWire(obj, wire, obj.FinalDepth.Value) - cutShp = self._getCutAreaCrossSection(obj, base, origWire, flatWire) - if cutShp is not False: - cutWireObjs = self._extractPathWire(obj, base, flatWire, cutShp) + flattened = self._flattenWire(obj, wire, obj.FinalDepth.Value) + if flattened: + (origWire, flatWire) = flattened + if PathLog.getLevel(PathLog.thisModule()) == 4: + os = FreeCAD.ActiveDocument.addObject('Part::Feature', 'tmpFlatWire') + os.Shape = flatWire + os.purgeTouched() + self.tmpGrp.addObject(os) + cutShp = self._getCutAreaCrossSection(obj, base, origWire, flatWire) + if cutShp is not False: + cutWireObjs = self._extractPathWire(obj, base, flatWire, cutShp) - if cutWireObjs is not False: - for cW in cutWireObjs: - shapes.append((cW, False)) - self.profileEdgesIsOpen = True + if cutWireObjs is not False: + for cW in cutWireObjs: + shapes.append((cW, False)) + self.profileEdgesIsOpen = True + else: + PathLog.error(inaccessible) else: - PathLog.error(translate('PathProfileEdges', 'The selected edge(s) are inaccessible.')) + PathLog.error(inaccessible) # Delete the temporary objects - if PathLog.getLevel(PathLog.thisModule()) != 4: - for to in self.tmpGrp.Group: - FreeCAD.ActiveDocument.removeObject(to.Name) - FreeCAD.ActiveDocument.removeObject(tmpGrpNm) - else: + if PathLog.getLevel(PathLog.thisModule()) == 4: if FreeCAD.GuiUp: import FreeCADGui FreeCADGui.ActiveDocument.getObject(tmpGrpNm).Visibility = False - + self.tmpGrp.purgeTouched() + return shapes def _flattenWire(self, obj, wire, trgtDep): '''_flattenWire(obj, wire)... Return a flattened version of the wire''' PathLog.debug('_flattenWire()') wBB = wire.BoundBox - tmpGrp = self.tmpGrp - - OW = FreeCAD.ActiveDocument.addObject('Part::Feature', 'tmpOriginalWire') - OW.Shape = wire - OW.purgeTouched() - tmpGrp.addObject(OW) if wBB.ZLength > 0.0: PathLog.debug('Wire is not horizontally co-planar. Flattening it.') # Extrude non-horizontal wire extFwdLen = wBB.ZLength * 2.2 - mbbEXT = self._extrudeObject(OW, extFwdLen, False) + mbbEXT = wire.extrude(FreeCAD.Vector(0, 0, extFwdLen)) # Create cross-section of shape and translate sliceZ = wire.BoundBox.ZMin + (extFwdLen / 2) - crsectFaceShp = self._makeCrossSection(mbbEXT.Shape, sliceZ, trgtDep) + crsectFaceShp = self._makeCrossSection(mbbEXT, sliceZ, trgtDep) if crsectFaceShp is not False: - # srtWire = Part.Wire(Part.__sortEdges__(crsectFaceShp.Edges)) - FW = FreeCAD.ActiveDocument.addObject('Part::Feature', 'tmpFlattenedWire') - FW.Shape = crsectFaceShp # srtWire - FW.recompute() - FW.purgeTouched() - tmpGrp.addObject(FW) - - return (OW, FW) + return (wire, crsectFaceShp) else: return False else: srtWire = Part.Wire(Part.__sortEdges__(wire.Edges)) srtWire.translate(FreeCAD.Vector(0, 0, trgtDep - srtWire.BoundBox.ZMin)) - FW = FreeCAD.ActiveDocument.addObject('Part::Feature', 'tmpOriginalWireSorted') - FW.Shape = srtWire - FW.purgeTouched() - tmpGrp.addObject(FW) - return (OW, FW) + return (wire, srtWire) # Open-edges methods - def _getCutAreaCrossSection(self, obj, base, origWire, flatWireObj): + def _getCutAreaCrossSection(self, obj, base, origWire, flatWire): PathLog.debug('_getCutAreaCrossSection()') - tmpGrp = self.tmpGrp FCAD = FreeCAD.ActiveDocument tolerance = self.JOB.GeometryTolerance.Value toolDiam = 2 * self.radius # self.radius defined in PathAreaOp or PathProfileBase modules @@ -198,16 +188,16 @@ class ObjectProfile(PathProfileBase.ObjectProfile): bbBfr = (self.ofstRadius * 2) * 1.25 if bbBfr < minBfr: bbBfr = minBfr - fwBB = flatWireObj.Shape.BoundBox - wBB = origWire.Shape.BoundBox + fwBB = flatWire.BoundBox + wBB = origWire.BoundBox minArea = (self.ofstRadius - tolerance)**2 * math.pi - useWire = origWire.Shape.Wires[0] + useWire = origWire.Wires[0] numOrigEdges = len(useWire.Edges) sdv = wBB.ZMax fdv = obj.FinalDepth.Value extLenFwd = sdv - fdv - WIRE = flatWireObj.Shape.Wires[0] + WIRE = flatWire.Wires[0] numEdges = len(WIRE.Edges) # Identify first/last edges and first/last vertex on wire @@ -242,15 +232,24 @@ class ObjectProfile(PathProfileBase.ObjectProfile): # Create intersection tags for determining which side of wire to cut (begInt, begExt, iTAG, eTAG) = self._makeIntersectionTags(useWire, numOrigEdges, fdv) + if not begInt or not begExt: + return False self.iTAG = iTAG self.eTAG = eTAG # Create extended wire boundbox, and extrude extBndbox = self._makeExtendedBoundBox(wBB, bbBfr, fdv) - extBndboxEXT = self._extrudeObject(extBndbox, extLenFwd) # (objToExt, extFwdLen) + extBndboxEXT = extBndbox.extrude(FreeCAD.Vector(0, 0, extLenFwd)) # Cut model(selected edges) from extended edges boundbox - cutArea = extBndboxEXT.Shape.cut(base.Shape) + cutArea = extBndboxEXT.cut(base.Shape) + if PathLog.getLevel(PathLog.thisModule()) == 4: + CA = FCAD.addObject('Part::Feature', 'tmpCutArea') + CA.Shape = cutArea + CA.recompute() + CA.purgeTouched() + self.tmpGrp.addObject(CA) + # Get top and bottom faces of cut area (CA), and combine faces when necessary topFc = list() @@ -270,8 +269,8 @@ class ObjectProfile(PathProfileBase.ObjectProfile): topComp.translate(FreeCAD.Vector(0, 0, fdv - topComp.BoundBox.ZMin)) # Translate face to final depth if len(botFc) > 1: PathLog.debug('len(botFc) > 1') - bndboxFace = Part.Face(extBndbox.Shape.Wires[0]) - tmpFace = Part.Face(extBndbox.Shape.Wires[0]) + bndboxFace = Part.Face(extBndbox.Wires[0]) + tmpFace = Part.Face(extBndbox.Wires[0]) for f in botFc: Q = tmpFace.cut(cutArea.Faces[f]) tmpFace = Q @@ -280,38 +279,20 @@ class ObjectProfile(PathProfileBase.ObjectProfile): botComp = Part.makeCompound([cutArea.Faces[f] for f in botFc]) # Part.makeCompound([CA.Shape.Faces[f] for f in botFc]) botComp.translate(FreeCAD.Vector(0, 0, fdv - botComp.BoundBox.ZMin)) # Translate face to final depth - # Convert compound shapes to FC objects for use in multicommon operation - TP = FCAD.addObject('Part::Feature', 'tmpTopCompound') - TP.Shape = topComp - TP.recompute() - TP.purgeTouched() - tmpGrp.addObject(TP) - BT = FCAD.addObject('Part::Feature', 'tmpBotCompound') - BT.Shape = botComp - BT.recompute() - BT.purgeTouched() - tmpGrp.addObject(BT) - # Make common of the two - comFC = FCAD.addObject('Part::MultiCommon', 'tmpCommonTopBotFaces') - comFC.Shapes = [TP, BT] - comFC.recompute() - TP.purgeTouched() - BT.purgeTouched() - comFC.purgeTouched() - tmpGrp.addObject(comFC) + comFC = topComp.common(botComp) # Determine with which set of intersection tags the model intersects (cmnIntArea, cmnExtArea) = self._checkTagIntersection(iTAG, eTAG, 'QRY', comFC) if cmnExtArea > cmnIntArea: PathLog.debug('Cutting on Ext side.') self.cutSide = 'E' - self.cutSideTags = eTAG.Shape + self.cutSideTags = eTAG tagCOM = begExt.CenterOfMass else: PathLog.debug('Cutting on Int side.') self.cutSide = 'I' - self.cutSideTags = iTAG.Shape + self.cutSideTags = iTAG tagCOM = begInt.CenterOfMass # Make two beginning style(oriented) 'L' shape stops @@ -331,9 +312,9 @@ class ObjectProfile(PathProfileBase.ObjectProfile): pathStops.translate(FreeCAD.Vector(0, 0, fdv - pathStops.BoundBox.ZMin)) # Identify closed wire in cross-section that corresponds to user-selected edge(s) - workShp = comFC.Shape + workShp = comFC fcShp = workShp - wire = origWire.Shape # flatWireObj.Shape + wire = origWire WS = workShp.Wires lenWS = len(WS) if lenWS < 3: @@ -354,7 +335,6 @@ class ObjectProfile(PathProfileBase.ObjectProfile): if wi is None: PathLog.error('The cut area cross-section wire does not coincide with selected edge. Wires[] index is None.') - tmpGrp.purgeTouched() return False else: PathLog.debug('Cross-section Wires[] index is {}.'.format(wi)) @@ -368,13 +348,8 @@ class ObjectProfile(PathProfileBase.ObjectProfile): if wi > 0: # and isInterior is False: PathLog.debug('Multiple wires in cut area. First choice is not 0. Testing.') testArea = fcShp.cut(base.Shape) - # testArea = fcShp - TA = FreeCAD.ActiveDocument.addObject('Part::Feature','tmpCutFaceTest') - TA.Shape = testArea - TA.purgeTouched() - tmpGrp.addObject(TA) - isReady = self._checkTagIntersection(iTAG, eTAG, self.cutSide, TA) + isReady = self._checkTagIntersection(iTAG, eTAG, self.cutSide, testArea) PathLog.debug('isReady {}.'.format(isReady)) if isReady is False: @@ -395,38 +370,18 @@ class ObjectProfile(PathProfileBase.ObjectProfile): # Add path stops at ends of wire cutShp = workShp.cut(pathStops) - - CF = FreeCAD.ActiveDocument.addObject('Part::Feature','tmpCutFace') - CF.Shape = cutShp - CF.recompute() - CF.purgeTouched() - tmpGrp.addObject(CF) - - tmpGrp.purgeTouched() - return cutShp # CF.Shape + return cutShp def _checkTagIntersection(self, iTAG, eTAG, cutSide, tstObj): # Identify intersection of Common area and Interior Tags - intCmn = FreeCAD.ActiveDocument.addObject('Part::MultiCommon', 'tmpCmnIntTags') - intCmn.Shapes = [tstObj, iTAG] - intCmn.recompute() - tstObj.purgeTouched() - iTAG.purgeTouched() - intCmn.purgeTouched() - self.tmpGrp.addObject(intCmn) + intCmn = tstObj.common(iTAG) # Identify intersection of Common area and Exterior Tags - extCmn = FreeCAD.ActiveDocument.addObject('Part::MultiCommon', 'tmpCmnExtTags') - extCmn.Shapes = [tstObj, eTAG] - extCmn.recompute() - tstObj.purgeTouched() - eTAG.purgeTouched() - extCmn.purgeTouched() - self.tmpGrp.addObject(extCmn) + extCmn = tstObj.common(eTAG) # Calculate common intersection (solid model side, or the non-cut side) area with tags, to determine physical cut side - cmnIntArea = intCmn.Shape.Area - cmnExtArea = extCmn.Shape.Area + cmnIntArea = intCmn.Area + cmnExtArea = extCmn.Area if cutSide == 'QRY': return (cmnIntArea, cmnExtArea) @@ -440,16 +395,15 @@ class ObjectProfile(PathProfileBase.ObjectProfile): return True return False - def _extractPathWire(self, obj, base, fWire, cutShp): + def _extractPathWire(self, obj, base, flatWire, cutShp): PathLog.debug('_extractPathWire()') subLoops = list() rtnWIRES = list() osWrIdxs = list() subDistFactor = 1.0 # Raise to include sub wires at greater distance from original - tmpGrp = self.tmpGrp fdv = obj.FinalDepth.Value - wire = fWire.Shape + wire = flatWire lstVrtIdx = len(wire.Vertexes) - 1 lstVrt = wire.Vertexes[lstVrtIdx] frstVrt = wire.Vertexes[0] @@ -468,14 +422,14 @@ class ObjectProfile(PathProfileBase.ObjectProfile): osArea = ofstShp.Area except Exception as ee: PathLog.error('No area to offset shape returned.') - tmpGrp.purgeTouched() return False - os = FreeCAD.ActiveDocument.addObject('Part::Feature', 'tmpOffsetShape') - os.Shape = ofstShp - os.recompute() - os.purgeTouched() - tmpGrp.addObject(os) + if PathLog.getLevel(PathLog.thisModule()) == 4: + os = FreeCAD.ActiveDocument.addObject('Part::Feature', 'tmpOffsetShape') + os.Shape = ofstShp + os.recompute() + os.purgeTouched() + self.tmpGrp.addObject(os) numOSWires = len(ofstShp.Wires) for w in range(0, numOSWires): @@ -491,10 +445,12 @@ class ObjectProfile(PathProfileBase.ObjectProfile): min0 = N[4] min0i = n (w0, vi0, pnt0, vrt0, d0) = NEAR0[0] # min0i - near0 = Draft.makeWire([cent0, pnt0], placement=pl, closed=False, face=False, support=None) - near0.recompute() - near0.purgeTouched() - tmpGrp.addObject(near0) + if PathLog.getLevel(PathLog.thisModule()) == 4: + near0 = FreeCAD.ActiveDocument.addObject('Part::Feature', 'tmpNear0') + near0.Shape = Part.makeLine(cent0, pnt0) + near0.recompute() + near0.purgeTouched() + self.tmpGrp.addObject(near0) NEAR1 = self._findNearestVertex(ofstShp, cent1) min1i = 0 @@ -505,24 +461,23 @@ class ObjectProfile(PathProfileBase.ObjectProfile): min1 = N[4] min1i = n (w1, vi1, pnt1, vrt1, d1) = NEAR1[0] # min1i - near1 = Draft.makeWire([cent1, pnt1], placement=pl, closed=False, face=False, support=None) - near1.recompute() - near1.purgeTouched() - tmpGrp.addObject(near1) + if PathLog.getLevel(PathLog.thisModule()) == 4: + near1 = FreeCAD.ActiveDocument.addObject('Part::Feature', 'tmpNear1') + near1.Shape = Part.makeLine(cent1, pnt1) + near1.recompute() + near1.purgeTouched() + self.tmpGrp.addObject(near1) if w0 != w1: - PathLog.debug('w0 is {}.'.format(w0)) - PathLog.debug('w1 is {}.'.format(w1)) - PathLog.warning('Offset wire endpoint indexes are not equal: {}, {}'.format(w0, w1)) + PathLog.warning('Offset wire endpoint indexes are not equal - w0, w1: {}, {}'.format(w0, w1)) - ''' - PathLog.debug('min0i is {}.'.format(min0i)) - PathLog.debug('min1i is {}.'.format(min1i)) - PathLog.debug('NEAR0[{}] is {}.'.format(w0, NEAR0[w0])) - PathLog.debug('NEAR1[{}] is {}.'.format(w1, NEAR1[w1])) - PathLog.debug('NEAR0 is {}.'.format(NEAR0)) - PathLog.debug('NEAR1 is {}.'.format(NEAR1)) - ''' + if PathLog.getLevel(PathLog.thisModule()) == 4: + PathLog.debug('min0i is {}.'.format(min0i)) + PathLog.debug('min1i is {}.'.format(min1i)) + PathLog.debug('NEAR0[{}] is {}.'.format(w0, NEAR0[w0])) + PathLog.debug('NEAR1[{}] is {}.'.format(w1, NEAR1[w1])) + PathLog.debug('NEAR0 is {}.'.format(NEAR0)) + PathLog.debug('NEAR1 is {}.'.format(NEAR1)) mainWire = ofstShp.Wires[w0] @@ -553,7 +508,6 @@ class ObjectProfile(PathProfileBase.ObjectProfile): # Eif # Break offset loop into two wires - one of which is the desired profile path wire. - # (edgeIdxs0, edgeIdxs1) = self._separateWireAtVertexes(mainWire, ofstShp.Vertexes[vi0], ofstShp.Vertexes[vi1]) (edgeIdxs0, edgeIdxs1) = self._separateWireAtVertexes(mainWire, mainWire.Vertexes[vi0], mainWire.Vertexes[vi1]) edgs0 = list() edgs1 = list() @@ -573,7 +527,6 @@ class ObjectProfile(PathProfileBase.ObjectProfile): rtnWIRES.append(part1) rtnWIRES.extend(subLoops) - tmpGrp.purgeTouched() return rtnWIRES def _extractFaceOffset(self, obj, fcShape, isHole): @@ -608,13 +561,7 @@ class ObjectProfile(PathProfileBase.ObjectProfile): area.add(fcShape) # obj.Shape to use for extracting offset area.setParams(**areaParams) # set parameters - # Save parameters for debugging - # obj.AreaParams = str(area.getParams()) - # PathLog.debug("Area with params: {}".format(area.getParams())) - - offsetShape = area.getShape() - - return offsetShape + return area.getShape() def _findNearestVertex(self, shape, point): PathLog.debug('_findNearestVertex()') @@ -795,29 +742,17 @@ class ObjectProfile(PathProfileBase.ObjectProfile): return False def _makeExtendedBoundBox(self, wBB, bbBfr, zDep): - pl = FreeCAD.Placement() - pl.Rotation = FreeCAD.Rotation(FreeCAD.Vector(0, 0, 1), 0) - pl.Base = FreeCAD.Vector(0, 0, 0) - p1 = FreeCAD.Vector(wBB.XMin - bbBfr, wBB.YMin - bbBfr, zDep) p2 = FreeCAD.Vector(wBB.XMax + bbBfr, wBB.YMin - bbBfr, zDep) p3 = FreeCAD.Vector(wBB.XMax + bbBfr, wBB.YMax + bbBfr, zDep) p4 = FreeCAD.Vector(wBB.XMin - bbBfr, wBB.YMax + bbBfr, zDep) - bb = Draft.makeWire([p1, p2, p3, p4], placement=pl, closed=True, face=False, support=None) - bb.Label = 'ProfileEdges_BoundBox' - bb.recompute() - bb.purgeTouched() - self.tmpGrp.addObject(bb) - return bb + L1 = Part.makeLine(p1, p2) + L2 = Part.makeLine(p2, p3) + L3 = Part.makeLine(p3, p4) + L4 = Part.makeLine(p4, p1) - def _makeSimpleCircle(self, rad, plcmnt, isFace=False, label='SimpleCircle'): - C = Draft.makeCircle(rad, placement=plcmnt, face=isFace) - C.Label = 'tmp' + label - C.recompute() - C.purgeTouched() - self.tmpGrp.addObject(C) - return C + return Part.Face(Part.Wire([L1, L2, L3, L4])) def _makeIntersectionTags(self, useWire, numOrigEdges, fdv): # Create circular probe tags around perimiter of wire @@ -825,8 +760,8 @@ class ObjectProfile(PathProfileBase.ObjectProfile): intTags = list() tagRad = (self.radius / 2) tagCnt = 0 - begInt = None - begExt = None + begInt = False + begExt = False for e in range(0, numOrigEdges): E = useWire.Edges[e] LE = E.Length @@ -846,31 +781,22 @@ class ObjectProfile(PathProfileBase.ObjectProfile): cp1 = E.valueAt(E.getParameterByLength(0)) cp2 = E.valueAt(E.getParameterByLength(aspc)) (intTObj, extTObj) = self._makeOffsetCircleTag(cp1, cp2, tagRad, fdv, 'BeginEdge[{}]_'.format(e)) - if intTObj is not False: - begInt = intTObj.Shape - begExt = extTObj.Shape + if intTObj and extTObj: + begInt = intTObj + begExt = extTObj else: d = i * mid cp1 = E.valueAt(E.getParameterByLength(d - spc)) cp2 = E.valueAt(E.getParameterByLength(d + spc)) (intTObj, extTObj) = self._makeOffsetCircleTag(cp1, cp2, tagRad, fdv, 'Edge[{}]_'.format(e)) - if intTObj is not False: + if intTObj and extTObj: tagCnt += nt intTags.append(intTObj) extTags.append(extTObj) tagArea = math.pi * tagRad**2 * tagCnt - # FreeCAD object required for Part::MultiCommon usage - intTagsComp = Part.makeCompound([T.Shape for T in intTags]) - iTAG = FreeCAD.ActiveDocument.addObject('Part::Feature', 'tmpInteriorTags') - iTAG.Shape = intTagsComp - iTAG.purgeTouched() - self.tmpGrp.addObject(iTAG) - # FreeCAD object required for Part::MultiCommon usage - extTagsComp = Part.makeCompound([T.Shape for T in extTags]) - eTAG = FreeCAD.ActiveDocument.addObject('Part::Feature', 'tmpExteriorTags') - eTAG.Shape = extTagsComp - eTAG.purgeTouched() - self.tmpGrp.addObject(eTAG) + iTAG = Part.makeCompound(intTags) + eTAG = Part.makeCompound(extTags) + return (begInt, begExt, iTAG, eTAG) def _makeOffsetCircleTag(self, p1, p2, cutterRad, depth, lbl, reverse=False): @@ -890,32 +816,19 @@ class ObjectProfile(PathProfileBase.ObjectProfile): pl = FreeCAD.Placement() pl.Rotation = FreeCAD.Rotation(FreeCAD.Vector(0, 0, 1), 0) # make exterior tag - adjlbl = lbl + 'Ext' - pl.Base = extPnt.add(FreeCAD.Vector(0, 0, depth)) - extTag = self._makeSimpleCircle((cutterRad / 2), pl, True, adjlbl) + eCntr = extPnt.add(FreeCAD.Vector(0, 0, depth)) + ecw = Part.Wire(Part.makeCircle((cutterRad / 2), eCntr).Edges[0]) + extTag = Part.Face(ecw) # make interior tag - adjlbl = lbl + 'Int' perpI = FreeCAD.Vector(-1 * toMid.y, toMid.x, 0.0).multiply(cutFactor) # interior tag intPnt = pb.add(toMid.add(perpI)) - pl.Base = intPnt.add(FreeCAD.Vector(0, 0, depth)) - intTag = self._makeSimpleCircle((cutterRad / 2), pl, True, adjlbl) + iCntr = intPnt.add(FreeCAD.Vector(0, 0, depth)) + icw = Part.Wire(Part.makeCircle((cutterRad / 2), iCntr).Edges[0]) + intTag = Part.Face(icw) return (intTag, extTag) - def _extrudeObject(self, objToExt, extFwdLen, solid=True): - # Extrude non-horizontal wire - E = FreeCAD.ActiveDocument.addObject('Part::Extrusion', 'tmpExtrusion') - E.Base = objToExt - E.DirMode = 'Custom' - E.Dir = FreeCAD.Vector(0, 0, 1) - E.LengthFwd = extFwdLen - E.Solid = solid - E.recompute() - E.purgeTouched() - self.tmpGrp.addObject(E) - return E - def _makeStop(self, sType, pA, pB, lbl): rad = self.radius ofstRad = self.ofstRadius @@ -953,7 +866,13 @@ class ObjectProfile(PathProfileBase.ObjectProfile): p5 = self._makePerp2DVector(p3, p4, -1 * (1 + extra)) # E4 p6 = self._makePerp2DVector(p4, p5, -1 * (ofstRad + extra)) # E5 p7 = E # E6 - S = Draft.makeWire([p1, p2, p3, p4, p5, p6, p7], placement=pl, closed=True, face=True) + L1 = Part.makeLine(p1, p2) + L2 = Part.makeLine(p2, p3) + L3 = Part.makeLine(p3, p4) + L4 = Part.makeLine(p4, p5) + L5 = Part.makeLine(p5, p6) + L6 = Part.makeLine(p6, p7) + wire = Part.Wire([L1, L2, L3, L4, L5, L6]) else: # 'L' stop shape and edge legend # : @@ -973,13 +892,22 @@ class ObjectProfile(PathProfileBase.ObjectProfile): p4 = self._makePerp2DVector(p2, p3, -1 * (0.5 + abs(self.offsetExtra))) # FIRST POINT p5 = self._makePerp2DVector(p3, p4, -1 * (0.25 + abs(self.offsetExtra))) # E1 SECOND p6 = p1 # E4 - S = Draft.makeWire([p1, p2, p3, p4, p5, p6], placement=pl, closed=True, face=True) + L1 = Part.makeLine(p1, p2) + L2 = Part.makeLine(p2, p3) + L3 = Part.makeLine(p3, p4) + L4 = Part.makeLine(p4, p5) + L5 = Part.makeLine(p5, p6) + wire = Part.Wire([L1, L2, L3, L4, L5]) # Eif - S.Label = 'tmp' + lbl - S.recompute() - S.purgeTouched() - self.tmpGrp.addObject(S) - return S.Shape + face = Part.Face(wire) + if PathLog.getLevel(PathLog.thisModule()) == 4: + os = FreeCAD.ActiveDocument.addObject('Part::Feature', 'tmp' + lbl) + os.Shape = face + os.recompute() + os.purgeTouched() + self.tmpGrp.addObject(os) + + return face def _makePerp2DVector(self, v1, v2, dist): p1 = FreeCAD.Vector(v1.x, v1.y, 0.0)