00001
00002
00003 __version__ = "v1.33 - 2009.06.16"
00004 __author__ = "Stani Michiels(Stani), Remigiusz Fiedler(migius)"
00005 __license__ = "GPL"
00006 __url__ = "http://wiki.blender.org/index.php/Scripts/Manual/Export/autodesk_dxf"
00007 __bpydoc__ ="""The library to export geometry data to DXF format r12 version.
00008
00009 Copyright %s
00010 Version %s
00011 License %s
00012 Homepage %s
00013
00014 See the homepage for documentation.
00015 Dedicated thread on BlenderArtists: http://blenderartists.org/forum/showthread.php?t=136439
00016
00017 IDEAs:
00018 -
00019
00020 TODO:
00021 - add support for DXFr14 (needs extended file header)
00022 - add support for SPLINEs (possible first in DXFr14 version)
00023 - add user preset for floating point precision (3-16?)
00024
00025 History
00026 v1.33 - 2009.06.16 by migius
00027 - modif _point(): converts all coords to floats
00028 - modif LineType class: implement elements
00029 - added VPORT class, incl. defaults
00030 - fix Insert class
00031 v1.32 - 2009.06.06 by migius
00032 - modif Style class: changed defaults to widthFactor=1.0, obliqueAngle=0.0
00033 - modif Text class: alignment parameter reactivated
00034 v1.31 - 2009.06.02 by migius
00035 - modif _Entity class: added paperspace,elevation
00036 v1.30 - 2009.05.28 by migius
00037 - bugfix 3dPOLYLINE/POLYFACE: VERTEX needs x,y,z coordinates, index starts with 1 not 0
00038 v1.29 - 2008.12.28 by Yorik
00039 - modif POLYLINE to support bulge segments
00040 v1.28 - 2008.12.13 by Steeve/BlenderArtists
00041 - bugfix for EXTMIN/EXTMAX to suit Cycas-CAD
00042 v1.27 - 2008.10.07 by migius
00043 - beautifying output code: keys whitespace prefix
00044 - refactoring DXF-strings format: NewLine moved to the end of
00045 v1.26 - 2008.10.05 by migius
00046 - modif POLYLINE to support POLYFACE
00047 v1.25 - 2008.09.28 by migius
00048 - modif FACE class for r12
00049 v1.24 - 2008.09.27 by migius
00050 - modif POLYLINE class for r12
00051 - changing output format from r9 to r12(AC1009)
00052 v1.1 (20/6/2005) by www.stani.be/python/sdxf
00053 - Python library to generate dxf drawings
00054 ______________________________________________________________
00055 """ % (__author__,__version__,__license__,__url__)
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084 try:
00085 import copy
00086
00087 except:
00088 copy = None
00089
00090
00091 _HEADER_POINTS=['insbase','extmin','extmax']
00092
00093
00094 def _point(x,index=0):
00095 """Convert tuple to a dxf point"""
00096
00097 return '\n'.join([' %s\n%s'%((i+1)*10+index,float(x[i])) for i in range(len(x))])
00098
00099 def _points(plist):
00100 """Convert a list of tuples to dxf points"""
00101 out = '\n'.join([_point(plist[i],i)for i in range(len(plist))])
00102 return out
00103
00104
00105 class _Call:
00106 """Makes a callable class."""
00107 def copy(self):
00108 """Returns a copy."""
00109 return copy.deepcopy(self)
00110
00111 def __call__(self,**attrs):
00112 """Returns a copy with modified attributes."""
00113 copied=self.copy()
00114 for attr in attrs:setattr(copied,attr,attrs[attr])
00115 return copied
00116
00117
00118 class _Entity(_Call):
00119 """Base class for _common group codes for entities."""
00120 def __init__(self,paperspace=None,color=None,layer='0',
00121 lineType=None,lineTypeScale=None,lineWeight=None,
00122 extrusion=None,elevation=None,thickness=None,
00123 parent=None):
00124 """None values will be omitted."""
00125 self.paperspace = paperspace
00126 self.color = color
00127 self.layer = layer
00128 self.lineType = lineType
00129 self.lineTypeScale = lineTypeScale
00130 self.lineWeight = lineWeight
00131 self.extrusion = extrusion
00132 self.elevation = elevation
00133 self.thickness = thickness
00134
00135 self.parent = parent
00136
00137 def _common(self):
00138 """Return common group codes as a string."""
00139 if self.parent:parent=self.parent
00140 else:parent=self
00141 result =''
00142 if parent.paperspace==1: result+=' 67\n1\n'
00143 if parent.layer!=None: result+=' 8\n%s\n'%parent.layer
00144 if parent.color!=None: result+=' 62\n%s\n'%parent.color
00145 if parent.lineType!=None: result+=' 6\n%s\n'%parent.lineType
00146
00147
00148 if parent.lineTypeScale!=None: result+=' 48\n%s\n'%parent.lineTypeScale
00149 if parent.elevation!=None: result+=' 38\n%s\n'%parent.elevation
00150 if parent.thickness!=None: result+=' 39\n%s\n'%parent.thickness
00151 if parent.extrusion!=None: result+='%s\n'%_point(parent.extrusion,200)
00152 return result
00153
00154
00155 class _Entities:
00156 """Base class to deal with composed objects."""
00157 def __dxf__(self):
00158 return []
00159
00160 def __str__(self):
00161 return ''.join([str(x) for x in self.__dxf__()])
00162
00163
00164 class _Collection(_Call):
00165 """Base class to expose entities methods to main object."""
00166 def __init__(self,entities=[]):
00167 self.entities=copy.copy(entities)
00168
00169 for attr in dir(self.entities):
00170 if attr[0]!='_':
00171 attrObject=getattr(self.entities,attr)
00172 if callable(attrObject):
00173 setattr(self,attr,attrObject)
00174
00175
00176
00177 BYBLOCK=0
00178 BYLAYER=256
00179
00180
00181 ANONYMOUS =1
00182 NON_CONSTANT_ATTRIBUTES =2
00183 XREF =4
00184 XREF_OVERLAY =8
00185 EXTERNAL =16
00186 RESOLVED =32
00187 REFERENCED =64
00188
00189
00190
00191 TOP_LEFT = 1
00192 TOP_CENTER = 2
00193 TOP_RIGHT = 3
00194 MIDDLE_LEFT = 4
00195 MIDDLE_CENTER = 5
00196 MIDDLE_RIGHT = 6
00197 BOTTOM_LEFT = 7
00198 BOTTOM_CENTER = 8
00199 BOTTOM_RIGHT = 9
00200
00201 LEFT_RIGHT = 1
00202 TOP_BOTTOM = 3
00203 BY_STYLE = 5
00204
00205 AT_LEAST = 1
00206 EXACT = 2
00207
00208
00209 CLOSED =1
00210 CURVE_FIT =2
00211 SPLINE_FIT =4
00212 POLYLINE_3D =8
00213 POLYGON_MESH =16
00214 CLOSED_N =32
00215 POLYFACE_MESH =64
00216 CONTINOUS_LINETYPE_PATTERN =128
00217
00218
00219
00220 LEFT = 0
00221 CENTER = 1
00222 RIGHT = 2
00223 ALIGNED = 3
00224 MIDDLE = 4
00225 FIT = 5
00226
00227 BASELINE = 0
00228 BOTTOM = 1
00229 MIDDLE = 2
00230 TOP = 3
00231
00232
00233
00234
00235 class Arc(_Entity):
00236 """Arc, angles in degrees."""
00237 def __init__(self,center=(0,0,0),radius=1,
00238 startAngle=0.0,endAngle=90,**common):
00239 """Angles in degrees."""
00240 _Entity.__init__(self,**common)
00241 self.center=center
00242 self.radius=radius
00243 self.startAngle=startAngle
00244 self.endAngle=endAngle
00245 def __str__(self):
00246 return ' 0\nARC\n%s%s\n 40\n%s\n 50\n%s\n 51\n%s\n'%\
00247 (self._common(),_point(self.center),
00248 self.radius,self.startAngle,self.endAngle)
00249
00250
00251 class Circle(_Entity):
00252 """Circle"""
00253 def __init__(self,center=(0,0,0),radius=1,**common):
00254 _Entity.__init__(self,**common)
00255 self.center=center
00256 self.radius=radius
00257 def __str__(self):
00258 return ' 0\nCIRCLE\n%s%s\n 40\n%s\n'%\
00259 (self._common(),_point(self.center),self.radius)
00260
00261
00262 class Face(_Entity):
00263 """3dface"""
00264 def __init__(self,points,**common):
00265 _Entity.__init__(self,**common)
00266 while len(points)<4:
00267 points.append(points[-1])
00268 self.points=points
00269
00270 def __str__(self):
00271 out = ' 0\n3DFACE\n%s%s\n' %(self._common(),_points(self.points))
00272
00273 return out
00274
00275
00276 class Insert(_Entity):
00277 """Block instance."""
00278 def __init__(self,name,point=(0,0,0),
00279 xscale=None,yscale=None,zscale=None,
00280 cols=None,colspacing=None,rows=None,rowspacing=None,
00281 rotation=None,
00282 **common):
00283 _Entity.__init__(self,**common)
00284 self.name=name
00285 self.point=point
00286 self.xscale=xscale
00287 self.yscale=yscale
00288 self.zscale=zscale
00289 self.cols=cols
00290 self.colspacing=colspacing
00291 self.rows=rows
00292 self.rowspacing=rowspacing
00293 self.rotation=rotation
00294
00295 def __str__(self):
00296 result=' 0\nINSERT\n 2\n%s\n%s%s\n'%\
00297 (self.name,self._common(),_point(self.point))
00298 if self.xscale!=None:result+=' 41\n%s\n'%self.xscale
00299 if self.yscale!=None:result+=' 42\n%s\n'%self.yscale
00300 if self.zscale!=None:result+=' 43\n%s\n'%self.zscale
00301 if self.rotation:result+=' 50\n%s\n'%self.rotation
00302 if self.cols!=None:result+=' 70\n%s\n'%self.cols
00303 if self.colspacing!=None:result+=' 44\n%s\n'%self.colspacing
00304 if self.rows!=None:result+=' 71\n%s\n'%self.rows
00305 if self.rowspacing!=None:result+=' 45\n%s\n'%self.rowspacing
00306 return result
00307
00308
00309 class Line(_Entity):
00310 """Line"""
00311 def __init__(self,points,**common):
00312 _Entity.__init__(self,**common)
00313 self.points=points
00314 def __str__(self):
00315 return ' 0\nLINE\n%s%s\n' %(
00316 self._common(), _points(self.points))
00317
00318
00319
00320 class PolyLine(_Entity):
00321 def __init__(self,points,org_point=[0,0,0],flag=0,width=None,**common):
00322
00323
00324
00325
00326 _Entity.__init__(self,**common)
00327 self.points=points
00328 self.org_point=org_point
00329 self.flag=flag
00330 self.polyface = False
00331 self.polyline2d = False
00332 self.faces = []
00333 self.width= None
00334 if self.flag & POLYFACE_MESH:
00335 self.polyface=True
00336 self.points=points[0]
00337 self.faces=points[1]
00338 self.p_count=len(self.points)
00339 self.f_count=len(self.faces)
00340 elif not self.flag & POLYLINE_3D:
00341 self.polyline2d = True
00342 if width:
00343 if type(width)!='list':
00344 width=[width,width]
00345 self.width=width
00346
00347 def __str__(self):
00348 result= ' 0\nPOLYLINE\n%s 70\n%s\n' %(self._common(),self.flag)
00349 result+=' 66\n1\n'
00350 result+='%s\n' %_point(self.org_point)
00351 if self.polyface:
00352 result+=' 71\n%s\n' %self.p_count
00353 result+=' 72\n%s\n' %self.f_count
00354 elif self.polyline2d:
00355 if self.width!=None: result+=' 40\n%s\n 41\n%s\n' %(self.width[0],self.width[1])
00356 for point in self.points:
00357 result+=' 0\nVERTEX\n'
00358 result+=' 8\n%s\n' %self.layer
00359 if self.polyface:
00360 result+='%s\n' %_point(point[0:3])
00361 result+=' 70\n192\n'
00362 elif self.polyline2d:
00363 result+='%s\n' %_point(point[0:2])
00364 if len(point)>4:
00365 width1, width2 = point[3], point[4]
00366 if width1!=None: result+=' 40\n%s\n' %width1
00367 if width2!=None: result+=' 41\n%s\n' %width2
00368 if len(point)==6:
00369 bulge = point[5]
00370 if bulge: result+=' 42\n%s\n' %bulge
00371 else:
00372 result+='%s\n' %_point(point[0:3])
00373 for face in self.faces:
00374 result+=' 0\nVERTEX\n'
00375 result+=' 8\n%s\n' %self.layer
00376 result+='%s\n' %_point(self.org_point)
00377 result+=' 70\n128\n'
00378 result+=' 71\n%s\n' %face[0]
00379 result+=' 72\n%s\n' %face[1]
00380 result+=' 73\n%s\n' %face[2]
00381 if len(face)==4: result+=' 74\n%s\n' %face[3]
00382 result+=' 0\nSEQEND\n'
00383 result+=' 8\n%s\n' %self.layer
00384 return result
00385
00386
00387 class Point(_Entity):
00388 """Point."""
00389 def __init__(self,points=None,**common):
00390 _Entity.__init__(self,**common)
00391 self.points=points
00392 def __str__(self):
00393 return ' 0\nPOINT\n%s%s\n' %(self._common(),
00394 _points(self.points)
00395 )
00396
00397
00398 class Solid(_Entity):
00399 """Colored solid fill."""
00400 def __init__(self,points=None,**common):
00401 _Entity.__init__(self,**common)
00402 self.points=points
00403 def __str__(self):
00404 return ' 0\nSOLID\n%s%s\n' %(self._common(),
00405 _points(self.points[:2]+[self.points[3],self.points[2]])
00406 )
00407
00408
00409
00410 class Dimension(_Entity):
00411 """Basic dimension entity"""
00412 def __init__(self,point,start,end,**common):
00413 _Entity.__init__(self,**common)
00414 self.points=[point,start,end]
00415 def __str__(self):
00416 result = ' 0\nDIMENSION\n%s' %(self._common())
00417 result+=' 3\nStandard\n'
00418 result+=' 70\n1\n'
00419 result+='%s\n' %_point(self.points[0])
00420 result+='%s\n' %_point(self.points[1],3)
00421 result+='%s\n' %_point(self.points[2],4)
00422 print result
00423 return result
00424
00425
00426 class Text(_Entity):
00427 """Single text line."""
00428 def __init__(self,text='',point=(0,0,0),alignment=None,
00429 flag=None,height=1,justifyhor=None,justifyver=None,
00430 rotation=None,obliqueAngle=None,style=None,xscale=None,**common):
00431 _Entity.__init__(self,**common)
00432 self.text=text
00433 self.point=point
00434 self.alignment=alignment
00435 self.flag=flag
00436 self.height=height
00437 self.justifyhor=justifyhor
00438 self.justifyver=justifyver
00439 self.rotation=rotation
00440 self.obliqueAngle=obliqueAngle
00441 self.style=style
00442 self.xscale=xscale
00443 def __str__(self):
00444 result= ' 0\nTEXT\n%s%s\n 40\n%s\n 1\n%s\n'%\
00445 (self._common(),_point(self.point),self.height,self.text)
00446 if self.rotation: result+=' 50\n%s\n'%self.rotation
00447 if self.xscale: result+=' 41\n%s\n'%self.xscale
00448 if self.obliqueAngle: result+=' 51\n%s\n'%self.obliqueAngle
00449 if self.style: result+=' 7\n%s\n'%self.style
00450 if self.flag: result+=' 71\n%s\n'%self.flag
00451 if self.justifyhor: result+=' 72\n%s\n'%self.justifyhor
00452 if self.alignment: result+='%s\n'%_point(self.alignment,1)
00453 if self.justifyver: result+=' 73\n%s\n'%self.justifyver
00454 return result
00455
00456
00457 class Mtext(Text):
00458 """Surrogate for mtext, generates some Text instances."""
00459 def __init__(self,text='',point=(0,0,0),width=250,spacingFactor=1.5,down=0,spacingWidth=None,**options):
00460 Text.__init__(self,text=text,point=point,**options)
00461 if down:spacingFactor*=-1
00462 self.spacingFactor=spacingFactor
00463 self.spacingWidth=spacingWidth
00464 self.width=width
00465 self.down=down
00466 def __str__(self):
00467 texts=self.text.replace('\r\n','\n').split('\n')
00468 if not self.down:texts.reverse()
00469 result=''
00470 x=y=0
00471 if self.spacingWidth:spacingWidth=self.spacingWidth
00472 else:spacingWidth=self.height*self.spacingFactor
00473 for text in texts:
00474 while text:
00475 result+='%s\n'%Text(text[:self.width],
00476 point=(self.point[0]+x*spacingWidth,
00477 self.point[1]+y*spacingWidth,
00478 self.point[2]),
00479 alignment=self.alignment,flag=self.flag,height=self.height,
00480 justifyhor=self.justifyhor,justifyver=self.justifyver,
00481 rotation=self.rotation,obliqueAngle=self.obliqueAngle,
00482 style=self.style,xscale=self.xscale,parent=self
00483 )
00484 text=text[self.width:]
00485 if self.rotation:x+=1
00486 else:y+=1
00487 return result[1:]
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531 class Block(_Collection):
00532 """Use list methods to add entities, eg append."""
00533 def __init__(self,name,layer='0',flag=0,base=(0,0,0),entities=[]):
00534 self.entities=copy.copy(entities)
00535 _Collection.__init__(self,entities)
00536 self.layer=layer
00537 self.name=name
00538 self.flag=0
00539 self.base=base
00540 def __str__(self):
00541 e=''.join([str(x)for x in self.entities])
00542 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'%\
00543 (self.layer,self.name.upper(),self.flag,_point(self.base),self.name.upper(),e)
00544
00545
00546 class Layer(_Call):
00547 """Layer"""
00548 def __init__(self,name='pydxf',color=7,lineType='continuous',flag=64):
00549 self.name=name
00550 self.color=color
00551 self.lineType=lineType
00552 self.flag=flag
00553 def __str__(self):
00554 return ' 0\nLAYER\n 2\n%s\n 70\n%s\n 62\n%s\n 6\n%s\n'%\
00555 (self.name.upper(),self.flag,self.color,self.lineType)
00556
00557
00558 class LineType(_Call):
00559 """Custom linetype"""
00560 def __init__(self,name='CONTINUOUS',description='Solid line',elements=[0.0],flag=0):
00561 self.name=name
00562 self.description=description
00563 self.elements=copy.copy(elements)
00564 self.flag=flag
00565 def __str__(self):
00566 result = ' 0\nLTYPE\n 2\n%s\n 70\n%s\n 3\n%s\n 72\n65\n'%\
00567 (self.name.upper(),self.flag,self.description)
00568 if self.elements:
00569 elements = ' 73\n%s\n' %(len(self.elements)-1)
00570 elements += ' 40\n%s\n' %(self.elements[0])
00571 for e in self.elements[1:]:
00572 elements += ' 49\n%s\n' %e
00573 result += elements
00574 return result
00575
00576
00577
00578 class Style(_Call):
00579 """Text style"""
00580 def __init__(self,name='standard',flag=0,height=0,widthFactor=1.0,obliqueAngle=0.0,
00581 mirror=0,lastHeight=1,font='arial.ttf',bigFont=''):
00582 self.name=name
00583 self.flag=flag
00584 self.height=height
00585 self.widthFactor=widthFactor
00586 self.obliqueAngle=obliqueAngle
00587 self.mirror=mirror
00588 self.lastHeight=lastHeight
00589 self.font=font
00590 self.bigFont=bigFont
00591 def __str__(self):
00592 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'%\
00593 (self.name.upper(),self.flag,self.flag,self.widthFactor,
00594 self.obliqueAngle,self.mirror,self.lastHeight,
00595 self.font.upper(),self.bigFont.upper())
00596
00597
00598 class VPort(_Call):
00599 def __init__(self,name,flag=0,
00600 leftBottom=(0.0,0.0),
00601 rightTop=(1.0,1.0),
00602 center=(0.5,0.5),
00603 snap_base=(0.0,0.0),
00604 snap_spacing=(0.1,0.1),
00605 grid_spacing=(0.1,0.1),
00606 direction=(0.0,0.0,1.0),
00607 target=(0.0,0.0,0.0),
00608 height=1.0,
00609 ratio=1.0,
00610 lens=50,
00611 frontClipping=0,
00612 backClipping=0,
00613 snap_rotation=0,
00614 twist=0,
00615 mode=0,
00616 circle_zoom=100,
00617 fast_zoom=1,
00618 ucsicon=1,
00619 snap_on=0,
00620 grid_on=0,
00621 snap_style=0,
00622 snap_isopair=0
00623 ):
00624 self.name=name
00625 self.flag=flag
00626 self.leftBottom=leftBottom
00627 self.rightTop=rightTop
00628 self.center=center
00629 self.snap_base=snap_base
00630 self.snap_spacing=snap_spacing
00631 self.grid_spacing=grid_spacing
00632 self.direction=direction
00633 self.target=target
00634 self.height=float(height)
00635 self.ratio=float(ratio)
00636 self.lens=float(lens)
00637 self.frontClipping=float(frontClipping)
00638 self.backClipping=float(backClipping)
00639 self.snap_rotation=float(snap_rotation)
00640 self.twist=float(twist)
00641 self.mode=mode
00642 self.circle_zoom=circle_zoom
00643 self.fast_zoom=fast_zoom
00644 self.ucsicon=ucsicon
00645 self.snap_on=snap_on
00646 self.grid_on=grid_on
00647 self.snap_style=snap_style
00648 self.snap_isopair=snap_isopair
00649 def __str__(self):
00650 output = [' 0', 'VPORT',
00651 ' 2', self.name,
00652 ' 70', self.flag,
00653 _point(self.leftBottom),
00654 _point(self.rightTop,1),
00655 _point(self.center,2),
00656 _point(self.snap_base,3),
00657 _point(self.snap_spacing,4),
00658 _point(self.grid_spacing,5),
00659 _point(self.direction,6),
00660 _point(self.target,7),
00661 ' 40', self.height,
00662 ' 41', self.ratio,
00663 ' 42', self.lens,
00664 ' 43', self.frontClipping,
00665 ' 44', self.backClipping,
00666 ' 50', self.snap_rotation,
00667 ' 51', self.twist,
00668 ' 71', self.mode,
00669 ' 72', self.circle_zoom,
00670 ' 73', self.fast_zoom,
00671 ' 74', self.ucsicon,
00672 ' 75', self.snap_on,
00673 ' 76', self.grid_on,
00674 ' 77', self.snap_style,
00675 ' 78', self.snap_isopair
00676 ]
00677
00678 output_str = ''
00679 for s in output:
00680 output_str += '%s\n' %s
00681 return output_str
00682
00683
00684
00685
00686 class View(_Call):
00687 def __init__(self,name,flag=0,
00688 width=1,
00689 height=1,
00690 center=(0.5,0.5),
00691 direction=(0,0,1),
00692 target=(0,0,0),
00693 lens=50,
00694 frontClipping=0,
00695 backClipping=0,
00696 twist=0,mode=0
00697 ):
00698 self.name=name
00699 self.flag=flag
00700 self.width=float(width)
00701 self.height=float(height)
00702 self.center=center
00703 self.direction=direction
00704 self.target=target
00705 self.lens=float(lens)
00706 self.frontClipping=float(frontClipping)
00707 self.backClipping=float(backClipping)
00708 self.twist=float(twist)
00709 self.mode=mode
00710 def __str__(self):
00711 output = [' 0', 'VIEW',
00712 ' 2', self.name,
00713 ' 70', self.flag,
00714 ' 40', self.height,
00715 _point(self.center),
00716 ' 41', self.width,
00717 _point(self.direction,1),
00718 _point(self.target,2),
00719 ' 42', self.lens,
00720 ' 43', self.frontClipping,
00721 ' 44', self.backClipping,
00722 ' 50', self.twist,
00723 ' 71', self.mode
00724 ]
00725 output_str = ''
00726 for s in output:
00727 output_str += '%s\n' %s
00728 return output_str
00729
00730
00731 def ViewByWindow(name,leftBottom=(0,0),rightTop=(1,1),**options):
00732 width=abs(rightTop[0]-leftBottom[0])
00733 height=abs(rightTop[1]-leftBottom[1])
00734 center=((rightTop[0]+leftBottom[0])*0.5,(rightTop[1]+leftBottom[1])*0.5)
00735 return View(name=name,width=width,height=height,center=center,**options)
00736
00737
00738
00739 class Drawing(_Collection):
00740 """Dxf drawing. Use append or any other list methods to add objects."""
00741 def __init__(self,insbase=(0.0,0.0,0.0),extmin=(0.0,0.0,0.0),extmax=(0.0,0.0,0.0),
00742 layers=[Layer()],linetypes=[LineType()],styles=[Style()],blocks=[],
00743 views=[],vports=[],entities=None,fileName='test.dxf'):
00744
00745 if not entities:
00746 entities=[]
00747 _Collection.__init__(self,entities)
00748 self.insbase=insbase
00749 self.extmin=extmin
00750 self.extmax=extmax
00751 self.layers=copy.copy(layers)
00752 self.linetypes=copy.copy(linetypes)
00753 self.styles=copy.copy(styles)
00754 self.views=copy.copy(views)
00755 self.vports=copy.copy(vports)
00756 self.blocks=copy.copy(blocks)
00757 self.fileName=fileName
00758
00759
00760 self.acadver=' 9\n$ACADVER\n 1\nAC1009\n'
00761 """DXF AutoCAD-Release format codes
00762 AC1021 2008, 2007
00763 AC1018 2006, 2005, 2004
00764 AC1015 2002, 2000i, 2000
00765 AC1014 R14,14.01
00766 AC1012 R13
00767 AC1009 R12,11
00768 AC1006 R10
00769 AC1004 R9
00770 AC1002 R2.6
00771 AC1.50 R2.05
00772 """
00773
00774 def _name(self,x):
00775 """Helper function for self._point"""
00776 return ' 9\n$%s\n' %x.upper()
00777
00778 def _point(self,name,x):
00779 """Point setting from drawing like extmin,extmax,..."""
00780 return '%s%s' %(self._name(name),_point(x))
00781
00782 def _section(self,name,x):
00783 """Sections like tables,blocks,entities,..."""
00784 if x: xstr=''.join(x)
00785 else: xstr=''
00786 return ' 0\nSECTION\n 2\n%s\n%s 0\nENDSEC\n'%(name.upper(),xstr)
00787
00788 def _table(self,name,x):
00789 """Tables like ltype,layer,style,..."""
00790 if x: xstr=''.join(x)
00791 else: xstr=''
00792 return ' 0\nTABLE\n 2\n%s\n 70\n%s\n%s 0\nENDTAB\n'%(name.upper(),len(x),xstr)
00793
00794 def __str__(self):
00795 """Returns drawing as dxf string."""
00796 header=[self.acadver]+[self._point(attr,getattr(self,attr))+'\n' for attr in _HEADER_POINTS]
00797 header=self._section('header',header)
00798
00799 tables=[self._table('vport',[str(x) for x in self.vports]),
00800 self._table('ltype',[str(x) for x in self.linetypes]),
00801 self._table('layer',[str(x) for x in self.layers]),
00802 self._table('style',[str(x) for x in self.styles]),
00803 self._table('view',[str(x) for x in self.views]),
00804 ]
00805 tables=self._section('tables',tables)
00806
00807 blocks=self._section('blocks',[str(x) for x in self.blocks])
00808
00809 entities=self._section('entities',[str(x) for x in self.entities])
00810
00811 all=''.join([header,tables,blocks,entities,' 0\nEOF\n'])
00812 return all
00813
00814 def saveas(self,fileName):
00815 self.fileName=fileName
00816 self.save()
00817
00818 def save(self):
00819 test=open(self.fileName,'w')
00820 test.write(str(self))
00821 test.close()
00822
00823
00824
00825
00826 class Rectangle(_Entity):
00827 """Rectangle, creates lines."""
00828 def __init__(self,point=(0,0,0),width=1,height=1,solid=None,line=1,**common):
00829 _Entity.__init__(self,**common)
00830 self.point=point
00831 self.width=width
00832 self.height=height
00833 self.solid=solid
00834 self.line=line
00835 def __str__(self):
00836 result=''
00837 points=[self.point,(self.point[0]+self.width,self.point[1],self.point[2]),
00838 (self.point[0]+self.width,self.point[1]+self.height,self.point[2]),
00839 (self.point[0],self.point[1]+self.height,self.point[2]),self.point]
00840 if self.solid:
00841 result+= Solid(points=points[:-1],parent=self.solid)
00842 if self.line:
00843 for i in range(4):
00844 result+= Line(points=[points[i],points[i+1]],parent=self)
00845 return result[1:]
00846
00847
00848 class LineList(_Entity):
00849 """Like polyline, but built of individual lines."""
00850 def __init__(self,points=[],org_point=[0,0,0],closed=0,**common):
00851 _Entity.__init__(self,**common)
00852 self.closed=closed
00853 self.points=copy.copy(points)
00854 def __str__(self):
00855 if self.closed:points=self.points+[self.points[0]]
00856 else: points=self.points
00857 result=''
00858 for i in range(len(points)-1):
00859 result+= Line(points=[points[i],points[i+1]],parent=self)
00860 return result[1:]
00861
00862
00863 def test():
00864
00865 b=Block('test')
00866 b.append(Solid(points=[(0,0,0),(1,0,0),(1,1,0),(0,1,0)],color=1))
00867 b.append(Arc(center=(1,0,0),color=2))
00868
00869
00870 d=Drawing()
00871
00872 d.blocks.append(b)
00873 d.styles.append(Style())
00874 d.views.append(View('Normal'))
00875 d.views.append(ViewByWindow('Window',leftBottom=(1,0),rightTop=(2,1)))
00876
00877
00878 d.append(Circle(center=(1,1,0),color=3))
00879 d.append(Face(points=[(0,0,0),(1,0,0),(1,1,0),(0,1,0)],color=4))
00880 d.append(Insert('test',point=(3,3,3),cols=5,colspacing=2))
00881 d.append(Line(points=[(0,0,0),(1,1,1)]))
00882 d.append(Mtext('Click on Ads\nmultiple lines with mtext',point=(1,1,1),color=5,rotation=90))
00883 d.append(Text('Please donate!',point=(3,0,1)))
00884
00885 d.append(Solid(points=[(4,4,0),(5,4,0),(7,8,0),(9,9,0)],color=3))
00886
00887
00888
00889 d.saveas('test.dxf')
00890
00891
00892 if __name__=='__main__':
00893 if not copy:
00894 Draw.PupMenu('Error%t|This script requires a full python install')
00895 else: test()
00896