assembly: improve constraint mutliplication
It can now auto change any part into link array if necessary.
This commit is contained in:
parent
049eca5bdb
commit
ce3193946a
208
assembly.py
208
assembly.py
|
@ -27,7 +27,7 @@ def getProxy(obj,tp):
|
||||||
|
|
||||||
def getLinkProperty(obj,name,default=None,writable=False):
|
def getLinkProperty(obj,name,default=None,writable=False):
|
||||||
try:
|
try:
|
||||||
obj = obj.getLinkedObject(True)
|
# obj = obj.getLinkedObject(True)
|
||||||
if not writable:
|
if not writable:
|
||||||
return obj.getLinkExtProperty(name)
|
return obj.getLinkExtProperty(name)
|
||||||
name = obj.getLinkExtPropertyName(name)
|
name = obj.getLinkExtPropertyName(name)
|
||||||
|
@ -38,7 +38,7 @@ def getLinkProperty(obj,name,default=None,writable=False):
|
||||||
return default
|
return default
|
||||||
|
|
||||||
def setLinkProperty(obj,name,val):
|
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):
|
def flattenSubname(obj,subname):
|
||||||
|
@ -46,7 +46,7 @@ def flattenSubname(obj,subname):
|
||||||
Falttern any AsmPlainGroups inside subname path. Only the first encountered
|
Falttern any AsmPlainGroups inside subname path. Only the first encountered
|
||||||
assembly along the subname path is considered
|
assembly along the subname path is considered
|
||||||
'''
|
'''
|
||||||
|
|
||||||
func = getattr(obj,'flattenSubname',None)
|
func = getattr(obj,'flattenSubname',None)
|
||||||
if not func:
|
if not func:
|
||||||
return subname
|
return subname
|
||||||
|
@ -406,6 +406,19 @@ class ViewProviderAsmPartGroup(ViewProviderAsmGroup):
|
||||||
cvp.ForceMapColors = True
|
cvp.ForceMapColors = True
|
||||||
vobj.DefaultMode = mode
|
vobj.DefaultMode = mode
|
||||||
|
|
||||||
|
def replaceObject(self,oldObj,newObj):
|
||||||
|
res = self.ViewObject.replaceObject(oldObj,newObj)
|
||||||
|
if res<=0:
|
||||||
|
return res
|
||||||
|
for obj in oldObj.InList:
|
||||||
|
if isTypeOf(obj,AsmElement):
|
||||||
|
link = obj.LinkedObject
|
||||||
|
if isinstance(link,tuple):
|
||||||
|
obj.setLink(newObj,link[1])
|
||||||
|
else:
|
||||||
|
obj.setLink(newObj)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
class AsmVersion(object):
|
class AsmVersion(object):
|
||||||
def __init__(self,v=None):
|
def __init__(self,v=None):
|
||||||
|
@ -877,7 +890,7 @@ class AsmElement(AsmBase):
|
||||||
# it is, after making sure it is referencing an sub-element
|
# it is, after making sure it is referencing an sub-element
|
||||||
if not utils.isElement((group,subname)):
|
if not utils.isElement((group,subname)):
|
||||||
raise RuntimeError( 'Element must reference a geometry '
|
raise RuntimeError( 'Element must reference a geometry '
|
||||||
'element {} {}'.format(objName(group),subname))
|
'element {}.{}'.format(objName(group),subname))
|
||||||
else:
|
else:
|
||||||
# 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
|
||||||
|
@ -1236,41 +1249,42 @@ def getElementInfo(parent,subname,
|
||||||
# special treatment of link array (i.e. when ElementCount!=0), we
|
# special treatment of link array (i.e. when ElementCount!=0), we
|
||||||
# allow the array element to be moveable by the solver
|
# allow the array element to be moveable by the solver
|
||||||
if getLinkProperty(part,'ElementCount'):
|
if getLinkProperty(part,'ElementCount'):
|
||||||
|
|
||||||
|
# Handle old element reference before this link is expanded to
|
||||||
|
# array.
|
||||||
if not names[1]:
|
if not names[1]:
|
||||||
names[1] = '0'
|
names[1] = '0'
|
||||||
names.append('')
|
names.append('')
|
||||||
|
elif len(names) == 2:
|
||||||
|
names.insert(1,'0')
|
||||||
|
|
||||||
# store both the part (i.e. the link array), and the array
|
# store both the part (i.e. the link array), and the array
|
||||||
# element object
|
# element object
|
||||||
part = (part,part.getSubObject(names[1]+'.',1))
|
part = (part,part.getSubObject(names[1]+'.',1))
|
||||||
|
if not part[1]:
|
||||||
|
raise RuntimeError('Cannot find part array element {}.{}.',
|
||||||
|
part.Name,names[1])
|
||||||
|
|
||||||
# trim the subname to be after the array element
|
# trim the subname to be after the array element
|
||||||
subname = '.'.join(names[2:])
|
subname = '.'.join(names[2:])
|
||||||
|
if not shape:
|
||||||
|
shape=utils.getElementShape((part[1],subname))
|
||||||
|
|
||||||
# There are two states of an link array.
|
# There are two states of an link array.
|
||||||
if getLinkProperty(part[0],'ElementList'):
|
if getLinkProperty(part[0],'ElementList'):
|
||||||
# a) The elements are expanded as individual objects, i.e
|
# a) The elements are expanded as individual objects, i.e
|
||||||
# when ElementList has members, then the moveable Placement
|
# when ElementList has members, then the moveable Placement
|
||||||
# is a property of the array element. So we obtain the shape
|
# is a property of the array element.
|
||||||
# before 'Placement' by setting 'transform' set to False.
|
|
||||||
if not shape:
|
|
||||||
shape=utils.getElementShape(
|
|
||||||
(part[1],subname),transform=False)
|
|
||||||
pla = part[0].Placement.multiply(part[1].Placement)
|
pla = part[0].Placement.multiply(part[1].Placement)
|
||||||
obj = part[1].getLinkedObject(False)
|
obj = part[1].getLinkedObject(False)
|
||||||
partName = part[1].Name
|
partName = objName(part[1])
|
||||||
idx = int(partName.split('_i')[-1])
|
idx = int(partName.split('_i')[-1])
|
||||||
part = (part[0],idx,part[1],False)
|
part = (part[0],idx,part[1],False)
|
||||||
else:
|
else:
|
||||||
plaList = getLinkProperty(part[0],'PlacementList',None,True)
|
plaList = getLinkProperty(part[0],'PlacementList',None,True)
|
||||||
if plaList:
|
if plaList:
|
||||||
# b) The elements are collapsed. Then the moveable Placement
|
# b) The elements are collapsed. Then the moveable Placement
|
||||||
# is stored inside link object's PlacementList property. So,
|
# is stored inside link object's PlacementList property.
|
||||||
# the shape obtained below is already before 'Placement',
|
|
||||||
# i.e. must set 'transform' to True.
|
|
||||||
if not shape:
|
|
||||||
shape=utils.getElementShape(
|
|
||||||
(part[1],subname),transform=True)
|
|
||||||
obj = part[1]
|
obj = part[1]
|
||||||
try:
|
try:
|
||||||
if names[1] == part[1].Name:
|
if names[1] == part[1].Name:
|
||||||
|
@ -1287,7 +1301,7 @@ def getElementInfo(parent,subname,
|
||||||
raise RuntimeError('invalid array subname of element '
|
raise RuntimeError('invalid array subname of element '
|
||||||
'{}: {}'.format(objName(parent),subnameRef))
|
'{}: {}'.format(objName(parent),subnameRef))
|
||||||
|
|
||||||
partName = '{}.{}.'.format(part[0].Name,idx)
|
partName = '{}.{}.'.format(objName(part[0]),idx)
|
||||||
|
|
||||||
if not obj:
|
if not obj:
|
||||||
part = partSaved
|
part = partSaved
|
||||||
|
@ -1438,26 +1452,26 @@ class AsmElementLink(AsmBase):
|
||||||
not getattr(self,'parent',None) or \
|
not getattr(self,'parent',None) or \
|
||||||
FreeCAD.isRestoring():
|
FreeCAD.isRestoring():
|
||||||
return
|
return
|
||||||
if obj.Document and getattr(obj.Document,'Transacting',False):
|
elif obj.Document and getattr(obj.Document,'Transacting',False):
|
||||||
self.infos *= 0 # clear the list
|
self.infos *= 0 # clear the list
|
||||||
self.info = None
|
self.info = None
|
||||||
return
|
return
|
||||||
if prop == 'Count':
|
elif prop == 'Count':
|
||||||
self.infos *= 0 # clear the list
|
self.infos *= 0 # clear the list
|
||||||
self.info = None
|
self.info = None
|
||||||
return
|
return
|
||||||
if prop == 'Offset':
|
elif prop == 'Offset':
|
||||||
self.getInfo(True)
|
self.getInfo(True)
|
||||||
return
|
return
|
||||||
if prop == 'NoExpand':
|
elif prop == 'NoExpand':
|
||||||
cstr = self.parent.Object
|
cstr = self.parent.Object
|
||||||
if obj!=flattenGroup(cstr)[0] \
|
if obj!=cstr.Group[0] \
|
||||||
and cstr.Multiply \
|
and cstr.Multiply \
|
||||||
and obj.LinkedObject:
|
and obj.LinkedObject:
|
||||||
self.setLink(self.getAssembly().getPartGroup(),
|
self.setLink(self.getAssembly().getPartGroup(),
|
||||||
self.getElementSubname(True))
|
self.getElementSubname(True))
|
||||||
return
|
return
|
||||||
if prop == 'Label':
|
elif prop == 'Label':
|
||||||
if obj.Document and getattr(obj.Document,'Transacting',False):
|
if obj.Document and getattr(obj.Document,'Transacting',False):
|
||||||
return
|
return
|
||||||
link = getattr(obj,'LinkedObject',None)
|
link = getattr(obj,'LinkedObject',None)
|
||||||
|
@ -1471,6 +1485,9 @@ class AsmElementLink(AsmBase):
|
||||||
# re-lable it.
|
# re-lable it.
|
||||||
obj.Label = linked.Label
|
obj.Label = linked.Label
|
||||||
return
|
return
|
||||||
|
elif prop == 'AutoCount':
|
||||||
|
if obj.AutoCount and hasattr(obj,'ShowElement'):
|
||||||
|
self.parent.checkMultiply()
|
||||||
if prop not in self._MyIgnoredProperties and \
|
if prop not in self._MyIgnoredProperties and \
|
||||||
not Constraint.isDisabled(self.parent.Object):
|
not Constraint.isDisabled(self.parent.Object):
|
||||||
Assembly.autoSolve(obj,prop)
|
Assembly.autoSolve(obj,prop)
|
||||||
|
@ -1634,7 +1651,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 == flattenGroup(parent)[0]:
|
if obj == parent.Group[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)
|
||||||
|
@ -1653,10 +1670,11 @@ class AsmElementLink(AsmBase):
|
||||||
part = (part[0],i,sobj,part[3])
|
part = (part[0],i,sobj,part[3])
|
||||||
pla = part[0].Placement.multiply(pla)
|
pla = part[0].Placement.multiply(pla)
|
||||||
plaList.append(pla.multiply(offset))
|
plaList.append(pla.multiply(offset))
|
||||||
infos.append(ElementInfo(Parent = info.Parent,
|
infos.append(ElementInfo(
|
||||||
|
Parent = info.Parent,
|
||||||
SubnameRef = info.SubnameRef,
|
SubnameRef = info.SubnameRef,
|
||||||
Part=part,
|
Part=part,
|
||||||
PartName = '{}.{}'.format(part[0].Name,i),
|
PartName = '{}.{}'.format(objName(part[0]),i),
|
||||||
Placement = pla,
|
Placement = pla,
|
||||||
Object = info.Object,
|
Object = info.Object,
|
||||||
Subname = info.Subname,
|
Subname = info.Subname,
|
||||||
|
@ -1778,7 +1796,7 @@ class ViewProviderAsmElementLink(ViewProviderAsmOnTop):
|
||||||
class AsmConstraint(AsmGroup):
|
class AsmConstraint(AsmGroup):
|
||||||
|
|
||||||
def __init__(self,parent):
|
def __init__(self,parent):
|
||||||
self.prevOrder = None
|
self.prevOrder = []
|
||||||
self.version = None
|
self.version = None
|
||||||
self._initializing = True
|
self._initializing = True
|
||||||
self.elements = None
|
self.elements = None
|
||||||
|
@ -1813,6 +1831,7 @@ class AsmConstraint(AsmGroup):
|
||||||
|
|
||||||
def onChanged(self,obj,prop):
|
def onChanged(self,obj,prop):
|
||||||
if obj.Document and getattr(obj.Document,'Transacting',False):
|
if obj.Document and getattr(obj.Document,'Transacting',False):
|
||||||
|
Constraint.onChanged(obj,prop)
|
||||||
return
|
return
|
||||||
if not obj.Removing and prop not in _IgnoredProperties:
|
if not obj.Removing and prop not in _IgnoredProperties:
|
||||||
if prop == Constraint.propMultiply() and not FreeCAD.isRestoring():
|
if prop == Constraint.propMultiply() and not FreeCAD.isRestoring():
|
||||||
|
@ -1844,7 +1863,11 @@ class AsmConstraint(AsmGroup):
|
||||||
obj = self.Object
|
obj = self.Object
|
||||||
if not obj.Multiply:
|
if not obj.Multiply:
|
||||||
return
|
return
|
||||||
children = flattenGroup(obj)
|
|
||||||
|
if getattr(obj,'Cascade',False):
|
||||||
|
obj.Cascade = False
|
||||||
|
|
||||||
|
children = obj.Group
|
||||||
if len(children)<=1:
|
if len(children)<=1:
|
||||||
return
|
return
|
||||||
count = 0
|
count = 0
|
||||||
|
@ -1896,13 +1919,13 @@ class AsmConstraint(AsmGroup):
|
||||||
firstChild = children[0]
|
firstChild = children[0]
|
||||||
info = firstChild.Proxy.getInfo()
|
info = firstChild.Proxy.getInfo()
|
||||||
if not isinstance(info.Part,tuple):
|
if not isinstance(info.Part,tuple):
|
||||||
raise RuntimeError('Expect part {} to be an array for'
|
raise RuntimeError('Expect part {} to be an array for '
|
||||||
'constraint multiplication'.format(info.PartName))
|
'constraint multiplication'.format(info.PartName))
|
||||||
|
|
||||||
touched = 'Touched' in firstChild.State
|
touched = 'Touched' in firstChild.State
|
||||||
if not hasattr(firstChild,'Count'):
|
if not hasattr(firstChild,'Count'):
|
||||||
firstChild.addProperty("App::PropertyInteger","Count",'','')
|
firstChild.addProperty("App::PropertyInteger","Count",'','')
|
||||||
firstChild.setPropertyStatus('Count',('ReadOnly','Output'))
|
firstChild.setPropertyStatus('Count','ReadOnly')
|
||||||
firstChild.addProperty("App::PropertyBool","AutoCount",'',
|
firstChild.addProperty("App::PropertyBool","AutoCount",'',
|
||||||
'Auto change part count to match constraining elements')
|
'Auto change part count to match constraining elements')
|
||||||
firstChild.AutoCount = True
|
firstChild.AutoCount = True
|
||||||
|
@ -1931,7 +1954,7 @@ class AsmConstraint(AsmGroup):
|
||||||
|
|
||||||
if firstChild.Count != count:
|
if firstChild.Count != count:
|
||||||
firstChild.Count = count
|
firstChild.Count = count
|
||||||
firstChild.Proxy.getInfo(True)
|
firstChild.recompute()
|
||||||
|
|
||||||
if not touched and 'Touched' in firstChild.State:
|
if not touched and 'Touched' in firstChild.State:
|
||||||
# purge touched to avoid recomputation multi-pass
|
# purge touched to avoid recomputation multi-pass
|
||||||
|
@ -2016,6 +2039,7 @@ class AsmConstraint(AsmGroup):
|
||||||
# initial placement
|
# initial placement
|
||||||
|
|
||||||
partGroup = self.getAssembly().getPartGroup()
|
partGroup = self.getAssembly().getPartGroup()
|
||||||
|
touched = False
|
||||||
for i,info0 in enumerate(infos0):
|
for i,info0 in enumerate(infos0):
|
||||||
if not distances[i]:
|
if not distances[i]:
|
||||||
continue
|
continue
|
||||||
|
@ -2042,10 +2066,13 @@ class AsmConstraint(AsmGroup):
|
||||||
else:
|
else:
|
||||||
pla = info0.Placement.multiply(pla.multiply(pla0.inverse()))
|
pla = info0.Placement.multiply(pla.multiply(pla0.inverse()))
|
||||||
showPart(partGroup,info0.Part)
|
showPart(partGroup,info0.Part)
|
||||||
info0.Placement.Rotation = pla.Rotation
|
touched = True
|
||||||
info0.Placement.Base = pla.Base
|
|
||||||
setPlacement(info0.Part,pla,True)
|
setPlacement(info0.Part,pla,True)
|
||||||
|
|
||||||
|
if touched:
|
||||||
|
firstChild.Proxy.getInfo(True)
|
||||||
|
firstChild.purgeTouched()
|
||||||
|
|
||||||
def execute(self,obj):
|
def execute(self,obj):
|
||||||
if not getattr(self,'_initializing',False) and\
|
if not getattr(self,'_initializing',False) and\
|
||||||
getattr(self,'parent',None):
|
getattr(self,'parent',None):
|
||||||
|
@ -2085,7 +2112,6 @@ class AsmConstraint(AsmGroup):
|
||||||
elements.append(o)
|
elements.append(o)
|
||||||
if count <= len(infos):
|
if count <= len(infos):
|
||||||
infos = infos[:count]
|
infos = infos[:count]
|
||||||
o.Proxy.infos = infos
|
|
||||||
elementInfo += infos
|
elementInfo += infos
|
||||||
break
|
break
|
||||||
elementInfo += infos
|
elementInfo += infos
|
||||||
|
@ -2280,37 +2306,93 @@ class AsmConstraint(AsmGroup):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def makeMultiply(checkOnly=False):
|
def makeMultiply(checkOnly=False):
|
||||||
sels = FreeCADGui.Selection.getSelection()
|
sel = FreeCADGui.Selection.getSelectionEx('*',0)
|
||||||
if not len(sels)==1 or not isTypeOf(sels[0],AsmConstraint):
|
if len(sel)!=1 or len(sel[0].SubElementNames)!=1:
|
||||||
|
raise RuntimeError('Too many selections')
|
||||||
|
|
||||||
|
sel = sel[0]
|
||||||
|
cstr = sel.Object.getSubObject(sel.SubElementNames[0],1)
|
||||||
|
if not isTypeOf(cstr,AsmConstraint):
|
||||||
raise RuntimeError('Must select a constraint')
|
raise RuntimeError('Must select a constraint')
|
||||||
cstr = sels[0]
|
|
||||||
multiplied = Constraint.canMultiply(cstr)
|
multiplied = Constraint.canMultiply(cstr)
|
||||||
if multiplied is None:
|
if multiplied is None:
|
||||||
raise RuntimeError('Constraint do not support multiplication')
|
raise RuntimeError('Constraint do not support multiplication')
|
||||||
|
|
||||||
elements = cstr.Proxy.getElements()
|
elements = cstr.Proxy.getElements()
|
||||||
if len(elements)<=1:
|
if len(elements)<2:
|
||||||
raise RuntimeError('Constraint must have more than one element')
|
raise RuntimeError('Constraint must have more than one element')
|
||||||
|
|
||||||
info = elements[0].Proxy.getInfo()
|
if checkOnly:
|
||||||
if not isinstance(info.Part,tuple) or info.Part[1]!=0:
|
return True
|
||||||
raise RuntimeError('Constraint multiplication requires the first '
|
|
||||||
'element to be from the first element of a link array')
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if not checkOnly:
|
FreeCAD.setActiveTransaction("Assembly constraint multiply")
|
||||||
FreeCAD.setActiveTransaction("Assembly constraint multiply")
|
|
||||||
|
info = elements[0].Proxy.getInfo()
|
||||||
|
if not isinstance(info.Part,tuple):
|
||||||
|
# The first element must be an link array in order to get
|
||||||
|
# multiplied.
|
||||||
|
|
||||||
|
#First, check if it is a link (with element count)
|
||||||
|
if getLinkProperty(info.Part,'ElementCount') is None:
|
||||||
|
# No. So we replace it with a link with command
|
||||||
|
# Std_LinkReplace, which requires a select of the object
|
||||||
|
# to be replaced first. So construct the selection path
|
||||||
|
# by replacing the last two subnames (i.e.
|
||||||
|
# Constraints.Constraint) with PartGroup.PartName
|
||||||
|
|
||||||
|
subs = flattenSubname(sel.Object,sel.SubElementNames[0])
|
||||||
|
subs = subs.split('.')
|
||||||
|
# The last entry is for sub-element name (e.g. Edge1,
|
||||||
|
# Face2), which should be empty
|
||||||
|
subs[-1] = ''
|
||||||
|
subs[-2] = info.Part.Name
|
||||||
|
subs[-3] = '2'
|
||||||
|
# remember last selection
|
||||||
|
FreeCADGui.Selection.pushSelStack()
|
||||||
|
FreeCADGui.Selection.clearSelection()
|
||||||
|
FreeCADGui.Selection.addSelection(
|
||||||
|
sel.Object,'.'.join(subs))
|
||||||
|
FreeCADGui.Selection.pushSelStack()
|
||||||
|
FreeCADGui.runCommand('Std_LinkReplace')
|
||||||
|
# restore the last selection
|
||||||
|
FreeCADGui.runCommand('Std_SelBack')
|
||||||
|
|
||||||
|
info = elements[0].Proxy.getInfo(True)
|
||||||
|
# make sure the replace command works
|
||||||
|
if getLinkProperty(info.Part,'ElementCount') is None:
|
||||||
|
raise RuntimeError('Failed to replace part with a link')
|
||||||
|
|
||||||
|
# Let's first make an single element array without showing
|
||||||
|
# its element object, which will make the linked object
|
||||||
|
# grouped under the link rather than floating under tree
|
||||||
|
# view root
|
||||||
|
setLinkProperty(info.Part,'ShowElement',False)
|
||||||
|
try:
|
||||||
|
setLinkProperty(info.Part,'ElementCount',1)
|
||||||
|
except Exception:
|
||||||
|
raise RuntimeError('Failed to change element count of '
|
||||||
|
'{}'.format(info.PartName))
|
||||||
|
|
||||||
partGroup = cstr.Proxy.getAssembly().getPartGroup()
|
partGroup = cstr.Proxy.getAssembly().getPartGroup()
|
||||||
|
|
||||||
if multiplied:
|
cstr.recompute(True)
|
||||||
cstr.recompute(True)
|
|
||||||
|
if not multiplied:
|
||||||
|
for elementLink in elements[1:]:
|
||||||
|
subname = elementLink.Proxy.getElementSubname(True)
|
||||||
|
elementLink.Proxy.setLink(
|
||||||
|
partGroup,subname,checkOnly,multiply=True)
|
||||||
|
cstr.Multiply = True
|
||||||
|
else:
|
||||||
|
# Here means the constraint is already multiplied, expand it to
|
||||||
|
# multiple individual constraints
|
||||||
elements = cstr.Proxy.getElements()
|
elements = cstr.Proxy.getElements()
|
||||||
subs = elements[0].Proxy.getElementSubname(True).split('.')
|
infos0 = [(partGroup,'{}.{}.{}'.format(info.Part[0].Name,
|
||||||
infos0 = []
|
info.Part[1],
|
||||||
for info0 in elements[0].Proxy.getInfo(expand=True):
|
info.Subname)) \
|
||||||
subs[1] = str(info0.Part[1])
|
for info in elements[0].Proxy.getInfo(expand=True)]
|
||||||
infos0.append((partGroup,'.'.join(subs)))
|
|
||||||
infos = []
|
infos = []
|
||||||
for element in elements[1:]:
|
for element in elements[1:]:
|
||||||
if element.NoExpand:
|
if element.NoExpand:
|
||||||
|
@ -2334,8 +2416,6 @@ class AsmConstraint(AsmGroup):
|
||||||
if subs[1] == subs[2]:
|
if subs[1] == subs[2]:
|
||||||
subs[1] = ''
|
subs[1] = ''
|
||||||
infos.append((partGroup,Part.joinSubname(*subs)))
|
infos.append((partGroup,Part.joinSubname(*subs)))
|
||||||
if checkOnly:
|
|
||||||
return True
|
|
||||||
assembly = cstr.Proxy.getAssembly().Object
|
assembly = cstr.Proxy.getAssembly().Object
|
||||||
typeid = Constraint.getTypeID(cstr)
|
typeid = Constraint.getTypeID(cstr)
|
||||||
for info in zip(infos0,infos[:len(infos0)]):
|
for info in zip(infos0,infos[:len(infos0)]):
|
||||||
|
@ -2346,23 +2426,14 @@ 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,flattenGroup(newCstr)):
|
for element,target in zip(elements,newCstr.Group):
|
||||||
target.Offset = element.Offset
|
target.Offset = element.Offset
|
||||||
cstr.Document.removeObject(cstr.Name)
|
cstr.Document.removeObject(cstr.Name)
|
||||||
FreeCAD.closeActiveTransaction()
|
|
||||||
return True
|
|
||||||
|
|
||||||
for elementLink in elements[1:]:
|
FreeCAD.closeActiveTransaction()
|
||||||
subname = elementLink.Proxy.getElementSubname(True)
|
|
||||||
elementLink.Proxy.setLink(
|
|
||||||
partGroup,subname,checkOnly,multiply=True)
|
|
||||||
if not checkOnly:
|
|
||||||
cstr.Multiply = True
|
|
||||||
FreeCAD.closeActiveTransaction()
|
|
||||||
return True
|
return True
|
||||||
except Exception:
|
except Exception:
|
||||||
if not checkOnly:
|
FreeCAD.closeActiveTransaction(True)
|
||||||
FreeCAD.closeActiveTransaction(True)
|
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
@ -2464,7 +2535,6 @@ class AsmConstraintGroup(AsmGroup):
|
||||||
if obj.Document and getattr(obj.Document,'Transacting',False):
|
if obj.Document and getattr(obj.Document,'Transacting',False):
|
||||||
return
|
return
|
||||||
if prop not in _IgnoredProperties:
|
if prop not in _IgnoredProperties:
|
||||||
System.onChanged(obj,prop)
|
|
||||||
Assembly.autoSolve(obj,prop)
|
Assembly.autoSolve(obj,prop)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -3008,8 +3078,8 @@ class AsmRelation(AsmBase):
|
||||||
else:
|
else:
|
||||||
part = obj.Part
|
part = obj.Part
|
||||||
group = []
|
group = []
|
||||||
for cstr in self.getAssembly().getConstraintGroup().LinkedChildren:
|
for cstr in flattenGroup(self.getAssembly().getConstraintGroup()):
|
||||||
for element in flattenGroup(cstr):
|
for element in cstr.Group:
|
||||||
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]
|
||||||
|
@ -3501,7 +3571,7 @@ class Assembly(AsmGroup):
|
||||||
continue
|
continue
|
||||||
if not System.isConstraintSupported(self.Object,
|
if not System.isConstraintSupported(self.Object,
|
||||||
Constraint.getTypeName(o)):
|
Constraint.getTypeName(o)):
|
||||||
logger.debug('skip unsupported constraint '
|
logger.warn('skip unsupported constraint '
|
||||||
'{}',cstrName(o))
|
'{}',cstrName(o))
|
||||||
continue
|
continue
|
||||||
ret.append(o)
|
ret.append(o)
|
||||||
|
|
11
gui.py
11
gui.py
|
@ -1038,12 +1038,11 @@ 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'\
|
||||||
'against the rest of the elements.\n\n'\
|
'against the rest of the elements. It will auto replace the\n'\
|
||||||
'To activate this function, the FIRST part must be of the\n'\
|
'first part owner with a link array when necessary.\n\n'\
|
||||||
'FIRST element of a link array. In will optionally expand\n'\
|
'It will also optionally expand colplanar circular edges with\n'\
|
||||||
'colplanar circular edges with the same radius in the second\n'\
|
'the same radius in the second element on wards. To disable\n'\
|
||||||
'element on wards. To disable auto expansion, use NoExpand\n'\
|
'auto expansion, use NoExpand property in the element link.'
|
||||||
'property in the element link.'
|
|
||||||
_iconName = 'Assembly_ConstraintMultiply.svg'
|
_iconName = 'Assembly_ConstraintMultiply.svg'
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|
Loading…
Reference in New Issue
Block a user