-
Notifications
You must be signed in to change notification settings - Fork 0
/
dxf_frame_generator.py
131 lines (107 loc) · 4.04 KB
/
dxf_frame_generator.py
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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
"""DXF Frame Generator.
This module generates DXF files for laser cutting custom sized frames, which
can be easily manufactured at the nearest FabLab.
Example
-------
Generate a frame that fits an A4 sized sheet:
$ python -m dxf_frame_generator 210 297
This will create a 'frame_210x297.dxf' file on the current working directory.
"""
import os.path
import ezdxf
class Frame():
"""Frame generator class."""
dwg = ezdxf.new('R2010')
dwg.layers.new(name='CUT', dxfattribs={'color': 7})
msp = dwg.modelspace()
front = 25 # width of the front sides
back = 15 # width of the back sides
offset = 0 # distance between front and back patterns
def __init__(self, width: int, height: int):
"""Initialize a new Frame instance."""
if width > height:
width, height = height, width
self.width = width
self.height = height
def draw(self):
"""Draw the frame."""
outer_width = 2 * self.back + self.width
outer_height = 2 * self.back + self.height
self._draw_back(outer_width, outer_height)
self._draw_front(outer_width, outer_height)
self._save()
def _draw_back(self, outer_width, outer_height):
"""Draw the back pattern of a frame, starting on origin (0, 0)."""
rectangles = [
[
(0, 0),
(outer_width, 0),
(outer_width, outer_height),
(0, outer_height)
],
[
(self.back, self.back),
(outer_width - self.back, self.back),
(outer_width - self.back, outer_height - self.back),
(self.back, outer_height - self.back)
]
]
for rect in rectangles:
self.msp.add_lwpolyline(
rect, dxfattribs={'layer': 'CUT', 'closed': True})
radius = self.back / 4
circles = [
(self.back / 2, self.back / 2),
(self.back / 2, outer_height / 2),
(self.back / 2, outer_height - self.back / 2),
(outer_width / 2, outer_height - self.back / 2),
(outer_width / 2, self.back / 2),
(outer_width - self.back / 2, self.back / 2),
(outer_width - self.back / 2, outer_height / 2),
(outer_width - self.back / 2, outer_height - self.back / 2)
]
for center in circles:
self.msp.add_circle(center, radius, dxfattribs={'layer': 'CUT'})
def _draw_front(self, outer_width, outer_height):
"""Draw the front pattern of a frame, starting from offset point."""
offset = outer_width + self.offset
rectangles = [
[
(offset, 0),
(offset + outer_width, 0),
(offset + outer_width, outer_height),
(offset, outer_height)
],
[
(offset + self.front, self.front),
(offset + outer_width - self.front, self.front),
(offset + outer_width - self.front, outer_height - self.front),
(offset + self.front, outer_height - self.front)
]
]
for rect in rectangles:
self.msp.add_lwpolyline(
rect, dxfattribs={'layer': 'CUT', 'closed': True})
def _save(self):
"""Save frame to filesystem."""
filename = f'frame_{self.width}x{self.height}.dxf'
self.dwg.saveas(filename)
print(os.path.abspath(filename), end='')
def run():
"""Draw a frame from CLI arguments."""
from argparse import ArgumentParser
parser = ArgumentParser(
description="Generate frames for digital fabrication.")
parser.add_argument(
"width", metavar="W", type=int,
help="an integer for the frame's inner width, in milimeters."
)
parser.add_argument(
"height", metavar="H", type=int,
help="an integer for the frame's inner height, in milimeters."
)
args = parser.parse_args()
f = Frame(args.width, args.height)
f.draw()
if __name__ == '__main__':
run()