/
dxfsanitizer
executable file
·157 lines (143 loc) · 7.31 KB
/
dxfsanitizer
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
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
#!/usr/bin/python3
import ezdxf
import argparse
from ezdxf.math import Vector, BSpline, BSplineClosed, bulge_to_arc
from math import degrees
parser = argparse.ArgumentParser(description='DXF sanitizer for laser cutter')
parser.add_argument('source')
parser.add_argument('target')
parser.add_argument('--debug', action='store_true')
parser.add_argument('--ignore', help="ignore unknown DXF types", action='store_true')
parser.add_argument('--layer', '-l', help="layer to export (can be used multiple times)", action='append', default=[])
args = parser.parse_args()
if len(args.layer) == 0:
args.layer.append("0")
DEBUG = print if args.debug else lambda x : None
source = ezdxf.readfile(args.source)
target = ezdxf.new('AC1015')
target.header['$AUNITS'] = source.header['$AUNITS'] if '$AUNITS' in source.header else 0
def add_line(start, end, color):
DEBUG("LINE start:%s end:%s color:%s" % (start, end, color))
target.modelspace().add_line(start, end, dxfattribs={'color': color})
def add_circle(center, radius, color):
DEBUG('CIRCLE center:%s radius:%s color:%s' % (center, radius, color))
target.modelspace().add_circle(center, radius, dxfattribs={'color': color})
def add_arc(center, radius, start_angle, end_angle, color):
DEBUG('ARC center:%s radius:%s start_angle:%s end_angle:%s color:%s' % (center, radius, start_angle, end_angle, color))
target.modelspace().add_arc(center, radius, start_angle, end_angle, dxfattribs={'color': color})
def color_of(entity):
return source.layers.get(entity.dxf.layer).dxf.color if entity.dxf.color == 256 else entity.dxf.color
entities = [ entity for entity in source.entities ]
for entity in entities:
if entity.dxf.layer not in args.layer:
continue
elif entity.dxftype() == 'LINE':
start = entity.dxf.start
end = entity.dxf.end
color = color_of(entity)
add_line(start, end, color)
elif entity.dxftype() == 'CIRCLE':
center = entity.dxf.center
radius = entity.dxf.radius
color = source.layers.get(entity.dxf.layer).dxf.color if entity.dxf.color == 256 else entity.dxf.color
add_circle(center, radius, color)
elif entity.dxftype() == 'ARC':
center = entity.dxf.center
radius = entity.dxf.radius
start_angle = entity.dxf.start_angle
end_angle = entity.dxf.end_angle
color = color_of(entity)
add_arc(center, radius, start_angle, end_angle, color)
elif entity.dxftype() == 'LWPOLYLINE':
DEBUG('= LWPOLYLINE =')
points = list(entity)
color = color_of(entity)
if entity.closed:
points.append(points[0])
p1 = points.pop(0)
while len(points) > 0:
p2 = points.pop(0)
if p1[4] != 0:
( center, start_angle, end_angle, radius ) = bulge_to_arc(p1[0:2], p2[0:2], p1[4])
add_arc(center, radius, degrees(start_angle), degrees(end_angle), color)
else:
start = p1[0:2]
end = p2[0:2]
add_line(start, end, color)
p1 = p2
DEBUG('= END LWPOLYLINE =')
elif entity.dxftype() == 'SPLINE':
DEBUG('= SPLINE =')
control_points = entity.control_points
knots = entity.knots
weights = entity.weights
order = entity.dxf.degree + 1
color = color_of(entity)
segments = len(control_points) * 20
if entity.closed:
points = list(BSplineClosed(control_points[:-entity.dxf.degree], order).approximate(segments))
else:
points = list(BSpline(control_points, order).approximate(segments))
p1 = points.pop(0)
while len(points) > 0:
p2 = points.pop(0)
add_line(p1, p2, color)
p1 = p2
DEBUG('= END SPLINE =')
elif entity.dxftype() == 'INSERT':
DEBUG('= INSERT "%s" at %s scale:%s =' % (entity.dxf.name, entity.dxf.insert, entity.dxf.xscale))
block = source.blocks.get(entity.dxf.name)
assert entity.dxf.xscale == entity.dxf.yscale, "scale with aspect ration != 1 is not supported"
assert entity.dxf.row_count != 1, "row_count is not supported"
assert entity.dxf.column_count != 1, "column_count is not supported"
for block_entity in block:
if block_entity.dxftype() == 'LINE':
start = Vector(block_entity.dxf.start).rot_z_deg(entity.dxf.rotation) * entity.dxf.xscale + Vector(entity.dxf.insert)
end = Vector(block_entity.dxf.end).rot_z_deg(entity.dxf.rotation) * entity.dxf.xscale + Vector(entity.dxf.insert)
color = color_of(entity)
add_line(start, end, color)
elif block_entity.dxftype() == 'CIRCLE':
center = Vector(block_entity.dxf.center).rot_z_deg(entity.dxf.rotation) * entity.dxf.xscale + Vector(entity.dxf.insert)
radius = block_entity.dxf.radius * entity.dxf.xscale
color = color_of(entity)
add_circle(center, radius, color)
elif block_entity.dxftype() == 'ARC':
center = Vector(block_entity.dxf.center).rot_z_deg(entity.dxf.rotation) * entity.dxf.xscale + Vector(entity.dxf.insert)
radius = block_entity.dxf.radius * entity.dxf.xscale
start_angle = block_entity.dxf.start_angle + entity.dxf.rotation
end_angle = block_entity.dxf.end_angle + entity.dxf.rotation
color = color_of(entity)
add_arc(center, radius, start_angle, end_angle, color)
elif block_entity.dxftype() == 'LWPOLYLINE':
DEBUG('== LWPOLYLINE ==')
points = list(block_entity)
color = color_of(entity)
if entity.closed:
points.append(points[0])
p1 = points.pop(0)
while len(points) > 0:
p2 = points.pop(0)
if start[4] != 0:
( center, start_angle, end_angle, radius ) = bulge_to_arc(p1[0:2], p2[0:2], p1[4])
center = Vector(center).rot_z_deg(entity.dxf.rotation) * entity.dxf.xscale + Vector(entity.dxf.insert)
radius = radius * entity.dxf.xscale
start_angle = degrees(start_angle) + entity.dxf.rotation
end_angle = degrees(end_angle) + entity.dxf.rotation
add_arc(center, radius, start_angle, end_angle, color)
else:
start = Vector(p1[0:2]).rot_z_deg(entity.dxf.rotation) * entity.dxf.xscale + Vector(entity.dxf.insert)
end = Vector(p2[0:2]).rot_z_deg(entity.dxf.rotation) * entity.dxf.xscale + Vector(entity.dxf.insert)
add_line(start, end, color)
p1 = p2
else:
if args.ignore:
DEBUG('%s ignored' % (block_entity.dxftype()))
else:
raise Exception('DXF type %s is not supported' % (block_entity.dxftype()))
DEBUG('= END INSERT =')
else:
if args.ignore:
DEBUG('%s ignored' % (entity.dxftype()))
else:
raise Exception('DXF type %s is not supported' % (entity.dxftype()))
target.saveas(args.target)