Skip to content

Commit

Permalink
constraint: add LockAngle option
Browse files Browse the repository at this point in the history
LockAngle option is available to the following constraints,

* PlaneCoincident
* PlaneAlignment
* AxialAlignment
* MultiParallel
  • Loading branch information
realthunder committed Dec 9, 2017
1 parent 9e98a55 commit c2662d8
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 28 deletions.
35 changes: 25 additions & 10 deletions constraint.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def _p(solver,partInfo,subname,shape):
partInfo.EntityMap[key] = 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'
if not solver:
if utils.isPlanar(shape):
Expand All @@ -40,13 +40,24 @@ def _n(solver,partInfo,subname,shape):
if h:
system.log('cache {}: {}'.format(key,h))
else:
h = []

system.NameTag = subname
e = system.addNormal3dV(*utils.getElementNormal(shape))
rot = utils.getElementRotation(shape)
e = system.addNormal3dV(*utils.getNormal(rot))
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))
partInfo.EntityMap[key] = h
return h
return h if retAll else h[0]

def _l(solver,partInfo,subname,shape,retAll=False):
'return a pair of handle of the end points of an edge in "shape"'
Expand Down Expand Up @@ -97,10 +108,10 @@ def _w(solver,partInfo,subname,shape,retAll=False):
system.log('cache {}: {}'.format(key,h))
else:
p = _p(solver,partInfo,subname,shape)
n = _n(solver,partInfo,subname,shape)
n = _n(solver,partInfo,subname,shape,True)
system.NameTag = partInfo.PartName
h = system.addWorkplane(p,n,group=partInfo.Group)
h = (h,p,n)
h = system.addWorkplane(p,n[0],group=partInfo.Group)
h = [h,p] + n
system.log('{}: {},{}'.format(key,h,partInfo.Group))
partInfo.EntityMap[key] = h
return h if retAll else h[0]
Expand Down Expand Up @@ -134,13 +145,14 @@ def _c(solver,partInfo,subname,shape,requireArc=False):
raise RuntimeError('shape is not an arc')
else:
system.NameTag = partInfo.PartName
h.append(solver.addDistanceV(r))
h.append(system.addDistanceV(r))
h = system.addCircle(*h,group=partInfo.Group)
system.log('{}: {},{}'.format(key,h,partInfo.Group))
partInfo.EntityMap[key] = h
return h

def _a(solver,partInfo,subname,shape):
'return a handle of a transformed arc derived from "shape"'
return _c(solver,partInfo,subname,shape,True)


Expand Down Expand Up @@ -294,6 +306,7 @@ def _makeProp(name,tp,doc='',getter=propGet,internal=False):
_makeProp('Offset','App::PropertyDistance',getter=propGetValue)
_makeProp('Cascade','App::PropertyBool',internal=True)
_makeProp('Angle','App::PropertyAngle',getter=propGetValue)
_makeProp('LockAngle','App::PropertyBool')
_makeProp('Ratio','App::PropertyFloat')
_makeProp('Difference','App::PropertyFloat')
_makeProp('Diameter','App::PropertyFloat')
Expand Down Expand Up @@ -593,7 +606,7 @@ def prepare(cls,obj,solver):
class PlaneCoincident(BaseCascade):
_id = 35
_iconName = 'Assembly_ConstraintCoincidence.svg'
_props = ['Cascade','Offset']
_props = ['Cascade','Offset','LockAngle','Angle']
_menuItem = True
_tooltip = \
'Add a "{}" constraint to conincide planes of two or more parts.\n'\
Expand All @@ -603,7 +616,7 @@ class PlaneCoincident(BaseCascade):
class PlaneAlignment(BaseCascade):
_id = 37
_iconName = 'Assembly_ConstraintAlignment.svg'
_props = ['Cascade','Offset']
_props = ['Cascade','Offset','LockAngle','Angle']
_menuItem = True
_tooltip = 'Add a "{}" constraint to rotate planes of two or more parts\n'\
'into the same orientation'
Expand All @@ -612,6 +625,7 @@ class PlaneAlignment(BaseCascade):
class AxialAlignment(BaseMulti):
_id = 36
_iconName = 'Assembly_ConstraintAxial.svg'
_props = ['LockAngle','Angle']
_menuItem = True
_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.'
Expand Down Expand Up @@ -661,6 +675,7 @@ class MultiParallel(BaseMulti):
_id = 291
_entityDef = (_ln,)
_iconName = 'Assembly_ConstraintMultiParallel.svg'
_props = ['LockAngle','Angle']
_menuItem = True
_tooltip = 'Add a "{}" constraint to make planes or linear edges of two\n'\
'or more parts parallel.'
Expand Down
32 changes: 21 additions & 11 deletions system.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,47 +107,57 @@ class SystemExtension(object):
def __init__(self):
self.NameTag = ''

def addPlaneCoincident(self,d,e1,e2,group=0):
def addPlaneCoincident(self,d,lockAngle,angle,e1,e2,group=0):
if not group:
group = self.GroupHandle
d = abs(d)
_,p1,n1 = e1
w2,p2,n2 = e2
_,p1,n1,nx1 = e1
w2,p2,n2,nx2 = e2
h = []
if d>0.0:
h.append(self.addPointPlaneDistance(d,p1,w2,group=group))
h.append(self.addPointsCoincident(p1,p2,w2,group=group))
else:
h.append(self.addPointsCoincident(p1,p2,group=group))
h.append(self.addParallel(n1,n2,group=group))
if lockAngle:
h.append(self.addAngle(angle,False,nx1,nx2,group=group))
return h

def addPlaneAlignment(self,d,e1,e2,group=0):
def addPlaneAlignment(self,d,lockAngle,angle,e1,e2,group=0):
if not group:
group = self.GroupHandle
d = abs(d)
_,p1,n1 = e1
w2,_,n2 = e2
_,p1,n1,nx1 = e1
w2,_,n2,nx2 = e2
h = []
if d>0.0:
h.append(self.addPointPlaneDistance(d,p1,w2,group=group))
else:
h.append(self.addPointInPlane(p1,w2,group=group))
h.append(self.addParallel(n1,n2,group=group))
if lockAngle:
h.append(self.addAngle(angle,False,nx1,nx2,group=group))
return h

def addAxialAlignment(self,e1,e2,group=0):
def addAxialAlignment(self,lockAngle,angle,e1,e2,group=0):
if not group:
group = self.GroupHandle
_,p1,n1 = e1
w2,p2,n2 = e2
_,p1,n1,nx1 = e1
w2,p2,n2,nx2 = e2
h = []
h.append(self.addPointsCoincident(p1,p2,w2,group=group))
h.append(self.addParallel(n1,n2,group=group))
if lockAngle:
h.append(self.addAngle(angle,False,nx1,nx2,group=group))
return h

def addMultiParallel(self,e1,e2,group=0):
return self.addParallel(e1,e2,group=group)
def addMultiParallel(self,lockAngle,angle,e1,e2,group=0):
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):
q = pla.Rotation.Q
Expand Down
19 changes: 12 additions & 7 deletions utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -285,14 +285,19 @@ def getElementRotation(obj,reverse=False):
[L.tangent(0)[0] for L in lines]) #D(irections)
if np.std( D, axis=0 ).max() < 10**-9: #then linear curve
return D[0]
if axis:
return FreeCAD.Rotation(FreeCAD.Vector(0,0,-1 if reverse else 1),axis)
if not axis:
return FreeCAD.Rotation()
return FreeCAD.Rotation(FreeCAD.Vector(0,0,-1 if reverse else 1),axis)

def getElementNormal(obj,reverse=False):
rot = getElementRotation(obj,reverse)
if rot:
q = rot.Q
return q[3],q[0],q[1],q[2]
def getNormal(obj):
if isinstance(obj,FreeCAD.Rotation):
rot = obj
elif isinstance(obj,FreeCAD.Placement):
rot = obj.Rotation
else:
rot = getElementRotation(obj)
q = rot.Q
return q[3],q[0],q[1],q[2]

def getElementCircular(obj):
'return radius if it is closed, or a list of two endpoints'
Expand Down

0 comments on commit c2662d8

Please sign in to comment.