diff options
author | Remigiusz Fiedler <migius@gmx.net> | 2012-07-11 03:16:32 +0400 |
---|---|---|
committer | Remigiusz Fiedler <migius@gmx.net> | 2012-07-11 03:16:32 +0400 |
commit | 1dd571efee1758e622f48a42f46ce8dbc1a507af (patch) | |
tree | 061cd8c6d7d0ac5ebce89184d56a05cc650e56e2 /io_export_dxf/model | |
parent | 891ce0209b978ba8407bbb739e12db1562ea02b6 (diff) |
DXF-exporter script moved from addons_contrib to official addons folder
Diffstat (limited to 'io_export_dxf/model')
-rw-r--r-- | io_export_dxf/model/__init__.py | 0 | ||||
-rw-r--r-- | io_export_dxf/model/dxfLibrary.py | 927 | ||||
-rw-r--r-- | io_export_dxf/model/migiusModel.py | 122 | ||||
-rw-r--r-- | io_export_dxf/model/model.py | 38 |
4 files changed, 1087 insertions, 0 deletions
diff --git a/io_export_dxf/model/__init__.py b/io_export_dxf/model/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/io_export_dxf/model/__init__.py diff --git a/io_export_dxf/model/dxfLibrary.py b/io_export_dxf/model/dxfLibrary.py new file mode 100644 index 00000000..c1730d4d --- /dev/null +++ b/io_export_dxf/model/dxfLibrary.py @@ -0,0 +1,927 @@ +#dxfLibrary.py : provides functions for generating DXF files +# -------------------------------------------------------------------------- +__version__ = "v1.35 - 2010.06.23" +__author__ = "Stani Michiels(Stani), Remigiusz Fiedler(migius)" +__license__ = "GPL" +__url__ = "http://wiki.blender.org/index.php/Extensions:2.4/Py/Scripts/Export/DXF" +__bpydoc__ ="""The library to export geometry data to DXF format r12 version. + +Copyright %s +Version %s +License %s +Homepage %s + +See the homepage for documentation. +Dedicated thread on BlenderArtists: http://blenderartists.org/forum/showthread.php?t=136439 + +IDEAs: +- + +TODO: +- add support for DXFr14 version (needs extended file header) +- add support for DXF-SPLINEs (possible first in DXFr14 version) +- add support for DXF-MTEXT +- add user preset for floating point precision (3-16?) + +History +v1.35 - 2010.06.23 by migius + - added (as default) writing to DXF file without RAM-buffering: faster and low-RAM-machines friendly +v1.34 - 2010.06.20 by migius + - bugfix POLYFACE + - added DXF-flags for POLYLINE and VERTEX class (NURBS-export) +v1.33 - 2009.07.03 by migius + - fix MTEXT newline bug (not supported by DXF-Exporter yet) + - modif _point(): converts all coords to floats + - modif LineType class: implement elements + - added VPORT class, incl. defaults + - fix Insert class +v1.32 - 2009.06.06 by migius + - modif Style class: changed defaults to widthFactor=1.0, obliqueAngle=0.0 + - modif Text class: alignment parameter reactivated +v1.31 - 2009.06.02 by migius + - modif _Entity class: added paperspace,elevation +v1.30 - 2009.05.28 by migius + - bugfix 3dPOLYLINE/POLYFACE: VERTEX needs x,y,z coordinates, index starts with 1 not 0 +v1.29 - 2008.12.28 by Yorik + - modif POLYLINE to support bulge segments +v1.28 - 2008.12.13 by Steeve/BlenderArtists + - bugfix for EXTMIN/EXTMAX to suit Cycas-CAD +v1.27 - 2008.10.07 by migius + - beautifying output code: keys whitespace prefix + - refactoring DXF-strings format: NewLine moved to the end of +v1.26 - 2008.10.05 by migius + - modif POLYLINE to support POLYFACE +v1.25 - 2008.09.28 by migius + - modif FACE class for r12 +v1.24 - 2008.09.27 by migius + - modif POLYLINE class for r12 + - changing output format from r9 to r12(AC1009) +v1.1 (20/6/2005) by www.stani.be/python/sdxf + - Python library to generate dxf drawings +______________________________________________________________ +""" % (__author__,__version__,__license__,__url__) + +# -------------------------------------------------------------------------- +# DXF Library: copyright (C) 2005 by Stani Michiels (AKA Stani) +# 2008/2009 modif by Remigiusz Fiedler (AKA migius) +# -------------------------------------------------------------------------- +# ***** 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""" + return '\n'.join([' %s\n%s'%((i+1)*10+index,float(x[i])) for i in range(len(x))]) + +def _points(plist): + """Convert a list of tuples to dxf points""" + out = '\n'.join([_point(plist[i],i)for i in range(len(plist))]) + return out + +#---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,paperspace=None,color=None,layer='0', + lineType=None,lineTypeScale=None,lineWeight=None, + extrusion=None,elevation=None,thickness=None, + parent=None): + """None values will be omitted.""" + self.paperspace = paperspace + self.color = color + self.layer = layer + self.lineType = lineType + self.lineTypeScale = lineTypeScale + self.lineWeight = lineWeight + self.extrusion = extrusion + self.elevation = elevation + self.thickness = thickness + #self.visible = visible + self.parent = parent + + def _common(self): + """Return common group codes as a string.""" + if self.parent:parent=self.parent + else:parent=self + result ='' + if parent.paperspace==1: result+=' 67\n1\n' + if parent.layer!=None: result+=' 8\n%s\n'%parent.layer + if parent.color!=None: result+=' 62\n%s\n'%parent.color + if parent.lineType!=None: result+=' 6\n%s\n'%parent.lineType + # TODO: if parent.lineWeight!=None: result+='370\n%s\n'%parent.lineWeight + # TODO: if parent.visible!=None: result+='60\n%s\n'%parent.visible + if parent.lineTypeScale!=None: result+=' 48\n%s\n'%parent.lineTypeScale + if parent.elevation!=None: result+=' 38\n%s\n'%parent.elevation + if parent.thickness!=None: result+=' 39\n%s\n'%parent.thickness + if parent.extrusion!=None: result+='%s\n'%_point(parent.extrusion,200) + return result + +#-------------------------- +class _Entities: + """Base class to deal with composed objects.""" + def __dxf__(self): + return [] + + def __str__(self): + return ''.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 flag 70 +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 + +#---polyline flag 75, = curve type +QUADRIC_NURBS = 5 +CUBIC_NURBS = 6 +BEZIER_CURVE = 8 + + +#---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%s\n 40\n%s\n 50\n%s\n 51\n%s\n'%\ + (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%s\n 40\n%s\n'%\ + (self._common(),_point(self.center),self.radius) + +#----------------------------------------------- +class Face(_Entity): + """3dface""" + def __init__(self,points,**common): + _Entity.__init__(self,**common) + while len(points)<4: #fix for r12 format + points.append(points[-1]) + self.points=points + + def __str__(self): + out = ' 0\n3DFACE\n%s%s\n' %(self._common(),_points(self.points)) + return out + +#----------------------------------------------- +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\n 2\n%s\n%s%s\n'%\ + (self.name,self._common(),_point(self.point)) + if self.xscale!=None:result+=' 41\n%s\n'%self.xscale + if self.yscale!=None:result+=' 42\n%s\n'%self.yscale + if self.zscale!=None:result+=' 43\n%s\n'%self.zscale + if self.rotation:result+=' 50\n%s\n'%self.rotation + if self.cols!=None:result+=' 70\n%s\n'%self.cols + if self.colspacing!=None:result+=' 44\n%s\n'%self.colspacing + if self.rows!=None:result+=' 71\n%s\n'%self.rows + if self.rowspacing!=None:result+=' 45\n%s\n'%self.rowspacing + return result + +#----------------------------------------------- +class Line(_Entity): + """Line""" + def __init__(self,points,**common): + _Entity.__init__(self,**common) + self.points=points + def __str__(self): + return ' 0\nLINE\n%s%s\n' %( + self._common(), _points(self.points)) + + +#----------------------------------------------- +class PolyLine(_Entity): + def __init__(self,points,org_point=[0,0,0],flag70=0,flag75=0,width=None,**common): + #width = number, or width = list [width_start=None, width_end=None] + #for 2d-polyline: points = [ [[x, y, z], vflag=None, [width_start=None, width_end=None], bulge=0 or None] ...] + #for 3d-polyline: points = [ [[x, y, z], vflag=None], ...] + #for polyface: points = [points_list, faces_list] + _Entity.__init__(self,**common) + self.points=points + self.org_point=org_point + self.pflag70 = flag70 + self.pflag75 = flag75 + self.polyface = False + self.polyline2d = False + self.faces = [] # dummy value + self.width= None # dummy value + if self.pflag70 & POLYFACE_MESH: + self.polyface=True + self.points=points[0] + self.faces=points[1] + self.p_count=len(self.points) + self.f_count=len(self.faces) + elif not (self.pflag70 & POLYLINE_3D): + self.polyline2d = True + if width: + if type(width)!='list': width=[width,width] + self.width=width + + def __str__(self): + result= ' 0\nPOLYLINE\n%s 70\n%s\n' %(self._common(),self.pflag70) + result+=' 66\n1\n' + result+='%s\n' %_point(self.org_point) + if self.polyface: + result+=' 71\n%s\n' %self.p_count + result+=' 72\n%s\n' %self.f_count + elif self.polyline2d: + if self.width!=None: result+=' 40\n%s\n 41\n%s\n' %(self.width[0],self.width[1]) + if self.pflag75: + result+=' 75\n%s\n' %self.pflag75 + for point in self.points: + result+=' 0\nVERTEX\n' + result+=' 8\n%s\n' %self.layer + if self.polyface: + result+='%s\n' %_point(point) + result+=' 70\n192\n' + elif self.polyline2d: + result+='%s\n' %_point(point[0]) + flag = point[1] + if len(point)>2: + [width1, width2] = point[2] + if width1!=None: result+=' 40\n%s\n' %width1 + if width2!=None: result+=' 41\n%s\n' %width2 + if len(point)==4: + bulge = point[3] + if bulge: result+=' 42\n%s\n' %bulge + if flag: + result+=' 70\n%s\n' %flag + else: + result+='%s\n' %_point(point[0]) + flag = point[1] + if flag: + result+=' 70\n%s\n' %flag + + for face in self.faces: + result+=' 0\nVERTEX\n' + result+=' 8\n%s\n' %self.layer + result+='%s\n' %_point(self.org_point) + result+=' 70\n128\n' + result+=' 71\n%s\n' %face[0] + result+=' 72\n%s\n' %face[1] + result+=' 73\n%s\n' %face[2] + if len(face)==4: result+=' 74\n%s\n' %face[3] + result+=' 0\nSEQEND\n' + result+=' 8\n%s\n' %self.layer + return result + +#----------------------------------------------- +class Point(_Entity): + """Point.""" + def __init__(self,points=None,**common): + _Entity.__init__(self,**common) + self.points=points + def __str__(self): # TODO: + return ' 0\nPOINT\n%s%s\n' %(self._common(), + _points(self.points) + ) + +#----------------------------------------------- +class Solid(_Entity): + """Colored solid fill.""" + def __init__(self,points=None,**common): + _Entity.__init__(self,**common) + self.points=points + def __str__(self): + return ' 0\nSOLID\n%s%s\n' %(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%s\n 40\n%s\n 1\n%s\n'%\ + (self._common(),_point(self.point),self.height,self.text) + if self.rotation: result+=' 50\n%s\n'%self.rotation + if self.xscale: result+=' 41\n%s\n'%self.xscale + if self.obliqueAngle: result+=' 51\n%s\n'%self.obliqueAngle + if self.style: result+=' 7\n%s\n'%self.style + if self.flag: result+=' 71\n%s\n'%self.flag + if self.justifyhor: result+=' 72\n%s\n'%self.justifyhor + if self.alignment: result+='%s\n'%_point(self.alignment,1) + if self.justifyver: result+=' 73\n%s\n'%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+='%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+='3\n%s\n'%input[:250] + input=input[250:] + text+='1\n%s\n'%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\n'%\ + (self._common(),_point(self.point),self.charHeight,self.width, + self.attachment,self.direction,text, + self.height, + self.rotation) + if self.style:result+='7\n%s\n'%self.style + if self.xdirection:result+='%s\n'%_point(self.xdirection,1) + if self.charWidth:result+='42\n%s\n'%self.charWidth + if self.spacingStyle:result+='73\n%s\n'%self.spacingStyle + if self.spacingFactor:result+='44\n%s\n'%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): # TODO: + e=''.join([str(x)for x in self.entities]) + return ' 0\nBLOCK\n 8\n%s\n 2\n%s\n 70\n%s\n%s\n 3\n%s\n%s 0\nENDBLK\n'%\ + (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\n 2\n%s\n 70\n%s\n 62\n%s\n 6\n%s\n'%\ + (self.name.upper(),self.flag,self.color,self.lineType) + +#----------------------------------------------- +class LineType(_Call): + """Custom linetype""" + def __init__(self,name='CONTINUOUS',description='Solid line',elements=[0.0],flag=0): + self.name=name + self.description=description + self.elements=copy.copy(elements) + self.flag=flag + def __str__(self): + result = ' 0\nLTYPE\n 2\n%s\n 70\n%s\n 3\n%s\n 72\n65\n'%\ + (self.name.upper(),self.flag,self.description) + if self.elements: + elements = ' 73\n%s\n' %(len(self.elements)-1) + elements += ' 40\n%s\n' %(self.elements[0]) + for e in self.elements[1:]: + elements += ' 49\n%s\n' %e + result += elements + return result + + +#----------------------------------------------- +class Style(_Call): + """Text style""" + def __init__(self,name='standard',flag=0,height=0,widthFactor=1.0,obliqueAngle=0.0, + 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\n 2\n%s\n 70\n%s\n 40\n%s\n 41\n%s\n 50\n%s\n 71\n%s\n 42\n%s\n 3\n%s\n 4\n%s\n'%\ + (self.name.upper(),self.flag,self.flag,self.widthFactor, + self.obliqueAngle,self.mirror,self.lastHeight, + self.font.upper(),self.bigFont.upper()) + +#----------------------------------------------- +class VPort(_Call): + def __init__(self,name,flag=0, + leftBottom=(0.0,0.0), + rightTop=(1.0,1.0), + center=(0.5,0.5), + snap_base=(0.0,0.0), + snap_spacing=(0.1,0.1), + grid_spacing=(0.1,0.1), + direction=(0.0,0.0,1.0), + target=(0.0,0.0,0.0), + height=1.0, + ratio=1.0, + lens=50.0, + frontClipping=0.0, + backClipping=0.0, + snap_rotation=0.0, + twist=0.0, + mode=0, + circle_zoom=100, + fast_zoom=1, + ucsicon=1, + snap_on=0, + grid_on=0, + snap_style=0, + snap_isopair=0 + ): + self.name=name + self.flag=flag + self.leftBottom=leftBottom + self.rightTop=rightTop + self.center=center + self.snap_base=snap_base + self.snap_spacing=snap_spacing + self.grid_spacing=grid_spacing + self.direction=direction + self.target=target + self.height=float(height) + self.ratio=float(ratio) + self.lens=float(lens) + self.frontClipping=float(frontClipping) + self.backClipping=float(backClipping) + self.snap_rotation=float(snap_rotation) + self.twist=float(twist) + self.mode=mode + self.circle_zoom=circle_zoom + self.fast_zoom=fast_zoom + self.ucsicon=ucsicon + self.snap_on=snap_on + self.grid_on=grid_on + self.snap_style=snap_style + self.snap_isopair=snap_isopair + def __str__(self): + output = [' 0', 'VPORT', + ' 2', self.name, + ' 70', self.flag, + _point(self.leftBottom), + _point(self.rightTop,1), + _point(self.center,2), # View center point (in DCS) + _point(self.snap_base,3), + _point(self.snap_spacing,4), + _point(self.grid_spacing,5), + _point(self.direction,6), #view direction from target (in WCS) + _point(self.target,7), + ' 40', self.height, + ' 41', self.ratio, + ' 42', self.lens, + ' 43', self.frontClipping, + ' 44', self.backClipping, + ' 50', self.snap_rotation, + ' 51', self.twist, + ' 71', self.mode, + ' 72', self.circle_zoom, + ' 73', self.fast_zoom, + ' 74', self.ucsicon, + ' 75', self.snap_on, + ' 76', self.grid_on, + ' 77', self.snap_style, + ' 78', self.snap_isopair + ] + + output_str = '' + for s in output: + output_str += '%s\n' %s + return output_str + + + +#----------------------------------------------- +class View(_Call): + def __init__(self,name,flag=0, + width=1.0, + height=1.0, + center=(0.5,0.5), + direction=(0.0,0.0,1.0), + target=(0.0,0.0,0.0), + lens=50.0, + frontClipping=0.0, + backClipping=0.0, + twist=0.0,mode=0 + ): + self.name=name + self.flag=flag + self.width=float(width) + self.height=float(height) + self.center=center + self.direction=direction + self.target=target + self.lens=float(lens) + self.frontClipping=float(frontClipping) + self.backClipping=float(backClipping) + self.twist=float(twist) + self.mode=mode + def __str__(self): + output = [' 0', 'VIEW', + ' 2', self.name, + ' 70', self.flag, + ' 40', self.height, + _point(self.center), + ' 41', self.width, + _point(self.direction,1), + _point(self.target,2), + ' 42', self.lens, + ' 43', self.frontClipping, + ' 44', self.backClipping, + ' 50', self.twist, + ' 71', self.mode + ] + output_str = '' + for s in output: + output_str += '%s\n' %s + return output_str + +#----------------------------------------------- +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,0.0),extmax=(0.0,0.0,0.0), + layers=[Layer()],linetypes=[LineType()],styles=[Style()],blocks=[], + views=[],vports=[],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.vports=copy.copy(vports) + self.blocks=copy.copy(blocks) + self.fileName=fileName + #print 'deb: blocks=',blocks #---------- + #private + #self.acadver='9\n$ACADVER\n1\nAC1006\n' + self.acadver=' 9\n$ACADVER\n 1\nAC1009\n' + """DXF AutoCAD-Release format codes: + 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\n' %x.upper() + + def _point(self,name,x): + """Point setting from drawing like extmin,extmax,...""" + return '%s%s' %(self._name(name),_point(x)) + + def _section(self,name,x): + """Sections like tables,blocks,entities,...""" + if x: xstr=''.join(x) + else: xstr='' + return ' 0\nSECTION\n 2\n%s\n%s 0\nENDSEC\n'%(name.upper(),xstr) + + def _table(self,name,x): + """Tables like ltype,layer,style,...""" + if x: xstr=''.join(x) + else: xstr='' + return ' 0\nTABLE\n 2\n%s\n 70\n%s\n%s 0\nENDTAB\n'%(name.upper(),len(x),xstr) + + def __str__(self): + """Returns drawing as dxf string.""" + header=[self.acadver]+[self._point(attr,getattr(self,attr))+'\n' for attr in _HEADER_POINTS] + header=self._section('header',header) + + tables=[self._table('vport',[str(x) for x in self.vports]), + 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=''.join([header,tables,blocks,entities,' 0\nEOF\n']) + return all + + def _write_section(self,file,name,data): + file.write(' 0\nSECTION\n 2\n%s\n'%name.upper()) + for x in data: + file.write(str(x)) + file.write(' 0\nENDSEC\n') + + def saveas(self,fileName,buffer=0): + """Writes DXF file. Needs target file name. If optional parameter buffer>0, then switch to old behavior: store entire output string in RAM. + """ + self.fileName=fileName + if buffer: self.save() + else: self.export() + + def save(self): + outfile=open(self.fileName,'w') + outfile.write(str(self)) + outfile.close() + + def export(self): + outfile=open(self.fileName,'w') + header=[self.acadver]+[self._point(attr,getattr(self,attr))+'\n' for attr in _HEADER_POINTS] + self._write_section(outfile,'header',header) + tables=[self._table('vport',[str(x) for x in self.vports]), + 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]), + ] + self._write_section(outfile,'tables',tables) + self._write_section(outfile,'blocks',self.blocks) + self._write_section(outfile,'entities',self.entities) + outfile.write(' 0\nEOF\n') + outfile.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+= Solid(points=points[:-1],parent=self.solid) + if self.line: + for i in range(4): + result+= 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+= Line(points=[points[i][0],points[i+1][0]],parent=self) + return result[1:] + +#----------------------------------------------------- +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)],flag=1,color=1)) + + #d.saveas('c:\\test.dxf') + d.saveas('test.dxf') + +#----------------------------------------------------- +if __name__=='__main__': + if not copy: + Draw.PupMenu('Error%t|This script requires a full python install') + else: test() + diff --git a/io_export_dxf/model/migiusModel.py b/io_export_dxf/model/migiusModel.py new file mode 100644 index 00000000..a1e8b830 --- /dev/null +++ b/io_export_dxf/model/migiusModel.py @@ -0,0 +1,122 @@ +""" +Created on Sep 2, 2011 + +@author: vencax +""" + +from .model import DxfDrawing + +try: + from . import dxfLibrary as DXF + #reload(DXF) + #reload(dxfLibrary) + #from dxfLibrary import * +except Exception: + raise Exception("No dxfLibrary.py module in Blender script folder found!") + +#------------------------------------------------------ +#def col2RGB(color): +# return [int(floor(255*color[0])), +# int(floor(255*color[1])), +# int(floor(255*color[2]))] +# +#global dxfColors +#dxfColors=None +# +##------------------------------------------------------ +#def col2DXF(rgbcolor): +# global dxfColors +# if dxfColors is None: +# from dxfColorMap import color_map +# dxfColors = [(tuple(color),idx) for idx, color in color_map.iteritems()] +# dxfColors.sort() +# entry = (tuple(rgbcolor), -1) +# dxfColors.append(entry) +# dxfColors.sort() +# i = dxfColors.index(entry) +# dxfColors.pop(i) +# return dxfColors[i-1][1] + +""" +v = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,\ +28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,46,47,58,59,60,61,62,63,64,91,92,93,94,96,\ +123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,\ +151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,\ +171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,\ +191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,\ +211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,\ +231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254] +invalid = ''.join([chr(i) for i in v]) +del v, i +""" +#TODO: validDXFr14 = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.' +validDXFr12 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_' +NAMELENGTH_MAX = 80 #max_obnamelength in DXF, (limited to 256? ) +#------------------------------------------------------ +def cleanName(name, valid): + validname = '' + for ch in name: + if ch not in valid: ch = '_' + validname += ch + return validname + +#------------------------------------------------------ +def validDXFr12name(str_name): + dxfname = str(str_name) + dxfname = dxfname[:NAMELENGTH_MAX].upper() + dxfname = cleanName(dxfname, validDXFr12) + return dxfname + +class MigiusDXFLibDrawing(DxfDrawing): + """ Drawing that can convert itself into MIGIUS DXFLib stuff objects """ + + def convert(self, file, **kwargs): + drawing = self._write() + for type, ents in self._entities.items(): + self._processEntityArray(drawing, type, ents) + for v in self._views: + drawing.views.append(DXF.View(**v)) + for v in self._vports: + drawing.vports.append(DXF.VPort(**v)) +# for l in self._layers: + drawing.saveas(file) + + def _write(self): + # init Drawing --------------------- + d=DXF.Drawing() + # add Tables ----------------- + # initialized automatic: d.blocks.append(b) #section BLOCKS + # initialized automatic: d.styles.append(DXF.Style()) #table STYLE + + #table LTYPE --------------- + #d.linetypes.append(DXF.LineType(name='CONTINUOUS',description='--------',elements=[0.0])) + d.linetypes.append(DXF.LineType(name='DOT',description='. . . . . . .',elements=[0.25, 0.0, -0.25])) + d.linetypes.append(DXF.LineType(name='DASHED',description='__ __ __ __ __',elements=[0.8, 0.5, -0.3])) + d.linetypes.append(DXF.LineType(name='DASHDOT',description='__ . __ . __ .',elements=[1.0, 0.5, -0.25, 0.0, -0.25])) + d.linetypes.append(DXF.LineType(name='DIVIDE',description='____ . . ____ . . ',elements=[1.25, 0.5, -0.25, 0.0, -0.25, 0.0, -0.25])) + d.linetypes.append(DXF.LineType(name='BORDER',description='__ __ . __ __ . ',elements=[1.75, 0.5, -0.25, 0.5, -0.25, 0.0, -0.25])) + d.linetypes.append(DXF.LineType(name='HIDDEN',description='__ __ __ __ __',elements=[0.4, 0.25, -0.25])) + d.linetypes.append(DXF.LineType(name='CENTER',description='____ _ ____ _ __',elements=[2.0, 1.25, -0.25, 0.25, -0.25])) + + #d.vports.append(DXF.VPort('*ACTIVE')) + d.vports.append(DXF.VPort('*ACTIVE',center=(-5.0,1.0),height=10.0)) + #d.vports.append(DXF.VPort('*ACTIVE',leftBottom=(-100.0,-60.0),rightTop=(100.0,60.0))) + #d.views.append(DXF.View('Normal')) #table view + d.views.append(DXF.ViewByWindow('BF_TOPVIEW',leftBottom=(-100,-60),rightTop=(100,60))) #idem + + return d + + def _processEntityArray(self, drawing, type, ents): + if type=='Point': + for e in ents: + drawing.append(DXF.Point(**e)) + elif type=='Line': + for e in ents: + drawing.append(DXF.Line(**e)) + elif type=='PolyLine': + for e in ents: + drawing.append(DXF.PolyLine(**e)) + elif type=='Face': + for e in ents: + drawing.append(DXF.Face(**e)) + diff --git a/io_export_dxf/model/model.py b/io_export_dxf/model/model.py new file mode 100644 index 00000000..bff37339 --- /dev/null +++ b/io_export_dxf/model/model.py @@ -0,0 +1,38 @@ + +class DxfDrawing(object): + """ + Represents intermediate model of DXF drawing. It is useful in iterating + through exported object and for easy change the DXF handling library. + """ + def __init__(self): + self._entities = {} + self._layers = {} + self._views = [] + self._vports = [] + self._blocks = [] + + def isEmpty(self): + return len(self._entities) == 0 + + def addEntity(self, type, **kwargs): + if type not in self._entities: + self._entities[type] = [] + self._entities[type].append(kwargs) + + def addLayer(self, name, color): + self._layers[name] = color + + def containsLayer(self, name): + return name in self._layers + + def addBlock(self, block): + self._blocks.append(block) + + def containsBlock(self, blockname): + return blockname in self._blocks + + def convert(self, **kwargs): + """ Converts this drawing into DXF representation object """ + raise NotImplementedError() + + |