forked from mikedh/trimesh
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtest_dxf.py
191 lines (153 loc) · 6.45 KB
/
test_dxf.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
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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
try:
from . import generic as g
except BaseException:
import generic as g
class DXFTest(g.unittest.TestCase):
def test_dxf(self):
# get a path we can write
temp_name = g.tempfile.NamedTemporaryFile(
suffix='.dxf', delete=False).name
# split drawings into single body parts
splits = []
for d in g.get_2D():
s = d.split()
# check area of split result vs source
assert g.np.isclose(sum(i.area for i in s),
d.area)
splits.append(s)
# export the drawing to the file
d.export(file_obj=temp_name)
# export to a string
text = d.export(file_type='dxf')
# DXF files are always pairs of lines
assert (len(str.splitlines(str(text))) % 2) == 0
# reload the file by name and by stream
rc = [g.trimesh.load(temp_name),
g.trimesh.load(g.io_wrap(text),
file_type='dxf')]
# compare reloaded with original
for r in rc:
assert g.np.isclose(r.area, d.area)
assert g.np.isclose(r.length, d.length)
assert len(r.entities) == len(d.entities)
single = g.np.hstack(splits)
for p in single:
p.vertices /= p.scale
# make sure exporting by name works
# use tempfile to avoid dumping file in
# our working directory
p.export(temp_name)
r = g.trimesh.load(temp_name)
ratio = abs(p.length - r.length) / p.length
if ratio > .01:
g.log.error('perimeter ratio on export %s wrong! %f %f %f',
p.metadata['file_name'],
p.length,
r.length,
ratio)
raise ValueError('perimeter ratio too large ({}) on {}'.format(
ratio,
p.metadata['file_name']))
def test_spline(self):
d = g.get_mesh('2D/cycloidal.dxf')
assert len(d.entities) == 1
assert type(d.entities[0]).__name__ == 'BSpline'
# export to dxf and wrap as a file object
e = g.trimesh.util.wrap_as_stream(d.export(file_type='dxf'))
# reconstitute drawing
r = g.trimesh.load(e, file_type='dxf')
# make sure reconstituted drawing is the same as the source
assert len(r.entities) == 1
assert type(r.entities[0]).__name__ == 'BSpline'
assert g.np.isclose(r.area, d.area)
assert len(d.entities[0].points) == len(r.entities[0].points)
assert len(d.entities[0].knots) == len(r.entities[0].knots)
def test_versions(self):
"""
DXF files have a bajillion versions, so test against
the same files saved in multiple versions by 2D CAD
packages.
Version test files are named things like:
ae.r14a.dxf: all entity types, R14 ASCII DXF
uc.2007b.dxf: unit square, R2007 binary DXF
"""
# directory where multiple versions of DXF are
dir_versions = g.os.path.join(g.dir_2D, 'versions')
# load the different versions
paths = {}
for f in g.os.listdir(dir_versions):
# full path including directory
ff = g.os.path.join(dir_versions, f)
try:
paths[f] = g.trimesh.load(ff)
except ValueError as E:
# something like 'r14a' for ascii
# and 'r14b' for binary
version = f.split('.')[-2]
# we should only get ValueErrors on binary DXF
assert version[-1] == 'b'
print(E, f)
# group drawings which have the same geometry
# but exported in different revisions of the DXF format
groups = g.collections.defaultdict(list)
for k in paths.keys():
# the first string before a period is the drawing name
groups[k.split('.')[0]].append(k)
# loop through each group of the same drawing
for k, group in groups.items():
# get the total length of every entity
L = [paths[i].length for i in group]
L = g.np.array(L, dtype=g.np.float64)
# make sure all versions have consistent length
assert g.np.allclose(L, L.mean(), rtol=.01)
# count the number of entities in the path
# this should be the same for every version
E = g.np.array(
[len(paths[i].entities) for i in group],
dtype=g.np.int64)
assert E.ptp() == 0
def test_bulge(self):
"""
Test bulged polylines which are polylines with
implicit arcs.
"""
# get a drawing with bulged polylines
p = g.get_mesh('2D/LM2.dxf')
# count the number of unclosed arc entities
# this drawing only has polylines with bulge
spans = [e.center(p.vertices)['span']
for e in p.entities if
type(e).__name__ == 'Arc' and
not e.closed]
# should have only one outer loop
assert len(p.root) == 1
# should have 6 partial arcs from bulge
assert len(spans) == 6
# all arcs should be 180 degree slot end caps
assert g.np.allclose(spans, g.np.pi)
def test_text(self):
# load file with a single text entity
original = g.get_mesh('2D/text.dxf')
# export then reload
roundtrip = g.trimesh.load(
file_obj=g.io_wrap(original.export(file_type='dxf')),
file_type='dxf')
for d in [original, roundtrip]:
# should contain a single Text entity
assert len(d.entities) == 1
# shouldn't crash anything
assert len(d.polygons_closed) == 0
assert len(d.polygons_full) == 0
assert len(d.discrete) == 0
assert len(d.paths) == 0
# make sure it preserved case and special chars
assert d.entities[0].text == "HEY WHAT's poppin"
# height should 1.0
assert g.np.isclose(d.entities[0].height, 1.0)
# get the 2D rotation of the text
angle = d.entities[0].angle(d.vertices)
# angle should be 30 degrees
assert g.np.isclose(angle, g.np.radians(30.0))
if __name__ == '__main__':
g.trimesh.util.attach_to_log()
g.unittest.main()