#!/usr/bin/env python
from numpy import *
'''Class for outputting dxf files from python.
-Dustin Kleckner c.2012, Noah Mitchell 2017
'''
[docs]class DXF:
"""Class for handling dxf files using python. DXF is a vector graphics format widely used in CAD applications."""
def __init__(self):
"""Initialize the dxf instance, with attributes 'contents' 'closing' and 'preview'"""
self.contents = [0, 'SECTION', 2, 'ENTITIES']
self.closing = [0, 'ENDSEC', 0, 'EOF']
self.preview = []
[docs] def save(self, fn):
"""Output the dxf instance to a dxf file"""
f = open(fn, 'wt')
f.write('\n'.join(map(str, self.contents + self.closing)))
[docs] def line(self, x0, y0, x1, y1, layer='0'):
"""Create a line segment in the dxf instance
Parameters
----------
x0 : float
starting x coordinate for lineseg
y0 : float
starting y coordinate for lineseg
x1 : float
ending x coordinate for lineseg
y1 : float
ending y coordinate for lineseg
layer : str (default='0')
which layer of the dxf vector graphics image to add line to
"""
self.contents += [0, 'LINE', 8, layer, 10, x0, 20, y0, 11, x1, 21, y1]
self.preview.append(array([(x0, y0), (x1, y1)]))
[docs] def polyline(self, X, layer='0', closed=False):
"""Create a sequence of line segments in the dxf instance
Parameters
----------
X : length N list of length 2 lists of floats or N x 2 float array
the sequence of points for which to create linesegments, in order
layer : str (default='0')
which layer of the dxf vector graphics image to add line to
closed : bool
whether to connect X[-1] to X[0] as a lineseg
"""
X = asarray(X)
for i, x in enumerate(X):
ip = i + 1
if ip == len(X):
if closed: ip = 0
else: break
xp = X[ip]
self.line(x[0], x[1], xp[0], xp[1], layer)
if closed:
X = vstack([X, X[:1]])
self.preview.append(X)
[docs] def circle(self, X, r, layer='0', preview_points=200):
"""Create a circle in the dxf instance
Parameters
----------
X : length 2 list of floats or 2 x 1 float array
the center point for the circle to create
r : float
the radius of the circle
layer : str (default='0')
which layer of the dxf vector graphics image to add line to
preview_points : int
how many points with which to approximate the circle in the preview (the actual dxf file has a true vector graphics circle)
"""
self.contents += [0, 'CIRCLE', 8, layer, 10, X[0], 20, X[1], 40, r]
phi = arange(preview_points+1) * 2*pi / preview_points
self.preview.append(X + r * array([cos(phi), sin(phi)]).T)
[docs] def plot_preview(self, show=True):
"""Plot the contents of the dxf instance
Parameters
----------
show : bool
whether to render the figure showing the dxf contents
"""
import pylab
for line in self.preview:
pylab.plot(line[:, 0], line[:, 1], '-k')
pylab.gca().set_aspect('equal')
if show: pylab.show()
if __name__ == '__main__':
inch = 25.4
dxf = DXF()
#dxf.polyline(5 * circle, closed=True)
dxf.circle([0, 0], 2.5*inch)
dxf.circle([5*inch, 0], 2.5*inch)
for phi in arange(8) * 2*pi / 8:
dxf.circle(array([cos(phi), sin(phi)]) * 2.25 * inch, 0.08 * inch)
dxf.circle((array([cos(phi), sin(phi)]) * 2.25 + (5, 0)) * inch, 0.08 * inch)
N = 500
phi = arange(N) * 2 * pi / N
circle = array((cos(phi), sin(phi))).T
dxf.polyline(circle * (25 + 25/4.*cos(3*phi).reshape((N, 1))), closed=True)
dxf.circle([5*inch -30, 0], 15)
dxf.circle([5*inch +30, 0], 15)
#dxf.circle([0, 0], 2*inch)
dxf.plot_preview()
#dxf.save('two_vortex_masks.dxf')