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.
This commit is contained in:
Russell Johnson
2020-04-16 12:53:17 -05:00
parent 63fcfb4802
commit 9642271335

View File

@@ -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)