TTK
Loading...
Searching...
No Matches
MergeTreeTemplate.h
Go to the documentation of this file.
1
20
21#pragma once
22
23#include "MergeTree.h"
24
25namespace ttk {
26 namespace cf {
27 // Init
28 // {
29
30 template <typename scalarType>
32 const auto &nbVertices = scalars_->size;
33
34 if(scalars_->sortedVertices.size() != static_cast<size_t>(nbVertices)) {
35 scalars_->sortedVertices.resize(nbVertices);
36 }
37
38#ifdef TTK_ENABLE_OPENMP
39#pragma omp parallel for
40#endif
41 for(SimplexId i = 0; i < nbVertices; i++) {
42 scalars_->sortedVertices[scalars_->sosOffsets[i]] = i;
43 }
44 }
45 // }
46
47 // Process
48 // {
49
50 // Simplify
51
52 template <typename scalarType>
54 const SimplexId &posSeed0,
55 const SimplexId &posSeed1,
56 std::list<std::vector<std::pair<SimplexId, bool>>> &storage) {
57
58 // if null threshold, leave
59 if(!params_->simplifyThreshold) {
60 return 0;
61 }
62
63 const bool DEBUG = false;
64
65 // -----------------
66 // Persistence pairs
67 // -----------------
68 // {
69
70 std::vector<std::tuple<SimplexId, SimplexId, scalarType, bool>> pairs;
71 computePersistencePairs<scalarType>(pairs);
72
73 if(DEBUG) {
74 std::cout << "pairs : ( threshold : " << params_->simplifyThreshold
75 << " )" << std::endl;
76 for(const auto &p : pairs) {
77 const SimplexId &thisOriginVert = std::get<0>(p);
78 const SimplexId &thisEndVert = std::get<1>(p);
79 const scalarType &thisPersist = std::get<2>(p);
80 const bool thisNeedUp = std::get<3>(p);
81 std::cout << thisOriginVert << " - " << thisEndVert << " : "
82 << thisPersist;
83 std::cout << " ( " << thisNeedUp << " )" << std::endl;
84 }
85 std::cout << std::endl;
86 }
87
88 // }
89 // --------------
90 // Simplify
91 // --------------
92 // {
93
94 return simplifyTree<scalarType>(posSeed0, posSeed1, storage, pairs);
95
96 // }
97 }
98
99 template <typename scalarType, typename triangulationType>
101 const SimplexId posSeed0,
102 const SimplexId posSeed1,
103 std::list<std::vector<std::pair<SimplexId, bool>>> &storage,
104 const triangulationType &mesh) {
105
106 // if null threshold, leave
107 if(!params_->simplifyThreshold) {
108 return 0;
109 }
110
111 //---------------------
112 // Sort Nodes
113 //---------------------
114 //{
115
116 auto isLowerComp = [&](const idNode &n1, const idNode &n2) {
117 return isLower(getNode(n1)->getVertexId(), getNode(n2)->getVertexId());
118 };
119
120 const auto nbNode = getNumberOfNodes();
121
122 std::vector<idNode> sortedNodes(nbNode);
123 iota(sortedNodes.begin(), sortedNodes.end(), 0);
124 // Sort nodes by vertex scalar
125 //{
126 TTK_PSORT(this->threadNumber_, sortedNodes.begin(), sortedNodes.end(),
127 isLowerComp);
128 //}
129
130 //}
131 //---------------------
132 // Make pairs
133 //---------------------
134 //{
135
136 // origin, end, persistence, needToGoUp
137 std::vector<std::tuple<SimplexId, SimplexId, scalarType, bool>> pairsJT;
138 std::vector<std::tuple<SimplexId, SimplexId, scalarType, bool>> pairsST;
139
140 recoverMTPairs<scalarType>(sortedNodes, pairsJT, pairsST, mesh);
141
142 //}
143 //---------------------
144 // Fusionne & Sort pairs
145 //---------------------
146 //{
147
148 auto pairComp
149 = [](const std::tuple<SimplexId, SimplexId, scalarType, bool> &a,
150 const std::tuple<SimplexId, SimplexId, scalarType, bool> &b) {
151 // sort by persistence
152 return std::get<2>(a) < std::get<2>(b);
153 };
154
155 std::vector<std::tuple<SimplexId, SimplexId, scalarType, bool>>
156 sortedPairs;
157 size_t sizePJT = pairsJT.size(), sizePST = pairsST.size();
158
159 sortedPairs.reserve(sizePJT + sizePST);
160
161 sortedPairs.insert(sortedPairs.end(), pairsJT.begin(), pairsJT.end());
162 sortedPairs.insert(sortedPairs.end(), pairsST.begin(), pairsST.end());
163
164 // Sort pairs by persistence
165 //{
166 // IS SET STILL BETTER ? (parallel sort) TODO
167 TTK_PSORT(
168 this->threadNumber_, sortedPairs.begin(), sortedPairs.end(), pairComp);
169
170 auto last = unique(sortedPairs.begin(), sortedPairs.end());
171 sortedPairs.erase(last, sortedPairs.end());
172
173 //}
174 //---------------------
175 // Traverse pairs and merge on the tree
176 //---------------------
177 //{
178
179 // identify subtrees and merge them in recept'arcs
180 return simplifyTree<scalarType>(posSeed0, posSeed1, storage, sortedPairs);
181 //}
182 }
183
184 template <typename scalarType>
186 const SimplexId &posSeed0,
187 const SimplexId &posSeed1,
188 std::list<std::vector<std::pair<SimplexId, bool>>> &storage,
189 const std::vector<std::tuple<SimplexId, SimplexId, scalarType, bool>>
190 &sortedPairs) {
191 const auto nbNode = getNumberOfNodes();
192 const auto nbArcs = getNumberOfSuperArcs();
193 // Retain the relation between merge coming from st, jt
194 // also retain info about what we keep
195 std::vector<ExtendedUnionFind> storageUF(nbNode, 0);
196 std::vector<ExtendedUnionFind *> subtreeUF(nbNode, nullptr);
197
198 // nb arc seen below / above this node
199 std::vector<std::pair<idSuperArc, idSuperArc>> valenceOffset(
200 nbNode, std::make_pair(0, 0));
201 SimplexId nbPairMerged = 0;
202
203 const bool DEBUG = false;
204
205 if(DEBUG) {
206 std::cout << "Impact simplify on tree btwn : " << posSeed0 << " and "
207 << posSeed1 << std::endl;
208 }
209
210 //----------
211 // Make subtrees
212 //-----------
213 //{
214
215 std::queue<std::tuple<idNode, bool>> node2see;
216
217 // Add the origin of all pairs that need to merge
218 for(const auto &pp : sortedPairs) {
219 if(std::get<2>(pp) < params_->simplifyThreshold) {
220 const SimplexId &thisOriginVert = std::get<0>(pp);
221 const SimplexId &thisEndVert = std::get<1>(pp);
222 const idNode &thisOriginId = getCorrespondingNodeId(thisOriginVert);
223
224 if(scalars_->sosOffsets[thisOriginVert] <= posSeed0
225 || scalars_->sosOffsets[thisOriginVert] >= posSeed1
226 || scalars_->sosOffsets[thisEndVert] <= posSeed0
227 || scalars_->sosOffsets[thisEndVert] >= posSeed1) {
228 continue;
229 }
230
231 node2see.emplace(thisOriginId, std::get<3>(pp));
232 storageUF[thisOriginId] = ExtendedUnionFind{0};
233 subtreeUF[thisOriginId] = &storageUF[thisOriginId];
234 ++nbPairMerged;
235 if(DEBUG) {
236 std::cout << "willSee " << printNode(thisOriginId) << std::endl;
237 }
238 } else
239 break;
240 }
241
242 //---
243 // In UF :
244 // Origin is the size of the segmentation
245 // Data is negative : -idNodeRoot-1
246 // Data is positive : Receptacle Arc id
247 //--
248 // Use the queue to mark Arc that will be merged and UF to identify
249 // subtree. When a node have only one way out : enqueue it to continue
250 // travresall
251 while(!node2see.empty()) {
252 idNode curNodeId;
253 bool needToGoUp; // identify up/down traversall
254
255 std::tie(curNodeId, needToGoUp) = node2see.front();
256 // should have only one arc valid to take
257 node2see.pop();
258
259 if(DEBUG) {
260 std::cout << "process : " << printNode(curNodeId) << std::endl;
261 }
262
263 // Here we take the only available arc :
264 idSuperArc mergingArcId;
265 idNode parentNodeId;
266 // continue traversall
267 if(needToGoUp) {
268 mergingArcId = newUpArc(curNodeId, subtreeUF);
269 parentNodeId = getSuperArc(mergingArcId)->getUpNodeId();
270 ++valenceOffset[curNodeId].second;
271 ++valenceOffset[parentNodeId].first;
272 } else {
273 mergingArcId = newDownArc(curNodeId, subtreeUF);
274 parentNodeId = getSuperArc(mergingArcId)->getDownNodeId();
275 ++valenceOffset[curNodeId].first;
276 ++valenceOffset[parentNodeId].second;
277 }
278
279 markThisArc(subtreeUF, curNodeId, mergingArcId, parentNodeId);
280
281 // if we have processed all but one arc of this node, we nee to continue
282 // traversall
283 // through it
284 if(valenceOffset[parentNodeId].first
285 + valenceOffset[parentNodeId].second + 1
286 == getNode(parentNodeId)->getValence()) {
287 // only one way out, is it up ?
288 node2see.emplace(
289 parentNodeId, valenceOffset[parentNodeId].second + 1 ==
290
291 getNode(parentNodeId)->getUpValence());
292 if(DEBUG) {
293 std::cout << " add to see " << printNode(parentNodeId) << std::endl;
294 }
295 }
296 } // end while node2see
297
298 // for each node valenceOffset is the number of arc attached to this node
299 // that will merge
300
301 // Debug print
302 if(DEBUG) {
303 std::cout << "node subtrees before creating receptarc " << std::endl;
304 for(idNode nid = 0; nid < nbNode; nid++) {
305 if(subtreeUF[nid]) {
306 std::cout << "node " << getNode(nid)->getVertexId()
307 << " is in subtree rooted :";
308 const idNode &root = -subtreeUF[nid]->find()->getData() - 1;
309 std::cout << getNode(root)->getVertexId();
310 const SimplexId &segmSize = subtreeUF[nid]->find()->getOrigin();
311 std::cout << " with segmentation of " << segmSize << std::endl;
312 }
313 }
314 }
315
316 //}
317 //----------
318 // Create the recept'arcs
319 //-----------
320 //{
321
322 // Add the origin of all pairs that need to merge
323 for(const auto &pp : sortedPairs) {
324 if(std::get<2>(pp) < params_->simplifyThreshold) {
325 const SimplexId &thisOriginVert = std::get<0>(pp);
326 const SimplexId &thisEndVert = std::get<1>(pp);
327 const idNode &thisOriginId = getCorrespondingNodeId(thisOriginVert);
328 // const idNode & thisEndId = getCorrespondingNode(thisEndVert);
329
330 if(scalars_->sosOffsets[thisOriginVert] <= posSeed0
331 || scalars_->sosOffsets[thisOriginVert] >= posSeed1
332 || scalars_->sosOffsets[thisEndVert] <= posSeed0
333 || scalars_->sosOffsets[thisEndVert] >= posSeed1) {
334 continue;
335 }
336
337 if(subtreeUF[thisOriginId]->find()->getData() < 0) {
338 // create receptarc
339 const idNode &subtreeRoot
340 = -subtreeUF[thisOriginId]->find()->getData() - 1;
341 // The id of the next arc to be created : NOT PARALLEL
342 const idSuperArc receptArcId = treeData_.superArcs.size();
343 // down , up, segmentation size
344 // create the receptacle arc and merge arc not in sub-tree in it
345 const std::tuple<idNode, idNode, SimplexId> &receptArc
346 = createReceptArc(
347 subtreeRoot, receptArcId, subtreeUF, valenceOffset);
348
349 // make superArc and do the makeAlloc on it
350 const bool overlapB =
351
353 ->sosOffsets[getNode(std::get<0>(receptArc))->getVertexId()]
354 < posSeed0;
355 const bool overlapA =
356
358 ->sosOffsets[getNode(std::get<1>(receptArc))->getVertexId()]
359 >= posSeed1;
360 const idSuperArc na
361 = makeSuperArc(std::get<0>(receptArc), std::get<1>(receptArc),
362 overlapB, overlapA, nullptr, -1);
363
364 if(overlapB) {
365 treeData_.arcsCrossingBelow.emplace_back(na);
366 }
367
368 if(overlapA) {
369 treeData_.arcsCrossingAbove.emplace_back(na);
370 }
371
372 subtreeUF[thisOriginId]->find()->setData(receptArcId);
373 getSuperArc(receptArcId)
374 ->makeAllocGlobal(std::get<2>(receptArc), storage);
375
376 if(DEBUG) {
377 std::cout << "create arc : " << printArc(receptArcId)
378 << " with segm : " << std::get<2>(receptArc)
379 << std::endl;
380 }
381 }
382 } else
383 break;
384 }
385
386 //}
387 //----------
388 // Merge these subtrees
389 //-----------
390 //{
391
392 // The merge is done after because we don't want to forget arcs parallel
393 // to the recept'arc but we cannot make the difference before the former
394 // are created
395
396 // nbArcs is before the insertion of receptarcs so they will no be crossed
397 // here
398 for(idSuperArc arc = 0; arc < nbArcs; arc++) {
399
400 if(getSuperArc(arc)->isMerged()) {
401 const idSuperArc &receptacleArcId
402 = getSuperArc(arc)->getReplacantArcId();
403 // take care of connectivity
404 mergeArc(arc, receptacleArcId);
405 if(DEBUG) {
406 std::cout << " parallel merge in " << printArc(receptacleArcId)
407 << std::endl;
408 std::cout << " arc " << printArc(arc)
409 << " size : " << getSuperArc(arc)->getVertSize()
410 << std::endl;
411 }
412 getSuperArc(receptacleArcId)
413 ->addSegmentationGlobal(
414 getSuperArc(arc)->getVertList(), getSuperArc(arc)->getVertSize());
415 } else {
416 const idNode &downNode = getSuperArc(arc)->getDownNodeId();
417 const idNode &upNode = getSuperArc(arc)->getUpNodeId();
418
419 if(!(subtreeUF[downNode] && subtreeUF[upNode]))
420 continue;
421
422 if(subtreeUF[downNode] && subtreeUF[upNode]
423 && subtreeUF[downNode]->find() != subtreeUF[upNode]->find()) {
424 if(DEBUG) {
425 std::cout << "Arc between 2 degenerate with mergin "
426 << printArc(arc) << std::endl;
427 std::cout << "below recept : "
428 << printArc(subtreeUF[downNode]->find()->getData());
429 std::cout << std::endl;
430 std::cout << "Above recept : "
431 << printArc(subtreeUF[upNode]->find()->getData())
432 << std::endl;
433 std::cout << std::endl;
434 }
435
436 continue;
437 }
438
439 ExtendedUnionFind *curUF = (subtreeUF[upNode])
440 ? subtreeUF[upNode]->find()
441 : subtreeUF[downNode]->find();
442
443 const idSuperArc &receptacleArcId = curUF->getData();
444
445 if(DEBUG) {
446 std::cout << "merge in " << printArc(receptacleArcId) << std::endl;
447 std::cout << " arc " << printArc(arc)
448 << " size : " << getSuperArc(arc)->getVertSize();
449 std::cout << std::endl;
450 }
451
452 getSuperArc(arc)->merge(receptacleArcId);
453 if(getSuperArc(arc)->getVertSize()) {
454 getSuperArc(receptacleArcId)
455 ->addSegmentationGlobal(getSuperArc(arc)->getVertList(),
456 getSuperArc(arc)->getVertSize());
457
458 getSuperArc(receptacleArcId)
459 ->addSegmentationGlobal(getNode(downNode)->getVertexId());
460
461 getSuperArc(receptacleArcId)
462 ->addSegmentationGlobal(getNode(upNode)->getVertexId());
463 }
464
465 // Tree topology
466 getNode(downNode)->removeUpSuperArc(arc);
467 getNode(downNode)->decUpValence();
468 getNode(upNode)->removeDownSuperArc(arc);
469 getNode(upNode)->decDownValence();
470
471 if(!getNode(downNode)->getNumberOfUpSuperArcs())
472 hideNode(downNode);
473 if(!getNode(upNode)->getNumberOfDownSuperArcs())
474 hideNode(upNode);
475 }
476 } // end for arcs
477
478 //}
479
480 return nbPairMerged;
481 }
482
483 // Persistence
484
485 template <typename scalarType, typename triangulationType>
487 std::vector<std::tuple<SimplexId, SimplexId, scalarType>> &pairs,
488 const triangulationType &mesh) {
489#ifndef TTK_ENABLE_KAMIKAZE
490 if(!getNumberOfSuperArcs()) {
491 return -1;
492 }
493#endif
494
495 pairs.reserve(treeData_.leaves.size());
496
497 for(const idNode &leave : treeData_.leaves) {
498 Node *curNode = getNode(leave);
499 SimplexId curVert = curNode->getVertexId();
500 SimplexId termVert = getNode(curNode->getTermination())->getVertexId();
501
502 addPair<scalarType>(pairs, curVert, termVert, mesh);
503 }
504
505 auto pair_sort
506 = [](const std::tuple<SimplexId, SimplexId, scalarType> &a,
507 const std::tuple<SimplexId, SimplexId, scalarType> &b) {
508 return std::get<2>(a) < std::get<2>(b);
509 };
510
511 sort(pairs.begin(), pairs.end(), pair_sort);
512
513 return 0;
514 }
515
516 template <typename scalarType, typename triangulationType>
518 std::vector<std::tuple<SimplexId, SimplexId, scalarType, bool>> &pairs,
519 const triangulationType &mesh) {
520 // Need to be called on MergeTree, not ContourTree
521
522#ifndef TTK_ENABLE_KAMIKAZE
523 if(!getNumberOfSuperArcs()) {
524 return -1;
525 }
526
528 std::cout << "WARNING, computePersistencePairs is made to be called on "
529 << "Join or Split Tree" << std::endl;
530 }
531#endif
532
533 pairs.reserve(treeData_.leaves.size());
534
535 for(const idNode &leave : treeData_.leaves) {
536 Node *curNode = getNode(leave);
537 SimplexId curVert = curNode->getVertexId();
538 SimplexId termVert = getNode(curNode->getTermination())->getVertexId();
539
540 addPair<scalarType>(
541 pairs, curVert, termVert, mesh, treeData_.treeType == TreeType::Join);
542 }
543
544 auto pair_sort
545 = [](const std::tuple<SimplexId, SimplexId, scalarType, bool> &a,
546 const std::tuple<SimplexId, SimplexId, scalarType, bool> &b) {
547 return std::get<2>(a) < std::get<2>(b);
548 };
549
550 sort(pairs.begin(), pairs.end(), pair_sort);
551
552 return 0;
553 }
554
555 template <typename scalarType, typename triangulationType>
557 const std::vector<idNode> &sortedNodes,
558 std::vector<std::tuple<SimplexId, SimplexId, scalarType, bool>> &pairsJT,
559 std::vector<std::tuple<SimplexId, SimplexId, scalarType, bool>> &pairsST,
560 const triangulationType &mesh) {
561 const auto nbNode = getNumberOfNodes();
562
563 std::vector<ExtendedUnionFind> storage_JoinUF(nbNode, 0);
564 std::vector<ExtendedUnionFind> storage_SplitUF(nbNode, 0);
565
566 std::vector<ExtendedUnionFind *> vect_JoinUF(nbNode, nullptr);
567 std::vector<ExtendedUnionFind *> vect_SplitUF(nbNode, nullptr);
568
569#ifdef TTK_ENABLE_OPENMP
570#pragma omp parallel sections num_threads(2)
571#endif
572 {
573#ifdef TTK_ENABLE_OPENMP
574#pragma omp section
575#endif
576 {
577 pairsJT.reserve(treeData_.leaves.size());
578 // For the biggest pair of the component
579 std::map<SimplexId, SimplexId> pendingMinMax;
580
581 for(auto it = sortedNodes.cbegin(); it != sortedNodes.cend(); ++it) {
582 const idNode &n = *it;
583 const SimplexId &v = getNode(n)->getVertexId();
584
585 const auto &nbUp = getNode(n)->getNumberOfUpSuperArcs();
586 const auto &nbDown = getNode(n)->getNumberOfDownSuperArcs();
587
588 if(nbDown == 0) {
589 // leaf
590 storage_JoinUF[n] = ExtendedUnionFind{getNode(n)->getVertexId()};
591 vect_JoinUF[n] = &storage_JoinUF[n];
592 vect_JoinUF[n]->setOrigin(v);
593 // std::cout << " jt origin : " << v << std::endl;
594 } else {
595 // first descendant
596 const idSuperArc firstSaId = getNode(n)->getDownSuperArcId(0);
597 const SuperArc *firstSA = getSuperArc(firstSaId);
598 const idNode &firstChildNodeId = firstSA->getDownNodeId();
599
600 ExtendedUnionFind *merge = vect_JoinUF[firstChildNodeId]->find();
601 SimplexId further = merge->getOrigin();
602 idSuperArc furtherI = 0;
603
604 // Find the most persistent way
605 for(idSuperArc ni = 1; ni < nbDown; ++ni) {
606 const idSuperArc curSaId = getNode(n)->getDownSuperArcId(ni);
607 const SuperArc *curSA = getSuperArc(curSaId);
608 const idNode &neigh = curSA->getDownNodeId();
609
610 // fix
611 if(neigh == n)
612 continue;
613
614 ExtendedUnionFind *neighUF = vect_JoinUF[neigh]->find();
615
616 if(isLower(neighUF->getOrigin(), further)) {
617 further = neighUF->getOrigin();
618 furtherI = ni;
619 }
620 }
621
622 if(nbDown > 1) {
623 // close finish pair and make union
624 for(idSuperArc ni = 0; ni < nbDown; ++ni) {
625 const idSuperArc curSaId = getNode(n)->getDownSuperArcId(ni);
626 const SuperArc *curSA = getSuperArc(curSaId);
627 const idNode &neigh = curSA->getDownNodeId();
628
629 // fix
630 if(neigh == n)
631 continue;
632
633 ExtendedUnionFind *neighUF = vect_JoinUF[neigh]->find();
634
635 if(ni != furtherI) { // keep the more persistent pair
636 addPair<scalarType>(
637 pairsJT, neighUF->getOrigin(), v, mesh, true);
638 pendingMinMax.erase(neighUF->getOrigin());
639
640 // std::cout << " jt make pair : " <<
641 // neighUF->getOrigin() << " - " << v <<
642 // std::endl;
643 }
644
645 ExtendedUnionFind::makeUnion(merge, neighUF)
646 ->setOrigin(further);
647 }
648 }
649
650 merge->find()->setOrigin(further);
651 vect_JoinUF[n] = merge->find();
652
653 if(!nbUp) {
654 // potential close of the component
655 // std::cout << "pending for " << further << " is " << v <<
656 // std::endl;
657 pendingMinMax[further] = v;
658 }
659 }
660 } // end for each node
661
662 // Add the pending biggest pair of each component
663 for(const auto &pair_vert : pendingMinMax) {
664 if(isCorrespondingNode(pair_vert.second)) {
665 // std::cout << " add : " << pair_vert.first << " - " <<
666 // pair_vert.second << std::endl;
667 addPair<scalarType>(
668 pairsJT, pair_vert.first, pair_vert.second, mesh, true);
669 }
670 }
671 } // end para section
672
673#ifdef TTK_ENABLE_OPENMP
674#pragma omp section
675#endif
676 {
677 pairsST.reserve(treeData_.leaves.size());
678 // For the biggest pair of the component
679 std::map<SimplexId, SimplexId> pendingMinMax;
680
681 for(auto it = sortedNodes.crbegin(); it != sortedNodes.crend();
682 ++it) {
683 const idNode &n = *it;
684 const SimplexId &v = getNode(n)->getVertexId();
685
686 const auto &nbUp = getNode(n)->getNumberOfUpSuperArcs();
687 const auto &nbDown = getNode(n)->getNumberOfDownSuperArcs();
688
689 if(nbUp == 0) {
690 // leaf
691 storage_SplitUF[n] = ExtendedUnionFind{getNode(n)->getVertexId()};
692 vect_SplitUF[n] = &storage_SplitUF[n];
693 vect_SplitUF[n]->setOrigin(v);
694 // std::cout << " st origin : " << v << std::endl;
695 } else {
696 // first descendant
697 const idSuperArc firstSaId = getNode(n)->getUpSuperArcId(0);
698 const SuperArc *firstSA = getSuperArc(firstSaId);
699 const idNode &firstChildNodeId = firstSA->getUpNodeId();
700
701 ExtendedUnionFind *merge = vect_SplitUF[firstChildNodeId]->find();
702 SimplexId further = merge->getOrigin();
703 idSuperArc furtherI = 0;
704
705 for(idSuperArc ni = 1; ni < nbUp; ++ni) {
706 // find the more persistent way
707 const idSuperArc curSaId = getNode(n)->getUpSuperArcId(ni);
708 const SuperArc *curSA = getSuperArc(curSaId);
709 // Ignore hidden / simplified arc
710 if(!curSA->isVisible())
711 continue;
712 const idNode &neigh = curSA->getUpNodeId();
713
714 // fix
715 if(neigh == n)
716 continue;
717
718 // std::cout << "visit neighbor : " << ni << " which is " <<
719 // getNode(neigh)->getVertexId() << std::endl;
720
721 ExtendedUnionFind *neighUF = vect_SplitUF[neigh]->find();
722
723 if(isHigher(neighUF->getOrigin(), further)) {
724 further = neighUF->getOrigin();
725 furtherI = ni;
726 }
727 }
728
729 if(nbUp > 1) {
730 // close finish pair and make union
731 for(idSuperArc ni = 0; ni < nbUp; ++ni) {
732 const idSuperArc curSaId = getNode(n)->getUpSuperArcId(ni);
733 const SuperArc *curSA = getSuperArc(curSaId);
734 const idNode &neigh = curSA->getUpNodeId();
735
736 // fix
737 if(neigh == n)
738 continue;
739
740 ExtendedUnionFind *neighUF = vect_SplitUF[neigh]->find();
741
742 if(ni != furtherI) {
743 addPair<scalarType>(
744 pairsST, neighUF->getOrigin(), v, mesh, false);
745
746 pendingMinMax.erase(neighUF->getOrigin());
747
748 // std::cout << " st make pair : " <<
749 // neighUF->getOrigin() << " - " << v
750 //<< " for neighbor " <<
751 // getNode(neigh)->getVertexId() << std::endl;
752 }
753
754 ExtendedUnionFind::makeUnion(merge, neighUF)
755 ->setOrigin(further);
756 // Re-visit after merge lead to add the most persistent
757 // pair....
758 }
759 }
760 merge->find()->setOrigin(further);
761 vect_SplitUF[n] = merge->find();
762
763 if(!nbDown) {
764 pendingMinMax[further] = v;
765 }
766
767 } // end nbUp == 0 else
768 } // end for each node
769
770 // Add the pending biggest pair of each component
771 for(const auto &pair_vert : pendingMinMax) {
772 addPair<scalarType>(
773 pairsST, pair_vert.first, pair_vert.second, mesh, false);
774 }
775 } // end para section
776 } // end para
777 }
778
779 // }
780 // Tools
781 // {
782
783 template <typename scalarType, typename triangulationType>
784 void MergeTree::addPair(
785 std::vector<std::tuple<SimplexId, SimplexId, scalarType, bool>> &pairs,
786 const SimplexId &orig,
787 const SimplexId &term,
788 const triangulationType &mesh,
789 const bool goUp) {
790 if(params_->simplifyMethod == SimplifMethod::Persist) {
791 pairs.emplace_back(
792 orig, term,
793 std::abs(static_cast<double>(getValue<scalarType>(orig)
794 - getValue<scalarType>(term))),
795 goUp);
796 } else if(params_->simplifyMethod == SimplifMethod::Span) {
797 float coordOrig[3], coordTerm[3], span;
798 mesh->getVertexPoint(orig, coordOrig[0], coordOrig[1], coordOrig[2]);
799 mesh->getVertexPoint(term, coordTerm[0], coordTerm[1], coordTerm[2]);
800 span = Geometry::distance(coordOrig, coordTerm);
801 pairs.emplace_back(orig, term, span, goUp);
802 }
803 }
804
805 template <typename scalarType, typename triangulationType>
806 void MergeTree::addPair(
807 std::vector<std::tuple<SimplexId, SimplexId, scalarType>> &pairs,
808 const SimplexId &orig,
809 const SimplexId &term,
810 const triangulationType &mesh) {
811 if(params_->simplifyMethod == SimplifMethod::Persist) {
812 pairs.emplace_back(
813 orig, term,
814 std::abs(static_cast<double>(getValue<scalarType>(orig)
815 - getValue<scalarType>(term))));
816 } else if(params_->simplifyMethod == SimplifMethod::Span) {
817 float coordOrig[3], coordTerm[3], span;
818 mesh->getVertexPoint(orig, coordOrig[0], coordOrig[1], coordOrig[2]);
819 mesh->getVertexPoint(term, coordTerm[0], coordTerm[1], coordTerm[2]);
820 span = Geometry::distance(coordOrig, coordTerm);
821 pairs.emplace_back(orig, term, span);
822 }
823 }
824
825 template <typename triangulationType>
826 int MergeTree::build(std::vector<ExtendedUnionFind *> &vect_baseUF,
827 const std::vector<SimplexId> &overlapBefore,
828 const std::vector<SimplexId> &overlapAfter,
829 SimplexId start,
830 SimplexId end,
831 const SimplexId &posSeed0,
832 const SimplexId &posSeed1,
833 const triangulationType &mesh) {
834 // idea, work on the neighborhood instead of working on the node itself.
835 // Need lower / higher star construction.
836 //
837 // at this time, ST have no root except in Adjacency list. These root are
838 // isolated vertices.
839 //
840 // clear and reset tree data (this step should take almost no time)
841 flush();
842
843 DebugTimer timerBegin;
844
845 // -----------------
846 // Find boundaries
847 // -----------------
848 // {
849
850 SimplexId sortedNode;
851 const SimplexId step = (treeData_.treeType == TreeType::Join) ? 1 : -1;
852
853 // main
854 const SimplexId mainStart = start;
855 const SimplexId mainEnd = end;
856
857 const bool isJT = treeData_.treeType == TreeType::Join;
858 // else Split Tree, can't be called on ContourTree
859
860 // overlap before
861 const SimplexId beforeStart = (isJT) ? 0 : overlapBefore.size() - 1;
862 const SimplexId beforeEnd = (isJT) ? overlapBefore.size() : -1;
863
864 // overlap after
865 const SimplexId afterStart = (isJT) ? 0 : overlapAfter.size() - 1;
866 const SimplexId afterEnd = (isJT) ? overlapAfter.size() : -1;
867
868 // print debug
869 if(params_->debugLevel >= 3) {
870#ifdef TTK_ENABLE_OPENMP
871#pragma omp critical
872#endif
873 {
874 std::stringstream msg;
875 msg << "partition : " << static_cast<unsigned>(treeData_.partition);
876 msg << ", isJT : " << isJT;
877 msg << ", size : ";
878 msg << "before : " << std::abs(beforeEnd - beforeStart);
879 msg << ", main : " << std::abs(mainEnd - mainStart);
880 msg << ", after : " << std::abs(afterEnd - afterStart);
881 msg << ", Total : ";
882 msg << std::abs(beforeEnd - beforeStart)
883 + std::abs(mainEnd - mainStart)
884 + std::abs(afterEnd - afterStart);
885 this->printMsg(msg.str());
886 }
887 }
888
889 // }
890 // --------------
891 // Overlap Before
892 // --------------
893 // {
894
895 // for each vertex of our triangulation
896 for(sortedNode = beforeStart; sortedNode != beforeEnd;
897 sortedNode += step) {
898 const SimplexId currentVertex = overlapBefore[sortedNode];
899 const bool overlapB = isJT;
900 const bool overlapA = !isJT;
902 currentVertex, vect_baseUF, overlapB, overlapA, mesh, timerBegin);
903 } // foreach node
904
905 // }
906 // ---------------
907 // Partition
908 // ---------------
909 // {
910
911 // for each vertex of our triangulation
912 for(sortedNode = mainStart; sortedNode != mainEnd; sortedNode += step) {
913 const SimplexId currentVertex = scalars_->sortedVertices[sortedNode];
915 currentVertex, vect_baseUF, false, false, mesh, timerBegin);
916 } // foreach node
917
918 // }
919 // ---------------
920 // Overlap After
921 // ---------------
922 // {
923
924 // for each vertex of our triangulation
925 for(sortedNode = afterStart; sortedNode != afterEnd; sortedNode += step) {
926 const SimplexId currentVertex = overlapAfter[sortedNode];
927 const bool overlapB = !isJT;
928 const bool overlapA = isJT;
930 currentVertex, vect_baseUF, overlapB, overlapA, mesh, timerBegin);
931 } // foreach node
932
933 // }
934 // ---------------
935 // Close root arcs
936 // ---------------
937 // {
938
939 // Closing step for openedSuperArc.
940 // Not aesthetic but efficient
941 // More efficient that using nullity of the neighborhood
942 // to detect extrema of the opponent tree
943 idNode rootNode;
944 SimplexId corrVertex, origin;
945 idSuperArc tmp_sa;
946
947 // It can't be more connected component that leaves so test for each
948 // leaves (even virtual extrema)
949 for(const auto &l : treeData_.leaves) {
950 corrVertex = getNode(l)->getVertexId();
951
952 // case of an isolated point
953 if(!mesh->getVertexNeighborNumber(corrVertex)) {
954 tmp_sa = getNode(l)->getUpSuperArcId(0);
955 } else {
956 tmp_sa = (idSuperArc)((vect_baseUF[corrVertex])->find()->getData());
957 origin = (idSuperArc)((vect_baseUF[corrVertex])->find()->getOrigin());
958 }
959
960 if(treeData_.superArcs[tmp_sa].getUpNodeId() == nullNodes) {
961 rootNode
962 = makeNode(treeData_.superArcs[tmp_sa].getLastVisited(), origin);
963 Node *originNode = getNode(
964 getNode(getSuperArc(tmp_sa)->getDownNodeId())->getOrigin());
965 originNode->setTermination(rootNode);
966
967 const bool overlapB
968 = scalars_->sosOffsets[getNode(rootNode)->getVertexId()]
969 <= posSeed0;
970 const bool overlapA
971 = scalars_->sosOffsets[getNode(rootNode)->getVertexId()]
972 >= posSeed1;
973
974 closeSuperArc(tmp_sa, rootNode, overlapB, overlapA);
975
976 // in the case we have 1 vertex domain,
977 // hide the close SuperArc which is point1 <>> point1
978 if(getSuperArc(tmp_sa)->getDownNodeId()
979 == getSuperArc(tmp_sa)->getUpNodeId()) {
980 hideArc(tmp_sa);
981 }
982
983 treeData_.roots.emplace_back(rootNode);
984 }
985 }
986
987 // }
988 // -----------
989 // Timer print
990 // ------------
991 // {
992
993 this->printMsg("Tree " + std::to_string(treeData_.partition)
994 + " computed (" + std::to_string(getNumberOfSuperArcs())
995 + " arcs)",
996 1.0, timerBegin.getElapsedTime(), this->threadNumber_);
997
998 // }
999
1000 return 0;
1001 }
1002
1003 template <typename triangulationType>
1004 void MergeTree::processVertex(const SimplexId &currentVertex,
1005 std::vector<ExtendedUnionFind *> &vect_baseUF,
1006 const bool overlapB,
1007 const bool overlapA,
1008 const triangulationType &mesh,
1009 DebugTimer &begin) {
1010 std::vector<ExtendedUnionFind *> vect_neighUF;
1011 ExtendedUnionFind *seed = nullptr, *tmpseed;
1012
1013 SimplexId neighSize;
1014 const SimplexId neighborNumber
1015 = mesh->getVertexNeighborNumber(currentVertex);
1016 const bool isJT = treeData_.treeType == TreeType::Join;
1017
1018 idSuperArc currentArc;
1019 idNode closingNode, currentNode;
1020 SimplexId neighbor{-1};
1021
1022 // Check UF in neighborhood
1023 for(SimplexId n = 0; n < neighborNumber; ++n) {
1024 mesh->getVertexNeighbor(currentVertex, n, neighbor);
1025 // if the vertex is out: consider it null
1026 tmpseed = vect_baseUF[neighbor];
1027 // unvisited vertex, we continue.
1028 if(tmpseed == nullptr) {
1029 continue;
1030 }
1031
1032 tmpseed = tmpseed->find();
1033
1034 // get all different UF in neighborhood
1035 if(find(vect_neighUF.cbegin(), vect_neighUF.cend(), tmpseed)
1036 == vect_neighUF.end()) {
1037 vect_neighUF.emplace_back(tmpseed);
1038 seed = tmpseed;
1039 }
1040 }
1041
1042 (neighSize = vect_neighUF.size());
1043
1044 // SimplexId test = 1;
1045 // if (currentVertex == test)
1046 // cout << test << " : " << vect_neighUF.size() << " " <<
1047 // vect_interfaceUF.size() << endl; Make output
1048 if(!neighSize) {
1049 // we are on a real extrema we have to create a new UNION FIND and a
1050 // branch a real extrema can't be a virtual extrema
1051
1052#ifdef TTK_ENABLE_OPENMP
1053#pragma omp critical
1054#endif // TTK_ENABLE_OPENMP
1055 {
1056 this->storageEUF_.emplace_back(currentVertex);
1057 seed = &this->storageEUF_.back();
1058 }
1059 // When creating an extrema we create a pair ending on this node.
1060 currentNode = makeNode(currentVertex);
1061 getNode(currentNode)->setOrigin(currentNode);
1062 currentArc = openSuperArc(currentNode, overlapB, overlapA);
1063 // if(overlap && partition_ == 1) cout << currentVertex << endl;
1064 treeData_.leaves.emplace_back(currentNode);
1065
1066 if(params_->debugLevel >= static_cast<int>(debug::Priority::DETAIL)) {
1067 if(isJT) {
1068 this->printMsg("Min node id: " + std::to_string(currentVertex), 1.0,
1069 begin.getElapsedTime(), this->threadNumber_);
1070 } else {
1071 this->printMsg("Max node id: " + std::to_string(currentVertex), 1.0,
1072 begin.getElapsedTime(), this->threadNumber_);
1073 }
1074 }
1075 } else if(neighSize > 1) {
1076 // Is a saddle if have more than one UF in neighborhood
1077 // Or is linked to an interface (virtual extrema -> leaves or
1078 // interface cc representant : regular node )
1079
1080 // Merge operation => close all arriving SuperArc (ignoring UF from
1081 // interface) And open a new one
1082 closingNode = makeNode(currentVertex);
1083 currentArc = openSuperArc(closingNode, overlapB, overlapA);
1084
1085 SimplexId farOrigin = vect_neighUF[0]->find()->getOrigin();
1086
1087 // close each SuperArc finishing here
1088 for(auto *neigh : vect_neighUF) {
1089 closeSuperArc((idSuperArc)neigh->find()->getData(), closingNode,
1090 overlapB, overlapA);
1091 // persistence pair closing here.
1092 // For the one who will continue, it will be override later
1093 vertex2Node(neigh->find()->getOrigin())->setTermination(closingNode);
1094
1095 // cout <<
1096 // getNode(getCorrespondingNode(neigh->find()->getOrigin()))->getVertexId()
1097 //<< " terminate on " << getNode(closingNode)->getVertexId() << endl;
1098
1099 if((isJT && isLower(neigh->find()->getOrigin(), farOrigin))
1100 || (!isJT && isHigher(neigh->find()->getOrigin(), farOrigin))) {
1101 // here we keep the continuing the most persitant pair.
1102 // It means a pair end when a parent have another origin than the
1103 // current leaf (or is the root) It might be not intuitive but it is
1104 // more convenient for degenerate cases
1105 farOrigin = neigh->find()->getOrigin();
1106 // cout << "find origin " << farOrigin << " for " << currentVertex
1107 // << " " << isJT
1108 //<< endl;
1109 }
1110 }
1111
1112 // Union correspond to the merge
1113 seed = ExtendedUnionFind::makeUnion(vect_neighUF);
1114 if(seed == nullptr) {
1115 return;
1116 }
1117 seed->setOrigin(farOrigin);
1118 getNode(closingNode)->setOrigin(getCorrespondingNodeId(farOrigin));
1119
1120 // cout << " " << getNode(closingNode)->getVertexId() << " have origin
1121 // at "
1122 //<< getNode(getCorrespondingNode(farOrigin))->getVertexId() << endl;
1123
1124 this->printMsg("Saddle node id: " + std::to_string(currentVertex),
1126
1127 } else {
1128#ifndef TTK_ENABLE_KAMIKAZE
1129 if(seed == nullptr) {
1130 return;
1131 }
1132#endif // TTK_ENABLE_KAMIKAZE
1133 // regular node
1134 currentArc = (idSuperArc)seed->find()->getData();
1135 updateCorrespondingArc(currentVertex, currentArc);
1136 }
1137 // common
1138 seed->setData((ufDataType)currentArc);
1139 getSuperArc(currentArc)->setLastVisited(currentVertex);
1140 vect_baseUF[currentVertex] = seed;
1141 }
1142
1143 template <typename triangulationType>
1144 bool MergeTree::verifyTree(const triangulationType &mesh) {
1145 bool res = true;
1146
1147#ifdef TTK_ENABLE_OPENMP
1148#pragma omp critical
1149#endif
1150 {
1151 const idSuperArc &nbArcs = getNumberOfSuperArcs();
1152 const idSuperArc &nbNodes = getNumberOfNodes();
1153
1154 std::cout << "Verify Tree : " << std::endl;
1155 std::cout << "nbNode initial : " << nbNodes << std::endl;
1156 std::cout << "nbArcs initial : " << nbArcs << std::endl;
1157
1158 idSuperArc nbArcsVisible = 0;
1159 idSuperArc nbNodesVisible = 0;
1160
1161 // for each visible arc, verify he is in the node
1162
1163 for(idSuperArc aid = 0; aid < nbArcs; aid++) {
1164 const SuperArc &arc = treeData_.superArcs[aid];
1165 if(arc.isVisible()) {
1166 ++nbArcsVisible;
1167 const idNode &up = arc.getUpNodeId();
1168 const idNode &down = arc.getDownNodeId();
1169 if(up == nullNodes || down == nullNodes) {
1170 res = false;
1171 std::cout << "[Verif]: arc id : " << aid
1172 << "have a null boundary :";
1173 std::cout << " down :" << down << " up:" << up << std::endl;
1174 } else {
1175 bool isIn = false;
1176
1177 // Arc is present in its upNode
1178 const Node &nup = treeData_.nodes[up];
1179 const auto &upNbDown = nup.getNumberOfDownSuperArcs();
1180 for(idSuperArc d = 0; d < upNbDown; d++) {
1181 if(nup.getDownSuperArcId(d) == aid) {
1182 isIn = true;
1183 break;
1184 }
1185 }
1186 if(!isIn) {
1187 res = false;
1188 std::cout << "[Verif]: arc " << printArc(aid)
1189 << " is not known by its up node :";
1190 std::cout << treeData_.nodes[up].getVertexId() << std::endl;
1191 }
1192
1193 isIn = false;
1194
1195 // Arc is present in its upNode
1196 const Node &ndown = treeData_.nodes[arc.getDownNodeId()];
1197 const auto &upNbUp = ndown.getNumberOfUpSuperArcs();
1198 for(idSuperArc u = 0; u < upNbUp; u++) {
1199 if(ndown.getUpSuperArcId(u) == aid) {
1200 isIn = true;
1201 break;
1202 }
1203 }
1204 if(!isIn) {
1205 res = false;
1206 std::cout << "[Verif]: arc " << printArc(aid)
1207 << " is not known by its down node :";
1208 std::cout << treeData_.nodes[down].getVertexId() << std::endl;
1209 }
1210 }
1211 }
1212 }
1213
1214 // for each node, verify she is in the arc
1215
1216 for(idNode nid = 0; nid < nbNodes; nid++) {
1217 const Node &node = treeData_.nodes[nid];
1218 if(!node.isHidden()) {
1219 ++nbNodesVisible;
1220
1221 // Verify up arcs
1222 const auto &nbup = node.getNumberOfUpSuperArcs();
1223 for(idSuperArc ua = 0; ua < nbup; ua++) {
1224 const SuperArc &arc
1225 = treeData_.superArcs[node.getUpSuperArcId(ua)];
1226 const idNode arcDownNode = arc.getDownNodeId();
1227 if(arcDownNode != nid || !arc.isVisible()) {
1228 res = false;
1229 const idNode upnode = arc.getUpNodeId();
1230 const idNode downnode = arc.getDownNodeId();
1231 if(upnode == nullNodes || downnode == nullNodes) {
1232 std::cout << "[Verif]: arc id : " << node.getUpSuperArcId(ua);
1233 std::cout << "have a null boundary :";
1234 std::cout << " down :" << downnode << " up:" << upnode
1235 << std::endl;
1236 } else {
1237 std::cout << "[Verif] Node " << node.getVertexId()
1238 << " id : " << nid;
1239 std::cout << " Problem with up arc : "
1240 << printArc(node.getUpSuperArcId(ua)) << std::endl;
1241 }
1242 }
1243 }
1244
1245 // Verify down arcs
1246 const auto &nbdown = node.getNumberOfDownSuperArcs();
1247 for(idSuperArc da = 0; da < nbdown; da++) {
1248 const SuperArc &arc
1249 = treeData_.superArcs[node.getDownSuperArcId(da)];
1250 const idNode arcUpNode = arc.getUpNodeId();
1251 if(arcUpNode != nid || !arc.isVisible()) {
1252 res = false;
1253 const idNode upnode = arc.getUpNodeId();
1254 const idNode downnode = arc.getDownNodeId();
1255 if(upnode == nullNodes || downnode == nullNodes) {
1256 std::cout << "[Verif]: arc id : "
1257 << node.getDownSuperArcId(da);
1258 std::cout << "have a null boundary :";
1259 std::cout << " down :" << downnode << " up:" << upnode
1260 << std::endl;
1261 } else {
1262 std::cout << "[Verif] Node " << node.getVertexId()
1263 << " id : " << nid;
1264 std::cout << " Problem with down arc : "
1265 << printArc(node.getUpSuperArcId(da)) << std::endl;
1266 }
1267 }
1268 }
1269 }
1270 }
1271
1272 // verify segmentation information
1273 const auto &nbVert = mesh->getNumberOfVertices();
1274 std::vector<bool> segmSeen(nbVert, false);
1275
1276 for(idSuperArc aid = 0; aid < nbArcs; aid++) {
1277 SuperArc &arc = treeData_.superArcs[aid];
1278
1279 if(!arc.isVisible())
1280 continue;
1281
1282 const SimplexId segmSize = arc.getVertSize();
1283 const std::pair<SimplexId, bool> *segmVect = arc.getVertList();
1284
1285 if(segmSize && !segmVect) {
1286 res = false;
1287 std::cout << "[Verif] Inconsistent segmentation for arc : ";
1288 std::cout << printArc(aid);
1289 std::cout << " have size of " << segmSize;
1290 std::cout << " and a null list" << std::endl;
1291 }
1292
1293 if(segmVect != nullptr) {
1294 for(SimplexId v = 0; v < segmSize; v++) {
1295 if(!segmVect[v].second) {
1296 segmSeen.at(segmVect[v].first) = true;
1297 }
1298 }
1299 }
1300 }
1301
1302 for(const Node &node : treeData_.nodes) {
1303 if(node.isHidden())
1304 continue;
1305
1306 segmSeen.at(node.getVertexId()) = true;
1307 }
1308
1309 std::cout << "Segm missing : ";
1310 for(SimplexId v = 0; v < nbVert; v++) {
1311 if(!segmSeen[v]) {
1312 res = false;
1313 std::cout << v << ", ";
1314 }
1315 }
1316 std::cout << std::endl;
1317
1318 std::cout << "Nb visible Node : " << nbNodesVisible << std::endl;
1319 std::cout << "Nb visible Arcs : " << nbArcsVisible << std::endl;
1320 }
1321 return res;
1322 }
1323
1324 // }
1325 } // namespace cf
1326} // namespace ttk
#define DEBUG(msg)
Definition: Graph_Template.h:7
#define TTK_PSORT(NTHREADS,...)
Parallel sort macro.
Definition: OpenMP.h:46
int threadNumber_
Definition: BaseClass.h:95
Legacy backward compatibility.
Definition: Debug.h:472
int printMsg(const std::string &msg, const debug::Priority &priority=debug::Priority::INFO, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cout) const
Definition: Debug.h:118
int getNumberOfDownSuperArcs() const
Definition: ContourTree.h:182
int getDownSuperArcId(const int &neighborId) const
Definition: ContourTree.h:160
double getElapsedTime()
Definition: Timer.h:15
const ufDataType & getData() const
Definition: ExtendedUF.h:68
void setData(const ufDataType &d)
Definition: ExtendedUF.h:60
void setOrigin(const SimplexId &origin)
Definition: ExtendedUF.h:64
const SimplexId & getOrigin() const
Definition: ExtendedUF.h:72
static ExtendedUnionFind * makeUnion(ExtendedUnionFind *uf0, ExtendedUnionFind *uf1)
Definition: ExtendedUF.h:98
ExtendedUnionFind * find()
Definition: ExtendedUF.h:77
void hideArc(const idSuperArc &sa)
Definition: MergeTree.cpp:487
std::list< ExtendedUnionFind > storageEUF_
Definition: MergeTree.h:50
idNode makeNode(const SimplexId &vertexId, const SimplexId &linked=nullVertex)
Definition: MergeTree.cpp:516
Node * vertex2Node(const SimplexId &vert)
Definition: MergeTree.h:340
idNode getNumberOfNodes() const
Definition: MergeTree.h:235
idSuperArc openSuperArc(const idNode &downNodeId, const bool overlapB, const bool overlapA)
Definition: MergeTree.cpp:213
void sortInput()
if sortedVertices_ is null, define and fill it Also fill the mirror std::vector
int build(std::vector< ExtendedUnionFind * > &vect_baseUF, const std::vector< SimplexId > &overlapBefore, const std::vector< SimplexId > &overlapAfter, SimplexId start, SimplexId end, const SimplexId &posSeed0, const SimplexId &posSeed1, const triangulationType &mesh)
Compute the merge tree using Carr's algorithm.
std::string printArc(const idSuperArc &a)
Definition: MergeTree.h:580
SimplexId globalSimplify(const SimplexId posSeed0, const SimplexId posSeed1, std::list< std::vector< std::pair< SimplexId, bool > > > &storage, const triangulationType &mesh)
std::shared_ptr< Scalars > scalars_
Definition: MergeTree.h:44
void mergeArc(const idSuperArc &sa, const idSuperArc &recept, const bool changeConnectivity=true)
Definition: MergeTree.cpp:495
void markThisArc(std::vector< ExtendedUnionFind * > &ufArray, const idNode &curNodeId, const idSuperArc &mergingArcId, const idNode &parentNodeId)
Definition: MergeTree.cpp:1066
idSuperArc getNumberOfSuperArcs() const
Definition: MergeTree.h:183
void processVertex(const SimplexId &vertex, std::vector< ExtendedUnionFind * > &vect_baseUF, const bool overlapB, const bool overlapA, const triangulationType &mesh, DebugTimer &begin)
bool isCorrespondingNode(const SimplexId &val) const
Definition: MergeTree.h:298
SimplexId localSimplify(const SimplexId &podSeed0, const SimplexId &podSeed1, std::list< std::vector< std::pair< SimplexId, bool > > > &storage)
SimplexId simplifyTree(const SimplexId &posSeed0, const SimplexId &posSeed1, std::list< std::vector< std::pair< SimplexId, bool > > > &storage, const std::vector< std::tuple< SimplexId, SimplexId, scalarType, bool > > &sortedPairs)
idSuperArc makeSuperArc(const idNode &downNodeId, const idNode &upNodeId, const bool overlapB, const bool overlapA, std::pair< SimplexId, bool > *vertexList=nullptr, SimplexId vertexSize=-1)
Definition: MergeTree.cpp:232
std::string printNode(const idNode &n)
Definition: MergeTree.h:598
void updateCorrespondingArc(const SimplexId &arc, const idSuperArc &val)
Definition: MergeTree.h:348
bool isHigher(const SimplexId &a, const SimplexId &b) const
Definition: MergeTree.h:649
idNode getCorrespondingNodeId(const SimplexId &val) const
Definition: MergeTree.h:310
void closeSuperArc(const idSuperArc &superArcId, const idNode &upNodeId, const bool overlapB, const bool overlapA)
Definition: MergeTree.cpp:261
void flush()
clear local data for new computation
Definition: MergeTree.h:87
void hideNode(const idNode &node)
Definition: MergeTree.cpp:510
TreeData treeData_
Definition: MergeTree.h:47
int computePersistencePairs(std::vector< std::tuple< SimplexId, SimplexId, scalarType > > &pairs, const triangulationType &mesh)
bool isLower(const SimplexId &a, const SimplexId &b) const
Definition: MergeTree.h:645
void recoverMTPairs(const std::vector< idNode > &sortedNodes, std::vector< std::tuple< SimplexId, SimplexId, scalarType, bool > > &pairsJT, std::vector< std::tuple< SimplexId, SimplexId, scalarType, bool > > &pairsST, const triangulationType &mesh)
const std::vector< SuperArc > & getSuperArc() const
Definition: MergeTree.h:197
Node * getNode(const idNode &nodeId)
Definition: MergeTree.h:244
std::shared_ptr< Params > params_
Definition: MergeTree.h:43
SimplexId getVertexId() const
const SimplexId & getTermination() const
void removeDownSuperArc(const idSuperArc &idSa)
idSuperArc getDownSuperArcId(const idSuperArc &neighborId) const
void decDownValence()
idSuperArc getNumberOfUpSuperArcs() const
void setTermination(const SimplexId &linked)
void setOrigin(const SimplexId &linked)
void removeUpSuperArc(const idSuperArc &idSa)
idSuperArc getUpSuperArcId(const idSuperArc &neighborId) const
idSuperArc getNumberOfDownSuperArcs() const
const idNode & getUpNodeId() const
const idNode & getDownNodeId() const
T distance(const T *p0, const T *p1, const int &dimension=3)
Definition: Geometry.cpp:344
long unsigned int idSuperArc
SuperArc index in vect_superArcs_.
long int ufDataType
type stored by UnionFind
unsigned int idNode
Node index in vect_nodes_.
The Topology ToolKit.
int SimplexId
Identifier type for simplices of any dimension.
Definition: DataTypes.h:22
std::vector< idSuperArc > arcsCrossingAbove
std::vector< idNode > leaves
std::vector< Node > nodes
std::vector< SuperArc > superArcs
std::vector< idSuperArc > arcsCrossingBelow
std::vector< idNode > roots