improvements in exportDRAWEXE
fix Draft._clone output
export Shape2DViews
export Part::MultiFuse with single boolean operation like done in c2ce8f5eba
make DRAWEXE ouput more readable
* omit unessary parameters of spheres, cylinders, cones and tori
* denormalize the rotation axis in placements
* use the extension .tcl for the output
This commit is contained in:
parent
16c1dbd25d
commit
1846087723
|
@ -26,5 +26,5 @@
|
|||
#***************************************************************************/
|
||||
|
||||
import FreeCAD
|
||||
FreeCAD.addExportType("DRAWEXE source (*.draw)","exportDRAWEXE")
|
||||
FreeCAD.addExportType("DRAWEXE script (*.tcl)","exportDRAWEXE")
|
||||
|
||||
|
|
|
@ -32,6 +32,15 @@ if open.__module__ == '__builtin__':
|
|||
# Part:: Wedge, Helix, Spiral, Elipsoid
|
||||
# Draft: Rectangle, BSpline, BezCurve
|
||||
|
||||
def quaternionToString(rot):
|
||||
def shorthexfloat(f):
|
||||
s=f.hex()
|
||||
mantisse, exponent = f.hex().split('p',1)
|
||||
return '%sp%s' % (mantisse.rstrip('0'),exponent)
|
||||
x,y,z,w=rot.Q
|
||||
return 'q=%s+%s*i+%s*j+%s*k' % (shorthexfloat(w),shorthexfloat(x),
|
||||
shorthexfloat(y),shorthexfloat(z))
|
||||
|
||||
def f2s(n,angle=False,axis=False):
|
||||
'''convert to numerical value to string
|
||||
try to remove no significant digits, by guessing a former rounding
|
||||
|
@ -51,6 +60,33 @@ def f2s(n,angle=False,axis=False):
|
|||
if float(s) == n:
|
||||
return s
|
||||
|
||||
def ax2_xdir(normal):
|
||||
#adaped from gp_Ax2.ccc (c) OpenCascade SAS LGPL 2.1+
|
||||
|
||||
xa=abs(normal.x)
|
||||
ya=abs(normal.y)
|
||||
za=abs(normal.z)
|
||||
if ya <= xa and ya <= za:
|
||||
if xa > za:
|
||||
return FreeCAD.Vector(-normal.z,0, normal.x)
|
||||
else:
|
||||
return FreeCAD.Vector( normal.z,0,-normal.x)
|
||||
elif xa <= ya and xa <= za:
|
||||
if ya > za:
|
||||
return FreeCAD.Vector(0,-normal.z, normal.y)
|
||||
else:
|
||||
return FreeCAD.Vector(0, normal.z,-normal.y)
|
||||
else:
|
||||
if xa > ya:
|
||||
return FreeCAD.Vector(-normal.y, normal.x,0)
|
||||
else:
|
||||
return FreeCAD.Vector( normal.y,-normal.x,0)
|
||||
|
||||
def occversiontuple():
|
||||
import FreeCAD,Part
|
||||
occmajs,occmins,occfixs = FreeCAD.ConfigGet('OCC_VERSION').split('.')[:3]
|
||||
return (int(occmajs),int(occmins),int(occfixs))
|
||||
|
||||
def polygonstr(r,pcount):
|
||||
import math
|
||||
v=FreeCAD.Vector(r,0,0)
|
||||
|
@ -80,10 +116,22 @@ def placement2draw(placement,name='object'):
|
|||
drawcommand=''
|
||||
if not placement.Rotation.isNull():
|
||||
import math
|
||||
dx,dy,dz=placement.Rotation.Axis
|
||||
#dx,dy,dz=placement.Rotation.Axis
|
||||
ax=placement.Rotation.Axis
|
||||
import itertools
|
||||
# denormalize rotation axis
|
||||
for t in itertools.product((0,1,-1),repeat=3):
|
||||
if t != (0,0,0):
|
||||
if (ax-FreeCAD.Vector(*t).normalize()).Length < 1e-15:
|
||||
dx,dy,dz = t
|
||||
break
|
||||
else:
|
||||
dx,dy,dz=placement.Rotation.Axis
|
||||
#drawcommand += "# %s\n" %quaternionToString(placement.Rotation)
|
||||
an=math.degrees(placement.Rotation.Angle)
|
||||
drawcommand += "trotate %s 0 0 0 %s %s %s %s\n" % \
|
||||
(name,f2s(dx,axis=True),f2s(dy,axis=True),f2s(dz,axis=True),\
|
||||
drawcommand += "trotate %s 0 0 0 %s %s %s %s\n" % (name,\
|
||||
f2s(dx),f2s(dy),f2s(dz),\
|
||||
# f2s(dx,axis=True),f2s(dy,axis=True),f2s(dz,axis=True),\
|
||||
f2s(an,angle=True))
|
||||
if placement.Base.Length > 1e-8:
|
||||
x,y,z=placement.Base
|
||||
|
@ -130,7 +178,8 @@ def isDraftFeature(ob):
|
|||
return True
|
||||
|
||||
def isDraftClone(ob):
|
||||
if ob.isDerivedFrom('Part::FeaturePython') and \
|
||||
if (ob.isDerivedFrom('Part::FeaturePython') or \
|
||||
ob.isDerivedFrom('Part::Part2DObjectPython')) and \
|
||||
hasattr(ob.Proxy,'__module__') and \
|
||||
ob.Proxy.__module__ == 'Draft':
|
||||
import Draft
|
||||
|
@ -170,6 +219,10 @@ def isDraftWire(ob):
|
|||
ob.ChamferSize.Value == 0.0:
|
||||
return True
|
||||
|
||||
def isDraftShape2DView(ob):
|
||||
if isDraftFeature(ob):
|
||||
import Draft
|
||||
return isinstance(ob.Proxy,Draft._Shape2DView)
|
||||
|
||||
def isOpenSCADFeature(ob):
|
||||
if ob.isDerivedFrom('Part::FeaturePython') and \
|
||||
|
@ -211,6 +264,7 @@ class Drawexporter(object):
|
|||
|
||||
def write_header(self):
|
||||
import FreeCAD
|
||||
#self.csg.write('#!/usr/bin/env DRAWEXE\n')
|
||||
self.csg.write('#generated by FreeCAD %s\n' % \
|
||||
'.'.join(FreeCAD.Version()[0:3]))
|
||||
self.csg.write('pload MODELING\n')
|
||||
|
@ -352,8 +406,12 @@ class Drawexporter(object):
|
|||
if checksupported: return True # The object is supported
|
||||
d1.update({'radius':f2s(ob.Radius),'angle1':f2s(ob.Angle1),\
|
||||
'angle2':f2s(ob.Angle2),'angle3':f2s(ob.Angle3)})
|
||||
self.csg.write('psphere %(name)s %(radius)s %(angle1)s %(angle2)s '\
|
||||
'%(angle3)s\n'%d1)
|
||||
if ob.Angle1.Value == -90 and ob.Angle2.Value == 90 and \
|
||||
ob.Angle3.Value == 360:
|
||||
self.csg.write('psphere %(name)s %(radius)s\n'%d1)
|
||||
else:
|
||||
self.csg.write('psphere %(name)s %(radius)s %(angle1)s '
|
||||
'%(angle2)s %(angle3)s\n'%d1)
|
||||
elif ob.TypeId == "Part::Box" :
|
||||
if checksupported: return True # The object is supported
|
||||
d1.update({'dx':f2s(ob.Length),'dy':f2s(ob.Width),'dz':f2s(ob.Height)})
|
||||
|
@ -362,19 +420,32 @@ class Drawexporter(object):
|
|||
if checksupported: return True # The object is supported
|
||||
d1.update({'radius':f2s(ob.Radius),'height':f2s(ob.Height),\
|
||||
'angle':f2s(ob.Angle)})
|
||||
self.csg.write('pcylinder %(name)s %(radius)s %(height)s %(angle)s\n'%d1)
|
||||
if ob.Angle.Value == 360:
|
||||
self.csg.write('pcylinder %(name)s %(radius)s %(height)s\n'%d1)
|
||||
else:
|
||||
self.csg.write('pcylinder %(name)s %(radius)s %(height)s '\
|
||||
'%(angle)s\n'%d1)
|
||||
elif ob.TypeId == "Part::Cone" :
|
||||
if checksupported: return True # The object is supported
|
||||
d1.update({'radius1':f2s(ob.Radius1),'radius2':f2s(ob.Radius2),\
|
||||
'height':f2s(ob.Height),'angle':f2s(ob.Angle)})
|
||||
self.csg.write('pcone %(name)s %(radius1)s %(radius2)s %(height)s %(angle)s\n'%d1)
|
||||
if ob.Angle.Value == 360:
|
||||
self.csg.write('pcone %(name)s %(radius1)s %(radius2)s '\
|
||||
'%(height)s\n'%d1)
|
||||
else:
|
||||
self.csg.write('pcone %(name)s %(radius1)s %(radius2)s '\
|
||||
'%(height)s %(angle)s\n'%d1)
|
||||
elif ob.TypeId == "Part::Torus" :
|
||||
if checksupported: return True # The object is supported
|
||||
d1.update({'radius1':f2s(ob.Radius1),'radius2':f2s(ob.Radius2),\
|
||||
'angle1': f2s(ob.Angle1),'angle2':f2s(ob.Angle2),\
|
||||
'angle3': f2s(ob.Angle3)})
|
||||
self.csg.write('ptorus %(name)s %(radius1)s %(radius2)s %(angle1)s '\
|
||||
'%(angle2)s %(angle3)s\n' % d1)
|
||||
if ob.Angle1.Value == -180 and ob.Angle2.Value == 180 and \
|
||||
ob.Angle3.Value == 360:
|
||||
self.csg.write('ptorus %(name)s %(radius1)s %(radius2)s\n'%d1)
|
||||
else:
|
||||
self.csg.write('ptorus %(name)s %(radius1)s %(radius2)s '\
|
||||
'%(angle1)s %(angle2)s %(angle3)s\n' % d1)
|
||||
elif ob.TypeId == "Part::Mirroring" :
|
||||
if checksupported: return True # The object is supported
|
||||
self.process_object(ob.Source)
|
||||
|
@ -411,6 +482,17 @@ class Drawexporter(object):
|
|||
return self.process_object(ob.Shapes[0],True)
|
||||
self.process_object(ob.Shapes[0],)
|
||||
self.csg.write('tcopy %s %s\n'%(ob.Shapes[0].Name,d1['name']))
|
||||
elif ob.TypeId == "Part::MultiFuse" and \
|
||||
occversiontuple() >= (6,8,1):
|
||||
if checksupported: return True # The object is supported
|
||||
for subobj in ob.Shapes:
|
||||
self.process_object(subobj)
|
||||
self.csg.write("bclearobjects\nbcleartools\n")
|
||||
self.csg.write("baddobjects %s\n" % ob.Shapes[0].Name)
|
||||
self.csg.write("baddtools %s\n" % " ".join(subobj.Name for \
|
||||
subobj in ob.Shapes[1:]))
|
||||
self.csg.write("bfillds\n")
|
||||
self.csg.write("bbop %s 1\n" % ob.Name) #BOPAlgo_FUSE == 1
|
||||
else:
|
||||
if checksupported: return True # The object is supported
|
||||
topname = ob.Name
|
||||
|
@ -646,7 +728,7 @@ class Drawexporter(object):
|
|||
self.csg.write('wire %s %s\n' %(wirename,polyname))
|
||||
elif isDraftClone(ob):
|
||||
if checksupported: return True # The object is supported
|
||||
x,y,z=ob.Scale.x
|
||||
x,y,z=ob.Scale
|
||||
if x == y == z: #uniform scaling
|
||||
d1['scale']=f2s(x)
|
||||
else:
|
||||
|
@ -677,7 +759,29 @@ class Drawexporter(object):
|
|||
self.csg.write('deform %(newname)s %(basename)s'\
|
||||
' %(cx)s %(cy)s %(cz)s\n' % d1)
|
||||
self.csg.write('compound %s %s\n' % (' '.join(newnames),ob.Name))
|
||||
|
||||
elif isDraftShape2DView(ob) and not ob.Tessellation and \
|
||||
ob.ProjectionMode == "Solid" and ob.Base is not None and \
|
||||
hasattr(ob.Base,'Shape'):
|
||||
# not supported are groups, Arch/Sections and individual faces mode
|
||||
if checksupported: return True # The object is supported
|
||||
self.process_object(ob.Base)
|
||||
v=ob.Projection
|
||||
x=ax2_xdir(v)
|
||||
self.csg.write('hprj %s_proj 0 0 0 %s %s %s %s %s %s\n' % \
|
||||
( ob.Name,f2s(v.x),f2s(v.y),f2s(v.z)\
|
||||
, f2s(x.x),f2s(x.y),f2s(x.z)))
|
||||
self.csg.write('houtl %s_outl %s\n' % (ob.Name, ob.Base.Name))
|
||||
self.csg.write('hfill %s_outl %s_proj 0\n' %(ob.Name,ob.Name)) #0?
|
||||
self.csg.write('hload %s_outl\n' % (ob.Name))
|
||||
self.csg.write('hsetprj %s_proj\n' % (ob.Name))
|
||||
self.csg.write('hupdate\n')
|
||||
self.csg.write('hhide\n')
|
||||
self.csg.write('unset -nocomplain vl v1l vnl vol vil hl h1l hnl hol hil\n')
|
||||
self.csg.write('hres2d\n')
|
||||
if ob.HiddenLines:
|
||||
self.csg.write('compound vl v1l vnl vol vil hl h1l hnl hol hil %s\n' % ob.Name)
|
||||
else:
|
||||
self.csg.write('compound vl v1l vnl vol vil %s\n' % ob.Name)
|
||||
#elif ob.isDerivedFrom('Part::FeaturePython') and \
|
||||
# hasattr(ob.Proxy,'__module__'):
|
||||
# pass
|
||||
|
@ -744,3 +848,6 @@ def export(exportList,filename):
|
|||
"called when freecad exports a file"
|
||||
with Drawexporter(filename) as exporter:
|
||||
exporter.export_objects(exportList)
|
||||
|
||||
if 'tcl' not in FreeCAD.getExportType():
|
||||
FreeCAD.addExportType("DRAWEXE script (*.tcl)","exportDRAWEXE")
|
||||
|
|
Loading…
Reference in New Issue
Block a user