#@PydevCodeAnalysisIgnore
#(c)www.stani.be (read __doc__ for more information)
__version__ = """v1.2 (11/16/08)"""
__author__ = "www.stani.be"
__license__ = "GPL"
__url__ = "http://www.stani.be/python/sdxf"
__doc__ = \
"""SDXF - Stani's DXF
Python library to generate dxf drawings
Copyright %s
Version %s
License %s
Homepage %s
Library by Stani, whose website is now defunct.
Modifications by Kelly Farrell (http://www.kellbot.com)
to support LWPOLYLINE.
""" % \
(__author__,__version__,__license__,__url__)
# TODO: support for Numeric/Numarray for speeding up
#_______________________________________________________________________________
import copy
####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,x[i]) for i in range(len(x))])
def _points(p):
"""Convert a list of tuples to dxf points"""
return [_point(p[i],i)for i in range(len(p))]
#---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)
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