parent
a7887bd177
commit
e73ad4cc87
381
assembly.py
381
assembly.py
|
@ -41,6 +41,59 @@ def setLinkProperty(obj,name,val):
|
||||||
obj = obj.getLinkedObject(True)
|
obj = obj.getLinkedObject(True)
|
||||||
setattr(obj,obj.getLinkExtPropertyName(name),val)
|
setattr(obj,obj.getLinkExtPropertyName(name),val)
|
||||||
|
|
||||||
|
def flattenSubname(obj,subname):
|
||||||
|
func = getattr(obj,'flattenSubname',None)
|
||||||
|
if not func:
|
||||||
|
return subname
|
||||||
|
return func(subname)
|
||||||
|
|
||||||
|
def flattenSubnameRecursive(obj,subname):
|
||||||
|
r = Assembly.find(obj,subname,recursive=True)[-1]
|
||||||
|
return subname[:-len(r.Subname)] + flattenSubname(r.Object,r.Subname)
|
||||||
|
|
||||||
|
def expandSubname(obj,subname):
|
||||||
|
func = getattr(obj,'expandSubname',None)
|
||||||
|
if not func:
|
||||||
|
return subname
|
||||||
|
return func(subname)
|
||||||
|
|
||||||
|
def flattenGroup(obj):
|
||||||
|
group = getattr(obj,'LinkedChildren',None)
|
||||||
|
if group is None:
|
||||||
|
return obj.Group
|
||||||
|
return group
|
||||||
|
|
||||||
|
def editGroup(obj,children):
|
||||||
|
if 'Immutable' in obj.getPropertyStatus('Group'):
|
||||||
|
obj.setPropertyStatus('Group','-Immutable')
|
||||||
|
obj.Group = children
|
||||||
|
obj.setPropertyStatus('Group','Immutable')
|
||||||
|
else:
|
||||||
|
obj.Group = children
|
||||||
|
|
||||||
|
def setupSortMenu(menu,func,func2):
|
||||||
|
action = QtGui.QAction(QtGui.QIcon(),"Sort A~Z",menu)
|
||||||
|
QtCore.QObject.connect(action,QtCore.SIGNAL("triggered()"),func)
|
||||||
|
menu.addAction(action)
|
||||||
|
action = QtGui.QAction(QtGui.QIcon(),"Sort Z~A",menu)
|
||||||
|
QtCore.QObject.connect(
|
||||||
|
action,QtCore.SIGNAL("triggered()"),func2)
|
||||||
|
menu.addAction(action)
|
||||||
|
|
||||||
|
def sortChildren(obj,reverse):
|
||||||
|
group = [ (o,o.Label) for o in obj.Group ]
|
||||||
|
group = sorted(group,reverse=reverse,key=lambda x:x[1])
|
||||||
|
touched = 'Touched' in obj.State
|
||||||
|
FreeCAD.setActiveTransaction('Sort children')
|
||||||
|
try:
|
||||||
|
editGroup(obj, [o[0] for o in group])
|
||||||
|
except Exception:
|
||||||
|
FreeCAD.closeActiveTransaction(True)
|
||||||
|
raise
|
||||||
|
FreeCAD.closeActiveTransaction()
|
||||||
|
if not touched:
|
||||||
|
obj.purgeTouched()
|
||||||
|
|
||||||
def resolveAssembly(obj):
|
def resolveAssembly(obj):
|
||||||
'''Try various ways to obtain an assembly from the input object
|
'''Try various ways to obtain an assembly from the input object
|
||||||
|
|
||||||
|
@ -199,9 +252,9 @@ class AsmPartGroup(AsmGroup):
|
||||||
self.derivedParts = None
|
self.derivedParts = None
|
||||||
return
|
return
|
||||||
|
|
||||||
parts = set(obj.Group)
|
parts = set(obj.LinkedObject)
|
||||||
derived = obj.DerivedFrom.getLinkedObject(True).Proxy.getPartGroup()
|
derived = obj.DerivedFrom.getLinkedObject(True).Proxy.getPartGroup()
|
||||||
self.derivedParts = derived.Group
|
self.derivedParts = derived.LinkedObject
|
||||||
newParts = obj.Group
|
newParts = obj.Group
|
||||||
vis = list(obj.VisibilityList)
|
vis = list(obj.VisibilityList)
|
||||||
touched = False
|
touched = False
|
||||||
|
@ -231,7 +284,7 @@ class AsmPartGroup(AsmGroup):
|
||||||
return
|
return
|
||||||
if prop == 'DerivedFrom':
|
if prop == 'DerivedFrom':
|
||||||
self.checkDerivedParts()
|
self.checkDerivedParts()
|
||||||
elif prop == 'Group':
|
elif prop in ('Group','_ChildCache'):
|
||||||
parent = getattr(self,'parent',None)
|
parent = getattr(self,'parent',None)
|
||||||
if parent and not self.parent.Object.Freeze:
|
if parent and not self.parent.Object.Freeze:
|
||||||
relationGroup = parent.getRelationGroup()
|
relationGroup = parent.getRelationGroup()
|
||||||
|
@ -343,6 +396,10 @@ class AsmElement(AsmBase):
|
||||||
obj.setPropertyStatus('LinkedObject','ReadOnly')
|
obj.setPropertyStatus('LinkedObject','ReadOnly')
|
||||||
obj.configLinkProperty('LinkedObject','Placement','LinkTransform')
|
obj.configLinkProperty('LinkedObject','Placement','LinkTransform')
|
||||||
|
|
||||||
|
parent = getattr(obj,'_Parent',None)
|
||||||
|
if parent:
|
||||||
|
self.parent = parent.Proxy
|
||||||
|
|
||||||
AsmElement.migrate(obj)
|
AsmElement.migrate(obj)
|
||||||
|
|
||||||
self.version = AsmVersion()
|
self.version = AsmVersion()
|
||||||
|
@ -369,6 +426,9 @@ class AsmElement(AsmBase):
|
||||||
|
|
||||||
def attach(self,obj):
|
def attach(self,obj):
|
||||||
obj.addProperty("App::PropertyXLink","LinkedObject"," Link",'')
|
obj.addProperty("App::PropertyXLink","LinkedObject"," Link",'')
|
||||||
|
obj.addProperty("App::PropertyLinkHidden","_Parent"," Link",'')
|
||||||
|
obj._Parent = self.parent.Object
|
||||||
|
obj.setPropertyStatus('_Parent',('Hidden','Immutable'))
|
||||||
super(AsmElement,self).attach(obj)
|
super(AsmElement,self).attach(obj)
|
||||||
|
|
||||||
def getViewProviderName(self,_obj):
|
def getViewProviderName(self,_obj):
|
||||||
|
@ -644,10 +704,14 @@ class AsmElement(AsmBase):
|
||||||
for i,hierarchy in enumerate(hierarchies):
|
for i,hierarchy in enumerate(hierarchies):
|
||||||
for path in hierarchy:
|
for path in hierarchy:
|
||||||
if path.Assembly == assembly:
|
if path.Assembly == assembly:
|
||||||
|
sub = flattenSubname(path.Object,
|
||||||
|
path.Subname[path.Subname.index('.')+1:])
|
||||||
hierarchies[i] = AsmElement.Selection(
|
hierarchies[i] = AsmElement.Selection(
|
||||||
Element=element,Group=path.Object,
|
Element=element,
|
||||||
Subname=path.Subname[path.Subname.index('.')+1:],
|
Group=path.Object,
|
||||||
SelObj=selObj, SelSubname=selSubname)
|
Subname=sub,
|
||||||
|
SelObj=selObj,
|
||||||
|
SelSubname=selSubname)
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
raise RuntimeError('parent assembly mismatch')
|
raise RuntimeError('parent assembly mismatch')
|
||||||
|
@ -763,7 +827,7 @@ class AsmElement(AsmBase):
|
||||||
|
|
||||||
# This give us reference to child assembly's immediate child
|
# This give us reference to child assembly's immediate child
|
||||||
# without trailing dot.
|
# without trailing dot.
|
||||||
prefix = subname[:len(subname)-len(ret.Subname)-1]
|
prefix = subname[:-len(ret.Subname)+1]
|
||||||
|
|
||||||
# Pop the immediate child name, and replace it with child
|
# Pop the immediate child name, and replace it with child
|
||||||
# assembly's element group name
|
# assembly's element group name
|
||||||
|
@ -793,7 +857,7 @@ class AsmElement(AsmBase):
|
||||||
if not element:
|
if not element:
|
||||||
if not allowDuplicate:
|
if not allowDuplicate:
|
||||||
# try to search the element group for an existing element
|
# try to search the element group for an existing element
|
||||||
for e in elements.Group:
|
for e in flattenGroup(elements):
|
||||||
if not e.Offset.isIdentity():
|
if not e.Offset.isIdentity():
|
||||||
continue
|
continue
|
||||||
sub = logger.catch('',e.Proxy.getSubName)
|
sub = logger.catch('',e.Proxy.getSubName)
|
||||||
|
@ -976,11 +1040,10 @@ def getElementInfo(parent,subname,
|
||||||
subnameRef = subname
|
subnameRef = subname
|
||||||
parentSave = parent
|
parentSave = parent
|
||||||
|
|
||||||
names = subname.split('.')
|
|
||||||
if isTypeOf(parent,Assembly,True):
|
if isTypeOf(parent,Assembly,True):
|
||||||
parent = parent.getSubObject(names[0]+'.',1)
|
idx = subname.index('.')
|
||||||
names = names[1:]
|
parent = parent.getSubObject(subname[:idx+1],1)
|
||||||
subname = '.'.join(names)
|
subname = subname[idx+1:]
|
||||||
|
|
||||||
if isTypeOf(parent,(AsmElementGroup,AsmConstraintGroup)):
|
if isTypeOf(parent,(AsmElementGroup,AsmConstraintGroup)):
|
||||||
child = parent.getSubObject(subname,1)
|
child = parent.getSubObject(subname,1)
|
||||||
|
@ -988,7 +1051,6 @@ def getElementInfo(parent,subname,
|
||||||
raise RuntimeError('Invalid sub-object {}, {}'.format(
|
raise RuntimeError('Invalid sub-object {}, {}'.format(
|
||||||
objName(parent), subname))
|
objName(parent), subname))
|
||||||
subname = child.Proxy.getElementSubname(recursive)
|
subname = child.Proxy.getElementSubname(recursive)
|
||||||
names = subname.split('.')
|
|
||||||
partGroup = parent.Proxy.getAssembly().getPartGroup()
|
partGroup = parent.Proxy.getAssembly().getPartGroup()
|
||||||
|
|
||||||
elif isTypeOf(parent,AsmPartGroup):
|
elif isTypeOf(parent,AsmPartGroup):
|
||||||
|
@ -997,6 +1059,8 @@ def getElementInfo(parent,subname,
|
||||||
raise RuntimeError('{} is not Assembly or PartGroup'.format(
|
raise RuntimeError('{} is not Assembly or PartGroup'.format(
|
||||||
objName(parent)))
|
objName(parent)))
|
||||||
|
|
||||||
|
subname = flattenSubname(partGroup,subname)
|
||||||
|
names = subname.split('.')
|
||||||
part = partGroup.getSubObject(names[0]+'.',1)
|
part = partGroup.getSubObject(names[0]+'.',1)
|
||||||
if not part:
|
if not part:
|
||||||
raise RuntimeError('Invalid sub-object {}, {}'.format(
|
raise RuntimeError('Invalid sub-object {}, {}'.format(
|
||||||
|
@ -1114,6 +1178,9 @@ class AsmElementLink(AsmBase):
|
||||||
|
|
||||||
def linkSetup(self,obj):
|
def linkSetup(self,obj):
|
||||||
super(AsmElementLink,self).linkSetup(obj)
|
super(AsmElementLink,self).linkSetup(obj)
|
||||||
|
parent = getattr(obj,'_Parent',None)
|
||||||
|
if parent:
|
||||||
|
self.parent = parent.Proxy
|
||||||
obj.setPropertyStatus('LinkedObject','ReadOnly')
|
obj.setPropertyStatus('LinkedObject','ReadOnly')
|
||||||
if not hasattr(obj,'Offset'):
|
if not hasattr(obj,'Offset'):
|
||||||
obj.addProperty("App::PropertyPlacement","Offset"," Link",'')
|
obj.addProperty("App::PropertyPlacement","Offset"," Link",'')
|
||||||
|
@ -1163,6 +1230,9 @@ class AsmElementLink(AsmBase):
|
||||||
|
|
||||||
def attach(self,obj):
|
def attach(self,obj):
|
||||||
obj.addProperty("App::PropertyXLink","LinkedObject"," Link",'')
|
obj.addProperty("App::PropertyXLink","LinkedObject"," Link",'')
|
||||||
|
obj.addProperty("App::PropertyLinkHidden","_Parent"," Link",'')
|
||||||
|
obj._Parent = self.parent.Object
|
||||||
|
obj.setPropertyStatus('_Parent',('Hidden','Immutable'))
|
||||||
super(AsmElementLink,self).attach(obj)
|
super(AsmElementLink,self).attach(obj)
|
||||||
|
|
||||||
def canLinkProperties(self,_obj):
|
def canLinkProperties(self,_obj):
|
||||||
|
@ -1218,7 +1288,9 @@ class AsmElementLink(AsmBase):
|
||||||
return
|
return
|
||||||
if prop == 'NoExpand':
|
if prop == 'NoExpand':
|
||||||
cstr = self.parent.Object
|
cstr = self.parent.Object
|
||||||
if obj!=cstr.Group[0] and cstr.Multiply and obj.LinkedObject:
|
if obj!=flattenGroup(cstr)[0] \
|
||||||
|
and cstr.Multiply \
|
||||||
|
and obj.LinkedObject:
|
||||||
self.setLink(self.getAssembly().getPartGroup(),
|
self.setLink(self.getAssembly().getPartGroup(),
|
||||||
self.getElementSubname(True))
|
self.getElementSubname(True))
|
||||||
return
|
return
|
||||||
|
@ -1283,7 +1355,7 @@ class AsmElementLink(AsmBase):
|
||||||
def setLink(self,owner,subname,checkOnly=False,multiply=False):
|
def setLink(self,owner,subname,checkOnly=False,multiply=False):
|
||||||
obj = self.Object
|
obj = self.Object
|
||||||
cstr = self.parent.Object
|
cstr = self.parent.Object
|
||||||
elements = cstr.Group
|
elements = flattenGroup(cstr)
|
||||||
radius = None
|
radius = None
|
||||||
if (multiply or Constraint.canMultiply(cstr)) and \
|
if (multiply or Constraint.canMultiply(cstr)) and \
|
||||||
obj!=elements[0] and \
|
obj!=elements[0] and \
|
||||||
|
@ -1402,7 +1474,7 @@ class AsmElementLink(AsmBase):
|
||||||
return self.infos if expand else self.info
|
return self.infos if expand else self.info
|
||||||
|
|
||||||
self.multiply = True
|
self.multiply = True
|
||||||
if obj == parent.Group[0]:
|
if obj == flattenGroup(parent)[0]:
|
||||||
if not isinstance(info.Part,tuple) or \
|
if not isinstance(info.Part,tuple) or \
|
||||||
getLinkProperty(info.Part[0],'ElementCount')!=obj.Count:
|
getLinkProperty(info.Part[0],'ElementCount')!=obj.Count:
|
||||||
self.infos.append(info)
|
self.infos.append(info)
|
||||||
|
@ -1588,27 +1660,29 @@ class AsmConstraint(AsmGroup):
|
||||||
Assembly.autoSolve(obj,prop)
|
Assembly.autoSolve(obj,prop)
|
||||||
|
|
||||||
def childVersion(self):
|
def childVersion(self):
|
||||||
return [(o,o.Proxy.version.value) for o in self.Object.Group]
|
return [(o,o.Proxy.version.value) \
|
||||||
|
for o in flattenGroup(self.Object)]
|
||||||
|
|
||||||
def linkSetup(self,obj):
|
def linkSetup(self,obj):
|
||||||
|
parent = getattr(obj,'_Parent',None)
|
||||||
|
if parent:
|
||||||
|
self.parent = parent.Proxy
|
||||||
self.elements = None
|
self.elements = None
|
||||||
super(AsmConstraint,self).linkSetup(obj)
|
super(AsmConstraint,self).linkSetup(obj)
|
||||||
group = obj.Group
|
|
||||||
for o in group:
|
|
||||||
getProxy(o,AsmElementLink).parent = self
|
|
||||||
if gui.AsmCmdManager.AutoElementVis:
|
|
||||||
obj.setPropertyStatus('VisibilityList','-Immutable')
|
|
||||||
obj.VisibilityList = [False]*len(group)
|
|
||||||
obj.setPropertyStatus('VisibilityList','Immutable')
|
|
||||||
obj.setPropertyStatus('VisibilityList','NoModify')
|
|
||||||
Constraint.attach(obj)
|
Constraint.attach(obj)
|
||||||
self.version = AsmVersion()
|
self.version = AsmVersion()
|
||||||
|
|
||||||
|
def attach(self,obj):
|
||||||
|
obj.addProperty("App::PropertyLinkHidden","_Parent"," Link",'')
|
||||||
|
obj._Parent = self.parent.Object
|
||||||
|
obj.setPropertyStatus('_Parent',('Hidden','Immutable'))
|
||||||
|
super(AsmConstraint,self).attach(obj)
|
||||||
|
|
||||||
def checkMultiply(self):
|
def checkMultiply(self):
|
||||||
obj = self.Object
|
obj = self.Object
|
||||||
if not obj.Multiply:
|
if not obj.Multiply:
|
||||||
return
|
return
|
||||||
children = obj.Group
|
children = flattenGroup(obj)
|
||||||
if len(children)<=1:
|
if len(children)<=1:
|
||||||
return
|
return
|
||||||
count = 0
|
count = 0
|
||||||
|
@ -1835,7 +1909,7 @@ class AsmConstraint(AsmGroup):
|
||||||
|
|
||||||
elementInfo = []
|
elementInfo = []
|
||||||
elements = []
|
elements = []
|
||||||
group = obj.Group
|
group = flattenGroup(obj)
|
||||||
if Constraint.canMultiply(obj):
|
if Constraint.canMultiply(obj):
|
||||||
firstInfo = group[0].Proxy.getInfo(expand=True)
|
firstInfo = group[0].Proxy.getInfo(expand=True)
|
||||||
count = len(firstInfo)
|
count = len(firstInfo)
|
||||||
|
@ -1971,7 +2045,7 @@ class AsmConstraint(AsmGroup):
|
||||||
if cstr:
|
if cstr:
|
||||||
typeid = Constraint.getTypeID(cstr)
|
typeid = Constraint.getTypeID(cstr)
|
||||||
check = []
|
check = []
|
||||||
for o in cstr.Group:
|
for o in flattenGroup(cstr):
|
||||||
check.append(o.Proxy.getInfo())
|
check.append(o.Proxy.getInfo())
|
||||||
elementInfo = check + elementInfo
|
elementInfo = check + elementInfo
|
||||||
|
|
||||||
|
@ -2010,7 +2084,7 @@ class AsmConstraint(AsmGroup):
|
||||||
|
|
||||||
if gui.AsmCmdManager.AutoElementVis:
|
if gui.AsmCmdManager.AutoElementVis:
|
||||||
cstr.setPropertyStatus('VisibilityList','-Immutable')
|
cstr.setPropertyStatus('VisibilityList','-Immutable')
|
||||||
cstr.VisibilityList = [False]*len(cstr.Group)
|
cstr.VisibilityList = [False]*len(flattenGroup(cstr))
|
||||||
cstr.setPropertyStatus('VisibilityList','Immutable')
|
cstr.setPropertyStatus('VisibilityList','Immutable')
|
||||||
|
|
||||||
cstr.Proxy._initializing = False
|
cstr.Proxy._initializing = False
|
||||||
|
@ -2110,7 +2184,7 @@ class AsmConstraint(AsmGroup):
|
||||||
Elements = info)
|
Elements = info)
|
||||||
newCstr = AsmConstraint.make(typeid,sel,undo=False)
|
newCstr = AsmConstraint.make(typeid,sel,undo=False)
|
||||||
Constraint.copy(cstr,newCstr)
|
Constraint.copy(cstr,newCstr)
|
||||||
for element,target in zip(elements,newCstr.Group):
|
for element,target in zip(elements,flattenGroup(newCstr)):
|
||||||
target.Offset = element.Offset
|
target.Offset = element.Offset
|
||||||
cstr.Document.removeObject(cstr.Name)
|
cstr.Document.removeObject(cstr.Name)
|
||||||
FreeCAD.closeActiveTransaction()
|
FreeCAD.closeActiveTransaction()
|
||||||
|
@ -2221,10 +2295,6 @@ class AsmConstraintGroup(AsmGroup):
|
||||||
if not hasattr(obj,'_Version'):
|
if not hasattr(obj,'_Version'):
|
||||||
obj.addProperty("App::PropertyInteger","_Version","Base",'')
|
obj.addProperty("App::PropertyInteger","_Version","Base",'')
|
||||||
obj.setPropertyStatus('_Version',['Hidden','Output'])
|
obj.setPropertyStatus('_Version',['Hidden','Output'])
|
||||||
for o in obj.Group:
|
|
||||||
cstr = getProxy(o,AsmConstraint)
|
|
||||||
if cstr:
|
|
||||||
cstr.parent = self
|
|
||||||
|
|
||||||
def onChanged(self,obj,prop):
|
def onChanged(self,obj,prop):
|
||||||
if obj.Removing or FreeCAD.isRestoring():
|
if obj.Removing or FreeCAD.isRestoring():
|
||||||
|
@ -2269,8 +2339,6 @@ class AsmElementGroup(AsmGroup):
|
||||||
|
|
||||||
def linkSetup(self,obj):
|
def linkSetup(self,obj):
|
||||||
super(AsmElementGroup,self).linkSetup(obj)
|
super(AsmElementGroup,self).linkSetup(obj)
|
||||||
for o in obj.Group:
|
|
||||||
getProxy(o,AsmElement).parent = self
|
|
||||||
obj.cacheChildLabel()
|
obj.cacheChildLabel()
|
||||||
# 'PartialTrigger' is just for silencing warning when partial load
|
# 'PartialTrigger' is just for silencing warning when partial load
|
||||||
self.Object.setPropertyStatus('VisibilityList', 'PartialTrigger')
|
self.Object.setPropertyStatus('VisibilityList', 'PartialTrigger')
|
||||||
|
@ -2283,7 +2351,7 @@ class AsmElementGroup(AsmGroup):
|
||||||
def onChildLabelChange(self,obj,label):
|
def onChildLabelChange(self,obj,label):
|
||||||
names = set()
|
names = set()
|
||||||
label = label.replace('.','_')
|
label = label.replace('.','_')
|
||||||
for o in self.Object.Group:
|
for o in flattenGroup(self.Object):
|
||||||
if o != obj:
|
if o != obj:
|
||||||
names.add(o.Label)
|
names.add(o.Label)
|
||||||
if label not in names:
|
if label not in names:
|
||||||
|
@ -2314,33 +2382,13 @@ class ViewProviderAsmElementGroup(ViewProviderAsmGroup):
|
||||||
_iconName = 'Assembly_Assembly_Element_Tree.svg'
|
_iconName = 'Assembly_Assembly_Element_Tree.svg'
|
||||||
|
|
||||||
def setupContextMenu(self,_vobj,menu):
|
def setupContextMenu(self,_vobj,menu):
|
||||||
action = QtGui.QAction(QtGui.QIcon(),"Sort A~Z",menu)
|
setupSortMenu(menu,self.sort,self.sortReverse)
|
||||||
QtCore.QObject.connect(action,QtCore.SIGNAL("triggered()"),self.sort)
|
|
||||||
menu.addAction(action)
|
|
||||||
action = QtGui.QAction(QtGui.QIcon(),"Sort Z~A",menu)
|
|
||||||
QtCore.QObject.connect(
|
|
||||||
action,QtCore.SIGNAL("triggered()"),self.sortReverse)
|
|
||||||
menu.addAction(action)
|
|
||||||
|
|
||||||
def sortReverse(self):
|
def sortReverse(self):
|
||||||
self.sort(True)
|
sortChildren(self.ViewObject.Object,True)
|
||||||
|
|
||||||
def sort(self,reverse=False):
|
def sort(self):
|
||||||
obj = self.ViewObject.Object
|
sortChildren(self.ViewObject.Object,False)
|
||||||
group = [ (o,o.Label) for o in obj.Group ]
|
|
||||||
group = sorted(group,reverse=reverse,key=lambda x:x[1])
|
|
||||||
touched = 'Touched' in obj.State
|
|
||||||
FreeCAD.setActiveTransaction('Sort elements')
|
|
||||||
try:
|
|
||||||
obj.setPropertyStatus('Group','-Immutable')
|
|
||||||
obj.Group = [o[0] for o in group]
|
|
||||||
obj.setPropertyStatus('Group','Immutable')
|
|
||||||
except Exception:
|
|
||||||
FreeCAD.closeActiveTransaction(True)
|
|
||||||
raise
|
|
||||||
FreeCAD.closeActiveTransaction()
|
|
||||||
if not touched:
|
|
||||||
obj.purgeTouched()
|
|
||||||
|
|
||||||
def canDropObjectEx(self,_obj,owner,subname,elements):
|
def canDropObjectEx(self,_obj,owner,subname,elements):
|
||||||
if not owner:
|
if not owner:
|
||||||
|
@ -2440,7 +2488,7 @@ class AsmRelationGroup(AsmBase):
|
||||||
relations = self.relations.copy()
|
relations = self.relations.copy()
|
||||||
touched = False
|
touched = False
|
||||||
new = []
|
new = []
|
||||||
for part in self.getAssembly().getPartGroup().Group:
|
for part in self.getAssembly().getPartGroup().LinkedChildren:
|
||||||
o = relations.get(part,None)
|
o = relations.get(part,None)
|
||||||
if not o:
|
if not o:
|
||||||
touched = True
|
touched = True
|
||||||
|
@ -2523,6 +2571,7 @@ class AsmRelationGroup(AsmBase):
|
||||||
sobj = obj.getSubObject(subname,1)
|
sobj = obj.getSubObject(subname,1)
|
||||||
if not isTypeOf(sobj,AsmConstraint):
|
if not isTypeOf(sobj,AsmConstraint):
|
||||||
return
|
return
|
||||||
|
subname = flattenSubnameRecursive(obj,subname)
|
||||||
sub = Part.splitSubname(subname)[0].split('.')
|
sub = Part.splitSubname(subname)[0].split('.')
|
||||||
sub = sub[:-1]
|
sub = sub[:-1]
|
||||||
sub[-2] = '3'
|
sub[-2] = '3'
|
||||||
|
@ -2557,13 +2606,14 @@ class AsmRelationGroup(AsmBase):
|
||||||
if not moveInfo:
|
if not moveInfo:
|
||||||
return
|
return
|
||||||
info = moveInfo.ElementInfo
|
info = moveInfo.ElementInfo
|
||||||
|
subname = flattenSubnameRecursive(moveInfo.SelObj,moveInfo.SelSubname)
|
||||||
if not info.Subname:
|
if not info.Subname:
|
||||||
subs = moveInfo.SelSubname.split('.')
|
subs = subname.split('.')
|
||||||
elif moveInfo.SelSubname.endswith(info.Subname):
|
elif subname.endswith(info.Subname):
|
||||||
subs = moveInfo.SelSubname[:-len(info.Subname)].split('.')
|
subs = subname[:-len(info.Subname)].split('.')
|
||||||
else:
|
else:
|
||||||
sobj = moveInfo.SelObj.getSubObject(moveInfo.SelSubname,1)
|
sobj = moveInfo.SelObj.getSubObject(moveInfo.SelSubname,1)
|
||||||
subs = moveInfo.SelSubname.split('.')
|
subs = subname.split('.')
|
||||||
if isTypeOf(sobj,AsmElementLink):
|
if isTypeOf(sobj,AsmElementLink):
|
||||||
subs = subs[:-3]
|
subs = subs[:-3]
|
||||||
elif isTypeOf(sobj,AsmElement):
|
elif isTypeOf(sobj,AsmElement):
|
||||||
|
@ -2760,8 +2810,8 @@ class AsmRelation(AsmBase):
|
||||||
else:
|
else:
|
||||||
part = obj.Part
|
part = obj.Part
|
||||||
group = []
|
group = []
|
||||||
for cstr in self.getAssembly().getConstraintGroup().Group:
|
for cstr in self.getAssembly().getConstraintGroup().LinkedChildren:
|
||||||
for element in cstr.Group:
|
for element in flattenGroup(cstr):
|
||||||
info = element.Proxy.getInfo()
|
info = element.Proxy.getInfo()
|
||||||
if isinstance(info.Part,tuple):
|
if isinstance(info.Part,tuple):
|
||||||
infoPart = info.Part[:2]
|
infoPart = info.Part[:2]
|
||||||
|
@ -3030,7 +3080,7 @@ class Assembly(AsmGroup):
|
||||||
cls._PendingReload.clear()
|
cls._PendingReload.clear()
|
||||||
|
|
||||||
def onSolverChanged(self):
|
def onSolverChanged(self):
|
||||||
for obj in self.getConstraintGroup().Group:
|
for obj in self.getConstraintGroup().LinkedChildren:
|
||||||
# setup==True usually means we are restoring, so try to restore the
|
# setup==True usually means we are restoring, so try to restore the
|
||||||
# non-touched state if possible, since recompute() below will touch
|
# non-touched state if possible, since recompute() below will touch
|
||||||
# the constraint object
|
# the constraint object
|
||||||
|
@ -3093,7 +3143,7 @@ class Assembly(AsmGroup):
|
||||||
partGroup.Shape = Part.Shape()
|
partGroup.Shape = Part.Shape()
|
||||||
return
|
return
|
||||||
|
|
||||||
group = partGroup.Group
|
group = flattenGroup(partGroup)
|
||||||
|
|
||||||
shapes = []
|
shapes = []
|
||||||
if obj.BuildShape == BuildShapeCompound or \
|
if obj.BuildShape == BuildShapeCompound or \
|
||||||
|
@ -3147,6 +3197,8 @@ class Assembly(AsmGroup):
|
||||||
|
|
||||||
def attach(self, obj):
|
def attach(self, obj):
|
||||||
obj.addProperty("App::PropertyEnumeration","BuildShape","Base",'')
|
obj.addProperty("App::PropertyEnumeration","BuildShape","Base",'')
|
||||||
|
obj.addProperty("App::PropertyInteger","_Version","Base",'')
|
||||||
|
obj._Version = 1
|
||||||
obj.BuildShape = BuildShapeNames
|
obj.BuildShape = BuildShapeNames
|
||||||
super(Assembly,self).attach(obj)
|
super(Assembly,self).attach(obj)
|
||||||
|
|
||||||
|
@ -3171,6 +3223,19 @@ class Assembly(AsmGroup):
|
||||||
# all groups exist. The order of the group is important to make sure
|
# all groups exist. The order of the group is important to make sure
|
||||||
# correct rendering and picking behavior
|
# correct rendering and picking behavior
|
||||||
partGroup = self.getPartGroup(True)
|
partGroup = self.getPartGroup(True)
|
||||||
|
|
||||||
|
if not getattr(obj,'_Version',None):
|
||||||
|
cstrGroup = self.getConstraintGroup().Proxy
|
||||||
|
for o in flattenGroup(cstrGroup.Object):
|
||||||
|
cstr = getProxy(o,AsmConstraint)
|
||||||
|
cstr.parent = cstrGroup
|
||||||
|
for oo in flattenGroup(o):
|
||||||
|
oo.Proxy.parent = cstr
|
||||||
|
elementGroup = self.getElementGroup().Proxy
|
||||||
|
for o in flattenGroup(elementGroup.Object):
|
||||||
|
element = getProxy(o,AsmElement)
|
||||||
|
element.parent = elementGroup
|
||||||
|
|
||||||
self.getRelationGroup()
|
self.getRelationGroup()
|
||||||
|
|
||||||
self.frozen = obj.Freeze
|
self.frozen = obj.Freeze
|
||||||
|
@ -3178,8 +3243,8 @@ class Assembly(AsmGroup):
|
||||||
cstrGroup = self.getConstraintGroup()
|
cstrGroup = self.getConstraintGroup()
|
||||||
if cstrGroup._Version<=0:
|
if cstrGroup._Version<=0:
|
||||||
cstrGroup._Version = 1
|
cstrGroup._Version = 1
|
||||||
for cstr in cstrGroup.Group:
|
for cstr in flattenGroup(cstrGroup):
|
||||||
for link in cstr.Group:
|
for link in flattenGroup(cstr):
|
||||||
link.Proxy.migrate(link)
|
link.Proxy.migrate(link)
|
||||||
|
|
||||||
if self.frozen or hasattr(partGroup,'Shape'):
|
if self.frozen or hasattr(partGroup,'Shape'):
|
||||||
|
@ -3253,7 +3318,7 @@ class Assembly(AsmGroup):
|
||||||
if not cstrGroup:
|
if not cstrGroup:
|
||||||
return []
|
return []
|
||||||
ret = []
|
ret = []
|
||||||
for o in cstrGroup.Group:
|
for o in flattenGroup(cstrGroup):
|
||||||
checkType(o,AsmConstraint)
|
checkType(o,AsmConstraint)
|
||||||
if Constraint.isDisabled(o):
|
if Constraint.isDisabled(o):
|
||||||
logger.debug('skip constraint {}',cstrName(o))
|
logger.debug('skip constraint {}',cstrName(o))
|
||||||
|
@ -3343,7 +3408,7 @@ class Assembly(AsmGroup):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def addOrigin(partGroup, name=None):
|
def addOrigin(partGroup, name=None):
|
||||||
obj = None
|
obj = None
|
||||||
for o in partGroup.Group:
|
for o in flattenGroup(partGroup):
|
||||||
if o.TypeId == 'App::Origin':
|
if o.TypeId == 'App::Origin':
|
||||||
obj = o
|
obj = o
|
||||||
break
|
break
|
||||||
|
@ -3521,7 +3586,7 @@ class ViewProviderAssembly(ViewProviderAsmGroup):
|
||||||
|
|
||||||
def onDelete(self,vobj,_subs):
|
def onDelete(self,vobj,_subs):
|
||||||
assembly = vobj.Object.Proxy
|
assembly = vobj.Object.Proxy
|
||||||
for o in assembly.getPartGroup().Group:
|
for o in assembly.getPartGroup().LinkedChildren:
|
||||||
if o.isDerivedFrom('App::Origin'):
|
if o.isDerivedFrom('App::Origin'):
|
||||||
o.Document.removeObject(o.Name)
|
o.Document.removeObject(o.Name)
|
||||||
break
|
break
|
||||||
|
@ -3704,14 +3769,16 @@ class AsmWorkPlane(object):
|
||||||
for sel in sels:
|
for sel in sels:
|
||||||
if not sel.SubElementNames:
|
if not sel.SubElementNames:
|
||||||
elements.append((sel.Object,''))
|
elements.append((sel.Object,''))
|
||||||
|
if len(elements) > 2:
|
||||||
|
raise RuntimeError('Too many selection')
|
||||||
objs.append(sel.Object)
|
objs.append(sel.Object)
|
||||||
continue
|
continue
|
||||||
for sub in sel.SubElementNames:
|
for sub in sel.SubElementNames:
|
||||||
elements.append((sel.Object,sub))
|
elements.append((sel.Object,sub))
|
||||||
|
if len(elements) > 2:
|
||||||
|
raise RuntimeError('Too many selection')
|
||||||
objs.append(sel.Object.getSubObject(sub,1))
|
objs.append(sel.Object.getSubObject(sub,1))
|
||||||
if len(elements) > 2:
|
if len(elements)==2:
|
||||||
raise RuntimeError('Too many selection')
|
|
||||||
elif len(elements)==2:
|
|
||||||
if isTypeOf(objs[0],Assembly,True):
|
if isTypeOf(objs[0],Assembly,True):
|
||||||
assembly = objs[0]
|
assembly = objs[0]
|
||||||
selObj,sub = elements[0]
|
selObj,sub = elements[0]
|
||||||
|
@ -3832,3 +3899,161 @@ class ViewProviderAsmWorkPlane(ViewProviderAsmBase):
|
||||||
|
|
||||||
def setDisplayMode(self, mode):
|
def setDisplayMode(self, mode):
|
||||||
return mode
|
return mode
|
||||||
|
|
||||||
|
|
||||||
|
class AsmPlainGroup(object):
|
||||||
|
def __init__(self,obj):
|
||||||
|
obj.Proxy = self
|
||||||
|
|
||||||
|
def __getstate__(self):
|
||||||
|
return
|
||||||
|
|
||||||
|
def __setstate__(self,_state):
|
||||||
|
return
|
||||||
|
|
||||||
|
# SelObj: selected top object
|
||||||
|
# SelSubname: subname refercing the last common parent of the selections
|
||||||
|
# Parent: sub-group of the parent assembly
|
||||||
|
# Group: immediate group of all selected objects, may or may not be the
|
||||||
|
# same as 'Parent'
|
||||||
|
# Objects: selected objects
|
||||||
|
Info = namedtuple('AsmPlainGroupSelectionInfo',
|
||||||
|
('SelObj','SelSubname','Parent','Group','Objects'))
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def getSelection(sels=None):
|
||||||
|
if not sels:
|
||||||
|
sels = FreeCADGui.Selection.getSelectionEx('',False)
|
||||||
|
if not sels:
|
||||||
|
raise RuntimeError('no selection')
|
||||||
|
elif len(sels)>1:
|
||||||
|
raise RuntimeError('Too many selection')
|
||||||
|
sel = sels[0]
|
||||||
|
if not sel.SubElementNames:
|
||||||
|
raise RuntimeError('Invalid selection')
|
||||||
|
|
||||||
|
parent = None
|
||||||
|
subs = []
|
||||||
|
for sub in sel.SubElementNames:
|
||||||
|
h = Assembly.find(sel.Object,sub,recursive=True,
|
||||||
|
childType=(AsmConstraintGroup,AsmElementGroup,AsmPartGroup))
|
||||||
|
if not h:
|
||||||
|
raise RuntimeError("Invalid selection {}.{}".format(
|
||||||
|
objName(sel.Object),sub))
|
||||||
|
h = h[-1]
|
||||||
|
if not parent:
|
||||||
|
parent = h.Object
|
||||||
|
selSub = sub[:-len(h.Subname)]
|
||||||
|
elif parent != h.Object:
|
||||||
|
raise RuntimeError("Selection from different assembly")
|
||||||
|
subs.append(h.Subname)
|
||||||
|
|
||||||
|
if len(subs) == 1:
|
||||||
|
group = parent
|
||||||
|
common = ''
|
||||||
|
else:
|
||||||
|
common = os.path.commonprefix(subs)
|
||||||
|
idx = common.rfind('.')
|
||||||
|
if idx<0:
|
||||||
|
group = parent
|
||||||
|
common = ''
|
||||||
|
else:
|
||||||
|
common = common[:idx+1]
|
||||||
|
group = parent.getSubObject(common,1)
|
||||||
|
if not group:
|
||||||
|
raise RuntimeError('Sub object not found: {}.{}'.format(
|
||||||
|
objName(parent),common))
|
||||||
|
if not isTypeOf(group,(AsmPlainGroup,AsmConstraint)):
|
||||||
|
raise RuntimeError('Not from plain group')
|
||||||
|
subs = [ s[idx+1:] for s in subs ]
|
||||||
|
objs = []
|
||||||
|
for s in subs:
|
||||||
|
sub = s[:s.index('.')+1]
|
||||||
|
if not sub:
|
||||||
|
raise RuntimeError('Invalid subname: {}.{}{}'.format(
|
||||||
|
objName(parent),common,s))
|
||||||
|
sobj = group.getSubObject(sub,1)
|
||||||
|
if not sobj:
|
||||||
|
raise RuntimeError('Sub object not found: {}.{}'.format(
|
||||||
|
objName(h.Object),sub))
|
||||||
|
objs.append(sobj)
|
||||||
|
|
||||||
|
return AsmPlainGroup.Info(SelObj=sel.Object,
|
||||||
|
SelSubname=selSub,
|
||||||
|
Parent=parent,
|
||||||
|
Group=group,
|
||||||
|
Objects=objs)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def make(sels=None,name=None, undo=True):
|
||||||
|
info = AsmPlainGroup.getSelection(sels)
|
||||||
|
doc = info.Parent.Document
|
||||||
|
if undo:
|
||||||
|
FreeCAD.setActiveTransaction('Assembly create group')
|
||||||
|
try:
|
||||||
|
if not name:
|
||||||
|
name = 'Group'
|
||||||
|
obj = doc.addObject('App::DocumentObjectGroupPython',name)
|
||||||
|
AsmPlainGroup(obj)
|
||||||
|
ViewProviderAsmPlainGroup(obj.ViewObject)
|
||||||
|
group = info.Group.Group
|
||||||
|
child = info.Objects[0]
|
||||||
|
idx = group.index(child)
|
||||||
|
group = [ o for o in info.Group.Group
|
||||||
|
if o not in info.Objects ]
|
||||||
|
group.insert(idx,obj)
|
||||||
|
obj.Group = info.Objects
|
||||||
|
editGroup(info.Group,group)
|
||||||
|
info.Parent.recompute(True)
|
||||||
|
|
||||||
|
if undo:
|
||||||
|
FreeCAD.closeActiveTransaction()
|
||||||
|
|
||||||
|
FreeCADGui.Selection.clearSelection()
|
||||||
|
FreeCADGui.Selection.addSelection(info.SelObj,'{}{}.{}.'.format(
|
||||||
|
info.SelSubname,obj.Name,child.Name))
|
||||||
|
FreeCADGui.runCommand('Std_TreeSelection')
|
||||||
|
return obj
|
||||||
|
except Exception:
|
||||||
|
if undo:
|
||||||
|
FreeCAD.closeActiveTransaction(True)
|
||||||
|
raise
|
||||||
|
|
||||||
|
class ViewProviderAsmPlainGroup(object):
|
||||||
|
def __init__(self,vobj):
|
||||||
|
vobj.Visibility = False
|
||||||
|
vobj.Proxy = self
|
||||||
|
self.attach(vobj)
|
||||||
|
|
||||||
|
def attach(self,vobj):
|
||||||
|
if hasattr(self,'ViewObject'):
|
||||||
|
return
|
||||||
|
self.ViewObject = vobj
|
||||||
|
vobj.setPropertyStatus('Visibility','Hidden')
|
||||||
|
|
||||||
|
def __getstate__(self):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def __setstate__(self, _state):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def onDelete(self,vobj,_subs):
|
||||||
|
obj = vobj.Object
|
||||||
|
for o in obj.InList:
|
||||||
|
if isTypeOf(o,(AsmPlainGroup, AsmGroup)):
|
||||||
|
children = o.Group + obj.Group
|
||||||
|
obj.Group = []
|
||||||
|
editGroup(o,children)
|
||||||
|
break
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def setupContextMenu(self,_vobj,menu):
|
||||||
|
setupSortMenu(menu,self.sort,self.sortReverse)
|
||||||
|
|
||||||
|
def sortReverse(self):
|
||||||
|
sortChildren(self.ViewObject.Object,True)
|
||||||
|
|
||||||
|
def sort(self):
|
||||||
|
sortChildren(self.ViewObject.Object,False)
|
||||||
|
|
||||||
|
|
26
gui.py
26
gui.py
|
@ -22,14 +22,14 @@ class SelectionObserver:
|
||||||
def _setElementVisible(self,obj,subname,vis):
|
def _setElementVisible(self,obj,subname,vis):
|
||||||
sobj = obj.getSubObject(subname,1)
|
sobj = obj.getSubObject(subname,1)
|
||||||
from .assembly import isTypeOf,AsmConstraint,\
|
from .assembly import isTypeOf,AsmConstraint,\
|
||||||
AsmElement,AsmElementLink
|
AsmElement,AsmElementLink,flattenGroup
|
||||||
if isTypeOf(sobj,(AsmElement,AsmElementLink)):
|
if isTypeOf(sobj,(AsmElement,AsmElementLink)):
|
||||||
res = sobj.Proxy.parent.Object.isElementVisible(sobj.Name)
|
res = sobj.Proxy.parent.Object.isElementVisible(sobj.Name)
|
||||||
if res and vis:
|
if res and vis:
|
||||||
return False
|
return False
|
||||||
sobj.Proxy.parent.Object.setElementVisible(sobj.Name,vis)
|
sobj.Proxy.parent.Object.setElementVisible(sobj.Name,vis)
|
||||||
elif isTypeOf(sobj,AsmConstraint):
|
elif isTypeOf(sobj,AsmConstraint):
|
||||||
vis = [vis] * len(sobj.Group)
|
vis = [vis] * len(flattenGroup(sobj))
|
||||||
sobj.setPropertyStatus('VisibilityList','-Immutable')
|
sobj.setPropertyStatus('VisibilityList','-Immutable')
|
||||||
sobj.VisibilityList = vis
|
sobj.VisibilityList = vis
|
||||||
sobj.setPropertyStatus('VisibilityList','Immutable')
|
sobj.setPropertyStatus('VisibilityList','Immutable')
|
||||||
|
@ -268,6 +268,28 @@ class AsmCmdNew(AsmCmdBase):
|
||||||
assembly.Assembly.make()
|
assembly.Assembly.make()
|
||||||
|
|
||||||
|
|
||||||
|
class AsmCmdNewGroup(AsmCmdBase):
|
||||||
|
_id = 24
|
||||||
|
_menuText = 'Group objects'
|
||||||
|
_iconName = 'Assembly_New_Group.svg'
|
||||||
|
_accel = 'A, Z'
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def Activated(cls):
|
||||||
|
from . import assembly
|
||||||
|
assembly.AsmPlainGroup.make()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def checkActive(cls):
|
||||||
|
from . import assembly
|
||||||
|
cls._active = logger.catchTrace(
|
||||||
|
'',assembly.AsmPlainGroup.getSelection) is not None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def onSelectionChange(cls,hasSelection):
|
||||||
|
cls._active = None if hasSelection else False
|
||||||
|
|
||||||
|
|
||||||
class AsmCmdSolve(AsmCmdBase):
|
class AsmCmdSolve(AsmCmdBase):
|
||||||
_id = 1
|
_id = 1
|
||||||
_menuText = 'Solve constraints'
|
_menuText = 'Solve constraints'
|
||||||
|
|
Loading…
Reference in New Issue
Block a user