Lagrange
Edge.h
1/*
2 * Copyright 2016 Adobe. All rights reserved.
3 * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License. You may obtain a copy
5 * of the License at http://www.apache.org/licenses/LICENSE-2.0
6 *
7 * Unless required by applicable law or agreed to in writing, software distributed under
8 * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9 * OF ANY KIND, either express or implied. See the License for the specific language
10 * governing permissions and limitations under the License.
11 */
12#pragma once
13
14#include <array>
15#include <exception>
16#include <functional>
17#include <memory>
18#include <unordered_map>
19#include <unordered_set>
20
21#include <lagrange/common.h>
22#include <lagrange/utils/assert.h>
23#include <lagrange/utils/safe_cast.h>
24
25namespace lagrange {
26
27template <typename Index>
29{
30private:
31 Index m_v1;
32 Index m_v2;
33
34public:
35 EdgeType(Index v1, Index v2)
36 : m_v1(v1)
37 , m_v2(v2)
38 {}
39 EdgeType(const EdgeType<Index>& obj)
40 : m_v1(obj.v1())
41 , m_v2(obj.v2())
42 {}
43 EdgeType(EdgeType<Index>&& obj) noexcept
44 : m_v1(obj.v1())
45 , m_v2(obj.v2())
46 {}
47
48 // Invalid() can be useful for EdgeType temporary variables
49 static EdgeType Invalid() { return EdgeType(invalid<Index>(), invalid<Index>()); }
50
51 // Alternate constructor for backward compatibility,
52 // allowing `EdgeType e = {0, 1}`
53 EdgeType(const std::array<Index, 2>& arr)
54 : m_v1(arr[0])
55 , m_v2(arr[1])
56 {}
57
58 inline Index v1() const { return m_v1; }
59 inline Index v2() const { return m_v2; }
60 inline bool is_valid() const { return m_v1 != invalid<Index>() && m_v2 != invalid<Index>(); }
61
62 EdgeType<Index>& operator=(const EdgeType<Index>& other)
63 {
64 this->m_v1 = other.m_v1;
65 this->m_v2 = other.m_v2;
66 return *this;
67 }
68 EdgeType<Index>& operator=(EdgeType<Index>&& other) noexcept
69 {
70 this->m_v1 = other.m_v1;
71 this->m_v2 = other.m_v2;
72 return *this;
73 }
74
75 ~EdgeType() noexcept = default;
76
77 bool operator==(const EdgeType<Index>& rhs) const
78 {
79 return (m_v1 == rhs.m_v1 && m_v2 == rhs.m_v2) || (m_v1 == rhs.m_v2 && m_v2 == rhs.m_v1);
80 }
81 bool operator!=(const EdgeType<Index>& rhs) const { return !(*this == rhs); }
82
83 Index operator[](const Index i) const
84 {
85 if (i == 0) return m_v1;
86 if (i == 1) return m_v2;
87 la_runtime_assert(false, "Bad Index: " + std::to_string(i));
88 return m_v1;
89 }
90
91 // Note: strict order operator< is NOT implemented, because:
92 // - order of edges is not well defined
93 // - by not implementing it, defining a std::set<EdgeType> will
94 // result in a compile error, and you should *not* use
95 // std::set<EdgeType>. Use std::unordered_set<EdgeType> instead.
96
97 // allows: for (Index v : edge) { ... }
99 {
100 public:
101 // Types needed to make a compatible iterator.
102 using iterator_category = std::input_iterator_tag;
104 using difference_type = std::ptrdiff_t;
105 using pointer = EdgeType<Index>*;
106 using reference = EdgeType<Index>&;
107
108 private:
109 int m_i;
110 const EdgeType<Index>& m_edge;
111
112 public:
113 iterator(const EdgeType<Index>& edge, int i)
114 : m_i(i)
115 , m_edge(edge)
116 {}
117 bool operator!=(const iterator& rhs) const
118 {
119 return m_edge != rhs.m_edge || m_i != rhs.m_i;
120 }
121 iterator& operator++()
122 {
123 ++m_i;
124 return *this;
125 }
126 Index operator*() const { return m_edge[m_i]; }
127 };
128 iterator begin() const { return iterator(*this, 0); }
129 iterator end() const { return iterator(*this, 2); }
130
131
132 bool has_shared_vertex(const EdgeType<Index>& other) const
133 {
134 return m_v1 == other.m_v1 || m_v1 == other.m_v2 || m_v2 == other.m_v1 || m_v2 == other.m_v2;
135 }
136 Index get_shared_vertex(const EdgeType<Index>& other) const
137 {
138 la_runtime_assert(*this != other, "get_shared_vertex() failed due to identical edges");
139 if (m_v1 == other.m_v1) return m_v1;
140 if (m_v1 == other.m_v2) return m_v1;
141 if (m_v2 == other.m_v1) return m_v2;
142 if (m_v2 == other.m_v2) return m_v2;
143 return invalid<Index>();
144 }
145 Index get_other_vertex(Index v) const
146 {
147 la_runtime_assert(m_v1 == v || m_v2 == v);
148 if (m_v1 == v) return m_v2;
149 return m_v1;
150 }
151};
152
153template <typename Index, typename T>
154using EdgeMap = std::unordered_map<EdgeType<Index>, T>;
155
156template <typename Index>
157using EdgeSet = std::unordered_set<EdgeType<Index>>;
158
159template <typename MeshType>
160using EdgeFacetMap =
161 std::unordered_map<EdgeType<typename MeshType::Index>, std::vector<typename MeshType::Index>>;
162
163// Computes a mapping from each edge to its adjacent facets.
164// Only considers the sub-mesh defined by 'active_facets'
165template <typename MeshType>
166EdgeFacetMap<MeshType> compute_edge_facet_map_in_active_facets(
167 const MeshType& mesh,
168 const std::unordered_set<typename MeshType::Index>& active_facets)
169{
170 using Index = typename MeshType::Index;
171 std::unordered_map<EdgeType<Index>, std::vector<Index>> edge_facet_map;
172 const Index num_facets = mesh.get_num_facets();
173 const Index vertex_per_facet = mesh.get_vertex_per_facet();
174 const typename MeshType::FacetArray& facets = mesh.get_facets();
175 edge_facet_map.reserve(active_facets.size() * vertex_per_facet);
176 for (Index i = 0; i < num_facets; ++i) {
177 if (active_facets.find(i) == active_facets.end()) continue;
178 for (Index j = 0; j < vertex_per_facet; ++j) {
179 const Index v1 = facets(i, j);
180 const Index v2 = facets(i, (j + 1) % vertex_per_facet);
181 const EdgeType<Index> edge(v1, v2);
182 auto it = edge_facet_map.find(edge);
183 if (it == edge_facet_map.end()) {
184 edge_facet_map[edge] = {i};
185 } else {
186 it->second.push_back(i);
187 }
188 }
189 }
190 return edge_facet_map;
191}
192
193// Computes a mapping from each edge to its adjacent facets.
194// Only considers the sub-mesh defined by 'active_vertices'
195template <typename MeshType>
196EdgeFacetMap<MeshType> compute_edge_facet_map_in_active_vertices(
197 const MeshType& mesh,
198 const std::unordered_set<typename MeshType::Index>& active_vertices)
199{
200 using Index = typename MeshType::Index;
201
202 std::unordered_set<Index> active_facets;
203
204 if (mesh.is_connectivity_initialized()) {
205 // this path is faster but requires connectivity initialized
206 for (Index v : active_vertices) {
207 for (Index f : mesh.get_facets_adjacent_to_vertex(v)) {
208 active_facets.insert(f);
209 }
210 }
211 } else {
212 const Index num_facets = mesh.get_num_facets();
213 const Index vertex_per_facet = mesh.get_vertex_per_facet();
214 const typename MeshType::FacetArray& facets = mesh.get_facets();
215 for (Index i = 0; i < num_facets; ++i) {
216 if (active_facets.find(i) != active_facets.end()) continue; // already there
217 for (Index j = 0; j < vertex_per_facet; ++j) {
218 if (active_vertices.find(facets(i, j)) != active_vertices.end()) {
219 active_facets.insert(i);
220 break;
221 }
222 }
223 }
224 }
225 return compute_edge_facet_map_in_active_facets(mesh, active_facets);
226}
227} // namespace lagrange
228
229namespace std {
230template <typename Index>
231struct hash<lagrange::EdgeType<Index>>
232{
233 std::size_t operator()(const lagrange::EdgeType<Index>& key) const
234 {
235 return lagrange::safe_cast<std::size_t>(key.v1() + key.v2());
236 }
237};
238} // namespace std
Definition: Edge.h:99
Definition: Edge.h:29
Definition: Mesh.h:48
#define la_runtime_assert(...)
Runtime assertion check.
Definition: assert.h:169
Main namespace for Lagrange.
Definition: AABBIGL.h:30