Wildmeshing Toolkit
Loading...
Searching...
No Matches
tagged_mesh_data.hpp
1#pragma once
2#include <wmtk/SurfaceTagAttributes.h>
3#include <algorithm>
4#include <array>
5#include <set>
6#include <wmtk/io/ComponentIO.hpp>
7#include <wmtk/io/DataWriter.hpp>
8
9namespace wmtk::io {
10inline MeshData geometry_data(const MatrixXd& V, const MatrixXi& C, CellType type)
11{
12 MeshData data;
13 data.V = DataMatrix<double>::Zero(V.rows(), 3);
14 data.V.leftCols(V.cols()) = V;
15 data.cells[type].connectivity = C.cast<int64_t>();
16 data.validate();
17 return data;
18}
19template <typename Vertex, typename Cell>
20MeshData
21geometry_data(const std::vector<Vertex>& vertices, const std::vector<Cell>& cells, CellType type)
22{
23 MeshData data;
24 data.V = DataMatrix<double>::Zero(vertices.size(), 3);
25 for (size_t i = 0; i < vertices.size(); ++i)
26 for (int j = 0; j < vertices[i].size(); ++j) data.V(i, j) = vertices[i][j];
27 auto& C = data.cells[type].connectivity;
28 C.resize(cells.size(), cell_size(type));
29 for (size_t i = 0; i < cells.size(); ++i)
30 for (int j = 0; j < C.cols(); ++j) C(i, j) = cells[i][j];
31 data.validate();
32 return data;
33}
34template <typename Point>
35MeshData feature_data(
36 const std::vector<std::array<Point, 2>>& segments,
37 const std::vector<Point>& anchors)
38{
39 std::map<std::array<double, 3>, int64_t> rows;
40 MeshData data;
41 std::vector<std::array<double, 3>> vertices;
42 auto vertex = [&](const Point& p) {
43 std::array<double, 3> key{{0, 0, 0}};
44 for (int i = 0; i < p.size(); ++i) key[i] = p[i];
45 auto [it, added] = rows.emplace(key, rows.size());
46 if (added) vertices.push_back(key);
47 return it->second;
48 };
49 auto& E = data.cells[CellType::Edge].connectivity;
50 E.resize(segments.size(), 2);
51 for (size_t i = 0; i < segments.size(); ++i) {
52 E(i, 0) = vertex(segments[i][0]);
53 E(i, 1) = vertex(segments[i][1]);
54 }
55 auto& P = data.cells[CellType::Point].connectivity;
56 P.resize(anchors.size(), 1);
57 for (size_t i = 0; i < anchors.size(); ++i) P(i, 0) = vertex(anchors[i]);
58 data.V.resize(vertices.size(), 3);
59 for (size_t i = 0; i < vertices.size(); ++i)
60 for (int j = 0; j < 3; ++j) data.V(i, j) = vertices[i][j];
61 data.validate();
62 return data;
63}
64template <typename Mesh, typename TupleRange, typename Tags>
65void collect_tags(Mesh& mesh, MeshMap& outputs, CellType type, const TupleRange& cells, Tags tags)
66{
67 // A result without cells has no block yet: the exporter only creates the ones it fills.
68 auto& block = outputs.at("mesh").cells[type];
69 if (block.connectivity.cols() != cell_size(type)) block.connectivity.resize(0, cell_size(type));
70 // An unnamed tag is called tag_<id>, unless that name is taken, in which case '_' is
71 // appended as SimWildMesh::write_msh does; labels must be unique.
72 std::set<std::string> named, labelled;
73 for (const auto& [id, name] : mesh.m_tag_id_to_name) named.insert(name);
74 std::vector<std::string> labels;
75 for (size_t j = 0; j < mesh.m_tags_count; ++j) {
76 const auto it = mesh.m_tag_id_to_name.find(j);
77 const bool unnamed = it == mesh.m_tag_id_to_name.end();
78 std::string label = unnamed ? "tag_" + std::to_string(j) : it->second;
79 while (labelled.count(label) || (unnamed && named.count(label))) label += "_";
80 labelled.insert(label);
81 labels.push_back(label);
82 }
83 DataMatrix<uint8_t> values = DataMatrix<uint8_t>::Zero(cells.size(), labels.size());
84 for (size_t i = 0; i < cells.size(); ++i)
85 for (size_t j = 0; j < labels.size(); ++j) values(i, j) = tags(cells[i]).count(j) ? 1 : 0;
86 // The fixed tags field replaces per-group named scalar arrays.
87 for (size_t j = 0; j < labels.size(); ++j) {
88 block.attributes.erase(labels[j]);
89 block.attributes.erase("tag_" + std::to_string(j));
90 }
91 // Cells without a tag are the background the component built. They are labelled
92 // explicitly: the IO infers nothing from an empty row.
93 if (std::find(labels.begin(), labels.end(), "ambient") == labels.end()) {
94 const auto empty = (values.template cast<int>().rowwise().sum().array() == 0).eval();
95 if (labels.empty() || empty.any()) {
96 values.conservativeResize(Eigen::NoChange, values.cols() + 1);
97 values.col(values.cols() - 1) = empty.template cast<uint8_t>();
98 labels.push_back("ambient");
99 }
100 }
101 block.attributes["tags"] = {std::move(values), std::move(labels)};
102}
103// The faces whose input set is not empty, as the triangle block of outputs["mesh"]: rows of its
104// V (the vertices in get_vertices() order, as compact_slot_outputs leaves them), one tags
105// column per name (bit j of the input set is names[j]), each row oriented as the face's input
106// was. Nothing is written without names.
107template <typename Mesh>
108void collect_face_tags(const Mesh& mesh, MeshMap& outputs, const std::vector<std::string>& names)
109{
110 if (names.empty()) return;
111 std::vector<int64_t> row(mesh.vert_capacity(), -1);
112 int64_t n = 0;
113 for (const auto& v : mesh.get_vertices()) row[v.vid(mesh)] = n++;
114 std::vector<std::array<int64_t, 3>> faces;
115 std::vector<InputSet> sets;
116 const InputSet mask = names.size() >= size_t(SurfaceTagAttributes::max_inputs)
117 ? ~InputSet(0)
118 : (InputSet(1) << names.size()) - 1;
119 for (const auto& f : mesh.get_faces()) {
120 const auto& attr = mesh.m_face_attribute[f.fid(mesh)];
121 // Bits past the names are not face tags -- simwild's region labels -- and are not written.
122 const InputSet set = attr.input_set() & mask;
123 if (set == 0) continue;
124 auto vids = mesh.get_face_vids(f);
125 std::sort(vids.begin(), vids.end());
126 if (attr.orientation_along(vids) < 0) std::swap(vids[1], vids[2]);
127 faces.push_back({{row[vids[0]], row[vids[1]], row[vids[2]]}});
128 sets.push_back(set);
129 }
130 auto& block = outputs.at("mesh").cells[CellType::Triangle];
131 block.connectivity.resize(faces.size(), 3);
132 DataMatrix<uint8_t> member = DataMatrix<uint8_t>::Zero(faces.size(), names.size());
133 for (size_t i = 0; i < faces.size(); ++i) {
134 for (int k = 0; k < 3; ++k) block.connectivity(i, k) = faces[i][k];
135 for (size_t j = 0; j < names.size(); ++j) member(i, j) = (sets[i] >> j) & 1;
136 }
137 block.attributes["tags"] = {std::move(member), names};
138}
139} // namespace wmtk::io
static constexpr int max_inputs
One input per bit of InputSet: the width is set there, and only there.
Definition SurfaceTagAttributes.h:130