15#include <unordered_set>
19#include <lagrange/Edge.h>
20#include <lagrange/common.h>
21#include <lagrange/legacy/inline.h>
22#include <lagrange/utils/range.h>
23#include <lagrange/utils/warning.h>
44template <
typename Index,
typename Allocator = std::list<EdgeType<Index>>>
45std::vector<std::list<Index>> chain_edges(
const Allocator& edges,
bool close_loop =
false)
47 using EdgeIterator =
typename Allocator::const_iterator;
48 using VertexEdgeAdjList = std::unordered_map<Index, std::vector<EdgeIterator>>;
50 using Chain = std::list<Index>;
51 std::vector<Chain> chains;
52 VertexEdgeAdjList next;
53 VertexEdgeAdjList prev;
54 size_t num_edges = std::distance(edges.begin(), edges.end());
55 next.reserve(num_edges);
56 prev.reserve(num_edges);
57 std::vector<bool> visited(num_edges,
false);
59 auto insert_or_append = [&](VertexEdgeAdjList& adj_list, Index key, EdgeIterator value) {
60 auto itr = adj_list.find(key);
61 if (itr == adj_list.end()) {
62 adj_list.insert({key, {std::move(value)}});
64 itr->second.push_back(std::move(value));
68 for (
auto itr = edges.begin(); itr != edges.end(); ++itr) {
70 insert_or_append(next, e[0], itr);
71 insert_or_append(prev, e[1], itr);
78 auto grow_chain_forward = [&](Chain& chain) ->
void {
80 assert(chain.size() > 0);
82 const auto curr_v = chain.back();
83 const auto itr = next.find(curr_v);
84 if (itr != next.end()) {
85 const auto& next_edges = itr->second;
86 if (next_edges.size() != 1)
break;
88 auto e_itr = next_edges.front();
89 auto eid = std::distance(edges.begin(), e_itr);
90 if (visited[eid])
break;
92 const auto& e = *e_itr;
94 chain.push_back(e[1]);
106 auto grow_chain_backward = [&](Chain& chain) ->
void {
108 assert(chain.size() > 0);
110 const auto curr_v = chain.front();
111 const auto itr = prev.find(curr_v);
112 if (itr != prev.end()) {
113 const auto& prev_edges = itr->second;
114 if (prev_edges.size() != 1)
break;
116 auto e_itr = prev_edges.front();
117 auto eid = std::distance(edges.begin(), e_itr);
118 if (visited[eid])
break;
120 const auto& e = *e_itr;
122 chain.push_front(e[0]);
131 for (
auto itr = edges.begin(); itr != edges.end(); ++itr, eid++) {
132 if (visited[eid])
continue;
134 const auto& e = *itr;
136 chain.push_back(e[0]);
137 chain.push_back(e[1]);
140 grow_chain_forward(chain);
141 grow_chain_backward(chain);
143 if (!close_loop && chain.back() == chain.front()) {
146 chains.push_back(std::move(chain));
154template <
typename EdgeArray>
155size_t get_num_edges(
const EdgeArray& edges)
157 return static_cast<size_t>(edges.rows());
161template <
typename EdgeType>
162size_t get_num_edges(
const std::vector<EdgeType>& edges)
168template <
typename VertexIndex,
typename EdgeArray,
typename EdgeIndex>
169std::pair<VertexIndex, VertexIndex> get_edge_endpoints(EdgeArray& edges, EdgeIndex edge_index)
171 return std::make_pair(
172 static_cast<VertexIndex>(edges(
static_cast<Eigen::Index
>(edge_index), 0)),
173 static_cast<VertexIndex>(edges(
static_cast<Eigen::Index
>(edge_index), 1)));
177template <
typename VertexIndex,
typename EdgeType,
typename EdgeIndex>
178std::pair<VertexIndex, VertexIndex> get_edge_endpoints(
179 const std::vector<EdgeType>& edges,
180 EdgeIndex edge_index)
182 const auto& e = edges[
static_cast<size_t>(edge_index)];
201template <
typename Index,
typename Allocator = std::vector<EdgeType<Index>>>
203 const Allocator& edges,
204 bool close_loop =
false)
206 using VertexEdgeAdjList = std::unordered_map<Index, std::vector<Index>>;
208 using Chain = std::vector<Index>;
209 std::vector<Chain> chains;
210 VertexEdgeAdjList adj_list;
211 size_t num_edges = _detail::get_num_edges(edges);
212 adj_list.reserve(num_edges);
213 std::vector<bool> visited(num_edges,
false);
215 auto add_adj_connection = [&](Index ei) {
216 auto v = _detail::get_edge_endpoints<Index>(edges, ei);
218 auto itr = adj_list.find(v.first);
219 if (itr != adj_list.end()) {
220 itr->second.push_back(ei);
222 adj_list.insert({v.first, {ei}});
225 itr = adj_list.find(v.second);
226 if (itr != adj_list.end()) {
227 itr->second.push_back(ei);
229 adj_list.insert({v.second, {ei}});
234 for (
auto ei :
range(num_edges)) {
235 add_adj_connection(ei);
237 LA_IGNORE_RANGE_LOOP_ANALYSIS_END
239 auto grow_chain_forward = [&](Chain& chain) {
240 Index curr_v = chain.back();
243 const auto& adj_edges = adj_list[curr_v];
244 if (adj_edges.size() != 2)
break;
246 bool updated =
false;
247 for (
auto ei : adj_edges) {
248 if (visited[ei])
continue;
250 auto v = _detail::get_edge_endpoints<Index>(edges, ei);
251 if (v.first == curr_v) {
252 chain.push_back(v.second);
255 chain.push_back(v.first);
257 curr_v = chain.back();
265 auto grow_chain_backward = [&](Chain& chain) {
266 std::reverse(chain.begin(), chain.end());
267 grow_chain_forward(chain);
268 std::reverse(chain.begin(), chain.end());
271 for (
auto ei :
range(num_edges)) {
272 if (visited[ei])
continue;
274 auto v = _detail::get_edge_endpoints<Index>(edges, ei);
277 chain.reserve(num_edges);
278 chain.push_back(v.first);
279 chain.push_back(v.second);
280 grow_chain_forward(chain);
281 grow_chain_backward(chain);
283 if (!close_loop && chain.front() == chain.back()) {
286 chains.push_back(std::move(chain));
@ VertexIndex
Single channel integer attribute indexing a mesh vertex.
#define la_debug_assert(...)
Debug assertion check.
Definition: assert.h:189
internal::Range< Index > range(Index end)
Returns an iterable object representing the range [0, end).
Definition: range.h:176
#define LA_IGNORE_RANGE_LOOP_ANALYSIS_BEGIN
Ignore range loop variable may be a copy.
Definition: warning.h:148
ChainEdgesResult< Index > chain_undirected_edges(const span< const Index > edges, const ChainEdgesOptions &options={})
Chain a set of undirected edges into loops and chains.
Definition: chain_edges.cpp:248
Main namespace for Lagrange.
Definition: AABBIGL.h:30