DXF-Exporter script - initial commit
authorRemigiusz Fiedler <migius@gmx.net>
Mon, 29 Sep 2008 14:03:15 +0000 (14:03 +0000)
committerRemigiusz Fiedler <migius@gmx.net>
Mon, 29 Sep 2008 14:03:15 +0000 (14:03 +0000)
 Built on "Stanis Python Library for generating dxf drawing":
History:
v1.25 - 2008.09.28 by migius
 - modif FACE class for r12
 - add mesh-polygon -> Bezier-curve converter (Yorik's code)
 - add support for curves ->POLYLINEs
 - add "3d-View to Flat" - geometry projection to XY-plane
v1.24 - 2008.09.27 by migius
 - add start UI with preferences
 - modif POLYLINE class for r12
 - changing output format from r9 to r12(AC1009)
v1.23 - 2008.09.26 by migius
 - add finish message-box
v1.22 - 2008.09.26 by migius
 - add support for curves ->LINEs
 - add support for mesh-edges ->LINEs
v1.21 - 2008.06.04 by migius
 - initial adaptation for Blender
v1.1 (20/6/2005) by www.stani.be/python/sdxf
 - Python library to generate dxf drawings

release/scripts/export_dxf.py [new file with mode: 0644]

diff --git a/release/scripts/export_dxf.py b/release/scripts/export_dxf.py
new file mode 100644 (file)
index 0000000..6658615
--- /dev/null
@@ -0,0 +1,860 @@
+#!BPY
+
+"""
+ Name: 'Autodesk DXF (.dxf)'
+ Blender: 247
+ Group: 'Export'
+ Tooltip: 'Export geometry to DXF-r12 (Drawing eXchange Format).'
+"""
+
+__version__ = "v1.25beta - 2008.09.28"
+__author__  = "Stani & migius(Remigiusz Fiedler)"
+__license__ = "GPL"
+__url__         = "http://wiki.blender.org/index.php/Scripts/Manual/Export/autodesk_dxf"
+__bpydoc__ ="""The script exports Blender geometry to DXF format r12 version.
+
+Copyright %s
+Version %s
+License %s
+Homepage %s
+
+See the homepage for documentation.
+url:
+""" % (__author__,__version__,__license__,__url__)
+
+"""
+IDEAs:
+ - correct normals for POLYLINE-POLYFACE objects via correct point-order
+ - HPGL output for 2d and flattened3d content
+               
+TODO:
+ - support hierarchies: groups, instances, parented structures
+ - support 210-code (3d orientation vector)
+ - presets for architectural scales
+
+History
+v1.25 - 2008.09.28 by migius
+ - modif FACE class for r12
+ - add mesh-polygon -> Bezier-curve converter (Yorik's code)
+ - add support for curves ->POLYLINEs
+ - add "3d-View to Flat" - geometry projection to XY-plane
+v1.24 - 2008.09.27 by migius
+ - add start UI with preferences
+ - modif POLYLINE class for r12
+ - changing output format from r9 to r12(AC1009)
+v1.23 - 2008.09.26 by migius
+ - add finish message-box
+v1.22 - 2008.09.26 by migius
+ - add support for curves ->LINEs
+ - add support for mesh-edges ->LINEs
+v1.21 - 2008.06.04 by migius
+ - initial adaptation for Blender
+v1.1 (20/6/2005) by www.stani.be/python/sdxf
+ - Python library to generate dxf drawings
+______________________________________________________________
+"""
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#
+# ***** END GPL LICENCE BLOCK *****
+
+
+import Blender
+from Blender import Mathutils, Window, Scene, sys, Draw
+import BPyMessages
+
+try:
+       import copy
+       #from struct import pack
+except:
+       copy = None
+
+####1) Private (only for developpers)
+_HEADER_POINTS=['insbase','extmin','extmax']
+
+#---helper functions-----------------------------------
+def _point(x,index=0):
+       """Convert tuple to a dxf point"""
+       #print '_point=', x #-------------
+       return '\n'.join(['%s\n%s'%((i+1)*10+index,x[i]) for i in range(len(x))])
+
+def _points(plist):
+       """Convert a list of tuples to dxf points"""
+       return [_point(plist[i],i)for i in range(len(plist))]
+
+#---base classes----------------------------------------
+class _Call:
+       """Makes a callable class."""
+       def copy(self):
+               """Returns a copy."""
+               return copy.deepcopy(self)
+
+       def __call__(self,**attrs):
+               """Returns a copy with modified attributes."""
+               copied=self.copy()
+               for attr in attrs:setattr(copied,attr,attrs[attr])
+               return copied
+
+#-------------------------------------------------------
+class _Entity(_Call):
+       """Base class for _common group codes for entities."""
+       def __init__(self,color=None,extrusion=None,layer='0',
+                                lineType=None,lineTypeScale=None,lineWeight=None,
+                                thickness=None,parent=None):
+               """None values will be omitted."""
+               self.color                = color
+               self.extrusion    = extrusion
+               self.layer                = layer
+               self.lineType      = lineType
+               self.lineTypeScale  = lineTypeScale
+               self.lineWeight  = lineWeight
+               self.thickness    = thickness
+               self.parent              = parent
+
+       def _common(self):
+               """Return common group codes as a string."""
+               if self.parent:parent=self.parent
+               else:parent=self
+               result='8\n%s'%parent.layer
+               if parent.color!=None:            result+='\n62\n%s'%parent.color
+               if parent.extrusion!=None:        result+='\n%s'%_point(parent.extrusion,200)
+               if parent.lineType!=None:          result+='\n6\n%s'%parent.lineType
+               if parent.lineWeight!=None:      result+='\n370\n%s'%parent.lineWeight
+               if parent.lineTypeScale!=None:  result+='\n48\n%s'%parent.lineTypeScale
+               if parent.thickness!=None:        result+='\n39\n%s'%parent.thickness
+               return result
+
+#--------------------------
+class _Entities:
+       """Base class to deal with composed objects."""
+       def __dxf__(self):
+               return []
+
+       def __str__(self):
+               return '\n'.join([str(x) for x in self.__dxf__()])
+
+#--------------------------
+class _Collection(_Call):
+       """Base class to expose entities methods to main object."""
+       def __init__(self,entities=[]):
+               self.entities=copy.copy(entities)
+               #link entities methods to drawing
+               for attr in dir(self.entities):
+                       if attr[0]!='_':
+                               attrObject=getattr(self.entities,attr)
+                               if callable(attrObject):
+                                       setattr(self,attr,attrObject)
+
+####2) Constants
+#---color values
+BYBLOCK=0
+BYLAYER=256
+
+#---block-type flags (bit coded values, may be combined):
+ANONYMOUS                         =1  # This is an anonymous block generated by hatching, associative dimensioning, other internal operations, or an application
+NON_CONSTANT_ATTRIBUTES =2  # This block has non-constant attribute definitions (this bit is not set if the block has any attribute definitions that are constant, or has no attribute definitions at all)
+XREF                                   =4  # This block is an external reference (xref)
+XREF_OVERLAY                   =8  # This block is an xref overlay
+EXTERNAL                               =16 # This block is externally dependent
+RESOLVED                               =32 # This is a resolved external reference, or dependent of an external reference (ignored on input)
+REFERENCED                       =64 # This definition is a referenced external reference (ignored on input)
+
+#---mtext flags
+#attachment point
+TOP_LEFT               = 1
+TOP_CENTER       = 2
+TOP_RIGHT         = 3
+MIDDLE_LEFT     = 4
+MIDDLE_CENTER   = 5
+MIDDLE_RIGHT   = 6
+BOTTOM_LEFT     = 7
+BOTTOM_CENTER   = 8
+BOTTOM_RIGHT   = 9
+#drawing direction
+LEFT_RIGHT       = 1
+TOP_BOTTOM       = 3
+BY_STYLE               = 5 #the flow direction is inherited from the associated text style
+#line spacing style (optional):
+AT_LEAST               = 1 #taller characters will override
+EXACT             = 2 #taller characters will not override
+
+#---polyline flags
+CLOSED                                   =1      # This is a closed polyline (or a polygon mesh closed in the M direction)
+CURVE_FIT                                 =2     # Curve-fit vertices have been added
+SPLINE_FIT                               =4      # Spline-fit vertices have been added
+POLYLINE_3D                             =8       # This is a 3D polyline
+POLYGON_MESH                           =16      # This is a 3D polygon mesh
+CLOSED_N                                       =32      # The polygon mesh is closed in the N direction
+POLYFACE_MESH                     =64   # The polyline is a polyface mesh
+CONTINOUS_LINETYPE_PATTERN  =128       # The linetype pattern is generated continuously around the vertices of this polyline
+
+#---text flags
+#horizontal
+LEFT           = 0
+CENTER   = 1
+RIGHT     = 2
+ALIGNED         = 3 #if vertical alignment = 0
+MIDDLE   = 4 #if vertical alignment = 0
+FIT             = 5 #if vertical alignment = 0
+#vertical
+BASELINE       = 0
+BOTTOM   = 1
+MIDDLE   = 2
+TOP             = 3
+
+####3) Classes
+#---entitities -----------------------------------------------
+#--------------------------
+class Arc(_Entity):
+       """Arc, angles in degrees."""
+       def __init__(self,center=(0,0,0),radius=1,
+                                startAngle=0.0,endAngle=90,**common):
+               """Angles in degrees."""
+               _Entity.__init__(self,**common)
+               self.center=center
+               self.radius=radius
+               self.startAngle=startAngle
+               self.endAngle=endAngle
+       def __str__(self):
+               return '0\nARC\n%s\n%s\n40\n%s\n50\n%s\n51\n%s'%\
+                          (self._common(),_point(self.center),
+                               self.radius,self.startAngle,self.endAngle)
+
+#-----------------------------------------------
+class Circle(_Entity):
+       """Circle"""
+       def __init__(self,center=(0,0,0),radius=1,**common):
+               _Entity.__init__(self,**common)
+               self.center=center
+               self.radius=radius
+       def __str__(self):
+               return '0\nCIRCLE\n%s\n%s\n40\n%s'%\
+                          (self._common(),_point(self.center),self.radius)
+
+#-----------------------------------------------
+class Face(_Entity):
+       """3dface"""
+       def __init__(self,points,**common):
+               _Entity.__init__(self,**common)
+               if len(points)<4: #fix for r12 format
+                       points.append(points[-1])
+               self.points=points
+               
+       def __str__(self):
+               return '\n'.join(['0\n3DFACE',self._common()]+
+                                                _points(self.points)
+                                                )
+#-----------------------------------------------
+class Insert(_Entity):
+       """Block instance."""
+       def __init__(self,name,point=(0,0,0),
+                                xscale=None,yscale=None,zscale=None,
+                                cols=None,colspacing=None,rows=None,rowspacing=None,
+                                rotation=None,
+                                **common):
+               _Entity.__init__(self,**common)
+               self.name=name
+               self.point=point
+               self.xscale=xscale
+               self.yscale=yscale
+               self.zscale=zscale
+               self.cols=cols
+               self.colspacing=colspacing
+               self.rows=rows
+               self.rowspacing=rowspacing
+               self.rotation=rotation
+
+       def __str__(self):
+               result='0\nINSERT\n2\n%s\n%s\n%s'%\
+                               (self.name,self._common(),_point(self.point))
+               if self.xscale!=None:result+='\n41\n%s'%self.xscale
+               if self.yscale!=None:result+='\n42\n%s'%self.yscale
+               if self.zscale!=None:result+='\n43\n%s'%self.zscale
+               if self.rotation:result+='\n50\n%s'%self.rotation
+               if self.cols!=None:result+='\n70\n%s'%self.cols
+               if self.colspacing!=None:result+='\n44\n%s'%self.colspacing
+               if self.rows!=None:result+='\n71\n%s'%self.rows
+               if self.rowspacing!=None:result+='\n45\n%s'%self.rowspacing
+               return result
+
+#-----------------------------------------------
+class Line(_Entity):
+       """Line"""
+       def __init__(self,points,**common):
+               _Entity.__init__(self,**common)
+               self.points=points
+       def __str__(self):
+               return '\n'.join(['0\nLINE',self._common()]+
+                                                _points(self.points))
+
+#-----------------------------------------------
+class PolyLine(_Entity):
+       #TODO: Finish polyline (now implemented as a series of lines)
+       def __init__(self,points,org_point=[0,0,0],flag=0,width=None,**common):
+               _Entity.__init__(self,**common)
+               self.points=points
+               self.org_point=org_point
+               self.flag=flag
+               self.width=width
+       def __str__(self):
+               result= '0\nPOLYLINE\n%s\n70\n%s' %(self._common(),self.flag)
+               #print 'self._common()', self._common() #----------
+               result+='\n66\n1'
+               result+='\n%s' %_point(self.org_point)
+               for point in self.points:
+                       result+='\n0\nVERTEX'
+                       result+='\n8\n%s' %self.layer
+                       result+='\n%s' %_point(point)
+                       if self.width:result+='\n40\n%s\n41\n%s' %(self.width,self.width)
+               result+='\n0\nSEQEND'
+               result+='\n8\n%s' %self.layer
+               return result
+
+#-----------------------------------------------
+class Point(_Entity):
+       """Colored solid fill."""
+       def __init__(self,points=None,**common):
+               _Entity.__init__(self,**common)
+               self.points=points
+
+#-----------------------------------------------
+class Solid(_Entity):
+       """Colored solid fill."""
+       def __init__(self,points=None,**common):
+               _Entity.__init__(self,**common)
+               self.points=points
+       def __str__(self):
+               return '\n'.join(['0\nSOLID',self._common()]+
+                                                _points(self.points[:2]+[self.points[3],self.points[2]])
+                                                )
+
+#-----------------------------------------------
+class Text(_Entity):
+       """Single text line."""
+       def __init__(self,text='',point=(0,0,0),alignment=None,
+                                flag=None,height=1,justifyhor=None,justifyver=None,
+                                rotation=None,obliqueAngle=None,style=None,xscale=None,**common):
+               _Entity.__init__(self,**common)
+               self.text=text
+               self.point=point
+               self.alignment=alignment
+               self.flag=flag
+               self.height=height
+               self.justifyhor=justifyhor
+               self.justifyver=justifyver
+               self.rotation=rotation
+               self.obliqueAngle=obliqueAngle
+               self.style=style
+               self.xscale=xscale
+       def __str__(self):
+               result= '0\nTEXT\n%s\n%s\n40\n%s\n1\n%s'%\
+                               (self._common(),_point(self.point),self.height,self.text)
+               if self.rotation:result+='\n50\n%s'%self.rotation
+               if self.xscale:result+='\n41\n%s'%self.xscale
+               if self.obliqueAngle:result+='\n51\n%s'%self.obliqueAngle
+               if self.style:result+='\n7\n%s'%self.style
+               if self.flag:result+='\n71\n%s'%self.flag
+               if self.justifyhor:result+='\n72\n%s'%self.justifyhor
+               if self.alignment:result+='\n%s'%_point(self.alignment,1)
+               if self.justifyver:result+='\n73\n%s'%self.justifyver
+               return result
+
+#-----------------------------------------------
+class Mtext(Text):
+       """Surrogate for mtext, generates some Text instances."""
+       def __init__(self,text='',point=(0,0,0),width=250,spacingFactor=1.5,down=0,spacingWidth=None,**options):
+               Text.__init__(self,text=text,point=point,**options)
+               if down:spacingFactor*=-1
+               self.spacingFactor=spacingFactor
+               self.spacingWidth=spacingWidth
+               self.width=width
+               self.down=down
+       def __str__(self):
+               texts=self.text.replace('\r\n','\n').split('\n')
+               if not self.down:texts.reverse()
+               result=''
+               x=y=0
+               if self.spacingWidth:spacingWidth=self.spacingWidth
+               else:spacingWidth=self.height*self.spacingFactor
+               for text in texts:
+                       while text:
+                               result+='\n%s'%Text(text[:self.width],
+                                       point=(self.point[0]+x*spacingWidth,
+                                                  self.point[1]+y*spacingWidth,
+                                                  self.point[2]),
+                                       alignment=self.alignment,flag=self.flag,height=self.height,
+                                       justifyhor=self.justifyhor,justifyver=self.justifyver,
+                                       rotation=self.rotation,obliqueAngle=self.obliqueAngle,
+                                       style=self.style,xscale=self.xscale,parent=self
+                               )
+                               text=text[self.width:]
+                               if self.rotation:x+=1
+                               else:y+=1
+               return result[1:]
+
+#-----------------------------------------------
+##class _Mtext(_Entity):
+##     """Mtext not functioning for minimal dxf."""
+##     def __init__(self,text='',point=(0,0,0),attachment=1,
+##                              charWidth=None,charHeight=1,direction=1,height=100,rotation=0,
+##                              spacingStyle=None,spacingFactor=None,style=None,width=100,
+##                              xdirection=None,**common):
+##             _Entity.__init__(self,**common)
+##             self.text=text
+##             self.point=point
+##             self.attachment=attachment
+##             self.charWidth=charWidth
+##             self.charHeight=charHeight
+##             self.direction=direction
+##             self.height=height
+##             self.rotation=rotation
+##             self.spacingStyle=spacingStyle
+##             self.spacingFactor=spacingFactor
+##             self.style=style
+##             self.width=width
+##             self.xdirection=xdirection
+##     def __str__(self):
+##             input=self.text
+##             text=''
+##             while len(input)>250:
+##                     text+='\n3\n%s'%input[:250]
+##                     input=input[250:]
+##             text+='\n1\n%s'%input
+##             result= '0\nMTEXT\n%s\n%s\n40\n%s\n41\n%s\n71\n%s\n72\n%s%s\n43\n%s\n50\n%s'%\
+##                             (self._common(),_point(self.point),self.charHeight,self.width,
+##                              self.attachment,self.direction,text,
+##                              self.height,
+##                              self.rotation)
+##             if self.style:result+='\n7\n%s'%self.style
+##             if self.xdirection:result+='\n%s'%_point(self.xdirection,1)
+##             if self.charWidth:result+='\n42\n%s'%self.charWidth
+##             if self.spacingStyle:result+='\n73\n%s'%self.spacingStyle
+##             if self.spacingFactor:result+='\n44\n%s'%self.spacingFactor
+##             return result
+
+#---tables ---------------------------------------------------
+#-----------------------------------------------
+class Block(_Collection):
+       """Use list methods to add entities, eg append."""
+       def __init__(self,name,layer='0',flag=0,base=(0,0,0),entities=[]):
+               self.entities=copy.copy(entities)
+               _Collection.__init__(self,entities)
+               self.layer=layer
+               self.name=name
+               self.flag=0
+               self.base=base
+       def __str__(self):
+               e='\n'.join([str(x)for x in self.entities])
+               return '0\nBLOCK\n8\n%s\n2\n%s\n70\n%s\n%s\n3\n%s\n%s\n0\nENDBLK'%\
+                          (self.layer,self.name.upper(),self.flag,_point(self.base),self.name.upper(),e)
+
+#-----------------------------------------------
+class Layer(_Call):
+       """Layer"""
+       def __init__(self,name='pydxf',color=7,lineType='continuous',flag=64):
+               self.name=name
+               self.color=color
+               self.lineType=lineType
+               self.flag=flag
+       def __str__(self):
+               return '0\nLAYER\n2\n%s\n70\n%s\n62\n%s\n6\n%s'%\
+                          (self.name.upper(),self.flag,self.color,self.lineType)
+
+#-----------------------------------------------
+class LineType(_Call):
+       """Custom linetype"""
+       def __init__(self,name='continuous',description='Solid line',elements=[],flag=64):
+               # TODO: Implement lineType elements
+               self.name=name
+               self.description=description
+               self.elements=copy.copy(elements)
+               self.flag=flag
+       def __str__(self):
+               return '0\nLTYPE\n2\n%s\n70\n%s\n3\n%s\n72\n65\n73\n%s\n40\n0.0'%\
+                       (self.name.upper(),self.flag,self.description,len(self.elements))
+
+#-----------------------------------------------
+class Style(_Call):
+       """Text style"""
+       def __init__(self,name='standard',flag=0,height=0,widthFactor=40,obliqueAngle=50,
+                                mirror=0,lastHeight=1,font='arial.ttf',bigFont=''):
+               self.name=name
+               self.flag=flag
+               self.height=height
+               self.widthFactor=widthFactor
+               self.obliqueAngle=obliqueAngle
+               self.mirror=mirror
+               self.lastHeight=lastHeight
+               self.font=font
+               self.bigFont=bigFont
+       def __str__(self):
+               return '0\nSTYLE\n2\n%s\n70\n%s\n40\n%s\n41\n%s\n50\n%s\n71\n%s\n42\n%s\n3\n%s\n4\n%s'%\
+                          (self.name.upper(),self.flag,self.flag,self.widthFactor,
+                               self.obliqueAngle,self.mirror,self.lastHeight,
+                               self.font.upper(),self.bigFont.upper())
+
+#-----------------------------------------------
+class View(_Call):
+       def __init__(self,name,flag=0,width=1,height=1,center=(0.5,0.5),
+                                direction=(0,0,1),target=(0,0,0),lens=50,
+                                frontClipping=0,backClipping=0,twist=0,mode=0):
+               self.name=name
+               self.flag=flag
+               self.width=width
+               self.height=height
+               self.center=center
+               self.direction=direction
+               self.target=target
+               self.lens=lens
+               self.frontClipping=frontClipping
+               self.backClipping=backClipping
+               self.twist=twist
+               self.mode=mode
+       def __str__(self):
+               return '0\nVIEW\n2\n%s\n70\n%s\n40\n%s\n%s\n41\n%s\n%s\n%s\n42\n%s\n43\n%s\n44\n%s\n50\n%s\n71\n%s'%\
+                          (self.name,self.flag,self.height,_point(self.center),self.width,
+                               _point(self.direction,1),_point(self.target,2),self.lens,
+                               self.frontClipping,self.backClipping,self.twist,self.mode)
+
+#-----------------------------------------------
+def ViewByWindow(name,leftBottom=(0,0),rightTop=(1,1),**options):
+       width=abs(rightTop[0]-leftBottom[0])
+       height=abs(rightTop[1]-leftBottom[1])
+       center=((rightTop[0]+leftBottom[0])*0.5,(rightTop[1]+leftBottom[1])*0.5)
+       return View(name=name,width=width,height=height,center=center,**options)
+
+#---drawing
+#-----------------------------------------------
+class Drawing(_Collection):
+       """Dxf drawing. Use append or any other list methods to add objects."""
+       def __init__(self,insbase=(0.0,0.0,0.0),extmin=(0.0,0.0),extmax=(0.0,0.0),
+                                layers=[Layer()],linetypes=[LineType()],styles=[Style()],blocks=[],
+                                views=[],entities=None,fileName='test.dxf'):
+               # TODO: replace list with None,arial
+               if not entities:entities=[]
+               _Collection.__init__(self,entities)
+               self.insbase=insbase
+               self.extmin=extmin
+               self.extmax=extmax
+               self.layers=copy.copy(layers)
+               self.linetypes=copy.copy(linetypes)
+               self.styles=copy.copy(styles)
+               self.views=copy.copy(views)
+               self.blocks=copy.copy(blocks)
+               self.fileName=fileName
+               #private
+               #self.acadver='9\n$ACADVER\n1\nAC1006'
+               self.acadver='9\n$ACADVER\n1\nAC1009'
+               """DXF AutoCAD-Release format code
+               AC1021  2008, 2007 
+               AC1018  2006, 2005, 2004 
+               AC1015  2002, 2000i, 2000 
+               AC1014  R14,14.01 
+               AC1012  R13    
+               AC1009  R12,11 
+               AC1006  R10    
+               AC1004  R9    
+               AC1002  R2.6  
+               AC1.50  R2.05 
+               """
+
+       def _name(self,x):
+               """Helper function for self._point"""
+               return '9\n$%s'%x.upper()
+
+       def _point(self,name,x):
+               """Point setting from drawing like extmin,extmax,..."""
+               return '%s\n%s'%(self._name(name),_point(x))
+
+       def _section(self,name,x):
+               """Sections like tables,blocks,entities,..."""
+               if x:xstr='\n'+'\n'.join(x)
+               else:xstr=''
+               return '0\nSECTION\n2\n%s%s\n0\nENDSEC'%(name.upper(),xstr)
+
+       def _table(self,name,x):
+               """Tables like ltype,layer,style,..."""
+               if x:xstr='\n'+'\n'.join(x)
+               else:xstr=''
+               return '0\nTABLE\n2\n%s\n70\n%s%s\n0\nENDTAB'%(name.upper(),len(x),xstr)
+
+       def __str__(self):
+               """Returns drawing as dxf string."""
+               header=[self.acadver]+[self._point(attr,getattr(self,attr)) for attr in _HEADER_POINTS]
+               header=self._section('header',header)
+
+               tables=[self._table('ltype',[str(x) for x in self.linetypes]),
+                               self._table('layer',[str(x) for x in self.layers]),
+                               self._table('style',[str(x) for x in self.styles]),
+                               self._table('view',[str(x) for x in self.views]),
+               ]
+               tables=self._section('tables',tables)
+
+               blocks=self._section('blocks',[str(x) for x in self.blocks])
+
+               entities=self._section('entities',[str(x) for x in self.entities])
+
+               all='\n'.join([header,tables,blocks,entities,'0\nEOF\n'])
+               return all
+
+       def saveas(self,fileName):
+               self.fileName=fileName
+               self.save()
+
+       def save(self):
+               test=open(self.fileName,'w')
+               test.write(str(self))
+               test.close()
+
+
+#---extras
+#-----------------------------------------------
+class Rectangle(_Entity):
+       """Rectangle, creates lines."""
+       def __init__(self,point=(0,0,0),width=1,height=1,solid=None,line=1,**common):
+               _Entity.__init__(self,**common)
+               self.point=point
+               self.width=width
+               self.height=height
+               self.solid=solid
+               self.line=line
+       def __str__(self):
+               result=''
+               points=[self.point,(self.point[0]+self.width,self.point[1],self.point[2]),
+                       (self.point[0]+self.width,self.point[1]+self.height,self.point[2]),
+                       (self.point[0],self.point[1]+self.height,self.point[2]),self.point]
+               if self.solid:
+                       result+='\n%s'%Solid(points=points[:-1],parent=self.solid)
+               if self.line:
+                       for i in range(4):result+='\n%s'%\
+                               Line(points=[points[i],points[i+1]],parent=self)
+               return result[1:]
+
+#-----------------------------------------------
+class LineList(_Entity):
+       """Like polyline, but built of individual lines."""
+       def __init__(self,points=[],org_point=[0,0,0],closed=0,**common):
+               _Entity.__init__(self,**common)
+               self.closed=closed
+               self.points=copy.copy(points)
+       def __str__(self):
+               if self.closed:points=self.points+[self.points[0]]
+               else: points=self.points
+               result=''
+               for i in range(len(points)-1):
+                       result+='\n%s' %Line(points=[points[i],points[i+1]],parent=self)
+               return result[1:]
+
+#-----------------------------------------------------
+def projected_co(vec, mw):
+       # convert the world coordinates of v to screen coordinates
+       #co = vec.co.copy().resize4D()
+       co = vec.copy().resize4D()
+       co[3] = 1.0
+       sc = co * mw
+       #print 'viewprojection=', sc #---------
+       return [sc[0],sc[1],0.0]
+
+
+#-----------------------------------------------------
+def dxf_export_ui(filepath):
+       print '\n\nDXF-Export %s' %__version__
+       #filepath = 'blend_test.dxf'
+       # Dont overwrite
+       if not BPyMessages.Warning_SaveOver(filepath):
+               print 'Aborted by user: nothing exported'
+               return
+       #test():return
+
+       ONLYSELECTED = True
+       POLYLINES = True
+       ONLYFACES = False
+       FLATTEN = 0 #dimmensions:1,2,3. Force Z dimmension value to 0.0, equal ground projection
+       SCALE_FACTOR = 1.0 #optional, can be done in CAD too
+       PREF_ONLYSELECTED= Draw.Create(ONLYSELECTED)
+       PREF_POLYLINES= Draw.Create(POLYLINES)
+       PREF_ONLYFACES= Draw.Create(ONLYFACES)
+       PREF_FLATTEN= Draw.Create(FLATTEN)
+       PREF_SCALE_FACTOR= Draw.Create(SCALE_FACTOR)
+       PREF_HELP= Draw.Create(0)
+       block = [\
+       ("only selected", PREF_ONLYSELECTED, "export only selected geometry"),\
+       ("global Scale:", PREF_SCALE_FACTOR, 0.001, 1000, "set global Scale factor for exporting geometry"),\
+       ("only faces", PREF_ONLYFACES, "from mesh-objects export only faces, not edges"),\
+       ("write POLYLINEs", PREF_POLYLINES, "export curves to POLYLINEs, otherwise to LINEs"),\
+       ("3D-View to Flat", PREF_FLATTEN, "flatten geometry according current 3d-View"),\
+       (''),\
+       ("online Help", PREF_HELP, "calls DXF-Exporter Manual Page on Wiki.Blender.org"),\
+       ]
+       
+       if not Draw.PupBlock("DXF-Exporter %s" %__version__[:10], block):
+               return
+
+       if PREF_HELP.val!=0:
+               try:
+                       import webbrowser
+                       webbrowser.open('http://wiki.blender.org/index.php?title=Scripts/Manual/Export/autodesk_dxf')
+               except:
+                       Draw.PupMenu('DXF Exporter: %t|no connection to manual-page on Blender-Wiki!    try:|\
+http://wiki.blender.org/index.php?title=Scripts/Manual/Export/autodesk_dxf')
+               return
+
+       ONLYSELECTED = PREF_ONLYSELECTED.val
+       POLYLINES = PREF_POLYLINES.val
+       ONLYFACES = PREF_ONLYFACES.val
+       FLATTEN = PREF_FLATTEN.val
+       SCALE_FACTOR = PREF_SCALE_FACTOR.val
+
+       sce = Scene.GetCurrent()
+       if ONLYSELECTED: sel_group = sce.objects.selected
+       else: sel_group = sce.objects
+
+       if sel_group:
+               Window.WaitCursor(1)
+               t = sys.time()
+
+               #init Drawing ---------------------
+               d=Drawing()
+               #add Tables -----------------
+               #d.blocks.append(b)                                     #table blocks
+               d.styles.append(Style())                        #table styles
+               d.views.append(View('Normal'))          #table view
+               d.views.append(ViewByWindow('Window',leftBottom=(1,0),rightTop=(2,1)))  #idem
+
+               #add Entities --------------------
+               something_ready = False
+               mw = Window.GetViewMatrix()
+               #mw = Window.GetPerspMatrix() #TODO: how get it working?
+               for ob in sel_group:
+                       entities = []
+                       mx = ob.matrix
+                       if (ob.type == 'Mesh'):
+                               me = ob.getData(mesh=1)
+                               faces=[]
+                               edges=[]
+                               if (not FLATTEN) and len(me.faces)>0 and ONLYFACES:
+                                       #export 3D as 3DFACEs
+                                       for f in me.faces:
+                                               #print 'face=', f #---------
+                                               verts = f.verts
+                                               points = [verts[i].co*mx for i in range(len(verts))]
+                                               if SCALE_FACTOR!=1.0:
+                                                       points = [p*SCALE_FACTOR for p in points]
+                                               #print 'points=', points #---------
+                                               dxfFACE = Face(points)
+                                               entities.append(dxfFACE)
+                               else:   #export 3D as LINEs
+                                       for e in me.edges:
+                                               #print 'edge=', e #---------
+                                               points=[]
+                                               points = [e.v1.co*mx, e.v2.co*mx]
+                                               if SCALE_FACTOR!=1.0:
+                                                       points = [p*SCALE_FACTOR for p in points]
+                                               if FLATTEN:
+#                                                      for p in points: p[FLATTEN-1]=0.0
+                                                       for i,v in enumerate(points):
+                                                               v = projected_co(v, mw)
+                                                               points[i]=v
+                                                       #print 'flatten points=', points #---------
+                                               dxfLINE = Line(points)
+                                               entities.append(dxfLINE)
+                       elif (ob.type == 'Curve'):
+                               curve = ob.getData()
+                               for cur in curve:
+                                       #print 'deb: START cur=', cur #--------------
+                                       if 1: #not cur.isNurb():
+                                               #print 'deb: START points' #--------------
+                                               points = []
+                                               org_point = [0.0,0.0,0.0]
+                                               for point in cur:
+                                                       #print 'point=', point #---------
+                                                       if cur.isNurb():
+                                                               vec = point[0:3]
+                                                       else:
+                                                               point = point.getTriple()
+                                                               #print 'point=', point #---------
+                                                               vec = point[1]
+                                                       #print 'vec=', vec #---------
+                                                       pkt = Mathutils.Vector(vec) * mx
+                                                       #print 'pkt=', pkt #---------
+                                                       pkt *= SCALE_FACTOR
+                                                       if FLATTEN:
+                                                               pkt = projected_co(pkt, mw)
+                                                       points.append(pkt)
+                                               if cur.isCyclic(): closed = 1
+                                               else: closed = 0
+                                               if len(points)>1:
+                                                       #print 'deb: points', points #--------------
+                                                       if POLYLINES: dxfPLINE = PolyLine(points,org_point,closed)
+                                                       else: dxfPLINE = LineList(points,org_point,closed)
+                                                       entities.append(dxfPLINE)
+                       for e in entities:
+                               d.append(e)
+                               something_ready = True
+               if something_ready:
+                       d.saveas(filepath)
+                       Window.WaitCursor(0)
+                       #Draw.PupMenu('DXF Exporter: job finished|search for blend_test.dxf in current project directory')
+                       print 'exported to %s' % filepath
+                       print 'finished in %.2f seconds' % (sys.time()-t)
+               else:
+                       print "Abort: no supported object types selected, nothing exported!"
+                       Draw.PupMenu('DXF Exporter:        Abort!|Not-supported object types selected.')
+       else:
+               print "Abort: selection was empty, no object to export!"
+               Draw.PupMenu('DXF Exporter:        Abort!|empty selection, no object to export!')
+       # Timing the script is a good way to be aware on any speed hits when scripting
+
+
+#-----------------------------------------------------
+def test():
+       #Blocks
+       b=Block('test')
+       b.append(Solid(points=[(0,0,0),(1,0,0),(1,1,0),(0,1,0)],color=1))
+       b.append(Arc(center=(1,0,0),color=2))
+
+       #Drawing
+       d=Drawing()
+       #tables
+       d.blocks.append(b)                                        #table blocks
+       d.styles.append(Style())                                #table styles
+       d.views.append(View('Normal'))            #table view
+       d.views.append(ViewByWindow('Window',leftBottom=(1,0),rightTop=(2,1)))  #idem
+
+       #entities
+       d.append(Circle(center=(1,1,0),color=3))
+       d.append(Face(points=[(0,0,0),(1,0,0),(1,1,0),(0,1,0)],color=4))
+       d.append(Insert('test',point=(3,3,3),cols=5,colspacing=2))
+       d.append(Line(points=[(0,0,0),(1,1,1)]))
+       d.append(Mtext('Click on Ads\nmultiple lines with mtext',point=(1,1,1),color=5,rotation=90))
+       d.append(Text('Please donate!',point=(3,0,1)))
+       d.append(Rectangle(point=(2,2,2),width=4,height=3,color=6,solid=Solid(color=2)))
+       d.append(Solid(points=[(4,4,0),(5,4,0),(7,8,0),(9,9,0)],color=3))
+       d.append(PolyLine(points=[(1,1,1),(2,1,1),(2,2,1),(1,2,1)],closed=1,color=1))
+
+       #d.saveas('c:\\test.dxf')
+       d.saveas('test.dxf')
+
+
+#-----------------------------------------------------
+if __name__=='__main__':
+       #main()
+       if not copy:
+               Draw.PupMenu('Error%t|This script requires a full python install')
+       Window.FileSelector(dxf_export_ui, 'EXPORT DXF', sys.makename(ext='.dxf'))
+       
+       
+       
\ No newline at end of file