DXF-Exporter update
[blender-staging.git] / release / scripts / export_dxf.py
index 665861563596935d65c144342289e28ddf6c6420..061e29b81c79c4f5f3a4a886c15ed32a20a8fbe7 100644 (file)
@@ -7,52 +7,65 @@
  Tooltip: 'Export geometry to DXF-r12 (Drawing eXchange Format).'
 """
 
-__version__ = "v1.25beta - 2008.09.28"
-__author__  = "Stani & migius(Remigiusz Fiedler)"
+__version__ = "v1.27beta - 2008.10.07"
+__author__  = "Remigiusz Fiedler (AKA migius)"
 __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
+Copyright %s
 License %s
-Homepage %s
+
+extern dependances: dxfLibrary.py
 
 See the homepage for documentation.
-url:
-""" % (__author__,__version__,__license__,__url__)
+url: %s
 
-"""
 IDEAs:
- - correct normals for POLYLINE-POLYFACE objects via correct point-order
- - HPGL output for 2d and flattened3d content
+ - correct normals for POLYLINE-POLYFACE via proper point-order
+ - HPGL output for 2d and flattened 3d content
                
 TODO:
- - support hierarchies: groups, instances, parented structures
- - support 210-code (3d orientation vector)
- - presets for architectural scales
+- optimize back-faces removal (probably needs matrix transform)
+- optimize POLYFACE routine: remove double-vertices
+- optimize POLYFACE routine: remove unused vertices
+- support hierarchies: groups, instances, parented structures
+- support 210-code (3d orientation vector)
+- presets for architectural scales
+- write drawing extends for automatic view positioning in CAD
 
 History
+v1.27 - 2008.10.07 by migius
+- exclude Stani's DXF-Library to extern module
+v1.26 - 2008.10.05 by migius
+- add "hidden mode" substitut: back-faces removal
+- add support for mesh ->POLYFACE
+- optimized code for "Flat" procedure
 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
+- 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)
+- 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
+- add finish message-box
 v1.22 - 2008.09.26 by migius
- - add support for curves ->LINEs
- - add support for mesh-edges ->LINEs
+- 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
+- initial adaptation for Blender
+v1.1 (20/6/2005) by Stani Michiels www.stani.be/python/sdxf
+- Python library to generate dxf drawings
 ______________________________________________________________
-"""
+""" % (__author__,__version__,__license__,__url__)
+
+# --------------------------------------------------------------------------
+# Script copyright (C) 2008 Remigiusz Fiedler (AKA migius)
+# --------------------------------------------------------------------------
 # ***** BEGIN GPL LICENSE BLOCK *****
 #
 # This program is free software; you can redistribute it and/or
@@ -76,602 +89,254 @@ 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:]
+#import dxfLibrary
+#reload(dxfLibrary)
+from  dxfLibrary import *
+
+
+#-----------------------------------------------------
+def hidden_status(faces, mx_n):
+       #print 'HIDDEN_MODE: caution! not full implemented yet'
+       ok_faces = []
+       ok_edges = []
+       #sort out back-faces = with normals pointed away from camera
+       for f in faces:
+               #print 'deb: face=', f #---------
+               # get its normal-vector in localCS
+               vec_normal = f.no.copy()
+               #print 'deb: vec_normal=', vec_normal #------------------
+               #must be transfered to camera/view-CS
+               vec_normal *= mx_n
+               #vec_normal *= mb.rotationPart()
+               #print 'deb:2vec_normal=', vec_normal #------------------
+               #vec_normal *= mw0.rotationPart()
+               #print 'deb:3vec_normal=', vec_normal, '\n' #------------------
+
+               # normal must point the Z direction-hemisphere
+               if vec_normal[2] > 0.0 :
+                       ok_faces.append(f.index)
+                       for key in f.edge_keys:
+                               #this test can be done faster with set()
+                               if key not in ok_edges:
+                                        ok_edges.append(key)
+       #print 'deb: amount of visible faces=', len(ok_faces) #---------
+       #print 'deb: visible faces=', ok_faces #---------
+       #print 'deb: amount of visible edges=', len(ok_edges) #---------
+       #print 'deb: visible edges=', ok_edges #---------
+       return ok_faces, ok_edges
+
 
 #-----------------------------------------------------
 def projected_co(vec, mw):
-       # convert the world coordinates of v to screen coordinates
+       # convert the world coordinates of vector to screen coordinates
        #co = vec.co.copy().resize4D()
        co = vec.copy().resize4D()
        co[3] = 1.0
        sc = co * mw
-       #print 'viewprojection=', sc #---------
+       #print 'deb: viewprojection=', sc #---------
        return [sc[0],sc[1],0.0]
 
 
+#--------not used---------------------------------------------
+def flatten(points, mw):
+       for i,v in enumerate(points):
+               v = projected_co(v, mw)
+               points[i]=v
+       #print 'deb: flatten points=', points #---------
+       return points
+
+#-----------------------------------------------------
+def    exportMesh(ob, mx, mx_n):
+       entities = []
+       me = ob.getData(mesh=1)
+       #me.transform(mx)
+       # above is eventualy faster, but bad, cause
+       # directly transforms origin geometry and write back rounding errors
+       me_verts = me.verts[:] #we dont want manipulate origin data
+       #print 'deb: me_verts=', me_verts #---------
+       #me.transform(mx_inv) #counterpart to - back to the origin state
+       for v in me_verts:
+               v.co *= mx
+       faces=[]
+       edges=[]
+       if HIDDEN_MODE:
+               ok_faces, ok_edges = hidden_status(me.faces, mx_n)
+
+       #if (not FLATTEN) and len(me.faces)>0 and ONLYFACES:
+       if ONLYFACES:
+               if POLYFACES: #export 3D as POLYFACEs
+                       allpoints = []
+                       allfaces = []
+                       allpoints =  [v.co[:3] for v in me_verts]
+                       for f in me.faces:
+                               #print 'deb: face=', f #---------
+                               if not HIDDEN_MODE or \
+                                       (HIDDEN_MODE and f.index in ok_faces):
+                                       if 1:
+                                               points = f.verts
+                                               face = [p.index+1 for p in points]
+                                               #print 'deb: face=', face #---------
+                                               allfaces.append(face)
+                                       else: #bad, cause create multiple vertex instances
+                                               points  = f.verts
+                                               points = [ me_verts[p.index].co[:3] for p in points]
+                                               #points = [p.co[:3] for p in points]
+                                               #print 'deb: points=', points #---------
+                                               index = len(allpoints)+1
+                                               face = [index+i for i in range(len(points))]
+                                               allpoints.extend(points)
+                                               allfaces.append(face)
+                       if allpoints and allfaces:
+                               #print 'deb: allpoints=', allpoints #---------
+                               #print 'deb: allfaces=', allfaces #---------
+                               dxfPOLYFACE = PolyLine([allpoints, allfaces], flag=64)
+                               entities.append(dxfPOLYFACE)
+               else: #export 3D as 3DFACEs
+                       for f in me.faces:
+                               #print 'deb: face=', f #---------
+                               if not HIDDEN_MODE or \
+                                       (HIDDEN_MODE and f.index in ok_faces):
+                                       points  = f.verts
+                                       points = [ me_verts[p.index].co[:3] for p in points]
+                                       #points = [p.co[:3] for p in points]
+                                       #print 'deb: points=', points #---------
+                                       dxfFACE = Face(points)
+                                       entities.append(dxfFACE)
+
+       else:   #export 3D as LINEs
+               if HIDDEN_MODE and len(me.faces)!=0:
+                       for e in ok_edges:
+                               points = [ me_verts[key].co[:3] for key in e]
+                               dxfLINE = Line(points)
+                               entities.append(dxfLINE)
+                               
+               else:
+                       for e in me.edges:
+                               #print 'deb: edge=', e #---------
+                               points=[]
+                               #points = [e.v1.co*mx, e.v2.co*mx]
+                               points = [ me_verts[key].co[:3] for key in e.key]
+                               #print 'deb: points=', points #---------
+                               dxfLINE = Line(points)
+                               entities.append(dxfLINE)
+       return entities
+
+
+#-----------------------------------------------------
+def exportCurve(ob, mx):
+       entities = []
+       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 'deb: point=', point #---------
+                               if cur.isNurb():
+                                       vec = point[0:3]
+                               else:
+                                       point = point.getTriple()
+                                       #print 'deb: point=', point #---------
+                                       vec = point[1]
+                               #print 'deb: vec=', vec #---------
+                               pkt = Mathutils.Vector(vec) * mx
+                               #print 'deb: pkt=', pkt #---------
+                               #pkt *= SCALE_FACTOR
+                               if 0: #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)
+       return entities
+
+#-----------------------------------------------------
+def do_export(sel_group, filepath):
+       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
+       #ViewVector = Mathutils.Vector(Window.GetViewVector())
+       #print 'deb: ViewVector=', ViewVector #------------------
+       mw0 = Window.GetViewMatrix()
+       #mw0 = Window.GetPerspMatrix() #TODO: how get it working?
+       mw = mw0.copy()
+       if FLATTEN:
+               m0 = Mathutils.Matrix()
+               m0[2][2]=0.0
+               mw *= m0 #flatten ViewMatrix
+
+       for ob in sel_group:
+               entities = []
+               mx = ob.matrix.copy()
+               mb = mx.copy()
+               #print 'deb: mb    =\n', mb     #---------
+               #print 'deb: mw0    =\n', mw0     #---------
+               mx_n = mx.rotationPart() * mw0.rotationPart() #trans-matrix for normal_vectors
+               if SCALE_FACTOR!=1.0: mx *= SCALE_FACTOR
+               if FLATTEN:     mx *= mw
+                       
+               #mx_inv = mx.copy().invert()
+               #print 'deb: mx    =\n', mx     #---------
+               #print 'deb: mx_inv=\n', mx_inv #---------
+
+               if (ob.type == 'Mesh'):
+                       entities = exportMesh(ob, mx, mx_n)
+               elif (ob.type == 'Curve'):
+                       entities = exportCurve(ob, mx)
+
+               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')
+               print 'exported to %s' % filepath
+               print 'finished in %.2f seconds' % (sys.time()-t)
+       else:
+               Window.WaitCursor(0)
+               print "Abort: selected objects dont mach choosen export option, nothing exported!"
+               Draw.PupMenu('DXF Exporter:   nothing exported!|selected objects dont mach choosen export option!')
+
+#----globals------------------------------------------
+ONLYSELECTED = True
+POLYLINES = True
+ONLYFACES = False
+POLYFACES = 1
+FLATTEN = 0
+HIDDEN_MODE = False #filter out hidden lines
+SCALE_FACTOR = 1.0 #optional, can be done later in CAD too
+
+
+
 #-----------------------------------------------------
 def dxf_export_ui(filepath):
-       print '\n\nDXF-Export %s' %__version__
+       global  ONLYSELECTED,\
+       POLYLINES,\
+       ONLYFACES,\
+       POLYFACES,\
+       FLATTEN,\
+       HIDDEN_MODE,\
+       SCALE_FACTOR
+
+       print '\n\nDXF-Export %s -----------------------' %__version__
        #filepath = 'blend_test.dxf'
        # Dont overwrite
        if not BPyMessages.Warning_SaveOver(filepath):
@@ -679,29 +344,28 @@ def dxf_export_ui(filepath):
                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_POLYFACES= Draw.Create(POLYFACES)
        PREF_FLATTEN= Draw.Create(FLATTEN)
+       PREF_HIDDEN_MODE= Draw.Create(HIDDEN_MODE)
        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"),\
+       ("only faces", PREF_ONLYFACES, "from mesh-objects export only faces, otherwise only edges"),\
+       ("write POLYFACE", PREF_POLYFACES, "export mesh to POLYFACE, otherwise to 3DFACEs"),\
+       ("write POLYLINEs", PREF_POLYLINES, "export curve to POLYLINE, otherwise to LINEs"),\
        ("3D-View to Flat", PREF_FLATTEN, "flatten geometry according current 3d-View"),\
-       (''),\
+       ("Hidden Mode", PREF_HIDDEN_MODE, "filter out hidden lines"),\
+       #(''),\
        ("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 not Draw.PupBlock("DXF-Exporter %s" %__version__[:10], block): return
 
        if PREF_HELP.val!=0:
                try:
@@ -715,139 +379,22 @@ http://wiki.blender.org/index.php?title=Scripts/Manual/Export/autodesk_dxf')
        ONLYSELECTED = PREF_ONLYSELECTED.val
        POLYLINES = PREF_POLYLINES.val
        ONLYFACES = PREF_ONLYFACES.val
+       POLYFACES = PREF_POLYFACES.val
        FLATTEN = PREF_FLATTEN.val
+       HIDDEN_MODE = PREF_HIDDEN_MODE.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.')
+       if sel_group: do_export(sel_group, filepath)
        else:
                print "Abort: selection was empty, no object to export!"
-               Draw.PupMenu('DXF Exporter:        Abort!|empty selection, no object to export!')
+               Draw.PupMenu('DXF Exporter:   nothing exported!|empty selection!')
        # 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__':