constraint: optimize constraint multiplication
This commit is contained in:
parent
677ba607f1
commit
7d4b184394
16
assembly.py
16
assembly.py
|
@ -365,12 +365,20 @@ class AsmElement(AsmBase):
|
|||
else:
|
||||
parentShape = Part.getShape(info.Part, info.Subname,
|
||||
transform=False, needSubElement=False)
|
||||
shapes = []
|
||||
found = False
|
||||
shapes = [info.Shape]
|
||||
pla = info.Shape.Placement
|
||||
for edge in parentShape.Edges:
|
||||
if info.Shape.isCoplanar(edge) and \
|
||||
utils.isSameValue(
|
||||
if not info.Shape.isCoplanar(edge) or \
|
||||
not utils.isSameValue(
|
||||
utils.getElementCircular(edge,True),obj.Radius):
|
||||
edge.transformShape(mat,True)
|
||||
continue
|
||||
edge.transformShape(mat,True)
|
||||
if not found and utils.isSamePlacement(pla,edge.Placement):
|
||||
found = True
|
||||
# make sure the direct referenced edge is the first one
|
||||
shapes[0] = edge
|
||||
else:
|
||||
shapes.append(edge)
|
||||
shape = shapes
|
||||
|
||||
|
|
|
@ -934,25 +934,43 @@ class BaseMulti(Base):
|
|||
logger.warn('{} no first part shape'.format(cstrName(obj)))
|
||||
return
|
||||
idx = 0
|
||||
updates = []
|
||||
for element in elements[1:]:
|
||||
for info in element.Proxy.getInfo(expand=True):
|
||||
info0 = firstInfo[idx]
|
||||
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 idx >= count:
|
||||
return ret
|
||||
infos = element.Proxy.getInfo(expand=True)
|
||||
if not infos:
|
||||
continue
|
||||
info0 = firstInfo[idx]
|
||||
partInfo0 = solver.getPartInfo(info0,infos)
|
||||
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))
|
||||
|
||||
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
|
||||
|
||||
return ret
|
||||
|
||||
parts = set()
|
||||
|
|
55
solver.py
55
solver.py
|
@ -1,5 +1,5 @@
|
|||
import random, math
|
||||
from collections import namedtuple
|
||||
from collections import namedtuple,defaultdict
|
||||
import FreeCAD, FreeCADGui
|
||||
from .assembly import Assembly, isTypeOf, setPlacement
|
||||
from . import utils
|
||||
|
@ -21,8 +21,12 @@ from .system import System
|
|||
# CstrMap: map from other part to the constrains between this and the othe 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
|
||||
# first element of all the coplanar edges will be actually constrainted.
|
||||
# The rest ElementInfo will be stored here for later update by matrix
|
||||
# transformation.
|
||||
PartInfo = namedtuple('SolverPartInfo', ('Part','PartName','Placement',
|
||||
'Params','Workplane','EntityMap','Group','CstrMap'))
|
||||
'Params','Workplane','EntityMap','Group','CstrMap','Update'))
|
||||
|
||||
class Solver(object):
|
||||
def __init__(self,assembly,reportFailed,dragPart,recompute,rollback):
|
||||
|
@ -116,6 +120,7 @@ class Solver(object):
|
|||
self.system.log('done solving')
|
||||
|
||||
touched = False
|
||||
updates = []
|
||||
for part,partInfo in self._partMap.items():
|
||||
if part in self._fixedParts:
|
||||
continue
|
||||
|
@ -147,6 +152,8 @@ class Solver(object):
|
|||
touched = True
|
||||
part.Points = points
|
||||
else:
|
||||
if partInfo.Update:
|
||||
updates.append(partInfo)
|
||||
params = [self.system.getParam(h).val for h in partInfo.Params]
|
||||
p = params[:3]
|
||||
q = (params[4],params[5],params[6],params[3])
|
||||
|
@ -161,6 +168,8 @@ class Solver(object):
|
|||
rollback.append((partInfo.PartName,
|
||||
part,
|
||||
partInfo.Placement.copy()))
|
||||
partInfo.Placement.Base = pla.Base
|
||||
partInfo.Placement.Rotation = pla.Rotation
|
||||
setPlacement(part,pla)
|
||||
|
||||
if utils.isDraftCircle(part):
|
||||
|
@ -198,6 +207,45 @@ class Solver(object):
|
|||
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.
|
||||
touches = defaultdict(set)
|
||||
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))
|
||||
|
||||
def isFixedPart(self,part):
|
||||
if isinstance(part,tuple) and part[0] in self._fixedParts:
|
||||
return True
|
||||
|
@ -257,7 +305,8 @@ class Solver(object):
|
|||
Workplane = h,
|
||||
EntityMap = {},
|
||||
Group = group if group else g,
|
||||
CstrMap = {})
|
||||
CstrMap = {},
|
||||
Update = [])
|
||||
|
||||
self.system.log('{}, {}'.format(partInfo,g))
|
||||
|
||||
|
|
|
@ -138,7 +138,7 @@ class SystemExtension(object):
|
|||
if not yaw and not pitch and not roll:
|
||||
n = n2.entity
|
||||
else:
|
||||
rot = n2.rot.multiply(FreeCAD.Rotation(yaw,pitch,roll))
|
||||
rot = FreeCAD.Rotation(yaw,pitch,roll).multiply(n2.rot)
|
||||
e = self.addNormal3dV(*getNormal(rot))
|
||||
n = self.addTransform(e,*n2.params,group=group)
|
||||
h.append(self.addSameOrientation(n1.entity,n,group=group))
|
||||
|
|
Loading…
Reference in New Issue
Block a user