8#ifndef GRIDFORMAT_VTK_VTP_WRITER_HPP_
9#define GRIDFORMAT_VTK_VTP_WRITER_HPP_
17#include <gridformat/common/ranges.hpp>
18#include <gridformat/common/filtered_range.hpp>
19#include <gridformat/common/field_storage.hpp>
20#include <gridformat/common/lvalue_reference.hpp>
22#include <gridformat/grid/grid.hpp>
31 template<
typename Gr
id, std::
size_t size>
32 struct CellTypesPredicate {
33 std::reference_wrapper<const Grid> grid;
34 std::array<CellType, size> cell_types;
36 bool operator()(
const Cell<Grid>& cell)
const {
37 return std::ranges::any_of(cell_types, [&] (
const CellType& _ct) {
38 return _ct == type(grid.get(), cell);
43 template<
typename G, std::
size_t s>
44 CellTypesPredicate(G&&, std::array<CellType, s>&&) -> CellTypesPredicate<std::remove_cvref_t<G>, s>;
45 template<
typename G, std::
size_t s>
46 CellTypesPredicate(G&&,
const std::array<CellType, s>&) -> CellTypesPredicate<std::remove_cvref_t<G>, s>;
55template<Concepts::UnstructuredGr
id Gr
id>
59 static constexpr std::array zero_d_types{CellType::vertex};
60 static constexpr std::array one_d_types{CellType::segment};
61 static constexpr std::array two_d_types{
62 CellType::quadrilateral,
69 explicit VTPWriter(LValueReferenceOf<const Grid> grid,
71 :
ParentType(grid.get(),
".vtp",
false, std::move(xml_opts))
76 return VTPWriter{this->grid(), std::move(xml_opts)};
79 void _write(std::ostream& s)
const override {
80 auto verts_range = _get_cell_range(Detail::CellTypesPredicate{this->grid(), zero_d_types});
81 auto lines_range = _get_cell_range(Detail::CellTypesPredicate{this->grid(), one_d_types});
82 auto polys_range = _get_cell_range(Detail::CellTypesPredicate{this->grid(), two_d_types});
83 auto unsupported_range = _get_cell_range(
84 [p=Detail::CellTypesPredicate{
85 this->grid(), Ranges::merged(Ranges::merged(zero_d_types, one_d_types), two_d_types)
86 }] (
const Cell<Grid>& cell) {
91 if (Ranges::size(unsupported_range) > 0)
92 this->_log_warning(
"Grid contains cell types not supported by .vtp; These will be ignored.");
93 if (!std::ranges::empty(this->_cell_field_names())
94 && !std::ranges::empty(verts_range)
95 + !std::ranges::empty(lines_range)
96 + !std::ranges::empty(polys_range)
99 "You appear to have cell data defined and your grid consists of multiple cell types "
100 "(vertices, lines, polys).\nNote that for correct cell data visualization with vtk, "
101 "your cell iterator must be such that it iterates over the cell types in order "
102 "(vertices -> lines -> polys)."
105 const auto num_verts = Ranges::size(verts_range);
106 const auto num_lines = Ranges::size(lines_range);
107 const auto num_polys = Ranges::size(polys_range);
109 auto context = this->_get_write_context(
"PolyData");
110 this->_set_attribute(context,
"Piece",
"NumberOfPoints", number_of_points(this->grid()));
111 this->_set_attribute(context,
"Piece",
"NumberOfVerts", num_verts);
112 this->_set_attribute(context,
"Piece",
"NumberOfLines", num_lines);
113 this->_set_attribute(context,
"Piece",
"NumberOfStrips",
"0");
114 this->_set_attribute(context,
"Piece",
"NumberOfPolys", num_polys);
116 FieldStorage vtk_point_fields;
117 FieldStorage vtk_cell_fields;
118 std::ranges::for_each(this->_point_field_names(), [&] (
const std::string& name) {
119 vtk_point_fields.set(name, VTK::make_vtk_field(this->_get_point_field_ptr(name)));
120 this->_set_data_array(context,
"Piece/PointData", name, vtk_point_fields.get(name));
122 std::ranges::for_each(this->_cell_field_names(), [&] (
const std::string& name) {
123 vtk_cell_fields.set(name, VTK::make_vtk_field(this->_get_cell_field_ptr(name)));
124 this->_set_data_array(context,
"Piece/CellData", name, vtk_cell_fields.get(name));
127 const FieldPtr coords_field = std::visit([&] <
typename T> (
const Precision<T>&) {
128 return VTK::make_coordinates_field<T>(this->grid(),
false);
129 }, this->_xml_settings.coordinate_precision);
130 this->_set_data_array(context,
"Piece/Points",
"Coordinates", *coords_field);
132 const auto point_id_map = make_point_id_map(this->grid());
133 const auto verts_connectivity_field = _make_connectivity_field(verts_range, point_id_map);
134 const auto verts_offsets_field = _make_offsets_field(verts_range);
135 this->_set_data_array(context,
"Piece/Verts",
"connectivity", *verts_connectivity_field);
136 this->_set_data_array(context,
"Piece/Verts",
"offsets", *verts_offsets_field);
138 const auto lines_connectivity_field = _make_connectivity_field(lines_range, point_id_map);
139 const auto lines_offsets_field = _make_offsets_field(lines_range);
140 this->_set_data_array(context,
"Piece/Lines",
"connectivity", *lines_connectivity_field);
141 this->_set_data_array(context,
"Piece/Lines",
"offsets", *lines_offsets_field);
143 const auto polys_connectivity_field = _make_connectivity_field(polys_range, point_id_map);
144 const auto polys_offsets_field = _make_offsets_field(polys_range);
145 this->_set_data_array(context,
"Piece/Polys",
"connectivity", *polys_connectivity_field);
146 this->_set_data_array(context,
"Piece/Polys",
"offsets", *polys_offsets_field);
148 this->_write_xml(std::move(context), s);
151 template<
typename Predicate>
152 std::ranges::forward_range
auto _get_cell_range(Predicate&& pred)
const {
153 return Ranges::filter_by(std::forward<Predicate>(pred), cells(this->grid()));
156 template<
typename CellsRange,
typename Po
intMap>
157 FieldPtr _make_connectivity_field(CellsRange&& cells,
const PointMap& point_id_map)
const {
158 return std::visit([&] <
typename T> (
const Precision<T>&) {
159 return VTK::make_connectivity_field<T>(this->grid(), cells, point_id_map);
160 }, this->_xml_settings.header_precision);
163 template<
typename CellsRange>
164 FieldPtr _make_offsets_field(CellsRange&& cells)
const {
165 return std::visit([&] <
typename T> (
const Precision<T>&) {
166 return VTK::make_offsets_field<T>(this->grid(), cells);
167 }, this->_xml_settings.header_precision);
std::shared_ptr< const Field > FieldPtr
Pointer type used by writers/readers for fields.
Definition: field.hpp:186
Common functionality for VTK writers.
Helper classes and functions for VTK XML-type file format writers & readers.