17 std::optional<std::vector<uint8_t>> recorded_history, recorded_volume_history;
20 const MeshMap* inputs =
nullptr;
21 ComponentResult result{{}, nlohmann::json::object()};
22 explicit ComponentIO(
const MeshMap* meshes =
nullptr)
23 : logging(meshes !=
nullptr)
26 bool memory()
const {
return inputs !=
nullptr; }
36 logger().info(
"history: {} edits saved to {}", h.edits.size(), path);
41 "history: {} edits, {} bytes, returned in the report",
43 recorded_history->size());
49 void save_volume_history(std::vector<uint8_t> bytes,
const std::string& path)
54 "volume history: {:.1f} MB saved to {}",
55 double(bytes.size()) / 1e6,
60 "volume history: {:.1f} MB, returned in the report",
61 double(bytes.size()) / 1e6);
62 recorded_volume_history = std::move(bytes);
67 std::string history_metadata(
const nlohmann::json& params)
const
69 nlohmann::json metadata = params;
70 metadata[
"route"] = memory() ?
"memory" :
"file";
71 return metadata.dump();
75 ComponentResult take_result()
78 result.second[
"history"] = nlohmann::json::binary(std::move(*recorded_history));
79 if (recorded_volume_history) {
80 result.second[
"volume_history"] =
81 nlohmann::json::binary(std::move(*recorded_volume_history));
83 recorded_history.reset();
84 recorded_volume_history.reset();
85 return std::move(result);
87 const MeshData& mesh(
const std::string& name)
const
89 const auto it = inputs->find(name);
90 if (it == inputs->end())
throw std::runtime_error(
"Unknown input mesh: " + name);
91 it->second.validate();
97 inline static const std::set<std::string> reader_vertex_attributes = {
"vid"};
98 inline static const std::set<std::string> reader_corner_attributes = {
"uv",
"normal"};
99 static void attributes(
100 const MeshAttributes& a,
101 const std::set<std::string>& allowed,
102 const std::set<std::string>& required = {})
104 for (
const auto& name : required)
106 throw std::runtime_error(
"Missing required mesh attribute: " + name);
107 for (
const auto& [name, field] : a)
108 if (!allowed.count(name))
throw std::runtime_error(
"Unknown mesh attribute: " + name);
110 std::string path(
const std::filesystem::path& root,
const nlohmann::json& selector)
const
112 return memory() ? selector.get<std::string>()
113 : utils::resolve_path(root, selector.get<std::string>()).string();
115 std::vector<std::string> paths(
116 const std::filesystem::path& root,
117 const nlohmann::json& selectors)
const
119 if (selectors.is_string())
return {path(root, selectors)};
120 std::vector<std::string> out;
121 for (
const auto& v : selectors) out.push_back(path(root, v));
129 const std::string& name,
132 const std::set<std::string>& vertex_attributes = reader_vertex_attributes,
133 const std::set<std::string>& triangle_attributes = {})
const
135 const auto& data = mesh(name);
136 attributes(data.vertex_attributes, vertex_attributes);
137 std::set<std::string> allowed = reader_corner_attributes;
138 allowed.insert(triangle_attributes.begin(), triangle_attributes.end());
139 for (
const auto& [type, c] : data.cells) {
140 if (type != CellType::Triangle)
141 throw std::runtime_error(
"Expected triangle input: " + name);
142 attributes(c.attributes, allowed);
145 F = indices(data.cell(CellType::Triangle).connectivity);
146 if (!F.rows())
throw std::runtime_error(
"Empty triangle input: " + name);
149 const std::string& name,
153 double abs = -1)
const
156 read_triangle_mesh(name, V, F, rel, abs);
159 raw_triangles(name, V, F);
160 clean_triangle_mesh(V, F, rel, abs);
161 if (!F.rows())
throw std::runtime_error(
"No faces after cleaning: " + name);
169 const std::vector<std::string>& names,
174 std::vector<int>* provenance =
nullptr,
176 const std::set<std::string>& vertex_attributes = reader_vertex_attributes,
177 const std::set<std::string>& triangle_attributes = {})
const
180 read_triangle_mesh(names, V, F, rel, abs, provenance, read);
185 if (provenance) provenance->clear();
186 for (
size_t i = 0; i < names.size(); ++i) {
189 raw_triangles(names[i], v, f, vertex_attributes, triangle_attributes);
190 const auto nv = V.rows(), nf = F.rows();
192 V.conservativeResize(nv + v.rows(), 3);
193 V.bottomRows(v.rows()) = v;
194 F.conservativeResize(nf + f.rows(), 3);
195 F.bottomRows(f.rows()) = f;
196 if (provenance) provenance->resize(F.rows(),
int(i));
198 clean_triangle_mesh(V, F, rel, abs, provenance, read);
199 if (!F.rows())
throw std::runtime_error(
"No faces after cleaning");
204 const std::string& name,
212 read_edge_mesh(name, V, E, rel, abs, read);
215 const auto& data = mesh(name);
216 attributes(data.vertex_attributes, reader_vertex_attributes);
217 for (
const auto& [type, c] : data.cells) {
218 if (type != CellType::Edge && type != CellType::Point)
219 throw std::runtime_error(
"Expected curves or points: " + name);
220 attributes(c.attributes, {});
224 auto it = data.cells.find(CellType::Edge);
225 if (it != data.cells.end()) E = indices(it->second.connectivity);
226 clean_edge_mesh(V, E, rel, abs, read);
228 static MatrixXi indices(
const DataMatrix<int64_t>& c)
230 if (c.size() && (c.maxCoeff() > std::numeric_limits<int>::max() || c.minCoeff() < 0))
231 throw std::runtime_error(
"Connectivity exceeds internal index range");
232 return c.cast<
int>();
234 void prepare(nlohmann::json& j,
const std::string& component)
const
236 if (!memory())
return;
237 if ((component ==
"simwild" || component ==
"tetwild" || component ==
"triwild") &&
238 j.contains(
"input") && j[
"input"].is_string())
239 j[
"input"] = nlohmann::json::array({j[
"input"]});
240 j[
"application"] = component;
void write_history(const std::filesystem::path &path, const std::vector< uint8_t > &bytes)
Definition History.cpp:439
A complex and the edits it went through, in commit order.
Definition History.hpp:101
void save(const std::string &path) const
Definition History.cpp:323
std::vector< uint8_t > to_bytes() const
The bytes of a history file, in memory: what a component's memory route returns.
Definition History.cpp:341