1 """Generic support for new-style (XML) VTK visualization data files."""
2
3 __copyright__ = "Copyright (C) 2007 Andreas Kloeckner"
4
5 __license__ = """
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see U{http://www.gnu.org/licenses/}.
18 """
19
20
21
22
23 import numpy
24
25
26
27
28 VTK_INT8 = "Int8"
29 VTK_UINT8 = "UInt8"
30 VTK_INT16 = "Int16"
31 VTK_UINT16 = "UInt16"
32 VTK_INT32 = "Int32"
33 VTK_UINT32 = "UInt32"
34 VTK_INT64 = "Int64"
35 VTK_UINT64 = "UInt64"
36 VTK_FLOAT32 = "Float32"
37 VTK_FLOAT64 = "Float64"
38
39 VTK_VERTEX = 1
40 VTK_POLY_VERTEX = 2
41 VTK_LINE = 3
42 VTK_POLY_LINE = 4
43 VTK_TRIANGLE = 5
44 VTK_TRIANGLE_STRIP = 6
45 VTK_POLYGON = 7
46 VTK_PIXEL = 8
47 VTK_QUAD = 9
48 VTK_TETRA = 10
49 VTK_VOXEL = 11
50 VTK_HEXAHEDRON = 12
51 VTK_WEDGE = 13
52 VTK_PYRAMID = 14
53
54 CELL_NODE_COUNT = {
55 VTK_VERTEX: 1,
56
57 VTK_LINE: 2,
58
59 VTK_TRIANGLE: 3,
60
61
62 VTK_PIXEL: 4,
63 VTK_QUAD: 4,
64 VTK_TETRA: 4,
65 VTK_VOXEL: 8,
66 VTK_HEXAHEDRON: 8,
67 VTK_WEDGE: 6,
68 VTK_PYRAMID: 5,
69 }
70
71
72 VF_LIST_OF_COMPONENTS = 0
73 VF_LIST_OF_VECTORS = 1
74
75 _U32CHAR = numpy.dtype(numpy.uint32).char
76
77
78
79
80
84
85 - def copy(self, new_children=None):
86 result = self.__class__(self.tag, self.attributes)
87 if new_children is not None:
88 result.children = new_children
89 else:
90 result.children = self.children
91 return result
92
94 self.children.append(child)
95
96
97
98
104
106 attr_string = "".join(
107 " %s=\"%s\"" % (key,value)
108 for key,value in self.attributes.iteritems())
109 if self.children:
110 file.write("<%s%s>\n" % (self.tag, attr_string))
111 for child in self.children:
112 if isinstance(child, XMLElement):
113 child.write(file)
114 else:
115
116 file.write(child)
117 file.write("</%s>\n" % self.tag)
118 else:
119 file.write("<%s%s/>\n" % (self.tag, attr_string))
120
121
122
123
124
130
132 file.write("<?xml version=\"1.0\"?>\n")
133 for child in self.children:
134 if isinstance(child, XMLElement):
135 child.write(file)
136 else:
137
138 file.write(child)
139
140
141
144 """Return an identifier for the binary encoding used."""
145 raise NotImplementedError
146
148 """Return an identifier for the compressor used, or None."""
149 raise NotImplementedError
150
152 """Reobtain the raw buffer string object that was used to
153 construct this encoded buffer."""
154
155 raise NotImplementedError
156
158 """Add encoded buffer to the given C{xml_element}.
159 Return total size of encoded buffer in bytes."""
160
161 raise NotImplementedError
162
163
164
165
166
170
173
176
179
181 raise NotImplementedError
182
183
184
185
188 from struct import pack
189 from base64 import b64encode
190 self.b64header = b64encode(
191 pack(_U32CHAR, len(buffer)))
192 self.b64data = b64encode(buffer)
193
196
199
201 from base64 import b64decode
202 return b64decode(self.b64data)
203
205 """Add encoded buffer to the given C{xml_element}.
206 Return total size of encoded buffer in bytes."""
207
208 xml_element.add_child(self.b64header)
209 xml_element.add_child(self.b64data)
210
211 return len(self.b64header) + len(self.b64data)
212
213
214
215
218 from struct import pack
219 from base64 import b64encode
220 from zlib import compress
221 comp_buffer = compress(buffer)
222 comp_header = [1, len(buffer), len(buffer), len(comp_buffer)]
223 self.b64header = b64encode(
224 pack(_U32CHAR*len(comp_header), *comp_header))
225 self.b64data = b64encode(comp_buffer)
226
229
232
234 from base64 import b64decode
235 from zlib import decompress
236 return decompress(b64decode(self.b64data))
237
239 """Add encoded buffer to the given C{xml_element}.
240 Return total size of encoded buffer in bytes."""
241
242 xml_element.add_child(self.b64header)
243 xml_element.add_child(self.b64data)
244
245 return len(self.b64header) + len(self.b64data)
246
247
248
249
250
251
255 self.name = name
256
257 if isinstance(container, DataArray):
258 self.type = container.type
259 self.components = container.components
260 self.encoded_buffer = container.encoded_buffer
261 return
262
263 def vec_type(vec):
264 if vec.dtype == numpy.int8: return VTK_INT8
265 elif vec.dtype == numpy.uint8: return VTK_UINT8
266 elif vec.dtype == numpy.int16: return VTK_INT16
267 elif vec.dtype == numpy.uint16: return VTK_UINT16
268 elif vec.dtype == numpy.int32: return VTK_INT32
269 elif vec.dtype == numpy.uint32: return VTK_UINT32
270 elif vec.dtype == numpy.int64: return VTK_INT64
271 elif vec.dtype == numpy.uint64: return VTK_UINT64
272 elif vec.dtype == numpy.float32: return VTK_FLOAT32
273 elif vec.dtype == numpy.float64: return VTK_FLOAT64
274 else:
275 raise TypeError, "Unsupported vector type '%s' in VTK writer" % (vec.dtype)
276
277 if not isinstance(container, numpy.ndarray):
278 raise ValueError, "cannot convert object of type `%s' to DataArray" % type(container)
279
280 if container.dtype == object:
281 container = numpy.array(list(container))
282 assert container.dtype != object
283
284 if len(container.shape) > 1:
285 if vector_format == VF_LIST_OF_COMPONENTS:
286 container = container.T.copy()
287
288 assert len(container.shape) == 2, "numpy vectors of rank >2 are not supported"
289 assert container.strides[1] == container.itemsize, "2D numpy arrays must be row-major"
290 if vector_padding > container.shape[1]:
291 container = numpy.asarray(numpy.hstack((
292 container,
293 numpy.zeros((
294 container.shape[0],
295 vector_padding-container.shape[1],
296 ),
297 container.dtype))), order="C")
298 self.components = container.shape[1]
299 else:
300 self.components = 1
301 self.type = vec_type(container)
302 buf = buffer(container)
303
304 self.encoded_buffer = BinaryEncodedBuffer(buf)
305
307 have_encoder = self.encoded_buffer.encoder()
308 have_compressor = self.encoded_buffer.compressor()
309
310 if (encoder, compressor) != (have_encoder, have_compressor):
311 raw_buf = self.encoded_buffer.raw_buffer()
312
313
314 del self.encoded_buffer
315
316 if (encoder, compressor) == ("binary", None):
317 self.encoded_buffer = BinaryEncodedBuffer(raw_buf)
318 elif (encoder, compressor) == ("base64", None):
319 self.encoded_buffer = Base64EncodedBuffer(raw_buf)
320 elif (encoder, compressor) == ("base64", "zlib"):
321 self.encoded_buffer = Base64ZLibEncodedBuffer(raw_buf)
322 else:
323 self.encoded_buffer = BinaryEncodedBuffer(raw_buf)
324 raise ValueError, "invalid encoder/compressor pair"
325
326 have_encoder = self.encoded_buffer.encoder()
327 have_compressor = self.encoded_buffer.compressor()
328
329 assert (encoder, compressor) == (have_encoder, have_compressor)
330
331 return self.encoded_buffer
332
333 - def encode(self, compressor, xml_element):
336
339
340
341
342
344 - def __init__(self, points, cells, cell_types):
345 self.point_count = len(points)
346 self.cell_count = len(cells)
347
348 self.point_count, self.points = points
349 assert self.points.name == "points"
350
351 try:
352 self.cell_count, self.cell_connectivity, \
353 self.cell_offsets = cells
354 except:
355 self.cell_count = len(cell_types)
356
357 offsets = numpy.cumsum(numpy.fromiter(
358 (CELL_NODE_COUNT[ct] for ct in cell_types),
359 dtype=numpy.int,
360 count=len(cell_types)))
361
362 self.cell_connectivity = DataArray("connectivity", cells)
363 self.cell_offsets = DataArray("offsets", offsets)
364
365 self.cell_types = DataArray("types", cell_types)
366
367 self.pointdata = []
368 self.celldata = []
369
371 return UnstructuredGrid(
372 (self.point_count, self.points),
373 (self.cell_count, self.cell_connectivity,
374 self.cell_offsets),
375 self.cell_types)
376
379
382
384 self.pointdata.append(data_array)
385
386
387
388
389
391 import sys
392 if sys.byteorder == "little":
393 bo = "LittleEndian"
394 else:
395 bo = "BigEndian"
396
397 kwargs = {}
398 if compressor == "zlib":
399 kwargs["compressor"] = "vtkZLibDataCompressor"
400
401 return XMLElement("VTKFile", type=filetype, version="0.1", byte_order=bo, **kwargs)
402
403
404
405
419
425
426 - def rec(self, vtkobj):
428
429
430
431
432
463
464
465
466
474
480
482 el = XMLElement("DataArray", type=data.type, Name=data.name,
483 NumberOfComponents=data.components, format="appended",
484 offset=self.base64_len)
485
486 self.base64_len += data.encode(self.compressor, self.app_data)
487
488 return el
489
490
491
492
526