Complete support for drag and drop

This commit is contained in:
Zheng, Lei 2017-11-03 15:04:40 +08:00
parent 6b91e11daf
commit 2274fec363
3 changed files with 269 additions and 105 deletions

View File

@ -28,13 +28,16 @@ def isTypeOf(obj,tp,resolve=False):
def checkType(obj,tp,resolve=False): def checkType(obj,tp,resolve=False):
if not isTypeOf(obj,tp,resolve): if not isTypeOf(obj,tp,resolve):
raise TypeError('Expect object "{}" to be of type "{}"'.format( raise TypeError('Expect object {} to be of type "{}"'.format(
objName(obj),tp.__name__)) objName(obj),tp.__name__))
def getProxy(obj,tp): def getProxy(obj,tp):
checkType(obj,tp) checkType(obj,tp)
return obj.Proxy return obj.Proxy
# For faking selection obtained from Gui.getSelectionEx()
Selection = namedtuple('AsmSelection',('Object','SubElementNames'))
class AsmBase(object): class AsmBase(object):
def __init__(self): def __init__(self):
self.Object = None self.Object = None
@ -86,6 +89,15 @@ class ViewProviderAsmBase(object):
if cls._iconName: if cls._iconName:
return utils.getIcon(cls) return utils.getIcon(cls)
def canDropObjects(self):
return True
def canDragObjects(self):
return False
def canDragAndDropObject(self,_obj):
return False
class AsmGroup(AsmBase): class AsmGroup(AsmBase):
def linkSetup(self,obj): def linkSetup(self,obj):
@ -115,6 +127,9 @@ class ViewProviderAsmGroup(ViewProviderAsmBase):
def doubleClicked(self, _vobj): def doubleClicked(self, _vobj):
return False return False
def canDropObject(self,_child):
return False
class AsmPartGroup(AsmGroup): class AsmPartGroup(AsmGroup):
def __init__(self,parent): def __init__(self,parent):
@ -139,12 +154,19 @@ class ViewProviderAsmPartGroup(ViewProviderAsmBase):
def onDelete(self,_obj,_subs): def onDelete(self,_obj,_subs):
return False return False
def canDropObject(self,obj): def canDropObjectEx(self,obj,_owner,_subname):
return isTypeOf(obj,Assembly) or not isTypeOf(obj,AsmBase) return isTypeOf(obj,Assembly) or not isTypeOf(obj,AsmBase)
def canDropObjects(self): def canDragObject(self,_obj):
return True return True
def canDragObjects(self):
return True
def canDragAndDropObject(self,_obj):
return True
class AsmElement(AsmBase): class AsmElement(AsmBase):
def __init__(self,parent): def __init__(self,parent):
self.shape = None self.shape = None
@ -237,17 +259,24 @@ class AsmElement(AsmBase):
'The selections must have a common (grand)parent assembly') 'The selections must have a common (grand)parent assembly')
sel = sels[0] sel = sels[0]
subs = sel.SubElementNames subs = list(sel.SubElementNames)
if not subs:
raise RuntimeError('no sub object in selection')
if len(subs)>2: if len(subs)>2:
raise RuntimeError('At most two selection is allowed.\n' raise RuntimeError('At most two selection is allowed.\n'
'The first selection must be a sub element belonging to some ' 'The first selection must be a sub element belonging to some '
'assembly. The optional second selection must be an element ' 'assembly. The optional second selection must be an element '
'belonging to the same assembly of the first selection') '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]]
subElement = subs[0].split('.')[-1] if subs[0][-1] == '.':
subElement = utils.deduceSelectedElement(sel.Object,subs[0])
if not subElement: if not subElement:
raise RuntimeError( raise RuntimeError('no sub element (face, edge, vertex) in '
'Please select a sub element belonging to some assembly') '{}.{}'.format(sel.Object.Name,subs[0]))
subs[0] += subElement
link = Assembly.findPartGroup(sel.Object,subs[0]) link = Assembly.findPartGroup(sel.Object,subs[0])
if not link: if not link:
@ -276,14 +305,17 @@ class AsmElement(AsmBase):
def make(selection=None,name='Element'): def make(selection=None,name='Element'):
if not selection: if not selection:
selection = AsmElement.getSelection() selection = AsmElement.getSelection()
if not selection.Subname or selection.Subname[-1]=='.':
raise RuntimeError('Subname must refer to a sub-element')
assembly = getProxy(selection.Assembly,Assembly) assembly = getProxy(selection.Assembly,Assembly)
element = selection.Element element = selection.Element
if not element: if not element:
elements = assembly.getElementGroup() elements = assembly.getElementGroup()
# 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 elements.Group:
if getProxy(e,AsmElement).getSubName() == selection.Subname: sub = logger.catch('',e.Proxy.getSubName)
return element if sub == selection.Subname:
return e
element = elements.Document.addObject("App::FeaturePython", element = elements.Document.addObject("App::FeaturePython",
name,AsmElement(elements),None,True) name,AsmElement(elements),None,True)
ViewProviderAsmElement(element.ViewObject) ViewProviderAsmElement(element.ViewObject)
@ -307,6 +339,20 @@ class ViewProviderAsmElement(ViewProviderAsmBase):
def getDefaultColor(self): def getDefaultColor(self):
return (60.0/255.0,1.0,1.0) return (60.0/255.0,1.0,1.0)
def canDropObjectEx(self,_obj,owner,subname):
# check if is dropping a sub-element
if not subname or subname[-1]=='.':
return False
proxy = self.ViewObject.Object.Proxy
return proxy.getAssembly().getPartGroup()==owner
def dropObjectEx(self,vobj,_obj,_owner,subname):
obj = vobj.Object
AsmElement.make(AsmElement.Selection(
Assembly=obj.Proxy.getAssembly().Object,
Element=obj, Subname=subname))
PartInfo = namedtuple('AsmPartInfo', ('Parent','SubnameRef','Part', PartInfo = namedtuple('AsmPartInfo', ('Parent','SubnameRef','Part',
'PartName','Placement','Object','Subname','Shape')) 'PartName','Placement','Object','Subname','Shape'))
@ -517,7 +563,9 @@ class AsmElementLink(AsmBase):
logger.debug('shape subname {} -> {}'.format(subname,sub)) logger.debug('shape subname {} -> {}'.format(subname,sub))
return sub return sub
def prepareLink(self,owner,subname): def prepareLink(self,owner,subname,checkOnly=False):
if not owner or not subname:
raise RuntimeError('no owner or subname')
assembly = self.getAssembly() assembly = self.getAssembly()
sobj = owner.getSubObject(subname,1) sobj = owner.getSubObject(subname,1)
if not sobj: if not sobj:
@ -550,6 +598,11 @@ class AsmElementLink(AsmBase):
if not isTypeOf(ret[-1].Object,AsmPartGroup): if not isTypeOf(ret[-1].Object,AsmPartGroup):
raise RuntimeError('Invalid element link ' + subname) raise RuntimeError('Invalid element link ' + subname)
if checkOnly:
if not ret[-1].Subname or ret[-1].Subname[-1]=='.':
raise RuntimeError('Subname must refer to a sub-element')
return True
# call AsmElement.make to either create a new element, or an existing # call AsmElement.make to either create a new element, or an existing
# element if there is one # element if there is one
element = AsmElement.make(AsmElement.Selection( element = AsmElement.make(AsmElement.Selection(
@ -566,7 +619,16 @@ class AsmElementLink(AsmBase):
def setLink(self,owner,subname): def setLink(self,owner,subname):
obj = self.Object obj = self.Object
obj.setLink(*self.prepareLink(owner,subname)) owner,subname = self.prepareLink(owner,subname)
for sibling in self.parent.Object.Group:
if sibling == self.Object:
continue
linked = sibling.LinkedObject
if isinstance(linked,tuple) and \
linked[0]==owner and linked[1]==subname:
raise RuntimeError('duplicate element link {} in constraint '
'{}'.format(objName(sibling),objName(self.parent.Object)))
obj.setLink(owner,subname)
linked = obj.getLinkedObject(False) linked = obj.getLinkedObject(False)
if linked and linked!=obj: if linked and linked!=obj:
label = linked.Label.split('_') label = linked.Label.split('_')
@ -607,7 +669,7 @@ class AsmElementLink(AsmBase):
setupUndo(part.Document,undoDocs,undoName) setupUndo(part.Document,undoDocs,undoName)
part.Placement = pla part.Placement = pla
MakeInfo = namedtuple('AsmElementLinkSelection', MakeInfo = namedtuple('AsmElementLinkMakeInfo',
('Constraint','Owner','Subname')) ('Constraint','Owner','Subname'))
@staticmethod @staticmethod
@ -627,6 +689,17 @@ class ViewProviderAsmElementLink(ViewProviderAsmBase):
def doubleClicked(self,_vobj): def doubleClicked(self,_vobj):
return movePart() return movePart()
def canDropObjectEx(self,_obj,owner,subname):
if logger.catchTrace('Cannot drop to AsmLink {}'.format(
objName(self.ViewObject.Object)),
self.ViewObject.Object.Proxy.prepareLink,
owner, subname, True):
return True
return False
def dropObjectEx(self,vobj,_obj,owner,subname):
vobj.Object.Proxy.setLink(owner,subname)
class AsmConstraint(AsmGroup): class AsmConstraint(AsmGroup):
@ -700,54 +773,69 @@ class AsmConstraint(AsmGroup):
return return
shapes.append(info.Shape) shapes.append(info.Shape)
elements.append(o) elements.append(o)
Constraint.check(obj,shapes) Constraint.check(obj,shapes,True)
self.elements = elements self.elements = elements
return self.elements return self.elements
Selection = namedtuple('ConstraintSelection', Selection = namedtuple('AsmConstraintSelection',
('SelObject','SelSubname','Assembly','Constraint','Elements')) ('SelObject','SelSubname','Assembly','Constraint','Elements'))
@staticmethod @staticmethod
def getSelection(typeid=0): def getSelection(typeid=0,sels=None):
''' '''
Parse Gui.Selection for making a constraint Parse Gui.Selection for making a constraint
The selected elements must all belong to the same immediate parent The selected elements must all belong to the same immediate parent
assembly. assembly.
''' '''
if not sels:
sels = FreeCADGui.Selection.getSelectionEx('',False) sels = FreeCADGui.Selection.getSelectionEx('',False)
if not sels: if not sels:
raise RuntimeError('no selection') raise RuntimeError('no selection')
if len(sels)>1: if len(sels)>1:
raise RuntimeError( raise RuntimeError(
'The selections must have a common (grand)parent assembly') 'The selections must have a common (grand)parent assembly')
subs = sels[0].SubElementNames
if not subs:
raise RuntimeError('no sub-object in selection')
if len(subs)>2:
raise RuntimeError('too many selection')
if len(subs)==2:
sobj = sels[0].Object.getSubObject(subs[1],1)
if isTypeOf(sobj,(AsmConstraintGroup,Assembly,AsmConstraint)):
subs = (subs[1],subs[0])
sel = sels[0] sel = sels[0]
cstr = None cstr = None
elements = [] elements = []
assembly = None assembly = None
selSubname = None selSubname = None
for sub in sel.SubElementNames: for sub in subs:
sobj = sel.Object.getSubObject(sub,1) sobj = sel.Object.getSubObject(sub,1)
if not sobj: if not sobj:
raise RuntimeError('Cannot find sub-object "{}" of {}'.format( raise RuntimeError('Cannot find sub-object {}.{}'.format(
sub,sel.Object)) sel.Object.Name,sub))
ret = Assembly.find(sel.Object,sub, ret = Assembly.find(sel.Object,sub,
recursive=True,relativeToChild=False) recursive=True,relativeToChild=False)
if not ret: if not ret:
raise RuntimeError('Selection {}.{} is not from an ' raise RuntimeError('Selection {}.{} is not from an '
'assembly'.format(sel.Object.Name,sub)) 'assembly'.format(sel.Object.Name,sub))
if not assembly:
# check if the selection is a constraint group or a constraint # check if the selection is a constraint group or a constraint
if isTypeOf(sobj,(AsmConstraintGroup,Assembly,AsmConstraint)): if isTypeOf(sobj,(AsmConstraintGroup,Assembly,AsmConstraint)):
if assembly:
raise RuntimeError('no element selection')
assembly = ret[-1].Assembly assembly = ret[-1].Assembly
selSubname = sub[:-len(ret[-1].Subname)] selSubname = sub[:-len(ret[-1].Subname)]
if isTypeOf(sobj,AsmConstraint): if isTypeOf(sobj,AsmConstraint):
cstr = sobj cstr = sobj
continue continue
if not assembly:
assembly = ret[0].Assembly assembly = ret[0].Assembly
selSubname = sub[:-len(ret[0].Subname)] selSubname = sub[:-len(ret[0].Subname)]
found = ret[0]
else:
found = None found = None
for r in ret: for r in ret:
if r.Assembly == assembly: if r.Assembly == assembly:
@ -755,22 +843,30 @@ class AsmConstraint(AsmGroup):
break break
if not found: if not found:
raise RuntimeError('Selection {}.{} is not from the target ' raise RuntimeError('Selection {}.{} is not from the target '
'assembly {}'.format(sel.Object.Name,sub,objName(assembly))) 'assembly {}'.format(
sel.Object.Name,sub,objName(assembly)))
# because we call Assembly.find() above with relativeToChild=False, # because we call Assembly.find() above with relativeToChild=False,
# we shall adjust the element subname by popping the first '.' # we shall adjust the element subname by popping the first '.'
sub = found.Subname sub = found.Subname
sub = sub[sub.index('.')+1:] sub = sub[sub.index('.')+1:]
if sub[-1] == '.' and not isTypeOf(sobj,(Assembly,AsmConstraint,
AsmConstraintGroup,AsmElement,AsmElementLink)):
# Too bad, its a full selection, let's guess the sub element
subElement = utils.deduceSelectedElement(found.Object,sub)
if not subElement:
raise RuntimeError('no sub element (face, edge, vertex) in '
'{}.{}'.format(found.Object.Name,sub))
sub += subElement
elements.append((found.Object,sub)) elements.append((found.Object,sub))
check = None if not Constraint.isDisabled(cstr):
if cstr and not Constraint.isDisabled(cstr): if cstr:
typeid = Constraint.getTypeID(cstr) typeid = Constraint.getTypeID(cstr)
info = cstr.Proxy.getInfo() check = [o.Proxy.getInfo().Shape for o in cstr.Group] + elements
check = [o.getShape() for o in info.Elements] + elements
else: else:
check = elements check = elements
if check:
Constraint.check(typeid,check) Constraint.check(typeid,check)
return AsmConstraint.Selection(SelObject=sel.Object, return AsmConstraint.Selection(SelObject=sel.Object,
@ -795,7 +891,10 @@ class AsmConstraint(AsmGroup):
doc.openTransaction('Assembly make constraint') doc.openTransaction('Assembly make constraint')
cstr = constraints.Document.addObject("App::FeaturePython", cstr = constraints.Document.addObject("App::FeaturePython",
name,AsmConstraint(constraints),None,True) name,AsmConstraint(constraints),None,True)
ViewProviderAsmConstraint(cstr.ViewObject) proxy = ViewProviderAsmConstraint(cstr.ViewObject)
logger.debug('cstr viewobject {},{},{},{}'.format(
id(proxy),id(cstr.ViewObject.Proxy),
id(proxy.ViewObject),id(cstr.ViewObject)))
constraints.setLink({-1:cstr}) constraints.setLink({-1:cstr})
Constraint.setTypeID(cstr,typeid) Constraint.setTypeID(cstr,typeid)
@ -809,13 +908,15 @@ class AsmConstraint(AsmGroup):
if undo: if undo:
doc.commitTransaction() doc.commitTransaction()
if sel.SelObject:
FreeCADGui.Selection.clearSelection() FreeCADGui.Selection.clearSelection()
subname = sel.SelSubname subname = sel.SelSubname
if subname: if subname:
subname += '.' subname += '.'
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.runCommand('Std_TreeSelection')
return cstr return cstr
except Exception: except Exception:
@ -837,6 +938,44 @@ class ViewProviderAsmConstraint(ViewProviderAsmGroup):
def getIcon(self): def getIcon(self):
return Constraint.getIcon(self.ViewObject.Object) return Constraint.getIcon(self.ViewObject.Object)
def _getSelection(self,owner,subname):
if not owner:
raise RuntimeError('no owner')
parent = getattr(owner.Proxy,'parent',None)
if isinstance(parent,AsmConstraintGroup):
# This can happen when we are dropping another element link from the
# same constraint group, in which case, 'owner' here will be the
# parent constraint of the dropping element link
subname = owner.Name + '.' + subname
owner = parent.Object
parent = parent.parent # ascend to the parent assembly
if not isinstance(parent,Assembly):
raise RuntimeError('not from the same assembly')
subname = owner.Name + '.' + subname
obj = self.ViewObject.Object
mysub = parent.getConstraintGroup().Name + '.' + obj.Name + '.'
sel = [Selection(Object=parent.Object,SubElementNames=[subname,mysub])]
typeid = Constraint.getTypeID(obj)
return AsmConstraint.getSelection(typeid,sel)
def canDropObjectEx(self,_obj,owner,subname):
cstr = self.ViewObject.Object
if logger.catchTrace('Cannot drop to AsmConstraint {}'.format(cstr),
self._getSelection,owner,subname):
return True
return False
def dropObjectEx(self,_vobj,_obj,owner,subname):
sel = self._getSelection(owner,subname)
cstr = self.ViewObject.Object
typeid = Constraint.getTypeID(cstr)
sel = AsmConstraint.Selection(SelObject=None,
SelSubname=None,
Assembly=sel.Assembly,
Constraint=cstr,
Elements=sel.Elements)
AsmConstraint.make(typeid,sel,undo=False)
class AsmConstraintGroup(AsmGroup): class AsmConstraintGroup(AsmGroup):
def __init__(self,parent): def __init__(self,parent):
@ -864,6 +1003,9 @@ class AsmConstraintGroup(AsmGroup):
class ViewProviderAsmConstraintGroup(ViewProviderAsmBase): class ViewProviderAsmConstraintGroup(ViewProviderAsmBase):
_iconName = 'Assembly_Assembly_Constraints_Tree.svg' _iconName = 'Assembly_Assembly_Constraints_Tree.svg'
def canDropObjects(self):
return False
class AsmElementGroup(AsmGroup): class AsmElementGroup(AsmGroup):
def __init__(self,parent): def __init__(self,parent):
@ -876,6 +1018,9 @@ class AsmElementGroup(AsmGroup):
for o in obj.Group: for o in obj.Group:
getProxy(o,AsmElement).parent = self getProxy(o,AsmElement).parent = self
def getAssembly(self):
return self.parent
@staticmethod @staticmethod
def make(parent,name='Elements'): def make(parent,name='Elements'):
obj = parent.Document.addObject("App::FeaturePython",name, obj = parent.Document.addObject("App::FeaturePython",name,
@ -891,24 +1036,17 @@ class ViewProviderAsmElementGroup(ViewProviderAsmBase):
def onDelete(self,_obj,_subs): def onDelete(self,_obj,_subs):
return False return False
def canDragObject(self,_obj):
return False
def canDragObjects(self):
return False
def canDragAndDropObject(self,_obj):
return False
def canDropObjectEx(self,_obj,owner,subname): def canDropObjectEx(self,_obj,owner,subname):
# check if is dropping a sub-element # check if is dropping a sub-element
if subname.rfind('.')+1 == len(subname): if not subname or subname[-1]=='.':
return False return False
return self.ViewObject.Object.Proxy.parent.getPartGroup()==owner proxy = self.ViewObject.Object.Proxy
return proxy.getAssembly().getPartGroup()==owner
def dropObjectEx(self,vobj,_obj,_owner,subname): def dropObjectEx(self,vobj,_obj,_owner,subname):
AsmElement.make(AsmElement.Selection( AsmElement.make(AsmElement.Selection(
vobj.Object.Proxy.parent.Object,None,subname)) Assembly=vobj.Object.Proxy.getAssembly().Object,
Element=None, Subname=subname))
BuildShapeNone = 'None' BuildShapeNone = 'None'
@ -1341,6 +1479,9 @@ def getMovingPartInfo():
if not sels: if not sels:
raise RuntimeError('no selection') raise RuntimeError('no selection')
if not sels[0].SubElementNames:
raise RuntimeError('no sub object in selection')
if len(sels)>1 or len(sels[0].SubElementNames)>2: if len(sels)>1 or len(sels[0].SubElementNames)>2:
raise RuntimeError('too many selection') raise RuntimeError('too many selection')
@ -1401,24 +1542,29 @@ class ViewProviderAssembly(ViewProviderAsmGroup):
self._movingPart = None self._movingPart = None
super(ViewProviderAssembly,self).__init__(vobj) super(ViewProviderAssembly,self).__init__(vobj)
def canDragObject(self,_child): def _convertSubname(self,owner,subname):
sub = subname.split('.')
if not sub:
return
me = self.ViewObject.Object
partGroup = me.Proxy.getPartGroup().ViewObject
if sub == me.Name:
return partGroup,partGroup,subname[len[sub]+1:]
return partGroup,owner,subname
def canDropObjectEx(self,obj,owner,subname):
info = self._convertSubname(owner,subname)
if not info:
return False return False
partGroup,owner,subname = info
def canDragObjects(self): return partGroup.canDropObject(obj,owner,subname)
return False
@property
def PartGroup(self):
return self.ViewObject.Object.Proxy.getPartGroup()
def canDropObject(self,obj):
self.PartGroup.ViewObject.canDropObject(obj)
def canDropObjects(self):
return True
def dropObjectEx(self,_vobj,obj,owner,subname): def dropObjectEx(self,_vobj,obj,owner,subname):
self.PartGroup.ViewObject.dropObject(obj,owner,subname) info = self._convertSubname(owner,subname)
if not info:
return False
partGroup,owner,subname = info
partGroup.dropObject(obj,owner,subname)
def getIcon(self): def getIcon(self):
return System.getIcon(self.ViewObject.Object) return System.getIcon(self.ViewObject.Object)

View File

@ -218,8 +218,8 @@ class Constraint(ProxyType):
return getattr(obj,mcs._disabled,False) return getattr(obj,mcs._disabled,False)
@classmethod @classmethod
def check(mcs,tp,group): def check(mcs,tp,group,checkCount=False):
mcs.getType(tp).check(group) mcs.getType(tp).check(group,checkCount)
@classmethod @classmethod
def prepare(mcs,obj,solver): def prepare(mcs,obj,solver):
@ -260,6 +260,7 @@ class Constraint(ProxyType):
ret = {} ret = {}
for obj in cstrs: for obj in cstrs:
cstr = mcs.getProxy(obj) cstr = mcs.getProxy(obj)
if cstr.hasFixedPart(obj):
for info in cstr.getFixedTransform(obj): for info in cstr.getFixedTransform(obj):
found = True found = True
ret[info.Part] = info ret[info.Part] = info
@ -331,32 +332,33 @@ class Base(with_metaclass(Constraint,object)):
@classmethod @classmethod
def getEntityDef(cls,group,checkCount,obj=None): def getEntityDef(cls,group,checkCount,obj=None):
entities = cls._entityDef entities = cls._entityDef
if len(group) != len(entities): if len(group) == len(entities):
return entities
if cls._workplane and len(group)==len(entities)+1:
return list(entities) + [_w]
if not checkCount and len(group)<len(entities): if not checkCount and len(group)<len(entities):
return entities[:len(group)] return entities[:len(group)]
if cls._workplane and len(group)==len(entities)+1:
entities = list(entities)
entities.append(_w)
else:
if not obj: if not obj:
name = cls.getName() name = cls.getName()
else: else:
name += cstrName(obj) name += cstrName(obj)
raise RuntimeError('Constraint {} has wrong number of ' if len(group)<len(entities):
'elements {}, expecting {}'.format( msg = entities[len(group)](None,None,None,None)
name,len(group),len(entities))) raise RuntimeError('Constraint {} expects a {} element of '
return entities '{}'.format(name,_ordinal[len(group)],msg))
raise RuntimeError('Constraint {} has too many elements, expecting '
'only {}'.format(name,len(entities)))
@classmethod @classmethod
def check(cls,group): def check(cls,group,checkCount=False):
entities = cls.getEntityDef(group,False) entities = cls.getEntityDef(group,checkCount)
for i,e in enumerate(entities): for i,e in enumerate(entities):
o = group[i] o = group[i]
msg = e(None,None,None,o) msg = e(None,None,None,o)
if not msg: if not msg:
continue continue
if i == len(cls._entityDef): if i == len(cls._entityDef):
raise RuntimeError('Constraint "{}" requires the optional {} ' raise RuntimeError('Constraint "{}" requires an optional {} '
'element to be a planar face for defining a ' 'element to be a planar face for defining a '
'workplane'.format(cls.getName(), _ordinal[i], msg)) 'workplane'.format(cls.getName(), _ordinal[i], msg))
raise RuntimeError('Constraint "{}" requires the {} element to be' raise RuntimeError('Constraint "{}" requires the {} element to be'
@ -475,7 +477,7 @@ class Locked(Base):
return ret return ret
@classmethod @classmethod
def check(cls,group): def check(cls,group,_checkCount=False):
if not all([utils.isElement(o) for o in group]): if not all([utils.isElement(o) for o in group]):
raise RuntimeError('Constraint "{}" requires all children to be ' raise RuntimeError('Constraint "{}" requires all children to be '
'of element (Vertex, Edge or Face)'.format(cls.getName())) 'of element (Vertex, Edge or Face)'.format(cls.getName()))
@ -486,7 +488,7 @@ class BaseMulti(Base):
_entityDef = (_wa,) _entityDef = (_wa,)
@classmethod @classmethod
def check(cls,group): def check(cls,group,_checkCount=False):
if len(group)<2: if len(group)<2:
raise RuntimeError('Constraint "{}" requires at least two ' raise RuntimeError('Constraint "{}" requires at least two '
'elements'.format(cls.getName())) 'elements'.format(cls.getName()))

View File

@ -61,6 +61,22 @@ def isLine(param):
else: else:
return isinstance(param,Part.Line) return isinstance(param,Part.Line)
def deduceSelectedElement(obj,subname):
shape = obj.getSubObject(subname)
if not shape:
return
count = len(shape.Faces)
if count==1:
return 'Face1'
elif not count:
count = len(shape.Edges)
if count==1:
return 'Edge1'
elif not count:
count = len(shape.Vertexes)
if count==1:
return 'Vertex1'
def getElement(obj,tp): def getElement(obj,tp):
if isinstance(obj,tuple): if isinstance(obj,tuple):
obj = obj[0].getSubObject(obj[1]) obj = obj[0].getSubObject(obj[1])