assembly: support auto fix in AsmElement

This commit is contained in:
Zheng, Lei 2020-02-26 12:07:45 +08:00
parent 89700cc1c1
commit 3f120aced5
3 changed files with 121 additions and 4 deletions

View File

@ -1,4 +1,4 @@
import os
import os, traceback
from collections import namedtuple,defaultdict
import FreeCAD, FreeCADGui, Part
from PySide import QtCore, QtGui
@ -612,6 +612,74 @@ class AsmElement(AsmBase):
not Constraint.isDisabled(parent.Object):
Assembly.autoSolve(obj,prop)
def isBroken(self):
linked,subname = self.Object.LinkedObject
obj = linked.getSubObject(subname,1)
if isTypeOf(obj, AsmElement):
return obj.Proxy.isBroken()
if not obj:
return False # broken beyond fix
subs = Part.splitSubname(subname)
if not subs[1]:
return False # no mapped element name
shape = linked.getSubObject(subs[0])
if not utils.getElement(shape, subs[1]):
return True
def fix(self):
linked,subname = self.Object.LinkedObject
obj = linked.getSubObject(subname,1)
if isTypeOf(obj, AsmElement):
obj.Proxy.fix()
return
if not obj:
raise RuntimeError('Broken link')
subs = Part.splitSubname(subname)
if not subs[1]:
raise RuntimeError('No mapped sub-element found')
shape = linked.getSubObject(subs[0])
if utils.getElement(shape, subs[1]):
return
for mapped, element in Part.getRelatedElements(linked, subname):
logger.msg('{} reference change {} {} -> {}',
element.FullName, linked.FullName,
subs[0], subs[2], element)
subname = Part.joinSubname(subs[0],mapped,element)
self.Object.setLink(linked,subname)
return
if not hasattr(shape, 'searchSubShape'):
raise RuntimeError('Failed to fix element')
try:
myShape = self.Object.Shape.SubShapes[0]
except Exception:
raise RuntimeError('No element shape saved')
if myShape.countElement('Face')==1:
myShape = myShape.Face1
elif myShape.countElement('Edge')==1:
myShape = myShape.Edge1
elif myShape.countElement('Vertex')==1:
myShape = myShape.Vertex1
else:
raise RuntimeError('Unsupported element shape')
try:
element,_ = shape.searchSubShape(myShape,True)[0]
logger.msg('{} reference change {}.{} {} -> {}',
obj.FullName, linked.FullName,
subs[0], subs[2], element)
subname = Part.joinSubname(subs[0],'',element)
self.Object.setLink(linked,subname)
return
except Exception:
raise RuntimeError('Matching element shape not found')
def execute(self,obj):
if not obj.isDerivedFrom('Part::FeaturePython'):
self.version.value += 1
@ -627,7 +695,13 @@ class AsmElement(AsmBase):
self.getElementSubname())
except Exception:
self.updatePlacement()
raise
if not gui.AsmCmdManager.AutoFixElement:
raise
self.fix()
info = getElementInfo(self.getAssembly().getPartGroup(),
self.getElementSubname())
if not getattr(obj,'Radius',None):
shape = Part.Shape(info.Shape).copy()
@ -678,8 +752,8 @@ class AsmElement(AsmBase):
shape = shape.SubShapes[0]
# Call getElementInfo() to obtain part's placement only. We don't
# need the shape here, in order to handle even with missing
# down-stream element
# need the shape here, in order to handle missing down-stream
# element
info = getElementInfo(self.getAssembly().getPartGroup(),
self.getElementSubname(),False,True)
pla = info.Placement
@ -1182,6 +1256,23 @@ class ViewProviderAsmElement(ViewProviderAsmOnTop):
action,QtCore.SIGNAL("triggered()"),self.toggleDetach)
menu.addAction(action)
if obj.Proxy.isBroken():
action = QtGui.QAction(QtGui.QIcon(), "Fix", menu)
QtCore.QObject.connect(
action,QtCore.SIGNAL("triggered()"),self.fix)
menu.addAction(action)
def fix(self):
obj = self.ViewObject.Object
FreeCAD.setActiveTransaction('Fix element')
try:
obj.Proxy.fix()
obj.recompute();
FreeCAD.closeActiveTransaction()
except Exception:
FreeCAD.closeActiveTransaction(True)
raise
def toggleDetach(self):
obj = self.ViewObject.Object
FreeCAD.setActiveTransaction('Attach element' if obj.Detach else 'Detach element')

View File

@ -651,6 +651,17 @@ class AsmCmdSmartRecompute(AsmCmdCheckable):
def IsActive(cls):
return True
class AsmCmdAutoFixElement(AsmCmdCheckable):
_id = 31
_menuText = 'Auto fix element'
_tooltip = 'Toggle element auto fixing during recomputation (Experimental!)'
_iconName = 'Assembly_AutoFixElement.svg'
_saveParam = True
@classmethod
def IsActive(cls):
return True
class AsmCmdAutoElementVis(AsmCmdCheckable):
_id = 9
_menuText = 'Auto element visibility'

View File

@ -205,6 +205,21 @@ def isElement(obj):
shape.countElement('Edge')==1 or \
shape.countElement('Face')==1
def getElement(shape, element):
res = None
try:
res = shape.getElement(element, True)
except TypeError:
try:
# older FC does not accept the second 'silent' argument
res = shape.getElement(element)
except Exception:
return
except Exception:
return
if res and not res.isNull():
return res
def isPlanar(obj):
if isCircularEdge(obj):
return True