Add support for draft circle/arc
When added to an assembly, a normal part object has six degrees of freedom, three positional and three rotational. A draft circle has one additional dof, its radius. And a draft arc has three additional dof, radius, first angle and last angle.
This commit is contained in:
parent
05595e3f41
commit
b087200e50
21
assembly.py
21
assembly.py
|
@ -488,7 +488,7 @@ class ViewProviderAsmElement(ViewProviderAsmOnTop):
|
||||||
Group=owner, Subname=subname),undo=True)
|
Group=owner, Subname=subname),undo=True)
|
||||||
|
|
||||||
|
|
||||||
def getPartInfo(parent, subname):
|
def getElementInfo(parent, subname):
|
||||||
'''Return a named tuple containing the part object element information
|
'''Return a named tuple containing the part object element information
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
|
@ -630,7 +630,7 @@ def getPartInfo(parent, subname):
|
||||||
obj = part.getLinkedObject(False)
|
obj = part.getLinkedObject(False)
|
||||||
partName = part.Name
|
partName = part.Name
|
||||||
|
|
||||||
return utils.PartInfo(Parent = parent,
|
return utils.ElementInfo(Parent = parent,
|
||||||
SubnameRef = subnameRef,
|
SubnameRef = subnameRef,
|
||||||
Part = part,
|
Part = part,
|
||||||
PartName = partName,
|
PartName = partName,
|
||||||
|
@ -749,7 +749,7 @@ class AsmElementLink(AsmBase):
|
||||||
self.info = None
|
self.info = None
|
||||||
if not getattr(self,'Object',None):
|
if not getattr(self,'Object',None):
|
||||||
return
|
return
|
||||||
self.info = getPartInfo(self.getAssembly().getPartGroup(),
|
self.info = getElementInfo(self.getAssembly().getPartGroup(),
|
||||||
self.getElementSubname())
|
self.getElementSubname())
|
||||||
return self.info
|
return self.info
|
||||||
|
|
||||||
|
@ -1619,7 +1619,7 @@ class AsmMovingPart(object):
|
||||||
movingPart.tracePoint = movingPart.draggerPlacement.Base
|
movingPart.tracePoint = movingPart.draggerPlacement.Base
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
info = getPartInfo(self.parent,self.subname)
|
info = getElementInfo(self.parent,self.subname)
|
||||||
self.oldPlacement = info.Placement.copy()
|
self.oldPlacement = info.Placement.copy()
|
||||||
self.part = info.Part
|
self.part = info.Part
|
||||||
self.partName = info.PartName
|
self.partName = info.PartName
|
||||||
|
@ -1691,11 +1691,12 @@ class AsmMovingPart(object):
|
||||||
# AsmMovingPart.update()
|
# AsmMovingPart.update()
|
||||||
return self.draggerPlacement
|
return self.draggerPlacement
|
||||||
|
|
||||||
def getMovingPartInfo():
|
def getMovingElementInfo():
|
||||||
'''Extract information from current selection for part moving
|
'''Extract information from current selection for part moving
|
||||||
|
|
||||||
It returns a tuple containing the selected assembly hierarchy (obtained from
|
It returns a tuple containing the selected assembly hierarchy (obtained from
|
||||||
Assembly.findChildren()), and AsmPartInfo of the selected child part object.
|
Assembly.findChildren()), and AsmElementInfo of the selected child part
|
||||||
|
object.
|
||||||
|
|
||||||
If there is only one selection, then the moving part will be one belong to
|
If there is only one selection, then the moving part will be one belong to
|
||||||
the highest level assembly in selected hierarchy.
|
the highest level assembly in selected hierarchy.
|
||||||
|
@ -1722,7 +1723,7 @@ def getMovingPartInfo():
|
||||||
objName(sels[0].Object),sels[0].SubElementNames[0]))
|
objName(sels[0].Object),sels[0].SubElementNames[0]))
|
||||||
|
|
||||||
if len(sels[0].SubElementNames)==1:
|
if len(sels[0].SubElementNames)==1:
|
||||||
info = getPartInfo(ret[0].Assembly,ret[0].Subname)
|
info = getElementInfo(ret[0].Assembly,ret[0].Subname)
|
||||||
if not info:
|
if not info:
|
||||||
return
|
return
|
||||||
return (ret, info)
|
return (ret, info)
|
||||||
|
@ -1741,14 +1742,14 @@ def getMovingPartInfo():
|
||||||
assembly = ret[-1].Assembly
|
assembly = ret[-1].Assembly
|
||||||
for r in ret2:
|
for r in ret2:
|
||||||
if assembly == r.Assembly:
|
if assembly == r.Assembly:
|
||||||
return (ret2, getPartInfo(r.Assembly,r.Subname))
|
return (ret2, getElementInfo(r.Assembly,r.Subname))
|
||||||
raise RuntimeError('not child parent selection')
|
raise RuntimeError('not child parent selection')
|
||||||
|
|
||||||
def canMovePart():
|
def canMovePart():
|
||||||
return logger.catchTrace('',getMovingPartInfo) is not None
|
return logger.catchTrace('',getMovingElementInfo) is not None
|
||||||
|
|
||||||
def movePart(useCenterballDragger=None):
|
def movePart(useCenterballDragger=None):
|
||||||
ret = logger.catch('exception when moving part', getMovingPartInfo)
|
ret = logger.catch('exception when moving part', getMovingElementInfo)
|
||||||
if not ret:
|
if not ret:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
331
constraint.py
331
constraint.py
|
@ -1,5 +1,5 @@
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
import FreeCAD, FreeCADGui
|
import FreeCAD, FreeCADGui, Part
|
||||||
from . import utils, gui
|
from . import utils, gui
|
||||||
from .utils import objName,cstrlogger as logger, guilogger
|
from .utils import objName,cstrlogger as logger, guilogger
|
||||||
from .proxy import ProxyType, PropertyInfo, propGet, propGetValue
|
from .proxy import ProxyType, PropertyInfo, propGet, propGetValue
|
||||||
|
@ -12,11 +12,10 @@ def _p(solver,partInfo,subname,shape,retAll=False):
|
||||||
if not solver:
|
if not solver:
|
||||||
if not utils.hasCenter(shape):
|
if not utils.hasCenter(shape):
|
||||||
return 'a vertex or circular edge/face'
|
return 'a vertex or circular edge/face'
|
||||||
if not utils.isDraftWire(partInfo):
|
if utils.isDraftWire(partInfo):
|
||||||
return
|
if utils.draftWireVertex2PointIndex(partInfo,subname) is None:
|
||||||
if utils.draftWireVertex2PointIndex(partInfo,subname) is None:
|
raise RuntimeError('Invalid draft wire vertex "{}" {}'.format(
|
||||||
raise RuntimeError('Invalid draft wire vertex "{}" {}'.format(
|
subname,objName(partInfo)))
|
||||||
subname,objName(partInfo)))
|
|
||||||
return
|
return
|
||||||
|
|
||||||
key = subname+'.p'
|
key = subname+'.p'
|
||||||
|
@ -24,27 +23,46 @@ def _p(solver,partInfo,subname,shape,retAll=False):
|
||||||
system = solver.system
|
system = solver.system
|
||||||
if h:
|
if h:
|
||||||
system.log('cache {}: {}'.format(key,h))
|
system.log('cache {}: {}'.format(key,h))
|
||||||
|
return h if retAll else h[0]
|
||||||
|
|
||||||
|
if utils.isDraftWire(partInfo.Part):
|
||||||
|
v = utils.getElementPos(shape)
|
||||||
|
nameTag = partInfo.PartName + '.' + key
|
||||||
|
v = partInfo.Placement.multVec(v)
|
||||||
|
params = []
|
||||||
|
for n,val in (('.x',v.x),('.y',v.y),('.z',v.z)):
|
||||||
|
system.NameTag = nameTag+n
|
||||||
|
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))
|
||||||
|
|
||||||
|
elif utils.isDraftCircle(partInfo.Part):
|
||||||
|
shape = utils.getElementShape((partInfo.Part,'Edge1'),Part.Edge)
|
||||||
|
if subname == 'Vertex1':
|
||||||
|
e = _c(solver,partInfo,'Edge1',shape,retAll=True)
|
||||||
|
h = [e[2]]
|
||||||
|
elif subname == 'Vertex2':
|
||||||
|
e = _a(solver,partInfo,'Edge1',shape,retAll=True)
|
||||||
|
h = [e[1]]
|
||||||
|
else:
|
||||||
|
raise RuntimeError('Invalid draft circle vertex {} of '
|
||||||
|
'{}'.format(subname,objName(partInfo.Part)))
|
||||||
|
|
||||||
|
system.log('{}: add circle point {},{}'.format(key,h,e))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
v = utils.getElementPos(shape)
|
v = utils.getElementPos(shape)
|
||||||
nameTag = partInfo.PartName + '.' + key
|
nameTag = partInfo.PartName + '.' + key
|
||||||
if utils.isDraftWire(partInfo.Part):
|
system.NameTag = nameTag
|
||||||
v = partInfo.Placement.multVec(v)
|
e = system.addPoint3dV(*v)
|
||||||
params = []
|
system.NameTag = nameTag + 't'
|
||||||
for n,val in (('.x',v.x),('.y',v.y),('.z',v.z)):
|
h = system.addTransform(e[0],*partInfo.Params,group=partInfo.Group)
|
||||||
system.NameTag = nameTag+n
|
h = [h,e]
|
||||||
params.append(system.addParamV(val,group=partInfo.Group))
|
system.log('{}: {},{}'.format(key,h,partInfo.Group))
|
||||||
system.NameTag = nameTag
|
|
||||||
e = system.addPoint3d(*params)
|
partInfo.EntityMap[key] = h
|
||||||
h = [e, params]
|
|
||||||
system.log('{}: add draft point {},{}'.format(key,h,v))
|
|
||||||
else:
|
|
||||||
system.NameTag = nameTag
|
|
||||||
e = system.addPoint3dV(*v)
|
|
||||||
system.NameTag = nameTag + 't'
|
|
||||||
h = system.addTransform(e[0],*partInfo.Params,group=partInfo.Group)
|
|
||||||
h = [h,e]
|
|
||||||
system.log('{}: {},{}'.format(key,h,partInfo.Group))
|
|
||||||
partInfo.EntityMap[key] = h
|
|
||||||
return h if retAll else h[0]
|
return h if retAll else h[0]
|
||||||
|
|
||||||
def _n(solver,partInfo,subname,shape,retAll=False):
|
def _n(solver,partInfo,subname,shape,retAll=False):
|
||||||
|
@ -52,9 +70,9 @@ def _n(solver,partInfo,subname,shape,retAll=False):
|
||||||
if not solver:
|
if not solver:
|
||||||
if not utils.isPlanar(shape):
|
if not utils.isPlanar(shape):
|
||||||
return 'an edge or face with a surface normal'
|
return 'an edge or face with a surface normal'
|
||||||
if utils.isDraftWire(partInfo):
|
if utils.isDraftWire(partInfo.Part):
|
||||||
logger.warn('Use draft wire {} for normal. Draft wire placement'
|
logger.warn('Use draft wire {} for normal. Draft wire placement'
|
||||||
' is not transformable'.format(objName(partInfo)))
|
' is not transformable'.format(partInfo.PartName))
|
||||||
return
|
return
|
||||||
|
|
||||||
key = subname+'.n'
|
key = subname+'.n'
|
||||||
|
@ -88,7 +106,7 @@ def _l(solver,partInfo,subname,shape,retAll=False):
|
||||||
if not solver:
|
if not solver:
|
||||||
if not utils.isLinearEdge(shape):
|
if not utils.isLinearEdge(shape):
|
||||||
return 'a linear edge'
|
return 'a linear edge'
|
||||||
if not utils.isDraftWire(partInfo):
|
if not utils.isDraftWire(partInfo.Part):
|
||||||
return
|
return
|
||||||
part = partInfo
|
part = partInfo
|
||||||
vname1,vname2 = utils.edge2VertexIndex(subname)
|
vname1,vname2 = utils.edge2VertexIndex(subname)
|
||||||
|
@ -132,6 +150,14 @@ def _l(solver,partInfo,subname,shape,retAll=False):
|
||||||
|
|
||||||
return h if retAll else h[0]
|
return h if retAll else h[0]
|
||||||
|
|
||||||
|
def _dl(solver,partInfo,subname,shape,retAll=False):
|
||||||
|
'return a handle of a draft wire'
|
||||||
|
if not solver:
|
||||||
|
if utils.isDraftWire(partInfo):
|
||||||
|
return
|
||||||
|
raise RuntimeError('Requires a non-closed-or-subdivided draft wire')
|
||||||
|
return _l(solver,partInfo,subname,shape,retAll)
|
||||||
|
|
||||||
def _ln(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'
|
'return a handle for either a line or a normal depends on the shape'
|
||||||
if not solver:
|
if not solver:
|
||||||
|
@ -173,8 +199,10 @@ def _c(solver,partInfo,subname,shape,requireArc=False,retAll=False):
|
||||||
if not solver:
|
if not solver:
|
||||||
r = utils.getElementCircular(shape)
|
r = utils.getElementCircular(shape)
|
||||||
if r:
|
if r:
|
||||||
|
if requireArc and not isinstance(r,tuple):
|
||||||
|
return 'an arc edge'
|
||||||
return
|
return
|
||||||
return 'an cicular edge'
|
return 'a cicular edge'
|
||||||
if requireArc:
|
if requireArc:
|
||||||
key = subname+'.a'
|
key = subname+'.a'
|
||||||
else:
|
else:
|
||||||
|
@ -183,26 +211,76 @@ def _c(solver,partInfo,subname,shape,requireArc=False,retAll=False):
|
||||||
system = solver.system
|
system = solver.system
|
||||||
if h:
|
if h:
|
||||||
system.log('cache {}: {}'.format(key,h))
|
system.log('cache {}: {}'.format(key,h))
|
||||||
|
return h if retAll else h[0]
|
||||||
|
|
||||||
|
g = partInfo.Group
|
||||||
|
nameTag = partInfo.PartName + '.' + key
|
||||||
|
|
||||||
|
if utils.isDraftCircle(partInfo.Part):
|
||||||
|
part = partInfo.Part
|
||||||
|
w,p,n = partInfo.Workplane
|
||||||
|
if part.FirstAngle == part.LastAngle:
|
||||||
|
if requireArc:
|
||||||
|
raise RuntimeError('expecting an arc from {}'.format(
|
||||||
|
partInfo.PartName))
|
||||||
|
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)
|
||||||
|
system.NameTag = nameTag
|
||||||
|
e = system.addCircle(p,n,system.addDistance(r),group=g)
|
||||||
|
h = [e,r,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)
|
||||||
|
params = []
|
||||||
|
points = []
|
||||||
|
v = shape.Vertexes
|
||||||
|
for i in 0,1:
|
||||||
|
for n,val in ('.x{}',v[i].Point.x),('.y{}',v[i].Point.y):
|
||||||
|
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))
|
||||||
|
system.NameTag = nameTag
|
||||||
|
e = system.addArcOfCircle(w,center,*points,group=g)
|
||||||
|
h = [e,points[1],points[0],params]
|
||||||
|
system.log('{}: add draft arc {}, {}'.format(key,h,g))
|
||||||
|
|
||||||
|
# exhaust all possible keys from a draft circle to save
|
||||||
|
# recomputation
|
||||||
|
sub = subname + '.c' if requireArc else '.a'
|
||||||
|
partInfo.EntityMap[sub] = h
|
||||||
else:
|
else:
|
||||||
w,p,n,_ = _w(solver,partInfo,subname,shape,True)
|
w,p,n,_ = _w(solver,partInfo,subname,shape,True)
|
||||||
r = utils.getElementCircular(shape)
|
r = utils.getElementCircular(shape)
|
||||||
if not r:
|
if not r:
|
||||||
raise RuntimeError('shape is not cicular')
|
raise RuntimeError('shape is not cicular')
|
||||||
nameTag = partInfo.PartName + '.' + key
|
|
||||||
system.NameTag = nameTag + '.r'
|
system.NameTag = nameTag + '.r'
|
||||||
hr = system.addDistanceV(r)
|
hr = system.addDistanceV(r)
|
||||||
if requireArc or isinstance(r,(list,tuple)):
|
if requireArc or isinstance(r,(list,tuple)):
|
||||||
l = _l(solver,partInfo,subname,shape,True)
|
l = _l(solver,partInfo,subname,shape,True)
|
||||||
system.NameTag = nameTag
|
system.NameTag = nameTag
|
||||||
h = system.addArcOfCircle(w,p,l[1],l[2],group=partInfo.Group)
|
h = system.addArcOfCircle(w,p,l[1],l[2],group=g)
|
||||||
else:
|
else:
|
||||||
system.NameTag = nameTag
|
system.NameTag = nameTag
|
||||||
h = system.addCircle(p,n,hr,group=partInfo.Group)
|
h = system.addCircle(p,n,hr,group=g)
|
||||||
h = (h,hr)
|
h = (h,hr)
|
||||||
system.log('{}: {},{}'.format(key,h,partInfo.Group))
|
system.log('{}: {},{}'.format(key,h,g))
|
||||||
partInfo.EntityMap[key] = h
|
|
||||||
|
partInfo.EntityMap[key] = h
|
||||||
|
|
||||||
return h if retAll else h[0]
|
return h if retAll else h[0]
|
||||||
|
|
||||||
|
def _dc(solver,partInfo,subname,shape,requireArc=False,retAll=False):
|
||||||
|
'return a handle of a draft circle'
|
||||||
|
if not solver:
|
||||||
|
if utils.isDraftCircle(partInfo):
|
||||||
|
return
|
||||||
|
raise RuntimeError('Requires a draft circle')
|
||||||
|
return _c(solver,partInfo,subname,shape,requireArc,retAll)
|
||||||
|
|
||||||
def _a(solver,partInfo,subname,shape,retAll=False):
|
def _a(solver,partInfo,subname,shape,retAll=False):
|
||||||
'return a handle of a transformed arc derived from "shape"'
|
'return a handle of a transformed arc derived from "shape"'
|
||||||
return _c(solver,partInfo,subname,shape,True,retAll)
|
return _c(solver,partInfo,subname,shape,True,retAll)
|
||||||
|
@ -298,31 +376,34 @@ class Constraint(ProxyType):
|
||||||
return mcs.getProxy(obj).prepare(obj,solver)
|
return mcs.getProxy(obj).prepare(obj,solver)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def getFixedParts(mcs,cstrs):
|
def getFixedParts(mcs,solver,cstrs):
|
||||||
firstPart = None
|
firstInfo = None
|
||||||
firstPartName = None
|
|
||||||
found = False
|
found = False
|
||||||
ret = set()
|
ret = set()
|
||||||
for obj in cstrs:
|
for obj in cstrs:
|
||||||
cstr = mcs.getProxy(obj)
|
cstr = mcs.getProxy(obj)
|
||||||
if cstr.hasFixedPart(obj):
|
if cstr.hasFixedPart(obj):
|
||||||
found = True
|
found = True
|
||||||
for info in cstr.getFixedParts(obj):
|
for info in cstr.getFixedParts(solver,obj):
|
||||||
logger.debug('fixed part ' + info.PartName)
|
logger.debug('fixed part ' + info.PartName)
|
||||||
ret.add(info.Part)
|
ret.add(info.Part)
|
||||||
|
|
||||||
if not found and not firstPart:
|
if not found and not firstInfo:
|
||||||
elements = obj.Proxy.getElements()
|
elements = obj.Proxy.getElements()
|
||||||
if elements:
|
if elements:
|
||||||
info = elements[0].Proxy.getInfo()
|
firstInfo = elements[0].Proxy.getInfo()
|
||||||
firstPart = info.Part
|
|
||||||
firstPartName = info.PartName
|
|
||||||
|
|
||||||
if not found:
|
if not found:
|
||||||
if not firstPart:
|
if not firstInfo:
|
||||||
return None
|
return None
|
||||||
logger.debug('lock first part {}'.format(firstPartName))
|
if utils.isDraftObject(firstInfo.Part):
|
||||||
ret.add(firstPart)
|
Locked.lockElement(firstInfo,solver)
|
||||||
|
logger.debug('lock first draft object {}'.format(
|
||||||
|
firstInfo.PartName))
|
||||||
|
solver.getPartInfo(firstInfo,True,solver.group)
|
||||||
|
else:
|
||||||
|
logger.debug('lock first part {}'.format(firstInfo.PartName))
|
||||||
|
ret.add(firstInfo.Part)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -353,20 +434,20 @@ class Constraint(ProxyType):
|
||||||
return cstr.getIcon(obj)
|
return cstr.getIcon(obj)
|
||||||
|
|
||||||
|
|
||||||
def _makeProp(name,tp,doc='',getter=propGet,internal=False):
|
def _makeProp(name,tp,doc='',getter=propGet,internal=False,default=None):
|
||||||
PropertyInfo(Constraint,name,tp,doc,getter=getter,
|
PropertyInfo(Constraint,name,tp,doc,getter=getter,
|
||||||
group='Constraint',internal=internal)
|
group='Constraint',internal=internal,default=default)
|
||||||
|
|
||||||
_makeProp('Distance','App::PropertyDistance',getter=propGetValue)
|
_makeProp('Distance','App::PropertyDistance',getter=propGetValue)
|
||||||
_makeProp('Length','App::PropertyDistance',getter=propGetValue)
|
_makeProp('Length','App::PropertyDistance',getter=propGetValue,default=5.0)
|
||||||
_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('LockAngle','App::PropertyBool')
|
||||||
_makeProp('Ratio','App::PropertyFloat')
|
_makeProp('Ratio','App::PropertyFloat',default=1.0)
|
||||||
_makeProp('Difference','App::PropertyFloat')
|
_makeProp('Difference','App::PropertyFloat')
|
||||||
_makeProp('Diameter','App::PropertyFloat')
|
_makeProp('Diameter','App::PropertyDistance',getter=propGetValue,default=10.0)
|
||||||
_makeProp('Radius','App::PropertyFloat')
|
_makeProp('Radius','App::PropertyDistance',getter=propGetValue,default=5.0)
|
||||||
_makeProp('Supplement','App::PropertyBool',
|
_makeProp('Supplement','App::PropertyBool',
|
||||||
'If True, then the second angle is calculated as 180-angle')
|
'If True, then the second angle is calculated as 180-angle')
|
||||||
_makeProp('AtEnd','App::PropertyBool',
|
_makeProp('AtEnd','App::PropertyBool',
|
||||||
|
@ -428,7 +509,7 @@ class Base(object):
|
||||||
entities = cls.getEntityDef(group,checkCount)
|
entities = cls.getEntityDef(group,checkCount)
|
||||||
for i,e in enumerate(entities):
|
for i,e in enumerate(entities):
|
||||||
o = group[i]
|
o = group[i]
|
||||||
if isinstance(o,utils.PartInfo):
|
if isinstance(o,utils.ElementInfo):
|
||||||
msg = e(None,o.Part,o.Subname,o.Shape)
|
msg = e(None,o.Part,o.Subname,o.Shape)
|
||||||
else:
|
else:
|
||||||
msg = e(None,None,None,o)
|
msg = e(None,None,None,o)
|
||||||
|
@ -496,12 +577,13 @@ class Locked(Base):
|
||||||
_tooltip = 'Add a "{}" constraint to fix part(s)'
|
_tooltip = 'Add a "{}" constraint to fix part(s)'
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def getFixedParts(cls,obj):
|
def getFixedParts(cls,_solver,obj):
|
||||||
ret = []
|
ret = []
|
||||||
for e in obj.Proxy.getElements():
|
for e in obj.Proxy.getElements():
|
||||||
info = e.Proxy.getInfo()
|
info = e.Proxy.getInfo()
|
||||||
if not utils.isVertex(info.Shape) and \
|
if not utils.isVertex(info.Shape) and \
|
||||||
not utils.isLinearEdge(info.Shape):
|
not utils.isLinearEdge(info.Shape) and \
|
||||||
|
not utils.isDraftCircle(info):
|
||||||
ret.append(info)
|
ret.append(info)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
@ -512,11 +594,12 @@ class Locked(Base):
|
||||||
ret = []
|
ret = []
|
||||||
for e in obj.Proxy.getElements():
|
for e in obj.Proxy.getElements():
|
||||||
info = e.Proxy.getInfo()
|
info = e.Proxy.getInfo()
|
||||||
if not utils.isVertex(info.Shape) and \
|
shape = None
|
||||||
not utils.isLinearEdge(info.Shape):
|
if utils.isVertex(info.Shape) or \
|
||||||
ret.append(cls.Info(Part=info.Part,Shape=None))
|
utils.isDraftCircle(info) or \
|
||||||
continue
|
utils.isLinearEdge(info.Shape):
|
||||||
ret.append(cls.Info(Part=info.Part,Shape=info.Shape))
|
shape = info.Shape
|
||||||
|
ret.append(cls.Info(Part=info.Part,Shape=shape))
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -524,67 +607,77 @@ class Locked(Base):
|
||||||
return len(obj.Proxy.getElements())>0
|
return len(obj.Proxy.getElements())>0
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def prepare(cls,obj,solver):
|
def lockElement(cls,info,solver):
|
||||||
ret = []
|
ret = []
|
||||||
system = solver.system
|
system = solver.system
|
||||||
|
|
||||||
for element in obj.Proxy.getElements():
|
isVertex = utils.isVertex(info.Shape)
|
||||||
info = element.Proxy.getInfo()
|
if not isVertex and utils.isDraftCircle(info):
|
||||||
isVertex = utils.isVertex(info.Shape)
|
solver.getPartInfo(info,True,solver.group)
|
||||||
if not isVertex and not utils.isLinearEdge(info.Shape):
|
return ret
|
||||||
continue
|
|
||||||
if solver.isFixedPart(info):
|
|
||||||
logger.warn('redundant locking element "{}" in constraint '
|
|
||||||
'{}'.format(info.Subname,objName(obj)))
|
|
||||||
continue
|
|
||||||
|
|
||||||
partInfo = solver.getPartInfo(info)
|
if not isVertex and not utils.isLinearEdge(info.Shape):
|
||||||
|
return ret
|
||||||
|
|
||||||
fixPoint = False
|
if solver.isFixedPart(info):
|
||||||
if isVertex:
|
logger.warn('redundant locking element "{}" in constraint '
|
||||||
names = [info.Subname]
|
'{}'.format(info.Subname,info.PartName))
|
||||||
elif utils.isDraftObject(info):
|
return ret
|
||||||
fixPoint = True
|
|
||||||
names = utils.edge2VertexIndex(info.Subname)
|
|
||||||
else:
|
|
||||||
names = [info.Subname+'.fp1', info.Subname+'.fp2']
|
|
||||||
|
|
||||||
nameTag = partInfo.PartName + '.' + info.Subname
|
partInfo = solver.getPartInfo(info)
|
||||||
|
|
||||||
for i,v in enumerate(info.Shape.Vertexes):
|
fixPoint = False
|
||||||
surfix = '.fp{}'.format(i)
|
if isVertex:
|
||||||
|
names = [info.Subname]
|
||||||
|
elif utils.isDraftObject(info):
|
||||||
|
fixPoint = True
|
||||||
|
names = utils.edge2VertexIndex(info.Subname)
|
||||||
|
else:
|
||||||
|
names = [info.Subname+'.fp1', info.Subname+'.fp2']
|
||||||
|
|
||||||
|
nameTag = partInfo.PartName + '.' + info.Subname
|
||||||
|
|
||||||
|
for i,v in enumerate(info.Shape.Vertexes):
|
||||||
|
surfix = '.fp{}'.format(i)
|
||||||
|
system.NameTag = nameTag + surfix
|
||||||
|
|
||||||
|
# Create an entity for the transformed constant point
|
||||||
|
e1 = system.addPoint3dV(*info.Placement.multVec(v.Point))
|
||||||
|
|
||||||
|
# Get the entity for the point expressed in variable parameters
|
||||||
|
e2 = _p(solver,partInfo,names[i],v)
|
||||||
|
|
||||||
|
if i==0 or fixPoint:
|
||||||
|
# We are fixing a vertex, or a linear edge. Either way, we
|
||||||
|
# shall add a point coincidence constraint here.
|
||||||
|
e0 = e1
|
||||||
system.NameTag = nameTag + surfix
|
system.NameTag = nameTag + surfix
|
||||||
|
e = system.addPointsCoincident(e1,e2,group=solver.group)
|
||||||
|
system.log('{}: fix point {},{},{}'.format(
|
||||||
|
info.PartName,e,e1,e2))
|
||||||
|
else:
|
||||||
|
# The second point, so we are fixing a linear edge. We can't
|
||||||
|
# add a second coincidence constraint, which will cause
|
||||||
|
# over-constraint. We constraint the second point to be on
|
||||||
|
# the line defined by the linear edge.
|
||||||
|
#
|
||||||
|
# First, get an entity of the transformed constant line
|
||||||
|
system.NameTag = nameTag + '.fl'
|
||||||
|
l = system.addLineSegment(e0,e1)
|
||||||
|
system.NameTag = nameTag
|
||||||
|
# Now, constraint the second variable point to the line
|
||||||
|
e = system.addPointOnLine(e2,l,group=solver.group)
|
||||||
|
system.log('{}: fix line {},{}'.format(info.PartName,e,l))
|
||||||
|
|
||||||
# Create an entity for the transformed constant point
|
ret.append(e)
|
||||||
e1 = system.addPoint3dV(*info.Placement.multVec(v.Point))
|
|
||||||
|
|
||||||
# Get the entity for the point expressed in variable parameters
|
return ret
|
||||||
e2 = _p(solver,partInfo,names[i],v)
|
|
||||||
|
|
||||||
if i==0 or fixPoint:
|
|
||||||
# We are fixing a vertex, or a linear edge. Either way, we
|
|
||||||
# shall add a point coincidence constraint here.
|
|
||||||
e0 = e1
|
|
||||||
system.NameTag = nameTag + surfix
|
|
||||||
e = system.addPointsCoincident(e1,e2,group=solver.group)
|
|
||||||
system.log('{}: fix point {},{},{}'.format(
|
|
||||||
cstrName(obj),e,e1,e2))
|
|
||||||
else:
|
|
||||||
# The second point, so we are fixing a linear edge. We can't
|
|
||||||
# add a second coincidence constraint, which will cause
|
|
||||||
# over-constraint. We constraint the second point to be on
|
|
||||||
# the line defined by the linear edge.
|
|
||||||
#
|
|
||||||
# First, get an entity of the transformed constant line
|
|
||||||
system.NameTag = nameTag + '.fl'
|
|
||||||
l = system.addLineSegment(e0,e1)
|
|
||||||
system.NameTag = nameTag
|
|
||||||
# Now, constraint the second variable point to the line
|
|
||||||
e = system.addPointOnLine(e2,l,group=solver.group)
|
|
||||||
system.log('{}: fix line {},{}'.format(cstrName(obj),e,l))
|
|
||||||
|
|
||||||
ret.append(e)
|
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def prepare(cls,obj,solver):
|
||||||
|
ret = []
|
||||||
|
for element in obj.Proxy.getElements():
|
||||||
|
ret += cls.lockElement(element.Proxy.getInfo(),solver)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -604,7 +697,7 @@ class BaseMulti(Base):
|
||||||
raise RuntimeError('Constraint "{}" requires at least two '
|
raise RuntimeError('Constraint "{}" requires at least two '
|
||||||
'elements'.format(cls.getName()))
|
'elements'.format(cls.getName()))
|
||||||
for o in group:
|
for o in group:
|
||||||
if isinstance(o,utils.PartInfo):
|
if isinstance(o,utils.ElementInfo):
|
||||||
msg = cls._entityDef[0](None,o.Part,o.Subname,o.Shape)
|
msg = cls._entityDef[0](None,o.Part,o.Subname,o.Shape)
|
||||||
else:
|
else:
|
||||||
msg = cls._entityDef[0](None,None,None,o)
|
msg = cls._entityDef[0](None,None,None,o)
|
||||||
|
@ -942,9 +1035,9 @@ class BaseDraftWire(BaseSketch):
|
||||||
'from a non-closed-or-subdivided Draft.Wire'.format(
|
'from a non-closed-or-subdivided Draft.Wire'.format(
|
||||||
cls.getName()))
|
cls.getName()))
|
||||||
|
|
||||||
class LineLength(BaseDraftWire):
|
class LineLength(BaseSketch):
|
||||||
_id = 34
|
_id = 34
|
||||||
_entityDef = (_l,)
|
_entityDef = (_dl,)
|
||||||
_workplane = True
|
_workplane = True
|
||||||
_props = ["Length"]
|
_props = ["Length"]
|
||||||
_iconName = 'Assembly_ConstraintLineLength.svg'
|
_iconName = 'Assembly_ConstraintLineLength.svg'
|
||||||
|
@ -1030,23 +1123,11 @@ class MidPoint(BaseSketch):
|
||||||
|
|
||||||
class Diameter(BaseSketch):
|
class Diameter(BaseSketch):
|
||||||
_id = 25
|
_id = 25
|
||||||
_entityDef = (_c,)
|
_entityDef = (_dc,)
|
||||||
_prop = ("Diameter",)
|
_props = ("Diameter",)
|
||||||
_iconName = 'Assembly_ConstraintDiameter.svg'
|
_iconName = 'Assembly_ConstraintDiameter.svg'
|
||||||
_tooltip='Add a "{}" to constrain the diameter of a circle/arc'
|
_tooltip='Add a "{}" to constrain the diameter of a circle/arc'
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def check(cls,group,checkCount=False):
|
|
||||||
super(Diameter,cls).check(group,checkCount)
|
|
||||||
if not checkCount:
|
|
||||||
return
|
|
||||||
if len(group):
|
|
||||||
o = group[0]
|
|
||||||
if utils.isDraftCircle(o):
|
|
||||||
return
|
|
||||||
raise RuntimeError('Constraint "{}" requires a '
|
|
||||||
'Draft.Circle'.format(cls.getName()))
|
|
||||||
|
|
||||||
|
|
||||||
class EqualRadius(BaseSketch):
|
class EqualRadius(BaseSketch):
|
||||||
_id = 33
|
_id = 33
|
||||||
|
|
6
proxy.py
6
proxy.py
|
@ -11,7 +11,8 @@ class PropertyInfo(object):
|
||||||
'For holding information to create dynamic properties'
|
'For holding information to create dynamic properties'
|
||||||
|
|
||||||
def __init__(self,host,name,tp,doc='', enum=None,
|
def __init__(self,host,name,tp,doc='', enum=None,
|
||||||
getter=propGet,group='Base',internal=False,duplicate=False):
|
getter=propGet,group='Base',internal=False,
|
||||||
|
duplicate=False,default=None):
|
||||||
self.Name = name
|
self.Name = name
|
||||||
self.Type = tp
|
self.Type = tp
|
||||||
self.Group = group
|
self.Group = group
|
||||||
|
@ -19,6 +20,7 @@ class PropertyInfo(object):
|
||||||
self.Enum = enum
|
self.Enum = enum
|
||||||
self.get = getter.__get__(self,self.__class__)
|
self.get = getter.__get__(self,self.__class__)
|
||||||
self.Internal = internal
|
self.Internal = internal
|
||||||
|
self.Default = default
|
||||||
self.Key = host.addPropertyInfo(self,duplicate)
|
self.Key = host.addPropertyInfo(self,duplicate)
|
||||||
|
|
||||||
class ProxyType(type):
|
class ProxyType(type):
|
||||||
|
@ -106,6 +108,8 @@ class ProxyType(type):
|
||||||
obj.addProperty(prop.Type,prop.Name,prop.Group,prop.Doc)
|
obj.addProperty(prop.Type,prop.Name,prop.Group,prop.Doc)
|
||||||
if prop.Enum:
|
if prop.Enum:
|
||||||
setattr(obj,prop.Name,prop.Enum)
|
setattr(obj,prop.Name,prop.Enum)
|
||||||
|
if prop.Default is not None:
|
||||||
|
setattr(obj,prop.Name,prop.Default)
|
||||||
|
|
||||||
setattr(obj.Proxy,mcs._proxyName,cls(obj))
|
setattr(obj.Proxy,mcs._proxyName,cls(obj))
|
||||||
obj.ViewObject.signalChangeIcon()
|
obj.ViewObject.signalChangeIcon()
|
||||||
|
|
83
solver.py
83
solver.py
|
@ -1,4 +1,4 @@
|
||||||
import random
|
import random, math
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
import FreeCAD, FreeCADGui
|
import FreeCAD, FreeCADGui
|
||||||
from .assembly import Assembly, isTypeOf, setPlacement
|
from .assembly import Assembly, isTypeOf, setPlacement
|
||||||
|
@ -35,9 +35,12 @@ class Solver(object):
|
||||||
|
|
||||||
self.system.GroupHandle = self._fixedGroup
|
self.system.GroupHandle = self._fixedGroup
|
||||||
|
|
||||||
self._fixedParts = Constraint.getFixedParts(cstrs)
|
# convenience constant of zero
|
||||||
|
self.v0 = self.system.addParamV(0,group=self._fixedGroup)
|
||||||
|
|
||||||
|
self._fixedParts = Constraint.getFixedParts(self,cstrs)
|
||||||
if self._fixedParts is None:
|
if self._fixedParts is None:
|
||||||
logger.warn('no fixed part found')
|
self.system.log('no fixed part found')
|
||||||
return
|
return
|
||||||
|
|
||||||
for cstr in cstrs:
|
for cstr in cstrs:
|
||||||
|
@ -96,21 +99,21 @@ class Solver(object):
|
||||||
if part in self._fixedParts:
|
if part in self._fixedParts:
|
||||||
continue
|
continue
|
||||||
if utils.isDraftWire(part):
|
if utils.isDraftWire(part):
|
||||||
pointChanged = False
|
changed = False
|
||||||
points = part.Points
|
points = part.Points
|
||||||
for subname,h in partInfo.EntityMap.items():
|
for key,h in partInfo.EntityMap.items():
|
||||||
if not subname.endswith('.p') or\
|
if not key.endswith('.p') or\
|
||||||
not subname.startswith('Vertex'):
|
not key.startswith('Vertex'):
|
||||||
continue
|
continue
|
||||||
v = [ self.system.getParam(p).val for p in h[1] ]
|
v = [ self.system.getParam(p).val for p in h[1] ]
|
||||||
v = FreeCAD.Vector(*v)
|
v = FreeCAD.Vector(*v)
|
||||||
v = partInfo.Placement.inverse().multVec(v)
|
v = partInfo.Placement.inverse().multVec(v)
|
||||||
idx = utils.draftWireVertex2PointIndex(part,subname[:-2])
|
idx = utils.draftWireVertex2PointIndex(part,key[:-2])
|
||||||
if utils.isSamePos(points[idx],v):
|
if utils.isSamePos(points[idx],v):
|
||||||
self.system.log('not moving {} point {}'.format(
|
self.system.log('not moving {} point {}'.format(
|
||||||
partInfo.PartName,idx))
|
partInfo.PartName,idx))
|
||||||
else:
|
else:
|
||||||
pointChanged = True
|
changed = True
|
||||||
self.system.log('moving {} point{} from {}->{}'.format(
|
self.system.log('moving {} point{} from {}->{}'.format(
|
||||||
partInfo.PartName,idx,points[idx],v))
|
partInfo.PartName,idx,points[idx],v))
|
||||||
if rollback is not None:
|
if rollback is not None:
|
||||||
|
@ -118,7 +121,7 @@ class Solver(object):
|
||||||
part,
|
part,
|
||||||
(idx, points[idx])))
|
(idx, points[idx])))
|
||||||
points[idx] = v
|
points[idx] = v
|
||||||
if pointChanged:
|
if changed:
|
||||||
touched = True
|
touched = True
|
||||||
part.Points = points
|
part.Points = points
|
||||||
else:
|
else:
|
||||||
|
@ -132,11 +135,43 @@ class Solver(object):
|
||||||
touched = True
|
touched = True
|
||||||
self.system.log('moving {} {} {} {}'.format(
|
self.system.log('moving {} {} {} {}'.format(
|
||||||
partInfo.PartName,partInfo.Params,params,pla))
|
partInfo.PartName,partInfo.Params,params,pla))
|
||||||
setPlacement(part,pla)
|
|
||||||
if rollback is not None:
|
if rollback is not None:
|
||||||
rollback.append((partInfo.PartName,
|
rollback.append((partInfo.PartName,
|
||||||
part,
|
part,
|
||||||
partInfo.Placement.copy()))
|
partInfo.Placement.copy()))
|
||||||
|
setPlacement(part,pla)
|
||||||
|
|
||||||
|
if utils.isDraftCircle(part):
|
||||||
|
changed = False
|
||||||
|
h = partInfo.EntityMap.get('Edge1.c',None)
|
||||||
|
if not h:
|
||||||
|
continue
|
||||||
|
v0 = (part.Radius.Value,
|
||||||
|
part.FirstAngle.Value,
|
||||||
|
part.LastAngle.Value)
|
||||||
|
if part.FirstAngle == part.LastAngle:
|
||||||
|
v = (self.system.getParam(h[1]).val,v0[1],v0[2])
|
||||||
|
else:
|
||||||
|
params = [self.system.getParam(p).val for p in h[3]]
|
||||||
|
p0 = FreeCAD.Vector(1,0,0)
|
||||||
|
p1 = FreeCAD.Vector(params[0],params[1],0)
|
||||||
|
p2 = FreeCAD.Vector(params[2],params[3],0)
|
||||||
|
v = (p1.Length,
|
||||||
|
math.degrees(p0.getAngle(p1)),
|
||||||
|
math.degrees(p0.getAngle(p2)))
|
||||||
|
|
||||||
|
if utils.isSameValue(v0,v):
|
||||||
|
self.system.log('not change draft circle {}'.format(
|
||||||
|
partInfo.PartName))
|
||||||
|
else:
|
||||||
|
touched = True
|
||||||
|
self.system.log('change draft circle {} {}->{}'.format(
|
||||||
|
partInfo.PartName,v0,v))
|
||||||
|
if rollback is not None:
|
||||||
|
rollback.append((partInfo.PartName, part, v0))
|
||||||
|
part.Radius = v[0]
|
||||||
|
part.FirstAngle = v[1]
|
||||||
|
part.LastAngle = v[2]
|
||||||
|
|
||||||
if recompute and touched:
|
if recompute and touched:
|
||||||
assembly.recompute(True)
|
assembly.recompute(True)
|
||||||
|
@ -144,12 +179,12 @@ class Solver(object):
|
||||||
def isFixedPart(self,info):
|
def isFixedPart(self,info):
|
||||||
return info.Part in self._fixedParts
|
return info.Part in self._fixedParts
|
||||||
|
|
||||||
def getPartInfo(self,info):
|
def getPartInfo(self,info,fixed=False,group=0):
|
||||||
partInfo = self._partMap.get(info.Part,None)
|
partInfo = self._partMap.get(info.Part,None)
|
||||||
if partInfo:
|
if partInfo:
|
||||||
return partInfo
|
return partInfo
|
||||||
|
|
||||||
if info.Part in self._fixedParts:
|
if fixed or info.Part in self._fixedParts:
|
||||||
g = self._fixedGroup
|
g = self._fixedGroup
|
||||||
else:
|
else:
|
||||||
g = self.group
|
g = self.group
|
||||||
|
@ -177,9 +212,9 @@ class Solver(object):
|
||||||
Params = params,
|
Params = params,
|
||||||
Workplane = h,
|
Workplane = h,
|
||||||
EntityMap = {},
|
EntityMap = {},
|
||||||
Group = g)
|
Group = group if group else g)
|
||||||
|
|
||||||
self.system.log('{}'.format(partInfo))
|
self.system.log('{}, {}'.format(partInfo,g))
|
||||||
|
|
||||||
self._partMap[info.Part] = partInfo
|
self._partMap[info.Part] = partInfo
|
||||||
return partInfo
|
return partInfo
|
||||||
|
@ -245,13 +280,19 @@ def _solve(objs=None,recursive=None,reportFailed=True,
|
||||||
System.touch(assembly,False)
|
System.touch(assembly,False)
|
||||||
except Exception:
|
except Exception:
|
||||||
if rollback is not None:
|
if rollback is not None:
|
||||||
for name,part,pla in reversed(rollback):
|
for name,part,v in reversed(rollback):
|
||||||
logger.debug('roll back {} to {}'.format(name,pla))
|
logger.debug('roll back {} to {}'.format(name,v))
|
||||||
if utils.isDraftWire(part):
|
if isinstance(v,FreeCAD.Placement):
|
||||||
idx,pt = pla
|
setPlacement(part,v)
|
||||||
|
elif utils.isDraftWire(part):
|
||||||
|
idx,pt = v
|
||||||
part.Points[idx] = pt
|
part.Points[idx] = pt
|
||||||
else:
|
elif utils.isDraftWire(part):
|
||||||
setPlacement(part,pla)
|
r,a1,a2 = v
|
||||||
|
part.Radius = r
|
||||||
|
part.FirstAngle = a1
|
||||||
|
part.LastAngle = a2
|
||||||
|
|
||||||
raise
|
raise
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
23
utils.py
23
utils.py
|
@ -126,11 +126,11 @@ def getElementShape(obj,tp):
|
||||||
if len(f)==1:
|
if len(f)==1:
|
||||||
return f[0]
|
return f[0]
|
||||||
|
|
||||||
PartInfo = namedtuple('AsmPartInfo', ('Parent','SubnameRef','Part',
|
ElementInfo = namedtuple('AsmElementInfo', ('Parent','SubnameRef','Part',
|
||||||
'PartName','Placement','Object','Subname','Shape'))
|
'PartName','Placement','Object','Subname','Shape'))
|
||||||
|
|
||||||
def isDraftWire(obj):
|
def isDraftWire(obj):
|
||||||
if isinstance(obj,PartInfo):
|
if isinstance(obj,ElementInfo):
|
||||||
obj = obj.Part
|
obj = obj.Part
|
||||||
proxy = getattr(obj,'Proxy',None)
|
proxy = getattr(obj,'Proxy',None)
|
||||||
return isinstance(proxy,Draft._Wire) and \
|
return isinstance(proxy,Draft._Wire) and \
|
||||||
|
@ -138,7 +138,7 @@ def isDraftWire(obj):
|
||||||
not obj.Subdivisions
|
not obj.Subdivisions
|
||||||
|
|
||||||
def isDraftCircle(obj):
|
def isDraftCircle(obj):
|
||||||
if isinstance(obj,PartInfo):
|
if isinstance(obj,ElementInfo):
|
||||||
obj = obj.Part
|
obj = obj.Part
|
||||||
proxy = getattr(obj,'Proxy',None)
|
proxy = getattr(obj,'Proxy',None)
|
||||||
return isinstance(proxy,Draft._Circle)
|
return isinstance(proxy,Draft._Circle)
|
||||||
|
@ -147,7 +147,7 @@ def isDraftObject(obj):
|
||||||
return isDraftWire(obj) or isDraftCircle(obj)
|
return isDraftWire(obj) or isDraftCircle(obj)
|
||||||
|
|
||||||
def isElement(obj):
|
def isElement(obj):
|
||||||
if isinstance(obj,PartInfo):
|
if isinstance(obj,ElementInfo):
|
||||||
shape = obj.Shape
|
shape = obj.Shape
|
||||||
elif not isinstance(obj,(tuple,list)):
|
elif not isinstance(obj,(tuple,list)):
|
||||||
shape = obj
|
shape = obj
|
||||||
|
@ -469,12 +469,25 @@ def fit_rotation_axis_to_surface1( surface, n_u=3, n_v=3 ):
|
||||||
|
|
||||||
_tol = 10e-7
|
_tol = 10e-7
|
||||||
|
|
||||||
|
def isSameValue(v1,v2):
|
||||||
|
if isinstance(v1,(tuple,list)):
|
||||||
|
assert(len(v1)==len(v2))
|
||||||
|
vs = zip(v1,v2)
|
||||||
|
else:
|
||||||
|
vs = (v1,v2),
|
||||||
|
|
||||||
|
for v1,v2 in vs:
|
||||||
|
v = v1-v2
|
||||||
|
if v>=_tol or v<=-_tol:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
def isSamePos(p1,p2):
|
def isSamePos(p1,p2):
|
||||||
return p1.distanceToPoint(p2) < _tol
|
return p1.distanceToPoint(p2) < _tol
|
||||||
|
|
||||||
def isSamePlacement(pla1,pla2):
|
def isSamePlacement(pla1,pla2):
|
||||||
return isSamePos(pla1.Base,pla2.Base) and \
|
return isSamePos(pla1.Base,pla2.Base) and \
|
||||||
np.linalg.norm(np.array(pla1.Rotation.Q)-np.array(pla2.Rotation.Q))<_tol
|
isSameValue(pla1.Rotation.Q,pla2.Rotation.Q)
|
||||||
|
|
||||||
def getElementIndex(name,check=None):
|
def getElementIndex(name,check=None):
|
||||||
'Return element index, 0 if invalid'
|
'Return element index, 0 if invalid'
|
||||||
|
|
Loading…
Reference in New Issue
Block a user