Line | Branch | Exec | Source |
---|---|---|---|
1 | // SPDX-FileCopyrightText: 2022-2023 Dennis Gläser <dennis.glaeser@iws.uni-stuttgart.de> | ||
2 | // SPDX-License-Identifier: MIT | ||
3 | /*! | ||
4 | * \file | ||
5 | * \ingroup VTK | ||
6 | * \copydoc GridFormat::VTIReader | ||
7 | */ | ||
8 | #ifndef GRIDFORMAT_VTK_VTI_READER_HPP_ | ||
9 | #define GRIDFORMAT_VTK_VTI_READER_HPP_ | ||
10 | |||
11 | #include <string> | ||
12 | #include <optional> | ||
13 | #include <algorithm> | ||
14 | #include <utility> | ||
15 | #include <ranges> | ||
16 | #include <array> | ||
17 | #include <cmath> | ||
18 | |||
19 | #include <gridformat/common/exceptions.hpp> | ||
20 | #include <gridformat/common/precision.hpp> | ||
21 | #include <gridformat/common/ranges.hpp> | ||
22 | #include <gridformat/common/field.hpp> | ||
23 | #include <gridformat/common/lazy_field.hpp> | ||
24 | |||
25 | #include <gridformat/grid/reader.hpp> | ||
26 | #include <gridformat/vtk/common.hpp> | ||
27 | #include <gridformat/vtk/xml.hpp> | ||
28 | |||
29 | namespace GridFormat { | ||
30 | |||
31 | /*! | ||
32 | * \ingroup VTK | ||
33 | * \brief Reader for .vti file format | ||
34 | */ | ||
35 | class VTIReader : public GridReader { | ||
36 | private: | ||
37 | struct ImageSpecs { | ||
38 | std::array<std::size_t, 6> extents; | ||
39 | std::array<double, 3> spacing; | ||
40 | std::array<double, 3> origin; | ||
41 | std::array<double, 9> direction; | ||
42 | }; | ||
43 | |||
44 | 300 | void _open(const std::string& filename, typename GridReader::FieldNames& fields) override { | |
45 |
1/2✓ Branch 2 taken 300 times.
✗ Branch 3 not taken.
|
300 | auto helper = VTK::XMLReaderHelper::make_from(filename, "ImageData"); |
46 | 300 | auto specs = ImageSpecs{}; | |
47 |
3/6✓ Branch 2 taken 300 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 300 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 300 times.
✗ Branch 10 not taken.
|
300 | specs.extents = Ranges::array_from_string<std::size_t, 6>(helper.get("ImageData/Piece").get_attribute("Extent")); |
48 |
3/6✓ Branch 2 taken 300 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 300 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 300 times.
✗ Branch 10 not taken.
|
300 | specs.spacing = Ranges::array_from_string<double, 3>(helper.get("ImageData").get_attribute("Spacing")); |
49 |
3/6✓ Branch 2 taken 300 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 300 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 300 times.
✗ Branch 10 not taken.
|
300 | specs.origin = Ranges::array_from_string<double, 3>(helper.get("ImageData").get_attribute("Origin")); |
50 |
3/6✓ Branch 2 taken 300 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 300 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 300 times.
✗ Branch 10 not taken.
|
600 | specs.direction = Ranges::array_from_string<double, 9>(helper.get("ImageData").get_attribute_or( |
51 |
1/2✓ Branch 1 taken 300 times.
✗ Branch 2 not taken.
|
600 | std::string{"1 0 0 0 1 0 0 0 1"}, "Direction" |
52 | )); | ||
53 | |||
54 |
2/4✓ Branch 2 taken 300 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 300 times.
✗ Branch 6 not taken.
|
300 | VTK::XMLDetail::copy_field_names_from(helper.get("ImageData"), fields); |
55 | 300 | _helper.emplace(std::move(helper)); | |
56 | 300 | _image_specs.emplace(std::move(specs)); | |
57 | 300 | } | |
58 | |||
59 | 44 | void _close() override { | |
60 | 44 | _helper.reset(); | |
61 | 44 | _image_specs.reset(); | |
62 | 44 | } | |
63 | |||
64 | 1 | std::string _name() const override { | |
65 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
2 | return "VTIReader"; |
66 | } | ||
67 | |||
68 | 1543 | std::size_t _number_of_cells() const override { | |
69 | 1543 | return VTK::CommonDetail::number_of_entities(_specs().extents); | |
70 | } | ||
71 | |||
72 | 1544 | std::size_t _number_of_points() const override { | |
73 |
2/4✓ Branch 1 taken 1544 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1404 times.
✗ Branch 5 not taken.
|
1544 | return VTK::CommonDetail::number_of_entities(_point_extents()); |
74 | } | ||
75 | |||
76 | 7 | std::size_t _number_of_pieces() const override { | |
77 | 7 | return 1; | |
78 | } | ||
79 | |||
80 | 13 | typename GridReader::Vector _origin() const override { | |
81 | 13 | return _specs().origin; | |
82 | } | ||
83 | |||
84 | 13 | typename GridReader::Vector _spacing() const override { | |
85 | 13 | return _specs().spacing; | |
86 | } | ||
87 | |||
88 | ✗ | typename GridReader::Vector _basis_vector(unsigned int i) const override { | |
89 | ✗ | const auto specs = _specs(); | |
90 | return { | ||
91 | ✗ | specs.direction.at(i), | |
92 | ✗ | specs.direction.at(i+3), | |
93 | ✗ | specs.direction.at(i+6) | |
94 | ✗ | }; | |
95 | } | ||
96 | |||
97 | 314 | typename GridReader::PieceLocation _location() const override { | |
98 | 314 | const auto& specs = _specs(); | |
99 | typename GridReader::PieceLocation result; | ||
100 | 314 | result.lower_left = {specs.extents[0], specs.extents[2], specs.extents[4]}; | |
101 | 314 | result.upper_right = {specs.extents[1], specs.extents[3], specs.extents[5]}; | |
102 | 314 | return result; | |
103 | } | ||
104 | |||
105 | 34 | std::vector<double> _ordinates(unsigned int direction) const override { | |
106 |
1/2✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
|
34 | const auto& specs = _specs(); |
107 |
1/2✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
|
34 | const auto extents = _point_extents(); |
108 | 34 | const auto extent_begin = extents[direction*2]; | |
109 | 34 | const std::size_t num_ordinates = extents[2*direction + 1] - extent_begin; | |
110 |
1/2✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
|
34 | std::vector<double> ordinates(num_ordinates); |
111 |
1/2✓ Branch 2 taken 34 times.
✗ Branch 3 not taken.
|
68 | std::ranges::copy( |
112 |
2/4✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 34 times.
✗ Branch 5 not taken.
|
34 | std::views::iota(std::size_t{0}, num_ordinates) | std::views::transform([&] (std::size_t i) { |
113 | 122 | return specs.origin[direction] + (extent_begin + i)*specs.spacing[direction]; | |
114 |
1/2✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
|
34 | }), |
115 | ordinates.begin() | ||
116 | ); | ||
117 | 34 | return ordinates; | |
118 | ✗ | } | |
119 | |||
120 | 85 | bool _is_sequence() const override { | |
121 | 85 | return false; | |
122 | } | ||
123 | |||
124 | 217 | FieldPtr _points() const override { | |
125 |
1/2✓ Branch 1 taken 217 times.
✗ Branch 2 not taken.
|
217 | const auto pextents = _point_extents(); |
126 |
1/2✓ Branch 1 taken 207 times.
✗ Branch 2 not taken.
|
217 | const auto num_points = VTK::CommonDetail::number_of_entities(pextents); |
127 | 217 | return make_field_ptr(LazyField{ | |
128 | int{}, // dummy "source" | ||
129 | ✗ | MDLayout{{num_points, std::size_t{3}}}, | |
130 | Precision<double>{}, | ||
131 |
1/2✓ Branch 1 taken 217 times.
✗ Branch 2 not taken.
|
217 | [specs=_specs(), pextents=pextents] (const int&) { |
132 | return VTK::CommonDetail::serialize_structured_points( | ||
133 | 217 | pextents, | |
134 | 217 | specs.origin, | |
135 | 217 | specs.spacing, | |
136 | 217 | specs.direction | |
137 | 217 | ); | |
138 | } | ||
139 |
3/6✓ Branch 1 taken 217 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 217 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 217 times.
✗ Branch 9 not taken.
|
651 | }); |
140 | } | ||
141 | |||
142 | 321 | void _visit_cells(const typename GridReader::CellVisitor& visitor) const override { | |
143 | 321 | VTK::CommonDetail::visit_structured_cells(visitor, _specs().extents); | |
144 | 321 | } | |
145 | |||
146 | 737 | FieldPtr _cell_field(std::string_view name) const override { | |
147 |
2/4✓ Branch 2 taken 737 times.
✗ Branch 3 not taken.
✓ Branch 7 taken 737 times.
✗ Branch 8 not taken.
|
737 | return _helper.value().make_data_array_field(name, "ImageData/Piece/CellData", _number_of_cells()); |
148 | } | ||
149 | |||
150 | 740 | FieldPtr _point_field(std::string_view name) const override { | |
151 |
2/4✓ Branch 2 taken 740 times.
✗ Branch 3 not taken.
✓ Branch 7 taken 740 times.
✗ Branch 8 not taken.
|
740 | return _helper.value().make_data_array_field(name, "ImageData/Piece/PointData", _number_of_points()); |
152 | } | ||
153 | |||
154 | 54 | FieldPtr _meta_data_field(std::string_view name) const override { | |
155 |
1/2✓ Branch 4 taken 54 times.
✗ Branch 5 not taken.
|
54 | return _helper.value().make_data_array_field(name, "ImageData/FieldData"); |
156 | } | ||
157 | |||
158 | 1795 | std::array<std::size_t, 6> _point_extents() const { | |
159 | 1795 | auto result = _specs().extents; | |
160 | 1795 | result[1] += 1; | |
161 | 1795 | result[3] += 1; | |
162 | 1795 | result[5] += 1; | |
163 | 1795 | return result; | |
164 | } | ||
165 | |||
166 | 4250 | const ImageSpecs& _specs() const { | |
167 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 4250 times.
|
4250 | if (!_image_specs.has_value()) |
168 | ✗ | throw ValueError("No data has been read"); | |
169 | 4250 | return _image_specs.value(); | |
170 | } | ||
171 | |||
172 | std::optional<VTK::XMLReaderHelper> _helper; | ||
173 | std::optional<ImageSpecs> _image_specs; | ||
174 | }; | ||
175 | |||
176 | } // namespace GridFormat | ||
177 | |||
178 | #endif // GRIDFORMAT_VTK_VTI_READER_HPP_ | ||
179 |