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:
parent
9513b774a8
commit
e63118d6b5
374
assembly.py
374
assembly.py
|
@ -83,10 +83,14 @@ class ViewProviderAsmBase(object):
|
|||
vobj.Proxy = self
|
||||
self.attach(vobj)
|
||||
|
||||
_addToSceneGraph = False
|
||||
|
||||
def attach(self,vobj):
|
||||
self.ViewObject = vobj
|
||||
vobj.signalChangeIcon()
|
||||
vobj.setPropertyStatus('Visibility','Hidden')
|
||||
if not self._addToSceneGraph:
|
||||
vobj.Document.ActiveView.getSceneGraph().removeChild(vobj.RootNode)
|
||||
|
||||
def __getstate__(self):
|
||||
return None
|
||||
|
@ -138,6 +142,9 @@ class AsmGroup(AsmBase):
|
|||
obj.addProperty("App::PropertyEnumeration","GroupMode","Base",'')
|
||||
super(AsmGroup,self).attach(obj)
|
||||
|
||||
def allowDuplicateLabel(self,_obj):
|
||||
return True
|
||||
|
||||
|
||||
class ViewProviderAsmGroup(ViewProviderAsmBase):
|
||||
def claimChildren(self):
|
||||
|
@ -166,10 +173,15 @@ class AsmPartGroup(AsmGroup):
|
|||
def groupSetup(self):
|
||||
pass
|
||||
|
||||
def canLoadPartial(self,_obj):
|
||||
return 1 if self.getAssembly().frozen else 0
|
||||
|
||||
@staticmethod
|
||||
def make(parent,name='Parts'):
|
||||
obj = parent.Document.addObject("App::FeaturePython",name,
|
||||
obj = parent.Document.addObject("Part::FeaturePython",name,
|
||||
AsmPartGroup(parent),None,True)
|
||||
obj.setPropertyStatus('Placement',('Output','Hidden'))
|
||||
obj.setPropertyStatus('Shape','Output')
|
||||
ViewProviderAsmPartGroup(obj.ViewObject)
|
||||
obj.purgeTouched()
|
||||
return obj
|
||||
|
@ -193,11 +205,35 @@ class ViewProviderAsmPartGroup(ViewProviderAsmGroup):
|
|||
def canDragAndDropObject(self,_obj):
|
||||
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):
|
||||
def __init__(self,parent):
|
||||
self._initializing = True
|
||||
self.info = None
|
||||
self.shape = None
|
||||
self.parent = getProxy(parent,AsmElementGroup)
|
||||
super(AsmElement,self).__init__()
|
||||
|
||||
|
@ -214,6 +250,7 @@ class AsmElement(AsmBase):
|
|||
obj.setPropertyStatus('LinkTransform',['Immutable','Hidden'])
|
||||
obj.configLinkProperty('LinkedObject','Placement','LinkTransform')
|
||||
obj.setPropertyStatus('LinkedObject','ReadOnly')
|
||||
self.shape = None
|
||||
|
||||
def attach(self,obj):
|
||||
obj.addProperty("App::PropertyXLink","LinkedObject"," Link",'')
|
||||
|
@ -235,7 +272,7 @@ class AsmElement(AsmBase):
|
|||
if not parent or FreeCAD.isRestoring():
|
||||
return
|
||||
if prop=='Offset':
|
||||
self.updatePlacement()
|
||||
self.update()
|
||||
elif prop == 'Label':
|
||||
parent.Object.cacheChildLabel()
|
||||
if prop not in _IgnoredProperties and \
|
||||
|
@ -247,23 +284,29 @@ class AsmElement(AsmBase):
|
|||
return False
|
||||
|
||||
def updatePlacement(self):
|
||||
obj = getattr(self,'Object',None)
|
||||
if not obj:
|
||||
obj = self.Object
|
||||
info = getElementInfo(self.getAssembly().getPartGroup(),
|
||||
self.getElementSubname(),offset=self.Object.Offset)
|
||||
if not info:
|
||||
return
|
||||
if obj.Offset.isIdentity():
|
||||
if obj.Placement.isIdentity():
|
||||
return
|
||||
pla = FreeCAD.Placement()
|
||||
else:
|
||||
info = getElementInfo(self.getAssembly().getPartGroup(),
|
||||
self.getElementSubname(),offset=self.Object.Offset)
|
||||
if not info or \
|
||||
utils.isSamePlacement(info.PlacementOffset,obj.Placement):
|
||||
return
|
||||
pla = info.PlacementOffset
|
||||
obj.setPropertyStatus('Placement','-Immutable')
|
||||
obj.Placement = pla
|
||||
obj.setPropertyStatus('Placement','Immutable')
|
||||
self.shape = info.Shape
|
||||
if not utils.isSamePlacement(info.PlacementOffset,obj.Placement):
|
||||
obj.setPropertyStatus('Placement','-Immutable')
|
||||
obj.Placement = info.PlacementOffset
|
||||
obj.setPropertyStatus('Placement','Immutable')
|
||||
|
||||
def freeze(self):
|
||||
obj = self.Object
|
||||
if self.getAssembly().Freeze:
|
||||
if not self.shape:
|
||||
self.updatePlacement();
|
||||
if self.shape:
|
||||
# make a compound to contain the shape's transformation
|
||||
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):
|
||||
return self.parent.parent
|
||||
|
@ -383,8 +426,8 @@ class AsmElement(AsmBase):
|
|||
|
||||
@classmethod
|
||||
def create(cls,name,elements):
|
||||
element = elements.Document.addObject("App::FeaturePython",
|
||||
name,cls(elements),None,True)
|
||||
element = elements.Document.addObject("Part::FeaturePython",
|
||||
name,cls(elements),None,True)
|
||||
ViewProviderAsmElement(element.ViewObject)
|
||||
return element
|
||||
|
||||
|
@ -560,6 +603,22 @@ class ViewProviderAsmElement(ViewProviderAsmOnTop):
|
|||
AsmElement.make(AsmElement.Selection(Element=vobj.Object,
|
||||
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):
|
||||
def __init__(self,obj,parent):
|
||||
|
@ -596,6 +655,9 @@ class AsmElementSketch(AsmElement):
|
|||
ret[0] = obj
|
||||
return ret
|
||||
|
||||
def freeze(self):
|
||||
pass
|
||||
|
||||
|
||||
class ViewProviderAsmElementSketch(ViewProviderAsmElement):
|
||||
def getIcon(self):
|
||||
|
@ -612,6 +674,10 @@ class ViewProviderAsmElementSketch(ViewProviderAsmElement):
|
|||
return subs[-1]
|
||||
return ''
|
||||
|
||||
def updateData(self,obj,prop):
|
||||
_ = obj
|
||||
_ = prop
|
||||
|
||||
|
||||
ElementInfo = namedtuple('AsmElementInfo', ('Parent','SubnameRef','Part',
|
||||
'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)
|
||||
|
||||
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:
|
||||
|
||||
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
|
||||
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
|
||||
|
@ -795,6 +873,7 @@ class AsmElementLink(AsmBase):
|
|||
super(AsmElementLink,self).linkSetup(obj)
|
||||
obj.configLinkProperty('LinkedObject')
|
||||
obj.setPropertyStatus('LinkedObject','ReadOnly')
|
||||
self.info = None
|
||||
|
||||
def attach(self,obj):
|
||||
obj.addProperty("App::PropertyXLink","LinkedObject"," Link",'')
|
||||
|
@ -898,6 +977,9 @@ class AsmElementLink(AsmBase):
|
|||
return
|
||||
self.info = getElementInfo(self.getAssembly().getPartGroup(),
|
||||
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
|
||||
|
||||
@staticmethod
|
||||
|
@ -1275,6 +1357,9 @@ class AsmConstraintGroup(AsmGroup):
|
|||
def getAssembly(self):
|
||||
return self.parent
|
||||
|
||||
def canLoadPartial(self,_obj):
|
||||
return 2 if self.getAssembly().frozen else 0
|
||||
|
||||
def linkSetup(self,obj):
|
||||
super(AsmConstraintGroup,self).linkSetup(obj)
|
||||
for o in obj.Group:
|
||||
|
@ -1380,8 +1465,9 @@ BuildShapeNone = 'None'
|
|||
BuildShapeCompound = 'Compound'
|
||||
BuildShapeFuse = 'Fuse'
|
||||
BuildShapeCut = 'Cut'
|
||||
BuildShapeCommon = 'Common'
|
||||
BuildShapeNames = (BuildShapeNone,BuildShapeCompound,
|
||||
BuildShapeFuse,BuildShapeCut)
|
||||
BuildShapeFuse,BuildShapeCut,BuildShapeCommon)
|
||||
|
||||
class Assembly(AsmGroup):
|
||||
_Timer = QtCore.QTimer()
|
||||
|
@ -1392,26 +1478,17 @@ class Assembly(AsmGroup):
|
|||
self.parts = set()
|
||||
self.partArrays = set()
|
||||
self.constraints = None
|
||||
self.frozen = False
|
||||
super(Assembly,self).__init__()
|
||||
|
||||
def allowDuplicateLabel(self,_obj):
|
||||
return False
|
||||
|
||||
def getSubObjects(self,_obj,reason):
|
||||
partGroup = self.getPartGroup()
|
||||
return ['{}.{}'.format(partGroup.Name,name)
|
||||
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):
|
||||
for part in newParts:
|
||||
try:
|
||||
|
@ -1422,22 +1499,24 @@ class Assembly(AsmGroup):
|
|||
del partMap[part]
|
||||
|
||||
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()
|
||||
partArrays = set()
|
||||
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)
|
||||
self.constraints = None
|
||||
|
||||
if not self.frozen:
|
||||
self.buildShape()
|
||||
System.touch(obj)
|
||||
obj.ViewObject.Proxy.onExecute()
|
||||
|
||||
# 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
|
||||
#
|
||||
|
@ -1523,48 +1602,104 @@ class Assembly(AsmGroup):
|
|||
if not touched:
|
||||
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):
|
||||
obj = self.Object
|
||||
if obj.BuildShape == BuildShapeNone:
|
||||
if not obj.Shape.isNull():
|
||||
obj.Shape = Part.Shape()
|
||||
partGroup = self.getPartGroup()
|
||||
if not obj.Freeze and obj.BuildShape==BuildShapeNone:
|
||||
obj.Shape = Part.Shape();
|
||||
if hasattr(partGroup, 'Shape'):
|
||||
partGroup.Shape = Part.Shape()
|
||||
return
|
||||
|
||||
shape = []
|
||||
partGroup = self.getPartGroup()
|
||||
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:
|
||||
if obj.isElementVisible(o.Name):
|
||||
shape += Part.getShape(o).Solids
|
||||
if not shape:
|
||||
raise RuntimeError('No solids found in parts')
|
||||
if len(shape) == 1:
|
||||
obj.Shape = shape[0]
|
||||
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])
|
||||
shapes = []
|
||||
if obj.BuildShape == BuildShapeCompound:
|
||||
for o in group:
|
||||
if obj.isElementVisible(o.Name):
|
||||
shape = Part.getShape(o)
|
||||
if not shape.isNull():
|
||||
shapes.append(shape)
|
||||
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):
|
||||
obj.addProperty("App::PropertyEnumeration","BuildShape","Base",'')
|
||||
obj.addProperty(
|
||||
"App::PropertyLinkSubHidden","ColoredElements","Base",'')
|
||||
obj.setPropertyStatus('ColoredElements',('Hidden','Immutable'))
|
||||
obj.BuildShape = BuildShapeNames
|
||||
super(Assembly,self).attach(obj)
|
||||
|
||||
|
@ -1573,13 +1708,14 @@ class Assembly(AsmGroup):
|
|||
self.partArrays = set()
|
||||
obj.configLinkProperty('Placement')
|
||||
if not hasattr(obj,'ColoredElements'):
|
||||
obj.addProperty(
|
||||
"App::PropertyLinkSubHidden","ColoredElements","Base",'')
|
||||
obj.setPropertyStatus('ColoredElements',('Hidden','Immutable'))
|
||||
obj.addProperty("App::PropertyLinkSubHidden",
|
||||
"ColoredElements","Base",'')
|
||||
obj.setPropertyStatus('ColoredElements',('Hidden','Immutable'))
|
||||
if not hasattr(obj,'Freeze'):
|
||||
obj.addProperty('App::PropertyBool','Freeze','Base','')
|
||||
obj.configLinkProperty('ColoredElements')
|
||||
super(Assembly,self).linkSetup(obj)
|
||||
System.attach(obj)
|
||||
self.onChanged(obj,'BuildShape')
|
||||
|
||||
# make sure all children are there, first constraint group, then element
|
||||
# group, and finally part group. Call getPartGroup below will make sure
|
||||
|
@ -1587,19 +1723,45 @@ class Assembly(AsmGroup):
|
|||
# correct rendering and picking behavior
|
||||
self.getPartGroup(True)
|
||||
|
||||
self.onChanged(obj,'BuildShape')
|
||||
|
||||
def onChanged(self, obj, prop):
|
||||
if not getattr(self,'Object',None) or FreeCAD.isRestoring():
|
||||
return
|
||||
if prop == 'BuildShape':
|
||||
if not obj.BuildShape or obj.BuildShape == BuildShapeCompound:
|
||||
obj.setPropertyStatus('Shape','-Transient')
|
||||
self.buildShape()
|
||||
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:
|
||||
obj.setPropertyStatus('Shape','Transient')
|
||||
self.getPartGroup().Shape = Part.Shape()
|
||||
return
|
||||
if prop not in _IgnoredProperties:
|
||||
System.onChanged(obj,prop)
|
||||
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):
|
||||
obj = self.Object
|
||||
if obj.Freeze:
|
||||
return None
|
||||
try:
|
||||
ret = obj.Group[0]
|
||||
checkType(ret,AsmConstraintGroup)
|
||||
|
@ -1694,8 +1856,8 @@ class Assembly(AsmGroup):
|
|||
if undo:
|
||||
FreeCAD.setActiveTransaction('Create assembly')
|
||||
try:
|
||||
obj = doc.addObject(
|
||||
"Part::FeaturePython",name,Assembly(),None,True)
|
||||
obj = doc.addObject("Part::FeaturePython",name,Assembly(),None,True)
|
||||
obj.setPropertyStatus('Shape','Transient')
|
||||
ViewProviderAssembly(obj.ViewObject)
|
||||
obj.Visibility = True
|
||||
obj.purgeTouched()
|
||||
|
@ -1805,10 +1967,18 @@ class Assembly(AsmGroup):
|
|||
|
||||
|
||||
class ViewProviderAssembly(ViewProviderAsmGroup):
|
||||
_iconName = 'Assembly_Assembly_Frozen_Tree.svg'
|
||||
_addToSceneGraph = True
|
||||
|
||||
def __init__(self,vobj):
|
||||
self._movingPart = None
|
||||
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):
|
||||
for o in vobj.Object.Proxy.getPartGroup().Group:
|
||||
if o.TypeId == 'App::Origin':
|
||||
|
@ -1843,7 +2013,13 @@ class ViewProviderAssembly(ViewProviderAsmGroup):
|
|||
partGroup,owner,subname = info
|
||||
partGroup.dropObject(obj,owner,subname)
|
||||
|
||||
def updateData(self,obj,prop):
|
||||
if prop == 'Freeze':
|
||||
obj.ViewObject.signalChangeIcon()
|
||||
|
||||
def getIcon(self):
|
||||
if getattr(self.ViewObject.Object,'Freeze',False):
|
||||
return utils.getIcon(self.__class__)
|
||||
return System.getIcon(self.ViewObject.Object)
|
||||
|
||||
def doubleClicked(self, _vobj):
|
||||
|
@ -1897,6 +2073,24 @@ class ViewProviderAssembly(ViewProviderAsmGroup):
|
|||
self._movingPart = None
|
||||
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
|
||||
def isBusy(cls):
|
||||
return cls._Busy
|
||||
|
|
|
@ -276,7 +276,7 @@ def _solve(objs=None,recursive=None,reportFailed=True,
|
|||
for obj in objs:
|
||||
if not isTypeOf(obj,Assembly):
|
||||
continue
|
||||
if System.isDisabled(obj):
|
||||
if System.isDisabled(obj) or obj.Freeze:
|
||||
logger.debug('bypass disabled assembly {}'.format(objName(obj)))
|
||||
continue
|
||||
logger.debug('adding assembly {}'.format(objName(obj)))
|
||||
|
@ -298,7 +298,7 @@ def _solve(objs=None,recursive=None,reportFailed=True,
|
|||
for obj in objs:
|
||||
if not isTypeOf(obj,Assembly):
|
||||
continue
|
||||
if System.isDisabled(obj):
|
||||
if System.isDisabled(obj) or obj.Freeze:
|
||||
logger.debug('skip disabled assembly {}'.format(objName(obj)))
|
||||
continue
|
||||
logger.debug('adding assembly {}'.format(objName(obj)))
|
||||
|
|
Loading…
Reference in New Issue
Block a user