Commit be3a0c84 authored by Philip Trettner's avatar Philip Trettner
Browse files

obj read/write, working on templates

parent 9c3d267c
......@@ -8,10 +8,14 @@ Best used with glm and glow.
* Properties
* Algorithms
* Loader/Writer
* Tests
* std::less and std::hash for _index (and maybe _handle)
* attribute transformations (also between different types)
* lambda to attribute (from attribute to attribute or from make_attribute to attribute)
* Debug: store compactify generation in handles to check for invalidation
* Debug: insert is_removed assertions into handle access
\ No newline at end of file
* Debug: insert is_removed assertions into handle access
* Switch primitives and valid_primitives, check if compact flag is inlined
* Test self-adjacent faces
* smart ranges: average, min, max, any, all, first, last ...
* mid-level topo API: edge-rotate-next/prev, edge-split, edge-collapse, halfedge-split, halfedge-collapse, vertex-collapse
* annotate property preservation for mid-level topo API
......@@ -8,6 +8,9 @@
#include "cursors.hh"
#include "ranges.hh"
// often used helper
#include "attribute_collection.hh"
namespace polymesh
{
using SharedMesh = std::shared_ptr<Mesh>;
......@@ -77,6 +80,9 @@ public:
vertex_handle operator[](vertex_index idx) const { return handle_of(idx); }
halfedge_handle operator[](halfedge_index idx) const { return handle_of(idx); }
/// deletes all faces, vertices, edges, and halfedges
void clear();
// helper
public:
/// Returns true if the mesh is guaranteed compact, otherwise call compactify() to be sure
......@@ -104,10 +110,10 @@ public:
// internal helper
private:
// reserves a certain number of primitives
void reserve_faces(size_t capacity);
void reserve_vertices(size_t capacity);
void reserve_edges(size_t capacity);
void reserve_halfedges(size_t capacity);
void reserve_faces(int capacity);
void reserve_vertices(int capacity);
void reserve_edges(int capacity);
void reserve_halfedges(int capacity);
int size_faces() const { return (int)mFaces.size(); }
int size_vertices() const { return (int)mVertices.size(); }
......@@ -159,10 +165,10 @@ private:
/// Adds a face consisting of N vertices
/// The vertices must already be sorted in CCW order
/// (note: trying to add already existing halfedges triggers assertions)
face_index add_face(vertex_handle const *v_handles, size_t vcnt);
face_index add_face(vertex_index const *v_indices, size_t vcnt);
face_index add_face(halfedge_handle const *half_loop, size_t vcnt);
face_index add_face(halfedge_index const *half_loop, size_t vcnt);
face_index add_face(vertex_handle const *v_handles, int vcnt);
face_index add_face(vertex_index const *v_indices, int vcnt);
face_index add_face(halfedge_handle const *half_loop, int vcnt);
face_index add_face(halfedge_index const *half_loop, int vcnt);
/// Adds an edge between two existing, distinct vertices
/// if edge already exists, returns it
......@@ -389,38 +395,38 @@ inline vertex_index Mesh::add_vertex()
return idx;
}
inline face_index Mesh::add_face(const vertex_handle *v_handles, size_t vcnt)
inline face_index Mesh::add_face(const vertex_handle *v_handles, int vcnt)
{
mFaceInsertCache.resize(vcnt);
for (auto i = 0u; i < vcnt; ++i)
for (auto i = 0; i < vcnt; ++i)
mFaceInsertCache[i] = add_or_get_halfedge(v_handles[i].idx, v_handles[(i + 1) % vcnt].idx);
return add_face(mFaceInsertCache.data(), vcnt);
}
inline face_index Mesh::add_face(const vertex_index *v_indices, size_t vcnt)
inline face_index Mesh::add_face(const vertex_index *v_indices, int vcnt)
{
mFaceInsertCache.resize(vcnt);
for (auto i = 0u; i < vcnt; ++i)
for (auto i = 0; i < vcnt; ++i)
mFaceInsertCache[i] = add_or_get_halfedge(v_indices[i], v_indices[(i + 1) % vcnt]);
return add_face(mFaceInsertCache.data(), vcnt);
}
inline face_index Mesh::add_face(const halfedge_handle *half_loop, size_t vcnt)
inline face_index Mesh::add_face(const halfedge_handle *half_loop, int vcnt)
{
mFaceInsertCache.resize(vcnt);
for (auto i = 0u; i < vcnt; ++i)
for (auto i = 0; i < vcnt; ++i)
mFaceInsertCache[i] = half_loop[i].idx;
return add_face(mFaceInsertCache.data(), vcnt);
}
inline face_index Mesh::add_face(const halfedge_index *half_loop, size_t vcnt)
inline face_index Mesh::add_face(const halfedge_index *half_loop, int vcnt)
{
assert(vcnt >= 3 && "no support for less-than-triangular faces");
auto fidx = face_index((int)mFaces.size());
// ensure that half-edges are adjacent at each vertex
for (auto i = 0u; i < vcnt; ++i)
for (auto i = 0; i < vcnt; ++i)
{
auto h0 = half_loop[i];
auto h1 = half_loop[(i + 1) % vcnt];
......@@ -438,7 +444,7 @@ inline face_index Mesh::add_face(const halfedge_index *half_loop, size_t vcnt)
}
// fix boundary states
for (auto i = 0u; i < vcnt; ++i)
for (auto i = 0; i < vcnt; ++i)
{
auto h = half_loop[i];
auto v = halfedge(h).to_vertex;
......@@ -1015,12 +1021,12 @@ inline void face_collection::reserve(int capacity) const
mesh->reserve_faces(capacity);
}
inline face_handle face_collection::add(const vertex_handle *v_handles, size_t vcnt) const
inline face_handle face_collection::add(const vertex_handle *v_handles, int vcnt) const
{
return mesh->handle_of(mesh->add_face(v_handles, vcnt));
}
inline face_handle face_collection::add(const halfedge_handle *half_loop, size_t vcnt) const
inline face_handle face_collection::add(const halfedge_handle *half_loop, int vcnt) const
{
return mesh->handle_of(mesh->add_face(half_loop, vcnt));
}
......@@ -1072,7 +1078,7 @@ template <size_t N>
inline face_handle face_collection::add(const vertex_handle (&v_handles)[N]) const
{
halfedge_index hs[N];
for (auto i = 0u; i < N; ++i)
for (auto i = 0; i < N; ++i)
hs[i] = mesh->find_halfedge(v_handles[i].idx, v_handles[(i + 1) % N].idx);
return mesh->handle_of(mesh->add_face(hs, N));
}
......@@ -1081,7 +1087,7 @@ template <size_t N>
inline face_handle face_collection::add(const halfedge_handle (&half_loop)[N]) const
{
halfedge_index hs[N];
for (auto i = 0u; i < N; ++i)
for (auto i = 0; i < N; ++i)
hs[i] = half_loop[i].idx;
return mesh->handle_of(mesh->add_face(hs, N));
}
......@@ -1375,7 +1381,22 @@ inline void Mesh::compactify()
mCompact = true;
}
inline void Mesh::reserve_faces(size_t capacity)
/// ======== OTHER IMPLEMENTATION ========
inline void Mesh::clear()
{
for (auto &v : mVertices)
v.set_removed();
for (auto &h : mHalfedges)
h.set_removed();
for (auto &f : mFaces)
f.set_removed();
mCompact = false;
compactify();
}
inline void Mesh::reserve_faces(int capacity)
{
for (auto a = mFaceAttrs; a; a = a->mNextAttribute)
a->resize(capacity, false);
......@@ -1383,7 +1404,7 @@ inline void Mesh::reserve_faces(size_t capacity)
mFaces.reserve(capacity);
}
inline void Mesh::reserve_vertices(size_t capacity)
inline void Mesh::reserve_vertices(int capacity)
{
for (auto a = mVertexAttrs; a; a = a->mNextAttribute)
a->resize(capacity, false);
......@@ -1391,7 +1412,7 @@ inline void Mesh::reserve_vertices(size_t capacity)
mVertices.reserve(capacity);
}
inline void Mesh::reserve_edges(size_t capacity)
inline void Mesh::reserve_edges(int capacity)
{
for (auto a = mEdgeAttrs; a; a = a->mNextAttribute)
a->resize(capacity, false);
......@@ -1401,7 +1422,7 @@ inline void Mesh::reserve_edges(size_t capacity)
mHalfedges.reserve(capacity * 2);
}
inline void Mesh::reserve_halfedges(size_t capacity)
inline void Mesh::reserve_halfedges(int capacity)
{
for (auto a = mHalfedgeAttrs; a; a = a->mNextAttribute)
a->resize(capacity, false);
......@@ -1624,49 +1645,49 @@ inline vertex_vertex_ring vertex_handle::adjacent_vertices() const
/// ======== attributes IMPLEMENTATION ========
template <typename AttrT>
template <class AttrT>
vertex_attribute<AttrT> vertex_collection::make_attribute(const AttrT &def_value)
{
return vertex_attribute<AttrT>(mesh, def_value);
}
template <typename AttrT>
template <class AttrT>
vertex_attribute<AttrT> const_vertex_collection::make_attribute(const AttrT &def_value)
{
return vertex_attribute<AttrT>(mesh, def_value);
}
template <typename AttrT>
template <class AttrT>
face_attribute<AttrT> face_collection::make_attribute(const AttrT &def_value)
{
return face_attribute<AttrT>(mesh, def_value);
}
template <typename AttrT>
template <class AttrT>
face_attribute<AttrT> const_face_collection::make_attribute(const AttrT &def_value)
{
return face_attribute<AttrT>(mesh, def_value);
}
template <typename AttrT>
template <class AttrT>
edge_attribute<AttrT> edge_collection::make_attribute(const AttrT &def_value)
{
return edge_attribute<AttrT>(mesh, def_value);
}
template <typename AttrT>
template <class AttrT>
edge_attribute<AttrT> const_edge_collection::make_attribute(const AttrT &def_value)
{
return edge_attribute<AttrT>(mesh, def_value);
}
template <typename AttrT>
template <class AttrT>
halfedge_attribute<AttrT> halfedge_collection::make_attribute(const AttrT &def_value)
{
return halfedge_attribute<AttrT>(mesh, def_value);
}
template <typename AttrT>
template <class AttrT>
halfedge_attribute<AttrT> const_halfedge_collection::make_attribute(const AttrT &def_value)
{
return halfedge_attribute<AttrT>(mesh, def_value);
......@@ -1860,103 +1881,114 @@ inline void halfedge_attribute_base::register_attr()
mMesh->register_attr(this);
}
template <typename AttrT>
template <class AttrT>
vertex_attribute<AttrT>::vertex_attribute(const Mesh *mesh, const AttrT &def_value)
: vertex_attribute_base(mesh), mDefaultValue(def_value)
{
register_attr();
}
template <typename AttrT>
template <class AttrT>
face_attribute<AttrT>::face_attribute(const Mesh *mesh, const AttrT &def_value)
: face_attribute_base(mesh), mDefaultValue(def_value)
{
register_attr();
}
template <typename AttrT>
template <class AttrT>
edge_attribute<AttrT>::edge_attribute(const Mesh *mesh, const AttrT &def_value)
: edge_attribute_base(mesh), mDefaultValue(def_value)
{
register_attr();
}
template <typename AttrT>
template <class AttrT>
halfedge_attribute<AttrT>::halfedge_attribute(const Mesh *mesh, const AttrT &def_value)
: halfedge_attribute_base(mesh), mDefaultValue(def_value)
{
register_attr();
}
template <typename AttrT>
size_t vertex_attribute<AttrT>::size() const
template <class AttrT>
int vertex_attribute<AttrT>::size() const
{
return mMesh->vertices().size();
}
template <typename AttrT>
template <class AttrT>
void vertex_attribute<AttrT>::clear(AttrT const &value)
{
mData.clear();
mData.resize(mMesh->vertices().size(), value);
}
template <typename AttrT>
template <class AttrT>
void vertex_attribute<AttrT>::clear()
{
clear(mDefaultValue);
}
template <typename AttrT>
size_t face_attribute<AttrT>::size() const
template <class AttrT>
int face_attribute<AttrT>::size() const
{
return mMesh->vertices().size();
}
template <typename AttrT>
template <class AttrT>
void face_attribute<AttrT>::clear(AttrT const &value)
{
mData.clear();
mData.resize(mMesh->vertices().size(), value);
}
template <typename AttrT>
template <class AttrT>
void face_attribute<AttrT>::clear()
{
clear(mDefaultValue);
}
template <typename AttrT>
size_t edge_attribute<AttrT>::size() const
template <class AttrT>
int edge_attribute<AttrT>::size() const
{
return mMesh->vertices().size();
}
template <typename AttrT>
template <class AttrT>
void edge_attribute<AttrT>::clear(AttrT const &value)
{
mData.clear();
mData.resize(mMesh->vertices().size(), value);
}
template <typename AttrT>
template <class AttrT>
void edge_attribute<AttrT>::clear()
{
clear(mDefaultValue);
}
template <typename AttrT>
size_t halfedge_attribute<AttrT>::size() const
template <class AttrT>
int halfedge_attribute<AttrT>::size() const
{
return mMesh->vertices().size();
}
template <typename AttrT>
template <class AttrT>
void halfedge_attribute<AttrT>::clear(AttrT const &value)
{
mData.clear();
mData.resize(mMesh->vertices().size(), value);
}
template <typename AttrT>
template <class AttrT>
void halfedge_attribute<AttrT>::clear()
{
clear(mDefaultValue);
}
template <class AttrT>
template <class FuncT>
auto vertex_attribute<AttrT>::map(FuncT f) const -> tmp::result_type_of<FuncT, AttrT>
{
auto attr = mMesh->vertices().make_attribute<tmp::result_type_of<FuncT, AttrT>>();
auto s = size();
for (auto i = 0; i < s; ++i)
attr.mData[i] = f(mData[i]);
return attr; // copy elison
}
}
......@@ -16,9 +16,7 @@
// Basic mesh operations, including:
// - elementary subdivision
// - edge splits
// - intersections
// - collapses
#include "algorithms/operations.hh"
// TODO:
......
......@@ -6,9 +6,7 @@
// Basic mesh operations, including:
// - elementary subdivision
// - edge splits
// - intersections
// - collapses
namespace polymesh
{
......
......@@ -3,6 +3,7 @@
#include <glm/glm.hpp>
#include "../Mesh.hh"
#include "../fields.hh"
// Derived mesh properties, including:
// - valences
......@@ -20,16 +21,20 @@ namespace polymesh
int valence_of(vertex_handle v);
/// returns the area of the (flat) polygonal face
float face_area(face_handle f, vertex_attribute<glm::vec3> const& position);
template <class Vec3>
typename field_3d<Vec3>::Scalar face_area(face_handle f, vertex_attribute<Vec3> const& position);
/// returns the center of gravity for a given (flat) polygonal face
glm::vec3 face_centroid(face_handle f, vertex_attribute<glm::vec3> const& position);
template <class Vec3>
Vec3 face_centroid(face_handle f, vertex_attribute<Vec3> const& position);
/// returns the area of a given triangle
float triangle_area(face_handle f, vertex_attribute<glm::vec3> const& position);
template <class Vec3>
typename field_3d<Vec3>::Scalar triangle_area(face_handle f, vertex_attribute<Vec3> const& position);
/// returns the center of gravity for a given triangle
glm::vec3 triangle_centroid(face_handle f, vertex_attribute<glm::vec3> const& position);
template <class Vec3>
Vec3 triangle_centroid(face_handle f, vertex_attribute<Vec3> const& position);
/// ======== IMPLEMENTATION ========
......@@ -38,29 +43,32 @@ inline int valence_of(vertex_handle v)
return v.adjacent_vertices().size();
}
inline float triangle_area(face_handle f, vertex_attribute<glm::vec3> const& position)
template <class Vec3>
typename field_3d<Vec3>::Scalar triangle_area(face_handle f, vertex_attribute<Vec3> const& position)
{
auto h = f.any_halfedge();
auto p0 = position[h.vertex_from()];
auto p1 = position[h.vertex_to()];
auto p2 = position[h.next().vertex_to()];
return 0.5f * length(cross(p0 - p1, p0 - p2));
return field_3d<Vec3>::length(field_3d<Vec3>::cross(p0 - p1, p0 - p2)) * field_3d<Vec3>::scalar(0.5f);
}
inline glm::vec3 triangle_centroid(face_handle f, vertex_attribute<glm::vec3> const& position)
template <class Vec3>
Vec3 triangle_centroid(face_handle f, vertex_attribute<Vec3> const& position)
{
auto h = f.any_halfedge();
auto p0 = position[h.vertex_from()];
auto p1 = position[h.vertex_to()];
auto p2 = position[h.next().vertex_to()];
return (p0 + p1 + p2) / 3.0f;
return (p0 + p1 + p2) / field_3d<Vec3>::scalar(3);
}
inline float face_area(face_handle f, vertex_attribute<glm::vec3> const& position)
template <class Vec3>
typename field_3d<Vec3>::Scalar face_area(face_handle f, vertex_attribute<Vec3> const& position)
{
glm::vec3 varea;
auto varea = field_3d<Vec3>::zero();
auto h = f.any_halfedge();
......@@ -74,22 +82,23 @@ inline float face_area(face_handle f, vertex_attribute<glm::vec3> const& positio
{
auto p_curr = h.vertex_to()[position];
varea += cross(p_prev - p0, p_curr - p0);
varea += field_3d<Vec3>::cross(p_prev - p0, p_curr - p0);
// circulate
h = h.next();
p_prev = p_curr;
} while (h.vertex_to() != v0);
return length(varea) * 0.5f;
return field_3d<Vec3>::length(varea) * 0.5f;
}
inline glm::vec3 face_centroid(face_handle f, vertex_attribute<glm::vec3> const& position)
template <class Vec3>
Vec3 face_centroid(face_handle f, vertex_attribute<Vec3> const& position)
{
// TODO: make correct for non-convex polygons!
float area = 0.0f;
glm::vec3 centroid;
auto area = field_3d<Vec3>::scalar(0);
auto centroid = field_3d<Vec3>::zero();
auto h = f.any_halfedge();
......@@ -103,7 +112,7 @@ inline glm::vec3 face_centroid(face_handle f, vertex_attribute<glm::vec3> const&
{
auto p_curr = h.vertex_to()[position];
auto a = length(cross(p_prev - p0, p_curr - p0));
auto a = field_3d<Vec3>::length(field_3d<Vec3>::cross(p_prev - p0, p_curr - p0));
area += a;
centroid += (p_prev + p_curr + p0) * a;
......
......@@ -9,10 +9,10 @@ namespace polymesh
{
class Mesh;
template <typename DataT>
template <class DataT>
struct attribute_data
{
size_t size = 0;
int size = 0;
DataT* data = nullptr;
DataT& operator[](int i) { return data[i]; }
......@@ -24,7 +24,7 @@ struct attribute_data
size = rhs.size;
data = new DataT[size];
for (size_t i = 0; i < size; ++i)
for (int i = 0; i < size; ++i)
data[i] = rhs.data[i];
}
attribute_data(attribute_data<DataT>&& rhs) // move
......@@ -42,7 +42,7 @@ struct attribute_data
size = rhs.size;
data = new DataT[size];
for (size_t i = 0; i < size; ++i)
for (int i = 0; i < size; ++i)
data[i] = rhs.data[i];
return *this;
......@@ -61,21 +61,21 @@ struct attribute_data
}
~attribute_data() { delete[] data; }
void resize(size_t new_size, DataT const& default_value)
void resize(int new_size, DataT const& default_value)
{
auto new_data = new DataT[new_size];
if (new_size < size)
{
for (size_t i = 0; i < new_size; ++i)
for (int i = 0; i < new_size; ++i)
new_data[i] = data[i];
}
else
{
for (size_t i = 0; i < size; ++i)
for (int i = 0; i < size; ++i)
new_data[i] = data[i];
for (size_t i = size; i < new_size; ++i)
for (int i = size; i < new_size; ++i)
new_data[i] = default_value;
}
......@@ -91,7 +91,7 @@ private:
vertex_attribute_base* mNextAttribute = nullptr;
vertex_attribute_base* mPrevAttribute = nullptr;
void resize(size_t newSize, bool force)
void resize(int newSize, bool force)
{
if (force)
{
......@@ -108,11 +108,11 @@ private:
}
protected:
size_t mDataSize = 0;
int mDataSize = 0;
Mesh const* mMesh;
vertex_attribute_base(Mesh const* mesh);
virtual ~vertex_attribute_base() { deregister_attr(); }
virtual void on_resize(size_t newSize) = 0;
virtual void on_resize(int newSize) = 0;
virtual void apply_remapping(std::vector<int> const& map) = 0;
void register_attr();
void deregister_attr();
......@@ -125,7 +125,7 @@ private:
face_attribute_base* mNextAttribute = nullptr;
face_attribute_base* mPrevAttribute = nullptr;
void resize(size