constraint: support cylindrical plane in AxialAlignment and Colinear

This commit is contained in:
Zheng, Lei 2018-05-08 15:09:36 +08:00
parent fe7a1757cb
commit 31f1f2b849
3 changed files with 100 additions and 49 deletions

View File

@ -7,9 +7,9 @@ from .proxy import ProxyType, PropertyInfo, propGet, propGetValue
import os
_iconPath = os.path.join(utils.iconPath,'constraints')
PointInfo = namedtuple('PointInfo', ('entity','params','vertex'))
LineInfo = namedtuple('LineInfo', ('entity','p1','p2'))
NormalInfo = namedtuple('NormalInfo', ('entity','rot','params'))
PointInfo = namedtuple('PointInfo', ('entity','params','vector'))
LineInfo = namedtuple('LineInfo', ('entity','p0','p1'))
NormalInfo = namedtuple('NormalInfo', ('entity','rot','params','p0','ln'))
PlaneInfo = namedtuple('PlaneInfo', ('entity','origin','normal'))
CircleInfo = namedtuple('CurcleInfo',('entity','radius','p0'))
ArcInfo = namedtuple('CurcleInfo',('entity','p1','p0','params'))
@ -65,7 +65,7 @@ def _p(solver,partInfo,subname,shape,retAll=False):
params.append(system.addParamV(val,group=partInfo.Group))
system.NameTag = nameTag
e = system.addPoint3d(*params)
h = PointInfo(entity=e,params=params,vertex=v)
h = PointInfo(entity=e,params=params,vector=v)
system.log('{}: add draft point {}'.format(key,h))
if system.sketchPlane and not solver.isFixedElement(part,subname):
@ -79,7 +79,7 @@ def _p(solver,partInfo,subname,shape,retAll=False):
requireArc = subname=='Vertex2'
e = _prepareDraftCircle(solver,partInfo,requireArc)
if requireArc or subname=='Vertex1':
h = PointInfo(entity=e.p0,params=partInfo.Params,vertex=v)
h = PointInfo(entity=e.p0,params=partInfo.Params,vector=v)
elif subname=='Edge1':
# center point
h = partInfo.Workplane.origin
@ -94,7 +94,7 @@ def _p(solver,partInfo,subname,shape,retAll=False):
e = system.addPoint3dV(*v)
system.NameTag = nameTag + 't'
h = system.addTransform(e,*partInfo.Params,group=partInfo.Group)
h = PointInfo(entity=h, params=partInfo.Params,vertex=v)
h = PointInfo(entity=h, params=partInfo.Params,vector=v)
system.log('{}: {},{}'.format(key,h,partInfo.Group))
partInfo.EntityMap[key] = h
@ -103,8 +103,8 @@ def _p(solver,partInfo,subname,shape,retAll=False):
def _n(solver,partInfo,subname,shape,retAll=False):
'return a handle of a transformed normal quaterion derived from shape'
if not solver:
if not utils.isPlanar(shape):
return 'an edge or face with a surface normal'
if not utils.isPlanar(shape) and not utils.isCylindricalPlane(shape):
return 'an edge or face with a planar or cylindrical surface'
if utils.isDraftWire(partInfo):
logger.warn('Use draft wire {} for normal. Draft wire placement'
' is not transformable'.format(partInfo.PartName))
@ -126,7 +126,20 @@ def _n(solver,partInfo,subname,shape,retAll=False):
system.NameTag += 't'
nz = system.addTransform(e,*partInfo.Params,group=partInfo.Group)
h = NormalInfo(entity=nz,rot=rot,params=partInfo.Params)
p0 = _p(solver,partInfo,subname,shape,True)
v = rot.inverted().multVec(p0.vector)
v.z += 1
v = rot.multVec(v)
system.NameTag = nameTag + 'p1'
e = system.addPoint3dV(*v)
system.NameTag += 't'
p1 = system.addTransform(e,*partInfo.Params,group=partInfo.Group)
system.NameTag = nameTag + 'l'
ln = system.addLineSegment(p0.entity,p1,group=partInfo.Group)
h = NormalInfo(entity=nz,rot=rot,
params=partInfo.Params, p0=p0.entity, ln=ln)
system.log('{}: {},{}'.format(key,h,partInfo.Group))
partInfo.EntityMap[key] = h
@ -137,6 +150,7 @@ def _l(solver,partInfo,subname,shape,retAll=False):
if not solver:
if not utils.isLinearEdge(shape):
return 'a linear edge'
if not utils.isDraftWire(partInfo):
return
vname1,vname2 = utils.edge2VertexIndex(partInfo,subname)
@ -157,27 +171,28 @@ def _l(solver,partInfo,subname,shape,retAll=False):
system.log('cache {}: {}'.format(key,h))
else:
nameTag = partInfo.PartName + '.' + key
v = shape.Edge1.Vertexes
if utils.isDraftWire(part):
v = shape.Edge1.Vertexes
vname1,vname2 = utils.edge2VertexIndex(part,subname)
if not vname1:
raise RuntimeError('Invalid draft subname {} or {}'.format(
subname,partInfo.PartName))
tp1 = _p(solver,partInfo,vname1,v[0])
tp2 = _p(solver,partInfo,vname2,v[1])
tp0 = _p(solver,partInfo,vname1,v[0])
tp1 = _p(solver,partInfo,vname2,v[1])
else:
v = shape.Edge1.Vertexes
system.NameTag = nameTag + 'p0'
p0 = system.addPoint3dV(*v[0].Point)
system.NameTag = nameTag + 'p0t'
tp0 = system.addTransform(p0,*partInfo.Params,group=partInfo.Group)
system.NameTag = nameTag + 'p1'
p1 = system.addPoint3dV(*v[0].Point)
p1 = system.addPoint3dV(*v[-1].Point)
system.NameTag = nameTag + 'p1t'
tp1 = system.addTransform(p1,*partInfo.Params,group=partInfo.Group)
system.NameTag = nameTag + 'p2'
p2 = system.addPoint3dV(*v[-1].Point)
system.NameTag = nameTag + 'p2t'
tp2 = system.addTransform(p2,*partInfo.Params,group=partInfo.Group)
system.NameTag = nameTag
h = system.addLineSegment(tp1,tp2,group=partInfo.Group)
h = LineInfo(entity=h,p1=tp1,p2=tp2)
h = system.addLineSegment(tp0,tp1,group=partInfo.Group)
h = LineInfo(entity=h,p0=tp0,p1=tp1)
system.log('{}: {},{}'.format(key,h,partInfo.Group))
partInfo.EntityMap[key] = h
@ -198,12 +213,18 @@ def _dl(solver,partInfo,subname,shape,retAll=False):
def _ln(solver,partInfo,subname,shape,retAll=False):
'return a handle for either a line or a normal depends on the shape'
if not solver:
if utils.isLinearEdge(shape) or utils.isPlanar(shape):
if utils.isLinearEdge(shape) or \
utils.isPlanar(shape) or \
utils.isCylindricalPlane(shape):
return
return 'a linear edge or edge/face with planar surface'
return 'a linear edge or edge/face with planar or cylindrical surface'
if utils.isLinearEdge(shape):
return _l(solver,partInfo,subname,shape,retAll)
return _n(solver,partInfo,subname,shape)
return _n(solver,partInfo,subname,shape,retAll)
def _lna(solver,partInfo,subname,shape,retAll=False):
_ = retAll
return _ln(solver,partInfo,subname,shape,True)
def _lw(solver,partInfo,subname,shape,retAll=False):
'return a handle for either a line or a plane depending on the shape'
@ -323,8 +344,8 @@ def _c(solver,partInfo,subname,shape,requireArc=False,retAll=False):
l = _l(solver,partInfo,subname,shape,True)
system.NameTag = nameTag
h = system.addArcOfCircle(
pln.entity, pln.origin.entity, l.p1, l.p2, group=g)
h = ArcInfo(entity=h,p1=l.p2,p0=l.p1,params=None)
pln.entity, pln.origin.entity, l.p0, l.p1, group=g)
h = ArcInfo(entity=h,p1=l.p1,p0=l.p0,params=None)
else:
system.NameTag = nameTag
h = system.addCircle(
@ -745,7 +766,7 @@ class Locked(Base):
fixPoint = True
names = utils.edge2VertexIndex(info.Part,info.Subname)
else:
names = [info.Subname+'.fp1', info.Subname+'.fp2']
names = [info.Subname+'.fp0', info.Subname+'.fp1']
nameTag = partInfo.PartName + '.' + info.Subname
@ -927,6 +948,7 @@ class PlaneAlignment(BaseCascade):
class AxialAlignment(BaseMulti):
_id = 36
_entityDef = (_lna,)
_iconName = 'Assembly_ConstraintAxial.svg'
_props = _AngleProps
_tooltip = 'Add a "{}" constraint to align planes of two or more parts.\n'\
@ -1167,7 +1189,7 @@ class ArcLineTangent(Base2):
class Colinear(Base2):
_id = 39
_entityDef = (_la, _l)
_entityDef = (_lna, _lna)
_workplane = True
_iconName = 'Assembly_ConstraintColinear.svg'
_tooltip='Add a "{}" constraint to make to line colinear'
@ -1239,8 +1261,8 @@ class LineLength(BaseSketch):
def prepare(cls,obj,solver):
func = PointsDistance.constraintFunc(obj,solver)
if func:
_,p1,p2 = cls.getEntities(obj,solver,retAll=True)[0]
params = cls.getPropertyValues(obj) + [p1,p2]
_,p0,p1 = cls.getEntities(obj,solver,retAll=True)[0]
params = cls.getPropertyValues(obj) + [p0,p1]
ret = func(*params,group=solver.group)
solver.system.log('{}: {}'.format(cstrName(obj),ret))
return ret

View File

@ -228,13 +228,19 @@ class Solver(object):
p = self.system.addPoint3d(*params[:3],group=g)
self.system.NameTag = info.PartName + '.n'
n = self.system.addNormal3d(*params[3:],group=g)
self.system.NameTag = info.PartName + '.np0'
p0 = self.system.addPoint3d(self.v0,self.v0,self.v0,group=g)
self.system.NameTag = info.PartName + '.np1'
p1 = self.system.addPoint3d(self.v0,self.v0,self.v1,group=g)
self.system.NameTag = info.PartName + '.l'
ln = self.system.addLineSegment(p0,p1,group=g)
self.system.NameTag = info.PartName + '.w'
w = self.system.addWorkplane(p,n,group=g)
h = PlaneInfo(entity=w,
origin=PointInfo(entity=p, params=None,
vertex=FreeCAD.Vector()),
vector=FreeCAD.Vector()),
normal=NormalInfo(entity=n,rot=FreeCAD.Rotation(),
params=params))
params=params,p0=p0,ln=ln))
partInfo = PartInfo(Part = info.Part,
PartName = info.PartName,

View File

@ -1,6 +1,6 @@
import os
import FreeCAD
from .constraint import cstrName
from .constraint import cstrName, PlaneInfo, NormalInfo
from .utils import getIcon, syslogger as logger, objName, project2D, getNormal
from .proxy import ProxyType, PropertyInfo
@ -134,7 +134,7 @@ class SystemExtension(object):
def setOrientation(self,h,lockAngle,yaw,pitch,roll,n1,n2,group):
if not lockAngle:
h.append(self.addParallel(n1.entity,n2.entity,group=group))
return
return h
if not yaw and not pitch and not roll:
n = n2.entity
else:
@ -188,11 +188,11 @@ class SystemExtension(object):
if d or dx or dy:
dx,dy,d = pln2.normal.rot.multVec(FreeCAD.Vector(dx,dy,d))
v = pln2.origin.vertex+FreeCAD.Vector(dx,dy,d)
v = pln2.origin.vector+FreeCAD.Vector(dx,dy,d)
e = self.addTransform(
self.addPoint3dV(*v),*pln2.origin.params,group=group)
else:
v = pln2.origin.vertex
v = pln2.origin.vector
e = pln2.origin.entity
if not lockAngle and count==2:
@ -204,7 +204,7 @@ class SystemExtension(object):
# We project the initial points to the first element plane, and
# check for differences in x and y components of the points to
# determine whether to use horizontal or vertical constraint.
v1,v2 = project2D(pln1.normal.rot, pln1.origin.vertex, v)
v1,v2 = project2D(pln1.normal.rot, pln1.origin.vector, v)
if abs(v1.x-v2.x) < abs(v1.y-v2.y):
h.append(self.addPointsHorizontal(
pln1.origin.entity, e, pln1.entity, group=group))
@ -241,29 +241,42 @@ class SystemExtension(object):
pln1.normal, pln2.normal, group)
return h
def addAxialAlignment(self,lockAngle,yaw,pitch,roll,pln1,pln2,group=0):
def addAxialAlignment(self,lockAngle,yaw,pitch,roll,ln1,ln2,group=0):
if not group:
group = self.GroupHandle
count = self.countConstraints(0,2,'Coincident')
h = []
if not isinstance(ln1,NormalInfo):
if not isinstance(ln2,NormalInfo):
lockAngle = False
else:
ln1,ln2 = ln2,ln1
count = self.countConstraints(2 if lockAngle else 1,2,'Axial')
if count < 0:
return
if count:
return self.addPlaneCoincident(0,0,0,False,0,0,0,pln1,pln2,group)
h = []
h.append(self.addPointsCoincident(pln1.origin.entity,
pln2.origin.entity, pln2.entity, group=group))
return self.setOrientation(h, lockAngle, yaw, pitch, roll,
pln1.normal, pln2.normal, group)
relax = count==2 and not lockAngle
if isinstance(ln2,NormalInfo):
ln = ln2.ln
if not relax:
h = self.setOrientation(
h,lockAngle,yaw,pitch,roll,ln1,ln2,group)
else:
ln = ln2.entity
if not relax:
h.append(self.addParallel(ln1.entity,ln,group=group))
h.append(self.addPointOnLine(ln1.p0,ln,group=group))
return h
def addMultiParallel(self,lockAngle,yaw,pitch,raw,e1,e2,group=0):
if not group:
group = self.GroupHandle
h = []
isPlane = isinstance(e1,list),isinstance(e2,list)
isPlane = isinstance(e1,PlaneInfo),isinstance(e2,PlaneInfo)
if all(isPlane):
return self.setOrientation(h, lockAngle, yaw, pitch, raw,
e1.normal, e2.normal, group);
if not any(isPlane):
h.append(self.addParallel(
e1.normal.entity, e2.normal.entity, group=group))
h.append(self.addParallel(e1, e2, group=group))
elif isPlane[0]:
h.append(self.addPerpendicular(e1.normal.entity, e2, group=group))
else:
@ -272,8 +285,18 @@ class SystemExtension(object):
def addColinear(self,l1,l2,wrkpln=0,group=0):
h = []
h.append(self.addParallel(l1.entity,l2,wrkpln=wrkpln,group=group))
h.append(self.addPointOnLine(l1.entity,l2,wrkpln=wrkpln,group=group))
if isinstance(l1,NormalInfo):
pt = l1.p0
l1 = l1.ln
else:
pt = l1.p0
l1 = l1.entity
if isinstance(l2,NormalInfo):
l2 = l2.ln
else:
l2 = l2.entity
h.append(self.addParallel(l1,l2,wrkpln=wrkpln,group=group))
h.append(self.addPointOnLine(pt,l2,wrkpln=wrkpln,group=group))
return h
def addPlacement(self,pla,group=0):