Commit 91282cdf authored by Philip Trettner's avatar Philip Trettner
Browse files

added optimized into container functions and smart bfs iterators

parent 4746bd45
#pragma once
#include "../Mesh.hh"
#include "../detail/primitive_set.hh"
#include "../detail/topology_iterator.hh"
#include <queue>
......@@ -18,6 +20,13 @@ vertex_attribute<int> vertex_components(Mesh const& m, int* comps = nullptr);
/// Optionally returns the total number of components in `comps`
face_attribute<int> face_components(Mesh const& m, int* comps = nullptr);
/// returns a range that iterates over all connected vertices in BFS order
detail::bfs_range<vertex_tag> vertex_component(vertex_handle v);
/// returns a range that iterates over all connected faces in BFS order
detail::bfs_range<face_tag> face_component(face_handle f);
detail::bfs_range<face_tag> face_component(vertex_handle v);
/// ======== IMPLEMENTATION ========
inline vertex_attribute<int> vertex_components(Mesh const& m, int* comps)
......@@ -88,4 +97,15 @@ inline face_attribute<int> face_components(Mesh const& m, int* comps)
return comp;
}
inline detail::bfs_range<vertex_tag> vertex_component(vertex_handle v) { return {v}; }
inline detail::bfs_range<face_tag> face_component(face_handle f) { return {f}; }
inline detail::bfs_range<face_tag> face_component(vertex_handle v)
{
for (auto f : v.faces())
if (f.is_valid())
return {f};
return {face_handle()};
}
}
......@@ -18,7 +18,9 @@ inline void triangulate_naive(Mesh& m)
std::vector<vertex_handle> vs;
for (auto f : m.faces())
{
vs = f.vertices().to_vector();
vs.clear();
f.vertices().into_vector(vs);
if (vs.size() <= 3)
continue;
......
#pragma once
#include <unordered_set>
/// Primitive sets are sets optimized for storing primitive indices
/// They support these operations:
/// .insert(T t) -> bool // true iff actually inserted
/// .contains(T t) -> bool // true iff contained
/// .clear() // removes all contained elements
/// .size() -> int // returns number of contained elements
/// .begin() / .end() // iteration
///
/// Notes:
/// - they should also have value-semantics and proper copy behavior
/// - they are designed to hold int-like objects (must be convertible to int via (int)obj)
namespace polymesh
{
namespace detail
{
template <class T>
struct primitive_set
{
public:
using iterator = typename std::unordered_set<T>::iterator;
using const_iterator = typename std::unordered_set<T>::const_iterator;
public:
bool insert(T t);
void clear();
bool contains(T t) const;
int size() const;
iterator begin();
iterator end();
const_iterator begin() const;
const_iterator end() const;
private:
std::unordered_set<T> mElements;
};
template <class T>
bool primitive_set<T>::insert(T t)
{
return mElements.insert(t).second;
}
template <class T>
void primitive_set<T>::clear()
{
mElements.clear();
}
template <class T>
bool primitive_set<T>::contains(T t) const
{
return mElements.count(t);
}
template <class T>
int primitive_set<T>::size() const
{
return (int)mElements.size();
}
template <class T>
typename primitive_set<T>::iterator primitive_set<T>::begin()
{
return mElements.begin();
}
template <class T>
typename primitive_set<T>::iterator primitive_set<T>::end()
{
return mElements.end();
}
template <class T>
typename primitive_set<T>::const_iterator primitive_set<T>::begin() const
{
return mElements.begin();
}
template <class T>
typename primitive_set<T>::const_iterator primitive_set<T>::end() const
{
return mElements.end();
}
}
}
#pragma once
#include <queue>
#include "../Mesh.hh"
#include "primitive_set.hh"
/// CAUTION: these iterators do NOT work like normal iterators where you can make copies!
/// they are designed for direct consumption by range-based for ONLY!
namespace polymesh
{
namespace detail
{
template <class tag, class range_t>
struct bfs_iterator;
template <class tag, class queue_t = std::queue<typename primitive<tag>::index>, class set_t = primitive_set<typename primitive<tag>::index>>
struct bfs_range
{
using index_t = typename primitive<tag>::index;
using handle_t = typename primitive<tag>::handle;
bfs_range(handle_t h) : mesh(h.mesh)
{
queue.push(h);
seen.insert(h);
}
bfs_iterator<tag, bfs_range> begin() { return {*this, queue.front().of(mesh)}; }
bfs_iterator<tag, bfs_range> end() { return {*this, handle_t()}; }
handle_t advance(handle_t curr)
{
assert(curr == queue.front() && "this iterator type can only be used in a single range-based for!");
queue.pop();
expand(curr);
return queue.empty() ? handle_t() : queue.front().of(mesh);
}
template <class Enabled = typename std::enable_if<std::is_same<handle_t, vertex_handle>::value>::type>
void expand(vertex_handle v)
{
for (auto vv : v.adjacent_vertices())
if (seen.insert(vv))
queue.push(vv);
}
template <class Enabled = typename std::enable_if<std::is_same<handle_t, face_handle>::value>::type>
void expand(face_handle f)
{
for (auto ff : f.adjacent_faces())
if (ff.is_valid() && seen.insert(ff))
queue.push(ff);
}
template <class Enabled = typename std::enable_if<std::is_same<handle_t, edge_handle>::value>::type>
void expand(edge_handle e)
{
for (auto ee : e.vertexA().edges())
if (seen.insert(ee))
queue.push(ee);
for (auto ee : e.vertexB().edges())
if (seen.insert(ee))
queue.push(ee);
}
template <class Enabled = typename std::enable_if<std::is_same<handle_t, halfedge_handle>::value>::type>
void expand(halfedge_handle h)
{
for (auto hh : h.vertex_to().outgoing_halfedges())
if (seen.insert(hh))
queue.push(hh);
}
private:
Mesh const* mesh;
queue_t queue;
set_t seen;
};
template <class tag, class range_t>
struct bfs_iterator
{
using index_t = typename primitive<tag>::index;
using handle_t = typename primitive<tag>::handle;
range_t* range;
handle_t handle;
bfs_iterator() = default;
bfs_iterator(range_t& range, handle_t handle) : range(&range), handle(handle) {}
handle_t operator*() const { return handle; }
bfs_iterator& operator++()
{
handle = range->advance(handle);
return *this;
}
bfs_iterator operator++(int)
{
auto i = *this;
operator++();
return i;
}
bool operator==(bfs_iterator const& rhs) const { return handle.idx == rhs.handle.idx; }
bool operator!=(bfs_iterator const& rhs) const { return handle.idx != rhs.handle.idx; }
};
}
}
\ No newline at end of file
......@@ -320,7 +320,7 @@ inline void Mesh::compactify()
inline void Mesh::clear()
{
for (auto &v_h : mVertexToOutgoingHalfedge)
v_h = halfedge_index::invalid();
v_h.value = -2;
for (auto &f_h : mFaceToHalfedge)
f_h = halfedge_index::invalid();
for (auto &h_v : mHalfedgeToVertex)
......
......@@ -340,8 +340,7 @@ template <class FuncT>
auto smart_range<this_t, ElementT>::to_vector(FuncT &&f) const -> std::vector<tmp::decayed_result_type_of<FuncT, ElementT>>
{
std::vector<tmp::decayed_result_type_of<FuncT, ElementT>> v;
for (auto h : *static_cast<this_t const *>(this))
v.push_back(f(h));
this->into_vector(v, f);
return v;
}
......@@ -350,16 +349,7 @@ template <size_t N, class FuncT>
auto smart_range<this_t, ElementT>::to_array(FuncT &&f) const -> std::array<tmp::decayed_result_type_of<FuncT, ElementT>, N>
{
std::array<tmp::decayed_result_type_of<FuncT, ElementT>, N> a;
auto idx = 0;
for (auto h : *static_cast<this_t const *>(this))
{
if (idx >= N)
break;
a[idx] = f(h);
++idx;
}
this->into_array(a, f);
return a;
}
......@@ -368,8 +358,7 @@ template <class FuncT>
auto smart_range<this_t, ElementT>::to_set(FuncT &&f) const -> std::set<tmp::decayed_result_type_of<FuncT, ElementT>>
{
std::set<tmp::decayed_result_type_of<FuncT, ElementT>> s;
for (auto h : *static_cast<this_t const *>(this))
s.insert(f(h));
this->into_set(s, f);
return s;
}
......@@ -378,11 +367,50 @@ template <class FuncT>
auto smart_range<this_t, ElementT>::to_map(FuncT &&f) const -> std::map<ElementT, tmp::decayed_result_type_of<FuncT, ElementT>>
{
std::map<ElementT, tmp::decayed_result_type_of<FuncT, ElementT>> m;
for (auto h : *static_cast<this_t const *>(this))
m[h] = f(h);
this->into_map(m, f);
return m;
}
template <class this_t, class ElementT>
template <class FuncT>
void smart_range<this_t, ElementT>::into_vector(std::vector<tmp::decayed_result_type_of<FuncT, ElementT>> &container, FuncT &&f) const
{
for (auto h : *static_cast<this_t const *>(this))
container.push_back(f(h));
}
template <class this_t, class ElementT>
template <class FuncT>
void smart_range<this_t, ElementT>::into_set(std::set<tmp::decayed_result_type_of<FuncT, ElementT>> &container, FuncT &&f) const
{
for (auto h : *static_cast<this_t const *>(this))
container.insert(f(h));
}
template <class this_t, class ElementT>
template <class FuncT>
void smart_range<this_t, ElementT>::into_map(std::map<ElementT, tmp::decayed_result_type_of<FuncT, ElementT>> &container, FuncT &&f) const
{
for (auto h : *static_cast<this_t const *>(this))
container[h] = f(h);
}
template <class this_t, class ElementT>
template <size_t N, class FuncT>
void smart_range<this_t, ElementT>::into_array(std::array<tmp::decayed_result_type_of<FuncT, ElementT>, N> &container, FuncT &&f) const
{
auto idx = 0;
for (auto h : *static_cast<this_t const *>(this))
{
if (idx >= N)
break;
container[idx] = f(h);
++idx;
}
}
template <class this_t, class ElementT>
template <class PredT>
......
......@@ -29,7 +29,7 @@ struct valid_primitive_iterator final
handle.idx = low_level_api(handle.mesh).next_valid_idx_from(handle.idx);
return *this;
}
valid_primitive_iterator operator++(int)const
valid_primitive_iterator operator++(int)
{
auto i = *this;
operator++();
......@@ -69,7 +69,7 @@ struct all_primitive_iterator final
++handle.idx.value;
return *this;
}
all_primitive_iterator operator++(int)const
all_primitive_iterator operator++(int)
{
auto i = *this;
operator++();
......@@ -107,7 +107,7 @@ struct attribute_iterator final
++idx;
return *this;
}
attribute_iterator operator++(int)const
attribute_iterator operator++(int)
{
auto i = *this;
operator++();
......@@ -136,7 +136,7 @@ struct filtering_iterator final
return *this;
}
filtering_iterator operator++(int)const
filtering_iterator operator++(int)
{
auto i = *this;
operator++();
......
#pragma once
// includes all supported objects
#include "objects/quad.hh"
#pragma once
#include "../Mesh.hh"
namespace polymesh
{
namespace objects
{
/// Adds a (tessellated) quad to the given mesh
/// qf is called with (v, x, y), with vertex handle v and (x,y) from 0..1 (row-by-row)
/// (w, h) is the number of sub-quads in each dimension
/// returns the one of the new vertices (usually the first)
/// NOTE: the result is NOT triangulated!
template <class QuadF>
vertex_handle add_quad(Mesh& m, QuadF&& qf, int w = 1, int h = 1);
/// ======== IMPLEMENTATION ========
template <class QuadF>
vertex_handle add_quad(Mesh& m, QuadF&& qf, int w, int h)
{
assert(w > 0 && h > 0);
std::vector<vertex_index> verts((w + 1) * (h + 1));
auto i = 0;
for (auto y = 0; y <= h; ++y)
for (auto x = 0; x <= w; ++x)
{
auto pu = x / float(w);
auto pv = y / float(h);
auto v = m.vertices().add();
verts[i] = v;
qf(v, pu, pv);
++i;
}
for (auto y = 0; y < h; ++y)
for (auto x = 0; x < w; ++x)
{
auto v00 = verts[(y + 0) * (w + 1) + (x + 0)].of(m);
auto v10 = verts[(y + 0) * (w + 1) + (x + 1)].of(m);
auto v01 = verts[(y + 1) * (w + 1) + (x + 0)].of(m);
auto v11 = verts[(y + 1) * (w + 1) + (x + 1)].of(m);
m.faces().add(v00, v01, v11, v10);
}
return verts.front().of(m);
}
}
}
#pragma once
#include <array>
#include <cstddef>
#include <map>
#include <set>
#include <array>
#include <vector>
#include "iterators.hh"
......@@ -143,6 +143,16 @@ struct smart_range
template <size_t N, class FuncT = tmp::identity>
auto to_array(FuncT&& f = {}) const -> std::array<tmp::decayed_result_type_of<FuncT, ElementT>, N>;
/// same as to_* but takes the container as a parameter (does NOT clear the container!)
template <class FuncT = tmp::identity>
void into_vector(std::vector<tmp::decayed_result_type_of<FuncT, ElementT>>& container, FuncT&& f = {}) const;
template <class FuncT = tmp::identity>
void into_set(std::set<tmp::decayed_result_type_of<FuncT, ElementT>>& container, FuncT&& f = {}) const;
template <class FuncT = tmp::identity>
void into_map(std::map<ElementT, tmp::decayed_result_type_of<FuncT, ElementT>>& container, FuncT&& f = {}) const;
template <size_t N, class FuncT = tmp::identity>
void into_array(std::array<tmp::decayed_result_type_of<FuncT, ElementT>, N>& container, FuncT&& f = {}) const;
/// returns a new range that consists of all elements where p(x) is true
template <class PredT>
auto where(PredT&& p) const -> filtered_range<ElementT, this_t const&, PredT>;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment