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:
|
else:
|
||||||
parentShape = Part.getShape(info.Part, info.Subname,
|
parentShape = Part.getShape(info.Part, info.Subname,
|
||||||
transform=False, needSubElement=False)
|
transform=False, needSubElement=False)
|
||||||
shapes = []
|
found = False
|
||||||
|
shapes = [info.Shape]
|
||||||
|
pla = info.Shape.Placement
|
||||||
for edge in parentShape.Edges:
|
for edge in parentShape.Edges:
|
||||||
if info.Shape.isCoplanar(edge) and \
|
if not info.Shape.isCoplanar(edge) or \
|
||||||
utils.isSameValue(
|
not utils.isSameValue(
|
||||||
utils.getElementCircular(edge,True),obj.Radius):
|
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)
|
shapes.append(edge)
|
||||||
shape = shapes
|
shape = shapes
|
||||||
|
|
||||||
|
|
|
@ -934,25 +934,43 @@ class BaseMulti(Base):
|
||||||
logger.warn('{} no first part shape'.format(cstrName(obj)))
|
logger.warn('{} no first part shape'.format(cstrName(obj)))
|
||||||
return
|
return
|
||||||
idx = 0
|
idx = 0
|
||||||
|
updates = []
|
||||||
for element in elements[1:]:
|
for element in elements[1:]:
|
||||||
for info in element.Proxy.getInfo(expand=True):
|
infos = element.Proxy.getInfo(expand=True)
|
||||||
info0 = firstInfo[idx]
|
if not infos:
|
||||||
partInfo0 = solver.getPartInfo(info0)
|
continue
|
||||||
partInfo = solver.getPartInfo(info)
|
info0 = firstInfo[idx]
|
||||||
e0 = cls._entityDef[0](
|
partInfo0 = solver.getPartInfo(info0,infos)
|
||||||
solver,partInfo0,info0.Subname,info0.Shape)
|
info = infos[0]
|
||||||
e = cls._entityDef[0](
|
partInfo = solver.getPartInfo(info)
|
||||||
solver,partInfo,info.Subname,info.Shape)
|
e0 = cls._entityDef[0](
|
||||||
params = props + [e0,e]
|
solver,partInfo0,info0.Subname,info0.Shape)
|
||||||
solver.system.checkRedundancy(obj,partInfo0,partInfo)
|
e = cls._entityDef[0](
|
||||||
h = func(*params,group=solver.group)
|
solver,partInfo,info.Subname,info.Shape)
|
||||||
if isinstance(h,(list,tuple)):
|
params = props + [e0,e]
|
||||||
ret += list(h)
|
solver.system.checkRedundancy(obj,partInfo0,partInfo)
|
||||||
else:
|
h = func(*params,group=solver.group)
|
||||||
ret.append(h)
|
if isinstance(h,(list,tuple)):
|
||||||
idx += 1
|
ret += list(h)
|
||||||
if idx >= count:
|
else:
|
||||||
return ret
|
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
|
return ret
|
||||||
|
|
||||||
parts = set()
|
parts = set()
|
||||||
|
|
55
solver.py
55
solver.py
|
@ -1,5 +1,5 @@
|
||||||
import random, math
|
import random, math
|
||||||
from collections import namedtuple
|
from collections import namedtuple,defaultdict
|
||||||
import FreeCAD, FreeCADGui
|
import FreeCAD, FreeCADGui
|
||||||
from .assembly import Assembly, isTypeOf, setPlacement
|
from .assembly import Assembly, isTypeOf, setPlacement
|
||||||
from . import utils
|
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.
|
# CstrMap: map from other part to the constrains between this and the othe part.
|
||||||
# This is for auto constraint DOF reduction. Only some composite
|
# This is for auto constraint DOF reduction. Only some composite
|
||||||
# constraints will be mapped.
|
# 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',
|
PartInfo = namedtuple('SolverPartInfo', ('Part','PartName','Placement',
|
||||||
'Params','Workplane','EntityMap','Group','CstrMap'))
|
'Params','Workplane','EntityMap','Group','CstrMap','Update'))
|
||||||
|
|
||||||
class Solver(object):
|
class Solver(object):
|
||||||
def __init__(self,assembly,reportFailed,dragPart,recompute,rollback):
|
def __init__(self,assembly,reportFailed,dragPart,recompute,rollback):
|
||||||
|
@ -116,6 +120,7 @@ class Solver(object):
|
||||||
self.system.log('done solving')
|
self.system.log('done solving')
|
||||||
|
|
||||||
touched = False
|
touched = False
|
||||||
|
updates = []
|
||||||
for part,partInfo in self._partMap.items():
|
for part,partInfo in self._partMap.items():
|
||||||
if part in self._fixedParts:
|
if part in self._fixedParts:
|
||||||
continue
|
continue
|
||||||
|
@ -147,6 +152,8 @@ class Solver(object):
|
||||||
touched = True
|
touched = True
|
||||||
part.Points = points
|
part.Points = points
|
||||||
else:
|
else:
|
||||||
|
if partInfo.Update:
|
||||||
|
updates.append(partInfo)
|
||||||
params = [self.system.getParam(h).val for h in partInfo.Params]
|
params = [self.system.getParam(h).val for h in partInfo.Params]
|
||||||
p = params[:3]
|
p = params[:3]
|
||||||
q = (params[4],params[5],params[6],params[3])
|
q = (params[4],params[5],params[6],params[3])
|
||||||
|
@ -161,6 +168,8 @@ class Solver(object):
|
||||||
rollback.append((partInfo.PartName,
|
rollback.append((partInfo.PartName,
|
||||||
part,
|
part,
|
||||||
partInfo.Placement.copy()))
|
partInfo.Placement.copy()))
|
||||||
|
partInfo.Placement.Base = pla.Base
|
||||||
|
partInfo.Placement.Rotation = pla.Rotation
|
||||||
setPlacement(part,pla)
|
setPlacement(part,pla)
|
||||||
|
|
||||||
if utils.isDraftCircle(part):
|
if utils.isDraftCircle(part):
|
||||||
|
@ -198,6 +207,45 @@ class Solver(object):
|
||||||
if recompute and touched:
|
if recompute and touched:
|
||||||
assembly.recompute(True)
|
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):
|
def isFixedPart(self,part):
|
||||||
if isinstance(part,tuple) and part[0] in self._fixedParts:
|
if isinstance(part,tuple) and part[0] in self._fixedParts:
|
||||||
return True
|
return True
|
||||||
|
@ -257,7 +305,8 @@ class Solver(object):
|
||||||
Workplane = h,
|
Workplane = h,
|
||||||
EntityMap = {},
|
EntityMap = {},
|
||||||
Group = group if group else g,
|
Group = group if group else g,
|
||||||
CstrMap = {})
|
CstrMap = {},
|
||||||
|
Update = [])
|
||||||
|
|
||||||
self.system.log('{}, {}'.format(partInfo,g))
|
self.system.log('{}, {}'.format(partInfo,g))
|
||||||
|
|
||||||
|
|
|
@ -138,7 +138,7 @@ class SystemExtension(object):
|
||||||
if not yaw and not pitch and not roll:
|
if not yaw and not pitch and not roll:
|
||||||
n = n2.entity
|
n = n2.entity
|
||||||
else:
|
else:
|
||||||
rot = n2.rot.multiply(FreeCAD.Rotation(yaw,pitch,roll))
|
rot = FreeCAD.Rotation(yaw,pitch,roll).multiply(n2.rot)
|
||||||
e = self.addNormal3dV(*getNormal(rot))
|
e = self.addNormal3dV(*getNormal(rot))
|
||||||
n = self.addTransform(e,*n2.params,group=group)
|
n = self.addTransform(e,*n2.params,group=group)
|
||||||
h.append(self.addSameOrientation(n1.entity,n,group=group))
|
h.append(self.addSameOrientation(n1.entity,n,group=group))
|
||||||
|
|
Loading…
Reference in New Issue
Block a user