constraint: extend Angle locking to yaw-pitch-roll
Angle locking applies to PlaneCoincident, PlaneAlignment, AxialAlignment, and MultiParallel
This commit is contained in:
parent
61ccdf5bac
commit
094828561b
147
constraint.py
147
constraint.py
|
@ -7,6 +7,13 @@ 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'))
|
||||
PlaneInfo = namedtuple('PlaneInfo', ('entity','origin','normal'))
|
||||
CircleInfo = namedtuple('CurcleInfo',('entity','radius','p0'))
|
||||
ArcInfo = namedtuple('CurcleInfo',('entity','p1','p0','params'))
|
||||
|
||||
def _d(solver,partInfo,subname,shape,retAll=False):
|
||||
'return a handle of any supported element of a draft object'
|
||||
if not solver:
|
||||
|
@ -45,7 +52,7 @@ def _p(solver,partInfo,subname,shape,retAll=False):
|
|||
system = solver.system
|
||||
if h:
|
||||
system.log('cache {}: {}'.format(key,h))
|
||||
return h if retAll else h[0]
|
||||
return h if retAll else h.entity
|
||||
|
||||
v = utils.getElementPos(shape)
|
||||
|
||||
|
@ -58,30 +65,28 @@ def _p(solver,partInfo,subname,shape,retAll=False):
|
|||
params.append(system.addParamV(val,group=partInfo.Group))
|
||||
system.NameTag = nameTag
|
||||
e = system.addPoint3d(*params)
|
||||
h = [e, params]
|
||||
system.log('{}: add draft point {},{}'.format(key,h,v))
|
||||
h = PointInfo(entity=e,params=params,vertex=v)
|
||||
system.log('{}: add draft point {}'.format(key,h))
|
||||
|
||||
if system.sketchPlane and not solver.isFixedElement(part,subname):
|
||||
system.NameTag = nameTag + '.i'
|
||||
e2 = system.addPointInPlane(e,system.sketchPlane[0],
|
||||
e2 = system.addPointInPlane(e,system.sketchPlane.entity,
|
||||
group=partInfo.Group)
|
||||
system.log('{}: add draft point in plane {},{}'.format(
|
||||
partInfo.PartName,e2,system.sketchPlane[0]))
|
||||
partInfo.PartName,e2,system.sketchPlane.entity))
|
||||
|
||||
elif utils.isDraftCircle(part):
|
||||
requireArc = subname=='Vertex2'
|
||||
e = _prepareDraftCircle(solver,partInfo,requireArc)
|
||||
if requireArc:
|
||||
h = [e[1]]
|
||||
elif subname=='Vertex1':
|
||||
h = [e[2]]
|
||||
if requireArc or subname=='Vertex1':
|
||||
h = PointInfo(entity=e.p0,params=partInfo.Params,vertex=v)
|
||||
elif subname=='Edge1':
|
||||
# center point
|
||||
h = [partInfo.Workplane[1]]
|
||||
h = partInfo.Workplane.origin
|
||||
else:
|
||||
raise RuntimeError('Invalid draft circle subname {} of '
|
||||
'{}'.format(subname,partInfo.PartName))
|
||||
system.log('{}: add circle point {},{}'.format(key,h,e))
|
||||
system.log('{}: add circle point {}'.format(key,h))
|
||||
|
||||
else:
|
||||
nameTag = partInfo.PartName + '.' + key
|
||||
|
@ -89,13 +94,11 @@ 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 = [h,e]
|
||||
h = PointInfo(entity=h, params=partInfo.Params,vertex=v)
|
||||
system.log('{}: {},{}'.format(key,h,partInfo.Group))
|
||||
|
||||
# use the point entity as key to store its original position vector
|
||||
partInfo.EntityMap[h[0]] = [v]
|
||||
partInfo.EntityMap[key] = h
|
||||
return h if retAll else h[0]
|
||||
return h if retAll else h.entity
|
||||
|
||||
def _n(solver,partInfo,subname,shape,retAll=False):
|
||||
'return a handle of a transformed normal quaterion derived from shape'
|
||||
|
@ -113,8 +116,6 @@ def _n(solver,partInfo,subname,shape,retAll=False):
|
|||
if h:
|
||||
system.log('cache {}: {}'.format(key,h))
|
||||
else:
|
||||
h = []
|
||||
|
||||
if utils.isDraftCircle(partInfo.Part):
|
||||
_prepareDraftCircle(solver,partInfo)
|
||||
|
||||
|
@ -123,25 +124,13 @@ def _n(solver,partInfo,subname,shape,retAll=False):
|
|||
system.NameTag = nameTag
|
||||
e = system.addNormal3dV(*utils.getNormal(rot))
|
||||
system.NameTag += 't'
|
||||
h.append(system.addTransform(e,*partInfo.Params,group=partInfo.Group))
|
||||
nz = system.addTransform(e,*partInfo.Params,group=partInfo.Group)
|
||||
|
||||
# also add x axis pointing quaterion for convenience
|
||||
xrot = FreeCAD.Rotation(FreeCAD.Vector(0,1,0),90).multiply(rot)
|
||||
system.NameTag = nameTag + 'x'
|
||||
e = system.addNormal3dV(*utils.getNormal(xrot))
|
||||
system.NameTag = nameTag + 'xt'
|
||||
h.append(system.addTransform(e,*partInfo.Params,group=partInfo.Group))
|
||||
|
||||
# also add local x pointing vector (1,0,0)
|
||||
px = rot.multVec(FreeCAD.Vector(1,0,0))
|
||||
hx = system.addPoint3dV(px.x,px.y,px.z)
|
||||
h.append(system.addTransform(hx,*partInfo.Params,group=partInfo.Group))
|
||||
h = NormalInfo(entity=nz,rot=rot,params=partInfo.Params)
|
||||
|
||||
system.log('{}: {},{}'.format(key,h,partInfo.Group))
|
||||
# use the normal entity as key to store its original rotation
|
||||
partInfo.EntityMap[h[0]] = [rot]
|
||||
partInfo.EntityMap[key] = h
|
||||
return h if retAll else h[0]
|
||||
return h if retAll else h.entity
|
||||
|
||||
def _l(solver,partInfo,subname,shape,retAll=False):
|
||||
'return a pair of handle of the end points of an edge in "shape"'
|
||||
|
@ -154,7 +143,7 @@ def _l(solver,partInfo,subname,shape,retAll=False):
|
|||
if not vname1:
|
||||
raise RuntimeError('Invalid draft subname {} or {}'.format(
|
||||
subname,objName(partInfo)))
|
||||
v = shape.Edges[0].Vertexes
|
||||
v = shape.Edge1.Vertexes
|
||||
ret = _p(solver,partInfo,vname1,v[0])
|
||||
if ret:
|
||||
return ret
|
||||
|
@ -168,7 +157,7 @@ def _l(solver,partInfo,subname,shape,retAll=False):
|
|||
system.log('cache {}: {}'.format(key,h))
|
||||
else:
|
||||
nameTag = partInfo.PartName + '.' + key
|
||||
v = shape.Edges[0].Vertexes
|
||||
v = shape.Edge1.Vertexes
|
||||
if utils.isDraftWire(part):
|
||||
vname1,vname2 = utils.edge2VertexIndex(part,subname)
|
||||
if not vname1:
|
||||
|
@ -188,11 +177,11 @@ def _l(solver,partInfo,subname,shape,retAll=False):
|
|||
|
||||
system.NameTag = nameTag
|
||||
h = system.addLineSegment(tp1,tp2,group=partInfo.Group)
|
||||
h = (h,tp1,tp2)
|
||||
h = LineInfo(entity=h,p1=tp1,p2=tp2)
|
||||
system.log('{}: {},{}'.format(key,h,partInfo.Group))
|
||||
partInfo.EntityMap[key] = h
|
||||
|
||||
return h if retAll else h[0]
|
||||
return h if retAll else h.entity
|
||||
|
||||
def _la(solver,partInfo,subname,shape,retAll=False):
|
||||
_ = retAll
|
||||
|
@ -240,13 +229,13 @@ def _w(solver,partInfo,subname,shape,retAll=False):
|
|||
if h:
|
||||
system.log('cache {}: {}'.format(key,h))
|
||||
else:
|
||||
p = _p(solver,partInfo,subname,shape)
|
||||
p = _p(solver,partInfo,subname,shape,True)
|
||||
n = _n(solver,partInfo,subname,shape,True)
|
||||
system.NameTag = partInfo.PartName + '.' + key
|
||||
w = system.addWorkplane(p,n[0],group=partInfo.Group)
|
||||
h = [w,p,n]
|
||||
w = system.addWorkplane(p.entity,n.entity,group=partInfo.Group)
|
||||
h = PlaneInfo(entity=w,origin=p,normal=n)
|
||||
system.log('{}: {},{}'.format(key,h,partInfo.Group))
|
||||
return h if retAll else h[0]
|
||||
return h if retAll else h.entity
|
||||
|
||||
def _wa(solver,partInfo,subname,shape,retAll=False):
|
||||
_ = retAll
|
||||
|
@ -269,21 +258,22 @@ def _c(solver,partInfo,subname,shape,requireArc=False,retAll=False):
|
|||
system = solver.system
|
||||
if h:
|
||||
system.log('cache {}: {}'.format(key,h))
|
||||
return h if retAll else h[0]
|
||||
return h if retAll else h.entity
|
||||
|
||||
g = partInfo.Group
|
||||
nameTag = partInfo.PartName + '.' + key
|
||||
|
||||
if utils.isDraftCircle(partInfo.Part):
|
||||
part = partInfo.Part
|
||||
w,p,n = partInfo.Workplane[:3]
|
||||
n = n[0]
|
||||
pln = partInfo.Workplane
|
||||
|
||||
if system.sketchPlane and not solver.isFixedElement(part,subname):
|
||||
system.NameTag = nameTag + '.o'
|
||||
e1 = system.addSameOrientation(n,system.sketchPlane[2],group=g)
|
||||
e1 = system.addSameOrientation(pln.normal.entity,
|
||||
system.sketchPlane.normal.entity, group=g)
|
||||
system.NameTag = nameTag + '.i'
|
||||
e2 = system.addPointInPlane(p,system.sketchPlane[0],group=g)
|
||||
e2 = system.addPointInPlane(
|
||||
pln.origin.entity, system.sketchPlane.entity, group=g)
|
||||
system.log('{}: fix draft circle in plane {},{}'.format(
|
||||
partInfo.PartName,e1,e2))
|
||||
|
||||
|
@ -294,14 +284,15 @@ def _c(solver,partInfo,subname,shape,requireArc=False,retAll=False):
|
|||
system.NameTag = nameTag + '.r'
|
||||
r = system.addParamV(part.Radius.Value,group=g)
|
||||
system.NameTag = nameTag + '.p0'
|
||||
p0 = system.addPoint2d(w,r,solver.v0,group=g)
|
||||
p0 = system.addPoint2d(pln.entity,r,solver.v0,group=g)
|
||||
system.NameTag = nameTag
|
||||
e = system.addCircle(p,n,system.addDistance(r),group=g)
|
||||
h = [e,r,p0]
|
||||
e = system.addCircle(pln.origin.entity, pln.normal.entity,
|
||||
system.addDistance(r), group=g)
|
||||
h = CircleInfo(entity=e,radius=r,p0=p0)
|
||||
system.log('{}: add draft circle {}, {}'.format(key,h,g))
|
||||
else:
|
||||
system.NameTag = nameTag + '.c'
|
||||
center = system.addPoint2d(w,solver.v0,solver.v0,group=g)
|
||||
center = system.addPoint2d(pln.entity,solver.v0,solver.v0,group=g)
|
||||
params = []
|
||||
points = []
|
||||
v = shape.Vertexes
|
||||
|
@ -310,10 +301,11 @@ def _c(solver,partInfo,subname,shape,requireArc=False,retAll=False):
|
|||
system.NameTag = nameTag+n.format(i)
|
||||
params.append(system.addParamV(val,group=g))
|
||||
system.NameTag = nameTag + '.p{}'.format(i)
|
||||
points.append(system.addPoint2d(w,*params[-2:],group=g))
|
||||
pt = system.addPoint2d(pln.entity,*params[-2:],group=g)
|
||||
points.append(pt)
|
||||
system.NameTag = nameTag
|
||||
e = system.addArcOfCircle(w,center,*points,group=g)
|
||||
h = [e,points[1],points[0],params]
|
||||
e = system.addArcOfCircle(pln.entity,center,*points,group=g)
|
||||
h = ArcInfo(entity=e,p1=points[1],p0=points[0],params=params)
|
||||
system.log('{}: add draft arc {}, {}'.format(key,h,g))
|
||||
|
||||
# exhaust all possible keys from a draft circle to save
|
||||
|
@ -321,8 +313,7 @@ def _c(solver,partInfo,subname,shape,requireArc=False,retAll=False):
|
|||
sub = subname + '.c' if requireArc else '.a'
|
||||
partInfo.EntityMap[sub] = h
|
||||
else:
|
||||
w,p,n = _w(solver,partInfo,subname,shape,True)[:3]
|
||||
n = n[0]
|
||||
pln = _w(solver,partInfo,subname,shape,True)
|
||||
r = utils.getElementCircular(shape)
|
||||
if not r:
|
||||
raise RuntimeError('shape is not cicular')
|
||||
|
@ -331,16 +322,19 @@ def _c(solver,partInfo,subname,shape,requireArc=False,retAll=False):
|
|||
if requireArc or isinstance(r,(list,tuple)):
|
||||
l = _l(solver,partInfo,subname,shape,True)
|
||||
system.NameTag = nameTag
|
||||
h = system.addArcOfCircle(w,p,l[1],l[2],group=g)
|
||||
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)
|
||||
else:
|
||||
system.NameTag = nameTag
|
||||
h = system.addCircle(p,n,hr,group=g)
|
||||
h = (h,hr)
|
||||
h = system.addCircle(
|
||||
pln.origin.entity, pln.normal.entity, hr, group=g)
|
||||
h = CircleInfo(entity=h,radius=hr,p0=None)
|
||||
system.log('{}: {},{}'.format(key,h,g))
|
||||
|
||||
partInfo.EntityMap[key] = h
|
||||
|
||||
return h if retAll else h[0]
|
||||
return h if retAll else h.entity
|
||||
|
||||
def _dc(solver,partInfo,subname,shape,requireArc=False,retAll=False):
|
||||
'return a handle of a draft circle'
|
||||
|
@ -519,21 +513,36 @@ class Constraint(ProxyType):
|
|||
|
||||
|
||||
def _makeProp(name,tp,doc='',getter=propGet,internal=False,default=None):
|
||||
PropertyInfo(Constraint,name,tp,doc,getter=getter,
|
||||
group='Constraint',internal=internal,default=default)
|
||||
return PropertyInfo(Constraint,name,tp,doc,getter=getter,duplicate=True,
|
||||
group='Constraint',internal=internal,default=default).Key
|
||||
|
||||
_makeProp('Distance','App::PropertyDistance',getter=propGetValue)
|
||||
_makeProp('Length','App::PropertyDistance',getter=propGetValue,default=5.0)
|
||||
_makeProp('Offset','App::PropertyDistance',getter=propGetValue)
|
||||
_makeProp('Cascade','App::PropertyBool',internal=True)
|
||||
_makeProp('Angle','App::PropertyAngle',getter=propGetValue)
|
||||
_makeProp('LockAngle','App::PropertyBool')
|
||||
|
||||
_AngleProps = [
|
||||
_makeProp('LockAngle','App::PropertyBool',
|
||||
doc='Enforce an angle offset defined as yaw-pitch-roll angle of the\n'
|
||||
'second plane performed in the order of x-y-z'),
|
||||
_makeProp('Angle','App::PropertyAngle',getter=propGetValue,
|
||||
doc='The rotation angle of the second plane about its z-axis.\n'
|
||||
'You need to enable LockAngle for this to take effect.'),
|
||||
_makeProp('AnglePitch','App::PropertyAngle',getter=propGetValue,
|
||||
doc='Rotation angle of the second plane about its y-axis.\n'
|
||||
'You need to enable LockAngle for this to take effect.'),
|
||||
_makeProp('AngleRoll','App::PropertyAngle',getter=propGetValue,
|
||||
doc='Rotation angle of the second plane about its x-axis\n'
|
||||
'You need to enable LockAngle for this to take effect.'),
|
||||
]
|
||||
|
||||
_makeProp('Ratio','App::PropertyFloat',default=1.0)
|
||||
_makeProp('Difference','App::PropertyFloat')
|
||||
_makeProp('Diameter','App::PropertyDistance',getter=propGetValue,default=10.0)
|
||||
_makeProp('Radius','App::PropertyDistance',getter=propGetValue,default=5.0)
|
||||
_makeProp('Supplement','App::PropertyBool',
|
||||
'If True, then the second angle is calculated as 180-angle')
|
||||
'If True, then the angle is calculated as 180-angle')
|
||||
_makeProp('AtEnd','App::PropertyBool',
|
||||
'If True, then tangent at the end point, or else at the start point')
|
||||
|
||||
|
@ -624,7 +633,7 @@ class Base(object):
|
|||
|
||||
if cls._workplane and len(elements)==len(cls._entityDef):
|
||||
if solver.system.sketchPlane:
|
||||
ret.append(solver.system.sketchPlane[0])
|
||||
ret.append(solver.system.sketchPlane.entity)
|
||||
elif int(cls._workplane)>1:
|
||||
raise RuntimeError('Constraint "{}" requires a sketch plane '
|
||||
'or a {} element to define a projection plane'.format(
|
||||
|
@ -755,7 +764,7 @@ class Locked(Base):
|
|||
e0 = e1
|
||||
system.NameTag = nameTag + surfix
|
||||
if system.sketchPlane and utils.isDraftObject(info.Part):
|
||||
w = system.sketchPlane[0]
|
||||
w = system.sketchPlane.entity
|
||||
else:
|
||||
w = 0
|
||||
e = system.addPointsCoincident(e1,e2,w,group=solver.group)
|
||||
|
@ -901,7 +910,7 @@ class BaseCascade(BaseMulti):
|
|||
class PlaneCoincident(BaseCascade):
|
||||
_id = 35
|
||||
_iconName = 'Assembly_ConstraintCoincidence.svg'
|
||||
_props = ['Cascade','Offset','LockAngle','Angle']
|
||||
_props = ['Cascade','Offset'] + _AngleProps
|
||||
_tooltip = \
|
||||
'Add a "{}" constraint to conincide planes of two or more parts.\n'\
|
||||
'The planes are coincided at their centers with an optional distance.'
|
||||
|
@ -909,7 +918,7 @@ class PlaneCoincident(BaseCascade):
|
|||
class PlaneAlignment(BaseCascade):
|
||||
_id = 37
|
||||
_iconName = 'Assembly_ConstraintAlignment.svg'
|
||||
_props = ['Cascade','Offset','LockAngle','Angle']
|
||||
_props = ['Cascade','Offset'] + _AngleProps
|
||||
_tooltip = 'Add a "{}" constraint to rotate planes of two or more parts\n'\
|
||||
'into the same orientation'
|
||||
|
||||
|
@ -917,7 +926,7 @@ class PlaneAlignment(BaseCascade):
|
|||
class AxialAlignment(BaseMulti):
|
||||
_id = 36
|
||||
_iconName = 'Assembly_ConstraintAxial.svg'
|
||||
_props = ['LockAngle','Angle']
|
||||
_props = _AngleProps
|
||||
_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.'
|
||||
|
||||
|
@ -934,8 +943,8 @@ class MultiParallel(BaseMulti):
|
|||
_id = 291
|
||||
_entityDef = (_lw,)
|
||||
_iconName = 'Assembly_ConstraintMultiParallel.svg'
|
||||
_props = ['LockAngle','Angle']
|
||||
_tooltip = 'Add a "{}" constraint to make planes normal or linear edges\n'\
|
||||
_props = _AngleProps
|
||||
_tooltip = 'Add a "{}" constraint to make planes ormal or linear edges\n'\
|
||||
'of two or more parts parallel.'
|
||||
|
||||
|
||||
|
|
29
solver.py
29
solver.py
|
@ -4,7 +4,8 @@ import FreeCAD, FreeCADGui
|
|||
from .assembly import Assembly, isTypeOf, setPlacement
|
||||
from . import utils
|
||||
from .utils import syslogger as logger, objName, isSamePlacement
|
||||
from .constraint import Constraint, cstrName
|
||||
from .constraint import Constraint, cstrName, \
|
||||
NormalInfo, PlaneInfo, PointInfo
|
||||
from .system import System
|
||||
|
||||
# Part: the part object
|
||||
|
@ -44,13 +45,17 @@ class Solver(object):
|
|||
self.v0 = self.system.addParamV(0,group=self._fixedGroup)
|
||||
self.v1 = self.system.addParamV(1,group=self._fixedGroup)
|
||||
|
||||
# convenience normals
|
||||
# convenience x normals
|
||||
rotx = FreeCAD.Rotation(FreeCAD.Vector(0,1,0),-90)
|
||||
self.nx = self.system.addNormal3dV(*utils.getNormal(rotx))
|
||||
|
||||
# convenience x pointing vector
|
||||
self.px = self.system.addPoint3d(self.v1,self.v0,self.v0)
|
||||
|
||||
# convenience y normals
|
||||
roty = FreeCAD.Rotation(FreeCAD.Vector(1,0,0),90)
|
||||
self.ny = self.system.addNormal3dV(*utils.getNormal(roty))
|
||||
|
||||
self._fixedParts = Constraint.getFixedParts(self,cstrs)
|
||||
for part in self._fixedParts:
|
||||
self._fixedElements.add((part,None))
|
||||
|
@ -115,10 +120,11 @@ class Solver(object):
|
|||
changed = False
|
||||
points = part.Points
|
||||
for key,h in partInfo.EntityMap.items():
|
||||
if not key.endswith('.p') or\
|
||||
if not isinstance(key, str) or\
|
||||
not key.endswith('.p') or\
|
||||
not key.startswith('Vertex'):
|
||||
continue
|
||||
v = [ self.system.getParam(p).val for p in h[1] ]
|
||||
v = [ self.system.getParam(p).val for p in h.params ]
|
||||
v = FreeCAD.Vector(*v)
|
||||
v = partInfo.Placement.inverse().multVec(v)
|
||||
idx = utils.draftWireVertex2PointIndex(part,key[:-2])
|
||||
|
@ -163,9 +169,9 @@ class Solver(object):
|
|||
part.FirstAngle.Value,
|
||||
part.LastAngle.Value)
|
||||
if part.FirstAngle == part.LastAngle:
|
||||
v = (self.system.getParam(h[1]).val,v0[1],v0[2])
|
||||
v = (self.system.getParam(h.radius).val,v0[1],v0[2])
|
||||
else:
|
||||
params = [self.system.getParam(p).val for p in h[3]]
|
||||
params = [self.system.getParam(p).val for p in h.params]
|
||||
p0 = FreeCAD.Vector(1,0,0)
|
||||
p1 = FreeCAD.Vector(params[0],params[1],0)
|
||||
p2 = FreeCAD.Vector(params[2],params[3],0)
|
||||
|
@ -222,14 +228,13 @@ 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 + '.nx'
|
||||
nx = self.system.addTransform(self.nx,
|
||||
self.v0,self.v0,self.v0,*params[3:],group=g)
|
||||
px = self.system.addTransform(self.px,self.v0,self.v0,
|
||||
self.v0,*params[3:],group=g)
|
||||
self.system.NameTag = info.PartName + '.w'
|
||||
w = self.system.addWorkplane(p,n,group=g)
|
||||
h = (w,p,(n,nx,px))
|
||||
h = PlaneInfo(entity=w,
|
||||
origin=PointInfo(entity=p, params=None,
|
||||
vertex=FreeCAD.Vector()),
|
||||
normal=NormalInfo(entity=n,rot=FreeCAD.Rotation(),
|
||||
params=params))
|
||||
|
||||
partInfo = PartInfo(Part = info.Part,
|
||||
PartName = info.PartName,
|
||||
|
|
105
system.py
105
system.py
|
@ -1,6 +1,7 @@
|
|||
import os
|
||||
import FreeCAD
|
||||
from .constraint import cstrName
|
||||
from .utils import getIcon, syslogger as logger, objName, project2D
|
||||
from .utils import getIcon, syslogger as logger, objName, project2D, getNormal
|
||||
from .proxy import ProxyType, PropertyInfo
|
||||
|
||||
class System(ProxyType):
|
||||
|
@ -130,22 +131,26 @@ class SystemExtension(object):
|
|||
self.sketchPlane = args[0] if args else None
|
||||
return self.sketchPlane
|
||||
|
||||
def setOrientation(self,h,lockAngle,angle,n1,n2,nx1,nx2,group):
|
||||
if lockAngle and not angle:
|
||||
h.append(self.addSameOrientation(n1,n2,group=group))
|
||||
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
|
||||
if not yaw and not pitch and not roll:
|
||||
n = n2.entity
|
||||
else:
|
||||
h.append(self.addParallel(n1,n2,group=group))
|
||||
if lockAngle:
|
||||
h.append(self.addAngle(angle,False,nx1,nx2,group=group))
|
||||
rot = n2.rot.multiply(FreeCAD.Rotation(yaw,pitch,roll))
|
||||
e = self.addNormal3dV(*getNormal(rot))
|
||||
n = self.addTransform(e,*n2.params,group=group)
|
||||
h.append(self.addSameOrientation(n1.entity,n,group=group))
|
||||
return h
|
||||
|
||||
def reportRedundancy(self,warn=False):
|
||||
msg = '{} between {} and {}'.format(cstrName(self.cstrObj),
|
||||
self.firstInfo.PartName, self.secondInfo.PartName)
|
||||
if warn:
|
||||
logger.warn('skip redundant ' + msg)
|
||||
logger.warn('skip redundant ' + msg, frame=1)
|
||||
else:
|
||||
logger.info('auto relax ' + msg)
|
||||
logger.info('auto relax ' + msg, frame=1)
|
||||
|
||||
def countConstraints(self,increment,count,*names):
|
||||
first,second = self.firstInfo,self.secondInfo
|
||||
|
@ -163,21 +168,18 @@ class SystemExtension(object):
|
|||
if increment:
|
||||
cstrs += [None]*increment
|
||||
ret += len(cstrs)
|
||||
if count and ret >= count:
|
||||
if count and ret>=count:
|
||||
if ret>count:
|
||||
self.reportRedundancy(True)
|
||||
return -1
|
||||
else:
|
||||
elif ret!=len(cstrs):
|
||||
self.reportRedundancy()
|
||||
return ret
|
||||
|
||||
def addPlaneCoincident(self,d,lockAngle,angle,e1,e2,group=0):
|
||||
def addPlaneCoincident(
|
||||
self, d, lockAngle, yaw, pitch, roll, pln1, pln2, group=0):
|
||||
if not group:
|
||||
group = self.GroupHandle
|
||||
w1,p1,n1 = e1[:3]
|
||||
_,p2,n2 = e2[:3]
|
||||
n1,nx1 = n1[:2]
|
||||
n2,nx2 = n2[:2]
|
||||
h = []
|
||||
count = self.countConstraints(2 if lockAngle else 1,2,'Coincident')
|
||||
if count<0:
|
||||
|
@ -191,28 +193,29 @@ 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(self.firstInfo.EntityMap[n1][0],
|
||||
self.firstInfo.EntityMap[p1][0],
|
||||
self.secondInfo.EntityMap[p2][0])
|
||||
v1,v2 = project2D(pln1.normal.rot,
|
||||
pln1.origin.vertex, pln2.origin.vertex)
|
||||
if abs(v1.x-v2.x) < abs(v1.y-v2.y):
|
||||
h.append(self.addPointsHorizontal(p1,p2,w1,group=group))
|
||||
h.append(self.addPointsHorizontal(pln1.origin.entity,
|
||||
pln2.origin.entity, pln1.entity, group=group))
|
||||
else:
|
||||
h.append(self.addPointsVertical(p1,p2,w1,group=group))
|
||||
h.append(self.addPointsVertical(pln1.origin.entity,
|
||||
pln2.origin.entity, pln1.entity, group=group))
|
||||
return h
|
||||
if d:
|
||||
h.append(self.addPointPlaneDistance(d,p2,w1,group=group))
|
||||
h.append(self.addPointsCoincident(p1,p2,w1,group=group))
|
||||
h.append(self.addPointPlaneDistance(
|
||||
d, pln2.origin.entity, pln1.entity, group=group))
|
||||
h.append(self.addPointsCoincident(pln1.origin.entity,
|
||||
pln2.origin.entity, pln1.entity, group=group))
|
||||
else:
|
||||
h.append(self.addPointsCoincident(p1,p2,group=group))
|
||||
return self.setOrientation(h,lockAngle,angle,n1,n2,nx1,nx2,group)
|
||||
h.append(self.addPointsCoincident(
|
||||
pln1.origin.entity, pln2.origin.entity, group=group))
|
||||
return self.setOrientation(h, lockAngle, yaw, pitch, roll,
|
||||
pln1.normal, pln2.normal, group)
|
||||
|
||||
def addPlaneAlignment(self,d,lockAngle,angle,e1,e2,group=0):
|
||||
def addPlaneAlignment(self,d,lockAngle,yaw,pitch,roll,pln1,pln2,group=0):
|
||||
if not group:
|
||||
group = self.GroupHandle
|
||||
w1,_,n1 = e1[:4]
|
||||
_,p2,n2 = e2[:4]
|
||||
n1,nx1 = n1[:2]
|
||||
n2,nx2 = n2[:2]
|
||||
h = []
|
||||
if self.relax:
|
||||
count = self.countConstraints(2 if lockAngle else 1,3,'Alignment')
|
||||
|
@ -221,49 +224,51 @@ class SystemExtension(object):
|
|||
else:
|
||||
count = 0
|
||||
if d:
|
||||
h.append(self.addPointPlaneDistance(d,p2,w1,group=group))
|
||||
h.append(self.addPointPlaneDistance(
|
||||
d, pln2.origin.entity, pln1.entity.entity, group=group))
|
||||
else:
|
||||
h.append(self.addPointInPlane(p2,w1,group=group))
|
||||
h.append(self.addPointInPlane(
|
||||
pln2.origin.entity, pln1.entity,group=group))
|
||||
if count<=2:
|
||||
if count==2 and not lockAngle:
|
||||
self.reportRedundancy()
|
||||
h.append(self.setOrientation(h,lockAngle,angle,n1,n2,nx1,nx2,group))
|
||||
self.setOrientation(h, lockAngle, yaw, pitch, roll,
|
||||
pln1.normal, pln2.normal, group)
|
||||
return h
|
||||
|
||||
def addAxialAlignment(self,lockAngle,angle,e1,e2,group=0):
|
||||
def addAxialAlignment(self,lockAngle,yaw,pitch,roll,pln1,pln2,group=0):
|
||||
if not group:
|
||||
group = self.GroupHandle
|
||||
count = self.countConstraints(0,2,'Coincident')
|
||||
if count<0:
|
||||
return
|
||||
if count:
|
||||
return self.addPlaneCoincident(False,0,0,e1,e2,group)
|
||||
w1,p1,n1 = e1[:3]
|
||||
_,p2,n2 = e2[:3]
|
||||
n1,nx1 = n1[:2]
|
||||
n2,nx2 = n2[:2]
|
||||
return self.addPlaneCoincident(0,False,0,0,0,pln1,pln2,group)
|
||||
h = []
|
||||
h.append(self.addPointsCoincident(p1,p2,w1,group=group))
|
||||
return self.setOrientation(h,lockAngle,angle,n1,n2,nx1,nx2,group)
|
||||
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)
|
||||
|
||||
def addMultiParallel(self,lockAngle,angle,e1,e2,group=0):
|
||||
def addMultiParallel(self,lockAngle,yaw,pitch,raw,e1,e2,group=0):
|
||||
h = []
|
||||
isPlane = isinstance(e1,list),isinstance(e2,list)
|
||||
if all(isPlane):
|
||||
return self.setOrientation(
|
||||
h,lockAngle,angle,e1[2],e2[2],e1[3],e2[3],group);
|
||||
return self.setOrientation(h, lockAngle, yaw, pitch, raw,
|
||||
e1.normal, e2.normal, group);
|
||||
if not any(isPlane):
|
||||
h.append(self.addParallel(e1,e2,group=group))
|
||||
h.append(self.addParallel(
|
||||
e1.normal.entity, e2.normal.entity, group=group))
|
||||
elif isPlane[0]:
|
||||
h.append(self.addPerpendicular(e1[2],e2,group=group))
|
||||
h.append(self.addPerpendicular(e1.normal.entity, e2, group=group))
|
||||
else:
|
||||
h.append(self.addPerpendicular(e1,e2[2],group=group))
|
||||
h.append(self.addPerpendicular(e1, e2.normal.entity, group=group))
|
||||
return h
|
||||
|
||||
def addColinear(self,e1,e2,wrkpln=0,group=0):
|
||||
def addColinear(self,l1,l2,wrkpln=0,group=0):
|
||||
h = []
|
||||
h.append(self.addParallel(e1[0],e2,wrkpln=wrkpln,group=group))
|
||||
h.append(self.addPointOnLine(e1[1],e2,wrkpln=wrkpln,group=group))
|
||||
h.append(self.addParallel(l1.entity,l2,wrkpln=wrkpln,group=group))
|
||||
h.append(self.addPointOnLine(l1.entity,l2,wrkpln=wrkpln,group=group))
|
||||
return h
|
||||
|
||||
def addPlacement(self,pla,group=0):
|
||||
|
|
Loading…
Reference in New Issue
Block a user