VCG Library
Loading...
Searching...
No Matches
reeb_graph.h
Go to the documentation of this file.
1/****************************************************************************
2* VCGLib o o *
3* Visual and Computer Graphics Library o o *
4* _ O _ *
5* Copyright(C) 2004-2026 \/)\/ *
6* Visual Computing Lab /\/| *
7* ISTI - Italian National Research Council | *
8* \ *
9* All rights reserved. *
10* *
11* This program is free software; you can redistribute it and/or modify *
12* it under the terms of the GNU General Public License as published by *
13* the Free Software Foundation; either version 2 of the License, or *
14* (at your option) any later version. *
15* *
16* This program is distributed in the hope that it will be useful, *
17* but WITHOUT ANY WARRANTY; without even the implied warranty of *
18* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
19* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
20* for more details. *
21* *
22****************************************************************************/
23#ifndef VCG_REEB_GRAPH_H
24#define VCG_REEB_GRAPH_H
25
26#include <vcg/complex/complex.h>
27#include <vcg/complex/algorithms/mesh_assert.h>
28#include <vcg/complex/algorithms/update/topology.h>
29#include <algorithm>
30
35namespace vcg {
36namespace tri {
37
85template <class MeshType>
87{
88public:
89 typedef typename MeshType::FaceType FaceType;
90
91 std::vector<int> nodeVert;
92 std::vector<int> vertNode;
93 std::vector<int> vertArc;
94 std::vector<int> rank;
95 std::vector<int> faceEdge;
96 std::vector<std::pair<int,int> > edgeVert;
97 std::vector<std::vector<int> > edgePath;
98
100 bool Below(int v, int w) const { return rank[v] < rank[w]; }
101
112 template <class EdgeMeshType>
113 void Compute(MeshType &m, EdgeMeshType &graph)
114 {
115 RequirePerVertexQuality(m);
116 RequireFFAdjacency(m);
117 MeshAssert<MeshType>::FFAdjacencyIsInitialized(m);
118 MeshAssert<MeshType>::FFTwoManifoldEdge(m);
119 MeshAssert<MeshType>::VertexQualityFinite(m);
120
121 // Total order of the vertices: by quality, ties by index.
122 std::vector<int> order;
123 for (size_t i = 0; i < m.vert.size(); ++i)
124 if (!m.vert[i].IsD()) order.push_back(int(i));
125 std::sort(order.begin(), order.end(), [&](int a, int b) {
126 const auto qa = m.vert[a].cQ(), qb = m.vert[b].cQ();
127 return qa < qb || (qa == qb && a < b); });
128 rank.assign(m.vert.size(), -1);
129 for (size_t i = 0; i < order.size(); ++i) rank[order[i]] = int(i);
130
131 // One index per edge, shared by the two faces across it.
132 faceEdge.assign(3 * m.face.size(), -1);
133 edgeVert.clear();
134 std::vector<int> edgeFaces;
135 std::vector<int> vertFaces(m.vert.size(), 0);
136 for (FaceType &f : m.face) if (!f.IsD())
137 {
138 const size_t fi = tri::Index(m, f);
139 for (int z = 0; z < 3; ++z)
140 {
141 ++vertFaces[tri::Index(m, f.V(z))];
142 if (faceEdge[3 * fi + z] >= 0) continue;
143 int v0 = int(tri::Index(m, f.V0(z))), v1 = int(tri::Index(m, f.V1(z)));
144 if (Below(v1, v0)) std::swap(v0, v1);
145 faceEdge[3 * fi + z] = int(edgeVert.size());
146 edgeFaces.push_back(face::IsBorder(f, z) ? 1 : 2);
147 if (!face::IsBorder(f, z))
148 faceEdge[3 * tri::Index(m, f.FFp(z)) + f.FFi(z)] = int(edgeVert.size());
149 edgeVert.push_back(std::make_pair(v0, v1));
150 }
151 }
152
153 wArc.clear();
154 up.assign(m.vert.size(), std::vector<int>());
155 down.assign(m.vert.size(), std::vector<int>());
156 path.assign(edgeVert.size(), std::vector<int>());
157 pathHi.assign(edgeVert.size(), std::vector<int>());
158 active.assign(edgeVert.size(), false);
159 std::vector<int> label(m.vert.size(), -1);
160
161 // Sweep the triangles by their highest vertex, so that contours are glued close to
162 // the level they belong to and vertices leave the graph soon after the sweep passes.
163 std::vector<int> faceOrder;
164 std::vector<int> faceTop(m.face.size(), -1);
165 for (FaceType &f : m.face) if (!f.IsD())
166 {
167 const int fi = int(tri::Index(m, f));
168 for (int z = 0; z < 3; ++z) faceTop[fi] = std::max(faceTop[fi], rank[tri::Index(m, f.V(z))]);
169 faceOrder.push_back(fi);
170 }
171 std::sort(faceOrder.begin(), faceOrder.end(), [&](int a, int b) { return faceTop[a] < faceTop[b]; });
172
173 for (int fi : faceOrder)
174 {
175 FaceType &f = m.face[fi];
176 int v[3], e[3];
177 for (int z = 0; z < 3; ++z) { v[z] = int(tri::Index(m, f.V(z))); e[z] = faceEdge[3 * fi + z]; }
178 for (int z = 0; z < 3; ++z)
179 if (path[e[z]].empty()) NewEdge(e[z]);
180 // Sides of the sorted triangle: side z joins V(z) and V(z+1).
181 int lo = 0, mid = 1, hi = 2;
182 if (Below(v[mid], v[lo])) std::swap(lo, mid);
183 if (Below(v[hi], v[mid])) std::swap(mid, hi);
184 if (Below(v[mid], v[lo])) std::swap(lo, mid);
185 auto side = [&](int a, int b) { return (a + 1) % 3 == b ? e[a] : e[b]; };
186 Glue(side(lo, hi), side(lo, mid), side(mid, hi));
187
188 for (int z = 0; z < 3; ++z)
189 if (--edgeFaces[e[z]] == 0) Finish(e[z]);
190 for (int z = 0; z < 3; ++z)
191 if (--vertFaces[v[z]] == 0) RemoveRegular(v[z], label);
192 }
193
194 // Arcs merged after a vertex was complete can leave it with one arc on each side.
195 for (int vi : order) RemoveRegular(vi, label);
196
197 // The surviving arcs and nodes become the edges and vertices of the graph.
198 std::vector<int> arcId(wArc.size(), -1);
199 int na = 0;
200 for (size_t a = 0; a < wArc.size(); ++a) if (wArc[a].merged < 0) arcId[a] = na++;
201 nodeVert.clear();
202 vertNode.assign(m.vert.size(), -1);
203 vertArc.assign(m.vert.size(), -1);
204 for (int vi : order)
205 {
206 if (!up[vi].empty() || !down[vi].empty()) { vertNode[vi] = int(nodeVert.size()); nodeVert.push_back(vi); }
207 else if (label[vi] >= 0) vertArc[vi] = arcId[Resolve(label[vi], 2 * rank[vi])];
208 }
209 graph.Clear();
211 for (size_t i = 0; i < nodeVert.size(); ++i)
212 graph.vert[i].P() = EdgeMeshType::CoordType::Construct(m.vert[nodeVert[i]].cP());
214 for (size_t a = 0; a < wArc.size(); ++a)
215 if (arcId[a] >= 0)
216 {
217 graph.edge[arcId[a]].V(0) = &graph.vert[vertNode[wArc[a].lo]];
218 graph.edge[arcId[a]].V(1) = &graph.vert[vertNode[wArc[a].hi]];
219 }
220 if (tri::HasVEAdjacency(graph)) tri::UpdateTopology<EdgeMeshType>::VertexEdge(graph);
221
222 // Map every edge to the final arcs it crosses.
223 edgePath.assign(edgeVert.size(), std::vector<int>());
224 auto node = [&](int a, int k) { return int(tri::Index(graph, graph.edge[a].cV(k))); };
225 for (size_t ei = 0; ei < edgeVert.size(); ++ei)
226 {
227 // An edge is monotone: between two points of one arc it can only follow that arc.
228 const int u = edgeVert[ei].first, w = edgeVert[ei].second;
229 const int au = vertArc[u], aw = vertArc[w];
230 const int a = au >= 0 && (au == aw || (aw < 0 && node(au, 1) == vertNode[w])) ? au
231 : aw >= 0 && au < 0 && node(aw, 0) == vertNode[u] ? aw : -1;
232 if (a >= 0) { edgePath[ei].push_back(a); continue; }
233 const int top = 2 * rank[edgeVert[ei].second];
234 int pos = 2 * rank[edgeVert[ei].first] + 1;
235 size_t k = 0;
236 while (pos < top)
237 {
238 while (2 * rank[pathHi[ei][k]] < pos) ++k;
239 const int y = Resolve(path[ei][k], pos);
240 edgePath[ei].push_back(arcId[y]);
241 pos = 2 * rank[wArc[y].hi] + 1;
242 }
243 }
244 wArc.clear(); up.clear(); down.clear(); path.clear(); pathHi.clear(); active.clear();
245 }
246
247private:
248 // Working arc: the active edges whose path contains it, the arc it was merged into,
249 // and the arcs split off below it, as (lower node before the split, new lower arc).
250 struct WArc
251 {
252 int lo, hi, merged;
253 std::vector<int> edges;
254 std::vector<std::pair<int,int> > below;
255 };
256 std::vector<WArc> wArc;
257 std::vector<std::vector<int> > up, down; // working arcs at each vertex
258 std::vector<std::vector<int> > path; // working path of each edge, frozen when finished
259 std::vector<std::vector<int> > pathHi; // upper node of each arc of a frozen path
260 std::vector<bool> active;
261
262 int NewArc(int lo, int hi)
263 {
264 wArc.push_back(WArc{lo, hi, -1, std::vector<int>(), std::vector<std::pair<int,int> >()});
265 const int a = int(wArc.size()) - 1;
266 up[lo].push_back(a);
267 down[hi].push_back(a);
268 return a;
269 }
270
271 void NewEdge(int e)
272 {
273 const int a = NewArc(edgeVert[e].first, edgeVert[e].second);
274 path[e].push_back(a);
275 wArc[a].edges.push_back(e);
276 active[e] = true;
277 }
278
279 void Finish(int e)
280 {
281 active[e] = false;
282 for (int a : path[e]) pathHi[e].push_back(wArc[a].hi);
283 }
284
285 static void Erase(std::vector<int> &v, int x) { v.erase(std::find(v.begin(), v.end(), x)); }
286
287 // Glue the path of the long side lh of a triangle to the paths of its two short sides.
288 void Glue(int lh, int lm, int mh)
289 {
290 const std::vector<int> p = path[lh];
291 std::vector<int> q = path[lm];
292 q.insert(q.end(), path[mh].begin(), path[mh].end());
293 size_t i = 0, j = 0;
294 while (i < p.size() && j < q.size())
295 {
296 const int a = p[i], b = q[j];
297 assert(wArc[a].lo == wArc[b].lo);
298 if (a == b) { ++i; ++j; }
299 else if (wArc[a].hi == wArc[b].hi)
300 {
301 // Keep the arc on more edges, to rewrite fewer paths.
302 if (wArc[a].edges.size() < wArc[b].edges.size()) Merge(b, a); else Merge(a, b);
303 ++i; ++j;
304 }
305 else if (Below(wArc[a].hi, wArc[b].hi)) { Split(b, a); ++i; }
306 else { Split(a, b); ++j; }
307 }
308 }
309
310 // Arc b runs between the same nodes as a and is the same family of contours.
311 void Merge(int a, int b)
312 {
313 for (int e : wArc[b].edges) if (active[e])
314 {
315 *std::find(path[e].begin(), path[e].end(), b) = a;
316 wArc[a].edges.push_back(e);
317 }
318 Erase(up[wArc[b].lo], b);
319 Erase(down[wArc[b].hi], b);
320 wArc[b].merged = a;
321 wArc[b].edges.clear();
322 }
323
324 // Arc a starts where b starts and ends below it: a becomes the lower part of b.
325 void Split(int b, int a)
326 {
327 WArc &B = wArc[b];
328 Erase(up[B.lo], b);
329 B.below.push_back(std::make_pair(B.lo, a));
330 B.lo = wArc[a].hi;
331 up[B.lo].push_back(b);
332 std::vector<int> still;
333 for (int e : B.edges) if (active[e])
334 {
335 path[e].insert(std::find(path[e].begin(), path[e].end(), b), a);
336 wArc[a].edges.push_back(e);
337 still.push_back(e);
338 }
339 B.edges.swap(still);
340 }
341
342 // Once all its triangles are in, a vertex with one arc below and one above is regular:
343 // its two arcs become one. Every edge still active crosses it, so its paths go d, u.
344 void RemoveRegular(int v, std::vector<int> &label)
345 {
346 if (up[v].size() != 1 || down[v].size() != 1) return;
347 const int d = down[v][0], u = up[v][0];
348 for (int e : wArc[u].edges) if (active[e]) Erase(path[e], u);
349 wArc[d].hi = wArc[u].hi;
350 *std::find(down[wArc[u].hi].begin(), down[wArc[u].hi].end(), u) = d;
351 wArc[u].merged = d;
352 wArc[u].edges.clear();
353 up[v].clear(); down[v].clear();
354 label[v] = d;
355 }
356
357 // The live arc that now holds position pos (2*rank of a vertex, plus one just above it)
358 // of an arc that held it when it was recorded.
359 int Resolve(int x, int pos) const
360 {
361 for (;;)
362 {
363 const WArc &X = wArc[x];
364 if (pos < 2 * rank[X.lo])
365 {
366 // Lower nodes grow along the history: take the last split below pos.
367 x = std::partition_point(X.below.begin(), X.below.end(),
368 [&](const std::pair<int,int> &s) { return 2 * rank[s.first] < pos; })[-1].second;
369 }
370 else if (X.merged >= 0) x = X.merged;
371 else return x;
372 }
373 }
374};
375
376} // end namespace tri
377} // end namespace vcg
378
379#endif // VCG_REEB_GRAPH_H
static EdgeIterator AddEdges(MeshType &m, size_t n, PointerUpdater< EdgePointer > &pu)
Add n edges to the mesh. Function to add n edges to the mesh. The elements are added always to the en...
Definition: allocate.h:339
static VertexIterator AddVertices(MeshType &m, size_t n, PointerUpdater< VertexPointer > &pu)
Add n vertices to the mesh. Function to add n vertices to the mesh. The elements are added always to ...
Definition: allocate.h:195
Reeb graph of the vertex quality of a triangle mesh.
Definition: reeb_graph.h:87
std::vector< int > vertNode
node of each mesh vertex, -1 for vertices inside an arc
Definition: reeb_graph.h:92
std::vector< int > vertArc
arc of each mesh vertex inside an arc, -1 for nodes
Definition: reeb_graph.h:93
void Compute(MeshType &m, EdgeMeshType &graph)
Compute the Reeb graph of the vertex quality of m into graph.
Definition: reeb_graph.h:113
bool Below(int v, int w) const
True if mesh vertex v comes before w in the order by quality.
Definition: reeb_graph.h:100
std::vector< int > faceEdge
edge number of side z of face fi, at 3*fi+z
Definition: reeb_graph.h:95
std::vector< std::pair< int, int > > edgeVert
lower and upper mesh vertex of each edge
Definition: reeb_graph.h:96
std::vector< std::vector< int > > edgePath
arcs crossed by each mesh edge, going up
Definition: reeb_graph.h:97
std::vector< int > rank
position of each mesh vertex in the order by quality
Definition: reeb_graph.h:94
std::vector< int > nodeVert
mesh vertex of each node
Definition: reeb_graph.h:91
Generation of per-vertex and per-face topological information.
Definition: topology.h:43
bool IsBorder(FaceType const &f, const int j)
Definition: topology.h:55
Definition: color4.h:30