Commit 5f8df80c authored by Philip Trettner's avatar Philip Trettner
Browse files

removed glm/tg dependency. Renamed field_3d to field3

parent 80d2dc43
......@@ -13,19 +13,6 @@ target_include_directories(polymesh PUBLIC src/)
if (MSVC)
target_compile_options(polymesh PUBLIC /MP)
else()
target_compile_options(polymesh PRIVATE -Wall -Werror -fPIC)
target_compile_options(polymesh PRIVATE -Wall -fPIC)
target_link_libraries(polymesh PUBLIC -fuse-ld=gold)
endif()
# optional libs:
if (TARGET glm)
target_link_libraries(polymesh PUBLIC glm)
target_compile_definitions(polymesh PUBLIC POLYMESH_SUPPORT_GLM)
message(STATUS "enabled polymesh support for glm")
endif()
if (TARGET typed-geometry)
target_link_libraries(polymesh PUBLIC typed-geometry)
target_compile_definitions(polymesh PUBLIC POLYMESH_SUPPORT_TYPED_GEOMETRY)
message(STATUS "enabled polymesh support for typed geometry")
endif()
......@@ -8,7 +8,7 @@ namespace polymesh
/// calculates the barycentric coordinates of a given point p within a face f
/// NOTE: asserts that f is triangular
/// NOTE: also works for other points in the same plane as f
template <class Vec3, class Scalar = typename field_3d<Vec3>::Scalar>
template <class Vec3, class Scalar = typename field3<Vec3>::Scalar>
std::array<Scalar, 3> barycoords(face_handle f, vertex_attribute<Vec3> const& positions, Vec3 p);
/// ======== IMPLEMENTATION ========
......@@ -24,15 +24,15 @@ std::array<Scalar, 3> barycoords(face_handle f, vertex_attribute<Vec3> const& po
auto e21 = ps[2] - ps[1];
auto e02 = ps[0] - ps[2];
auto n = field_3d<Vec3>::cross(e10, e21);
auto n = field3<Vec3>::cross(e10, e21);
auto signed_area = [&](Vec3 const& v0, Vec3 const& v1, Vec3 const& v2) {
auto d1 = v1 - v0;
auto d2 = v2 - v0;
auto a = field_3d<Vec3>::cross(d1, d2);
auto a = field3<Vec3>::cross(d1, d2);
return field_3d<Vec3>::dot(a, n);
return field3<Vec3>::dot(a, n);
};
auto a = signed_area(ps[0], ps[1], ps[2]);
......
......@@ -12,7 +12,7 @@ namespace polymesh
*
* auto nnf = make_geodesic_nnf(mesh, positions);
*/
template <class Vec3, class Scalar = typename field_3d<Vec3>::Scalar>
template <class Vec3, class Scalar = typename field3<Vec3>::Scalar>
struct GeodesicNNF
{
public:
......@@ -23,7 +23,7 @@ private:
vertex_attribute<Vec3> const& position;
};
template <class Vec3, class Scalar = typename field_3d<Vec3>::Scalar>
template <class Vec3, class Scalar = typename field3<Vec3>::Scalar>
GeodesicNNF<Vec3, Scalar> make_geodesic_nnf(Mesh const& m, vertex_attribute<Vec3> const& position);
}
......
......@@ -53,7 +53,7 @@ bool is_triangle_mesh(Mesh const& m);
bool is_quad_mesh(Mesh const& m);
/// returns the area of the (flat) polygonal face
template <class Vec3, class Scalar = typename field_3d<Vec3>::Scalar>
template <class Vec3, class Scalar = typename field3<Vec3>::Scalar>
Scalar face_area(face_handle f, vertex_attribute<Vec3> const& position);
/// returns the center of gravity for a given (flat) polygonal face
......@@ -65,7 +65,7 @@ template <class Vec3>
Vec3 face_normal(face_handle f, vertex_attribute<Vec3> const& position);
/// returns the area of a given triangle
template <class Vec3, class Scalar = typename field_3d<Vec3>::Scalar>
template <class Vec3, class Scalar = typename field3<Vec3>::Scalar>
Scalar triangle_area(face_handle f, vertex_attribute<Vec3> const& position);
/// returns the center of gravity for a given triangle
......@@ -85,11 +85,11 @@ template <class Vec3>
Vec3 bary_interpolate(face_handle f, Vec3 bary, vertex_attribute<Vec3> const& position);
/// returns the length of an edge
template <class Vec3, class Scalar = typename field_3d<Vec3>::Scalar>
template <class Vec3, class Scalar = typename field3<Vec3>::Scalar>
Scalar edge_length(edge_handle e, vertex_attribute<Vec3> const& position);
/// returns the length of an edge
template <class Vec3, class Scalar = typename field_3d<Vec3>::Scalar>
template <class Vec3, class Scalar = typename field3<Vec3>::Scalar>
Scalar edge_length(halfedge_handle h, vertex_attribute<Vec3> const& position);
/// returns the (non-normalized) vector from -> to
......@@ -101,42 +101,42 @@ template <class Vec3>
Vec3 edge_dir(halfedge_handle h, vertex_attribute<Vec3> const& position);
/// calculates the angle between this half-edge and the next one
template <class Vec3, class Scalar = typename field_3d<Vec3>::Scalar>
template <class Vec3, class Scalar = typename field3<Vec3>::Scalar>
Scalar angle_to_next(halfedge_handle h, vertex_attribute<Vec3> const& position);
/// calculates the angle between this half-edge and the previous one
template <class Vec3, class Scalar = typename field_3d<Vec3>::Scalar>
template <class Vec3, class Scalar = typename field3<Vec3>::Scalar>
Scalar angle_to_prev(halfedge_handle h, vertex_attribute<Vec3> const& position);
/// sum of face angles at this vertex
template <class Vec3, class Scalar = typename field_3d<Vec3>::Scalar>
template <class Vec3, class Scalar = typename field3<Vec3>::Scalar>
Scalar angle_sum(vertex_handle v, vertex_attribute<Vec3> const& position);
/// difference between 2pi and the angle sum (positive means less than 2pi)
template <class Vec3, class Scalar = typename field_3d<Vec3>::Scalar>
template <class Vec3, class Scalar = typename field3<Vec3>::Scalar>
Scalar angle_defect(vertex_handle v, vertex_attribute<Vec3> const& position);
/// efficiently computes the voronoi areas of all vertices
/// assumes triangle meshes for now
template <class Vec3, class Scalar = typename field_3d<Vec3>::Scalar>
template <class Vec3, class Scalar = typename field3<Vec3>::Scalar>
vertex_attribute<Scalar> vertex_voronoi_areas(Mesh const& m, vertex_attribute<Vec3> const& position);
/// efficiently computes vertex normals by uniformly weighting face normals
/// assumes triangle meshes for now
template <class Vec3, class Scalar = typename field_3d<Vec3>::Scalar>
template <class Vec3, class Scalar = typename field3<Vec3>::Scalar>
vertex_attribute<Vec3> vertex_normals_uniform(Mesh const& m, vertex_attribute<Vec3> const& position);
/// efficiently computes vertex normals by area weighting face normals
/// assumes triangle meshes for now
template <class Vec3, class Scalar = typename field_3d<Vec3>::Scalar>
template <class Vec3, class Scalar = typename field3<Vec3>::Scalar>
vertex_attribute<Vec3> vertex_normals_by_area(Mesh const& m, vertex_attribute<Vec3> const& position);
/// efficiently computes face normal attribute
template <class Vec3, class Scalar = typename field_3d<Vec3>::Scalar>
template <class Vec3, class Scalar = typename field3<Vec3>::Scalar>
face_attribute<Vec3> face_normals(Mesh const& m, vertex_attribute<Vec3> const& position);
/// efficiently computes face normal attribute (assuming triangles)
template <class Vec3, class Scalar = typename field_3d<Vec3>::Scalar>
template <class Vec3, class Scalar = typename field3<Vec3>::Scalar>
face_attribute<Vec3> triangle_normals(Mesh const& m, vertex_attribute<Vec3> const& position);
/// creates a vec3 halfedge attribute with barycentric coordinates per to-vertex (i.e. 100, 010, 001)
......@@ -186,7 +186,7 @@ Scalar triangle_area(face_handle f, vertex_attribute<Vec3> const& position)
auto p1 = position[h.vertex_to()];
auto p2 = position[h.next().vertex_to()];
return field_3d<Vec3>::length(field_3d<Vec3>::cross(p0 - p1, p0 - p2)) * field_3d<Vec3>::scalar(0.5f);
return field3<Vec3>::length(field3<Vec3>::cross(p0 - p1, p0 - p2)) * field3<Vec3>::scalar(0.5f);
}
template <class Vec3>
......@@ -197,7 +197,7 @@ Vec3 triangle_centroid(face_handle f, vertex_attribute<Vec3> const& position)
auto p1 = position[h.vertex_to()];
auto p2 = position[h.next().vertex_to()];
return (p0 + p1 + p2) / field_3d<Vec3>::scalar(3);
return (p0 + p1 + p2) / field3<Vec3>::scalar(3);
}
template <class Vec3>
......@@ -207,9 +207,9 @@ Vec3 face_normal(face_handle f, vertex_attribute<Vec3> const& position)
auto e = f.any_halfedge();
auto v0 = e.vertex_from()[position];
auto v1 = e.vertex_to()[position];
auto n = field_3d<Vec3>::cross(v0 - c, v1 - c);
auto l = field_3d<Vec3>::length(n);
return l == 0 ? field_3d<Vec3>::zero() : n / l;
auto n = field3<Vec3>::cross(v0 - c, v1 - c);
auto l = field3<Vec3>::length(n);
return l == 0 ? field3<Vec3>::zero() : n / l;
}
template <class Vec3>
......@@ -219,9 +219,9 @@ Vec3 triangle_normal(face_handle f, vertex_attribute<Vec3> const& position)
auto v0 = e.vertex_from()[position];
auto v1 = e.vertex_to()[position];
auto v2 = e.next().vertex_to()[position];
auto n = field_3d<Vec3>::cross(v1 - v0, v2 - v0);
auto l = field_3d<Vec3>::length(n);
return l == 0 ? field_3d<Vec3>::zero() : n / l;
auto n = field3<Vec3>::cross(v1 - v0, v2 - v0);
auto l = field3<Vec3>::length(n);
return l == 0 ? field3<Vec3>::zero() : n / l;
}
template <class Vec3>
......@@ -231,13 +231,13 @@ Vec3 triangle_normal_unorm(face_handle f, vertex_attribute<Vec3> const& position
auto v0 = e.vertex_from()[position];
auto v1 = e.vertex_to()[position];
auto v2 = e.next().vertex_to()[position];
return field_3d<Vec3>::cross(v1 - v0, v2 - v0);
return field3<Vec3>::cross(v1 - v0, v2 - v0);
}
template <class Vec3, class Scalar>
Scalar face_area(face_handle f, vertex_attribute<Vec3> const& position)
{
auto varea = field_3d<Vec3>::zero();
auto varea = field3<Vec3>::zero();
auto h = f.any_halfedge();
......@@ -251,14 +251,14 @@ Scalar face_area(face_handle f, vertex_attribute<Vec3> const& position)
{
auto p_curr = h.vertex_to()[position];
varea += field_3d<Vec3>::cross(p_prev - p0, p_curr - p0);
varea += field3<Vec3>::cross(p_prev - p0, p_curr - p0);
// circulate
h = h.next();
p_prev = p_curr;
} while (h.vertex_to() != v0);
return field_3d<Vec3>::length(varea) * 0.5f;
return field3<Vec3>::length(varea) * 0.5f;
}
template <class Vec3>
......@@ -266,8 +266,8 @@ Vec3 face_centroid(face_handle f, vertex_attribute<Vec3> const& position)
{
// TODO: make correct for non-convex polygons!
auto area = field_3d<Vec3>::scalar(0);
auto centroid = field_3d<Vec3>::zero();
auto area = field3<Vec3>::scalar(0);
auto centroid = field3<Vec3>::zero();
auto h = f.any_halfedge();
......@@ -281,7 +281,7 @@ Vec3 face_centroid(face_handle f, vertex_attribute<Vec3> const& position)
{
auto p_curr = h.vertex_to()[position];
auto a = field_3d<Vec3>::length(field_3d<Vec3>::cross(p_prev - p0, p_curr - p0));
auto a = field3<Vec3>::length(field3<Vec3>::cross(p_prev - p0, p_curr - p0));
area += a;
centroid += (p_prev + p_curr + p0) * a;
......@@ -296,13 +296,13 @@ Vec3 face_centroid(face_handle f, vertex_attribute<Vec3> const& position)
template <class Vec3, class Scalar>
Scalar edge_length(edge_handle e, vertex_attribute<Vec3> const& position)
{
return field_3d<Vec3>::length(position[e.vertexA()] - position[e.vertexB()]);
return field3<Vec3>::length(position[e.vertexA()] - position[e.vertexB()]);
}
template <class Vec3, class Scalar>
Scalar edge_length(halfedge_handle h, vertex_attribute<Vec3> const& position)
{
return field_3d<Vec3>::length(position[h.vertex_from()] - position[h.vertex_to()]);
return field3<Vec3>::length(position[h.vertex_from()] - position[h.vertex_to()]);
}
template <class Vec3>
......@@ -315,9 +315,9 @@ template <class Vec3>
Vec3 edge_dir(halfedge_handle h, vertex_attribute<Vec3> const& position)
{
auto d = position[h.vertex_to()] - position[h.vertex_from()];
auto l = field_3d<Vec3>::length(d);
auto l = field3<Vec3>::length(d);
if (l == 0)
return field_3d<Vec3>::zero();
return field3<Vec3>::zero();
return d / l;
}
......@@ -331,13 +331,13 @@ Scalar angle_to_next(halfedge_handle h, vertex_attribute<Vec3> const& position)
auto v01 = v0 - v1;
auto v21 = v2 - v1;
auto l01 = field_3d<Vec3>::length(v01);
auto l21 = field_3d<Vec3>::length(v21);
auto l01 = field3<Vec3>::length(v01);
auto l21 = field3<Vec3>::length(v21);
if (l01 == 0 || l21 == 0)
return 0;
auto ca = field_3d<Vec3>::dot(v01, v21) / (l01 * l21);
auto ca = field3<Vec3>::dot(v01, v21) / (l01 * l21);
return std::acos(ca);
}
......@@ -351,13 +351,13 @@ Scalar angle_to_prev(halfedge_handle h, vertex_attribute<Vec3> const& position)
auto v01 = v0 - v1;
auto v21 = v2 - v1;
auto l01 = field_3d<Vec3>::length(v01);
auto l21 = field_3d<Vec3>::length(v21);
auto l01 = field3<Vec3>::length(v01);
auto l21 = field3<Vec3>::length(v21);
if (l01 == 0 || l21 == 0)
return 0;
auto ca = field_3d<Vec3>::dot(v01, v21) / (l01 * l21);
auto ca = field3<Vec3>::dot(v01, v21) / (l01 * l21);
return std::acos(ca);
}
......@@ -407,7 +407,7 @@ template <class Vec3, class Scalar>
vertex_attribute<Vec3> vertex_normals_uniform(Mesh const& m, vertex_attribute<Vec3> const& position)
{
face_attribute<Vec3> fnormals = m.faces().map([&](face_handle f) { return triangle_normal(f, position); });
vertex_attribute<Vec3> normals = m.vertices().make_attribute_with_default(field_3d<Vec3>::make(0, 0, 0));
vertex_attribute<Vec3> normals = m.vertices().make_attribute_with_default(field3<Vec3>::make(0, 0, 0));
for (auto f : m.faces())
for (auto v : f.vertices())
......@@ -415,7 +415,7 @@ vertex_attribute<Vec3> vertex_normals_uniform(Mesh const& m, vertex_attribute<Ve
for (auto& n : normals)
{
auto l = field_3d<Vec3>::length(n);
auto l = field3<Vec3>::length(n);
if (l > 0)
n /= l;
}
......@@ -427,7 +427,7 @@ template <class Vec3, class Scalar>
vertex_attribute<Vec3> vertex_normals_by_area(Mesh const& m, vertex_attribute<Vec3> const& position)
{
face_attribute<Vec3> fnormals = m.faces().map([&](face_handle f) { return triangle_normal_unorm(f, position); });
vertex_attribute<Vec3> normals = m.vertices().make_attribute_with_default(field_3d<Vec3>::make(0, 0, 0));
vertex_attribute<Vec3> normals = m.vertices().make_attribute_with_default(field3<Vec3>::make(0, 0, 0));
for (auto f : m.faces())
for (auto v : f.vertices())
......@@ -435,7 +435,7 @@ vertex_attribute<Vec3> vertex_normals_by_area(Mesh const& m, vertex_attribute<Ve
for (auto& n : normals)
{
auto l = field_3d<Vec3>::length(n);
auto l = field3<Vec3>::length(n);
if (l > 0)
n /= l;
}
......@@ -464,7 +464,7 @@ halfedge_attribute<Vec3> barycentric_coordinates(Mesh const& m)
auto idx = 0;
for (auto h : f.halfedges())
{
coords[h] = field_3d<Vec3>::make(idx == 0, idx == 1, idx == 2);
coords[h] = field3<Vec3>::make(idx == 0, idx == 1, idx == 2);
++idx;
}
}
......@@ -488,8 +488,8 @@ bool is_delaunay(edge_handle e, vertex_attribute<Vec3> const& position)
auto e_ib = pi - pb;
auto e_jb = pj - pb;
auto cot_a = field_3d<Vec3>::dot(e_ia, e_ja) / field_3d<Vec3>::length(field_3d<Vec3>::cross(e_ia, e_ja));
auto cot_b = field_3d<Vec3>::dot(e_ib, e_jb) / field_3d<Vec3>::length(field_3d<Vec3>::cross(e_ib, e_jb));
auto cot_a = field3<Vec3>::dot(e_ia, e_ja) / field3<Vec3>::length(field3<Vec3>::cross(e_ia, e_ja));
auto cot_b = field3<Vec3>::dot(e_ib, e_jb) / field3<Vec3>::length(field3<Vec3>::cross(e_ib, e_jb));
return cot_a + cot_b >= 0;
}
......
......@@ -69,12 +69,12 @@ void print_stats(std::ostream& out, Mesh const& m, vertex_attribute<Vec3> const*
auto aabb = m.vertices().aabb(pos);
auto min = aabb.min;
auto max = aabb.max;
out << " AABB Min: " << field_3d<Vec3>::to_string(min) << ln;
out << " AABB Max: " << field_3d<Vec3>::to_string(max) << ln;
out << " AABB Size: " << field_3d<Vec3>::to_string(max - min) << ln;
out << " AABB Min: " << field3<Vec3>::to_string(min) << ln;
out << " AABB Max: " << field3<Vec3>::to_string(max) << ln;
out << " AABB Size: " << field3<Vec3>::to_string(max - min) << ln;
auto avg = m.vertices().avg(pos);
out << " Vertex Centroid: " << field_3d<Vec3>::to_string(avg) << ln;
out << " Vertex Centroid: " << field3<Vec3>::to_string(avg) << ln;
auto el_minmax = m.edges().minmax([&](edge_handle e) { return edge_length(e, pos); });
auto el_avg = m.edges().avg([&](edge_handle e) { return edge_length(e, pos); });
......
......@@ -10,12 +10,19 @@ namespace polymesh
{
/// Type trait for 3D vector types
template <class Vec3>
struct field_3d
struct field3
{
using Point = Vec3;
using Scalar = typename std::decay<decltype(std::declval<Vec3>()[0])>::type;
constexpr static Point make(Scalar x, Scalar y, Scalar z) { return Point(x, y, z); }
constexpr static Point make(Scalar x, Scalar y, Scalar z)
{
Point p;
p[0] = x;
p[1] = y;
p[2] = z;
return p;
}
constexpr static Point zero() { return make(0, 0, 0); }
constexpr static Scalar dot(Vec3 const& a, Vec3 const& b)
......@@ -47,4 +54,4 @@ struct field_3d
return ss.str();
}
};
}
} // namespace polymesh
......@@ -8,7 +8,8 @@
#include "formats/pm.hh"
#include "formats/stl.hh"
bool polymesh::load(const std::string &filename, polymesh::Mesh &m, vertex_attribute<glm::vec3> &pos)
template <class ScalarT>
bool polymesh::detail::load(const std::string& filename, polymesh::Mesh& m, vertex_attribute<std::array<ScalarT, 3>>& pos)
{
if (!std::ifstream(filename).good())
{
......@@ -39,7 +40,37 @@ bool polymesh::load(const std::string &filename, polymesh::Mesh &m, vertex_attri
}
else
{
std::cerr << "unknown extension: " << ext << " (of " << filename << ")" << std::endl;
std::cerr << "unknown/unsupported extension: " << ext << " (of " << filename << ")" << std::endl;
return false;
}
}
template <class ScalarT>
void polymesh::detail::save(const std::string& filename, polymesh::Mesh& m, vertex_attribute<std::array<ScalarT, 3>> const& pos)
{
auto ext = filename.substr(filename.rfind('.') + 1);
std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
if (ext == "obj")
{
return write_obj(filename, m, pos);
}
else if (ext == "off")
{
return write_off(filename, m, pos);
}
else if (ext == "stl")
{
return write_stl_binary(filename, m, pos);
}
else
{
std::cerr << "unknown/unsupported extension: " << ext << " (of " << filename << ")" << std::endl;
}
}
template bool polymesh::detail::load<float>(std::string const& filename, Mesh& m, vertex_attribute<std::array<float, 3>>& pos);
template bool polymesh::detail::load<double>(std::string const& filename, Mesh& m, vertex_attribute<std::array<double, 3>>& pos);
template void polymesh::detail::save<float>(std::string const& filename, Mesh& m, vertex_attribute<std::array<float, 3>> const& pos);
template void polymesh::detail::save<double>(std::string const& filename, Mesh& m, vertex_attribute<std::array<double, 3>> const& pos);
#pragma once
#include <glm/vec3.hpp>
#include <array>
#include <cstring>
#include "Mesh.hh"
namespace polymesh
{
/// loads a mesh from a file
bool load(std::string const& filename, Mesh& m, vertex_attribute<glm::vec3>& pos);
template <class Vec3>
bool load(std::string const& filename, Mesh& m, vertex_attribute<Vec3>& pos);
/// saves a mesh to a file
template <class Vec3>
void save(std::string const& filename, Mesh& m, vertex_attribute<Vec3> const& pos);
// ------- IMPLEMENTATION -------
namespace detail
{
template <class ScalarT>
bool load(std::string const& filename, Mesh& m, vertex_attribute<std::array<ScalarT, 3>>& pos);
template <class ScalarT>
void save(std::string const& filename, Mesh& m, vertex_attribute<std::array<ScalarT, 3>> const& pos);
} // namespace detail
template <class Vec3>
bool load(std::string const& filename, Mesh& m, vertex_attribute<Vec3>& pos)
{
static_assert(sizeof(Vec3) == sizeof(float) * 3 || sizeof(Vec3) == sizeof(double) * 3, "position type must be 3 floats or 3 doubles");
bool ok;
if (sizeof(Vec3) == sizeof(float) * 3)
{
auto tmp_pos = m.vertices().make_attribute<std::array<float, 3>>();
ok = detail::load<float>(filename, m, tmp_pos);
std::memcpy(pos.data(), tmp_pos.data(), sizeof(Vec3) * m.vertices().size());
}
else
{
auto tmp_pos = m.vertices().make_attribute<std::array<double, 3>>();
ok = detail::load<double>(filename, m, tmp_pos);
std::memcpy(pos.data(), tmp_pos.data(), sizeof(Vec3) * m.vertices().size());
}
return ok;
}
template <class Vec3>
void save(std::string const& filename, Mesh& m, vertex_attribute<Vec3>& pos)
{
static_assert(sizeof(Vec3) == sizeof(float) * 3 || sizeof(Vec3) == sizeof(double) * 3, "position type must be 3 floats or 3 doubles");
if (sizeof(Vec3) == sizeof(float) * 3)
{
auto tmp_pos = m.vertices().make_attribute<std::array<float, 3>>();
std::memcpy(tmp_pos.data(), pos.data(), sizeof(Vec3) * m.vertices().size());
detail::save<float>(filename, m, tmp_pos);
}
else
{
auto tmp_pos = m.vertices().make_attribute<std::array<double, 3>>();
std::memcpy(tmp_pos.data(), pos.data(), sizeof(Vec3) * m.vertices().size());
detail::save<double>(filename, m, tmp_pos);
}
}
} // namespace polymesh
......@@ -3,34 +3,53 @@
#include <fstream>
#include <sstream>
using namespace polymesh;
namespace polymesh
{
template <class ScalarT>
void write_obj(std::string const &filename, Mesh const &mesh, vertex_attribute<std::array<ScalarT, 3>> const &position)
{
obj_writer<ScalarT> obj(filename);
obj.write_mesh(mesh, position);
}
void polymesh::write_obj(const std::string &filename,
const Mesh &mesh,
const vertex_attribute<glm::vec3> &position,
const vertex_attribute<glm::vec2> *tex_coord,
const vertex_attribute<glm::vec3> *normal)
template <class ScalarT>
bool read_obj(const std::string &filename, Mesh &mesh, vertex_attribute<std::array<ScalarT, 3>> &position)
{
obj_writer obj(filename);
obj.write_mesh(mesh, position, tex_coord, normal);
obj_reader<ScalarT> reader(filename, mesh);
position = reader.get_positions().map([](std::array<ScalarT, 4> const &p) { return std::array<ScalarT, 3>{p[0], p[1], p[2]}; });
return reader.error_faces() == 0;
}
obj_writer::obj_writer(const std::string &filename)
template <class ScalarT>
obj_writer<ScalarT>::obj_writer(const std::string &filename)
{
tmp_out = new std::ofstream(filename);
out = tmp_out;
}
obj_writer::obj_writer(std::ostream &out) { this->out = &out; }
template <class ScalarT>
obj_writer<ScalarT>::obj_writer(std::ostream &out)
{
this->out = &out;
}
obj_writer::~obj_writer() { delete tmp_out; }
template <class ScalarT>
obj_writer<ScalarT>::~obj_writer()
{
delete tmp_out;
}
void obj_writer::write_object_name(std::string object_name) { *out << "o " << object_name << "\n"; }
template <class ScalarT>
void obj_writer<ScalarT>::write_object_name(std::string object_name)
{
*out << "o " << object_name << "\n";
}
void obj_writer::write_mesh(const Mesh &mesh,
vertex_attribute<glm::vec3> const &position,