Commit 8f885d5d authored by Philip Trettner's avatar Philip Trettner
Browse files

working on SOA refactoring

parent befd1997
...@@ -29,4 +29,8 @@ Best used with glm and glow. ...@@ -29,4 +29,8 @@ Best used with glm and glow.
* primitive sort functions, better remap function, cache optimization * primitive sort functions, better remap function, cache optimization
* structure of arrays instead of AOS * structure of arrays instead of AOS
* lowlevel API that allows direct half-edge manipulation and does not fix boundaries (but also mirrors high level one) * lowlevel API that allows direct half-edge manipulation and does not fix boundaries (but also mirrors high level one)
* primitive collection sort and sort_by functions * primitive collection sort and sort_by functions
\ No newline at end of file
Low-level TODO:
* face_of(opposite(h)) -> opposite_face_of
...@@ -30,6 +30,8 @@ using SharedMesh = std::shared_ptr<Mesh>; ...@@ -30,6 +30,8 @@ using SharedMesh = std::shared_ptr<Mesh>;
* * `for (auto h : <primitive>())` iterates over _all_ primitives, including invalid ones * * `for (auto h : <primitive>())` iterates over _all_ primitives, including invalid ones
* (`for (auto h : valid_<primitive>())` skips over invalid ones) * (`for (auto h : valid_<primitive>())` skips over invalid ones)
* *
* * low-level operations can be performed by accessing low_level_api(mesh)
*
* For more concept documents see: * For more concept documents see:
* * http://kaba.hilvi.org/homepage/blog/halfedge/halfedge.htm * * http://kaba.hilvi.org/homepage/blog/halfedge/halfedge.htm
* * https://www.openmesh.org/media/Documentations/OpenMesh-Doc-Latest/a03930.html * * https://www.openmesh.org/media/Documentations/OpenMesh-Doc-Latest/a03930.html
...@@ -145,6 +147,8 @@ private: ...@@ -145,6 +147,8 @@ private:
/// Does NOT invalidate iterators! /// Does NOT invalidate iterators!
vertex_index add_vertex(); vertex_index add_vertex();
/// Allocates a new vertex
vertex_index alloc_vertex();
/// Allocates a new face /// Allocates a new face
face_index alloc_face(); face_index alloc_face();
/// Allocates a new edge /// Allocates a new edge
...@@ -223,9 +227,36 @@ private: ...@@ -223,9 +227,36 @@ private:
void fix_boundary_state_of_vertices(face_index f_idx); void fix_boundary_state_of_vertices(face_index f_idx);
// attributes // attributes
bool is_free(halfedge_index idx) const;
bool is_boundary(vertex_index idx) const; bool is_boundary(vertex_index idx) const;
bool is_boundary(halfedge_index idx) const; bool is_boundary(halfedge_index idx) const;
bool is_removed(vertex_index idx) const;
bool is_removed(face_index idx) const;
bool is_removed(edge_index idx) const;
bool is_removed(halfedge_index idx) const;
bool is_isolated(vertex_index idx) const;
vertex_index &to_vertex_of(halfedge_index idx);
face_index &face_of(halfedge_index idx);
halfedge_index &next_halfedge_of(halfedge_index idx);
halfedge_index &prev_halfedge_of(halfedge_index idx);
halfedge_index &halfedge_of(face_index idx);
halfedge_index &outgoing_halfedge_of(vertex_index idx);
vertex_index to_vertex_of(halfedge_index idx) const;
face_index face_of(halfedge_index idx) const;
halfedge_index next_halfedge_of(halfedge_index idx) const;
halfedge_index prev_halfedge_of(halfedge_index idx) const;
halfedge_index halfedge_of(face_index idx) const;
halfedge_index outgoing_halfedge_of(vertex_index idx) const;
void set_removed(vertex_index idx);
void set_removed(face_index idx);
void set_removed(edge_index idx);
/// Returns the opposite of a given valid half-edge /// Returns the opposite of a given valid half-edge
halfedge_index opposite(halfedge_index he) const; halfedge_index opposite(halfedge_index he) const;
...@@ -255,10 +286,8 @@ private: ...@@ -255,10 +286,8 @@ private:
/// returns a half-edge belonging to an edge /// returns a half-edge belonging to an edge
halfedge_index halfedge_of(edge_index idx, int i) const { return halfedge_index((idx.value << 1) + i); } halfedge_index halfedge_of(edge_index idx, int i) const { return halfedge_index((idx.value << 1) + i); }
/// returns the vertex that this half-edge is pointing to vertex_index &from_vertex_of(halfedge_index idx);
vertex_index to_vertex_of(halfedge_index idx) const { return halfedge(idx).to_vertex; } vertex_index from_vertex_of(halfedge_index idx) const;
/// returns the vertex that this half-edge is leaving from
vertex_index from_vertex_of(halfedge_index idx) const { return halfedge(opposite(idx)).to_vertex; }
/// applies an index remapping to all face indices (p[curr_idx] = new_idx) /// applies an index remapping to all face indices (p[curr_idx] = new_idx)
void permute_faces(std::vector<int> const &p); void permute_faces(std::vector<int> const &p);
...@@ -312,10 +341,19 @@ private: ...@@ -312,10 +341,19 @@ private:
// internal primitives // internal primitives
private: private:
std::vector<face_info> mFaces; // std::vector<face_info> mFaces;
std::vector<vertex_info> mVertices; // std::vector<vertex_info> mVertices;
std::vector<halfedge_info> mHalfedges; // std::vector<halfedge_info> mHalfedges;
std::vector<halfedge_index> mFaceToHalfedge;
std::vector<halfedge_index> mVertexToOutgoingHalfedge;
std::vector<vertex_index> mHalfedgeToVertex;
std::vector<face_index> mHalfedgeToFace;
std::vector<halfedge_index> mHalfedgeToNextHalfedge;
std::vector<halfedge_index> mHalfedgeToPrevHalfedge;
/*
struct face_info &face(face_index i) struct face_info &face(face_index i)
{ {
assert(i.is_valid() && i.value < size_all_faces()); assert(i.is_valid() && i.value < size_all_faces());
...@@ -356,6 +394,7 @@ private: ...@@ -356,6 +394,7 @@ private:
assert(i.is_valid() && i.value < size_all_edges()); assert(i.is_valid() && i.value < size_all_edges());
return mHalfedges[(i.value << 1) + h]; return mHalfedges[(i.value << 1) + h];
} }
*/
// internal state // internal state
private: private:
...@@ -431,6 +470,8 @@ private: ...@@ -431,6 +470,8 @@ private:
friend struct edge_collection; friend struct edge_collection;
template <class iterator> template <class iterator>
friend struct halfedge_collection; friend struct halfedge_collection;
friend struct low_level_api;
}; };
} }
......
...@@ -6,13 +6,15 @@ ...@@ -6,13 +6,15 @@
namespace polymesh namespace polymesh
{ {
inline vertex_index Mesh::add_vertex() inline vertex_index Mesh::add_vertex() { return alloc_vertex(); }
inline vertex_index Mesh::alloc_vertex()
{ {
auto idx = vertex_index((int)mVertices.size()); auto idx = vertex_index(size_all_vertices());
mVertices.push_back(vertex_info()); mVertexToOutgoingHalfedge.push_back(halfedge_index::invalid());
// notify attributes // notify attributes
auto vCnt = (int)mVertices.size(); auto vCnt = size_all_vertices();
for (auto p = mVertexAttrs; p; p = p->mNextAttribute) for (auto p = mVertexAttrs; p; p = p->mNextAttribute)
p->resize(vCnt, false); p->resize(vCnt, false);
...@@ -21,11 +23,11 @@ inline vertex_index Mesh::add_vertex() ...@@ -21,11 +23,11 @@ inline vertex_index Mesh::add_vertex()
inline face_index Mesh::alloc_face() inline face_index Mesh::alloc_face()
{ {
auto idx = face_index((int)mFaces.size()); auto idx = face_index(size_all_faces());
mFaces.push_back(face_info()); mFaceToHalfedge.push_back(halfedge_index::invalid());
// notify attributes // notify attributes
auto fCnt = (int)mFaces.size(); auto fCnt = size_all_faces();
for (auto p = mFaceAttrs; p; p = p->mNextAttribute) for (auto p = mFaceAttrs; p; p = p->mNextAttribute)
p->resize(fCnt, false); p->resize(fCnt, false);
...@@ -34,13 +36,20 @@ inline face_index Mesh::alloc_face() ...@@ -34,13 +36,20 @@ inline face_index Mesh::alloc_face()
inline edge_index Mesh::alloc_edge() inline edge_index Mesh::alloc_edge()
{ {
auto idx = edge_index((int)mHalfedges.size() >> 1); auto idx = edge_index(size_all_edges());
mHalfedges.push_back(halfedge_info());
mHalfedges.push_back(halfedge_info()); mHalfedgeToFace.push_back(face_index::invalid());
mHalfedgeToFace.push_back(face_index::invalid());
mHalfedgeToVertex.push_back(vertex_index::invalid());
mHalfedgeToVertex.push_back(vertex_index::invalid());
mHalfedgeToNextHalfedge.push_back(halfedge_index::invalid());
mHalfedgeToNextHalfedge.push_back(halfedge_index::invalid());
mHalfedgeToPrevHalfedge.push_back(halfedge_index::invalid());
mHalfedgeToPrevHalfedge.push_back(halfedge_index::invalid());
// notify attributes // notify attributes
auto hCnt = (int)mHalfedges.size(); auto hCnt = size_all_halfedges();
auto eCnt = (int)mHalfedges.size() >> 1; auto eCnt = size_all_edges();
for (auto p = mEdgeAttrs; p; p = p->mNextAttribute) for (auto p = mEdgeAttrs; p; p = p->mNextAttribute)
p->resize(eCnt, false); p->resize(eCnt, false);
for (auto p = mHalfedgeAttrs; p; p = p->mNextAttribute) for (auto p = mHalfedgeAttrs; p; p = p->mNextAttribute)
...@@ -77,7 +86,7 @@ inline face_index Mesh::add_face(const halfedge_index *half_loop, int vcnt) ...@@ -77,7 +86,7 @@ inline face_index Mesh::add_face(const halfedge_index *half_loop, int vcnt)
{ {
assert(vcnt >= 3 && "no support for less-than-triangular faces"); assert(vcnt >= 3 && "no support for less-than-triangular faces");
auto fidx = face_index((int)mFaces.size()); auto fidx = alloc_face();
// ensure that half-edges are adjacent at each vertex // ensure that half-edges are adjacent at each vertex
for (auto i = 0; i < vcnt; ++i) for (auto i = 0; i < vcnt; ++i)
...@@ -88,21 +97,21 @@ inline face_index Mesh::add_face(const halfedge_index *half_loop, int vcnt) ...@@ -88,21 +97,21 @@ inline face_index Mesh::add_face(const halfedge_index *half_loop, int vcnt)
// half-edge must form a chain // half-edge must form a chain
assert(to_vertex_of(h0) == from_vertex_of(h1) && "half-edges do not form a chain"); assert(to_vertex_of(h0) == from_vertex_of(h1) && "half-edges do not form a chain");
// half-edge must be free, i.e. allow a new polygon // half-edge must be free, i.e. allow a new polygon
assert(halfedge(h0).is_free() && "half-edge already contains a face"); assert(is_free(h0) && "half-edge already contains a face");
// make them adjacent // make them adjacent
make_adjacent(h0, h1); make_adjacent(h0, h1);
// link face // link face
halfedge(h0).face = fidx; face_of(h0) = fidx;
} }
// fix boundary states // fix boundary states
for (auto i = 0; i < vcnt; ++i) for (auto i = 0; i < vcnt; ++i)
{ {
auto h = half_loop[i]; auto h = half_loop[i];
auto v = halfedge(h).to_vertex; auto v = to_vertex_of(h);
auto f = halfedge(opposite(h)).face; auto f = face_of(opposite(h));
// fix vertex // fix vertex
fix_boundary_state_of(v); fix_boundary_state_of(v);
...@@ -113,18 +122,11 @@ inline face_index Mesh::add_face(const halfedge_index *half_loop, int vcnt) ...@@ -113,18 +122,11 @@ inline face_index Mesh::add_face(const halfedge_index *half_loop, int vcnt)
} }
// set up face data // set up face data
face_info f; halfedge_of(fidx) = half_loop[0];
f.halfedge = half_loop[0];
mFaces.push_back(f);
// fix new face // fix new face
fix_boundary_state_of(fidx); fix_boundary_state_of(fidx);
// notify attributes
auto fCnt = (int)mFaces.size();
for (auto p = mFaceAttrs; p; p = p->mNextAttribute)
p->resize(fCnt, false);
return fidx; return fidx;
} }
...@@ -288,17 +290,15 @@ inline halfedge_index Mesh::add_or_get_halfedge(halfedge_index h_from, halfedge_ ...@@ -288,17 +290,15 @@ inline halfedge_index Mesh::add_or_get_halfedge(halfedge_index h_from, halfedge_
auto e = add_or_get_edge(h_from, h_to); auto e = add_or_get_edge(h_from, h_to);
auto h0 = halfedge_of(e, 0); auto h0 = halfedge_of(e, 0);
auto h1 = halfedge_of(e, 1); auto h1 = halfedge_of(e, 1);
return halfedge(h_from).next_halfedge == h0 ? h0 : h1; return next_halfedge_of(h_from) == h0 ? h0 : h1;
} }
inline void Mesh::make_adjacent(halfedge_index he_in, halfedge_index he_out) inline void Mesh::make_adjacent(halfedge_index he_in, halfedge_index he_out)
{ {
// see http://kaba.hilvi.org/homepage/blog/halfedge/halfedge.htm ::makeAdjacent // see http://kaba.hilvi.org/homepage/blog/halfedge/halfedge.htm ::makeAdjacent
auto &in = halfedge(he_in);
auto &out = halfedge(he_out);
auto he_b = in.next_halfedge; auto he_b = next_halfedge_of(he_in);
auto he_d = out.prev_halfedge; auto he_d = prev_halfedge_of(he_out);
// already correct // already correct
if (he_b == he_out) if (he_b == he_out)
...@@ -308,56 +308,44 @@ inline void Mesh::make_adjacent(halfedge_index he_in, halfedge_index he_out) ...@@ -308,56 +308,44 @@ inline void Mesh::make_adjacent(halfedge_index he_in, halfedge_index he_out)
auto he_g = find_free_incident(opposite(he_out), he_in); auto he_g = find_free_incident(opposite(he_out), he_in);
assert(he_g.is_valid()); // unable to make adjacent assert(he_g.is_valid()); // unable to make adjacent
auto &b = halfedge(he_b); auto he_h = next_halfedge_of(he_g);
auto &d = halfedge(he_d);
auto &g = halfedge(he_g);
auto he_h = g.next_halfedge;
auto &h = halfedge(he_h);
// properly rewire // properly rewire
in.next_halfedge = he_out; connect_prev_next(he_in, he_out);
out.prev_halfedge = he_in; connect_prev_next(he_g, he_b);
connect_prev_next(he_d, he_h);
g.next_halfedge = he_b;
b.prev_halfedge = he_g;
d.next_halfedge = he_h;
h.prev_halfedge = he_d;
} }
inline void Mesh::remove_face(face_index f_idx) inline void Mesh::remove_face(face_index f_idx)
{ {
auto &f = face(f_idx); assert(!is_removed(f_idx));
assert(f.halfedge.is_valid());
auto he_begin = f.halfedge; auto he_begin = halfedge_of(f_idx);
auto he = he_begin; auto he = he_begin;
do do
{ {
auto &h = halfedge(he); assert(face_of(h) == f_idx);
assert(h.face == f_idx);
// set half-edge face to invalid // set half-edge face to invalid
h.face = face_index::invalid(); face_of(he) = face_index::invalid();
// fix outgoing vertex half-edge // fix outgoing vertex half-edge
// (vertex correctly reports is_boundary) // (vertex correctly reports is_boundary)
vertex(from_vertex_of(he)).outgoing_halfedge = he; outgoing_halfedge_of(from_vertex_of(he)) = he;
// fix opposite face half-edge // fix opposite face half-edge
auto ohe = opposite(he); auto ohe = opposite(he);
auto of = halfedge(ohe).face; auto of = face_of(ohe);
if (of.is_valid()) if (of.is_valid())
face(of).halfedge = ohe; halfedge_of(of) = ohe;
// advance // advance
he = h.next_halfedge; he = next_halfedge_of(he);
} while (he != he_begin); } while (he != he_begin);
// mark removed // mark removed
// (at the end!) // (at the end!)
f.set_removed(); set_removed(f_idx);
// bookkeeping // bookkeeping
mRemovedFaces++; mRemovedFaces++;
...@@ -430,15 +418,14 @@ inline void Mesh::remove_edge(edge_index e_idx) ...@@ -430,15 +418,14 @@ inline void Mesh::remove_edge(edge_index e_idx)
inline void Mesh::remove_vertex(vertex_index v_idx) inline void Mesh::remove_vertex(vertex_index v_idx)
{ {
auto &v = vertex(v_idx); assert(!is_removed(v_idx));
assert(v.is_valid());
// remove all outgoing edges // remove all outgoing edges
while (!v.is_isolated()) while (!is_isolated(v_idx))
remove_edge(edge_of(v.outgoing_halfedge)); remove_edge(edge_of(outgoing_halfedge_of(v_idx)));
// mark removed // mark removed
v.set_removed(); set_removed(v_idx);
// bookkeeping // bookkeeping
mRemovedVertices++; mRemovedVertices++;
...@@ -447,60 +434,53 @@ inline void Mesh::remove_vertex(vertex_index v_idx) ...@@ -447,60 +434,53 @@ inline void Mesh::remove_vertex(vertex_index v_idx)
inline void Mesh::fix_boundary_state_of(vertex_index v_idx) inline void Mesh::fix_boundary_state_of(vertex_index v_idx)
{ {
auto &v = vertex(v_idx); assert(!is_isolated(v_idx));
assert(!v.is_isolated());
auto he_begin = v.outgoing_halfedge; auto he_begin = outgoing_halfedge_of(v_idx);
auto he = he_begin; auto he = he_begin;
do do
{ {
// if half-edge is boundary, set it // if half-edge is boundary, set it
if (halfedge(he).is_free()) if (is_free(he))
{ {
v.outgoing_halfedge = he; outgoing_halfedge_of(v_idx) = he;
return; return;
} }
// advance // advance
he = halfedge(opposite(he)).next_halfedge; he = next_halfedge_of(opposite(he));
} while (he != he_begin); } while (he != he_begin);
} }
inline void Mesh::fix_boundary_state_of(face_index f_idx) inline void Mesh::fix_boundary_state_of(face_index f_idx)
{ {
auto &f = face(f_idx); auto he_begin = halfedge_of(f_idx);
auto he_begin = f.halfedge;
auto he = he_begin; auto he = he_begin;
do do
{ {
// if half-edge is boundary, set it // if half-edge is boundary, set it
if (halfedge(opposite(he)).is_free()) if (is_free(opposite(he)))
{ {
f.halfedge = he; halfedge_of(f_idx) = he;
return; return;
} }
// advance // advance
he = halfedge(he).next_halfedge; he = next_halfedge_of(he);
} while (he != he_begin); } while (he != he_begin);
} }
inline void Mesh::fix_boundary_state_of_vertices(face_index f_idx) inline void Mesh::fix_boundary_state_of_vertices(face_index f_idx)
{ {
auto &f = face(f_idx); auto he_begin = halfedge_of(f_idx);
auto he_begin = f.halfedge;
auto he = he_begin; auto he = he_begin;
do do
{ {
auto &h_ref = halfedge(he);
// fix vertex // fix vertex
fix_boundary_state_of(h_ref.to_vertex); fix_boundary_state_of(to_vertex_of(he));
// advance // advance
he = h_ref.next_halfedge; he = next_halfedge_of(he);
} while (he != he_begin); } while (he != he_begin);
} }
...@@ -511,15 +491,14 @@ inline halfedge_index Mesh::find_free_incident(halfedge_index in_begin, halfedge ...@@ -511,15 +491,14 @@ inline halfedge_index Mesh::find_free_incident(halfedge_index in_begin, halfedge
auto he = in_begin; auto he = in_begin;
do do
{ {
auto const &h = halfedge(he); assert(to_vertex_of(he) == to_vertex(in_end));
assert(h.to_vertex == halfedge(in_end).to_vertex);
// free? found one! // free? found one!
if (h.is_free()) if (is_free(he))
return he; return he;
// next half-edge of vertex // next half-edge of vertex
he = opposite(h.next_halfedge); he = opposite(next_halfedge_of(he));
} while (he != in_end); } while (he != in_end);
return halfedge_index::invalid(); return halfedge_index::invalid();
...@@ -527,27 +506,25 @@ inline halfedge_index Mesh::find_free_incident(halfedge_index in_begin, halfedge ...@@ -527,27 +506,25 @@ inline halfedge_index Mesh::find_free_incident(halfedge_index in_begin, halfedge
inline halfedge_index Mesh::find_free_incident(vertex_index v) const inline halfedge_index Mesh::find_free_incident(vertex_index v) const
{ {
auto in_begin = opposite(vertex(v).outgoing_halfedge); auto in_begin = opposite(outgoing_halfedge_of(v));
return find_free_incident(in_begin, in_begin); return find_free_incident(in_begin, in_begin);
} }
inline halfedge_index Mesh::find_halfedge(vertex_index from, vertex_index to) const inline halfedge_index Mesh::find_halfedge(vertex_index from, vertex_index to) const
{ {
auto he_begin = vertex(from).outgoing_halfedge; auto he_begin = outgoing_halfedge_of(from);
if (!he_begin.is_valid()) if (!he_begin.is_valid())
return halfedge_index::invalid(); // isolated vertex return halfedge_index::invalid(); // isolated vertex
auto he = he_begin; auto he = he_begin;