assembly: support freezing assembly

New property 'Freeze' added to assembly container to freeze any update
of the assembly.

AsmPartGroup and AsmElement has been change to bind to
Part::FeaturePython instead of App::FeaturePython, in order to be able
to hold its own shape when frozen. The new ChildViewProvider feature in
ViewProviderLink is used to display the native shape.
This commit is contained in:
Zheng, Lei 2018-07-06 15:44:47 +08:00
parent 9513b774a8
commit e63118d6b5
2 changed files with 286 additions and 92 deletions

View File

@ -83,10 +83,14 @@ class ViewProviderAsmBase(object):
vobj.Proxy = self vobj.Proxy = self
self.attach(vobj) self.attach(vobj)
_addToSceneGraph = False
def attach(self,vobj): def attach(self,vobj):
self.ViewObject = vobj self.ViewObject = vobj
vobj.signalChangeIcon() vobj.signalChangeIcon()
vobj.setPropertyStatus('Visibility','Hidden') vobj.setPropertyStatus('Visibility','Hidden')
if not self._addToSceneGraph:
vobj.Document.ActiveView.getSceneGraph().removeChild(vobj.RootNode)
def __getstate__(self): def __getstate__(self):
return None return None
@ -138,6 +142,9 @@ class AsmGroup(AsmBase):
obj.addProperty("App::PropertyEnumeration","GroupMode","Base",'') obj.addProperty("App::PropertyEnumeration","GroupMode","Base",'')
super(AsmGroup,self).attach(obj) super(AsmGroup,self).attach(obj)
def allowDuplicateLabel(self,_obj):
return True
class ViewProviderAsmGroup(ViewProviderAsmBase): class ViewProviderAsmGroup(ViewProviderAsmBase):
def claimChildren(self): def claimChildren(self):
@ -166,10 +173,15 @@ class AsmPartGroup(AsmGroup):
def groupSetup(self): def groupSetup(self):
pass pass
def canLoadPartial(self,_obj):
return 1 if self.getAssembly().frozen else 0
@staticmethod @staticmethod
def make(parent,name='Parts'): def make(parent,name='Parts'):
obj = parent.Document.addObject("App::FeaturePython",name, obj = parent.Document.addObject("Part::FeaturePython",name,
AsmPartGroup(parent),None,True) AsmPartGroup(parent),None,True)
obj.setPropertyStatus('Placement',('Output','Hidden'))
obj.setPropertyStatus('Shape','Output')
ViewProviderAsmPartGroup(obj.ViewObject) ViewProviderAsmPartGroup(obj.ViewObject)
obj.purgeTouched() obj.purgeTouched()
return obj return obj
@ -193,11 +205,35 @@ class ViewProviderAsmPartGroup(ViewProviderAsmGroup):
def canDragAndDropObject(self,_obj): def canDragAndDropObject(self,_obj):
return True return True
def updateData(self,obj,prop):
if not hasattr(self,'ViewObject') or FreeCAD.isRestoring():
return
if prop == 'Shape':
cvp = obj.ViewObject.ChildViewProvider
if cvp:
cvp.mapShapeColors()
def showParts(self):
vobj = self.ViewObject
obj = vobj.Object
assembly = obj.Proxy.getAssembly().Object
if not assembly.ViewObject.ShowParts and \
(assembly.Freeze or (assembly.BuildShape!=BuildShapeNone and \
assembly.BuildShape!=BuildShapeCompound)):
mode = 1
else:
mode = 0
if not vobj.ChildViewProvider:
if not mode:
return
vobj.ChildViewProvider = 'PartGui::ViewProviderPartExt'
vobj.DefaultMode = mode
class AsmElement(AsmBase): class AsmElement(AsmBase):
def __init__(self,parent): def __init__(self,parent):
self._initializing = True self._initializing = True
self.info = None self.shape = None
self.parent = getProxy(parent,AsmElementGroup) self.parent = getProxy(parent,AsmElementGroup)
super(AsmElement,self).__init__() super(AsmElement,self).__init__()
@ -214,6 +250,7 @@ class AsmElement(AsmBase):
obj.setPropertyStatus('LinkTransform',['Immutable','Hidden']) obj.setPropertyStatus('LinkTransform',['Immutable','Hidden'])
obj.configLinkProperty('LinkedObject','Placement','LinkTransform') obj.configLinkProperty('LinkedObject','Placement','LinkTransform')
obj.setPropertyStatus('LinkedObject','ReadOnly') obj.setPropertyStatus('LinkedObject','ReadOnly')
self.shape = None
def attach(self,obj): def attach(self,obj):
obj.addProperty("App::PropertyXLink","LinkedObject"," Link",'') obj.addProperty("App::PropertyXLink","LinkedObject"," Link",'')
@ -235,7 +272,7 @@ class AsmElement(AsmBase):
if not parent or FreeCAD.isRestoring(): if not parent or FreeCAD.isRestoring():
return return
if prop=='Offset': if prop=='Offset':
self.updatePlacement() self.update()
elif prop == 'Label': elif prop == 'Label':
parent.Object.cacheChildLabel() parent.Object.cacheChildLabel()
if prop not in _IgnoredProperties and \ if prop not in _IgnoredProperties and \
@ -247,23 +284,29 @@ class AsmElement(AsmBase):
return False return False
def updatePlacement(self): def updatePlacement(self):
obj = getattr(self,'Object',None) obj = self.Object
if not obj: info = getElementInfo(self.getAssembly().getPartGroup(),
self.getElementSubname(),offset=self.Object.Offset)
if not info:
return return
if obj.Offset.isIdentity(): self.shape = info.Shape
if obj.Placement.isIdentity(): if not utils.isSamePlacement(info.PlacementOffset,obj.Placement):
return obj.setPropertyStatus('Placement','-Immutable')
pla = FreeCAD.Placement() obj.Placement = info.PlacementOffset
else: obj.setPropertyStatus('Placement','Immutable')
info = getElementInfo(self.getAssembly().getPartGroup(),
self.getElementSubname(),offset=self.Object.Offset) def freeze(self):
if not info or \ obj = self.Object
utils.isSamePlacement(info.PlacementOffset,obj.Placement): if self.getAssembly().Freeze:
return if not self.shape:
pla = info.PlacementOffset self.updatePlacement();
obj.setPropertyStatus('Placement','-Immutable') if self.shape:
obj.Placement = pla # make a compound to contain the shape's transformation
obj.setPropertyStatus('Placement','Immutable') shape = Part.makeCompound(self.shape)
shape.ElementMap = self.shape.ElementMap
obj.Shape = shape
elif not obj.Shape.isNull():
obj.Shape = Part.Shape()
def getAssembly(self): def getAssembly(self):
return self.parent.parent return self.parent.parent
@ -383,8 +426,8 @@ class AsmElement(AsmBase):
@classmethod @classmethod
def create(cls,name,elements): def create(cls,name,elements):
element = elements.Document.addObject("App::FeaturePython", element = elements.Document.addObject("Part::FeaturePython",
name,cls(elements),None,True) name,cls(elements),None,True)
ViewProviderAsmElement(element.ViewObject) ViewProviderAsmElement(element.ViewObject)
return element return element
@ -560,6 +603,22 @@ class ViewProviderAsmElement(ViewProviderAsmOnTop):
AsmElement.make(AsmElement.Selection(Element=vobj.Object, AsmElement.make(AsmElement.Selection(Element=vobj.Object,
Group=owner, Subname=subname+element),undo=True) Group=owner, Subname=subname+element),undo=True)
def updateData(self,obj,prop):
if not hasattr(self,'ViewObject') or FreeCAD.isRestoring():
return
if prop == 'Shape':
vobj = obj.ViewObject
if obj.Shape.isNull():
vobj.ChildViewProvider = ''
elif not vobj.ChildViewProvider:
vobj.ChildViewProvider = 'PartGui::ViewProviderPartExt'
vobj.DefaultMode = 1
def onFinishRestoring(self):
vobj = self.ViewObject
if getattr(vobj,'ChildViewProvider',None):
vobj.DefaultMode = 1
class AsmElementSketch(AsmElement): class AsmElementSketch(AsmElement):
def __init__(self,obj,parent): def __init__(self,obj,parent):
@ -596,6 +655,9 @@ class AsmElementSketch(AsmElement):
ret[0] = obj ret[0] = obj
return ret return ret
def freeze(self):
pass
class ViewProviderAsmElementSketch(ViewProviderAsmElement): class ViewProviderAsmElementSketch(ViewProviderAsmElement):
def getIcon(self): def getIcon(self):
@ -612,6 +674,10 @@ class ViewProviderAsmElementSketch(ViewProviderAsmElement):
return subs[-1] return subs[-1]
return '' return ''
def updateData(self,obj,prop):
_ = obj
_ = prop
ElementInfo = namedtuple('AsmElementInfo', ('Parent','SubnameRef','Part', ElementInfo = namedtuple('AsmElementInfo', ('Parent','SubnameRef','Part',
'PartName','Placement','Object','Subname','Shape','PlacementOffset')) 'PartName','Placement','Object','Subname','Shape','PlacementOffset'))
@ -625,6 +691,14 @@ def getElementInfo(parent,subname,checkPlacement=False,shape=None,offset=None):
subname: subname reference to the part element (i.e. edge, face, vertex) subname: subname reference to the part element (i.e. edge, face, vertex)
shape: caller can pass in a pre-obtained element shape. The shape is
assumed ot be in the assembly coordinate space. This function will then
transform the shape into the its owner part's coordinate space. If
'shape' is not given, then the output shape will be obtained through
'parent' and 'subname'
offset: an optional offset in the element shape's coordinate space
Return a named tuple with the following fields: Return a named tuple with the following fields:
Parent: set to the input parent object Parent: set to the input parent object
@ -648,6 +722,10 @@ def getElementInfo(parent,subname,checkPlacement=False,shape=None,offset=None):
Shape: Part.Shape of the linked element. The shape's placement is relative Shape: Part.Shape of the linked element. The shape's placement is relative
to the owner Part. to the owner Part.
PlacementOffset: if 'offset' is given, then this field holds the necessary
placement offset in assembly coordinate space to achieve an equivalant
'offset', which is in element shape's coordinate space.
''' '''
subnameRef = subname subnameRef = subname
@ -795,6 +873,7 @@ class AsmElementLink(AsmBase):
super(AsmElementLink,self).linkSetup(obj) super(AsmElementLink,self).linkSetup(obj)
obj.configLinkProperty('LinkedObject') obj.configLinkProperty('LinkedObject')
obj.setPropertyStatus('LinkedObject','ReadOnly') obj.setPropertyStatus('LinkedObject','ReadOnly')
self.info = None
def attach(self,obj): def attach(self,obj):
obj.addProperty("App::PropertyXLink","LinkedObject"," Link",'') obj.addProperty("App::PropertyXLink","LinkedObject"," Link",'')
@ -898,6 +977,9 @@ class AsmElementLink(AsmBase):
return return
self.info = getElementInfo(self.getAssembly().getPartGroup(), self.info = getElementInfo(self.getAssembly().getPartGroup(),
self.getElementSubname(),shape=obj.getSubObject('')) self.getElementSubname(),shape=obj.getSubObject(''))
if hasattr(obj,'Shape') and self.getAssembly().Freeze:
# make a compound to contain the shape's transformation
obj.Shape = Part.makeCompound(self.info.Shape)
return self.info return self.info
@staticmethod @staticmethod
@ -1275,6 +1357,9 @@ class AsmConstraintGroup(AsmGroup):
def getAssembly(self): def getAssembly(self):
return self.parent return self.parent
def canLoadPartial(self,_obj):
return 2 if self.getAssembly().frozen else 0
def linkSetup(self,obj): def linkSetup(self,obj):
super(AsmConstraintGroup,self).linkSetup(obj) super(AsmConstraintGroup,self).linkSetup(obj)
for o in obj.Group: for o in obj.Group:
@ -1380,8 +1465,9 @@ BuildShapeNone = 'None'
BuildShapeCompound = 'Compound' BuildShapeCompound = 'Compound'
BuildShapeFuse = 'Fuse' BuildShapeFuse = 'Fuse'
BuildShapeCut = 'Cut' BuildShapeCut = 'Cut'
BuildShapeCommon = 'Common'
BuildShapeNames = (BuildShapeNone,BuildShapeCompound, BuildShapeNames = (BuildShapeNone,BuildShapeCompound,
BuildShapeFuse,BuildShapeCut) BuildShapeFuse,BuildShapeCut,BuildShapeCommon)
class Assembly(AsmGroup): class Assembly(AsmGroup):
_Timer = QtCore.QTimer() _Timer = QtCore.QTimer()
@ -1392,26 +1478,17 @@ class Assembly(AsmGroup):
self.parts = set() self.parts = set()
self.partArrays = set() self.partArrays = set()
self.constraints = None self.constraints = None
self.frozen = False
super(Assembly,self).__init__() super(Assembly,self).__init__()
def allowDuplicateLabel(self,_obj):
return False
def getSubObjects(self,_obj,reason): def getSubObjects(self,_obj,reason):
partGroup = self.getPartGroup() partGroup = self.getPartGroup()
return ['{}.{}'.format(partGroup.Name,name) return ['{}.{}'.format(partGroup.Name,name)
for name in partGroup.getSubObjects(reason)] for name in partGroup.getSubObjects(reason)]
def getSubObject(self,obj,subname,retType,mat,transform,depth):
if obj.BuildShape==BuildShapeNone:
if not subname or subname.startswith(';') or subname.find('.')<0:
_ = depth
if not retType:
return
if transform:
mat *= obj.Placement.toMatrix()
if retType==1:
return (obj,mat)
return (obj,mat,None)
return False
def _collectParts(self,oldParts,newParts,partMap): def _collectParts(self,oldParts,newParts,partMap):
for part in newParts: for part in newParts:
try: try:
@ -1422,22 +1499,24 @@ class Assembly(AsmGroup):
del partMap[part] del partMap[part]
def execute(self,obj): def execute(self,obj):
self.constraints = None
self.buildShape()
System.touch(obj)
obj.ViewObject.Proxy.onExecute()
# collect the part objects of this assembly
parts = set() parts = set()
partArrays = set() partArrays = set()
for cstr in self.getConstraints(): self.constraints = None
for element in cstr.Proxy.getElements():
info = element.Proxy.getInfo() if not self.frozen:
if isinstance(info.Part,tuple): self.buildShape()
partArrays.add(info.Part[0]) System.touch(obj)
parts.add(info.Part[0]) obj.ViewObject.Proxy.onExecute()
else:
parts.add(info.Part) # collect the part objects of this assembly
for cstr in self.getConstraints():
for element in cstr.Proxy.getElements():
info = element.Proxy.getInfo()
if isinstance(info.Part,tuple):
partArrays.add(info.Part[0])
parts.add(info.Part[0])
else:
parts.add(info.Part)
# Update the global part object list for auto solving # Update the global part object list for auto solving
# #
@ -1523,48 +1602,104 @@ class Assembly(AsmGroup):
if not touched: if not touched:
obj.purgeTouched() obj.purgeTouched()
def upgrade(self):
'Upgrade old assembly objects to the new version'
partGroup = self.getPartGroup()
if hasattr(partGroup,'Shape'):
return
partGroup.setPropertyStatus('GroupMode','-Immutable')
partGroup.GroupMode = 0 # prevent auto delete children
newPartGroup = AsmPartGroup.make(self.Object)
newPartGroup.Group = partGroup.Group
newPartGroup.VisibilityList = partGroup.VisibilityList
elementGroup = self.getElementGroup()
vis = elementGroup.VisibilityList
elements = []
old = elementGroup.Group
for element in old:
copy = AsmElement.create('Element',elementGroup)
link = element.LinkedObject
if isinstance(link,tuple):
copy.LinkedObject = (newPartGroup,link[1])
copy.Label = element.Label
copy.Proxy._initializing = False
elements.append(copy)
elementGroup.Group = elements
elementGroup.setPropertyStatus('VisibilityList','-Immutable')
elementGroup.VisibilityList = vis
elementGroup.cacheChildLabel()
for element in old:
old.Document.removeObject(old)
self.Object.setLink({2:newPartGroup})
partGroup.Document.removeObject(partGroup)
def buildShape(self): def buildShape(self):
obj = self.Object obj = self.Object
if obj.BuildShape == BuildShapeNone: partGroup = self.getPartGroup()
if not obj.Shape.isNull(): if not obj.Freeze and obj.BuildShape==BuildShapeNone:
obj.Shape = Part.Shape() obj.Shape = Part.Shape();
if hasattr(partGroup, 'Shape'):
partGroup.Shape = Part.Shape()
return return
shape = []
partGroup = self.getPartGroup()
group = partGroup.Group group = partGroup.Group
if not group:
raise RuntimeError('no parts')
if obj.BuildShape == BuildShapeCut:
shape = Part.getShape(group[0]).Solids
if not shape:
raise RuntimeError('First part has no solid')
if len(shape)>1:
shape = [shape[0].fuse(shape[1:])]
group = group[1:]
for o in group: shapes = []
if obj.isElementVisible(o.Name): if obj.BuildShape == BuildShapeCompound:
shape += Part.getShape(o).Solids for o in group:
if not shape: if obj.isElementVisible(o.Name):
raise RuntimeError('No solids found in parts') shape = Part.getShape(o)
if len(shape) == 1: if not shape.isNull():
obj.Shape = shape[0] shapes.append(shape)
elif obj.BuildShape == BuildShapeFuse:
obj.Shape = shape[0].fuse(shape[1:])
elif obj.BuildShape == BuildShapeCut:
if len(shape)>2:
obj.Shape = shape[0].cut(shape[1].fuse(shape[2:]))
else:
obj.Shape = shape[0].cut(shape[1])
else: else:
obj.Shape = Part.makeCompound(shape) # first shape is always included regardless of its visibility
solids = Part.getShape(group[0]).Solids
if solids:
if len(solids)>1 and obj.BuildShape!=BuildShapeFuse:
shapes.append(solids[0].fuse(solids[1:]))
else:
shapes += solids
group = group[1:]
for o in group:
if obj.isElementVisible(o.Name):
shape = Part.getShape(o)
# in case the first part have solids, we only include
# subsequent part containing solid
if solids:
shapes += shape.Solids
else:
shapes += shape
if not shapes:
raise RuntimeError('No shape found in parts')
if len(shapes) == 1:
shape = shapes[0]
# make sure the 'shape' has identity transform to prevent it from
# messing up with assembly's or partGroup's Placement
if not shape.Placement.isIdentity():
shape = Part.makeCompound(shape)
elif obj.BuildShape == BuildShapeFuse:
shape = shapes[0].fuse(shapes[1:])
elif obj.BuildShape == BuildShapeCut:
shape = shapes[0].cut(shapes[1:])
elif obj.BuildShape == BuildShapeCommon:
shape = shapes[0].common(shapes[1:])
else:
shape = Part.makeCompound(shapes)
if obj.Freeze or obj.BuildShape!=BuildShapeCompound:
partGroup.Shape = shape
elif hasattr(partGroup,'Shape'):
partGroup.Shape = Part.Shape()
shape.Placement = obj.Placement
obj.Shape = shape
def attach(self, obj): def attach(self, obj):
obj.addProperty("App::PropertyEnumeration","BuildShape","Base",'') obj.addProperty("App::PropertyEnumeration","BuildShape","Base",'')
obj.addProperty(
"App::PropertyLinkSubHidden","ColoredElements","Base",'')
obj.setPropertyStatus('ColoredElements',('Hidden','Immutable'))
obj.BuildShape = BuildShapeNames obj.BuildShape = BuildShapeNames
super(Assembly,self).attach(obj) super(Assembly,self).attach(obj)
@ -1573,13 +1708,14 @@ class Assembly(AsmGroup):
self.partArrays = set() self.partArrays = set()
obj.configLinkProperty('Placement') obj.configLinkProperty('Placement')
if not hasattr(obj,'ColoredElements'): if not hasattr(obj,'ColoredElements'):
obj.addProperty( obj.addProperty("App::PropertyLinkSubHidden",
"App::PropertyLinkSubHidden","ColoredElements","Base",'') "ColoredElements","Base",'')
obj.setPropertyStatus('ColoredElements',('Hidden','Immutable')) obj.setPropertyStatus('ColoredElements',('Hidden','Immutable'))
if not hasattr(obj,'Freeze'):
obj.addProperty('App::PropertyBool','Freeze','Base','')
obj.configLinkProperty('ColoredElements') obj.configLinkProperty('ColoredElements')
super(Assembly,self).linkSetup(obj) super(Assembly,self).linkSetup(obj)
System.attach(obj) System.attach(obj)
self.onChanged(obj,'BuildShape')
# make sure all children are there, first constraint group, then element # make sure all children are there, first constraint group, then element
# group, and finally part group. Call getPartGroup below will make sure # group, and finally part group. Call getPartGroup below will make sure
@ -1587,19 +1723,45 @@ class Assembly(AsmGroup):
# correct rendering and picking behavior # correct rendering and picking behavior
self.getPartGroup(True) self.getPartGroup(True)
self.onChanged(obj,'BuildShape')
def onChanged(self, obj, prop): def onChanged(self, obj, prop):
if not getattr(self,'Object',None) or FreeCAD.isRestoring():
return
if prop == 'BuildShape': if prop == 'BuildShape':
if not obj.BuildShape or obj.BuildShape == BuildShapeCompound: self.buildShape()
obj.setPropertyStatus('Shape','-Transient') return
if prop == 'Freeze':
if obj.Freeze == self.frozen:
return
self.upgrade()
for o in self.getElementGroup().Group:
self.freeze(o)
if obj.BuildShape==BuildShapeNone:
self.buildShape()
elif obj.Freeze:
self.getPartGroup().Shape = obj.Shape
else: else:
obj.setPropertyStatus('Shape','Transient') self.getPartGroup().Shape = Part.Shape()
return return
if prop not in _IgnoredProperties: if prop not in _IgnoredProperties:
System.onChanged(obj,prop) System.onChanged(obj,prop)
Assembly.autoSolve() Assembly.autoSolve()
def onDocumentRestored(self,obj):
super(Assembly,self).onDocumentRestored(obj)
partGroup = self.getPartGroup()
self.frozen = obj.Freeze
if self.frozen or hasattr(partGroup,'Shape'):
obj.Shape = partGroup.Shape
elif obj.Shape.isNull() and \
obj.BuildShape == BuildShapeCompound:
self.buildShape()
def getConstraintGroup(self, create=False): def getConstraintGroup(self, create=False):
obj = self.Object obj = self.Object
if obj.Freeze:
return None
try: try:
ret = obj.Group[0] ret = obj.Group[0]
checkType(ret,AsmConstraintGroup) checkType(ret,AsmConstraintGroup)
@ -1694,8 +1856,8 @@ class Assembly(AsmGroup):
if undo: if undo:
FreeCAD.setActiveTransaction('Create assembly') FreeCAD.setActiveTransaction('Create assembly')
try: try:
obj = doc.addObject( obj = doc.addObject("Part::FeaturePython",name,Assembly(),None,True)
"Part::FeaturePython",name,Assembly(),None,True) obj.setPropertyStatus('Shape','Transient')
ViewProviderAssembly(obj.ViewObject) ViewProviderAssembly(obj.ViewObject)
obj.Visibility = True obj.Visibility = True
obj.purgeTouched() obj.purgeTouched()
@ -1805,10 +1967,18 @@ class Assembly(AsmGroup):
class ViewProviderAssembly(ViewProviderAsmGroup): class ViewProviderAssembly(ViewProviderAsmGroup):
_iconName = 'Assembly_Assembly_Frozen_Tree.svg'
_addToSceneGraph = True
def __init__(self,vobj): def __init__(self,vobj):
self._movingPart = None self._movingPart = None
super(ViewProviderAssembly,self).__init__(vobj) super(ViewProviderAssembly,self).__init__(vobj)
def attach(self,vobj):
super(ViewProviderAssembly,self).attach(vobj)
if not hasattr(vobj,'ShowParts'):
vobj.addProperty("App::PropertyBool","ShowParts"," Link")
def onDelete(self,vobj,_subs): def onDelete(self,vobj,_subs):
for o in vobj.Object.Proxy.getPartGroup().Group: for o in vobj.Object.Proxy.getPartGroup().Group:
if o.TypeId == 'App::Origin': if o.TypeId == 'App::Origin':
@ -1843,7 +2013,13 @@ class ViewProviderAssembly(ViewProviderAsmGroup):
partGroup,owner,subname = info partGroup,owner,subname = info
partGroup.dropObject(obj,owner,subname) partGroup.dropObject(obj,owner,subname)
def updateData(self,obj,prop):
if prop == 'Freeze':
obj.ViewObject.signalChangeIcon()
def getIcon(self): def getIcon(self):
if getattr(self.ViewObject.Object,'Freeze',False):
return utils.getIcon(self.__class__)
return System.getIcon(self.ViewObject.Object) return System.getIcon(self.ViewObject.Object)
def doubleClicked(self, _vobj): def doubleClicked(self, _vobj):
@ -1897,6 +2073,24 @@ class ViewProviderAssembly(ViewProviderAsmGroup):
self._movingPart = None self._movingPart = None
return False return False
def showParts(self):
self.ViewObject.Object.Proxy.getPartGroup().ViewObject.Proxy.showParts()
def updateData(self,_obj,prop):
if not hasattr(self,'ViewObject') or FreeCAD.isRestoring():
return
if prop=='Freeze' or prop=='BuildShape':
self.showParts()
def onChanged(self,_vobj,prop):
if not hasattr(self,'ViewObject') or FreeCAD.isRestoring():
return
if prop=='ShowParts':
self.showParts()
def onFinishRestoring(self):
self.showParts()
@classmethod @classmethod
def isBusy(cls): def isBusy(cls):
return cls._Busy return cls._Busy

View File

@ -276,7 +276,7 @@ def _solve(objs=None,recursive=None,reportFailed=True,
for obj in objs: for obj in objs:
if not isTypeOf(obj,Assembly): if not isTypeOf(obj,Assembly):
continue continue
if System.isDisabled(obj): if System.isDisabled(obj) or obj.Freeze:
logger.debug('bypass disabled assembly {}'.format(objName(obj))) logger.debug('bypass disabled assembly {}'.format(objName(obj)))
continue continue
logger.debug('adding assembly {}'.format(objName(obj))) logger.debug('adding assembly {}'.format(objName(obj)))
@ -298,7 +298,7 @@ def _solve(objs=None,recursive=None,reportFailed=True,
for obj in objs: for obj in objs:
if not isTypeOf(obj,Assembly): if not isTypeOf(obj,Assembly):
continue continue
if System.isDisabled(obj): if System.isDisabled(obj) or obj.Freeze:
logger.debug('skip disabled assembly {}'.format(objName(obj))) logger.debug('skip disabled assembly {}'.format(objName(obj)))
continue continue
logger.debug('adding assembly {}'.format(objName(obj))) logger.debug('adding assembly {}'.format(objName(obj)))