23#ifndef VCG_HANDLE_TUNNEL_LOOPS_H
24#define VCG_HANDLE_TUNNEL_LOOPS_H
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>
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> > {};
140template <
class MeshType>
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);
186 throw vcg::MissingPreconditionException(
"HandleTunnelLoops: the mesh is not connected.");
187 bool oriented, orientable;
190 throw vcg::MissingPreconditionException(
"HandleTunnelLoops: the mesh is not orientable.");
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;
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);
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])
211 Loop o = ToInput(l, toM);
223 template <
class EdgeMeshType>
224 static void LoopsToEdgeMesh(
const MeshType &m,
const std::vector<Loop> &loops, EdgeMeshType &em)
226 for (
const Loop &l : loops)
228 const size_t base = em.vert.size();
231 for (
size_t k = 0; k < l.size(); ++k)
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()];
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;
249 handle_tunnel_detail::Graph graph;
251 std::vector<Loop> holes;
252 std::vector<int> order;
253 std::vector<Point3d> faceNrm;
254 std::vector<double> lift;
255 std::vector<std::vector<int> > vertEdges, vertFaces;
256 std::vector<double> edgeLen;
257 std::vector<std::vector<int> > chain[2];
258 std::vector<int> base;
266 firstFan = int(w.vert.size());
268 std::map<int,int> next;
269 for (WFace &f : w.face)
270 for (
int z = 0; z < 3; ++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())
277 for (
int v = next.begin()->first; next.count(v); )
280 const int u = next[v];
286 if (holes.empty())
return;
289 for (
size_t k = 0; k < holes.size(); ++k)
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();
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)
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];
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))); }
311 int Other(
int e,
int v)
const {
return rg.
edgeVert[e].first ^ rg.
edgeVert[e].second ^ v; }
313 int EdgeOf(
int v,
int u)
const
315 for (
int e : vertEdges[v])
if (Other(e, v) == u)
return e;
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)
328 for (
int z = 0; z < 3; ++z) vertFaces[tri::Index(w, f.V(z))].push_back(
int(tri::Index(w, f)));
330 const Point3d n = (f.P(1) - f.P(0)) ^ (f.P(2) - f.P(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);
336 vertEdges.assign(nv, std::vector<int>());
339 for (
size_t e = 0; e < rg.
edgeVert.size(); ++e)
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());
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;
355 static void CancelBacktracks(
Loop &l)
360 if (!s.empty() && s.back() == v)
continue;
361 if (s.size() >= 2 && s[s.size() - 2] == v) { s.pop_back();
continue; }
365 while (s.size() - b >= 3 && (s[b] == s.back() || s[b + 1] == s.back()))
367 if (s[b] == s.back()) s.pop_back();
368 else { s.pop_back(); ++b; }
370 l.assign(s.begin() + b, s.end());
371 if (l.size() < 3) l.clear();
374 static void Join(
Loop &l,
const Loop &seg)
376 l.insert(l.end(), seg.begin() + (!l.empty() && l.back() == seg.front() ? 1 : 0), seg.end());
379 std::vector<int> Edges(
const Loop &l)
const
382 for (
size_t i = 0; i < l.size(); ++i) e.push_back(EdgeOf(l[i], l[(i + 1) % l.size()]));
387 std::vector<int> Sum(
const std::vector<const Loop*> &loops)
const
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(); )
396 while (j < all.size() && all[j] == all[i]) ++j;
397 if ((j - i) % 2) odd.push_back(all[i]);
405 std::vector<Loop> ChainLoops(
const std::vector<int> &c)
const
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())
414 while (!stack.empty())
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()));
424 if (!l.empty() && !Zero(Class(Edges(l)))) loops.push_back(l);
430 Loop ToInput(
const Loop &l,
const std::vector<int> &toM)
const
433 for (
size_t i = 0; i < l.size(); ++i)
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]);
444 for (
int &v : o) v = toM[v];
452 Loop ArcPath(
int a)
const
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})
461 const int e = rg.
faceEdge[3 * f + s];
466 std::map<int,int> from;
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})
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);
476 while (!q.empty() && !reaches(q.front()))
478 const int f = q.front(); q.pop();
479 for (
int z = 0; z < 3; ++z)
481 const WFace &F = w.face[f];
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))));
486 if (q.empty())
return Loop();
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());
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
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; };
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; }
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())});
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;
524 }
while (rg.
faceEdge[3 * f + z] != e0);
528 int UpperEdge(
int v,
int a)
const
530 for (
int e : vertEdges[v])
if (rg.
edgeVert[e].first == v && rg.
edgePath[e].front() == a)
return e;
534 static void Frame(
const Point3d &d, Point3d &u, Point3d &v)
536 u = d ^ (std::abs(d[0]) < 0.6 ? Point3d(1, 0, 0) : Point3d(0, 1, 0));
546 std::vector<Point3d> PushOff(
const Loop &l,
double side)
const
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]));
556 for (
size_t i = 0; i < l.size(); ++i)
558 const int u = l[(i + l.size() - 1) % l.size()], v = l[i], x = l[(i + 1) % l.size()];
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));
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;
569 if (
int(tri::Index(w, F.cV1(zn))) == x)
break;
570 out.push_back(overEdge(f, zn));
572 f = int(tri::Index(w, F.cFFp(zn)));
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)
583 for (
const Point3d &x : pts)
585 q.p.push_back(Point2d(x * du, x * dv));
586 q.z.push_back(x * dw);
587 q.box.Add(q.p.back());
594 static int Link(
const Poly &a,
const Poly &b)
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)
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);
611 const std::vector<size_t> sa = near(a), sb = near(b);
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;
632 bool InitialBases(math::MarsenneTwisterRNG &rnd)
634 const Point3d d = math::GeneratePointOnUnitSphereUniform<double>(rnd);
635 tri::UpdateQuality<WMesh>::VertexFromPlane(w, Plane3d(0, d));
638 order.assign(w.vert.size(), -1);
640 for (
size_t i = 0; i < w.vert.size(); ++i)
642 order[rg.
rank[i]] = int(i);
643 if (!vertFaces[i].empty()) ++nv;
646 if (
genus == 0)
return true;
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);
657 for (
int &x : node) ds.MakeSet(&x);
658 std::vector<std::vector<std::pair<int,int> > > tree(nn);
659 std::vector<int> cut;
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));
668 if (
int(cut.size()) !=
genus)
return false;
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);
675 std::vector<double> side(2 *
genus);
677 for (
int k = 0; k <
genus; ++k)
680 const int p = Lo(cut[k]);
681 std::vector<std::pair<int,int> > from(nn, std::make_pair(-1, -1));
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); }
692 if (arcLoop(cut[k]).empty())
return false;
693 Join(l, arcLoop(cut[k]));
695 for (
int x = Hi(cut[k]); x != p; x = from[x].first)
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());
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) {
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;
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];
732 const Point3d dw = math::GeneratePointOnUnitSphereUniform<double>(rnd);
735 const int n2 = 2 *
genus;
736 std::vector<Poly> on, off;
737 for (
int k = 0; k < n2; ++k)
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));
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)
748 const int lk = Link(on[i], off[j]);
749 if (lk < 0)
return false;
750 if (lk) Flip(L[i], j);
752 if (!Invert(L))
return false;
755 chain[0].clear(); chain[1].clear();
756 for (
int k = 0; k < n2; ++k)
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));
762 return int(chain[0].size()) ==
genus;
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)
774 for (
size_t k = 0; k < a.size(); ++k) x ^= a[k] & b[k];
775 return std::bitset<64>(x).count() % 2 == 1;
779 static bool Invert(std::vector<Bits> &a)
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)
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]); }
800 std::vector<Bits> rows;
801 std::vector<int> pivot;
804 for (
size_t i = 0; i < rows.size(); ++i)
if (Bit(x, pivot[i])) Xor(x, rows[i]);
806 while (k < x.size() && x[k] == 0) ++k;
807 if (k == x.size())
return false;
809 while (!((x[k] >> b) & 1)) ++b;
811 pivot.push_back(
int(64 * k) + b);
818 std::vector<uint64_t> ann;
820 Bits Class(
const std::vector<int> &edges)
const
823 for (
int e : edges)
for (
int k = 0; k < words; ++k) x[k] ^= ann[e * words + k];
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);
838 parent[0] = -1; q.push(0);
841 const int f = q.front(); q.pop();
842 for (
int z = 0; z < 3; ++z)
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;
850 std::vector<char> seen(w.vert.size(), 0);
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)); }
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);
862 for (
int e = 0; e < ne; ++e)
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);
871 assert(k == 2 *
genus);
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
879 Dijkstra(std::vector<int>(1, r), dist, parentEdge, settled, bound);
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
884 dist.assign(w.vert.size(), std::numeric_limits<double>::max());
885 parentEdge.assign(w.vert.size(), -1);
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)); }
893 const QE t = q.top(); q.pop();
894 if (t.first > dist[t.second])
continue;
897 for (
int v : reached)
if (dist[v] > bound) { dist[v] = std::numeric_limits<double>::max(); parentEdge[v] = -1; }
900 settled.push_back(t.second);
901 for (
int e : vertEdges[t.second])
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); }
911 struct Elem {
double len; Bits a;
int root, edge; std::vector<Loop> loops; };
913 bool InFamily(
const Bits &x,
const std::vector<Bits> &masks)
const
915 for (
const Bits &m : masks)
if (Odd(x, m))
return false;
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
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)
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];
935 for (
size_t e = 0; e < rg.
edgeVert.size(); ++e)
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]))
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;
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);
959 Loop TreeLoop(
int r,
int e,
const std::vector<int> &par)
const
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());
972 void FamilyMasks(std::vector<Bits> masks[2])
const
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)
981 for (
int i = 0; i < 2 *
genus; ++i)
if (Bit(M[i], j)) Flip(col, i);
982 masks[t].push_back(col);
988 void Tighten(
int maxIter,
int patience, math::MarsenneTwisterRNG &rnd, std::vector<Loop> out[2])
990 std::vector<Bits> masks[2];
992 std::vector<Elem> cur[2];
993 std::map<Bits, Elem> best[2];
995 for (
int t = 0; t < 2; ++t)
997 for (
int i = 0; i <
genus; ++i)
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])});
1003 total[t] = std::numeric_limits<double>::max();
1006 std::vector<int> roots = base;
1007 for (
int it = 0, stall = 0; it < maxIter && stall < patience; ++it)
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)
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; });
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);
1023 for (
const Elem &e : next) sum += e.len;
1025 if (sum < total[t] * (1 - 1e-9)) shorter =
true;
1026 total[t] = std::min(total[t], sum);
1028 stall = shorter ? 0 : stall + 1;
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()))]);
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());
1041 static void MergeDuplicates(std::vector<Elem> &el,
double overlap)
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;
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)
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()));
1058 if (duplicate)
continue;
1059 keptVerts.push_back(vs);
1074 void KeepMinima(std::vector<Elem> &el,
double radius,
double persistence)
const
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)
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; }
1088 std::vector<int> id(n), lowest(n);
1089 std::vector<char> active(n, 0), kept(n, 0);
1090 DisjointSet<int> basin;
1091 for (
size_t i = 0; i < n; ++i)
1094 basin.MakeSet(&
id[i]);
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; }
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;
1108 std::vector<Elem> out;
1109 for (
size_t i = 0; i < n; ++i)
if (kept[i]) out.push_back(el[i]);
1114 void LocalMinima(
const Param &par, math::MarsenneTwisterRNG &rnd, std::vector<Loop> out[2])
1116 std::vector<Bits> masks[2];
1118 std::vector<Elem> cand[2];
1121 std::vector<double> nearest(w.vert.size(), std::numeric_limits<double>::max()), dist;
1123 int r = int(rnd.generate(
unsigned(firstFan)));
1124 for (
int k = 0; k < par.samples; ++k)
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);
1130 for (
int v = 0; v < firstFan; ++v)
1132 nearest[v] = std::min(nearest[v], dist[v]);
1133 if (far < 0 || nearest[v] > nearest[far]) far = v;
1135 if (far < 0 || !(nearest[far] > 0))
break;
1136 spacing = nearest[far];
1139 for (
int t = 0; t < 2; ++t)
1141 MergeDuplicates(cand[t], par.overlap);
1144 for (Elem &e : cand[t])
1145 for (
int it = 0, failed = 0; it < par.maxIter && failed < std::max(1, par.patience); ++it)
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; }
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]);
1164 void Materialize(std::vector<Elem> &el)
const
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)
1172 Dijkstra(i->first, dist, par, settled);
1173 for (Elem *e : i->second) e->loops.push_back(TreeLoop(i->first, e->edge, par));
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
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