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:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user