VTKio 0.1.0.dev2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
vtkio/utilities.py ADDED
@@ -0,0 +1,222 @@
1
+ #!/usr/bin/env python
2
+ """
3
+ Module for generic helper functions used in VTKio.
4
+
5
+ This module contains the following functions:
6
+
7
+
8
+ Functions
9
+ ---------
10
+ get_recursively()
11
+ Search a dictionary recursively.
12
+
13
+ """
14
+
15
+ __author__ = 'J.P. Morrissey'
16
+ __copyright__ = 'Copyright 2022-2025'
17
+ __maintainer__ = 'J.P. Morrissey'
18
+ __email__ = 'morrissey.jp@gmail.com'
19
+ __status__ = 'Development'
20
+
21
+ # Standard Library
22
+ from collections.abc import MutableMapping
23
+
24
+
25
+ def is_numeric_array(obj):
26
+ """
27
+ Check if the provided object behaves like a numeric array.
28
+
29
+ This function determines if the given object has specific attributes that are generally associated with numeric
30
+ array-like objects. The attributes checked include addition, subtraction, multiplication, division, and power
31
+ operations. Objects lacking these attributes are not considered numeric arrays.
32
+
33
+ Parameters
34
+ ----------
35
+ obj : object
36
+ The object to check for numeric array-like behavior.
37
+
38
+ Returns
39
+ -------
40
+ bool
41
+ Returns True if the object meets the required criteria for being
42
+ a numeric array-like object; otherwise, it returns False.
43
+ """
44
+ attrs = ['__add__', '__sub__', '__mul__', '__truediv__', '__pow__']
45
+ return all(hasattr(obj, attr) for attr in attrs)
46
+
47
+
48
+ def flatten(dictionary, parent_key='', separator='_'):
49
+ """
50
+ Flattens a nested dictionary into a single-depth dictionary.
51
+
52
+ The function takes a nested dictionary and transforms it into a flattened dictionary
53
+ with a single level. Each key in the resulting dictionary is a concatenation of the
54
+ hierarchical keys from the original dictionary, separated by the provided separator.
55
+ This is particularly useful for simplifying nested structures for certain operations,
56
+ such as data serialization or storage.
57
+
58
+ Parameters
59
+ ----------
60
+ dictionary : dict
61
+ A dictionary that may contain nested dictionaries as values.
62
+ parent_key : str, optional
63
+ A string to prefix the keys of the flattened dictionary with. Defaults to an
64
+ empty string, meaning no prefix is added.
65
+ separator : str, optional
66
+ A string used to separate concatenated keys in the flattened dictionary. Defaults
67
+ to an underscore ('_').
68
+
69
+ Returns
70
+ -------
71
+ dict
72
+ A flattened dictionary where all keys are made unique by combining their
73
+ hierarchical keys using the specified separator.
74
+ """
75
+ items = []
76
+ for key, value in dictionary.items():
77
+ new_key = parent_key + separator + key if parent_key else key
78
+ if isinstance(value, MutableMapping):
79
+ items.extend(flatten(value, new_key, separator=separator).items())
80
+ else:
81
+ items.append((new_key, value))
82
+ return dict(items)
83
+
84
+
85
+ def dict_extract_generator(key, var):
86
+ """
87
+ Generate values from a nested dictionary or list structure that match the specified key.
88
+
89
+ This generator function recursively traverses dictionaries and lists in search of values
90
+ associated with a specified key. The function yields these values when the matching key
91
+ is found.
92
+
93
+ Parameters
94
+ ----------
95
+ key : str
96
+ The key to search for in the nested structure.
97
+ var : dict or list
98
+ The nested dictionary or list structure to traverse.
99
+
100
+ Yields
101
+ ------
102
+ Any
103
+ Values associated with the specified key in the nested structure. The type of
104
+ the yielded value depends on the contents of the input structure.
105
+ """
106
+ if hasattr(var,'items'):
107
+ for k, v in var.items():
108
+ if k == key:
109
+ yield v
110
+ if isinstance(v, dict):
111
+ for result in dict_extract_generator(key, v):
112
+ yield result
113
+ elif isinstance(v, list):
114
+ for d in v:
115
+ for result in dict_extract_generator(key, d):
116
+ yield result
117
+
118
+
119
+ def get_recursively(search_dict, field):
120
+ """
121
+ Search a dictionary recursively.
122
+
123
+ Takes a dictionary with nested lists and dictionaries, and searches all dictionaries for a key of the field provided.
124
+
125
+ Parameters
126
+ ----------
127
+ search_dict : Dict [Any, Any]
128
+ Dictionary to be searched. It can contain nested dictionaries and lists as well as basic types such as strings, ints and floats.
129
+ field : key [Any]
130
+ Dictionary key to be searched for. Typically, a string, integer or float.
131
+
132
+ Returns
133
+ -------
134
+ result : List[Any]
135
+ The values associated with the key provided. If the key is not found, an empty list is returned.
136
+
137
+
138
+ Examples
139
+ --------
140
+ >>> d = {'a': 1, 'b': 2, 'c': {'da': 4, 'db': 5, 'dc': {'dda': 8, 'ddb': 9}}}
141
+ >>> get_recursively(d, 'da')
142
+ [4]
143
+ >>> get_recursively(d, 'ddb')
144
+ [9]
145
+ >>> get_recursively(d, 'missing_key')
146
+ []
147
+
148
+ """
149
+ fields_found = []
150
+
151
+ for key, value in search_dict.items():
152
+
153
+ if key == field:
154
+ fields_found.append(value)
155
+
156
+ elif isinstance(value, dict):
157
+ results = get_recursively(value, field)
158
+ for result in results:
159
+ fields_found.append(result)
160
+
161
+ elif isinstance(value, list):
162
+ for item in value:
163
+ if isinstance(item, dict):
164
+ more_results = get_recursively(item, field)
165
+ for another_result in more_results:
166
+ fields_found.append(another_result)
167
+
168
+ return fields_found
169
+
170
+
171
+ def flatten_list(nested_list):
172
+ """
173
+ Flattens a nested list into a single list.
174
+
175
+ The function takes a nested list of arbitrary depth and recursively flattens
176
+ it into a single list containing all the elements. Any nested sub-lists are
177
+ converted into their constituent elements and appended to the resulting list.
178
+
179
+ Parameters
180
+ ----------
181
+ nested_list : list
182
+ A possibly nested list of elements to be flattened. The input can consist
183
+ of multiple levels of lists.
184
+
185
+ Returns
186
+ -------
187
+ list
188
+ A flattened list containing all elements from the input `nested_list`,
189
+ including elements from any nested sub-lists.
190
+ """
191
+ def flatten_helper(sublist, result):
192
+ for item in sublist:
193
+ if isinstance(item, list): # Improved type checking
194
+ flatten_helper(item, result) # Recursive call
195
+ else:
196
+ result.append(item)
197
+ return result
198
+
199
+ return flatten_helper(nested_list, []) # Extracted recursive logic into helper
200
+
201
+
202
+ def first_key(dict):
203
+ """
204
+ Retrieve the first key from a given dictionary.
205
+
206
+ This function iterates over a dictionary and retrieves the first key it
207
+ encounters. If the dictionary is empty, it returns None.
208
+
209
+ Parameters
210
+ ----------
211
+ dict : dict
212
+ The dictionary from which the first key will be retrieved.
213
+
214
+ Returns
215
+ -------
216
+ Hashable or None
217
+ The first key encountered in the dictionary. If the dictionary is empty,
218
+ returns None.
219
+ """
220
+ for key in dict:
221
+ return key
222
+ return None
vtkio/version.py ADDED
@@ -0,0 +1,78 @@
1
+ #!/usr/bin/env python
2
+ """
3
+ This `version` module contains the version information for the VTKio package.
4
+
5
+ Created at 12:47, 23 Feb, 2025
6
+ """
7
+
8
+ __author__ = 'J.P. Morrissey'
9
+ __copyright__ = 'Copyright 2022-2025'
10
+ __maintainer__ = 'J.P. Morrissey'
11
+ __email__ = 'morrissey.jp@gmail.com'
12
+ __status__ = 'Development'
13
+
14
+ # Standard Library
15
+
16
+
17
+ # Imports
18
+
19
+
20
+ # Local Sources
21
+
22
+
23
+ __all__ = ['VERSION', 'version_info', 'version_short']
24
+
25
+ VERSION = '0.1.0.dev2'
26
+ """The version of VTKio."""
27
+
28
+ def version_short() -> str:
29
+ """Return the `major.minor` part of package version.
30
+
31
+ It returns '0.2' if VTKio version is '0.2.2'.
32
+ """
33
+ return '.'.join(VERSION.split('.')[:2])
34
+
35
+
36
+ def version_info() -> str:
37
+ """Return complete version information for VTKio and its dependencies."""
38
+ import importlib.metadata as importlib_metadata
39
+ import os
40
+ import platform
41
+ import sys
42
+ from pathlib import Path
43
+
44
+ # Local Sources
45
+ import _git as git
46
+
47
+ import vtkio as vtkio
48
+
49
+
50
+ # get data about packages that are closely related to or are used by VTKio
51
+ package_names = {
52
+ 'h5py',
53
+ 'xmltodict',
54
+ 'numpy',
55
+ 'pybase64',
56
+ }
57
+ related_packages = []
58
+
59
+ for dist in importlib_metadata.distributions():
60
+ name = dist.metadata['Name']
61
+ if name in package_names:
62
+ related_packages.append(f'{name}-{dist.version}')
63
+
64
+ vtkio_dir = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
65
+ most_recent_commit = (
66
+ git.git_revision(vtkio_dir) if git.is_git_repo(vtkio_dir) and git.have_git() else 'unknown'
67
+ )
68
+
69
+ info = {
70
+ 'vtkio version': VERSION,
71
+ 'vtkio-core build': getattr(vtkio, 'build_info', None) or vtkio.build_profile,
72
+ 'install path': Path(__file__).resolve().parent,
73
+ 'python version': sys.version,
74
+ 'platform': platform.platform(),
75
+ 'related packages': ' '.join(related_packages),
76
+ 'commit': most_recent_commit,
77
+ }
78
+ return '\n'.join('{:>30} {}'.format(k + ':', str(v).replace('\n', ' ')) for k, v in info.items())
@@ -0,0 +1,98 @@
1
+ #!/usr/bin/env python
2
+ """
3
+ VTKWriter Class for creating VTK's XML based format.
4
+
5
+ Supports ASCII, Base64 and Appended Raw encoding of data.
6
+
7
+ Created at 13:01, 24 Feb, 2022
8
+ """
9
+
10
+ __author__ = 'J.P. Morrissey'
11
+ __copyright__ = 'Copyright 2022-2025'
12
+ __maintainer__ = 'J.P. Morrissey'
13
+ __email__ = 'morrissey.jp@gmail.com'
14
+ __status__ = 'Development'
15
+
16
+ # Standard Library
17
+ from dataclasses import dataclass
18
+
19
+
20
+ @dataclass
21
+ class VTK_CellType:
22
+ """Generic Class for storing the various different vtk cell types."""
23
+
24
+ name: str
25
+ type_id: int
26
+ num_points: int
27
+ dimensionality: int
28
+ structure: str
29
+ interpolation: str
30
+
31
+ def set_num_points(self, num_points: int):
32
+ """
33
+ Set the number of points for the cell type.
34
+
35
+ This is used for the PolyLine, Polygon and PolyVertex cell types.
36
+ The number of points is set to the number of points in the cell.
37
+
38
+ Parameters
39
+ ----------
40
+ num_points : int
41
+ The number of points in the cell.
42
+ """
43
+ if self.name in ["PolyLine", "Polygon", "PolyVertex"]:
44
+ self.num_points = num_points
45
+ else:
46
+ raise ValueError(f"Cannot set number of points for {self.name} cell type.")
47
+
48
+ return self
49
+
50
+ def set_num_triangles(self, num_triangles: int):
51
+ """
52
+ Set the number of triangles and points for the Triangle Strip cell type.
53
+
54
+ Parameters
55
+ ----------
56
+ num_triangles : int
57
+ The number of triangles in the cell.
58
+
59
+ """
60
+ if self.name == "TriangleStrip":
61
+ # The number of points in a triangle strip is the number of triangles + 2
62
+ self.num_points = num_triangles + 2
63
+ else:
64
+ raise ValueError(f"Cannot set number of triangles for {self.name} cell type.")
65
+
66
+ return self
67
+
68
+
69
+ VTK_Vertex = VTK_CellType("Vertex", 1, 1, 0, "Primary", "Linear")
70
+ VTK_PolyVertex = VTK_CellType("PolyVertex", 1, "n", 0, "Composite", "Linear")
71
+ VTK_Line = VTK_CellType("Line", 3, 2, 1, "Primary", "Linear")
72
+ VTK_PolyLine = VTK_CellType("PolyLine", 4, "n", 1, "Composite", "Linear")
73
+ VTK_Triangle = VTK_CellType("Triangle", 5, 3, 2, "Primary", "Linear")
74
+ VTK_TriangleStrip = VTK_CellType("TriangleStrip", 6, "n+2", 2, "Composite", "Linear")
75
+ VTK_Polygon = VTK_CellType("Polygon", 7, "n", 2, "Primary", "Linear")
76
+ VTK_Pixel = VTK_CellType("Pixel", 8, 4, 2, "Primary", "Linear")
77
+ VTK_Quad = VTK_CellType("Quad", 9, 4, 3, "Primary", "Linear")
78
+ VTK_Tetra = VTK_CellType("Tetra", 10, 4, 3, "Primary", "Linear")
79
+ VTK_Voxel = VTK_CellType("Voxel", 11, 8, 3, "Primary", "Linear")
80
+ VTK_Hexahedron = VTK_CellType("Hexahedron", 12, 8, 3, "Primary", "Linear")
81
+ VTK_Wedge = VTK_CellType("Wedge", 13, 6, 3, "Primary", "Linear")
82
+ VTK_Pyramid = VTK_CellType("Pyramid", 14, 5, 3, "Primary", "Linear")
83
+ VTK_Pentagonal_Prism = VTK_CellType("Pentagonal_Prism", 15, 10, 3, "Primary", "Linear")
84
+ VTK_Hexagonal_Prism = VTK_CellType("Hexagonal_Prism", 16, 12, 3, "Primary", "Linear")
85
+ VTK_Quadratic_Edge = VTK_CellType("Quadratic_Edge", 21, 3, 1, "Primary", "NonLinear")
86
+ VTK_Quadratic_Triangle = VTK_CellType("Quadratic_Triangle", 22, 6, 2, "Primary", "NonLinear")
87
+ VTK_Quadratic_Quad = VTK_CellType("Quadratic_Quad", 23, 8, 2, "Primary", "NonLinear")
88
+ VTK_Quadratic_Tetra = VTK_CellType("Quadratic_Tetra", 24, 10, 3, "Primary", "NonLinear")
89
+ VTK_Quadratic_Hexahedron = VTK_CellType("Quadratic_Hexahedron", 25, 20, 3, "Primary", "NonLinear")
90
+ VTK_Quadratic_Wedge = VTK_CellType("Quadratic_Wedge", 26, 12, 3, "Primary", "NonLinear")
91
+ VTK_Quadratic_Pyramid = VTK_CellType("Quadratic_Pyramid", 27, 13, 3, "Primary", "NonLinear")
92
+ VTK_BiQuadratic_Quad = VTK_CellType("BiQuadratic_Quad", 28, 9, 2, "Primary", "NonLinear")
93
+ VTK_TriQuadratic_Hexahedron = VTK_CellType("TriQuadratic_Hexahedron", 29, 27, 3, "Primary", "NonLinear")
94
+ VTK_Quadratic_Linear_Quad = VTK_CellType("Quadratic_Linear_Quad", 30, 6, 3, "Primary", "NonLinear")
95
+ VTK_Quadratic_Linear_Wedge = VTK_CellType("Quadratic_Linear_Wedge", 31, 12, 3, "Primary", "NonLinear")
96
+ VTK_BiQuadratic_Quadratic_Wedge= VTK_CellType("BiQuadratic_Quadratic_Wedge", 32, 18, 3, "Primary", "NonLinear")
97
+ VTK_BiQuadratic_Quadratic_Hexahedron = VTK_CellType("BiQuadratic_Quadratic_Hexahedron", 33, 24, 3, "Primary", "NonLinear")
98
+ VTK_BiQuadratic_Triangle = VTK_CellType("BiQuadratic_Triangle", 34, 7, 2, "Primary", "NonLinear")
@@ -0,0 +1,306 @@
1
+ #!/usr/bin/env python
2
+ """
3
+ Module documentation goes here.
4
+
5
+ Created at 17:27, 22 Jul, 2024
6
+ """
7
+
8
+ __author__ = 'J.P. Morrissey'
9
+ __copyright__ = 'Copyright 2022-2025'
10
+ __maintainer__ = 'J.P. Morrissey'
11
+ __email__ = 'morrissey.jp@gmail.com'
12
+ __status__ = 'Development'
13
+
14
+ # Standard Library
15
+ from dataclasses import astuple, dataclass
16
+
17
+ # Imports
18
+ import numpy as np
19
+
20
+ # Local Sources
21
+ from .writer.writers import write_vti, write_vtp, write_vtr, write_vts, write_vtu
22
+
23
+
24
+ def compare_exact(first, second):
25
+ """Return whether two dicts of arrays are exactly equal."""
26
+ if first.keys() != second.keys():
27
+ return False
28
+ return all(np.array_equal(first[key], second[key]) for key in first)
29
+
30
+
31
+ def compare_approximate(first, second):
32
+ """
33
+ Return whether two dicts of arrays are roughly equal.
34
+
35
+ This is used otherwise comparing floats would return `False`.
36
+ """
37
+ if first.keys() != second.keys():
38
+ return False
39
+ return all(np.allclose(first[key], second[key]) for key in first)
40
+
41
+
42
+ def array_safe_eq(a, b) -> bool:
43
+ """Check if a and b are equal, even if they are numpy arrays."""
44
+ if a is b:
45
+ return True
46
+
47
+ if isinstance(a, np.ndarray) and isinstance(b, np.ndarray):
48
+ # return np.array_equal(a, b)
49
+ return np.allclose(a, b)
50
+
51
+ if isinstance(a, dict) and isinstance(b, dict):
52
+ return compare_approximate(a, b)
53
+
54
+ if isinstance(a, list) and isinstance(b, list):
55
+ pass
56
+
57
+ if isinstance(a, tuple) and isinstance(b, tuple):
58
+ return all((a == b).all() for a, b in zip(a, b))
59
+
60
+ try:
61
+ return a == b
62
+ except TypeError:
63
+ return NotImplemented
64
+
65
+
66
+ def dataclass_equality_check(dc1, dc2) -> bool:
67
+ """Checks if two dataclasses which hold numpy arrays are equal."""
68
+ if dc1 is dc2:
69
+ return True
70
+
71
+ if dc1.__class__ is not dc2.__class__:
72
+ return NotImplemented # better than False
73
+
74
+ t1 = astuple(dc1)
75
+ t2 = astuple(dc2)
76
+
77
+ if len(t1) != len(t2):
78
+ return False
79
+ else:
80
+ return all(array_safe_eq(a1, a2) for a1, a2 in zip(t1, t2))
81
+
82
+
83
+ @dataclass
84
+ class VTKData:
85
+ point_data: dict
86
+ cell_data: dict
87
+ field_data: dict
88
+
89
+
90
+ @dataclass
91
+ class Cell:
92
+ connectivity: np.ndarray
93
+ offsets: np.ndarray
94
+ types: np.ndarray
95
+
96
+
97
+ @dataclass
98
+ class PolyDataTopology:
99
+ connectivity: np.ndarray
100
+ offsets: np.ndarray
101
+
102
+
103
+ @dataclass
104
+ class VTKDataArray:
105
+ Scalars: dict
106
+ Vectors: dict
107
+ Tensors: dict
108
+ Normals: dict
109
+ TCoords: dict
110
+
111
+
112
+ @dataclass
113
+ class Grid:
114
+ whole_extents: np.ndarray
115
+ origin: np.ndarray
116
+ spacing: np.ndarray
117
+ direction: np.ndarray
118
+
119
+ def __post_init__(self):
120
+ _cells = np.array([self.whole_extents[1] - self.whole_extents[0],
121
+ self.whole_extents[3] - self.whole_extents[2],
122
+ self.whole_extents[5] - self.whole_extents[4]])
123
+ self.num_cells = np.prod(_cells)
124
+ self.num_points = np.prod(_cells + 1)
125
+
126
+
127
+ @dataclass
128
+ class GridCoordinates:
129
+ x: np.ndarray
130
+ y: np.ndarray
131
+ z: np.ndarray
132
+ whole_extents: np.ndarray
133
+
134
+ def __post_init__(self):
135
+ self.num_points = np.prod([self.x.size, self.y.size, self.z.size])
136
+ self.num_cells = np.prod([self.x.size - 1, self.y.size - 1, self.z.size - 1])
137
+
138
+
139
+ @dataclass
140
+ class ImageData(VTKData):
141
+ grid: Grid
142
+
143
+ def __eq__(self, other):
144
+ return dataclass_equality_check(self, other)
145
+
146
+ def write(self, filepath, file_format='xml', xml_encoding='appended'):
147
+ """
148
+
149
+ Parameters
150
+ ----------
151
+ filepath : str
152
+ file_format : {'xml', 'vtkhdf'}, default 'xml'
153
+ xml_encoding : {'ascii', 'binary', 'appended'}, default='appended'
154
+ Encoding of XML files can be ascii, binary or appended. The default formatting is 'appended'.
155
+
156
+ """
157
+ if file_format in ['xml','vtkhdf', 'hdf', 'hdf5', 'vtk hdf']:
158
+ write_vti(filepath, whole_extent=self.grid.whole_extents, piece_extent=self.grid.whole_extents,
159
+ spacing=self.grid.spacing, origin=self.grid.origin, direction=self.grid.direction,
160
+ point_data=self.point_data, cell_data=self.cell_data, field_data=self.field_data,
161
+ encoding=xml_encoding, file_format=file_format)
162
+
163
+ else:
164
+ raise NotImplementedError("This is not a supported file type")
165
+
166
+
167
+ @dataclass
168
+ class RectilinearData(VTKData):
169
+ coordinates: GridCoordinates
170
+
171
+ def __eq__(self, other):
172
+ return dataclass_equality_check(self, other)
173
+
174
+ def write(self, filepath, file_format='xml', xml_encoding='appended'):
175
+ """
176
+
177
+ Parameters
178
+ ----------
179
+ filepath : str
180
+ file_format : {'xml', 'vtkhdf'}, default 'xml'
181
+ xml_encoding : {'ascii', 'binary', 'appended'}, default='appended'
182
+ Encoding of XML files can be ascii, binary or appended. The default formatting is 'appended'.
183
+
184
+ """
185
+ if file_format in ['xml','vtkhdf', 'hdf', 'hdf5', 'vtk hdf']:
186
+ write_vtr(filepath, self.coordinates.x, self.coordinates.y, self.coordinates.z,
187
+ whole_extent=self.coordinates.whole_extents, piece_extent=self.coordinates.whole_extents,
188
+ point_data=self.point_data, cell_data=self.cell_data, field_data=self.field_data,
189
+ encoding=xml_encoding, file_format=file_format)
190
+
191
+ else:
192
+ raise NotImplementedError("This is not a supported file type")
193
+
194
+
195
+ @dataclass
196
+ class StructuredData(VTKData):
197
+ points: np.ndarray
198
+ whole_extents: np.ndarray
199
+
200
+ def __post_init__(self):
201
+ self.num_points = self.points.shape[0]
202
+ self.num_cells = np.prod([self.whole_extents[1] - self.whole_extents[0],
203
+ self.whole_extents[3] - self.whole_extents[2],
204
+ self.whole_extents[5] - self.whole_extents[4]])
205
+
206
+ def __eq__(self, other):
207
+ return dataclass_equality_check(self, other)
208
+
209
+ def write(self, filepath, file_format='xml', xml_encoding='appended'):
210
+ """
211
+ Write the data to a file.
212
+
213
+ This function writes the data to a file in either XML or HDF5 format.
214
+ The file format is determined by the `file_format` parameter.
215
+
216
+
217
+ Parameters
218
+ ----------
219
+ filepath : str
220
+ file_format : {'xml', 'vtkhdf'}, default 'xml'
221
+ xml_encoding : {'ascii', 'binary', 'appended'}, default='appended'
222
+ Encoding of XML files can be ascii, binary or appended. The default formatting is 'appended'.
223
+
224
+ """
225
+ if file_format in ['xml','vtkhdf', 'hdf', 'hdf5', 'vtk hdf']:
226
+ write_vts(filepath, self.points, whole_extent=self.whole_extents, piece_extent=self.whole_extents,
227
+ point_data=self.point_data, cell_data=self.cell_data, field_data=self.field_data,
228
+ encoding=xml_encoding, file_format=file_format)
229
+
230
+ else:
231
+ raise NotImplementedError("This is not a supported file type")
232
+
233
+
234
+ @dataclass
235
+ class UnstructuredGrid(VTKData):
236
+ points: np.ndarray
237
+ cells: Cell
238
+
239
+ def __eq__(self, other):
240
+ return dataclass_equality_check(self, other)
241
+
242
+ def write(self, filepath, file_format='xml', xml_encoding='appended'):
243
+ """
244
+
245
+ Parameters
246
+ ----------
247
+ filepath : str
248
+ file_format : {'xml', 'vtkhdf'}, default 'xml'
249
+ xml_encoding : {'ascii', 'binary', 'appended'}, default='appended'
250
+ Encoding of XML files can be ascii, binary or appended. The default formatting is 'appended'.
251
+
252
+ """
253
+ if file_format in ['xml','vtkhdf', 'hdf', 'hdf5', 'vtk hdf']:
254
+ write_vtu(filepath, nodes=self.points, cell_type=self.cells.types, connectivity=self.cells.connectivity,
255
+ offsets=self.cells.offsets, point_data=self.point_data, cell_data=self.cell_data,
256
+ field_data=self.field_data, encoding=xml_encoding, file_format=file_format)
257
+
258
+ else:
259
+ raise NotImplementedError("This is not a supported file type")
260
+
261
+
262
+ @dataclass
263
+ class PolyData(VTKData):
264
+ points: np.ndarray
265
+ verts: PolyDataTopology
266
+ lines: PolyDataTopology
267
+ strips: PolyDataTopology
268
+ polys: PolyDataTopology
269
+
270
+ def __eq__(self, other):
271
+ return dataclass_equality_check(self, other)
272
+
273
+ def write(self, filepath, file_format='xml', xml_encoding='appended'):
274
+ """
275
+
276
+ Parameters
277
+ ----------
278
+ filepath : str
279
+ file_format : {'xml', 'vtkhdf'}, default 'xml'
280
+ xml_encoding : {'ascii', 'binary', 'appended'}, default='appended'
281
+ Encoding of XML files can be ascii, binary or appended. The default formatting is 'appended'.
282
+
283
+ """
284
+ lines = None
285
+ verts = None
286
+ strips = None
287
+ polys = None
288
+
289
+ # check for none
290
+ if self.lines:
291
+ lines = astuple(self.lines)
292
+ if self.strips:
293
+ strips = astuple(self.strips)
294
+ if self.polys:
295
+ polys = astuple(self.polys)
296
+ if self.verts:
297
+ verts = astuple(self.verts)
298
+
299
+ if file_format in ['xml','vtkhdf', 'hdf', 'hdf5', 'vtk hdf']:
300
+
301
+ write_vtp(filepath, points=self.points, verts=verts, lines=lines, strips=strips, polys=polys,
302
+ point_data=self.point_data, cell_data=self.cell_data, field_data=self.field_data,
303
+ encoding=xml_encoding, file_format=file_format,)
304
+
305
+ else:
306
+ raise NotImplementedError("This is not a supported file type")