19#include <lagrange/utils/warnoff.h>
20#include <igl/writeOBJ.h>
21#include <lagrange/utils/warnon.h>
24#include <lagrange/Mesh.h>
25#include <lagrange/MeshTrait.h>
26#include <lagrange/common.h>
27#include <lagrange/utils/assert.h>
28#include <lagrange/utils/range.h>
29#include <lagrange/utils/safe_cast.h>
30#include <lagrange/legacy/inline.h>
32#include <lagrange/io/legacy/save_mesh_ply.h>
34#include <lagrange/fs/filesystem.h>
41template <
typename MeshType>
42void save_mesh_2D(
const fs::path& filename,
const MeshType& mesh)
44 fs::ofstream fout(filename);
45 const auto& vertices = mesh.get_vertices();
47 fout <<
"v " << vertices(i, 0) <<
" " << vertices(i, 1) << std::endl;
50 const auto& facets = mesh.get_facets();
54 for (
auto j :
range(vertex_per_facet)) {
55 fout <<
" " << facets(i, j) + 1;
62template <
typename MeshType>
63void save_mesh_basic(
const fs::path& filename,
const MeshType& mesh)
65 if (mesh.get_dim() == 2) {
66 save_mesh_2D(filename, mesh);
68 const auto& vertices = mesh.get_vertices();
69 const auto& facets = mesh.get_facets();
70 igl::writeOBJ(filename.string(), vertices, facets);
74template <
typename MeshType,
typename DerivedV,
typename DerivedF>
75void extract_attribute(
77 const std::string& attr_name,
78 Eigen::MatrixBase<DerivedV>& values,
79 Eigen::MatrixBase<DerivedF>& indices)
81 const auto& facets = mesh.get_facets();
82 if (mesh.has_indexed_attribute(attr_name)) {
84 values = std::get<0>(attr);
85 indices = std::get<1>(attr);
86 }
else if (mesh.has_corner_attribute(attr_name)) {
87 values = mesh.get_corner_attribute(attr_name);
88 indices.derived().resize(facets.rows(), facets.cols());
89 typename MeshType::Index count = 0;
90 for (
auto i :
range(facets.rows())) {
91 for (
auto j :
range(facets.cols())) {
92 indices(i, j) = count;
96 }
else if (mesh.has_vertex_attribute(attr_name)) {
97 values = mesh.get_vertex_attribute(attr_name);
102template <
typename MeshType>
105 using Scalar =
typename MeshType::Scalar;
106 using Index =
typename MeshType::Index;
108 const auto& vertices = mesh.get_vertices();
109 const auto& facets = mesh.get_facets();
111 Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> CN;
112 Eigen::Matrix<Index, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> FN;
113 Eigen::Matrix<Scalar, Eigen::Dynamic, 2, Eigen::RowMajor> TC;
114 Eigen::Matrix<Index, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> FTC;
116 extract_attribute(mesh,
"uv", TC, FTC);
117 extract_attribute(mesh,
"normal", CN, FN);
119 igl::writeOBJ(filename.string(), vertices, facets, CN, FN, TC, FTC);
122template <
typename MeshType>
124 const fs::path& filename,
126 const std::vector<std::string>& face_attrib_names,
127 const std::vector<std::string>& vertex_attrib_names)
129 using AttributeArray =
typename MeshType::AttributeArray;
131 auto write_connectivity = [&](std::ostream& fl) {
142 fl <<
"# vtk DataFile Version 2.0\n";
143 fl <<
"Lagrange output mesh\n";
145 fl <<
"DATASET UNSTRUCTURED_GRID\n";
151 auto xyz = mesh.get_vertices().row(vnidx).eval();
152 if (xyz.cols() == 3) {
153 fl << xyz(0) <<
" " << xyz(1) <<
" " << xyz(2) <<
"\n";
154 }
else if (xyz.cols() == 2) {
155 fl << xyz(0) <<
" " << xyz(1) <<
" " << 0 <<
"\n";
157 throw std::runtime_error(
"This dimension is not supported");
172 fl << mesh.get_facets()(fn, voffset) <<
" ";
188 auto write_vertex_data_header = [&](std::ostream& fl) {
192 auto write_cell_data_header = [&](std::ostream& fl) {
197 [](std::ostream& fl,
const std::string attrib_name,
const AttributeArray& attrib) {
198 fl <<
"SCALARS " << attrib_name <<
" float " << attrib.cols() <<
"\n";
199 fl <<
"LOOKUP_TABLE default \n";
200 for (
auto row :
range(attrib.rows())) {
201 for (
auto col :
range(attrib.cols())) {
202 fl << attrib(row, col) <<
" ";
210 fs::ofstream fl(filename, fs::fstream::out);
212 fl.flags(fs::fstream::scientific);
216 write_connectivity(fl);
221 bool has_any_facet_attrib =
false;
222 for (
const auto& attrib_name : face_attrib_names) {
223 if (mesh.has_facet_attribute(attrib_name)) {
224 has_any_facet_attrib =
true;
229 if (has_any_facet_attrib) {
230 write_cell_data_header(fl);
233 for (
const auto& attrib_name : face_attrib_names) {
234 if (mesh.has_facet_attribute(attrib_name)) {
235 write_data(fl, attrib_name, mesh.get_facet_attribute(attrib_name));
244 bool has_any_vertex_attrib =
false;
245 for (
const auto& attrib_name : vertex_attrib_names) {
246 if (mesh.has_vertex_attribute(attrib_name)) {
247 has_any_vertex_attrib =
true;
253 if (has_any_vertex_attrib) {
254 write_vertex_data_header(fl);
258 for (
const auto& attrib_name : vertex_attrib_names) {
259 if (mesh.has_vertex_attribute(attrib_name)) {
260 write_data(fl, attrib_name, mesh.get_vertex_attribute(attrib_name));
271template <
typename MeshType>
274 static_assert(MeshTrait<MeshType>::is_mesh(),
"Input type is not Mesh");
276 if (filename.extension() ==
".obj") {
277 internal::save_mesh_obj(filename, mesh);
278 }
else if (filename.extension() ==
".vtk") {
279 internal::save_mesh_vtk(
282 mesh.get_facet_attribute_names(),
283 mesh.get_vertex_attribute_names());
284 }
else if (filename.extension() ==
".ply") {
287 internal::save_mesh_basic(filename, mesh);
Index get_num_vertices() const
Retrieves the number of vertices.
Definition: SurfaceMesh.h:671
auto get_indexed_attribute(std::string_view name) const -> const IndexedAttribute< ValueType, Index > &
Gets a read-only reference to an indexed attribute given its name.
Definition: SurfaceMesh.cpp:1310
Index get_num_facets() const
Retrieves the number of facets.
Definition: SurfaceMesh.h:678
Index get_vertex_per_facet() const
Retrieves the number of vertex per facet in a regular mesh.
Definition: SurfaceMesh.cpp:2118
#define la_runtime_assert(...)
Runtime assertion check.
Definition: assert.h:169
internal::Range< Index > range(Index end)
Returns an iterable object representing the range [0, end).
Definition: range.h:176
Mesh input/output.
Definition: detect_file_format.h:18
void save_mesh(std::ostream &output_stream, const SurfaceMesh< Scalar, Index > &mesh, FileFormat format, const SaveOptions &options={})
Save a mesh to a stream.
Definition: save_mesh.cpp:30
void save_mesh_obj(std::ostream &output_stream, const SurfaceMesh< Scalar, Index > &mesh, const SaveOptions &options={})
Saves a mesh to a stream in OBJ format.
Definition: save_mesh_obj.cpp:31
void save_mesh_ply(std::ostream &output_stream, const SurfaceMesh< Scalar, Index > &mesh, const SaveOptions &options={})
Saves a mesh to a stream in PLY format.
Definition: save_mesh_ply.cpp:214