gui: add New Element command

This commit is contained in:
Zheng, Lei 2018-08-24 17:27:29 +08:00
parent 104d5d10b4
commit 821d7194fc
2 changed files with 145 additions and 77 deletions

View File

@ -460,73 +460,77 @@ class AsmElement(AsmBase):
# Group: the immediate child object of an assembly (i.e. ConstraintGroup,
# ElementGroup, or PartGroup)
# Subname: the subname reference realtive to 'Group'
Selection = namedtuple('AsmElementSelection',('Element','Group','Subname'))
Selection = namedtuple('AsmElementSelection',('Element','Group','Subname',
'SelObj', 'SelSubname'))
@staticmethod
def getSelection():
'''
Parse Gui.Selection for making an element
def getSelections():
'Parse Gui.Selection for making one or more elements'
If there is only one selection, then the selection must refer to a sub
element of some part object of an assembly. We shall create a new
element belonging to the top-level assembly
If there are two selections, then first one shall be either the
element group or an individual element. The second selection shall
be a sub-element belong to a child assembly of the parent assembly of
the first selected element/element group
'''
sels = FreeCADGui.Selection.getSelectionEx('',False)
if not sels:
return
if len(sels)>1:
raise RuntimeError(
'The selections must have a common (grand)parent assembly')
sel = sels[0]
subs = list(sel.SubElementNames)
if not subs:
raise RuntimeError('no selection')
if not sels[0].SubElementNames:
raise RuntimeError('no sub-object in selection')
if len(subs)>2:
raise RuntimeError('At most two selection is allowed.\n'
'The first selection must be a sub-element belonging to some '
'assembly. The optional second selection must be an element '
'belonging to the same assembly of the first selection')
if len(subs)==2:
if len(subs[0])<len(subs[1]):
subs = [subs[1],subs[2]]
if subs[0][-1] == '.':
if not utils.isElement((sel.Object,subs[0])):
raise RuntimeError('no sub-element (face, edge, vertex) in '
'{}.{}'.format(sel.Object.Name,subs[0]))
subElement = utils.deduceSelectedElement(sel.Object,subs[0])
if subElement:
subs[0] += subElement
else:
subElement = ''
link = Assembly.findPartGroup(sel.Object,subs[0])
if not link:
raise RuntimeError(
'Selected sub-element does not belong to an assembly')
if len(sels)>1:
raise RuntimeError('too many selection')
hierarchies = []
assembly = None
element = None
if len(subs)>1:
ret = Assembly.findElementGroup(sel.Object,subs[1])
if not ret:
raise RuntimeError('The second selection must be an element')
selObj = sels[0].Object
selSubname = None
for sub in sels[0].SubElementNames:
path = Assembly.findChildren(selObj,sub)
if not path:
raise RuntimeError('no assembly in selection {}.{}'.format(
objName(selObj),sub))
if not path[-1].Object or \
path[-1].Subname.index('.')+1==len(path[-1].Subname):
if assembly:
raise RuntimeError('invalid selection')
assembly = path[-1].Assembly
selSubname = sub[:-len(path[-1].Subname)]
continue
if ret.Assembly != link.Assembly:
raise RuntimeError(
'The two selections must belong to the same assembly')
elif isTypeOf(path[-1].Object,AsmElementGroup) and \
(not element or len(element)>len(path)):
if element:
hierarchies.append(element)
element = path
continue
element = ret.Object.getSubObject(ret.Subname,1)
hierarchies.append(path)
if not hierarchies:
if not element:
raise RuntimeError('no element selection')
hierarchies.append(element)
element = None
if element:
if len(hierarchies)>1:
raise RuntimeError('too many selections')
element = element[-1].Assembly.getSubObject(
element[-1].Subname,retType=1)
if not isTypeOf(element,AsmElement):
raise RuntimeError('The second selection must be an element')
element = None
return AsmElement.Selection(Element=element, Group=link.Object,
Subname=link.Subname+subElement)
if not assembly:
path = hierarchies[0]
assembly = path[0].Assembly
selSubname = sels[0].SubElementNames[0][:-len(path[0].Subname)]
for i,hierarchy in enumerate(hierarchies):
for path in hierarchy:
if path.Assembly == assembly:
hierarchies[i] = AsmElement.Selection(
Element=element,Group=path.Object,
Subname=path.Subname[path.Subname.index('.')+1:],
SelObj=selObj, SelSubname=selSubname)
break
else:
raise RuntimeError('parent assembly mismatch')
return hierarchies
@classmethod
def create(cls,name,elements):
@ -538,10 +542,42 @@ class AsmElement(AsmBase):
return element
@staticmethod
def make(selection=None,name='Element',undo=False,radius=None):
def make(selection=None,name='Element',undo=False,
radius=None,allowDuplicate=False):
'''Add/get/modify an element with the given selected object'''
if not selection:
selection = AsmElement.getSelection()
sels = AsmElement.getSelections()
if len(sels)==1:
ret = [AsmElement.make(sels[0],name,undo,radius,allowDuplicate)]
else:
if undo:
FreeCAD.setActiveTransaction('Assembly create element')
try:
ret = []
for sel in sels:
ret.append(AsmElement.make(
sel,name,False,radius,allowDuplicate))
if undo:
FreeCAD.closeActiveTransaction()
if not ret:
return
except Exception:
if undo:
FreeCAD.closeActiveTransaction(True)
raise
FreeCADGui.Selection.pushSelStack()
FreeCADGui.Selection.clearSelection()
for obj in ret:
if sels[0].SelSubname:
subname = sels[0].SelSubname
else:
subname = ''
subname += '1.{}.'.format(obj.Name)
FreeCADGui.Selection.addSelection(sels[0].SelObj,subname)
FreeCADGui.Selection.pushSelStack()
FreeCADGui.runCommand('Std_TreeSelection')
return ret
group = selection.Group
subname = selection.Subname
@ -553,7 +589,9 @@ class AsmElement(AsmBase):
if not isTypeOf(element,AsmElement):
raise RuntimeError('Invalid element reference {}.{}'.format(
group.Name,subname))
return element
if not allowDuplicate:
return element
group,subname = element.LinkedObject
if isTypeOf(group,AsmConstraintGroup):
# if the selected object is an element link of a constraint of the
@ -592,8 +630,8 @@ class AsmElement(AsmBase):
# In case there are intermediate assembly inside subname, we'll
# recursively export the element in child assemblies first, and
# then import that element to the current assembly.
sel = AsmElement.Selection(Element=None,
Group=ret.Object, Subname=ret.Subname)
sel = AsmElement.Selection(SelObj=None,SelSubname=None,
Element=None, Group=ret.Object, Subname=ret.Subname)
element = AsmElement.make(sel,radius=radius)
radius=None
@ -629,16 +667,17 @@ class AsmElement(AsmBase):
elements = group.Proxy.getAssembly().getElementGroup()
idx = -1
if not element:
# try to search the element group for an existing element
for e in elements.Group:
if not e.Offset.isIdentity():
continue
sub = logger.catch('',e.Proxy.getSubName)
if sub!=subname:
continue
r = getattr(e,'Radius',None)
if (not radius and not r) or radius==r:
return e
if not allowDuplicate:
# try to search the element group for an existing element
for e in elements.Group:
if not e.Offset.isIdentity():
continue
sub = logger.catch('',e.Proxy.getSubName)
if sub!=subname:
continue
r = getattr(e,'Radius',None)
if (not radius and not r) or radius==r:
return e
element = AsmElement.create(name,elements)
if radius:
element.addProperty('App::PropertyFloat','Radius','','')
@ -689,7 +728,8 @@ class ViewProviderAsmElement(ViewProviderAsmOnTop):
if not elements:
elements = ['']
for element in elements:
AsmElement.make(AsmElement.Selection(Element=vobj.Object,
AsmElement.make(AsmElement.Selection(
SelObj=None, SelSubname=None, Element=vobj.Object,
Group=owner, Subname=subname+element),undo=True)
def doubleClicked(self,_vobj):
@ -1087,15 +1127,15 @@ class AsmElementLink(AsmBase):
ret = Assembly.find(owner,subname)
if not ret:
# if not, add/get an element in our own element group
sel = AsmElement.Selection(Element=None, Group=owner,
Subname=subname)
sel = AsmElement.Selection(SelObj=None, SelSubname=None,
Element=None, Group=owner, Subname=subname)
element = AsmElement.make(sel,radius=radius)
owner = element.Proxy.parent.Object
subname = '${}.'.format(element.Label)
else:
# if so, add/get an element from the sub-assembly
sel = AsmElement.Selection(Element=None, Group=ret.Object,
Subname=ret.Subname)
sel = AsmElement.Selection(SelObj=None, SelSubname=None,
Element=None, Group=ret.Object, Subname=ret.Subname)
element = AsmElement.make(sel,radius=radius)
owner = owner.Proxy.getAssembly().getPartGroup()
@ -1617,6 +1657,7 @@ class AsmConstraint(AsmGroup):
undo = False
if sel.SelObject:
FreeCADGui.Selection.pushSelStack()
FreeCADGui.Selection.clearSelection()
if sel.SelSubname:
subname = sel.SelSubname
@ -1625,6 +1666,7 @@ class AsmConstraint(AsmGroup):
subname += sel.Assembly.Proxy.getConstraintGroup().Name + \
'.' + cstr.Name + '.'
FreeCADGui.Selection.addSelection(sel.SelObject,subname)
FreeCADGui.Selection.pushSelStack()
FreeCADGui.runCommand('Std_TreeSelection')
return cstr
@ -1893,6 +1935,7 @@ class ViewProviderAsmElementGroup(ViewProviderAsmGroup):
elements = ['']
for element in elements:
obj = AsmElement.make(AsmElement.Selection(
SelObj=None, SelSubname=None,
Element=None, Group=owner, Subname=subname+element))
if obj and sel:
FreeCADGui.Selection.addSelection(sel.Object,

29
gui.py
View File

@ -1,5 +1,6 @@
from collections import OrderedDict
import FreeCAD, FreeCADGui
from PySide import QtCore, QtGui
from .deps import with_metaclass
from .utils import getElementPos,objName,addIconToFCAD,guilogger as logger
from .proxy import ProxyType
@ -143,7 +144,6 @@ class AsmCmdManager(ProxyType):
if not hgrp.GetBool(toolbar,True):
show = True
break
from PySide import QtGui
mw = FreeCADGui.getMainWindow()
for toolbar in mcs._HiddenToolbars:
if show != hgrp.GetBool(toolbar,True):
@ -247,6 +247,31 @@ class AsmCmdNew(AsmCmdBase):
from . import assembly
assembly.Assembly.make()
class AsmCmdNewElement(AsmCmdBase):
_id = 19
_menuText = 'Create element'
_iconName = 'Assembly_New_Element.svg'
_accel = 'A, E'
@classmethod
def Activated(cls):
from . import assembly
logger.report('Failed to add element',
assembly.AsmElement.make, undo=True, allowDuplicate=
QtGui.QApplication.keyboardModifiers()==QtCore.Qt.ControlModifier)
@classmethod
def checkActive(cls):
from . import assembly
cls._active = logger.catchTrace(
'',assembly.AsmElement.getSelections) is not None
@classmethod
def onSelectionChange(cls,hasSelection):
cls._active = None if hasSelection else False
class AsmCmdSolve(AsmCmdBase):
_id = 1
_menuText = 'Solve constraints'
@ -660,7 +685,7 @@ class AsmCmdDown(AsmCmdUp):
cls.move(1)
class ASmCmdMultiply(AsmCmdBase):
class AsmCmdMultiply(AsmCmdBase):
_id = 18
_menuText = 'Multiply constraint'
_tooltip = 'Mutiply the part owner of the first element to constrain\n'\