VCG Library
Loading...
Searching...
No Matches
handle_tunnel_loops.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_HANDLE_TUNNEL_LOOPS_H
24#define VCG_HANDLE_TUNNEL_LOOPS_H
25
26#include <vcg/complex/complex.h>
27#include <vcg/complex/append.h>
28#include <vcg/complex/algorithms/clean.h>
29#include <vcg/complex/algorithms/stat.h>
30#include <vcg/complex/algorithms/update/quality.h>
31#include <vcg/complex/algorithms/update/topology.h>
33#include <vcg/math/disjoint_set.h>
34#include <vcg/math/random_generator.h>
35#include <vcg/space/planar_polygon_tessellation.h>
36#include <bitset>
37#include <map>
38#include <numeric>
39#include <queue>
40#include <set>
41
46namespace vcg {
47namespace tri {
48
50namespace handle_tunnel_detail {
51class Vertex; class Face;
52struct Types : public UsedTypes<Use<Vertex>::AsVertexType, Use<Face>::AsFaceType> {};
53class Vertex : public vcg::Vertex<Types, vertex::Coord3d, vertex::Qualityd, vertex::BitFlags> {};
54class Face : public vcg::Face<Types, face::VertexRef, face::FFAdj, face::BitFlags> {};
55class Mesh : public TriMesh<std::vector<Vertex>, std::vector<Face> > {};
56class GVertex; class GEdge;
57struct GTypes : public UsedTypes<Use<GVertex>::AsVertexType, Use<GEdge>::AsEdgeType> {};
58class GVertex : public vcg::Vertex<GTypes, vertex::Coord3d, vertex::BitFlags> {};
59class GEdge : public vcg::Edge<GTypes, edge::VertexRef, edge::BitFlags> {};
60class Graph : public TriMesh<std::vector<GVertex>, std::vector<GEdge> > {};
61}
63
140template <class MeshType>
142{
143public:
146 typedef std::vector<int> Loop;
147
149 struct Param
150 {
151 unsigned int seed = 0;
152 int maxIter = 100;
153 int patience = 10;
154 int attempts = 10;
155 bool localMinima = false;
156 int samples = 100;
157 double overlap = 0.5;
158 double persistence = 0.05;
159 int maxLoops = 0;
160 };
161
162 std::vector<Loop> handles;
163 std::vector<Loop> tunnels;
164 int genus = 0;
165
175 void Compute(MeshType &m, const Param &par = Param())
176 {
177 handles.clear(); tunnels.clear(); genus = 0;
178 w.Clear();
180 std::vector<int> toM;
181 for (size_t i = 0; i < m.vert.size(); ++i) if (!m.vert[i].IsD()) toM.push_back(int(i));
183 tri::MeshAssert<WMesh>::FFTwoManifoldEdge(w);
184 CloseHoles();
186 throw vcg::MissingPreconditionException("HandleTunnelLoops: the mesh is not connected.");
187 bool oriented, orientable;
188 tri::Clean<WMesh>::OrientCoherentlyMesh(w, oriented, orientable);
189 if (!orientable)
190 throw vcg::MissingPreconditionException("HandleTunnelLoops: the mesh is not orientable.");
191 if (tri::Stat<WMesh>::ComputeMeshVolume(w) < 0) tri::Clean<WMesh>::FlipMesh(w);
193
194 math::MarsenneTwisterRNG rnd(par.seed);
195 for (int attempt = 0; !InitialBases(rnd); ++attempt)
196 if (attempt + 1 == par.attempts)
197 throw vcg::MissingPreconditionException("HandleTunnelLoops: no generic height direction found.");
198 if (genus == 0) return;
199 Annotate();
200
201 std::vector<Loop> out[2];
202 if (par.localMinima) LocalMinima(par, rnd, out);
203 else if (par.maxIter > 0) Tighten(par.maxIter, par.patience, rnd, out);
204 else
205 for (int t = 0; t < 2; ++t)
206 for (const std::vector<int> &c : chain[t])
207 for (const Loop &l : ChainLoops(c)) out[t].push_back(l);
208 for (int t = 0; t < 2; ++t)
209 for (const Loop &l : out[t])
210 {
211 Loop o = ToInput(l, toM);
212 if (!o.empty()) (t == 0 ? handles : tunnels).push_back(o);
213 }
214 }
215
223 template <class EdgeMeshType>
224 static void LoopsToEdgeMesh(const MeshType &m, const std::vector<Loop> &loops, EdgeMeshType &em)
225 {
226 for (const Loop &l : loops)
227 {
228 const size_t base = em.vert.size();
231 for (size_t k = 0; k < l.size(); ++k)
232 {
233 em.vert[base + k].P() = EdgeMeshType::CoordType::Construct(m.vert[l[k]].cP());
234 typename EdgeMeshType::EdgeType &e = em.edge[em.edge.size() - l.size() + k];
235 e.V(0) = &em.vert[base + k];
236 e.V(1) = &em.vert[base + (k + 1) % l.size()];
237 }
238 }
239 }
240
241private:
242 typedef handle_tunnel_detail::Mesh WMesh;
243 typedef WMesh::FaceType WFace;
244 typedef std::vector<uint64_t> Bits;
245 typedef planar_polygon_detail::IndexedPoint2 IPoint;
246
247 WMesh w; // closed, outward oriented copy of the input
249 handle_tunnel_detail::Graph graph; // the Reeb graph, an edge per arc going up
250 int firstFan; // vertices added to close holes start here
251 std::vector<Loop> holes; // boundary of each closed hole, in order
252 std::vector<int> order; // vertices by rank
253 std::vector<Point3d> faceNrm; // outward unit normal of each face
254 std::vector<double> lift; // push-off distance over each face
255 std::vector<std::vector<int> > vertEdges, vertFaces;
256 std::vector<double> edgeLen; // edge weights
257 std::vector<std::vector<int> > chain[2]; // initial handle and tunnel bases, as edge sets
258 std::vector<int> base; // lowest point of each Reeb graph loop
259 int words; // 64-bit words of a homology class
260
261 // ---- Setup ---------------------------------------------------------------------------
262
263 // Close each hole with a fan of triangles around its centroid.
264 void CloseHoles()
265 {
266 firstFan = int(w.vert.size());
267 holes.clear();
268 std::map<int,int> next; // boundary sides, as seen walking the hole
269 for (WFace &f : w.face)
270 for (int z = 0; z < 3; ++z)
271 if (face::IsBorder(f, z))
272 if (!next.insert(std::make_pair(int(tri::Index(w, f.V1(z))), int(tri::Index(w, f.V0(z))))).second)
273 throw vcg::MissingPreconditionException("HandleTunnelLoops: a hole boundary touches itself.");
274 while (!next.empty())
275 {
276 Loop h;
277 for (int v = next.begin()->first; next.count(v); )
278 {
279 h.push_back(v);
280 const int u = next[v];
281 next.erase(v);
282 v = u;
283 }
284 holes.push_back(h);
285 }
286 if (holes.empty()) return;
287 tri::Allocator<WMesh>::AddVertices(w, holes.size());
288 size_t nf = 0;
289 for (size_t k = 0; k < holes.size(); ++k)
290 {
291 Point3d c(0, 0, 0);
292 for (int v : holes[k]) c += w.vert[v].P();
293 w.vert[firstFan + k].P() = c / double(holes[k].size());
294 nf += holes[k].size();
295 }
297 size_t fi = w.face.size() - nf;
298 for (size_t k = 0; k < holes.size(); ++k)
299 for (size_t i = 0; i < holes[k].size(); ++i, ++fi)
300 {
301 w.face[fi].V(0) = &w.vert[holes[k][i]];
302 w.face[fi].V(1) = &w.vert[holes[k][(i + 1) % holes[k].size()]];
303 w.face[fi].V(2) = &w.vert[firstFan + k];
304 }
306 }
307
308 int Lo(int a) const { return int(tri::Index(graph, graph.edge[a].cV(0))); }
309 int Hi(int a) const { return int(tri::Index(graph, graph.edge[a].cV(1))); }
310
311 int Other(int e, int v) const { return rg.edgeVert[e].first ^ rg.edgeVert[e].second ^ v; }
312
313 int EdgeOf(int v, int u) const
314 {
315 for (int e : vertEdges[v]) if (Other(e, v) == u) return e;
316 assert(false);
317 return -1;
318 }
319
320 // Adjacency, weights and normals, once the Reeb graph has numbered the edges.
321 void Setup()
322 {
323 const int nv = int(w.vert.size());
324 vertFaces.assign(nv, std::vector<int>());
325 faceNrm.clear(); lift.clear();
326 for (WFace &f : w.face)
327 {
328 for (int z = 0; z < 3; ++z) vertFaces[tri::Index(w, f.V(z))].push_back(int(tri::Index(w, f)));
329 // A small fraction of the distance from the centroid to the farthest side's line.
330 const Point3d n = (f.P(1) - f.P(0)) ^ (f.P(2) - f.P(0));
331 double longest = 0;
332 for (int z = 0; z < 3; ++z) longest = std::max(longest, Distance(f.P0(z), f.P1(z)));
333 faceNrm.push_back(n / std::max(n.Norm(), std::numeric_limits<double>::min()));
334 lift.push_back(longest > 0 ? 1e-3 * n.Norm() / (3 * longest) : 0);
335 }
336 vertEdges.assign(nv, std::vector<int>());
337 edgeLen.resize(rg.edgeVert.size());
338 double total = 0;
339 for (size_t e = 0; e < rg.edgeVert.size(); ++e)
340 {
341 const int a = rg.edgeVert[e].first, b = rg.edgeVert[e].second;
342 vertEdges[a].push_back(int(e));
343 vertEdges[b].push_back(int(e));
344 edgeLen[e] = Distance(w.vert[a].P(), w.vert[b].P());
345 total += edgeLen[e];
346 }
347 // Loops should not cross the fans that close the holes.
348 for (size_t e = 0; e < rg.edgeVert.size(); ++e)
349 if (std::max(rg.edgeVert[e].first, rg.edgeVert[e].second) >= firstFan) edgeLen[e] = total;
350 }
351
352 // ---- Loops ---------------------------------------------------------------------------
353
354 // Remove the spikes (a, b, a) of a closed walk, also across its ends.
355 static void CancelBacktracks(Loop &l)
356 {
357 Loop s;
358 for (int v : l)
359 {
360 if (!s.empty() && s.back() == v) continue;
361 if (s.size() >= 2 && s[s.size() - 2] == v) { s.pop_back(); continue; }
362 s.push_back(v);
363 }
364 size_t b = 0;
365 while (s.size() - b >= 3 && (s[b] == s.back() || s[b + 1] == s.back()))
366 {
367 if (s[b] == s.back()) s.pop_back();
368 else { s.pop_back(); ++b; }
369 }
370 l.assign(s.begin() + b, s.end());
371 if (l.size() < 3) l.clear();
372 }
373
374 static void Join(Loop &l, const Loop &seg)
375 {
376 l.insert(l.end(), seg.begin() + (!l.empty() && l.back() == seg.front() ? 1 : 0), seg.end());
377 }
378
379 std::vector<int> Edges(const Loop &l) const
380 {
381 std::vector<int> e;
382 for (size_t i = 0; i < l.size(); ++i) e.push_back(EdgeOf(l[i], l[(i + 1) % l.size()]));
383 return e;
384 }
385
386 // Edges used an odd number of times: the sum of the loops over Z2.
387 std::vector<int> Sum(const std::vector<const Loop*> &loops) const
388 {
389 std::vector<int> all;
390 for (const Loop *l : loops) { std::vector<int> e = Edges(*l); all.insert(all.end(), e.begin(), e.end()); }
391 std::sort(all.begin(), all.end());
392 std::vector<int> odd;
393 for (size_t i = 0; i < all.size(); )
394 {
395 size_t j = i;
396 while (j < all.size() && all[j] == all[i]) ++j;
397 if ((j - i) % 2) odd.push_back(all[i]);
398 i = j;
399 }
400 return odd;
401 }
402
403 // An edge set where every vertex has even degree, as one closed walk per connected part
404 // (Hierholzer), leaving out the parts that bound.
405 std::vector<Loop> ChainLoops(const std::vector<int> &c) const
406 {
407 std::map<int, std::vector<int> > adj;
408 for (int e : c) { adj[rg.edgeVert[e].first].push_back(e); adj[rg.edgeVert[e].second].push_back(e); }
409 std::set<int> left(c.begin(), c.end());
410 std::vector<Loop> loops;
411 while (!left.empty())
412 {
413 Loop stack(1, rg.edgeVert[*left.begin()].first), l;
414 while (!stack.empty())
415 {
416 std::vector<int> &a = adj[stack.back()];
417 while (!a.empty() && !left.count(a.back())) a.pop_back();
418 if (a.empty()) { l.push_back(stack.back()); stack.pop_back(); continue; }
419 left.erase(a.back());
420 stack.push_back(Other(a.back(), stack.back()));
421 }
422 l.pop_back();
423 CancelBacktracks(l);
424 if (!l.empty() && !Zero(Class(Edges(l)))) loops.push_back(l);
425 }
426 return loops;
427 }
428
429 // Map a loop back to the input mesh, going around the holes instead of across them.
430 Loop ToInput(const Loop &l, const std::vector<int> &toM) const
431 {
432 Loop o;
433 for (size_t i = 0; i < l.size(); ++i)
434 {
435 if (l[i] < firstFan) { o.push_back(l[i]); continue; }
436 const Loop &h = holes[l[i] - firstFan];
437 const int n = int(h.size());
438 const int x = int(std::find(h.begin(), h.end(), l[(i + l.size() - 1) % l.size()]) - h.begin());
439 const int y = int(std::find(h.begin(), h.end(), l[(i + 1) % l.size()]) - h.begin());
440 const int step = (y - x + n) % n <= n / 2 ? 1 : n - 1;
441 for (int k = (x + step) % n; k != y; k = (k + step) % n) o.push_back(h[k]);
442 }
443 CancelBacktracks(o);
444 for (int &v : o) v = toM[v];
445 return o;
446 }
447
448 // ---- Initial bases from the Reeb graph -----------------------------------------------
449
450 // Preimage of a Reeb arc: a path from its lower to its upper node through the triangles
451 // the arc crosses, snapped to the vertices on its left.
452 Loop ArcPath(int a) const
453 {
454 const int va = rg.nodeVert[Lo(a)], vb = rg.nodeVert[Hi(a)];
455 auto crosses = [&](int e) { const std::vector<int> &p = rg.edgePath[e]; return std::find(p.begin(), p.end(), a) != p.end(); };
456 auto reaches = [&](int f) {
457 for (int z = 0; z < 3; ++z)
458 if (int(tri::Index(w, w.face[f].cV(z))) == vb)
459 for (int s : {z, (z + 2) % 3})
460 {
461 const int e = rg.faceEdge[3 * f + s];
462 if (rg.edgeVert[e].second == vb && rg.edgePath[e].back() == a) return true;
463 }
464 return false;
465 };
466 std::map<int,int> from; // face -> 3 * previous face + side crossed
467 std::queue<int> q;
468 for (int f : vertFaces[va])
469 for (int z = 0; z < 3; ++z)
470 if (int(tri::Index(w, w.face[f].cV(z))) == va)
471 for (int s : {z, (z + 2) % 3})
472 {
473 const int e = rg.faceEdge[3 * f + s];
474 if (rg.edgeVert[e].first == va && rg.edgePath[e].front() == a && from.insert(std::make_pair(f, -1)).second) q.push(f);
475 }
476 while (!q.empty() && !reaches(q.front()))
477 {
478 const int f = q.front(); q.pop();
479 for (int z = 0; z < 3; ++z)
480 {
481 const WFace &F = w.face[f];
482 if (face::IsBorder(F, z) || !crosses(rg.faceEdge[3 * f + z])) continue;
483 if (from.insert(std::make_pair(int(tri::Index(w, F.cFFp(z))), 3 * f + z)).second) q.push(int(tri::Index(w, F.cFFp(z))));
484 }
485 }
486 if (q.empty()) return Loop();
487 Loop l(1, vb);
488 for (int c = from[q.front()]; c >= 0; c = from[c / 3])
489 if (l.back() != int(tri::Index(w, w.face[c / 3].cV1(c % 3)))) l.push_back(int(tri::Index(w, w.face[c / 3].cV1(c % 3))));
490 if (l.back() != va) l.push_back(va);
491 std::reverse(l.begin(), l.end());
492 return l;
493 }
494
495 // The contour just above the lower vertex of edge e0 that crosses e0, traced with the
496 // upper side on its left: its upper vertices and its points projected along the height.
497 struct Contour { Loop above; std::vector<IPoint> pts; std::set<int> edges; };
498 Contour Trace(int e0, const Point3d &du, const Point3d &dv) const
499 {
500 const int p = rg.edgeVert[e0].first, r = rg.rank[p];
501 const double h = 0.5 * (w.vert[p].Q() + w.vert[order[r + 1]].Q());
502 auto below = [&](const WFace &f, int z) { return rg.rank[tri::Index(w, f.cV(z))] <= r; };
503 int f = -1, z = 0;
504 for (int g : vertFaces[p])
505 for (int s = 0; s < 3; ++s)
506 if (rg.faceEdge[3 * g + s] == e0 && int(tri::Index(w, w.face[g].cV0(s))) == p) { f = g; z = s; }
507 Contour c;
508 do
509 {
510 const WFace &F = w.face[f];
511 const int e = rg.faceEdge[3 * f + z];
512 const Point3d &a = F.cP0(z), &b = F.cP1(z);
513 const double ha = F.cV0(z)->cQ(), hb = F.cV1(z)->cQ();
514 const Point3d x = a + (b - a) * std::min(1.0, std::max(0.0, (h - ha) / (hb - ha)));
515 c.above.push_back(int(tri::Index(w, F.cV1(z))));
516 c.pts.push_back(IPoint{Point2d(x * du, x * dv), int(c.pts.size())});
517 c.edges.insert(e);
518 const WFace &G = *F.cFFp(z);
519 const int zg = F.cFFi(z);
520 f = int(tri::Index(w, G));
521 for (z = 0; z < 3; ++z)
522 if (z != zg && below(G, z) && !below(G, (z + 1) % 3)) break;
523 assert(z < 3);
524 } while (rg.faceEdge[3 * f + z] != e0);
525 return c;
526 }
527
528 int UpperEdge(int v, int a) const
529 {
530 for (int e : vertEdges[v]) if (rg.edgeVert[e].first == v && rg.edgePath[e].front() == a) return e;
531 return -1;
532 }
533
534 static void Frame(const Point3d &d, Point3d &u, Point3d &v)
535 {
536 u = d ^ (std::abs(d[0]) < 0.6 ? Point3d(1, 0, 0) : Point3d(0, 1, 0));
537 u.Normalize();
538 v = d ^ u;
539 }
540
541 // A loop pushed off the surface, inside (side -1) or outside (+1). Pushing a vertex
542 // along any one direction can cross a folded fan of triangles, so the copy never passes
543 // over a vertex: it goes around each one on the left, through the centroids of the
544 // triangles lifted along their normal and the midpoints of the edges lifted along the
545 // bisector of the two triangles. Every segment then stays over a single triangle.
546 std::vector<Point3d> PushOff(const Loop &l, double side) const
547 {
548 std::vector<Point3d> out;
549 auto overEdge = [&](int f, int z) {
550 const WFace &F = w.face[f];
551 const int g = int(tri::Index(w, F.cFFp(z)));
552 Point3d b = faceNrm[f] + faceNrm[g];
553 b /= std::max(b.Norm(), std::numeric_limits<double>::min());
554 return (F.cP0(z) + F.cP1(z)) * 0.5 + b * (side * std::min(lift[f], lift[g]));
555 };
556 for (size_t i = 0; i < l.size(); ++i)
557 {
558 const int u = l[(i + l.size() - 1) % l.size()], v = l[i], x = l[(i + 1) % l.size()];
559 int f = -1, z = 0; // the triangle on the left of u->v
560 for (int g : vertFaces[v])
561 for (int s = 0; s < 3; ++s)
562 if (int(tri::Index(w, w.face[g].cV0(s))) == u && int(tri::Index(w, w.face[g].cV1(s))) == v) { f = g; z = s; }
563 out.push_back(overEdge(f, z));
564 for (;;)
565 {
566 const WFace &F = w.face[f];
567 out.push_back((F.cP(0) + F.cP(1) + F.cP(2)) / 3.0 + faceNrm[f] * (side * lift[f]));
568 const int zn = (z + 1) % 3; // the side leaving v
569 if (int(tri::Index(w, F.cV1(zn))) == x) break;
570 out.push_back(overEdge(f, zn));
571 z = F.cFFi(zn);
572 f = int(tri::Index(w, F.cFFp(zn)));
573 }
574 }
575 return out;
576 }
577
578 // A closed polyline projected on a plane, with the depth of its points.
579 struct Poly { std::vector<Point2d> p; std::vector<double> z; Box2d box; };
580 static Poly Project(const std::vector<Point3d> &pts, const Point3d &du, const Point3d &dv, const Point3d &dw)
581 {
582 Poly q;
583 for (const Point3d &x : pts)
584 {
585 q.p.push_back(Point2d(x * du, x * dv));
586 q.z.push_back(x * dw);
587 q.box.Add(q.p.back());
588 }
589 return q;
590 }
591
592 // Linking number over Z2: the parity of the crossings where a passes over b.
593 // -1 on a degenerate projection.
594 static int Link(const Poly &a, const Poly &b)
595 {
596 // Inclusive, unlike Box2::Collide: a segment along a projection axis on the border of
597 // the overlap can still cross.
598 auto overlap = [](const Box2d &x, const Box2d &y) {
599 return x.min.X() <= y.max.X() && y.min.X() <= x.max.X() && x.min.Y() <= y.max.Y() && y.min.Y() <= x.max.Y(); };
600 if (!overlap(a.box, b.box)) return 0;
601 Box2d ov = a.box; ov.Intersect(b.box);
602 auto near = [&](const Poly &q) {
603 std::vector<size_t> s;
604 for (size_t i = 0; i < q.p.size(); ++i)
605 {
606 Box2d sb; sb.Add(q.p[i]); sb.Add(q.p[(i + 1) % q.p.size()]);
607 if (overlap(sb, ov)) s.push_back(i);
608 }
609 return s;
610 };
611 const std::vector<size_t> sa = near(a), sb = near(b);
612 int count = 0;
613 for (size_t i : sa)
614 for (size_t j : sb)
615 {
616 const size_t i1 = (i + 1) % a.p.size(), j1 = (j + 1) % b.p.size();
617 using planar_polygon_detail::Orient2D;
618 const long double o1 = Orient2D(a.p[i], a.p[i1], b.p[j]), o2 = Orient2D(a.p[i], a.p[i1], b.p[j1]);
619 if ((o1 > 0 && o2 > 0) || (o1 < 0 && o2 < 0)) continue;
620 const long double o3 = Orient2D(b.p[j], b.p[j1], a.p[i]), o4 = Orient2D(b.p[j], b.p[j1], a.p[i1]);
621 if ((o3 > 0 && o4 > 0) || (o3 < 0 && o4 < 0)) continue;
622 if (o1 == 0 || o2 == 0 || o3 == 0 || o4 == 0) return -1;
623 const double s = double(o3 / (o3 - o4)), t = double(o1 / (o1 - o2));
624 const double za = a.z[i] + s * (a.z[i1] - a.z[i]), zb = b.z[j] + t * (b.z[j1] - b.z[j]);
625 if (za == zb) return -1;
626 if (za > zb) ++count;
627 }
628 return count % 2;
629 }
630
631 // Steps 1-5 of the algorithm for one height direction; false if it is degenerate.
632 bool InitialBases(math::MarsenneTwisterRNG &rnd)
633 {
634 const Point3d d = math::GeneratePointOnUnitSphereUniform<double>(rnd);
635 tri::UpdateQuality<WMesh>::VertexFromPlane(w, Plane3d(0, d));
636 rg.Compute(w, graph);
637 Setup();
638 order.assign(w.vert.size(), -1);
639 int nv = 0;
640 for (size_t i = 0; i < w.vert.size(); ++i)
641 {
642 order[rg.rank[i]] = int(i);
643 if (!vertFaces[i].empty()) ++nv;
644 }
645 genus = (2 - nv + int(rg.edgeVert.size()) - w.fn) / 2;
646 if (genus == 0) return true;
647
648 // Maximum spanning tree of the Reeb graph, each arc weighted by its lower node: every
649 // other arc closes a loop whose lowest point is its lower node, a splitting saddle.
650 const int nn = int(rg.nodeVert.size()), na = int(graph.edge.size());
651 std::vector<int> byLow(na);
652 std::iota(byLow.begin(), byLow.end(), 0);
653 std::sort(byLow.begin(), byLow.end(), [&](int a, int b) {
654 return rg.Below(rg.nodeVert[Lo(b)], rg.nodeVert[Lo(a)]); });
655 std::vector<int> node(nn);
656 DisjointSet<int> ds;
657 for (int &x : node) ds.MakeSet(&x);
658 std::vector<std::vector<std::pair<int,int> > > tree(nn);
659 std::vector<int> cut;
660 for (int a : byLow)
661 {
662 const int lo = Lo(a), hi = Hi(a);
663 if (ds.FindSet(&node[lo]) == ds.FindSet(&node[hi])) { cut.push_back(a); continue; }
664 ds.Union(&node[lo], &node[hi]);
665 tree[lo].push_back(std::make_pair(hi, a));
666 tree[hi].push_back(std::make_pair(lo, a));
667 }
668 if (int(cut.size()) != genus) return false;
669
670 Point3d du, dv;
671 Frame(d, du, dv);
672 std::vector<Loop> arcPath(na);
673 auto arcLoop = [&](int a) -> const Loop & { if (arcPath[a].empty()) arcPath[a] = ArcPath(a); return arcPath[a]; };
674 std::vector<Loop> loops(2 * genus); // the Reeb graph loops, then their duals
675 std::vector<double> side(2 * genus); // -1 to push a loop inside, +1 outside
676 base.clear();
677 for (int k = 0; k < genus; ++k)
678 {
679 // The loop: up the cut arc, then down the tree back to its lower node.
680 const int p = Lo(cut[k]);
681 std::vector<std::pair<int,int> > from(nn, std::make_pair(-1, -1));
682 std::queue<int> q;
683 q.push(p);
684 from[p].first = p;
685 while (!q.empty())
686 {
687 const int x = q.front(); q.pop();
688 for (const std::pair<int,int> &y : tree[x])
689 if (from[y.first].first < 0) { from[y.first] = std::make_pair(x, y.second); q.push(y.first); }
690 }
691 Loop &l = loops[k];
692 if (arcLoop(cut[k]).empty()) return false;
693 Join(l, arcLoop(cut[k]));
694 int last = -1;
695 for (int x = Hi(cut[k]); x != p; x = from[x].first)
696 {
697 last = from[x].second;
698 Loop seg = arcLoop(last);
699 if (seg.empty()) return false;
700 if (Hi(last) == x) std::reverse(seg.begin(), seg.end());
701 Join(l, seg);
702 }
703 l.pop_back();
704 CancelBacktracks(l);
705
706 // Its dual: the contour just above the lowest point on the cut arc. Seen along the
707 // height, a contour not enclosing the other one at the saddle winds counterclockwise
708 // when the region it bounds is inside near it; then the loop is non-trivial inside.
709 const int pv = rg.nodeVert[p], e1 = UpperEdge(pv, cut[k]), e2 = UpperEdge(pv, last);
710 if (e1 < 0 || e2 < 0 || l.empty()) return false;
711 const Contour b1 = Trace(e1, du, dv), b2 = Trace(e2, du, dv);
712 if (b1.edges.count(e2)) return false;
713 const Point2d o(w.vert[pv].P() * du, w.vert[pv].P() * dv);
714 auto far = [&](const Contour &c) {
715 size_t best = 0;
716 for (size_t i = 0; i < c.pts.size(); ++i)
717 if (Distance(c.pts[i].point, o) > Distance(c.pts[best].point, o)) best = i;
718 return c.pts[best].point;
719 };
720 const bool b2in1 = planar_polygon_detail::PointInContour(far(b2), b1.pts, 0);
721 const bool inside = planar_polygon_detail::SignedDoubleArea(b2in1 ? b2.pts : b1.pts) > 0;
722 loops[genus + k] = b1.above;
723 CancelBacktracks(loops[genus + k]);
724 if (loops[genus + k].empty()) return false;
725 side[k] = inside ? -1 : 1;
726 side[genus + k] = -side[k];
727 base.push_back(pv);
728 }
729
730 // Linking numbers between the loops and their pushed-off copies, and their inverse:
731 // row k of the inverse combines the loops into one linked only with pushed copy k.
732 const Point3d dw = math::GeneratePointOnUnitSphereUniform<double>(rnd);
733 Point3d pu, pv;
734 Frame(dw, pu, pv);
735 const int n2 = 2 * genus;
736 std::vector<Poly> on, off;
737 for (int k = 0; k < n2; ++k)
738 {
739 std::vector<Point3d> pts;
740 for (int v : loops[k]) pts.push_back(w.vert[v].P());
741 on.push_back(Project(pts, pu, pv, dw));
742 off.push_back(Project(PushOff(loops[k], side[k]), pu, pv, dw));
743 }
744 std::vector<Bits> L(n2, Bits((n2 + 63) / 64, 0));
745 for (int i = 0; i < n2; ++i)
746 for (int j = 0; j < n2; ++j)
747 {
748 const int lk = Link(on[i], off[j]);
749 if (lk < 0) return false;
750 if (lk) Flip(L[i], j);
751 }
752 if (!Invert(L)) return false;
753 // A combination linked with no copy pushed outside bounds inside (Lemma 3.3 of the
754 // paper, whose text swaps the two families): linked with one pushed inside, a handle.
755 chain[0].clear(); chain[1].clear();
756 for (int k = 0; k < n2; ++k)
757 {
758 std::vector<const Loop*> sel;
759 for (int j = 0; j < n2; ++j) if (Bit(L[k], j)) sel.push_back(&loops[j]);
760 chain[side[k] < 0 ? 0 : 1].push_back(Sum(sel));
761 }
762 return int(chain[0].size()) == genus;
763 }
764
765 // ---- Z2 linear algebra ---------------------------------------------------------------
766
767 static bool Bit(const Bits &b, int i) { return (b[i >> 6] >> (i & 63)) & 1; }
768 static void Flip(Bits &b, int i) { b[i >> 6] ^= uint64_t(1) << (i & 63); }
769 static void Xor(Bits &a, const Bits &b) { for (size_t k = 0; k < a.size(); ++k) a[k] ^= b[k]; }
770 static bool Zero(const Bits &b) { for (uint64_t x : b) if (x) return false; return true; }
771 static bool Odd(const Bits &a, const Bits &b)
772 {
773 uint64_t x = 0;
774 for (size_t k = 0; k < a.size(); ++k) x ^= a[k] & b[k];
775 return std::bitset<64>(x).count() % 2 == 1;
776 }
777
778 // Invert a square matrix given by rows; false if it is singular.
779 static bool Invert(std::vector<Bits> &a)
780 {
781 const int n = int(a.size());
782 std::vector<Bits> inv(n, Bits(a[0].size(), 0));
783 for (int i = 0; i < n; ++i) Flip(inv[i], i);
784 for (int c = 0; c < n; ++c)
785 {
786 int r = c;
787 while (r < n && !Bit(a[r], c)) ++r;
788 if (r == n) return false;
789 std::swap(a[r], a[c]); std::swap(inv[r], inv[c]);
790 for (int k = 0; k < n; ++k)
791 if (k != c && Bit(a[k], c)) { Xor(a[k], a[c]); Xor(inv[k], inv[c]); }
792 }
793 a.swap(inv);
794 return true;
795 }
796
797 // Classes inserted so far, reduced: a class is new if it does not reduce to zero.
798 struct Span
799 {
800 std::vector<Bits> rows;
801 std::vector<int> pivot;
802 bool Insert(Bits x)
803 {
804 for (size_t i = 0; i < rows.size(); ++i) if (Bit(x, pivot[i])) Xor(x, rows[i]);
805 size_t k = 0;
806 while (k < x.size() && x[k] == 0) ++k;
807 if (k == x.size()) return false;
808 int b = 0;
809 while (!((x[k] >> b) & 1)) ++b;
810 rows.push_back(x);
811 pivot.push_back(int(64 * k) + b);
812 return true;
813 }
814 };
815
816 // ---- Tightening ----------------------------------------------------------------------
817
818 std::vector<uint64_t> ann; // homology class of each edge, words per edge
819
820 Bits Class(const std::vector<int> &edges) const
821 {
822 Bits x(words, 0);
823 for (int e : edges) for (int k = 0; k < words; ++k) x[k] ^= ann[e * words + k];
824 return x;
825 }
826
827 // Classes of the edges against a cohomology basis from a tree-cotree decomposition: each
828 // of the 2g edges outside both trees, plus the dual path joining its faces in the dual
829 // tree, crosses exactly one loop of the corresponding homology basis.
830 void Annotate()
831 {
832 const int ne = int(rg.edgeVert.size()), nf = int(w.face.size());
833 words = (2 * genus + 63) / 64;
834 ann.assign(size_t(ne) * words, 0);
835 std::vector<int> parent(nf, -2), parentEdge(nf, -1);
836 std::vector<char> dual(ne, 0), primal(ne, 0);
837 std::queue<int> q;
838 parent[0] = -1; q.push(0);
839 while (!q.empty())
840 {
841 const int f = q.front(); q.pop();
842 for (int z = 0; z < 3; ++z)
843 {
844 const int g = int(tri::Index(w, w.face[f].cFFp(z)));
845 if (parent[g] != -2) continue;
846 parent[g] = f; parentEdge[g] = rg.faceEdge[3 * f + z]; dual[parentEdge[g]] = 1;
847 q.push(g);
848 }
849 }
850 std::vector<char> seen(w.vert.size(), 0);
851 std::queue<int> qv;
852 seen[rg.edgeVert[0].first] = 1; qv.push(rg.edgeVert[0].first);
853 while (!qv.empty())
854 {
855 const int v = qv.front(); qv.pop();
856 for (int e : vertEdges[v])
857 if (!dual[e] && !seen[Other(e, v)]) { seen[Other(e, v)] = 1; primal[e] = 1; qv.push(Other(e, v)); }
858 }
859 std::vector<std::vector<int> > edgeFace(ne);
860 for (int f = 0; f < nf; ++f) for (int z = 0; z < 3; ++z) edgeFace[rg.faceEdge[3 * f + z]].push_back(f);
861 int k = 0;
862 for (int e = 0; e < ne; ++e)
863 {
864 if (dual[e] || primal[e]) continue;
865 ann[size_t(e) * words + k / 64] ^= uint64_t(1) << (k % 64);
866 for (int f : edgeFace[e])
867 for (; parent[f] >= 0; f = parent[f])
868 ann[size_t(parentEdge[f]) * words + k / 64] ^= uint64_t(1) << (k % 64);
869 ++k;
870 }
871 assert(k == 2 * genus);
872 }
873
874 // Shortest path tree from r: distances and the edge to the parent, of the vertices within
875 // \a bound of r; the others are left at the maximum distance.
876 void Dijkstra(int r, std::vector<double> &dist, std::vector<int> &parentEdge, std::vector<int> &settled,
877 double bound = std::numeric_limits<double>::max()) const
878 {
879 Dijkstra(std::vector<int>(1, r), dist, parentEdge, settled, bound);
880 }
881 void Dijkstra(const std::vector<int> &sources, std::vector<double> &dist, std::vector<int> &parentEdge,
882 std::vector<int> &settled, double bound = std::numeric_limits<double>::max()) const
883 {
884 dist.assign(w.vert.size(), std::numeric_limits<double>::max());
885 parentEdge.assign(w.vert.size(), -1);
886 settled.clear();
887 typedef std::pair<double,int> QE;
888 std::priority_queue<QE, std::vector<QE>, std::greater<QE> > q;
889 std::vector<int> reached;
890 for (int r : sources) { dist[r] = 0; q.push(QE(0, r)); }
891 while (!q.empty())
892 {
893 const QE t = q.top(); q.pop();
894 if (t.first > dist[t.second]) continue;
895 if (t.first > bound)
896 {
897 for (int v : reached) if (dist[v] > bound) { dist[v] = std::numeric_limits<double>::max(); parentEdge[v] = -1; }
898 return;
899 }
900 settled.push_back(t.second);
901 for (int e : vertEdges[t.second])
902 {
903 const int u = Other(e, t.second);
904 if (t.first + edgeLen[e] < dist[u]) { dist[u] = t.first + edgeLen[e]; parentEdge[u] = e; q.push(QE(dist[u], u)); reached.push_back(u); }
905 }
906 }
907 }
908
909 // A basis element: a canonical loop (edge plus the tree paths of its ends to a root)
910 // or an initial loop, with its length and class.
911 struct Elem { double len; Bits a; int root, edge; std::vector<Loop> loops; };
912
913 bool InFamily(const Bits &x, const std::vector<Bits> &masks) const
914 {
915 for (const Bits &m : masks) if (Odd(x, m)) return false;
916 return true;
917 }
918
919 // Shortest canonical loop of every class of each family, over the tree from r. Optionally
920 // only the loops shorter than \a bound (the tree then stops at half of it), only those of
921 // class \a only, with their paths built, and the distances from r returned.
922 void Canonical(int r, const std::vector<Bits> masks[2], std::map<Bits, Elem> best[2],
923 double bound = std::numeric_limits<double>::max(), const Bits *only = nullptr,
924 bool build = false, std::vector<double> *distances = nullptr) const
925 {
926 std::vector<double> dist;
927 std::vector<int> par, settled;
928 Dijkstra(r, dist, par, settled, bound == std::numeric_limits<double>::max() ? bound : bound / 2);
929 std::vector<uint64_t> A(w.vert.size() * words, 0);
930 for (int v : settled)
931 if (v != r)
932 for (int k = 0; k < words; ++k)
933 A[size_t(v) * words + k] = A[size_t(Other(par[v], v)) * words + k] ^ ann[size_t(par[v]) * words + k];
934 Bits x(words);
935 for (size_t e = 0; e < rg.edgeVert.size(); ++e)
936 {
937 const int u = rg.edgeVert[e].first, v = rg.edgeVert[e].second;
938 if (par[u] == int(e) || par[v] == int(e) || dist[u] == std::numeric_limits<double>::max()
939 || dist[v] == std::numeric_limits<double>::max() || dist[u] + dist[v] + edgeLen[e] >= bound) continue;
940 for (int k = 0; k < words; ++k) x[k] = A[size_t(u) * words + k] ^ A[size_t(v) * words + k] ^ ann[e * words + k];
941 if (Zero(x) || (only && x != *only)) continue;
942 for (int t = 0; t < 2; ++t)
943 if (InFamily(x, masks[t]))
944 {
945 const Elem c{dist[u] + dist[v] + edgeLen[e], x, r, int(e), std::vector<Loop>()};
946 typename std::map<Bits, Elem>::iterator it = best[t].find(x);
947 if (it == best[t].end()) best[t].insert(std::make_pair(x, c));
948 else if (c.len < it->second.len) it->second = c;
949 }
950 }
951 if (build)
952 for (int t = 0; t < 2; ++t)
953 for (auto &kv : best[t])
954 if (kv.second.root == r && kv.second.loops.empty()) kv.second.loops.push_back(TreeLoop(r, kv.second.edge, par));
955 if (distances) distances->swap(dist);
956 }
957
958 // The loop made of edge e and the paths of its ends to r in the tree given by par.
959 Loop TreeLoop(int r, int e, const std::vector<int> &par) const
960 {
961 Loop up, down;
962 for (int x = rg.edgeVert[e].first; ; x = Other(par[x], x)) { up.push_back(x); if (x == r) break; }
963 for (int x = rg.edgeVert[e].second; x != r; x = Other(par[x], x)) down.push_back(x);
964 Loop l(up.rbegin(), up.rend());
965 l.insert(l.end(), down.begin(), down.end());
966 CancelBacktracks(l);
967 return l;
968 }
969
970 // The classes of the handle family (t = 0) and of the tunnel family (t = 1) are those
971 // whose coordinates on the other family's initial loops vanish: a mask per such coordinate.
972 void FamilyMasks(std::vector<Bits> masks[2]) const
973 {
974 std::vector<Bits> M;
975 for (int t = 0; t < 2; ++t) for (const std::vector<int> &c : chain[t]) M.push_back(Class(c));
976 if (!Invert(M)) throw std::logic_error("HandleTunnelLoops: the initial loops are not a homology basis.");
977 for (int t = 0; t < 2; ++t)
978 for (int j = (1 - t) * genus; j < (2 - t) * genus; ++j)
979 {
980 Bits col(words, 0);
981 for (int i = 0; i < 2 * genus; ++i) if (Bit(M[i], j)) Flip(col, i);
982 masks[t].push_back(col);
983 }
984 }
985
986 // Both families grow from the same base points: tunnel loops run through the handles
987 // and handle loops around the tunnels, so each family seeds the other.
988 void Tighten(int maxIter, int patience, math::MarsenneTwisterRNG &rnd, std::vector<Loop> out[2])
989 {
990 std::vector<Bits> masks[2];
991 FamilyMasks(masks);
992 std::vector<Elem> cur[2];
993 std::map<Bits, Elem> best[2];
994 double total[2];
995 for (int t = 0; t < 2; ++t)
996 {
997 for (int i = 0; i < genus; ++i)
998 {
999 double len = 0;
1000 for (int e : chain[t][i]) len += edgeLen[e];
1001 cur[t].push_back(Elem{len, Class(chain[t][i]), -1, -1, ChainLoops(chain[t][i])});
1002 }
1003 total[t] = std::numeric_limits<double>::max();
1004 }
1005 std::set<int> done;
1006 std::vector<int> roots = base;
1007 for (int it = 0, stall = 0; it < maxIter && stall < patience; ++it)
1008 {
1009 for (int r : roots) if (done.insert(r).second) Canonical(r, masks, best);
1010 bool shorter = false;
1011 for (int t = 0; t < 2; ++t)
1012 {
1013 std::vector<const Elem*> cand;
1014 for (const Elem &e : cur[t]) cand.push_back(&e);
1015 for (typename std::map<Bits, Elem>::const_iterator i = best[t].begin(); i != best[t].end(); ++i) cand.push_back(&i->second);
1016 std::stable_sort(cand.begin(), cand.end(), [](const Elem *a, const Elem *b) { return a->len < b->len; });
1017 Span span;
1018 std::vector<Elem> next;
1019 for (const Elem *c : cand)
1020 if (int(next.size()) < genus && span.Insert(c->a)) next.push_back(*c);
1021 Materialize(next);
1022 double sum = 0;
1023 for (const Elem &e : next) sum += e.len;
1024 cur[t].swap(next);
1025 if (sum < total[t] * (1 - 1e-9)) shorter = true;
1026 total[t] = std::min(total[t], sum);
1027 }
1028 stall = shorter ? 0 : stall + 1;
1029 roots.clear();
1030 for (int t = 0; t < 2; ++t)
1031 for (const Elem &e : cur[t])
1032 for (const Loop &l : e.loops)
1033 for (int k = 0; k < 2; ++k) roots.push_back(l[rnd.generate(unsigned(l.size()))]);
1034 }
1035 for (int t = 0; t < 2; ++t)
1036 for (const Elem &e : cur[t]) out[t].insert(out[t].end(), e.loops.begin(), e.loops.end());
1037 }
1038
1039 // Loops of one class sharing more than \a overlap of the vertices of the smaller are one:
1040 // keep the shortest of each such group, shortest first.
1041 static void MergeDuplicates(std::vector<Elem> &el, double overlap)
1042 {
1043 std::stable_sort(el.begin(), el.end(), [](const Elem &a, const Elem &b) { return a.len < b.len; });
1044 std::vector<Elem> kept;
1045 std::vector<std::vector<int> > keptVerts;
1046 for (Elem &e : el)
1047 {
1048 std::vector<int> vs(e.loops[0].begin(), e.loops[0].end());
1049 std::sort(vs.begin(), vs.end());
1050 bool duplicate = false;
1051 for (size_t k = 0; k < kept.size() && !duplicate; ++k)
1052 {
1053 if (kept[k].a != e.a) continue;
1054 std::vector<int> common;
1055 std::set_intersection(vs.begin(), vs.end(), keptVerts[k].begin(), keptVerts[k].end(), std::back_inserter(common));
1056 duplicate = common.size() > overlap * double(std::min(vs.size(), keptVerts[k].size()));
1057 }
1058 if (duplicate) continue;
1059 keptVerts.push_back(vs);
1060 kept.push_back(e);
1061 }
1062 el.swap(kept);
1063 }
1064
1065 // Keep the loops (sorted shortest first) that are local minima of length among their
1066 // neighbours -- loops of their class coming within \a radius of them, about twice the root
1067 // spacing, so that candidates from neighbouring roots meet -- and significant ones: the
1068 // merge tree of the candidates, added shortest first, joins the basins of two minima at
1069 // the shortest loop connecting them, and the higher minimum is kept only if that loop is
1070 // longer by at least \a persistence of it. Two necks of one handle are kept, with the wider
1071 // stretch between them; a tube of constant section, or a torus, gives one loop, not one per
1072 // cross-section. (Re-rooting a loop at its own vertices cannot slide it along a tube, so the
1073 // candidates alone do not tell a neck from any other cross-section.)
1074 void KeepMinima(std::vector<Elem> &el, double radius, double persistence) const
1075 {
1076 const size_t n = el.size();
1077 std::vector<std::vector<size_t> > near(n);
1078 std::vector<double> dist;
1079 std::vector<int> par, settled;
1080 for (size_t i = 0; i < n; ++i)
1081 {
1082 Dijkstra(el[i].loops[0], dist, par, settled, radius);
1083 for (size_t j = i + 1; j < n; ++j)
1084 if (el[j].a == el[i].a)
1085 for (int v : el[j].loops[0])
1086 if (dist[v] != std::numeric_limits<double>::max()) { near[i].push_back(j); near[j].push_back(i); break; }
1087 }
1088 std::vector<int> id(n), lowest(n); // a basin's minimum, stored at its representative
1089 std::vector<char> active(n, 0), kept(n, 0);
1090 DisjointSet<int> basin;
1091 for (size_t i = 0; i < n; ++i)
1092 {
1093 id[i] = int(i);
1094 basin.MakeSet(&id[i]);
1095 active[i] = 1;
1096 std::set<int *> roots;
1097 for (size_t j : near[i]) if (active[j] && j != i) roots.insert(basin.FindSet(&id[j]));
1098 if (roots.empty()) { lowest[i] = int(i); kept[i] = 1; continue; } // a new minimum
1099 // The deepest basin goes on; the others end here, kept only if this loop rises
1100 // clearly above their minimum.
1101 int *deepest = *std::min_element(roots.begin(), roots.end(), [&](int *x, int *y) { return lowest[*x] < lowest[*y]; });
1102 const int keep = lowest[*deepest];
1103 for (int *r : roots)
1104 if (r != deepest && el[i].len < el[size_t(lowest[*r])].len * (1 + persistence)) kept[size_t(lowest[*r])] = 0;
1105 for (int *r : roots) basin.Union(r, &id[i]);
1106 lowest[*basin.FindSet(&id[i])] = keep;
1107 }
1108 std::vector<Elem> out;
1109 for (size_t i = 0; i < n; ++i) if (kept[i]) out.push_back(el[i]);
1110 el.swap(out);
1111 }
1112
1113 // Locally shortest loops of both families, from roots spread over the surface.
1114 void LocalMinima(const Param &par, math::MarsenneTwisterRNG &rnd, std::vector<Loop> out[2])
1115 {
1116 std::vector<Bits> masks[2];
1117 FamilyMasks(masks);
1118 std::vector<Elem> cand[2];
1119 // Farthest point sampling: each root's tree gives both its candidates and the distances
1120 // that choose the next root, away from the fans that close the holes.
1121 std::vector<double> nearest(w.vert.size(), std::numeric_limits<double>::max()), dist;
1122 double spacing = 0; // no vertex is farther than this from a root
1123 int r = int(rnd.generate(unsigned(firstFan)));
1124 for (int k = 0; k < par.samples; ++k)
1125 {
1126 std::map<Bits, Elem> local[2];
1127 Canonical(r, masks, local, std::numeric_limits<double>::max(), nullptr, true, &dist);
1128 for (int t = 0; t < 2; ++t) for (auto &kv : local[t]) cand[t].push_back(kv.second);
1129 int far = -1;
1130 for (int v = 0; v < firstFan; ++v)
1131 {
1132 nearest[v] = std::min(nearest[v], dist[v]);
1133 if (far < 0 || nearest[v] > nearest[far]) far = v;
1134 }
1135 if (far < 0 || !(nearest[far] > 0)) break;
1136 spacing = nearest[far];
1137 r = far;
1138 }
1139 for (int t = 0; t < 2; ++t)
1140 {
1141 MergeDuplicates(cand[t], par.overlap);
1142 // Each tightened on its own, keeping its class: re-rooted at a vertex of the loop, a
1143 // shorter loop of the class through it, if there is one, lies within half its length.
1144 for (Elem &e : cand[t])
1145 for (int it = 0, failed = 0; it < par.maxIter && failed < std::max(1, par.patience); ++it)
1146 {
1147 const Loop &l = e.loops[0];
1148 const int root = (failed == 0) ? l[l.size() / 2] : l[rnd.generate(unsigned(l.size()))];
1149 std::map<Bits, Elem> local[2];
1150 Canonical(root, masks, local, e.len * (1 - 1e-9), &e.a, true);
1151 const typename std::map<Bits, Elem>::iterator f = local[t].find(e.a);
1152 if (f == local[t].end()) { ++failed; continue; }
1153 e = f->second;
1154 failed = 0;
1155 }
1156 MergeDuplicates(cand[t], par.overlap);
1157 KeepMinima(cand[t], 2 * spacing, par.persistence);
1158 if (par.maxLoops > 0 && int(cand[t].size()) > par.maxLoops) cand[t].resize(size_t(par.maxLoops));
1159 for (const Elem &e : cand[t]) out[t].push_back(e.loops[0]);
1160 }
1161 }
1162
1163 // Build the paths of the canonical loops, one shortest path tree per root.
1164 void Materialize(std::vector<Elem> &el) const
1165 {
1166 std::map<int, std::vector<Elem*> > byRoot;
1167 for (Elem &e : el) if (e.loops.empty()) byRoot[e.root].push_back(&e);
1168 std::vector<double> dist;
1169 std::vector<int> par, settled;
1170 for (typename std::map<int, std::vector<Elem*> >::iterator i = byRoot.begin(); i != byRoot.end(); ++i)
1171 {
1172 Dijkstra(i->first, dist, par, settled);
1173 for (Elem *e : i->second) e->loops.push_back(TreeLoop(i->first, e->edge, par));
1174 }
1175 }
1176};
1177
1178} // end namespace tri
1179} // end namespace vcg
1180
1181#endif // VCG_HANDLE_TUNNEL_LOOPS_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
static FaceIterator AddFaces(MeshType &m, size_t n)
Function to add n faces to the mesh. First wrapper, with no parameters.
Definition: allocate.h:621
static void MeshCopy(MeshLeft &ml, ConstMeshRight &mr, bool selected=false, const bool adjFlag=false)
Copy the second mesh over the first one. The first mesh is destroyed. If requested only the selected ...
Definition: append.h:601
Class of static functions to clean//restore meshs.
Definition: clean.h:165
static void FlipMesh(MeshType &m, bool selected=false)
Flip the orientation of the whole mesh flipping all the faces (by swapping the first two vertices)
Definition: clean.h:1581
Handle and tunnel loops of an orientable surface.
Definition: handle_tunnel_loops.h:142
std::vector< Loop > handles
the handle loops, around the handles
Definition: handle_tunnel_loops.h:162
static void LoopsToEdgeMesh(const MeshType &m, const std::vector< Loop > &loops, EdgeMeshType &em)
Append loops to the edge mesh em, one closed polyline each.
Definition: handle_tunnel_loops.h:224
void Compute(MeshType &m, const Param &par=Param())
Compute genus, handles and tunnels of m.
Definition: handle_tunnel_loops.h:175
std::vector< int > Loop
Definition: handle_tunnel_loops.h:146
int genus
genus of the surface, with its holes closed
Definition: handle_tunnel_loops.h:164
std::vector< Loop > tunnels
the tunnel loops, around the tunnels
Definition: handle_tunnel_loops.h:163
Reeb graph of the vertex quality of a triangle mesh.
Definition: reeb_graph.h:87
void Compute(MeshType &m, EdgeMeshType &graph)
Compute the Reeb graph of the vertex quality of m into graph.
Definition: reeb_graph.h:113
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
static void FaceFace(MeshType &m)
Update the Face-Face topological relation by allowing to retrieve for each face what other faces shar...
Definition: topology.h:395
bool IsBorder(FaceType const &f, const int j)
Definition: topology.h:55
Definition: color4.h:30
Reeb graph of a scalar function on a triangle mesh: tri::ReebGraph.
Options of Compute(); the defaults suit most meshes.
Definition: handle_tunnel_loops.h:150
double persistence
local minima: a loop is kept only if the loops joining it to a shorter one of its class are longer by...
Definition: handle_tunnel_loops.h:158
int maxLoops
local minima: at most this many loops per family, the shortest; 0 keeps all
Definition: handle_tunnel_loops.h:159
int maxIter
tightening rounds; 0 keeps the loops found on the Reeb graph
Definition: handle_tunnel_loops.h:152
double overlap
local minima: two loops of one class sharing more of their vertices are one
Definition: handle_tunnel_loops.h:157
unsigned int seed
seeds the height direction and the projection directions
Definition: handle_tunnel_loops.h:151
int samples
local minima: root vertices spread over the surface to start from
Definition: handle_tunnel_loops.h:156
int attempts
height directions tried before giving up on degenerate ones
Definition: handle_tunnel_loops.h:154
bool localMinima
instead of a basis, many locally shortest loops (see Compute())
Definition: handle_tunnel_loops.h:155
int patience
stop tightening after this many rounds without a shorter basis
Definition: handle_tunnel_loops.h:153