constraint: add LockAngle option

LockAngle option is available to the following constraints,

* PlaneCoincident
* PlaneAlignment
* AxialAlignment
* MultiParallel
This commit is contained in:
Zheng, Lei 2017-12-09 13:27:38 +08:00
parent 9e98a55b07
commit c2662d8cfd
3 changed files with 58 additions and 28 deletions

View File

@ -28,7 +28,7 @@ def _p(solver,partInfo,subname,shape):
partInfo.EntityMap[key] = h partInfo.EntityMap[key] = h
return h return h
def _n(solver,partInfo,subname,shape): def _n(solver,partInfo,subname,shape,retAll=False):
'return a handle of a transformed normal quaterion derived from shape' 'return a handle of a transformed normal quaterion derived from shape'
if not solver: if not solver:
if utils.isPlanar(shape): if utils.isPlanar(shape):
@ -40,13 +40,24 @@ def _n(solver,partInfo,subname,shape):
if h: if h:
system.log('cache {}: {}'.format(key,h)) system.log('cache {}: {}'.format(key,h))
else: else:
h = []
system.NameTag = subname system.NameTag = subname
e = system.addNormal3dV(*utils.getElementNormal(shape)) rot = utils.getElementRotation(shape)
e = system.addNormal3dV(*utils.getNormal(rot))
system.NameTag = partInfo.PartName system.NameTag = partInfo.PartName
h = system.addTransform(e,*partInfo.Params,group=partInfo.Group) h.append(system.addTransform(e,*partInfo.Params,group=partInfo.Group))
# also add x axis pointing quaterion for convenience
rot = FreeCAD.Rotation(FreeCAD.Vector(0,1,0),90).multiply(rot)
system.NameTag = subname + '.nx'
e = system.addNormal3dV(*utils.getNormal(rot))
system.NameTag = partInfo.PartName + '.nx'
h.append(system.addTransform(e,*partInfo.Params,group=partInfo.Group))
system.log('{}: {},{}'.format(key,h,partInfo.Group)) system.log('{}: {},{}'.format(key,h,partInfo.Group))
partInfo.EntityMap[key] = h partInfo.EntityMap[key] = h
return h return h if retAll else h[0]
def _l(solver,partInfo,subname,shape,retAll=False): def _l(solver,partInfo,subname,shape,retAll=False):
'return a pair of handle of the end points of an edge in "shape"' 'return a pair of handle of the end points of an edge in "shape"'
@ -97,10 +108,10 @@ def _w(solver,partInfo,subname,shape,retAll=False):
system.log('cache {}: {}'.format(key,h)) system.log('cache {}: {}'.format(key,h))
else: else:
p = _p(solver,partInfo,subname,shape) p = _p(solver,partInfo,subname,shape)
n = _n(solver,partInfo,subname,shape) n = _n(solver,partInfo,subname,shape,True)
system.NameTag = partInfo.PartName system.NameTag = partInfo.PartName
h = system.addWorkplane(p,n,group=partInfo.Group) h = system.addWorkplane(p,n[0],group=partInfo.Group)
h = (h,p,n) h = [h,p] + n
system.log('{}: {},{}'.format(key,h,partInfo.Group)) system.log('{}: {},{}'.format(key,h,partInfo.Group))
partInfo.EntityMap[key] = h partInfo.EntityMap[key] = h
return h if retAll else h[0] return h if retAll else h[0]
@ -134,13 +145,14 @@ def _c(solver,partInfo,subname,shape,requireArc=False):
raise RuntimeError('shape is not an arc') raise RuntimeError('shape is not an arc')
else: else:
system.NameTag = partInfo.PartName system.NameTag = partInfo.PartName
h.append(solver.addDistanceV(r)) h.append(system.addDistanceV(r))
h = system.addCircle(*h,group=partInfo.Group) h = system.addCircle(*h,group=partInfo.Group)
system.log('{}: {},{}'.format(key,h,partInfo.Group)) system.log('{}: {},{}'.format(key,h,partInfo.Group))
partInfo.EntityMap[key] = h partInfo.EntityMap[key] = h
return h return h
def _a(solver,partInfo,subname,shape): def _a(solver,partInfo,subname,shape):
'return a handle of a transformed arc derived from "shape"'
return _c(solver,partInfo,subname,shape,True) return _c(solver,partInfo,subname,shape,True)
@ -294,6 +306,7 @@ _makeProp('Distance','App::PropertyDistance',getter=propGetValue)
_makeProp('Offset','App::PropertyDistance',getter=propGetValue) _makeProp('Offset','App::PropertyDistance',getter=propGetValue)
_makeProp('Cascade','App::PropertyBool',internal=True) _makeProp('Cascade','App::PropertyBool',internal=True)
_makeProp('Angle','App::PropertyAngle',getter=propGetValue) _makeProp('Angle','App::PropertyAngle',getter=propGetValue)
_makeProp('LockAngle','App::PropertyBool')
_makeProp('Ratio','App::PropertyFloat') _makeProp('Ratio','App::PropertyFloat')
_makeProp('Difference','App::PropertyFloat') _makeProp('Difference','App::PropertyFloat')
_makeProp('Diameter','App::PropertyFloat') _makeProp('Diameter','App::PropertyFloat')
@ -593,7 +606,7 @@ class BaseCascade(BaseMulti):
class PlaneCoincident(BaseCascade): class PlaneCoincident(BaseCascade):
_id = 35 _id = 35
_iconName = 'Assembly_ConstraintCoincidence.svg' _iconName = 'Assembly_ConstraintCoincidence.svg'
_props = ['Cascade','Offset'] _props = ['Cascade','Offset','LockAngle','Angle']
_menuItem = True _menuItem = True
_tooltip = \ _tooltip = \
'Add a "{}" constraint to conincide planes of two or more parts.\n'\ 'Add a "{}" constraint to conincide planes of two or more parts.\n'\
@ -603,7 +616,7 @@ class PlaneCoincident(BaseCascade):
class PlaneAlignment(BaseCascade): class PlaneAlignment(BaseCascade):
_id = 37 _id = 37
_iconName = 'Assembly_ConstraintAlignment.svg' _iconName = 'Assembly_ConstraintAlignment.svg'
_props = ['Cascade','Offset'] _props = ['Cascade','Offset','LockAngle','Angle']
_menuItem = True _menuItem = True
_tooltip = 'Add a "{}" constraint to rotate planes of two or more parts\n'\ _tooltip = 'Add a "{}" constraint to rotate planes of two or more parts\n'\
'into the same orientation' 'into the same orientation'
@ -612,6 +625,7 @@ class PlaneAlignment(BaseCascade):
class AxialAlignment(BaseMulti): class AxialAlignment(BaseMulti):
_id = 36 _id = 36
_iconName = 'Assembly_ConstraintAxial.svg' _iconName = 'Assembly_ConstraintAxial.svg'
_props = ['LockAngle','Angle']
_menuItem = True _menuItem = True
_tooltip = 'Add a "{}" constraint to align planes of two or more parts.\n'\ _tooltip = 'Add a "{}" constraint to align planes of two or more parts.\n'\
'The planes are aligned at the direction of their surface normal axis.' 'The planes are aligned at the direction of their surface normal axis.'
@ -661,6 +675,7 @@ class MultiParallel(BaseMulti):
_id = 291 _id = 291
_entityDef = (_ln,) _entityDef = (_ln,)
_iconName = 'Assembly_ConstraintMultiParallel.svg' _iconName = 'Assembly_ConstraintMultiParallel.svg'
_props = ['LockAngle','Angle']
_menuItem = True _menuItem = True
_tooltip = 'Add a "{}" constraint to make planes or linear edges of two\n'\ _tooltip = 'Add a "{}" constraint to make planes or linear edges of two\n'\
'or more parts parallel.' 'or more parts parallel.'

View File

@ -107,12 +107,12 @@ class SystemExtension(object):
def __init__(self): def __init__(self):
self.NameTag = '' self.NameTag = ''
def addPlaneCoincident(self,d,e1,e2,group=0): def addPlaneCoincident(self,d,lockAngle,angle,e1,e2,group=0):
if not group: if not group:
group = self.GroupHandle group = self.GroupHandle
d = abs(d) d = abs(d)
_,p1,n1 = e1 _,p1,n1,nx1 = e1
w2,p2,n2 = e2 w2,p2,n2,nx2 = e2
h = [] h = []
if d>0.0: if d>0.0:
h.append(self.addPointPlaneDistance(d,p1,w2,group=group)) h.append(self.addPointPlaneDistance(d,p1,w2,group=group))
@ -120,34 +120,44 @@ class SystemExtension(object):
else: else:
h.append(self.addPointsCoincident(p1,p2,group=group)) h.append(self.addPointsCoincident(p1,p2,group=group))
h.append(self.addParallel(n1,n2,group=group)) h.append(self.addParallel(n1,n2,group=group))
if lockAngle:
h.append(self.addAngle(angle,False,nx1,nx2,group=group))
return h return h
def addPlaneAlignment(self,d,e1,e2,group=0): def addPlaneAlignment(self,d,lockAngle,angle,e1,e2,group=0):
if not group: if not group:
group = self.GroupHandle group = self.GroupHandle
d = abs(d) d = abs(d)
_,p1,n1 = e1 _,p1,n1,nx1 = e1
w2,_,n2 = e2 w2,_,n2,nx2 = e2
h = [] h = []
if d>0.0: if d>0.0:
h.append(self.addPointPlaneDistance(d,p1,w2,group=group)) h.append(self.addPointPlaneDistance(d,p1,w2,group=group))
else: else:
h.append(self.addPointInPlane(p1,w2,group=group)) h.append(self.addPointInPlane(p1,w2,group=group))
h.append(self.addParallel(n1,n2,group=group)) h.append(self.addParallel(n1,n2,group=group))
if lockAngle:
h.append(self.addAngle(angle,False,nx1,nx2,group=group))
return h return h
def addAxialAlignment(self,e1,e2,group=0): def addAxialAlignment(self,lockAngle,angle,e1,e2,group=0):
if not group: if not group:
group = self.GroupHandle group = self.GroupHandle
_,p1,n1 = e1 _,p1,n1,nx1 = e1
w2,p2,n2 = e2 w2,p2,n2,nx2 = e2
h = [] h = []
h.append(self.addPointsCoincident(p1,p2,w2,group=group)) h.append(self.addPointsCoincident(p1,p2,w2,group=group))
h.append(self.addParallel(n1,n2,group=group)) h.append(self.addParallel(n1,n2,group=group))
if lockAngle:
h.append(self.addAngle(angle,False,nx1,nx2,group=group))
return h return h
def addMultiParallel(self,e1,e2,group=0): def addMultiParallel(self,lockAngle,angle,e1,e2,group=0):
return self.addParallel(e1,e2,group=group) h = []
h.append(self.addParallel(e1,e2,group=group))
if lockAngle:
h.append(self.addAngle(angle,False,e1,e2,group=group))
return h
def addPlacement(self,pla,group=0): def addPlacement(self,pla,group=0):
q = pla.Rotation.Q q = pla.Rotation.Q

View File

@ -285,12 +285,17 @@ def getElementRotation(obj,reverse=False):
[L.tangent(0)[0] for L in lines]) #D(irections) [L.tangent(0)[0] for L in lines]) #D(irections)
if np.std( D, axis=0 ).max() < 10**-9: #then linear curve if np.std( D, axis=0 ).max() < 10**-9: #then linear curve
return D[0] return D[0]
if axis: if not axis:
return FreeCAD.Rotation()
return FreeCAD.Rotation(FreeCAD.Vector(0,0,-1 if reverse else 1),axis) return FreeCAD.Rotation(FreeCAD.Vector(0,0,-1 if reverse else 1),axis)
def getElementNormal(obj,reverse=False): def getNormal(obj):
rot = getElementRotation(obj,reverse) if isinstance(obj,FreeCAD.Rotation):
if rot: rot = obj
elif isinstance(obj,FreeCAD.Placement):
rot = obj.Rotation
else:
rot = getElementRotation(obj)
q = rot.Q q = rot.Q
return q[3],q[0],q[1],q[2] return q[3],q[0],q[1],q[2]