Fix constraint multiplication
This commit is contained in:
parent
cb84709871
commit
6cff9d111b
106
assembly.py
106
assembly.py
|
@ -1181,7 +1181,7 @@ class AsmElementLink(AsmBase):
|
|||
return self.infos if expand else self.info
|
||||
|
||||
self.info = None
|
||||
self.infos *= 0 # clear the list
|
||||
self.infos = []
|
||||
obj = getattr(self,'Object',None)
|
||||
if not obj:
|
||||
return
|
||||
|
@ -1286,19 +1286,32 @@ class AsmElementLink(AsmBase):
|
|||
info.Constraint.setElementVisible(link.Name,False)
|
||||
return link
|
||||
|
||||
def setPlacement(part,pla):
|
||||
|
||||
def setPlacement(part,pla,purgeTouched=False):
|
||||
''' called by solver after solving to adjust the placement.
|
||||
|
||||
part: obtained by AsmConstraint.getInfo().Part pla: the new placement
|
||||
'''
|
||||
if isinstance(part,tuple):
|
||||
if not isinstance(part,tuple):
|
||||
if purgeTouched:
|
||||
obj = part
|
||||
touched = 'Touched' in obj.State
|
||||
part.Placement = pla
|
||||
else:
|
||||
pla = part[0].Placement.inverse().multiply(pla)
|
||||
if part[3]:
|
||||
if purgeTouched:
|
||||
obj = part[0]
|
||||
touched = 'Touched' in obj.State
|
||||
setLinkProperty(part[0],'PlacementList',{part[1]:pla})
|
||||
else:
|
||||
if purgeTouched:
|
||||
obj = part[2]
|
||||
touched = 'Touched' in obj.State
|
||||
part[2].Placement = pla
|
||||
else:
|
||||
part.Placement = pla
|
||||
if purgeTouched and not touched:
|
||||
obj.purgeTouched()
|
||||
|
||||
|
||||
class ViewProviderAsmElementLink(ViewProviderAsmOnTop):
|
||||
def __init__(self,vobj):
|
||||
|
@ -1418,21 +1431,29 @@ class AsmConstraint(AsmGroup):
|
|||
name = 'Edge1'
|
||||
if not elementCount:
|
||||
shapes.append(None)
|
||||
e.Proxy.infos = []
|
||||
else:
|
||||
count += elementCount
|
||||
shapes.append(info.Shape.getElement(name))
|
||||
|
||||
# merge elements that are coplanar
|
||||
poses = []
|
||||
infos = []
|
||||
for i,e in enumerate(children[1:]):
|
||||
shape = shapes[i]
|
||||
if not shape or not e.Proxy.infos:
|
||||
if not shape:
|
||||
continue
|
||||
for j,e2 in enumerate(children[i+2:]):
|
||||
shape2 = shapes[i+j+1]
|
||||
if not shape2 or not e2.Proxy.infos:
|
||||
if not shape2:
|
||||
continue
|
||||
if shape.isCoplanar(shape2):
|
||||
e.Proxy.infos += e2.Proxy.infos
|
||||
e2.Proxy.infos = []
|
||||
for info in e.Proxy.infos:
|
||||
infos.append(info)
|
||||
poses.append(info.Placement.multVec(
|
||||
utils.getElementPos(info.Shape)))
|
||||
|
||||
firstChild = children[0]
|
||||
info = firstChild.Proxy.getInfo()
|
||||
|
@ -1456,25 +1477,66 @@ class AsmConstraint(AsmGroup):
|
|||
'ShowElement',ElementCount='Count')
|
||||
|
||||
if firstChild.AutoCount:
|
||||
if getLinkProperty(info.Part[0],'ElementCount',None,True) is None:
|
||||
oldCount = getLinkProperty(info.Part[0],'ElementCount',None,True)
|
||||
if oldCount is None:
|
||||
firstChild.AutoCount = False
|
||||
else:
|
||||
elif oldCount < count:
|
||||
partTouched = 'Touched' in info.Part[0].State
|
||||
setLinkProperty(info.Part[0],'ElementCount',count)
|
||||
if not partTouched:
|
||||
info.Part[0].purgeTouched()
|
||||
|
||||
if not firstChild.AutoCount:
|
||||
count = getLinkProperty(info.Part[0],'ElementCount')
|
||||
oldCount = getLinkProperty(info.Part[0],'ElementCount')
|
||||
if count > oldCount:
|
||||
count = oldCount
|
||||
|
||||
if firstChild.Count != count:
|
||||
firstChild.Count = count
|
||||
firstChild.Proxy.getInfo(True)
|
||||
|
||||
if not touched and 'Touched' in firstChild.State:
|
||||
firstChild.Proxy.getInfo(True)
|
||||
# purge touched to avoid recomputation multi-pass
|
||||
firstChild.purgeTouched()
|
||||
|
||||
# To solve the problem of element index reordering, we shall reorder the
|
||||
# linux array infos by its proximity to the corresponding constraining
|
||||
# element shape
|
||||
|
||||
poses = poses[:count]
|
||||
infos0 = firstChild.Proxy.getInfo(expand=True)[:count]
|
||||
distances = []
|
||||
for i,info0 in enumerate(infos0):
|
||||
pos0 = info0.Placement.multVec(utils.getElementPos(info0.Shape))
|
||||
for j,pos in enumerate(poses):
|
||||
distances.append((pos0.distanceToPoint(pos),i,j))
|
||||
|
||||
distances.sort()
|
||||
|
||||
used = [-1]*count
|
||||
order = [None]*count
|
||||
for _,i,j in distances:
|
||||
if used[i]>=0 or order[j]:
|
||||
continue
|
||||
used[i] = j
|
||||
order[j] = infos0[i]
|
||||
count -= 1
|
||||
if not count:
|
||||
break
|
||||
firstChild.Proxy.infos = order
|
||||
|
||||
for i in used[oldCount:]:
|
||||
info0 = order[i]
|
||||
info = infos[i]
|
||||
pla = info.Placement.multiply(
|
||||
utils.getElementPlacement(info.Shape))
|
||||
pla0 = info0.Placement.multiply(
|
||||
utils.getElementPlacement(info0.Shape))
|
||||
pla = info0.Placement.multiply(pla.multiply(pla0.inverse()))
|
||||
info0.Placement.Rotation = pla.Rotation
|
||||
info0.Placement.Base = pla.Base
|
||||
setPlacement(info0.Part,pla,True)
|
||||
|
||||
def execute(self,obj):
|
||||
if not getattr(self,'_initializing',False) and\
|
||||
getattr(self,'parent',None):
|
||||
|
@ -1500,16 +1562,23 @@ class AsmConstraint(AsmGroup):
|
|||
group = obj.Group
|
||||
if Constraint.canMultiply(obj):
|
||||
firstInfo = group[0].Proxy.getInfo(expand=True)
|
||||
if not firstInfo:
|
||||
count = len(firstInfo)
|
||||
if not count:
|
||||
raise RuntimeError('invalid first element')
|
||||
elements.append(group[0])
|
||||
for o in group[1:]:
|
||||
info = o.Proxy.getInfo(expand=True)
|
||||
if not info:
|
||||
infos = o.Proxy.getInfo(expand=True)
|
||||
if not infos:
|
||||
continue
|
||||
elementInfo += info
|
||||
elements.append(o)
|
||||
for info in zip(firstInfo,elementInfo[:len(firstInfo)]):
|
||||
if count <= len(infos):
|
||||
infos = infos[:count]
|
||||
o.Proxy.infos = infos
|
||||
elementInfo += infos
|
||||
break
|
||||
elementInfo += infos
|
||||
|
||||
for info in zip(firstInfo,elementInfo):
|
||||
Constraint.check(obj,info,True)
|
||||
else:
|
||||
for o in group:
|
||||
|
@ -1722,10 +1791,11 @@ class AsmConstraint(AsmGroup):
|
|||
partGroup = cstr.Proxy.getAssembly().getPartGroup()
|
||||
|
||||
if multiplied:
|
||||
cstr.recompute(True)
|
||||
subs = elements[0].Proxy.getElementSubname(True).split('.')
|
||||
infos0 = []
|
||||
for i in xrange(elements[0].Count):
|
||||
subs[1] = str(i)
|
||||
for info0 in elements[0].Proxy.getInfo(expand=True):
|
||||
subs[1] = str(info0.Part[1])
|
||||
infos0.append((partGroup,'.'.join(subs)))
|
||||
infos = []
|
||||
for element in elements[1:]:
|
||||
|
|
|
@ -978,23 +978,62 @@ class BaseMulti(Base):
|
|||
if not count:
|
||||
logger.warn('{} no first part shape'.format(cstrName(obj)))
|
||||
return
|
||||
|
||||
dragPart = solver.getDragPart()
|
||||
dragIndex = -1
|
||||
if isinstance(dragPart,tuple) and \
|
||||
dragPart[0]==firstInfo[0].Part[0] and \
|
||||
solver.getArrayPartConstraintCount(dragPart)==1 and \
|
||||
dragPart[1] < count:
|
||||
dragIndex = dragPart[1]
|
||||
|
||||
idx = 0
|
||||
for element in elements[1:]:
|
||||
updates = []
|
||||
for i,info in enumerate(element.Proxy.getInfo(expand=True)):
|
||||
info0Ref = None
|
||||
infoRef = None
|
||||
shapeRef = None
|
||||
refIdx = -1
|
||||
infos = element.Proxy.getInfo(expand=True)
|
||||
|
||||
# make sure the dragging part is picked as reference for
|
||||
# coplanar shortcut updating
|
||||
if dragIndex>=0:
|
||||
for i,info in enumerate(infos):
|
||||
if idx+i >= count:
|
||||
break
|
||||
info0 = firstInfo[idx+i]
|
||||
if info0.Part[1] == dragIndex:
|
||||
dragIndex = -1
|
||||
info0Ref = solver.getPartInfo(info0)
|
||||
infoRef = solver.getPartInfo(info)
|
||||
shapeRef = info.Shape
|
||||
refIdx = i
|
||||
break
|
||||
|
||||
for i,info in enumerate(infos):
|
||||
if idx >= count:
|
||||
break
|
||||
info0 = firstInfo[idx]
|
||||
if i and solver.getArrayPartConstraintCount(info0.Part)==1:
|
||||
# We can safely skip those coplanar edges if the part
|
||||
# array element is involved in one and only one
|
||||
partInfo = solver.getPartInfo(info)
|
||||
|
||||
if solver.getArrayPartConstraintCount(info0.Part)!=1:
|
||||
partInfo0 = solver.getPartInfo(info0)
|
||||
elif not infoRef:
|
||||
partInfo0 = solver.getPartInfo(info0)
|
||||
info0Ref = partInfo0
|
||||
infoRef = partInfo
|
||||
shapeRef = info.Shape
|
||||
elif i == refIdx:
|
||||
partInfo0 = info0Ref
|
||||
else:
|
||||
# We can safely skip those coplanar edges if the
|
||||
# part array element is involved in one and only one
|
||||
# constraint (i.e. this one).
|
||||
updates.append((idx,i))
|
||||
updates.append((info0,partInfo,info.Shape))
|
||||
idx += 1
|
||||
continue
|
||||
|
||||
partInfo0 = solver.getPartInfo(info0)
|
||||
partInfo = solver.getPartInfo(info)
|
||||
e0 = cls._entityDef[0](
|
||||
solver,partInfo0,info0.Subname,info0.Shape)
|
||||
e = cls._entityDef[0](
|
||||
|
@ -1009,7 +1048,7 @@ class BaseMulti(Base):
|
|||
idx += 1
|
||||
|
||||
if updates:
|
||||
partInfo0.Update.append((updates,element))
|
||||
info0Ref.Update.append((infoRef,shapeRef,updates))
|
||||
|
||||
return ret
|
||||
|
||||
|
|
34
solver.py
34
solver.py
|
@ -44,6 +44,7 @@ class Solver(object):
|
|||
self._cstrMap = {}
|
||||
self._cstrArrayMap = defaultdict(int)
|
||||
self._fixedElements = set()
|
||||
self._dragPart = dragPart
|
||||
|
||||
self.system.GroupHandle = self._fixedGroup
|
||||
|
||||
|
@ -207,28 +208,18 @@ class Solver(object):
|
|||
part.FirstAngle = v[1]
|
||||
part.LastAngle = v[2]
|
||||
|
||||
if recompute and touched:
|
||||
assembly.recompute(True)
|
||||
|
||||
# Update parts with constraint multiplication, which auto expands
|
||||
# coplanar circular edges of the same radius. For performance sake, only
|
||||
# the first edge of each expansion is used for constraint. We simply
|
||||
# translate the rest of the parts with the same relative offset.
|
||||
touched = False
|
||||
for partInfo in updates:
|
||||
for indices,element in partInfo.Update:
|
||||
element0 = element.Proxy.parent.Object.Group[0]
|
||||
infos0 = element0.Proxy.getInfo(expand=True)
|
||||
infos = element.Proxy.getInfo(expand=True)
|
||||
pos0 = infos[0].Placement.multVec(
|
||||
utils.getElementPos(infos[0].Shape))
|
||||
for idx0,idx in indices:
|
||||
info = infos[idx]
|
||||
pos = info.Placement.multVec(
|
||||
utils.getElementPos(info.Shape))
|
||||
pla = partInfo.Placement.copy()
|
||||
pla.Base += pos-pos0
|
||||
info0 = infos0[idx0]
|
||||
for partInfo0 in updates:
|
||||
for infoRef,shapeRef,pairs in partInfo0.Update:
|
||||
refPos = infoRef.Placement.multVec(
|
||||
utils.getElementPos(shapeRef))
|
||||
for info0,partInfo,shape in pairs:
|
||||
pos = partInfo.Placement.multVec(utils.getElementPos(shape))
|
||||
pla = partInfo0.Placement.copy()
|
||||
pla.Base += pos-refPos
|
||||
if isSamePlacement(info0.Placement,pla):
|
||||
self.system.log('not moving {}'.format(info0.PartName))
|
||||
else:
|
||||
|
@ -240,9 +231,11 @@ class Solver(object):
|
|||
info0.Part,
|
||||
info0.Placement.copy()))
|
||||
setPlacement(info0.Part,pla)
|
||||
if touched:
|
||||
|
||||
if recompute and touched:
|
||||
assembly.recompute(True)
|
||||
|
||||
|
||||
def isFixedPart(self,part):
|
||||
if isinstance(part,tuple) and part[0] in self._fixedParts:
|
||||
return True
|
||||
|
@ -255,6 +248,9 @@ class Solver(object):
|
|||
def addFixedElement(self,part,subname):
|
||||
self._fixedElements.add((part,subname))
|
||||
|
||||
def getDragPart(self):
|
||||
return self._dragPart
|
||||
|
||||
def countArrayPartConstraint(self,part):
|
||||
self._cstrArrayMap[part] += 1
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user