constraint: fix constraint multiplication

This commit is contained in:
Zheng, Lei 2018-09-05 20:41:15 +08:00
parent 59c8fa186f
commit fc8f2f1a47
2 changed files with 75 additions and 68 deletions

View File

@ -506,6 +506,17 @@ class Constraint(ProxyType):
for obj in cstrs:
cstr = mcs.getProxy(obj)
# Build array constraint map for constraint multiplication
if mcs.canMultiply(obj):
element0 = obj.Proxy.getElements()[0].Proxy
for info in element0.getInfo(expand=True):
solver.countArrayPartConstraint(info.Part)
else:
for info in obj.Proxy.getElementsInfo():
if isinstance(info.Part,tuple):
solver.countArrayPartConstraint(info.Part)
if cstr.hasFixedPart(obj):
found = True
for info in cstr.getFixedParts(solver,obj):
@ -934,42 +945,37 @@ class BaseMulti(Base):
logger.warn('{} no first part shape'.format(cstrName(obj)))
return
idx = 0
updates = []
for element in elements[1:]:
infos = element.Proxy.getInfo(expand=True)
if not infos:
continue
info0 = firstInfo[idx]
partInfo0 = solver.getPartInfo(info0)
info = infos[0]
partInfo = solver.getPartInfo(info)
e0 = cls._entityDef[0](
solver,partInfo0,info0.Subname,info0.Shape)
e = cls._entityDef[0](
solver,partInfo,info.Subname,info.Shape)
params = props + [e0,e]
solver.system.checkRedundancy(obj,partInfo0,partInfo)
h = func(*params,group=solver.group)
if isinstance(h,(list,tuple)):
ret += list(h)
else:
ret.append(h)
idx += 1
if idx >= count:
return ret
if len(infos)>1:
updates.append((partInfo0,element,len(infos)-1))
updates = []
for i,info in enumerate(element.Proxy.getInfo(expand=True)):
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
# constraint (i.e. this one).
updates.append((idx,i))
idx += 1
continue
for partInfo0,element,infoCount in updates:
if partInfo0.Update:
logger.warn('{} used in more than one constraint '
'multiplication'.format(partInfo0.PartName))
continue
partInfo0.Update.append(idx)
partInfo0.Update.append(element)
idx += infoCount
if idx >= count:
break
partInfo0 = solver.getPartInfo(info0)
partInfo = solver.getPartInfo(info)
e0 = cls._entityDef[0](
solver,partInfo0,info0.Subname,info0.Shape)
e = cls._entityDef[0](
solver,partInfo,info.Subname,info.Shape)
params = props + [e0,e]
solver.system.checkRedundancy(obj,partInfo0,partInfo)
h = func(*params,group=solver.group)
if isinstance(h,(list,tuple)):
ret += list(h)
else:
ret.append(h)
idx += 1
if updates:
partInfo0.Update.append((updates,element))
return ret

View File

@ -18,7 +18,7 @@ from .system import System
# plane of the part.
# EntityMap: string -> entity handle map, for caching
# Group: transforming entity group handle
# CstrMap: map from other part to the constrains between this and the other part.
# CstrMap: map from other part to the constrain between this and the other part.
# This is for auto constraint DOF reduction. Only some composite
# constraints will be mapped.
# Update: in case the constraint uses the `Multiplication` feature, only the
@ -41,6 +41,7 @@ class Solver(object):
self.group = 1 # the solving group
self._partMap = {}
self._cstrMap = {}
self._cstrArrayMap = defaultdict(int)
self._fixedElements = set()
self.system.GroupHandle = self._fixedGroup
@ -211,40 +212,34 @@ class Solver(object):
# 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.
touches = defaultdict(set)
touched = False
for partInfo in updates:
idx,element = partInfo.Update
element0 = element.Proxy.parent.Object.Group[0]
infos0 = element0.Proxy.getInfo(expand=True)
count = len(infos0)
infos = element.Proxy.getInfo(expand=True)
pos0 = infos[0].Placement.multVec(
utils.getElementPos(infos[0].Shape))
touched = False
for info in infos[1:]:
if idx >= count:
break
pos = info.Placement.multVec(
utils.getElementPos(info.Shape))
pla = partInfo.Placement.copy()
pla.Base += pos-pos0
info0 = infos0[idx]
idx += 1
if isSamePlacement(info0.Placement,pla):
self.system.log('not moving {}'.format(info0.PartName))
else:
self.system.log('moving {} {}'.format(
partInfo.PartName,pla))
touched = True
if rollback is not None:
rollback.append((info0.PartName,
info0.Part,
info0.Placement.copy()))
setPlacement(info0.Part,pla)
if touched:
touches[partInfo.Part[0].Document].add(partInfo.Part[0])
for doc,objs in touches.items():
doc.recompute(list(objs))
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]
if isSamePlacement(info0.Placement,pla):
self.system.log('not moving {}'.format(info0.PartName))
else:
self.system.log('moving {} {}'.format(
partInfo.PartName,pla))
touched = True
if rollback is not None:
rollback.append((info0.PartName,
info0.Part,
info0.Placement.copy()))
setPlacement(info0.Part,pla)
if touched:
assembly.recompute(True)
def isFixedPart(self,part):
if isinstance(part,tuple) and part[0] in self._fixedParts:
@ -258,6 +253,12 @@ class Solver(object):
def addFixedElement(self,part,subname):
self._fixedElements.add((part,subname))
def countArrayPartConstraint(self,part):
self._cstrArrayMap[part] += 1
def getArrayPartConstraintCount(self,part):
return self._cstrArrayMap[part]
def getPartInfo(self,info,fixed=False,group=0):
partInfo = self._partMap.get(info.Part,None)
if partInfo: