-
Notifications
You must be signed in to change notification settings - Fork 0
/
iges.py
407 lines (338 loc) · 14.6 KB
/
iges.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
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
from tqdm import tqdm
from entity import Entity
import geometry
try:
import pyvista
from pyvista._vtk import vtkAppendPolyData
except ImportError:
pass
class Iges():
"""pyiges.Iges object
Parameters
----------
filename : str
Filename of an IGES file.
Examples
--------
>>> import pyiges
>>> from pyiges import examples
>>> iges = pyiges.read(examples.impeller)
pyiges.Iges object
Description:
Number of Entities: 4615
"""
def __init__(self, filename):
self._read(filename)
self._desc = ''
def entities(self):
"""Return a list of all entities
Examples
--------
>>> iges.entities
[<pyiges.geometry.Point at 0x7f7056069c10>,
<pyiges.geometry.Point at 0x7f7056069790>,
<pyiges.geometry.Point at 0x7f7056069a50>,
<pyiges.geometry.Point at 0x7f7056069b10>,
<pyiges.entity.Entity at 0x7f7056069910>]
"""
return self._entities
def to_vtk(self, lines=True, bsplines=True,
surfaces=True, points=True, delta=0.025, merge=True,
progress=tqdm):
"""Converts entities to a vtk object
Parameters
----------
lines : bool, optional
Convert lines.
surfaces : bool, optional
Convert B-Spline surfaces.
points : bool, optional
Convert points.
delta : float, optional
Resolution when converting spline entities. Higher
resolution creates a better plot at the cost of computing
time.
merge : bool, optional
Merge all converted entites into one output.
progress: function, optional
Report conversion progress by use of this function. Example::
def silent_progress(iterable, *args, **kwargs):
return iterable
Passing progress=silent_progress will show no progress, the
default is to use tqdm for progress reporting.
Returns
-------
surf : pyvista.PolyData or pyvista.MultiBlock
Geometry represented as ``pyvista.PolyData`` if merged or
a ``MultiBlock`` if unmerged.
Examples
--------
Convert all entities except for surfaces to vtk
>>> lines = iges.to_vtk(surfaces=False)
>>> print(lines)
PolyData (0x7f700c79f3d0)
N Cells: 2440
N Points: 96218
X Bounds: -4.299e+01, 6.912e+14
Y Bounds: -4.255e+01, 6.290e+14
Z Bounds: -9.980e+02, 6.702e+14
N Arrays: 0
"""
items = pyvista.MultiBlock()
for entity in progress(self, desc='Converting entities to vtk'):
if isinstance(entity, geometry.RationalBSplineCurve) and bsplines:
items.append(entity.to_vtk(delta))
elif isinstance(entity, geometry.RationalBSplineSurface) and surfaces:
items.append(entity.to_vtk(delta))
elif isinstance(entity, geometry.Line) and lines:
items.append(entity.to_vtk())
elif isinstance(entity, geometry.Point) and points:
items.append(entity.to_vtk())
# merge to a single mesh
if merge:
afilter = vtkAppendPolyData()
for item in items:
afilter.AddInputData(item)
afilter.Update()
return pyvista.wrap(afilter.GetOutput())
return items
def points(self, as_vtk=False, merge=False, **kwargs):
"""Return all points"""
return self._return_type(geometry.Point, as_vtk, merge, **kwargs)
def edge_lists(self, as_vtk=False, merge=False, **kwargs):
"""All Edge Lists"""
return self._return_type(geometry.EdgeList, as_vtk, merge, **kwargs)
def vertex_lists(self, as_vtk=False, merge=False, **kwargs):
"""All Point Lists"""
return self._return_type(geometry.VertexList, as_vtk, merge, **kwargs)
def lines(self, as_vtk=False, merge=False, **kwargs):
"""All lines"""
return self._return_type(geometry.Line, as_vtk, merge, **kwargs)
def bsplines(self, as_vtk=False, merge=False, **kwargs):
"""All bsplines"""
return self._return_type(geometry.RationalBSplineCurve, as_vtk, merge,
**kwargs)
def bspline_surfaces(self, as_vtk=False, merge=False, **kwargs):
"""All bsplines
Examples
--------
Convert and plot all bspline surfaces. This takes a while
since the geometry tessellation is done in pure python by
``geomdl``. Reduce the conversion time by setting delta to a
larger than default value (0.025)
>>> mesh = iges.bspline_surfaces(as_vtk=True, merge=True)
>>> mesh.plot()
Alternatively, just extract the B-REP surfaces and extract
their parameters
>>> bsurf = iges.bspline_surfaces()
>>> bsurf[0]
Rational B-Spline Surface
Upper index of first sum: 3
Upper index of second sum: 3
Degree of first basis functions: 3
Degree of second basis functions: 3
Open in the first direction
Open in the second direction
Polynomial
Periodic in the first direction
Periodic in the second direction
Knot 1: [0. 0. 0. 0. 1. 1. 1. 1.]
Knot 2: [0. 0. 0. 0. 1. 1. 1. 1.]
u0: 1.000000
u1: 0.000000
v0: 1.000000
v1: 128.000000
Control Points: 16
"""
return self._return_type(geometry.RationalBSplineSurface, as_vtk, merge,
**kwargs)
def circular_arcs(self, to_vtk=False, merge=False, **kwargs):
"""All circular_arcs"""
return self._return_type(geometry.CircularArc, to_vtk, merge, **kwargs)
def conic_arcs(self, as_vtk=False, merge=False, **kwargs):
return self._return_type(geometry.ConicArc, as_vtk, merge,**kwargs)
def faces(self, as_vtk=False, merge=False, **kwargs):
return self._return_type(geometry.Face, as_vtk, merge,**kwargs)
def loops(self, as_vtk=False, merge=False, **kwargs):
return self._return_type(geometry.Loop, as_vtk, merge,**kwargs)
def _return_type(self, iges_type, to_vtk=False, merge=False, **kwargs):
"""Return an iges type"""
items = []
for entity in (self):
if isinstance(entity, iges_type):
if to_vtk:
items.append(entity.to_vtk(**kwargs))
else:
items.append(entity)
# merge to a single mesh
if merge and to_vtk:
afilter = vtkAppendPolyData()
for item in items:
afilter.AddInputData(item)
afilter.Update()
return pyvista.wrap(afilter.GetOutput())
return items
def __getitem__(self, indices):
return self._entities[indices]
def __iter__(self):
for entity in self._entities:
yield entity
def __len__(self):
return len(self._entities)
def __repr__(self):
info = 'pyiges.Iges object\n'
info += 'Description: %s\n' % self._desc
info += 'Number of Entities: %d' % len(self)
return info
def from_pointer(self, ptr):
"""Return an iges object according to an iges pointer"""
return self[self._pointers[ptr]]
def _read(self, filename):
with open(filename, 'r') as f:
param_string = ''
entity_list = []
entity_index = 0
first_dict_line = True
first_global_line = True
first_param_line = True
global_string = ""
pointer_dict = {}
# for line in tqdm(f.readlines(), desc='Reading file'):
for line in f.readlines():
data = line[:80]
id_code = line[72]
if id_code == 'S': # Start
desc = line[:72].strip()
elif id_code == 'G': # Global
global_string += data # Consolidate all global lines
if first_global_line:
param_sep = data[2]
record_sep = data[6]
first_global_line = False
elif id_code == 'D': # Directory entry
if first_dict_line:
entity_type_number = int(data[0:8].strip())
# Curve and surface entities. See IGES spec v5.3, p. 38, Table 3
if entity_type_number == 100: # Circular arc
e = geometry.CircularArc(self)
elif entity_type_number == 102: # Composite curve
e = Entity(self)
elif entity_type_number == 104: # Conic arc
e = geometry.ConicArc(self)
elif entity_type_number == 108: # Plane
e = Entity(self)
elif entity_type_number == 110: # Line
e = geometry.Line(self)
elif entity_type_number == 112: # Parametric spline curve
e = Entity(self)
elif entity_type_number == 114: # Parametric spline surface
e = Entity(self)
elif entity_type_number == 116: # Point
e = geometry.Point(self)
elif entity_type_number == 118: # Ruled surface
e = Entity(self)
elif entity_type_number == 120: # Surface of revolution
e = Entity(self)
elif entity_type_number == 122: # Tabulated cylinder
e = Entity(self)
elif entity_type_number == 124: # Transformation matrix
e = geometry.Transformation(self)
elif entity_type_number == 126: # Rational B-spline curve
e = geometry.RationalBSplineCurve(self)
elif entity_type_number == 128: # Rational B-spline surface
e = geometry.RationalBSplineSurface(self)
# CSG Entities. See IGES spec v5.3, p. 42, Section 3.3
elif entity_type_number == 150: # Block
e = Entity(self)
# B-Rep entities. See IGES spec v5.3, p. 43, Section 3.4
elif entity_type_number == 186:
e = Entity(self)
# Annotation entities. See IGES spec v5.3, p. 46, Section 3.5
elif entity_type_number == 202:
e = Entity(self)
# Structural entities. See IGES spec v5.3, p. 50, Section 3.6
elif entity_type_number == 132:
e = Entity(self)
elif entity_type_number == 502:
e = geometry.VertexList(self)
elif entity_type_number == 504:
e = geometry.EdgeList(self)
elif entity_type_number == 508:
e = geometry.Loop(self)
elif entity_type_number == 510:
e = geometry.Face(self)
else:
e = Entity(self)
e.add_section(data[0:8], 'entity_type_number')
e.add_section(data[8:16], 'parameter_pointer')
e.add_section(data[16:24], 'structure')
e.add_section(data[24:32], 'line_font_pattern')
e.add_section(data[32:40], 'level')
e.add_section(data[40:48], 'view')
e.add_section(data[48:56], 'transform')
e.add_section(data[56:65], 'label_assoc')
e.add_section(data[65:72], 'status_number')
e.sequence_number = int(data[73:].strip())
first_dict_line = False
else:
e.add_section(data[8:16], 'line_weight_number')
e.add_section(data[16:24], 'color_number')
e.add_section(data[24:32], 'param_line_count')
e.add_section(data[32:40], 'form_number')
e.add_section(data[56:64], 'entity_label', type='string')
e.add_section(data[64:72], 'entity_subs_num')
first_dict_line = True
entity_list.append(e)
pointer_dict.update({e.sequence_number : entity_index})
entity_index += 1
elif id_code == 'P': # Parameter data
# Concatenate multiple lines into one string
if first_param_line:
param_string = data[:64]
directory_pointer = int(data[64:72].strip())
first_param_line = False
else:
param_string += data[:64]
if param_string.strip()[-1] == record_sep:
first_param_line = True
param_string = param_string.strip()[:-1]
parameters = param_string.split(param_sep)
entity_list[pointer_dict[directory_pointer]]._add_parameters(parameters)
elif id_code == 'T': # Terminate
pass
self._entities = entity_list
self.desc = desc
self._pointers = pointer_dict
def __getitem__(self, index):
"""Get an item by its pointer"""
return self._entities[self._pointers[index]]
@property
def items(self):
"""IGES items
Examples
--------
>>> from pyiges import examples
>>> import pyiges
>>> sample = pyiges.read(examples.sample)
>>> item = sample.items[0]
>>> item
--- IGES Point ---
0.0, 0.0, 0.0
"""
return self._entities
def read(filename):
"""Read an iges file.
Parameters
----------
filename : str
Filename of an IGES file.
Examples
--------
>>> import pyiges
>>> from pyiges import examples
>>> iges = pyiges.read(examples.impeller)
pyiges.Iges object
Description:
Number of Entities: 4615
"""
return Iges(filename)