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
use crate::IOBuffer;
use num_derive::FromPrimitive;
use std::any::TypeId;
use std::fmt;

/**
 * Vtk Data Model
 */

/// Model of the Vtk data structure.
#[derive(Clone, PartialEq, Debug)]
pub struct Vtk {
    pub version: Version,
    pub title: String,
    pub data: DataSet,
}

/// Version number (e.g. `4.1 => (4,1)`)
#[derive(Copy, Clone, PartialEq, Debug)]
pub struct Version {
    pub major: u8,
    pub minor: u8,
}

impl Version {
    pub fn new(pair: (u8, u8)) -> Self {
        Version {
            major: pair.0,
            minor: pair.1,
        }
    }
}

impl fmt::Display for Version {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}.{}", self.major, self.minor)
    }
}

/// Special struct to store Field attribute data.
#[derive(Clone, PartialEq, Debug)]
pub struct FieldArray {
    pub name: String,
    pub num_comp: u32,
    pub data: IOBuffer,
}

/// Data structure that stores a Vtk attribute.
#[derive(Clone, PartialEq, Debug)]
pub enum Attribute {
    /// Scalar field. `num_comp` describes how many components (1, 2, 3 or 4) there are
    /// in the field.
    Scalars {
        num_comp: u8,
        lookup_table: Option<String>,
        data: IOBuffer,
    },
    /// `num_comp` is called `nValues` in the Vtk documentation.
    ColorScalars {
        num_comp: u8,
        data: IOBuffer,
    },
    LookupTable {
        data: IOBuffer,
    },
    Vectors {
        data: IOBuffer,
    },
    /// Normals are assumed to be normalized.
    Normals {
        data: IOBuffer,
    },
    /// 1D, 2D or 3D texture coordinates are supported by Vtk.
    TextureCoordinates {
        dim: u8,
        data: IOBuffer,
    },
    /// 3x3 symmetric tensors are supported. These are given in full row major form:
    /// ```verbatim
    ///     [t^1_00, t^1_01, t^1_02,
    ///      t^1_10, t^1_11, t^1_12,
    ///      t^1_20, t^1_21, t^1_22,
    ///      ...
    ///      t^{n}_00, t^{n}_01, t^{n}_02,
    ///      t^{n}_10, t^{n}_11, t^{n}_12,
    ///      t^{n}_20, t^{n}_21, t^{n}_22,
    ///     ]
    /// ```
    /// Note that symmetry is assumed (`t^k_ij == t^k_ji`).
    Tensors {
        data: IOBuffer,
    },
    /// Field attribute. Essentially an array of data arrays of any size.
    Field {
        data_array: Vec<FieldArray>,
    },
}

/// Point and cell attributes.
#[derive(Clone, PartialEq, Debug)]
pub struct Attributes {
    pub point: Vec<(String, Attribute)>,
    pub cell: Vec<(String, Attribute)>,
}

impl Attributes {
    pub fn new() -> Self {
        Attributes {
            point: Vec::new(),
            cell: Vec::new(),
        }
    }
}

/// Cell data. Used in `PolyData` and `UnstructuredGrid` datasets. A cell is just geometric object
/// referencing some points like a polygon or tetrahedron.
/// In general it could be one of VERTICES, LINES, POLYGONS, TRIANGLE_STRIPS or CELLS as defined by
/// the VTK standard.
#[derive(Clone, PartialEq, Debug)]
pub struct Cells {
    /// Total number of cells contained in the `vertices` vector.
    pub num_cells: u32,
    /// Each cell in `vertices` is of the form: `n i_1 ... i_n`.
    pub vertices: Vec<u32>,
}

#[derive(Clone, PartialEq, Debug)]
pub enum PolyDataTopology {
    /// Polygon data toplogy structure for vertices.
    Vertices(Cells),
    /// Polygon data toplogy structure for lines.
    Lines(Cells),
    /// Polygon data toplogy structure for polygons.
    Polygons(Cells),
    /// Polygon data toplogy structure for triangle strips.
    TriangleStrips(Cells),
}

/// This enum describes the types of Cells representable by vtk files. These are explicitly written
/// in `UnstructuredGrid`s and some are referred to in `PolyData` datasets.
/// For more details on each of these types see, the
/// [VTK file formats](https://www.vtk.org/wp-content/uploads/2015/04/file-formats.pdf)
/// documentation or `vtkCell.h` in the vtk SDK.
#[derive(Copy, Clone, PartialEq, Debug, FromPrimitive)]
pub enum CellType {
    Vertex = 1,
    PolyVertex = 2,
    Line = 3,
    PolyLine = 4,
    Triangle = 5,
    TriangleStrip = 6,
    Polygon = 7,
    Pixel = 8,
    Quad = 9,
    Tetra = 10,
    Voxel = 11,
    Hexahedron = 12,
    Wedge = 13,
    Pyramid = 14,
    QuadraticEdge = 21,
    QuadraticTriangle = 22,
    QuadraticQuad = 23,
    QuadraticTetra = 24,
    QuadraticHexahedron = 25,
}

/// Dataset described in the file.
/// For 2D objects, `dims[2]` will be set to `0`. For 1D objects, `dims[1]` will also be `0`.
/// This enum is designed to closely represent the data as it is stored in the vtk file.
#[derive(Clone, PartialEq, Debug)]
pub enum DataSet {
    StructuredPoints {
        dims: [u32; 3],
        origin: [f32; 3],
        spacing: [f32; 3],
        data: Attributes,
    },
    StructuredGrid {
        dims: [u32; 3],
        points: IOBuffer,
        data: Attributes,
    },
    /// 3D Unstructured grid. Note that `cells.num_cells` must equal `cell_types.len()`.
    UnstructuredGrid {
        /// A contiguous array of coordinates (x,y,z) representing the points in the mesh.
        points: IOBuffer,
        cells: Cells,
        cell_types: Vec<CellType>,
        data: Attributes,
    },
    /// 3D Polygon data.
    PolyData {
        points: IOBuffer,
        topo: Vec<PolyDataTopology>,
        data: Attributes,
    },
    RectilinearGrid {
        dims: [u32; 3],
        x_coords: IOBuffer,
        y_coords: IOBuffer,
        z_coords: IOBuffer,
        data: Attributes,
    },
    /// Same as one field attribute.
    Field {
        name: String,
        data_array: Vec<FieldArray>,
    },
}

/// Types of data that can be recognized by the parser. Not all data types are supported for all
/// classes.
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum DataType {
    Bit,
    UnsignedChar,
    Char,
    UnsignedShort,
    Short,
    UnsignedInt,
    Int,
    UnsignedLong,
    Long,
    Float,
    Double,
}

impl fmt::Display for DataType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            DataType::Bit => write!(f, "bit"),
            DataType::UnsignedChar => write!(f, "unsigned_char"),
            DataType::Char => write!(f, "char"),
            DataType::UnsignedShort => write!(f, "unsigned_short"),
            DataType::Short => write!(f, "short"),
            DataType::UnsignedInt => write!(f, "unsigned_int"),
            DataType::Int => write!(f, "int"),
            DataType::UnsignedLong => write!(f, "unsigned_long"),
            DataType::Long => write!(f, "long"),
            DataType::Float => write!(f, "float"),
            DataType::Double => write!(f, "double"),
        }
    }
}

impl From<TypeId> for DataType {
    fn from(dt: TypeId) -> Self {
        match dt {
            x if x == TypeId::of::<u8>() => DataType::UnsignedChar,
            x if x == TypeId::of::<i8>() => DataType::Char,
            x if x == TypeId::of::<u16>() => DataType::UnsignedShort,
            x if x == TypeId::of::<i16>() => DataType::Short,
            x if x == TypeId::of::<u32>() => DataType::UnsignedInt,
            x if x == TypeId::of::<i32>() => DataType::Int,
            x if x == TypeId::of::<u64>() => DataType::UnsignedLong,
            x if x == TypeId::of::<i64>() => DataType::Long,
            x if x == TypeId::of::<f32>() => DataType::Float,
            x if x == TypeId::of::<f64>() => DataType::Double,
            _ => panic!("Specified type is unsupported by VTK."),
        }
    }
}