gui: add New Element command
This commit is contained in:
parent
104d5d10b4
commit
821d7194fc
193
assembly.py
193
assembly.py
|
@ -460,73 +460,77 @@ class AsmElement(AsmBase):
|
||||||
# Group: the immediate child object of an assembly (i.e. ConstraintGroup,
|
# Group: the immediate child object of an assembly (i.e. ConstraintGroup,
|
||||||
# ElementGroup, or PartGroup)
|
# ElementGroup, or PartGroup)
|
||||||
# Subname: the subname reference realtive to 'Group'
|
# Subname: the subname reference realtive to 'Group'
|
||||||
Selection = namedtuple('AsmElementSelection',('Element','Group','Subname'))
|
Selection = namedtuple('AsmElementSelection',('Element','Group','Subname',
|
||||||
|
'SelObj', 'SelSubname'))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def getSelection():
|
def getSelections():
|
||||||
'''
|
'Parse Gui.Selection for making one or more elements'
|
||||||
Parse Gui.Selection for making an element
|
|
||||||
|
|
||||||
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)
|
sels = FreeCADGui.Selection.getSelectionEx('',False)
|
||||||
if not sels:
|
if not sels:
|
||||||
return
|
raise RuntimeError('no selection')
|
||||||
if len(sels)>1:
|
if not sels[0].SubElementNames:
|
||||||
raise RuntimeError(
|
|
||||||
'The selections must have a common (grand)parent assembly')
|
|
||||||
|
|
||||||
sel = sels[0]
|
|
||||||
subs = list(sel.SubElementNames)
|
|
||||||
if not subs:
|
|
||||||
raise RuntimeError('no sub-object in selection')
|
raise RuntimeError('no sub-object in selection')
|
||||||
if len(subs)>2:
|
if len(sels)>1:
|
||||||
raise RuntimeError('At most two selection is allowed.\n'
|
raise RuntimeError('too many selection')
|
||||||
'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')
|
|
||||||
|
|
||||||
|
hierarchies = []
|
||||||
|
assembly = None
|
||||||
element = None
|
element = None
|
||||||
if len(subs)>1:
|
selObj = sels[0].Object
|
||||||
ret = Assembly.findElementGroup(sel.Object,subs[1])
|
selSubname = None
|
||||||
if not ret:
|
for sub in sels[0].SubElementNames:
|
||||||
raise RuntimeError('The second selection must be an element')
|
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:
|
elif isTypeOf(path[-1].Object,AsmElementGroup) and \
|
||||||
raise RuntimeError(
|
(not element or len(element)>len(path)):
|
||||||
'The two selections must belong to the same assembly')
|
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):
|
if not isTypeOf(element,AsmElement):
|
||||||
raise RuntimeError('The second selection must be an element')
|
element = None
|
||||||
|
|
||||||
return AsmElement.Selection(Element=element, Group=link.Object,
|
if not assembly:
|
||||||
Subname=link.Subname+subElement)
|
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
|
@classmethod
|
||||||
def create(cls,name,elements):
|
def create(cls,name,elements):
|
||||||
|
@ -538,10 +542,42 @@ class AsmElement(AsmBase):
|
||||||
return element
|
return element
|
||||||
|
|
||||||
@staticmethod
|
@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'''
|
'''Add/get/modify an element with the given selected object'''
|
||||||
if not selection:
|
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
|
group = selection.Group
|
||||||
subname = selection.Subname
|
subname = selection.Subname
|
||||||
|
@ -553,7 +589,9 @@ class AsmElement(AsmBase):
|
||||||
if not isTypeOf(element,AsmElement):
|
if not isTypeOf(element,AsmElement):
|
||||||
raise RuntimeError('Invalid element reference {}.{}'.format(
|
raise RuntimeError('Invalid element reference {}.{}'.format(
|
||||||
group.Name,subname))
|
group.Name,subname))
|
||||||
return element
|
if not allowDuplicate:
|
||||||
|
return element
|
||||||
|
group,subname = element.LinkedObject
|
||||||
|
|
||||||
if isTypeOf(group,AsmConstraintGroup):
|
if isTypeOf(group,AsmConstraintGroup):
|
||||||
# if the selected object is an element link of a constraint of the
|
# 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
|
# In case there are intermediate assembly inside subname, we'll
|
||||||
# recursively export the element in child assemblies first, and
|
# recursively export the element in child assemblies first, and
|
||||||
# then import that element to the current assembly.
|
# then import that element to the current assembly.
|
||||||
sel = AsmElement.Selection(Element=None,
|
sel = AsmElement.Selection(SelObj=None,SelSubname=None,
|
||||||
Group=ret.Object, Subname=ret.Subname)
|
Element=None, Group=ret.Object, Subname=ret.Subname)
|
||||||
element = AsmElement.make(sel,radius=radius)
|
element = AsmElement.make(sel,radius=radius)
|
||||||
radius=None
|
radius=None
|
||||||
|
|
||||||
|
@ -629,16 +667,17 @@ class AsmElement(AsmBase):
|
||||||
elements = group.Proxy.getAssembly().getElementGroup()
|
elements = group.Proxy.getAssembly().getElementGroup()
|
||||||
idx = -1
|
idx = -1
|
||||||
if not element:
|
if not element:
|
||||||
# try to search the element group for an existing element
|
if not allowDuplicate:
|
||||||
for e in elements.Group:
|
# try to search the element group for an existing element
|
||||||
if not e.Offset.isIdentity():
|
for e in elements.Group:
|
||||||
continue
|
if not e.Offset.isIdentity():
|
||||||
sub = logger.catch('',e.Proxy.getSubName)
|
continue
|
||||||
if sub!=subname:
|
sub = logger.catch('',e.Proxy.getSubName)
|
||||||
continue
|
if sub!=subname:
|
||||||
r = getattr(e,'Radius',None)
|
continue
|
||||||
if (not radius and not r) or radius==r:
|
r = getattr(e,'Radius',None)
|
||||||
return e
|
if (not radius and not r) or radius==r:
|
||||||
|
return e
|
||||||
element = AsmElement.create(name,elements)
|
element = AsmElement.create(name,elements)
|
||||||
if radius:
|
if radius:
|
||||||
element.addProperty('App::PropertyFloat','Radius','','')
|
element.addProperty('App::PropertyFloat','Radius','','')
|
||||||
|
@ -689,7 +728,8 @@ class ViewProviderAsmElement(ViewProviderAsmOnTop):
|
||||||
if not elements:
|
if not elements:
|
||||||
elements = ['']
|
elements = ['']
|
||||||
for element in 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)
|
Group=owner, Subname=subname+element),undo=True)
|
||||||
|
|
||||||
def doubleClicked(self,_vobj):
|
def doubleClicked(self,_vobj):
|
||||||
|
@ -1087,15 +1127,15 @@ class AsmElementLink(AsmBase):
|
||||||
ret = Assembly.find(owner,subname)
|
ret = Assembly.find(owner,subname)
|
||||||
if not ret:
|
if not ret:
|
||||||
# if not, add/get an element in our own element group
|
# if not, add/get an element in our own element group
|
||||||
sel = AsmElement.Selection(Element=None, Group=owner,
|
sel = AsmElement.Selection(SelObj=None, SelSubname=None,
|
||||||
Subname=subname)
|
Element=None, Group=owner, Subname=subname)
|
||||||
element = AsmElement.make(sel,radius=radius)
|
element = AsmElement.make(sel,radius=radius)
|
||||||
owner = element.Proxy.parent.Object
|
owner = element.Proxy.parent.Object
|
||||||
subname = '${}.'.format(element.Label)
|
subname = '${}.'.format(element.Label)
|
||||||
else:
|
else:
|
||||||
# if so, add/get an element from the sub-assembly
|
# if so, add/get an element from the sub-assembly
|
||||||
sel = AsmElement.Selection(Element=None, Group=ret.Object,
|
sel = AsmElement.Selection(SelObj=None, SelSubname=None,
|
||||||
Subname=ret.Subname)
|
Element=None, Group=ret.Object, Subname=ret.Subname)
|
||||||
element = AsmElement.make(sel,radius=radius)
|
element = AsmElement.make(sel,radius=radius)
|
||||||
owner = owner.Proxy.getAssembly().getPartGroup()
|
owner = owner.Proxy.getAssembly().getPartGroup()
|
||||||
|
|
||||||
|
@ -1617,6 +1657,7 @@ class AsmConstraint(AsmGroup):
|
||||||
undo = False
|
undo = False
|
||||||
|
|
||||||
if sel.SelObject:
|
if sel.SelObject:
|
||||||
|
FreeCADGui.Selection.pushSelStack()
|
||||||
FreeCADGui.Selection.clearSelection()
|
FreeCADGui.Selection.clearSelection()
|
||||||
if sel.SelSubname:
|
if sel.SelSubname:
|
||||||
subname = sel.SelSubname
|
subname = sel.SelSubname
|
||||||
|
@ -1625,6 +1666,7 @@ class AsmConstraint(AsmGroup):
|
||||||
subname += sel.Assembly.Proxy.getConstraintGroup().Name + \
|
subname += sel.Assembly.Proxy.getConstraintGroup().Name + \
|
||||||
'.' + cstr.Name + '.'
|
'.' + cstr.Name + '.'
|
||||||
FreeCADGui.Selection.addSelection(sel.SelObject,subname)
|
FreeCADGui.Selection.addSelection(sel.SelObject,subname)
|
||||||
|
FreeCADGui.Selection.pushSelStack()
|
||||||
FreeCADGui.runCommand('Std_TreeSelection')
|
FreeCADGui.runCommand('Std_TreeSelection')
|
||||||
return cstr
|
return cstr
|
||||||
|
|
||||||
|
@ -1893,6 +1935,7 @@ class ViewProviderAsmElementGroup(ViewProviderAsmGroup):
|
||||||
elements = ['']
|
elements = ['']
|
||||||
for element in elements:
|
for element in elements:
|
||||||
obj = AsmElement.make(AsmElement.Selection(
|
obj = AsmElement.make(AsmElement.Selection(
|
||||||
|
SelObj=None, SelSubname=None,
|
||||||
Element=None, Group=owner, Subname=subname+element))
|
Element=None, Group=owner, Subname=subname+element))
|
||||||
if obj and sel:
|
if obj and sel:
|
||||||
FreeCADGui.Selection.addSelection(sel.Object,
|
FreeCADGui.Selection.addSelection(sel.Object,
|
||||||
|
|
29
gui.py
29
gui.py
|
@ -1,5 +1,6 @@
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
import FreeCAD, FreeCADGui
|
import FreeCAD, FreeCADGui
|
||||||
|
from PySide import QtCore, QtGui
|
||||||
from .deps import with_metaclass
|
from .deps import with_metaclass
|
||||||
from .utils import getElementPos,objName,addIconToFCAD,guilogger as logger
|
from .utils import getElementPos,objName,addIconToFCAD,guilogger as logger
|
||||||
from .proxy import ProxyType
|
from .proxy import ProxyType
|
||||||
|
@ -143,7 +144,6 @@ class AsmCmdManager(ProxyType):
|
||||||
if not hgrp.GetBool(toolbar,True):
|
if not hgrp.GetBool(toolbar,True):
|
||||||
show = True
|
show = True
|
||||||
break
|
break
|
||||||
from PySide import QtGui
|
|
||||||
mw = FreeCADGui.getMainWindow()
|
mw = FreeCADGui.getMainWindow()
|
||||||
for toolbar in mcs._HiddenToolbars:
|
for toolbar in mcs._HiddenToolbars:
|
||||||
if show != hgrp.GetBool(toolbar,True):
|
if show != hgrp.GetBool(toolbar,True):
|
||||||
|
@ -247,6 +247,31 @@ class AsmCmdNew(AsmCmdBase):
|
||||||
from . import assembly
|
from . import assembly
|
||||||
assembly.Assembly.make()
|
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):
|
class AsmCmdSolve(AsmCmdBase):
|
||||||
_id = 1
|
_id = 1
|
||||||
_menuText = 'Solve constraints'
|
_menuText = 'Solve constraints'
|
||||||
|
@ -660,7 +685,7 @@ class AsmCmdDown(AsmCmdUp):
|
||||||
cls.move(1)
|
cls.move(1)
|
||||||
|
|
||||||
|
|
||||||
class ASmCmdMultiply(AsmCmdBase):
|
class AsmCmdMultiply(AsmCmdBase):
|
||||||
_id = 18
|
_id = 18
|
||||||
_menuText = 'Multiply constraint'
|
_menuText = 'Multiply constraint'
|
||||||
_tooltip = 'Mutiply the part owner of the first element to constrain\n'\
|
_tooltip = 'Mutiply the part owner of the first element to constrain\n'\
|
||||||
|
|
Loading…
Reference in New Issue
Block a user