TTK
Loading...
Searching...
No Matches
ContourTree.cpp
Go to the documentation of this file.
1#include <ContourTree.h>
2
3#include <cmath>
4#include <iomanip>
5#include <queue>
6#include <set>
7
8using namespace std;
9using namespace ttk;
10
11struct MyCmp {
12 const vector<double> *vertexScalars_;
13 const vector<int> *vertexOffsets_;
14 const vector<Node> *nodeList_;
16
17 MyCmp(const vector<double> *vertexScalars,
18 const vector<int> *vertexOffsets,
19 const vector<Node> *nodeList,
20 bool isAscendingOrder)
21 : vertexScalars_(vertexScalars), vertexOffsets_(vertexOffsets),
22 nodeList_(nodeList), isAscendingOrder_(isAscendingOrder) {
23 }
24
25 bool operator()(int node1, int node2) {
26 int const vertex1 = (*nodeList_)[node1].getVertexId();
27 int const vertex2 = (*nodeList_)[node2].getVertexId();
28 bool const cmp
29 = ((*vertexScalars_)[vertex1] < (*vertexScalars_)[vertex2])
30 || ((*vertexScalars_)[vertex1] == (*vertexScalars_)[vertex2]
31 && (*vertexOffsets_)[vertex1] < (*vertexOffsets_)[vertex2]);
33 return cmp;
34 else
35 return !cmp;
36 }
37};
38
40 bool operator()(const pair<bool, pair<double, pair<int, int>>> &v0,
41 const pair<bool, pair<double, pair<int, int>>> &v1) const {
42
43 if(v0.first) {
44 return ((v0.second.first < v1.second.first)
45 || ((v0.second.first == v1.second.first)
46 && (v0.second.second.first < v1.second.second.first)));
47 } else {
48 return ((v0.second.first > v1.second.first)
49 || ((v0.second.first == v1.second.first)
50 && (v0.second.second.first > v1.second.second.first)));
51 }
52 }
54
56 bool operator()(const pair<pair<int, int>, double> &p0,
57 const pair<pair<int, int>, double> &p1) {
58
59 return p0.second < p1.second;
60 }
61
63
65 _persistenceCmp3(const vector<double> *vertexScalars)
66 : vertexScalars_{vertexScalars} {
67 }
68
69 bool operator()(const pair<pair<int, int>, double> &p0,
70 const pair<pair<int, int>, double> &p1) {
71 return (*vertexScalars_)[p0.first.first]
72 > (*vertexScalars_)[p1.first.first];
73 }
74
75 const vector<double> *vertexScalars_;
76};
77
79 bool operator()(const pair<double, double> &p0,
80 const pair<double, double> &p1) {
81 return p0.first < p1.first;
82 }
84
85void SuperArc::smooth(const vector<Node> &nodeList,
86 const vector<vector<double>> *vertexPositions,
87 bool order) {
88 int const N = getNumberOfBarycenters();
89 if(N) {
91 vector<vector<double>> barycenterList(barycenterList_.size());
92 for(unsigned int i = 0; i < barycenterList.size(); ++i)
93 barycenterList[i].resize(3);
94
95 int up_vId;
96 int down_vId;
97 if(order) {
98 up_vId = nodeList[getUpNodeId()].getVertexId();
99 down_vId = nodeList[getDownNodeId()].getVertexId();
100 } else {
101 up_vId = nodeList[getDownNodeId()].getVertexId();
102 down_vId = nodeList[getUpNodeId()].getVertexId();
103 }
104
105 double p0[3];
106 double p1[3];
107 for(unsigned int k = 0; k < 3; ++k) {
108 p0[k] = (*vertexPositions)[down_vId][k];
109 p1[k] = (*vertexPositions)[up_vId][k];
110 }
111
113 if(N > 1) {
114 // first
115 for(unsigned int k = 0; k < 3; ++k)
116 barycenterList[0][k] = (p0[k] + barycenterList_[1][k]) * 0.5;
117
118 // main
119 for(int i = 1; i < N - 1; ++i) {
120 for(unsigned int k = 0; k < 3; ++k)
121 barycenterList[i][k]
122 = (barycenterList_[i - 1][k] + barycenterList_[i + 1][k]) * 0.5;
123 }
124 // last
125 for(unsigned int k = 0; k < 3; ++k)
126 barycenterList[N - 1][k] = (p1[k] + barycenterList_[N - 1][k]) * 0.5;
127 } else {
128 for(unsigned int k = 0; k < 3; ++k)
129 barycenterList[0][k] = (p0[k] + p1[k]) * 0.5;
130 }
131
133 for(int i = 0; i < N; ++i) {
134 for(unsigned int k = 0; k < 3; ++k)
135 barycenterList_[i][k] = barycenterList[i][k];
136 }
137 }
138}
139
140void SuperArc::sortRegularNodes(const vector<double> *vertexScalars,
141 const vector<int> *vertexOffsets,
142 const vector<Node> *nodeList,
143 bool order) {
144 MyCmp const cmp(vertexScalars, vertexOffsets, nodeList, order);
145
146 if(order)
147 std::sort(regularNodeList_.begin(), regularNodeList_.end(), cmp);
148 else
149 std::sort(regularNodeList_.rbegin(), regularNodeList_.rend(), cmp);
150}
151
153 const int &downVertexId,
154 const int &upVertexId,
155 const vector<int> &ttkNotUsed(interiorNodeIds)) {
156
157 if(!tree_)
158 return -DBL_MAX;
159
160 double downScalar = 0, upScalar = 0;
161
162 tree_->getVertexScalar(downVertexId, downScalar);
163 tree_->getVertexScalar(upVertexId, upScalar);
164
165 return fabs(upScalar - downScalar);
166}
167
169 this->setDebugMsgPrefix("SubLevelSetTree");
170}
171
172int SubLevelSetTree::appendRegularNode(const int &superArcId,
173 const int &nodeId) {
174
175 superArcList_[superArcId].appendRegularNode(nodeId);
176 vertex2superArc_[nodeList_[nodeId].getVertexId()] = superArcId;
177 vertex2superArcNode_[nodeList_[nodeId].getVertexId()]
178 = superArcList_[superArcId].getNumberOfRegularNodes() - 1;
179
180 // create a low level arc with the previous node
181 int nId = -1;
182 if(superArcList_[superArcId].getNumberOfRegularNodes() == 1) {
183 // the down neighbor is the arc extremity
184 nId = superArcList_[superArcId].getDownNodeId();
185 } else {
186 nId = superArcList_[superArcId].getRegularNodeId(
187 superArcList_[superArcId].getNumberOfRegularNodes() - 2);
188 }
189
190 makeArc(nId, nodeId);
191
192 return 0;
193}
194
196
197 Timer timer;
198
199 if(!vertexNumber_)
200 return -1;
201 if((!vertexScalars_) || ((int)vertexScalars_->size() != vertexNumber_))
202 return -2;
203 if((!vertexSoSoffsets_) || ((int)vertexSoSoffsets_->size() != vertexNumber_))
204 return -3;
205 // TODO uncomment after triangulation templatization
206 // if(triangulation_->isEmpty())
207 // return -4;
208 if((!minimumList_) && (!maximumList_))
209 return -5;
210 if((minimumList_) && (maximumList_))
211 return -6;
212
213 vector<UnionFind> seeds;
214 vector<vector<int>> seedSuperArcs;
215 vector<UnionFind *> vertexSeeds(vertexNumber_, (UnionFind *)nullptr);
216 vector<UnionFind *> starSets;
217 vector<bool> visitedVertices(vertexNumber_, false);
218
219 SimplexId vertexId = -1, nId = -1;
220 UnionFind *seed = nullptr, *firstUf = nullptr;
221
222 const vector<int> *extremumList = nullptr;
223
224 bool isMergeTree = true;
225
226 if(minimumList_) {
227 extremumList = minimumList_;
228 } else {
229 isMergeTree = false;
230 extremumList = maximumList_;
231 }
232
233 set<
234 // is merging
235 pair<bool,
236 // function value
237 pair<double,
238 // vertex offset
239 pair<int,
240 // vertex id
241 int>>>,
243 filtrationFront;
244
245 seeds.resize(extremumList->size());
246 seedSuperArcs.resize(seeds.size());
247
248 for(int i = 0; i < (int)extremumList->size(); i++) {
249 // link each minimum to a union find seed
250 vertexSeeds[(*extremumList)[i]] = &(seeds[i]);
251
252 // open an arc
253 seedSuperArcs[i].push_back(openSuperArc(makeNode((*extremumList)[i])));
254
255 // add each minimum to the filtration front
256 pair<bool, pair<double, pair<int, int>>> v;
257 v.first = isMergeTree;
258 v.second.first = (*vertexScalars_)[(*extremumList)[i]];
259 v.second.second.first = (*vertexSoSoffsets_)[(*extremumList)[i]];
260 v.second.second.second = (*extremumList)[i];
261
262 filtrationFront.insert(v);
263 }
264
265 bool merge = false;
266
267 // filtration loop
268 do {
269
270 vertexId = filtrationFront.begin()->second.second.second;
271 filtrationFront.erase(filtrationFront.begin());
272
273 starSets.clear();
274
275 merge = false;
276 firstUf = nullptr;
277
278 SimplexId const neighborNumber
280 for(SimplexId i = 0; i < neighborNumber; i++) {
281 triangulation_->getVertexNeighbor(vertexId, i, nId);
282
283 if(vertexSeeds[nId]) {
284 seed = vertexSeeds[nId]->find();
285 starSets.push_back(seed);
286
287 // is it merging things?
288 if(!firstUf)
289 firstUf = seed;
290 else if(seed != firstUf)
291 merge = true;
292 }
293
294 if(!visitedVertices[nId]) {
295
296 pair<bool, pair<double, pair<int, int>>> v;
297 v.first = isMergeTree;
298 v.second.first = (*vertexScalars_)[nId];
299 v.second.second.first = (*vertexSoSoffsets_)[nId];
300 v.second.second.second = nId;
301
302 filtrationFront.insert(v);
303 visitedVertices[nId] = true;
304 }
305 }
306
307 if(!vertexSeeds[vertexId]) {
308
309 vertexSeeds[vertexId] = UnionFind::makeUnion(starSets);
310
311 int const newNodeId = makeNode(vertexId);
312
313 if(merge) {
314
315 vector<int> seedIds;
316 for(int i = 0; i < (int)starSets.size(); i++) {
317 int const seedId = starSets[i] - &(seeds[0]);
318 bool found = false;
319 for(int j = 0; j < (int)seedIds.size(); j++) {
320 if(seedIds[j] == seedId) {
321 found = true;
322 break;
323 }
324 }
325 if(!found)
326 seedIds.push_back(seedId);
327 }
328
329 for(int i = 0; i < (int)seedIds.size(); i++) {
330 int const superArcId
331 = seedSuperArcs[seedIds[i]][seedSuperArcs[seedIds[i]].size() - 1];
332 closeSuperArc(superArcId, newNodeId);
333 }
334
335 int const seedId = vertexSeeds[vertexId] - &(seeds[0]);
336 if(!filtrationFront.empty())
337 seedSuperArcs[seedId].push_back(openSuperArc(newNodeId));
338 } else if(starSets.size()) {
339 // we're dealing with a degree-2 node
340 int const seedId = starSets[0] - &(seeds[0]);
341 int const superArcId
342 = seedSuperArcs[seedId][seedSuperArcs[seedId].size() - 1];
343
344 if(filtrationFront.empty()) {
345 // last vertex
346 closeSuperArc(superArcId, newNodeId);
347 } else {
349 appendRegularNode(superArcId, newNodeId);
350 }
351 }
352 }
353
354 visitedVertices[vertexId] = true;
355
356 } while(!filtrationFront.empty());
357
358 const std::string tree = isMergeTree ? "JoinTree" : "SplitTree";
359 this->printMsg(
360 tree + " computed", 1.0, timer.getElapsedTime(), this->threadNumber_);
361 this->printMsg(std::vector<std::vector<std::string>>{
362 {"#Nodes", std::to_string(getNumberOfNodes())},
363 {"#Arcs", std::to_string(getNumberOfArcs())}});
364
365 print();
366
367 return 0;
368}
369
370int SubLevelSetTree::clearArc(const int &vertexId0, const int &vertexId1) {
371
372 if((vertexId0 < 0) || (vertexId0 >= vertexNumber_))
373 return -1;
374 if((vertexId1 < 0) || (vertexId1 >= vertexNumber_))
375 return -2;
376
377 const int nodeId0 = vertex2node_[vertexId0],
378 nodeId1 = vertex2node_[vertexId1];
379
380 for(int i = 0; i < nodeList_[nodeId0].getNumberOfUpArcs(); i++) {
381 if(nodeList_[arcList_[nodeList_[nodeId0].getUpArcId(i)].getUpNodeId()]
382 .getVertexId()
383 == vertexId1) {
384 nodeList_[nodeId0].removeUpArcId(i);
385 break;
386 }
387 }
388
389 for(int i = 0; i < nodeList_[nodeId1].getNumberOfDownArcs(); i++) {
390 if(nodeList_[arcList_[nodeList_[nodeId1].getDownArcId(i)].getDownNodeId()]
391 .getVertexId()
392 == vertexId0) {
393 nodeList_[nodeId1].removeDownArcId(i);
394 break;
395 }
396 }
397
398 return 0;
399}
400
401int SubLevelSetTree::clearRegularNode(const int &vertexId) {
402
403 if((vertexId < 0) || (vertexId >= vertexNumber_))
404 return -1;
405
406 int const nodeId = vertex2node_[vertexId];
407
408 if(!((nodeList_[nodeId].getNumberOfDownArcs() == 1)
409 && (nodeList_[nodeId].getNumberOfUpArcs() == 1)))
410 return -2;
411
412 const int downArcId = nodeList_[nodeId].getDownArcId(0),
413 upArcId = nodeList_[nodeId].getUpArcId(0);
414
415 int const upNodeId = arcList_[upArcId].getUpNodeId();
416
417 // removes the arcs from the current node
418 nodeList_[nodeId].removeDownArcId(0);
419 nodeList_[nodeId].removeUpArcId(0);
420
421 // update the arc from the down node
422 arcList_[downArcId].setUpNodeId(upNodeId);
423
424 // remove the arc from the up node
425 for(int i = 0; i < nodeList_[upNodeId].getNumberOfDownArcs(); i++) {
426 if(nodeList_[upNodeId].getDownArcId(i) == upArcId) {
427 nodeList_[upNodeId].removeDownArcId(i);
428 break;
429 }
430 }
431 // and add the updated arc
432 nodeList_[upNodeId].addDownArcId(downArcId);
433
434 return 0;
435}
436
437int SubLevelSetTree::clearRoot(const int &vertexId) {
438
439 if((vertexId < 0) || (vertexId >= vertexNumber_))
440 return -1;
441
442 int const nodeId = vertex2node_[vertexId];
443
444 if((nodeList_[nodeId].getNumberOfDownArcs() == 1)
445 && (!nodeList_[nodeId].getNumberOfUpArcs())) {
446 clearArc(
447 nodeList_[arcList_[nodeList_[nodeId].getDownArcId(0)].getDownNodeId()]
448 .getVertexId(),
449 vertexId);
450 }
451
452 return 0;
453}
454
456 const int &pointId,
457 vector<int> &vertexIds,
458 const vector<float> *origin,
459 const vector<float> *voxelSize,
460 ofstream &o) {
461
462 vector<float> myOrigin(3), myVoxelSize(3);
463
464 if(origin) {
465 myOrigin = *(origin);
466 } else {
467 myOrigin[0] = myOrigin[1] = myOrigin[2] = 0;
468 }
469
470 if(voxelSize) {
471 myVoxelSize = *(voxelSize);
472 } else {
473 myVoxelSize[0] = myVoxelSize[1] = myVoxelSize[2] = 1;
474 }
475
476 double const offset = myVoxelSize[0];
477
478 vector<double> v;
479
480 int const downNodeId = superArcList_[arcId].downNodeId_;
481 int const upNodeId = superArcList_[arcId].upNodeId_;
482
483 v = (*vertexPositions_)[nodeList_[downNodeId].vertexId_];
484 // fix a bug in paraview
485 for(int i = 0; i < 3; i++) {
486 v[i] -= myOrigin[i];
487 v[i] /= myVoxelSize[i];
488 }
489 v[0] -= offset;
490 v[2] += offset;
491 o << v[0] << " " << v[1] << " " << v[2] << endl;
492 vertexIds.push_back(pointId);
493
494 v = (*vertexPositions_)[nodeList_[downNodeId].vertexId_];
495 // fix a bug in paraview
496 for(int i = 0; i < 3; i++) {
497 v[i] -= myOrigin[i];
498 v[i] /= myVoxelSize[i];
499 }
500 v[0] += offset;
501 v[2] += offset;
502 o << v[0] << " " << v[1] << " " << v[2] << endl;
503 vertexIds.push_back(pointId + 1);
504
505 v = (*vertexPositions_)[nodeList_[downNodeId].vertexId_];
506 // fix a bug in paraview
507 for(int i = 0; i < 3; i++) {
508 v[i] -= myOrigin[i];
509 v[i] /= myVoxelSize[i];
510 }
511 v[0] += offset;
512 v[2] -= offset;
513 o << v[0] << " " << v[1] << " " << v[2] << endl;
514 vertexIds.push_back(pointId + 2);
515
516 v = (*vertexPositions_)[nodeList_[downNodeId].vertexId_];
517 // fix a bug in paraview
518 for(int i = 0; i < 3; i++) {
519 v[i] -= myOrigin[i];
520 v[i] /= myVoxelSize[i];
521 }
522 v[0] -= offset;
523 v[2] -= offset;
524 o << v[0] << " " << v[1] << " " << v[2] << endl;
525 vertexIds.push_back(pointId + 3);
526
527 v = (*vertexPositions_)[nodeList_[upNodeId].vertexId_];
528 // fix a bug in paraview
529 for(int i = 0; i < 3; i++) {
530 v[i] -= myOrigin[i];
531 v[i] /= myVoxelSize[i];
532 }
533 v[0] -= offset;
534 v[2] += offset;
535 o << v[0] << " " << v[1] << " " << v[2] << endl;
536 vertexIds.push_back(pointId + 4);
537
538 v = (*vertexPositions_)[nodeList_[upNodeId].vertexId_];
539 // fix a bug in paraview
540 for(int i = 0; i < 3; i++) {
541 v[i] -= myOrigin[i];
542 v[i] /= myVoxelSize[i];
543 }
544 v[0] += offset;
545 v[2] += offset;
546 o << v[0] << " " << v[1] << " " << v[2] << endl;
547 vertexIds.push_back(pointId + 5);
548
549 v = (*vertexPositions_)[nodeList_[upNodeId].vertexId_];
550 // fix a bug in paraview
551 for(int i = 0; i < 3; i++) {
552 v[i] -= myOrigin[i];
553 v[i] /= myVoxelSize[i];
554 }
555 v[0] += offset;
556 v[2] -= offset;
557 o << v[0] << " " << v[1] << " " << v[2] << endl;
558 vertexIds.push_back(pointId + 6);
559
560 v = (*vertexPositions_)[nodeList_[upNodeId].vertexId_];
561 // fix a bug in paraview
562 for(int i = 0; i < 3; i++) {
563 v[i] -= myOrigin[i];
564 v[i] /= myVoxelSize[i];
565 }
566 v[0] -= offset;
567 v[2] -= offset;
568 o << v[0] << " " << v[1] << " " << v[2] << endl;
569 vertexIds.push_back(pointId + 7);
570
571 return 0;
572}
573
574int SubLevelSetTree::exportNodeColorToVtk(const int &nodeId, ofstream &o) {
575
576 for(int i = 0; i < 8; i++) {
577
578 if(!nodeList_[nodeId].downSuperArcList_.size()) {
579 // extremum
580 if(minimumList_) {
581 // minimum
582 o << "0 ";
583 } else {
584 o << "1 ";
585 }
586 } else if(!nodeList_[nodeId].upSuperArcList_.size()) {
587 if(minimumList_) {
588 // maximum
589 o << "1 ";
590 } else {
591 o << "0 ";
592 }
593 } else {
594 o << "0.5 ";
595 }
596 }
597
598 return 0;
599}
600
602 const int &pointId,
603 vector<int> &vertexIds,
604 const vector<float> *origin,
605 const vector<float> *voxelSize,
606 ofstream &o) {
607
608 vector<float> myOrigin(3), myVoxelSize(3);
609
610 if(origin) {
611 myOrigin = *(origin);
612 } else {
613 myOrigin[0] = myOrigin[1] = myOrigin[2] = 0;
614 }
615
616 if(voxelSize) {
617 myVoxelSize = *(voxelSize);
618 } else {
619 myVoxelSize[0] = myVoxelSize[1] = myVoxelSize[2] = 1;
620 }
621
622 double const offset = myVoxelSize[0];
623
624 vector<double> v;
625
626 v = (*vertexPositions_)[nodeList_[nodeId].vertexId_];
627 // fix a bug in paraview
628 for(int i = 0; i < 3; i++) {
629 v[i] -= myOrigin[i];
630 v[i] /= myVoxelSize[i];
631 }
632
633 v[0] -= offset;
634 v[1] -= offset;
635 v[2] -= offset;
636 o << v[0] << " " << v[1] << " " << v[2] << endl;
637 vertexIds.push_back(pointId);
638
639 v = (*vertexPositions_)[nodeList_[nodeId].vertexId_];
640 // fix a bug in paraview
641 for(int i = 0; i < 3; i++) {
642 v[i] -= myOrigin[i];
643 v[i] /= myVoxelSize[i];
644 }
645 v[0] += offset;
646 v[1] -= offset;
647 v[2] -= offset;
648 o << v[0] << " " << v[1] << " " << v[2] << endl;
649 vertexIds.push_back(pointId + 1);
650
651 v = (*vertexPositions_)[nodeList_[nodeId].vertexId_];
652 // fix a bug in paraview
653 for(int i = 0; i < 3; i++) {
654 v[i] -= myOrigin[i];
655 v[i] /= myVoxelSize[i];
656 }
657 v[0] += offset;
658 v[1] += offset;
659 v[2] -= offset;
660 o << v[0] << " " << v[1] << " " << v[2] << endl;
661 vertexIds.push_back(pointId + 2);
662
663 v = (*vertexPositions_)[nodeList_[nodeId].vertexId_];
664 // fix a bug in paraview
665 for(int i = 0; i < 3; i++) {
666 v[i] -= myOrigin[i];
667 v[i] /= myVoxelSize[i];
668 }
669 v[0] -= offset;
670 v[1] += offset;
671 v[2] -= offset;
672 o << v[0] << " " << v[1] << " " << v[2] << endl;
673 vertexIds.push_back(pointId + 3);
674
675 v = (*vertexPositions_)[nodeList_[nodeId].vertexId_];
676 // fix a bug in paraview
677 for(int i = 0; i < 3; i++) {
678 v[i] -= myOrigin[i];
679 v[i] /= myVoxelSize[i];
680 }
681 v[0] -= offset;
682 v[1] -= offset;
683 v[2] += offset;
684 o << v[0] << " " << v[1] << " " << v[2] << endl;
685 vertexIds.push_back(pointId + 4);
686
687 v = (*vertexPositions_)[nodeList_[nodeId].vertexId_];
688 // fix a bug in paraview
689 for(int i = 0; i < 3; i++) {
690 v[i] -= myOrigin[i];
691 v[i] /= myVoxelSize[i];
692 }
693 v[0] += offset;
694 v[1] -= offset;
695 v[2] += offset;
696 o << v[0] << " " << v[1] << " " << v[2] << endl;
697 vertexIds.push_back(pointId + 5);
698
699 v = (*vertexPositions_)[nodeList_[nodeId].vertexId_];
700 // fix a bug in paraview
701 for(int i = 0; i < 3; i++) {
702 v[i] -= myOrigin[i];
703 v[i] /= myVoxelSize[i];
704 }
705 v[0] += offset;
706 v[1] += offset;
707 v[2] += offset;
708 o << v[0] << " " << v[1] << " " << v[2] << endl;
709 vertexIds.push_back(pointId + 6);
710
711 v = (*vertexPositions_)[nodeList_[nodeId].vertexId_];
712 // fix a bug in paraview
713 for(int i = 0; i < 3; i++) {
714 v[i] -= myOrigin[i];
715 v[i] /= myVoxelSize[i];
716 }
717 v[0] -= offset;
718 v[1] += offset;
719 v[2] += offset;
720 o << v[0] << " " << v[1] << " " << v[2] << endl;
721 vertexIds.push_back(pointId + 7);
722
723 return 0;
724}
725
726int SubLevelSetTree::exportPersistenceCurve(const string &fileName) const {
727 vector<pair<double, int>> persistencePlot;
728
729 getPersistencePlot(persistencePlot);
730
731 ofstream file(fileName.data(), ios::out);
732
733 if(!file) {
734 return -1;
735 }
736
737 for(int i = 0; i < (int)persistencePlot.size(); i++) {
738
739 file << setprecision(REAL_SIGNIFICANT_DIGITS) << persistencePlot[i].first
740 << " " << persistencePlot[i].second << endl;
741 }
742
743 file.close();
744
745 return 0;
746}
747
748int SubLevelSetTree::exportPersistenceDiagram(const string &fileName) const {
749
750 vector<pair<double, double>> diagram;
751
752 getPersistenceDiagram(diagram);
753
754 ofstream file(fileName.data(), ios::out);
755
756 if(!file) {
757 return -1;
758 }
759
760 for(int i = 0; i < (int)diagram.size(); i++) {
761 file << setprecision(REAL_SIGNIFICANT_DIGITS) << diagram[i].first << " "
762 << diagram[i].first << endl;
763 file << setprecision(REAL_SIGNIFICANT_DIGITS) << diagram[i].first << " "
764 << diagram[i].second << endl;
765 file << setprecision(REAL_SIGNIFICANT_DIGITS) << diagram[i].first << " "
766 << diagram[i].first << endl;
767 }
768
769 file.close();
770
771 return 0;
772}
773
774int SubLevelSetTree::exportToSvg(const string &fileName,
775 const double &scaleX,
776 const double &scaleY) {
777
778 Timer t;
779
780 if(!vertexScalars_)
781 return -1;
782
783 bool const hasLayout = buildPlanarLayout(scaleX, scaleY);
784
785 // put the root right above the highest saddle
786 double minY = -1, maxY = -1;
787 for(int i = 0; i < (int)superArcList_.size(); i++) {
788 const SuperArc *a = &(superArcList_[i]);
789 const Node *n = &(nodeList_[a->getDownNodeId()]);
790 if((!i) || (minY > n->layoutY_)) {
791 minY = n->layoutY_;
792 }
793 if((!i) || (maxY < n->layoutY_)) {
794 maxY = n->layoutY_;
795 }
796
797 n = &(nodeList_[a->getUpNodeId()]);
798 if((!i) || (minY > n->layoutY_)) {
799 minY = n->layoutY_;
800 }
801 if((!i) || (maxY < n->layoutY_)) {
802 maxY = n->layoutY_;
803 }
804 }
805
806 for(int i = 0; i < (int)superArcList_.size(); i++) {
807 const SuperArc *a = &(superArcList_[i]);
808 Node *upNode = &(nodeList_[a->getUpNodeId()]);
809 Node *downNode = &(nodeList_[a->getDownNodeId()]);
810
811 if(!upNode->getNumberOfUpSuperArcs()) {
812 // root
813 if(minimumList_) {
814 // join tree
815 upNode->layoutY_
816 = 0.4 * (downNode->layoutY_ - minY) + downNode->layoutY_;
817 break;
818 }
819 if(maximumList_) {
820 // split tree
821 upNode->layoutY_
822 = downNode->layoutY_ - 0.4 * (maxY - downNode->layoutY_);
823 break;
824 }
825 }
826 }
827
828 string const dotFileName = fileName + ".dot";
829
830 ofstream dotFile(dotFileName.data(), ios::out);
831
832 if(!dotFile) {
833 this->printErr("Could not open file `" + dotFileName + "'!");
834 return -2;
835 }
836
837 dotFile << "digraph \"";
838 if(minimumList_)
839 dotFile << "Join";
840 else
841 dotFile << "Split";
842 dotFile << " Tree\"{" << endl;
843
844 double minValue = 0, maxValue = 0;
845 for(int i = 0; i < (int)vertexScalars_->size(); i++) {
846 if((!i) || (minValue > (*vertexScalars_)[i])) {
847 minValue = (*vertexScalars_)[i];
848 }
849 if((!i) || (maxValue < (*vertexScalars_)[i])) {
850 maxValue = (*vertexScalars_)[i];
851 }
852 }
853
854 // super-arc first!
855 for(int i = 0; i < (int)superArcList_.size(); i++) {
856
857 if(!superArcList_[i].pruned_) {
858
859 int const downNodeId = superArcList_[i].getDownNodeId();
860 int const upNodeId = superArcList_[i].getUpNodeId();
861
862 dotFile << " \"f = ";
863 dotFile << (*vertexScalars_)[nodeList_[downNodeId].vertexId_];
864 if(vertexPositions_) {
865 dotFile << "\\n p = ("
866 << (*vertexPositions_)[nodeList_[downNodeId].vertexId_][0]
867 << " "
868 << (*vertexPositions_)[nodeList_[downNodeId].vertexId_][1]
869 << " "
870 << (*vertexPositions_)[nodeList_[downNodeId].vertexId_][2]
871 << ")";
872 }
873 dotFile << "\" -> \"f = ";
874 dotFile << (*vertexScalars_)[nodeList_[upNodeId].vertexId_];
875 if(vertexPositions_) {
876 dotFile << "\\n p = ("
877 << (*vertexPositions_)[nodeList_[upNodeId].vertexId_][0] << " "
878 << (*vertexPositions_)[nodeList_[upNodeId].vertexId_][1] << " "
879 << (*vertexPositions_)[nodeList_[upNodeId].vertexId_][2] << ")";
880 }
881 dotFile << "\"" << endl;
882 }
883 }
884
885 for(int i = 0; i < (int)nodeList_.size(); i++) {
886
887 if((nodeList_[i].downSuperArcList_.size())
888 || (nodeList_[i].upSuperArcList_.size())) {
889 // not a regular node
890 if(!nodeList_[i].pruned_) {
891 dotFile << " \"f = ";
892 dotFile << (*vertexScalars_)[nodeList_[i].vertexId_];
893 if(vertexPositions_) {
894 dotFile << "\\n p = ("
895 << (*vertexPositions_)[nodeList_[i].vertexId_][0] << " "
896 << (*vertexPositions_)[nodeList_[i].vertexId_][1] << " "
897 << (*vertexPositions_)[nodeList_[i].vertexId_][2] << ")";
898 }
899 dotFile << "\" [";
900
901 // properties
902 if(minimumList_) {
903 // join tree
904
905 // color
906 if(!nodeList_[i].upSuperArcList_.size()) {
907 // global maximum --> green
908 dotFile << "fillcolor=green,";
909 } else if(!nodeList_[i].downSuperArcList_.size()) {
910 // minimum --> blue
911 dotFile << "fillcolor=blue,fontcolor=white,";
912 } else {
913 dotFile << "fillcolor=lightyellow,shape=diamond,";
914 }
915
916 } else {
917 // split tree
918
919 // color
920 if(!nodeList_[i].upSuperArcList_.size()) {
921 // global minimum --> blue
922 dotFile << "fillcolor=blue,fontcolor=white,";
923 } else if(!nodeList_[i].downSuperArcList_.size()) {
924 // maximum --> green
925 dotFile << "fillcolor=green,";
926 } else {
927 dotFile << "fillcolor=lightyellow,shape=diamond,";
928 }
929 }
930
931 dotFile << "style=filled,";
932
933 if(hasLayout) {
934 dotFile << "pos=\"" << nodeList_[i].layoutX_ << ", "
935 << nodeList_[i].layoutY_ << "!\"";
936 }
937
938 dotFile << "]";
939
940 dotFile << endl;
941 }
942 }
943 }
944
945 dotFile << "}" << endl;
946
947 dotFile.close();
948
949 stringstream commandLine;
950 commandLine << "dot -Kneato -Tsvg " << dotFileName << " -o " << fileName
951 << " &> /dev/null";
952 this->printMsg("Calling GraphViz to generate the SVG file.");
953 this->printMsg("This may take a long time...");
954
955 int const cmdRet = system(commandLine.str().data());
956
957 if((!cmdRet) || (cmdRet == 256)) {
958 this->printMsg(
959 "Output file `" + fileName + "' generated", 1.0, t.getElapsedTime(), 1);
960 } else {
961 this->printErr("Could not find the `GraphViz' package!");
962 this->printErr("Please install it and re-run this program.");
963 }
964
965 // OsCall::rmFile(dotFileName);
966
967 return 0;
968}
969
970int SubLevelSetTree::exportToVtk(const string &fileName,
971 const vector<float> *origin,
972 const vector<float> *voxelSize) {
973
974 if(!vertexScalars_)
975 return -1;
976
978 return -2;
979
980 ofstream o(fileName.data(), ios::out);
981
982 if(!o) {
983 this->printErr("Could not open file `" + fileName + "'!");
984 return -3;
985 }
986
987 int superArcNumber = 0;
988 int nodeNumber = 0;
989 for(int i = 0; i < (int)superArcList_.size(); i++) {
990 if(!superArcList_[i].pruned_) {
991 superArcNumber++;
992 }
993 }
994 nodeNumber = superArcNumber + 1;
995
996 int pointNumber = 0, cellNumber = 0;
997 pointNumber = 8 * nodeNumber + 8 * superArcNumber;
998 cellNumber = nodeNumber + superArcNumber;
999
1000 vector<bool> nodeColorOut(nodeList_.size(), false);
1001 vector<bool> nodePosOut(nodeList_.size(), false);
1002 vector<bool> nodeMeshOut(nodeList_.size(), false);
1003 vector<vector<int>> nodeIds(nodeList_.size());
1004 vector<vector<int>> arcIds(superArcList_.size());
1005
1006 o << "<?xml version=\"1.0\"?>" << endl;
1007 o << "<VTKFile type=\"UnstructuredGrid\" version=\"0.1\""
1008 << " byte_order=\"LittleEndian\">" << endl;
1009 o << " <UnstructuredGrid>" << endl;
1010 o << " <Piece NumberOfPoints=\"" << pointNumber << "\" NumberOfCells=\""
1011 << cellNumber << "\">";
1012 o << " <PointData Scalars=\"Color Code\">" << endl;
1013 o << " <DataArray type=\"Float32\" Name=\"Critical Color\""
1014 << " format=\"ascii\" NumberOfComponents=\"1\">" << endl;
1015
1016 // node color
1017 for(int i = 0; i < (int)superArcList_.size(); i++) {
1018 if(!superArcList_[i].pruned_) {
1019 int const downNodeId = superArcList_[i].downNodeId_;
1020 int const upNodeId = superArcList_[i].upNodeId_;
1021
1022 if(!nodeColorOut[downNodeId]) {
1023 o << " ";
1024 exportNodeColorToVtk(downNodeId, o);
1025 o << endl;
1026 nodeColorOut[downNodeId] = true;
1027 }
1028 if(!nodeColorOut[upNodeId]) {
1029 o << " ";
1030 exportNodeColorToVtk(upNodeId, o);
1031 o << endl;
1032 nodeColorOut[upNodeId] = true;
1033 }
1034 }
1035 }
1036
1037 // arc color
1038 for(int i = 0; i < (int)superArcList_.size(); i++) {
1039 if(!superArcList_[i].pruned_) {
1040 o << "\t\t\t\t\t";
1041 for(int j = 0; j < 8; j++) {
1042 o << "2 ";
1043 }
1044 o << endl;
1045 }
1046 }
1047 o << " </DataArray>" << endl;
1048 o << " </PointData>" << endl;
1049
1050 // node position
1051
1052 o << " <Points>" << endl;
1053 o << " <DataArray type=\"Float32\" NumberOfComponents=\"3\""
1054 << " format=\"ascii\">" << endl;
1055
1056 int pointId = 0;
1057 for(int i = 0; i < (int)superArcList_.size(); i++) {
1058 if(!superArcList_[i].pruned_) {
1059 int const downNodeId = superArcList_[i].downNodeId_;
1060 int const upNodeId = superArcList_[i].upNodeId_;
1061
1062 if(!nodePosOut[downNodeId]) {
1063 o << " ";
1065 downNodeId, pointId, nodeIds[downNodeId], origin, voxelSize, o);
1066 nodePosOut[downNodeId] = true;
1067 o << endl;
1068 pointId += 8;
1069 }
1070 if(!nodePosOut[upNodeId]) {
1071 o << " ";
1073 upNodeId, pointId, nodeIds[upNodeId], origin, voxelSize, o);
1074 nodePosOut[upNodeId] = true;
1075 o << endl;
1076 pointId += 8;
1077 }
1078 }
1079 }
1080 for(int i = 0; i < (int)superArcList_.size(); i++) {
1081 if(!superArcList_[i].pruned_) {
1082 o << " ";
1083 exportArcPosToVtk(i, pointId, arcIds[i], origin, voxelSize, o);
1084 o << endl;
1085 pointId += 8;
1086 }
1087 }
1088 o << " </DataArray>" << endl;
1089 o << " </Points>" << endl;
1090
1091 // cells now
1092 o << " <Cells>" << endl;
1093
1094 o << " <DataArray type=\"Int32\" Name=\"connectivity\""
1095 << " format=\"ascii\">" << endl;
1096
1097 for(int i = 0; i < (int)superArcList_.size(); i++) {
1098 if(!superArcList_[i].pruned_) {
1099 int const downNodeId = superArcList_[i].downNodeId_;
1100 int const upNodeId = superArcList_[i].upNodeId_;
1101
1102 if(!nodeMeshOut[downNodeId]) {
1103 o << " " << nodeIds[downNodeId][0] << " "
1104 << nodeIds[downNodeId][1] << " " << nodeIds[downNodeId][2] << " "
1105 << nodeIds[downNodeId][3] << " " << nodeIds[downNodeId][4] << " "
1106 << nodeIds[downNodeId][5] << " " << nodeIds[downNodeId][6] << " "
1107 << nodeIds[downNodeId][7] << endl;
1108 nodeMeshOut[downNodeId] = true;
1109 }
1110 if(!nodeMeshOut[upNodeId]) {
1111 o << " " << nodeIds[upNodeId][0] << " " << nodeIds[upNodeId][1]
1112 << " " << nodeIds[upNodeId][2] << " " << nodeIds[upNodeId][3] << " "
1113 << nodeIds[upNodeId][4] << " " << nodeIds[upNodeId][5] << " "
1114 << nodeIds[upNodeId][6] << " " << nodeIds[upNodeId][7] << endl;
1115 nodeMeshOut[upNodeId] = true;
1116 }
1117 }
1118 }
1119 for(int i = 0; i < (int)superArcList_.size(); i++) {
1120 if(!superArcList_[i].pruned_) {
1121 o << " " << arcIds[i][0] << " " << arcIds[i][1] << " "
1122 << arcIds[i][2] << " " << arcIds[i][3] << " " << arcIds[i][4] << " "
1123 << arcIds[i][5] << " " << arcIds[i][6] << " " << arcIds[i][7] << endl;
1124 }
1125 }
1126
1127 o << " </DataArray>" << endl;
1128
1129 o << " <DataArray type=\"Int32\" Name=\"offsets\""
1130 << " format=\"ascii\">" << endl;
1131 pointId = 8;
1132 for(int i = 0; i < nodeNumber; i++) {
1133 o << " " << pointId << endl;
1134 pointId += 8;
1135 }
1136 for(int i = 0; i < superArcNumber; i++) {
1137 o << " " << pointId << endl;
1138 pointId += 8;
1139 }
1140 o << " </DataArray>" << endl;
1141
1142 o << " <DataArray type=\"Int32\" Name=\"types\""
1143 << " format=\"ascii\">" << endl;
1144 for(int i = 0; i < nodeNumber; i++) {
1145 o << " 12" << endl;
1146 }
1147 for(int i = 0; i < superArcNumber; i++) {
1148 o << " 12" << endl;
1149 }
1150 o << " </DataArray>" << endl;
1151
1152 o << " </Cells>" << endl;
1153 o << " </Piece>" << endl;
1154 o << " </UnstructuredGrid>" << endl;
1155 o << "</VTKFile>" << endl;
1156 o.close();
1157
1158 return 0;
1159}
1160
1162
1163 nodeList_.clear();
1164 arcList_.clear();
1165 superArcList_.clear();
1166 vertex2node_.clear();
1167 vertex2superArc_.clear();
1168 vertex2superArcNode_.clear();
1169
1170 vertex2node_.resize(vertexNumber_, -1);
1171 vertex2superArc_.resize(vertexNumber_, -1);
1173
1174 return 0;
1175}
1176
1177int SubLevelSetTree::buildExtremumList(vector<int> &extremumList,
1178 const bool &isSubLevelSet) {
1179
1180 // TODO uncomment after triangulation templatization
1181 if((!triangulation_) /*|| triangulation_->isEmpty()*/)
1182 return -1;
1183
1184 if((!vertexScalars_) || (!vertexScalars_->size()))
1185 return -2;
1186
1187 if((!vertexSoSoffsets_) || (!vertexSoSoffsets_->size()))
1188 return -3;
1189
1190 vector<pair<bool, pair<double, pair<int, int>>>> tmpList;
1191
1192 for(SimplexId i = 0; i < triangulation_->getNumberOfVertices(); i++) {
1193
1194 bool isExtremum = true;
1195 SimplexId const neighborNumber = triangulation_->getVertexNeighborNumber(i);
1196 for(SimplexId j = 0; j < neighborNumber; j++) {
1197 SimplexId otherId = -1;
1198 triangulation_->getVertexNeighbor(i, j, otherId);
1199
1200 if(isSubLevelSet) {
1201 // looking for minima
1202 if(isSosHigherThan(i, otherId)) {
1203 // not a minimum then
1204 isExtremum = false;
1205 break;
1206 }
1207 } else {
1208 // looking for maxima
1209 if(!isSosHigherThan(i, otherId)) {
1210 // not a maximum then
1211 isExtremum = false;
1212 break;
1213 }
1214 }
1215 }
1216 if(isExtremum) {
1217 pair<bool, pair<double, pair<int, int>>> entry;
1218 entry.first = isSubLevelSet;
1219 entry.second.first = (*vertexScalars_)[i];
1220 entry.second.second.first = (*vertexSoSoffsets_)[i];
1221 entry.second.second.second = i;
1222 tmpList.push_back(entry);
1223 }
1224 }
1225
1226 sort(tmpList.begin(), tmpList.end(), filtrationCmp);
1227
1228 extremumList.resize(tmpList.size());
1229 for(int i = 0; i < (int)extremumList.size(); i++) {
1230 extremumList[i] = tmpList[i].second.second.second;
1231 }
1232
1233 if(isSubLevelSet) {
1234 minimumList_ = &(extremumList);
1235 } else {
1236 maximumList_ = &(extremumList);
1237 }
1238
1239 return 0;
1240}
1241
1242int SubLevelSetTree::closeSuperArc(const int &superArcId, const int &nodeId) {
1243
1244 if((superArcId < 0) || (superArcId >= (int)superArcList_.size()))
1245 return -1;
1246
1247 if((nodeId < 0) || (nodeId >= (int)nodeList_.size()))
1248 return -2;
1249
1250 superArcList_[superArcId].setUpNodeId(nodeId);
1251
1252 nodeList_[nodeId].addDownSuperArcId(superArcId);
1253
1254 // create a low level arc with the previous node
1255 int nId = -1;
1256 if(!superArcList_[superArcId].getNumberOfRegularNodes()) {
1257 // the down neighbor is the arc extremity
1258 nId = superArcList_[superArcId].getDownNodeId();
1259 } else {
1260 nId = superArcList_[superArcId].getRegularNodeId(
1261 superArcList_[superArcId].getNumberOfRegularNodes() - 1);
1262 }
1263
1264 makeArc(nId, nodeId);
1265
1266 return 0;
1267}
1268
1270 vector<pair<double, double>> &diagram,
1271 vector<pair<pair<int, int>, double>> *pairs) const {
1272
1273 vector<pair<pair<int, int>, double>> defaultPairs{};
1274 if(!pairs) {
1275 pairs = &defaultPairs;
1276 }
1277
1278 if(!pairs->size())
1279 getPersistencePairs(*pairs);
1280
1281 // fast fix :(
1282 diagram.resize(pairs->size());
1283
1284 for(int i = 0; i < (int)pairs->size(); i++) {
1285 if((maximumList_) && (!minimumList_)) {
1286 // split tree
1287 diagram[i].second = (*vertexScalars_)[(*pairs)[i].first.first];
1288 diagram[i].first = (*vertexScalars_)[(*pairs)[i].first.second];
1289 } else {
1290 // join tree or contour tree
1291 diagram[i].first = (*vertexScalars_)[(*pairs)[i].first.first];
1292 diagram[i].second = (*vertexScalars_)[(*pairs)[i].first.second];
1293 }
1294 }
1295
1296 std::sort(diagram.begin(), diagram.end(), _pPairCmp);
1297
1298 return 0;
1299}
1300
1302 vector<pair<pair<int, int>, double>> &pairs,
1303 std::vector<std::pair<std::pair<int, int>, double>> *ttkNotUsed(mergePairs),
1304 std::vector<std::pair<std::pair<int, int>, double>> *ttkNotUsed(
1305 splitPairs)) const {
1306
1307 Timer t;
1308
1309 if(!superArcList_.size())
1310 return -1;
1311
1312 bool isMergeTree = true;
1313
1314 vector<int> *extremumList = minimumList_;
1315 if(!extremumList) {
1316 extremumList = maximumList_;
1317 isMergeTree = false;
1318 }
1319 if(!extremumList)
1320 return -2;
1321
1322 pairs.resize(extremumList->size());
1323
1324 vector<int> min2arc(vertexNumber_, -1);
1325
1326 // compute the initial persistence
1327 int leafId = 0;
1328 for(int i = 0; i < getNumberOfSuperArcs(); ++i) {
1329 const SuperArc *a = getSuperArc(i);
1330 const Node *n = getNode(a->getDownNodeId());
1331 int const nodeId = n->getVertexId();
1332
1333 if(!n->getNumberOfDownSuperArcs()) {
1334 // internal, split trees and merges trees have their leaves at the bottom
1335 double extremumScalar = 0;
1336 double saddleScalar = 0;
1337 int const saddleId = getNode(a->getUpNodeId())->getVertexId();
1338
1339 extremumScalar = (*vertexScalars_)[nodeId];
1340 saddleScalar = (*vertexScalars_)[saddleId];
1341
1342 pairs[leafId].first.first = nodeId;
1343 pairs[leafId].first.second = saddleId;
1344 pairs[leafId].second = fabs(saddleScalar - extremumScalar);
1345 float const persistence = pairs[leafId].second;
1346 if(isnan(persistence))
1347 pairs[leafId].second = 0;
1348
1349 // save that in the map
1350 min2arc[nodeId] = i;
1351 leafId++;
1352 }
1353 }
1354
1355 // sort the pairs and start the processing
1356 sort(pairs.begin(), pairs.end(), _pCmp);
1357
1358 vector<int> pairedSaddles(vertexNumber_, 0);
1359 // now start the pairing...
1360 for(unsigned int i = 0; i < pairs.size(); ++i) {
1361 pairedSaddles[pairs[i].first.second]++;
1362
1363 // now update the persistence of all others
1364 for(unsigned int j = i + 1; j < pairs.size(); ++j) {
1365 if((pairs[j].first.second == pairs[i].first.second)
1366 && (pairedSaddles[pairs[i].first.second] + 1
1367 == (getVertexNode(pairs[i].first.second))
1368 ->getNumberOfDownSuperArcs())) {
1369 // that pair contains a minimum competing with our guy
1370 // and the saddle is fully paired
1371
1372 const SuperArc *a = getSuperArc(min2arc[pairs[j].first.first]);
1373 do {
1375 break;
1376
1377 int const nextArcId = getNode(a->getUpNodeId())->getUpSuperArcId(0);
1378 a = getSuperArc(nextArcId);
1379
1380 if(a) {
1381 int const saddleId = getNode(a->getUpNodeId())->getVertexId();
1383 break;
1384
1385 if(pairedSaddles[saddleId]
1386 < (getVertexNode(saddleId))->getNumberOfDownSuperArcs() - 1) {
1387
1388 double extremumScalar = 0;
1389 double saddleScalar = 0;
1390
1391 extremumScalar = (*vertexScalars_)[pairs[j].first.first];
1392 saddleScalar = (*vertexScalars_)[saddleId];
1393 pairs[j].first.second = saddleId;
1394 pairs[j].second = fabs(saddleScalar - extremumScalar);
1395 float const persistence = pairs[j].second;
1396 if(isnan(persistence))
1397 pairs[j].second = 0;
1398 break;
1399 }
1400 }
1401 } while(a);
1402
1403 if(a) {
1404 // we indeed update the persistence of the competitor
1405 sort(pairs.begin() + j, pairs.end(), _pCmp);
1406 }
1407
1408 break;
1409 }
1410 }
1411 }
1412
1413 // the last entry should have infinite persistence
1414 // pairs.erase(pairs.end() - 1);
1415
1416 // let's pair the global maximum with the global min
1417 for(int i = 0; i < getNumberOfSuperArcs(); i++) {
1418 const SuperArc *a = getSuperArc(i);
1419 const Node *up = getNode(a->getUpNodeId());
1420 if(!up->getNumberOfUpSuperArcs()) {
1421 // global min
1422 pairs.back().first.second = up->getVertexId();
1423 pairs.back().second
1424 = fabs((*vertexScalars_)[pairs.back().first.first]
1425 - (*vertexScalars_)[pairs.back().first.second]);
1426 float const persistence = pairs.back().second;
1427 if(isnan(persistence))
1428 pairs.back().second = 0;
1429 break;
1430 }
1431 }
1432
1433 std::string const pairtype = isMergeTree ? "(0-1)" : "(1-2)";
1434 std::string const pairextr = isMergeTree ? "min" : "max";
1435
1436 this->printMsg(
1437 std::vector<std::vector<std::string>>{
1438 {"#" + pairtype + " pairs", std::to_string(pairs.size())}},
1440 for(const auto &p : pairs) {
1441 this->printMsg(
1442 std::vector<std::vector<std::string>>{
1443 {"#" + pairextr, std::to_string(p.first.first)},
1444 {"#saddles", std::to_string(p.first.second)},
1445 {"Persistence", std::to_string(p.second)}},
1447 }
1448
1449 this->printMsg(std::to_string(pairs.size()) + " persistence pairs computed",
1450 1.0, t.getElapsedTime(), this->threadNumber_);
1451
1452 return 0;
1453}
1454
1456 vector<pair<double, int>> &plot,
1457 vector<pair<pair<int, int>, double>> *persistencePairs) const {
1458
1459 vector<pair<pair<int, int>, double>> defaultPersistencePairs{};
1460 if(!persistencePairs) {
1461 persistencePairs = &defaultPersistencePairs;
1462 }
1463
1464 if(!persistencePairs->size())
1465 getPersistencePairs(*persistencePairs);
1466
1467 plot.resize(persistencePairs->size());
1468
1469 for(int i = 0; i < (int)plot.size(); i++) {
1470 plot[i].first = (*persistencePairs)[i].second;
1471 if(plot[i].first < Geometry::powIntTen(-REAL_SIGNIFICANT_DIGITS)) {
1473 }
1474 plot[i].second = persistencePairs->size() - i;
1475 }
1476
1477 return 0;
1478}
1479
1480bool SubLevelSetTree::buildPlanarLayout(const double &scaleX,
1481 const double &scaleY) {
1482
1483 if((minimumList_) && (maximumList_)) {
1484 this->printErr("Contour tree planar layout not implemented.");
1485 this->printErr("Planar layout is only implemented for merge-trees.");
1486 return false;
1487 }
1488
1489 if((!vertexScalars_) || (!vertexScalars_->size()))
1490 return false;
1491
1492 // global dimansions [0,1]x[0,1]
1493
1494 // 1) set the y coordinate for everyone
1495 for(int i = 0; i < (int)superArcList_.size(); i++) {
1496 int const downNodeId = superArcList_[i].downNodeId_;
1497 int const upNodeId = superArcList_[i].upNodeId_;
1498
1499 nodeList_[downNodeId].layoutY_
1500 = ((*vertexScalars_)[nodeList_[downNodeId].vertexId_] - minScalar_)
1501 / (maxScalar_ - minScalar_);
1502
1503 nodeList_[upNodeId].layoutY_
1504 = ((*vertexScalars_)[nodeList_[upNodeId].vertexId_] - minScalar_)
1505 / (maxScalar_ - minScalar_);
1506 }
1507
1508 // 2) for each node count the number of leaves under it
1509 // --> start a front from the leaves and increment a table
1510 vector<bool> inFront(nodeList_.size(), false);
1511 vector<int> node2LeafNumber(nodeList_.size(), 0);
1512 // use the same data-structure for front propagation
1513 set<pair<bool, pair<double, pair<int, int>>>, filtrationCtCmp> front;
1514
1515 // 2a) start from the leaves
1516 for(int i = 0; i < (int)superArcList_.size(); i++) {
1517
1518 if(!superArcList_[i].pruned_) {
1519
1520 int const downNodeId = superArcList_[i].downNodeId_;
1521 if(!nodeList_[downNodeId].downSuperArcList_.size()) {
1522 pair<bool, pair<double, pair<int, int>>> n;
1523 n.first = (minimumList_ ? true : false);
1524 n.second.first = (*vertexScalars_)[nodeList_[downNodeId].vertexId_];
1525 n.second.second.first
1526 = (*vertexSoSoffsets_)[nodeList_[downNodeId].vertexId_];
1527 n.second.second.second = nodeList_[downNodeId].vertexId_;
1528 front.insert(n);
1529
1530 node2LeafNumber[downNodeId] = 1;
1531 inFront[downNodeId] = true;
1532 }
1533 }
1534 }
1535
1536 // filtration loop
1537 do {
1538
1539 int const vertexId = front.begin()->second.second.second;
1540 front.erase(front.begin());
1541
1542 int const nodeId = vertex2node_[vertexId];
1543
1544 // retrieve the number of leaves given by its children
1545 for(int i = 0; i < (int)nodeList_[nodeId].downSuperArcList_.size(); i++) {
1546 int const arcId = nodeList_[nodeId].downSuperArcList_[i];
1547 int const childId = superArcList_[arcId].downNodeId_;
1548
1549 node2LeafNumber[nodeId] += node2LeafNumber[childId];
1550 }
1551
1552 // add its parents to the front
1553 for(int i = 0; i < (int)nodeList_[nodeId].upSuperArcList_.size(); i++) {
1554 int const arcId = nodeList_[nodeId].upSuperArcList_[i];
1555 int const parentId = superArcList_[arcId].upNodeId_;
1556
1557 if(!inFront[parentId]) {
1558 pair<bool, pair<double, pair<int, int>>> n;
1559 n.first = (minimumList_ ? true : false);
1560 n.second.first = (*vertexScalars_)[nodeList_[parentId].vertexId_];
1561 n.second.second.first
1562 = (*vertexSoSoffsets_)[nodeList_[parentId].vertexId_];
1563 n.second.second.second = nodeList_[parentId].vertexId_;
1564 front.insert(n);
1565
1566 node2LeafNumber[parentId] = 0;
1567 inFront[parentId] = true;
1568 }
1569 }
1570
1571 } while(!front.empty());
1572
1573 // 3) start from the node below the root, these two guys have the same x
1574 // each node has its X coordinate given by a ratio
1575
1576 // let's find the root
1577 int rootId = -1;
1578 int subRootId = -1;
1579
1580 for(int i = 0; i < (int)superArcList_.size(); i++) {
1581 if(!superArcList_[i].pruned_) {
1582 int const upNodeId = superArcList_[i].upNodeId_;
1583 if(!nodeList_[upNodeId].upSuperArcList_.size()) {
1584 // that's it
1585 rootId = upNodeId;
1586 break;
1587 }
1588 }
1589 }
1590
1591 // in theory, the root has exactly one arc below it
1592 subRootId = superArcList_[nodeList_[rootId].downSuperArcList_[0]].downNodeId_;
1593
1594 // now start the recursion
1595 vector<pair<double, double>> nodeInterval(
1596 nodeList_.size(), pair<double, double>(0, 1));
1597 queue<int> nodeQueue;
1598
1599 // printf("pushing root: %f\n",
1600 // (*vertexScalars_)[nodeList_[rootId].vertexId_]);
1601 nodeQueue.push(rootId);
1602
1603 do {
1604
1605 int const nodeId = nodeQueue.front();
1606 nodeQueue.pop();
1607
1608 // get the number of leaves of the first child
1609 double ratio = 0.5;
1610
1611 if((nodeList_[nodeId].downSuperArcList_.size()) && (nodeId != subRootId)
1612 && (nodeId != rootId)) {
1613
1614 int const arcId = nodeList_[nodeId].downSuperArcList_[0];
1615 int const childId = superArcList_[arcId].downNodeId_;
1616
1617 ratio = node2LeafNumber[childId] / ((double)node2LeafNumber[nodeId]);
1618 if(ratio > 1)
1619 ratio = 1;
1620 }
1621
1622 // printf("node %f: [%f-%f] r=%f l=%d\n",
1623 // (*vertexScalars_)[nodeList_[nodeId].vertexId_],
1624 // nodeInterval[nodeId].first, nodeInterval[nodeId].second, ratio,
1625 // node2LeafNumber[nodeId]);
1626 nodeList_[nodeId].layoutX_
1627 = nodeInterval[nodeId].first
1628 + ratio * (nodeInterval[nodeId].second - nodeInterval[nodeId].first);
1629 if(nodeList_[nodeId].layoutX_ > 1) {
1630 nodeList_[nodeId].layoutX_ = 1;
1631 }
1632
1633 // pass the right interval to the children and add them to the queue
1634 double xOffset = 0;
1635 for(int i = 0; i < (int)nodeList_[nodeId].downSuperArcList_.size(); i++) {
1636 int const arcId = nodeList_[nodeId].downSuperArcList_[i];
1637 int const childId = superArcList_[arcId].downNodeId_;
1638
1639 ratio = node2LeafNumber[childId] / ((double)node2LeafNumber[nodeId]);
1640 if(ratio > 1)
1641 ratio = 1;
1642
1643 nodeInterval[childId].first = nodeInterval[nodeId].first + xOffset;
1644 nodeInterval[childId].second
1645 = nodeInterval[childId].first
1646 + ratio * (nodeInterval[nodeId].second - nodeInterval[nodeId].first);
1647 xOffset = nodeInterval[childId].second;
1648
1649 nodeQueue.push(childId);
1650 }
1651
1652 } while(!nodeQueue.empty());
1653
1654 // test
1655 // for(int i = 0; i < (int) superArcList_.size(); i++){
1656 // if(!superArcList_[i].pruned_){
1657 // Node *downNode = &(nodeList_[superArcList_[i].getDownNodeId()]);
1658 // printf("node %f --> %fx%f\n",
1659 // (*vertexScalars_)[downNode->vertexId_],
1660 // downNode->layoutX_, downNode->layoutY_);
1661 // }
1662 // }
1663 //
1664
1665 for(int i = 0; i < (int)nodeList_.size(); i++) {
1666 nodeList_[i].layoutX_ *= 30 * scaleX;
1667 nodeList_[i].layoutY_ *= 1000 * scaleY;
1668 }
1669
1670 return true;
1671}
1672
1673int SubLevelSetTree::buildSaddleList(vector<int> &vertexList) const {
1674
1675 vertexList.clear();
1676
1677 for(int i = 0; i < (int)superArcList_.size(); i++) {
1678 const Node *down = &(nodeList_[superArcList_[i].getDownNodeId()]);
1679
1680 if(down->getNumberOfDownSuperArcs()) {
1681 vertexList.push_back(down->getVertexId());
1682 }
1683 }
1684
1685 return 0;
1686}
1687
1688int SubLevelSetTree::makeArc(const int &nodeId0, const int &nodeId1) {
1689
1690 if((nodeId0 < 0) || (nodeId0 >= (int)nodeList_.size()))
1691 return -1;
1692 if((nodeId1 < 0) || (nodeId1 >= (int)nodeList_.size()))
1693 return -2;
1694
1695 arcList_.resize(arcList_.size() + 1);
1696 arcList_[arcList_.size() - 1].setDownNodeId(nodeId0);
1697 arcList_[arcList_.size() - 1].setUpNodeId(nodeId1);
1698
1699 nodeList_[nodeId0].addUpArcId((int)arcList_.size() - 1);
1700 nodeList_[nodeId1].addDownArcId((int)arcList_.size() - 1);
1701
1702 return (int)arcList_.size() - 1;
1703}
1704
1705int SubLevelSetTree::makeNode(const int &vertexId) {
1706
1707 if((vertexId < 0) || (vertexId >= vertexNumber_))
1708 return -1;
1709
1710 if(vertex2node_[vertexId] == -1) {
1711 nodeList_.resize(nodeList_.size() + 1);
1712 nodeList_[nodeList_.size() - 1].setVertexId(vertexId);
1713
1714 vertex2node_[vertexId] = (int)nodeList_.size() - 1;
1715
1716 return (int)nodeList_.size() - 1;
1717 }
1718
1719 return vertex2node_[vertexId];
1720}
1721
1722int SubLevelSetTree::openSuperArc(const int &nodeId) {
1723
1724 if((nodeId < 0) || (nodeId >= (int)nodeList_.size()))
1725 return -1;
1726
1727 superArcList_.resize(superArcList_.size() + 1);
1728 superArcList_[superArcList_.size() - 1].setDownNodeId(nodeId);
1729
1730 nodeList_[nodeId].addUpSuperArcId((int)superArcList_.size() - 1);
1731
1732 return (int)superArcList_.size() - 1;
1733}
1734
1735bool SubLevelSetTree::isSosHigherThan(const int &vertexId0,
1736 const int &vertexId1) const {
1737
1738 return (((*vertexScalars_)[vertexId0] > (*vertexScalars_)[vertexId1])
1739 || (((*vertexScalars_)[vertexId0] == (*vertexScalars_)[vertexId1])
1740 && ((*vertexSoSoffsets_)[vertexId0]
1741 > (*vertexSoSoffsets_)[vertexId1])));
1742}
1743
1744bool SubLevelSetTree::isSosLowerThan(const int &vertexId0,
1745 const int &vertexId1) const {
1746
1747 return (((*vertexScalars_)[vertexId0] < (*vertexScalars_)[vertexId1])
1748 || (((*vertexScalars_)[vertexId0] == (*vertexScalars_)[vertexId1])
1749 && ((*vertexSoSoffsets_)[vertexId0]
1750 < (*vertexSoSoffsets_)[vertexId1])));
1751}
1752
1754 const Node *oldDown,
1755 const Node *oldUp,
1756 const Node *newDown,
1757 const Node *newUp) {
1758
1759 int arcId = -1;
1760 int const nodeId = n - &(nodeList_[0]);
1761
1762 // remove n from oldDown and oldUp and update n
1763 for(int i = 0; i < oldUp->getNumberOfDownArcs(); i++) {
1764 arcId = oldUp->getDownArcId(i);
1765 if(arcList_[arcId].getDownNodeId() == nodeId) {
1766 arcList_[arcId].setDownNodeId(oldDown - &(nodeList_[0]));
1767 break;
1768 }
1769 }
1770 for(int i = 0; i < n->getNumberOfUpArcs(); i++) {
1771 if(arcId == n->getUpArcId(i)) {
1772 nodeList_[nodeId].removeUpArcId(i);
1773 break;
1774 }
1775 }
1776
1777 for(int i = 0; i < oldDown->getNumberOfUpArcs(); i++) {
1778 if(arcList_[oldDown->getUpArcId(i)].getUpNodeId() == nodeId) {
1779 nodeList_[oldDown - &(nodeList_[0])].removeUpArcId(i);
1780 nodeList_[oldDown - &(nodeList_[0])].addUpArcId(arcId);
1781 break;
1782 }
1783 }
1784 for(int i = 0; i < n->getNumberOfDownArcs(); i++) {
1785 if(arcList_[n->getDownArcId(i)].getDownNodeId()
1786 == (oldDown - &(nodeList_[0]))) {
1787 nodeList_[nodeId].removeDownArcId(i);
1788 break;
1789 }
1790 }
1791
1792 // disconnect newDown and newUp
1793 if(newUp) {
1794 for(int i = 0; i < newDown->getNumberOfUpArcs(); i++) {
1795 arcId = newDown->getUpArcId(i);
1796 if(arcList_[arcId].getUpNodeId() == (newUp - &(nodeList_[0]))) {
1797 nodeList_[newDown - &(nodeList_[0])].removeUpArcId(i);
1798 break;
1799 }
1800 }
1801 for(int i = 0; i < newUp->getNumberOfDownArcs(); i++) {
1802 if(newUp->getDownArcId(i) == arcId) {
1803 nodeList_[newUp - &(nodeList_[0])].removeDownArcId(i);
1804 break;
1805 }
1806 }
1807 }
1808
1809 makeArc(newDown - &(nodeList_[0]), n - &(nodeList_[0]));
1810 if(newUp)
1811 makeArc(n - &(nodeList_[0]), newUp - &(nodeList_[0]));
1812
1813 return 0;
1814}
1815
1817
1818 stringstream const msg;
1819
1820 this->printMsg(
1821 "Node list (" + std::to_string(getNumberOfNodes()) + " nodes):",
1823
1824 int minCount = 0, saddleCount = 0, maxCount = 0, regularCount = 0;
1825
1826 for(int i = 0; i < getNumberOfNodes(); i++) {
1827 const Node *n = getNode(i);
1828
1829 if(vertex2superArc_[n->getVertexId()] == -1) {
1830 // regular node
1831
1832 this->printMsg(
1833 std::vector<std::vector<std::string>>{
1834 {"Id", std::to_string(i), "VertId", std::to_string(n->getVertexId()),
1838
1839 if(!n->getNumberOfDownSuperArcs())
1840 minCount++;
1841 else if(!n->getNumberOfUpSuperArcs())
1842 maxCount++;
1843 else
1844 saddleCount++;
1845 }
1846 }
1847
1848 this->printMsg(
1849 "Arc list (" + std::to_string(getNumberOfSuperArcs()) + " arcs):",
1851
1852 for(int i = 0; i < getNumberOfSuperArcs(); i++) {
1853 const SuperArc *a = getSuperArc(i);
1854
1855 const Node *down = getNode(a->getDownNodeId()),
1856 *up = getNode(a->getUpNodeId());
1857 if((up) && (down)) {
1858
1859 this->printMsg(
1860 std::vector<std::vector<std::string>>{
1861 {"Id", std::to_string(i), "D",
1863 std::to_string(up->getNumberOfUpSuperArcs()), "V",
1866 } else {
1867 this->printErr("Arc inconsistency! " + std::to_string(a->getDownNodeId())
1868 + "->" + std::to_string(a->getUpNodeId()));
1869 }
1870
1871 for(int j = 0; j < a->getNumberOfRegularNodes(); j++) {
1872 this->printMsg(
1873 std::vector<std::vector<std::string>>{
1874 {"Regular vertex",
1875 std::to_string(nodeList_[a->getRegularNodeId(j)].getVertexId())}},
1877 }
1878
1879 regularCount += a->getNumberOfRegularNodes();
1880 }
1881
1882 this->printMsg(
1883 std::vector<std::vector<std::string>>{
1884 {"#Minima", std::to_string(minCount)},
1885 {"#Saddles", std::to_string(saddleCount)},
1886 {"#Maxima", std::to_string(maxCount)},
1887 {"#Regular", std::to_string(regularCount)},
1888 {"#Sum",
1889 std::to_string(minCount + saddleCount + maxCount + regularCount)},
1890 {"#Input vertices", std::to_string(vertexNumber_)},
1891 },
1893
1894 return 0;
1895}
1896
1897int SubLevelSetTree::simplify(const double &simplificationThreshold,
1899
1900 Timer t;
1901
1902 // if((simplificationThreshold < 0)||(simplificationThreshold > 1))
1903 // return -1;
1904
1905 PersistenceMetric defaultMetric;
1906
1907 if(metric == nullptr) {
1908 metric = &defaultMetric;
1909 }
1910
1911 metric->tree_ = this;
1912
1913 // double unNormalizedThreshold = simplificationThreshold
1914 // * (maxScalar_ - minScalar_);
1915
1916 if(!nodeList_.size())
1917 return -2;
1918
1919 if(!superArcList_.size())
1920 return -3;
1921
1922 if((minimumList_) && (maximumList_)) {
1923 this->printErr("Contour tree simplification not implemented.");
1924 this->printErr("Simplification is only implemented for merge-trees.");
1925 return -4;
1926 }
1927
1928 int simplifiedArcNumber = 0;
1929 double maximumMetricScore = 0;
1930
1931 if(!originalNodeList_.size()) {
1932 // first time we simplify
1935 } else {
1936 // not the first time
1939 }
1940
1941 if(!simplificationThreshold)
1942 return 0;
1943
1944 // if(!unNormalizedThreshold) return -4;
1945
1946 vector<pair<real, int>> const regularNodeList;
1947
1948 int arcToSimplify = -1;
1949 double currentScore = 0, minScore;
1950
1951 do {
1952
1953 arcToSimplify = -1;
1954 minScore = 1.1 * (maxScalar_ - minScalar_);
1955
1956 // search for an elligible arc.
1957 for(int i = 0; i < (int)superArcList_.size(); i++) {
1958
1959 if(!superArcList_[i].pruned_) {
1960
1961 int const downNodeId = superArcList_[i].downNodeId_;
1962 int const upNodeId = superArcList_[i].upNodeId_;
1963
1964 if(!nodeList_[downNodeId].downSuperArcList_.size()) {
1965
1966 currentScore = metric->computeSuperArcMetric(
1967 nodeList_[downNodeId].vertexId_, nodeList_[upNodeId].vertexId_,
1968 superArcList_[i].regularNodeList_);
1969
1970 if((currentScore < 0) || (currentScore > (maxScalar_ - minScalar_))) {
1971 this->printWrn("Out-of-range score! (user-defined metric)");
1972 } else {
1973 if(currentScore < minScore) {
1974 arcToSimplify = i;
1975 minScore = currentScore;
1976 }
1977 }
1978 }
1979 }
1980 }
1981
1982 if(minScore > simplificationThreshold)
1983 break;
1984
1985 if(minScore > maximumMetricScore)
1986 maximumMetricScore = minScore;
1987
1988 if(arcToSimplify == -1)
1989 break;
1990
1991 // perform the simplification
1992 int const downNodeId = superArcList_[arcToSimplify].downNodeId_;
1993 int const upNodeId = superArcList_[arcToSimplify].upNodeId_;
1994
1995 int pivotId = upNodeId;
1996 int leafId = downNodeId;
1997
1998 if(!nodeList_[downNodeId].downSuperArcList_.size()) {
1999 // remove an extremum
2000 pivotId = upNodeId;
2001 leafId = downNodeId;
2002 }
2003
2004 bool const isSimpleSaddle = (nodeList_[pivotId].downSuperArcList_.size()
2005 + nodeList_[pivotId].upSuperArcList_.size()
2006 == 3);
2007
2008 int brotherId = 0;
2009
2010 for(int i = 0; i < (int)nodeList_[pivotId].downSuperArcList_.size(); i++) {
2011 if(nodeList_[pivotId].downSuperArcList_[i] != arcToSimplify) {
2012 brotherId = nodeList_[pivotId].downSuperArcList_[i];
2013 break;
2014 }
2015 }
2016
2017 int const brotherExtremityId = superArcList_[brotherId].downNodeId_;
2018
2019 int const parentId = nodeList_[pivotId].upSuperArcList_[0];
2020
2021 // 1) update the parent extremity (only if simple saddles)
2022 if(isSimpleSaddle) {
2023 superArcList_[parentId].downNodeId_ = brotherExtremityId;
2024 }
2025
2026 // 2) tell the brotherExtremityId that it's no longer linked to the
2027 // brother but to the parent
2028 if(isSimpleSaddle) {
2029 for(int i = 0;
2030 i < (int)nodeList_[brotherExtremityId].upSuperArcList_.size(); i++) {
2031 if(nodeList_[brotherExtremityId].upSuperArcList_[i] == brotherId) {
2032 nodeList_[brotherExtremityId].upSuperArcList_[i] = parentId;
2033 break;
2034 }
2035 }
2036 } else {
2037 // multi-saddle, we need to erase arcToSimplify from the pivot
2038 for(int i = 0; i < (int)nodeList_[pivotId].downSuperArcList_.size();
2039 i++) {
2040 if(nodeList_[pivotId].downSuperArcList_[i] == arcToSimplify) {
2041 nodeList_[pivotId].downSuperArcList_.erase(
2042 nodeList_[pivotId].downSuperArcList_.begin() + i);
2043 break;
2044 }
2045 }
2046 }
2047
2048 // 3) do the merging
2049 if(isSimpleSaddle) {
2050 // copy the regular nodes of the brother into the parent
2051 superArcList_[parentId].regularNodeList_.insert(
2052 superArcList_[parentId].regularNodeList_.end(),
2053 superArcList_[brotherId].regularNodeList_.begin(),
2054 superArcList_[brotherId].regularNodeList_.end());
2055
2056 // copy the regular nodes of the arcToSimplify into the parent
2057 superArcList_[parentId].regularNodeList_.insert(
2058 superArcList_[parentId].regularNodeList_.end(),
2059 superArcList_[arcToSimplify].regularNodeList_.begin(),
2060 superArcList_[arcToSimplify].regularNodeList_.end());
2061
2062 // add the pivot
2063 superArcList_[parentId].regularNodeList_.push_back(pivotId);
2064
2065 // add the leaf
2066 superArcList_[parentId].regularNodeList_.push_back(leafId);
2067
2068 // NOTE: optionally, the list of regular nodes could be sorted
2069
2070 // mark the brother as pruned
2071 superArcList_[brotherId].pruned_ = true;
2072 nodeList_[pivotId].pruned_ = true;
2073 simplifiedArcNumber++;
2074 } else {
2075 // just merge with the first brother we found....
2076 superArcList_[brotherId].regularNodeList_.insert(
2077 superArcList_[brotherId].regularNodeList_.end(),
2078 superArcList_[arcToSimplify].regularNodeList_.begin(),
2079 superArcList_[arcToSimplify].regularNodeList_.end());
2080
2081 // add the leaf
2082 superArcList_[brotherId].regularNodeList_.push_back(leafId);
2083 }
2084 superArcList_[arcToSimplify].pruned_ = true;
2085 nodeList_[leafId].pruned_ = true;
2086 simplifiedArcNumber++;
2087
2088 } while(minScore < simplificationThreshold);
2089
2090 // sort the regular nodes
2091 Timer sortTimer;
2092 for(int i = 0; i < getNumberOfSuperArcs(); ++i) {
2093 if(!superArcList_[i].pruned_) {
2094 superArcList_[i].sortRegularNodes(
2096 }
2097 }
2098
2099 this->printMsg("Regular node sorting", 1.0, sortTimer.getElapsedTime(),
2100 this->threadNumber_);
2101
2102 this->printMsg(std::to_string(simplifiedArcNumber)
2103 + " super-arcs pruned (threshold="
2104 + std::to_string(simplificationThreshold) + ")",
2105 1.0, t.getElapsedTime(), this->threadNumber_);
2106
2107 this->printMsg(
2108 "Biggest simplification metric score: " + std::to_string(maximumMetricScore)
2109 + " ("
2110 + std::to_string(maximumMetricScore * 100 / (maxScalar_ - minScalar_))
2111 + "%)");
2112
2113 return 0;
2114}
2115
2117 vector<int> sample;
2118 vector<double> barycenter(3);
2119 int vertexId;
2120
2121 const SuperArc *a;
2122 for(int i = 0; i < getNumberOfSuperArcs(); ++i) {
2123 a = getSuperArc(i);
2124 if(!a->isPruned()) {
2125 for(int j = 0; j < a->getNumberOfSamples(); ++j) {
2126 a->getSample(j, sample);
2127
2128 for(unsigned int k = 0; k < 3; ++k)
2129 barycenter[k] = 0;
2130
2131 for(unsigned int k = 0; k < sample.size(); ++k) {
2132 vertexId = getNode(sample[k])->getVertexId();
2133
2134 for(unsigned int l = 0; l < 3; ++l)
2135 barycenter[l] += (*vertexPositions_)[vertexId][l];
2136 }
2137 if(sample.size()) {
2138 for(unsigned int k = 0; k < 3; ++k)
2139 barycenter[k] /= sample.size();
2140
2141 // update the arc
2142 superArcList_[i].appendBarycenter(barycenter);
2143 }
2144 }
2145 }
2146 }
2147
2148 return 0;
2149}
2150
2152 const vector<double> &scalars,
2153 vector<vector<double>> &skeletonScalars) const {
2154 skeletonScalars.clear();
2155 skeletonScalars.resize(getNumberOfSuperArcs());
2156
2157 vector<int> sample;
2158 int nodeId;
2159 int vertexId;
2160
2161 double f;
2162 double f0;
2163 double f1;
2164 double fmin;
2165 double fmax;
2166 int nodeMinId;
2167 int nodeMaxId;
2168 int nodeMinVId;
2169 int nodeMaxVId;
2170 const SuperArc *a;
2171 for(int i = 0; i < getNumberOfSuperArcs(); ++i) {
2172 a = getSuperArc(i);
2173
2174 if(!a->isPruned()) {
2175 if(maximumList_ && !minimumList_) {
2176 nodeMinId = a->getUpNodeId();
2177 nodeMaxId = a->getDownNodeId();
2178 } else {
2179 nodeMaxId = a->getUpNodeId();
2180 nodeMinId = a->getDownNodeId();
2181 }
2182
2183 nodeMaxVId = getNode(nodeMaxId)->getVertexId();
2184 nodeMinVId = getNode(nodeMinId)->getVertexId();
2185
2186 fmax = scalars[nodeMaxVId];
2187 fmin = scalars[nodeMinVId];
2188
2189 // init: min
2190 f0 = fmin;
2191
2192 // iteration
2193 for(int j = 0; j < a->getNumberOfSamples(); ++j) {
2194 a->getSample(j, sample);
2195
2196 f = 0;
2197 for(unsigned int k = 0; k < sample.size(); ++k) {
2198 nodeId = sample[k];
2199 vertexId = getNode(nodeId)->getVertexId();
2200 f += scalars[vertexId];
2201 }
2202 if(sample.size()) {
2203 f /= sample.size();
2204
2205 f1 = f;
2206 // update the arc
2207 skeletonScalars[i].push_back((f0 + f1) / 2);
2208 f0 = f1;
2209 }
2210 }
2211
2212 // end: max
2213 f1 = fmax;
2214
2215 // update the arc
2216 skeletonScalars[i].push_back((f0 + f1) / 2);
2217 }
2218 }
2219
2220 return 0;
2221}
2222
2223int SubLevelSetTree::computeSkeleton(unsigned int arcResolution) {
2224 sample(arcResolution);
2226
2227 isSkeletonComputed_ = true;
2228 return 0;
2229}
2230
2231int SubLevelSetTree::smoothSkeleton(unsigned int skeletonSmoothing) {
2232 for(unsigned int i = 0; i < skeletonSmoothing; ++i) {
2233 for(int j = 0; j < getNumberOfSuperArcs(); ++j) {
2234 if(!superArcList_[j].isPruned()) {
2235 if(minimumList_)
2236 superArcList_[j].smooth(nodeList_, vertexPositions_, true);
2237 else
2238 superArcList_[j].smooth(nodeList_, vertexPositions_, false);
2239 }
2240 }
2241 }
2242
2243 return 0;
2244}
2245
2246int SubLevelSetTree::sample(unsigned int samplingLevel) {
2247 vector<vector<int>> sampleList(samplingLevel);
2248
2249 const SuperArc *a;
2250 for(int i = 0; i < getNumberOfSuperArcs(); ++i) {
2251 a = getSuperArc(i);
2252
2253 if(!a->isPruned()) {
2254
2255 for(unsigned int j = 0; j < samplingLevel; ++j)
2256 sampleList[j].clear();
2257
2258 double fmax, fmin;
2259 int nodeMaxId, nodeMinId;
2260 int nodeMaxVId, nodeMinVId;
2261 double delta;
2262 if(a->getNumberOfRegularNodes()) {
2263 if(minimumList_) {
2264 nodeMaxId = a->getUpNodeId();
2265 nodeMinId = a->getDownNodeId();
2266 } else {
2267 nodeMaxId = a->getDownNodeId();
2268 nodeMinId = a->getUpNodeId();
2269 }
2270
2271 nodeMaxVId = getNode(nodeMaxId)->getVertexId();
2272 nodeMinVId = getNode(nodeMinId)->getVertexId();
2273
2274 fmax = (*vertexScalars_)[nodeMaxVId];
2275 fmin = (*vertexScalars_)[nodeMinVId];
2276
2277 delta = (fmax - fmin) / samplingLevel;
2278
2279 double f;
2280 int nodeId;
2281 int vertexId;
2282 for(int j = 0; j < a->getNumberOfRegularNodes(); ++j) {
2283 nodeId = a->getRegularNodeId(j);
2284 vertexId = getNode(nodeId)->getVertexId();
2285 f = (*vertexScalars_)[vertexId];
2286
2287 for(unsigned int k = 0; k < samplingLevel; ++k) {
2288 if(f <= (k + 1) * delta + fmin) {
2289 sampleList[k].push_back(nodeId);
2290 break;
2291 }
2292 }
2293 }
2294
2295 // update the arc
2296 for(unsigned int j = 0; j < sampleList.size(); ++j)
2297 superArcList_[i].appendSample(sampleList[j]);
2298 }
2299 }
2300 }
2301
2302 return 0;
2303}
2304
2306 for(int j = 0; j < getNumberOfSuperArcs(); ++j) {
2307 superArcList_[j].clearBarycenters();
2308 superArcList_[j].clearSamples();
2309 }
2310
2311 return 0;
2312}
2313
2315 this->setDebugMsgPrefix("ContourTree");
2316}
2317
2319
2320 Timer timer;
2321
2322 if(!vertexNumber_)
2323 return -1;
2324 if((!vertexScalars_) || ((int)vertexScalars_->size() != vertexNumber_))
2325 return -2;
2327 return -3;
2328
2331
2332 std::vector<int> localVertSoSoffsets{};
2333
2334 // 0) init data structures
2335 if(!externalOffsets_) {
2336 vertexSoSoffsets_ = &localVertSoSoffsets;
2338 for(int i = 0; i < (int)vertexSoSoffsets_->size(); i++)
2339 (*vertexSoSoffsets_)[i] = i;
2340 }
2341
2342 // build the actual extrema list
2343
2344 std::vector<int> minimumVec, maximumVec;
2345 minimumList_ = &minimumVec;
2346 maximumList_ = &maximumVec;
2347
2348 for(int i = 0; i < vertexNumber_; i++) {
2349
2350 bool isMin = true, isMax = true;
2351 SimplexId const neighborNumber = triangulation_->getVertexNeighborNumber(i);
2352 for(SimplexId j = 0; j < neighborNumber; j++) {
2353 SimplexId nId = -1;
2355
2356 if(((*vertexScalars_)[nId] > (*vertexScalars_)[i])
2357 || (((*vertexScalars_)[nId] == (*vertexScalars_)[i])
2358 && ((*vertexSoSoffsets_)[nId] > (*vertexSoSoffsets_)[i])))
2359 isMax = false;
2360
2361 if(((*vertexScalars_)[nId] < (*vertexScalars_)[i])
2362 || (((*vertexScalars_)[nId] == (*vertexScalars_)[i])
2363 && ((*vertexSoSoffsets_)[nId] < (*vertexSoSoffsets_)[i])))
2364 isMin = false;
2365
2366 if((!isMin) && (!isMax))
2367 break;
2368 }
2369
2370 if((isMin) && (!isMax))
2371 minimumList_->push_back(i);
2372 if((isMax) && (!isMin))
2373 maximumList_->push_back(i);
2374 }
2375
2376#ifdef TTK_ENABLE_OPENMP
2377#pragma omp parallel sections
2378#endif
2379 {
2380
2381#ifdef TTK_ENABLE_OPENMP
2382#pragma omp section
2383#endif
2384 {
2385 // 1) build the merge tree
2392 mergeTree_.build();
2393 }
2394
2395#ifdef TTK_ENABLE_OPENMP
2396#pragma omp section
2397#endif
2398 {
2399 // 2) build the split tree
2406 splitTree_.build();
2407 }
2408 }
2409
2410 // note: at this point, the split tree is laid out upside down.
2411
2412 // 3) merge the two trees into the contour tree
2413 combineTrees();
2414
2415 // 4) update the high level super arc structure
2416 finalize();
2417
2418 this->printMsg("ContourTree computed", 1.0, timer.getElapsedTime());
2419
2420 this->printMsg(std::vector<std::vector<std::string>>{
2421 {"#Nodes", std::to_string(getNumberOfNodes())},
2422 {"#Arcs", std::to_string(getNumberOfArcs())}});
2423
2424 print();
2425
2426 return 0;
2427}
2428
2430
2431 Timer timer;
2432
2434 return -1;
2435
2436 queue<const Node *> nodeQueue;
2437 const Node *mergeNode = nullptr, *splitNode = nullptr;
2438
2439 do {
2440
2441 int const initQueueSize = (int)nodeQueue.size();
2442
2443 for(int i = 0; i < mergeTree_.getNumberOfNodes(); i++) {
2444 mergeNode = mergeTree_.getNode(i);
2445 if(isNodeEligible(mergeNode)) {
2446 nodeQueue.push(mergeNode);
2447 }
2448 }
2449 for(int i = 0; i < splitTree_.getNumberOfNodes(); i++) {
2450 splitNode = splitTree_.getNode(i);
2451 if(isNodeEligible(splitNode)) {
2452 nodeQueue.push(splitNode);
2453 }
2454 }
2455
2456 // no more eligible nodes
2457 if((int)nodeQueue.size() == initQueueSize)
2458 break;
2459
2460 const Node *n0 = nullptr, *n1 = nullptr, *other = nullptr;
2461
2462 do {
2463
2464 n0 = nodeQueue.front();
2465 nodeQueue.pop();
2466
2467#ifndef TTK_ENABLE_KAMIKAZE
2468 if(n0 == nullptr) {
2469 continue;
2470 }
2471#endif // TTK_ENABLE_KAMIKAZE
2472
2473 if((mergeTree_.getNode(n0 - mergeTree_.getNode(0)) == n0)
2474 && (isNodeEligible(n0))) {
2475 // merge node
2476 // get the corresponding split node
2477 other = splitTree_.getVertexNode(n0->getVertexId());
2478
2479 if(!((other->getNumberOfUpArcs())
2480 && (other->getNumberOfDownArcs() > 1))) {
2481
2482 n1 = nullptr;
2483
2484 if(n0->getNumberOfUpArcs()) {
2485
2486 n1 = mergeTree_.getNodeUpNeighbor(n0, 0);
2487
2488 const int newNode0 = makeNode(n0->getVertexId()),
2489 newNode1 = makeNode(n1->getVertexId());
2490
2491 // "we move v and its incident edge from JT to the contour tree".
2492 makeArc(newNode0, newNode1);
2493
2494 mergeTree_.clearArc(n0->getVertexId(), n1->getVertexId());
2495 }
2496 if((other->getNumberOfDownArcs() == 1)
2497 && (other->getNumberOfUpArcs() == 1)) {
2498 // "in ST, either v is a degree 2 node or..."
2499 // "in the former case, we suppress v in ST while maintaining the
2500 // connection"
2501 splitTree_.clearRegularNode(other->getVertexId());
2502 } else {
2503 // "or it's the root"
2504 // "in the latter, we delete v from ST"
2505 splitTree_.clearRoot(other->getVertexId());
2506 }
2507
2508 // update n1 if it's eligible
2509 if((n1) && (isNodeEligible(n1))) {
2510
2511 nodeQueue.push(n1);
2512 }
2513 } else {
2514 // unsure
2515 if(nodeQueue.empty())
2516 break;
2517 nodeQueue.push(n0);
2518 }
2519 }
2520
2521 // symmetric case with nodes coming from the split tree
2522 else if((splitTree_.getNode(n0 - splitTree_.getNode(0)) == n0)
2523 && (isNodeEligible(n0))) {
2524
2525 // merge node
2526 // get the corresponding split node
2527 other = mergeTree_.getVertexNode(n0->getVertexId());
2528
2529 if(!((other->getNumberOfUpArcs())
2530 && (other->getNumberOfDownArcs() > 1))) {
2531
2532 n1 = nullptr;
2533
2534 if(n0->getNumberOfUpArcs()) {
2535
2536 n1 = splitTree_.getNodeUpNeighbor(n0, 0);
2537
2538 const int newNode0 = makeNode(n0->getVertexId()),
2539 newNode1 = makeNode(n1->getVertexId());
2540
2541 makeArc(newNode1, newNode0);
2542 splitTree_.clearArc(n0->getVertexId(), n1->getVertexId());
2543 }
2544 if((other->getNumberOfDownArcs() == 1)
2545 && (other->getNumberOfUpArcs() == 1)) {
2546 // degree 2 node
2547 mergeTree_.clearRegularNode(other->getVertexId());
2548 } else {
2549 // other has to be the root
2550 mergeTree_.clearRoot(other->getVertexId());
2551 }
2552
2553 // update n1 if it's eligible
2554 if((n1) && (isNodeEligible(n1))) {
2555 nodeQueue.push(n1);
2556 }
2557 } else {
2558 if(nodeQueue.empty())
2559 break;
2560 nodeQueue.push(n0);
2561 }
2562 }
2563 } while(nodeQueue.size());
2564
2565 if((int)nodeList_.size() == vertexNumber_)
2566 break;
2567
2568 // if one of the two trees became a line, we need to re-iterate the process
2569 } while((int)nodeList_.size() < vertexNumber_);
2570
2571 if((int)nodeList_.size() != vertexNumber_) {
2572 this->printErr("Incomplete contour tree! ("
2573 + std::to_string(nodeList_.size()) + " vs. "
2574 + std::to_string(vertexNumber_) + ")");
2575 }
2576
2577 this->printMsg(
2578 "MergeTree and SplitTree combined", 1.0, timer.getElapsedTime(), 1);
2579
2580 return 0;
2581}
2582
2584
2585 vector<bool> inQueue(nodeList_.size(), false);
2586 queue<int> nodeIdQueue;
2587
2588 for(int i = 0; i < (int)nodeList_.size(); i++) {
2589 if(!nodeList_[i].getNumberOfDownArcs()) {
2590 nodeIdQueue.push(i);
2591 inQueue[i] = true;
2592 }
2593 }
2594
2595 while(nodeIdQueue.size()) {
2596
2597 int const nodeId = nodeIdQueue.front();
2598 nodeIdQueue.pop();
2599
2600 for(int i = 0; i < nodeList_[nodeId].getNumberOfUpArcs(); i++) {
2601 int const nextNodeId = finalizeSuperArc(nodeId, i);
2602
2603 if(!inQueue[nextNodeId]) {
2604 nodeIdQueue.push(nextNodeId);
2605 inQueue[nextNodeId] = true;
2606 }
2607 }
2608 }
2609
2610 return 0;
2611}
2612
2613int ContourTree::finalizeSuperArc(const int &nodeId, const int &arcId) {
2614
2615 if((nodeId < 0) || (nodeId >= (int)nodeList_.size()))
2616 return -1;
2617 if((arcId < 0) || (arcId >= nodeList_[nodeId].getNumberOfUpArcs()))
2618 return -2;
2619
2620 int const superArcId = openSuperArc(nodeId);
2621
2622 int currentNodeId = nodeId;
2623
2624 do {
2625
2626 if(nodeList_[currentNodeId].getNumberOfUpArcs()) {
2627 if(currentNodeId != nodeId) {
2628
2629 superArcList_[superArcId].appendRegularNode(currentNodeId);
2630 vertex2superArc_[nodeList_[currentNodeId].getVertexId()] = superArcId;
2631 vertex2superArcNode_[nodeList_[currentNodeId].getVertexId()]
2632 = superArcList_[superArcId].getNumberOfRegularNodes() - 1;
2633
2634 currentNodeId
2635 = arcList_[nodeList_[currentNodeId].getUpArcId(0)].getUpNodeId();
2636 } else {
2637 currentNodeId
2638 = arcList_[nodeList_[currentNodeId].getUpArcId(arcId)].getUpNodeId();
2639 }
2640 }
2641
2642 } while((currentNodeId != nodeId)
2643 && (nodeList_[currentNodeId].getNumberOfUpArcs() == 1)
2644 && (nodeList_[currentNodeId].getNumberOfDownArcs() == 1));
2645
2646 if(currentNodeId != nodeId) {
2647 superArcList_[superArcId].setUpNodeId(currentNodeId);
2648 nodeList_[currentNodeId].addDownSuperArcId(superArcId);
2649 }
2650
2651 return currentNodeId;
2652}
2653
2654bool ContourTree::isNodeEligible(const Node *n) const {
2655
2656#ifndef TTK_ENABLE_KAMIKAZE
2657 if(n == nullptr) {
2658 return false;
2659 }
2660#endif // TTK_ENABLE_KAMIKAZE
2661
2662 const Node *merge = nullptr, *split = nullptr;
2663
2664 if(mergeTree_.getNode(n - mergeTree_.getNode(0)) == n) {
2665 merge = n;
2666 split = splitTree_.getVertexNode(merge->getVertexId());
2667
2668 // "choose a non-root leaf that is not a split in ST"
2669 // non-root
2670 if((!merge->getNumberOfDownArcs())
2671 && (merge->getNumberOfUpArcs())
2672 // it is not a split in ST
2673 && (((split->getNumberOfDownArcs() < 2) && (split->getNumberOfUpArcs()))
2674 // or it's the root
2675 || ((split->getNumberOfDownArcs() == 1)
2676 && (!split->getNumberOfUpArcs())))) {
2677
2678 return true;
2679 }
2680 }
2681
2682 if(splitTree_.getNode(n - splitTree_.getNode(0)) == n) {
2683 split = n;
2684 merge = mergeTree_.getVertexNode(split->getVertexId());
2685
2686 if((!split->getNumberOfDownArcs()) && (split->getNumberOfUpArcs())
2687 && (((merge->getNumberOfDownArcs() < 2) && (merge->getNumberOfUpArcs()))
2688 || ((merge->getNumberOfDownArcs() == 1)
2689 && (!merge->getNumberOfUpArcs())))) {
2690
2691 return true;
2692 }
2693 }
2694
2695 return false;
2696}
2697
2698int ContourTree::computeSkeleton(unsigned int arcResolution) {
2699#ifdef TTK_ENABLE_OPENMP
2700#pragma omp parallel sections
2701#endif
2702 {
2703#ifdef TTK_ENABLE_OPENMP
2704#pragma omp section
2705#endif
2706 { SubLevelSetTree::computeSkeleton(arcResolution); }
2707
2708#ifdef TTK_ENABLE_OPENMP
2709#pragma omp section
2710#endif
2711 { mergeTree_.computeSkeleton(arcResolution); }
2712
2713#ifdef TTK_ENABLE_OPENMP
2714#pragma omp section
2715#endif
2716 { splitTree_.computeSkeleton(arcResolution); }
2717 }
2718
2719 return 0;
2720}
2721
2722int ContourTree::smoothSkeleton(unsigned int skeletonSmoothing) {
2723#ifdef TTK_ENABLE_OPENMP
2724#pragma omp parallel sections
2725#endif
2726 {
2727#ifdef TTK_ENABLE_OPENMP
2728#pragma omp section
2729#endif
2730 { SubLevelSetTree::smoothSkeleton(skeletonSmoothing); }
2731
2732#ifdef TTK_ENABLE_OPENMP
2733#pragma omp section
2734#endif
2735 { mergeTree_.smoothSkeleton(skeletonSmoothing); }
2736
2737#ifdef TTK_ENABLE_OPENMP
2738#pragma omp section
2739#endif
2740 { splitTree_.smoothSkeleton(skeletonSmoothing); }
2741 }
2742
2743 return 0;
2744}
2745
2747#ifdef TTK_ENABLE_OPENMP
2748#pragma omp parallel sections
2749#endif
2750 {
2751#ifdef TTK_ENABLE_OPENMP
2752#pragma omp section
2753#endif
2755
2756#ifdef TTK_ENABLE_OPENMP
2757#pragma omp section
2758#endif
2760
2761#ifdef TTK_ENABLE_OPENMP
2762#pragma omp section
2763#endif
2765 }
2766
2767 return 0;
2768}
2769
2771 vector<pair<pair<int, int>, double>> &pairs,
2772 vector<pair<pair<int, int>, double>> *mergePairs,
2773 vector<pair<pair<int, int>, double>> *splitPairs) const {
2774 if(pairs.size())
2775 return 0;
2776
2777 vector<pair<pair<int, int>, double>> defaultMergePairs{};
2778 if(!mergePairs) {
2779 mergePairs = &defaultMergePairs;
2780 }
2781 vector<pair<pair<int, int>, double>> defaultSplitPairs{};
2782 if(!splitPairs) {
2783 splitPairs = &defaultSplitPairs;
2784 }
2785
2786 if(!mergePairs->size() || !splitPairs->size()) {
2787#ifdef TTK_ENABLE_OPENMP
2788#pragma omp parallel sections
2789#endif
2790 {
2791
2792#ifdef TTK_ENABLE_OPENMP
2793#pragma omp section
2794#endif
2795 {
2796 if(!mergePairs->size())
2797 mergeTree_.getPersistencePairs(*mergePairs);
2798 }
2799
2800#ifdef TTK_ENABLE_OPENMP
2801#pragma omp section
2802#endif
2803 {
2804 if(!splitPairs->size())
2805 splitTree_.getPersistencePairs(*splitPairs);
2806 }
2807 }
2808 }
2809
2810 pairs.resize(mergePairs->size() + splitPairs->size());
2811
2812 for(unsigned int i = 0; i < mergePairs->size(); ++i)
2813 pairs[i] = (*mergePairs)[i];
2814
2815 unsigned int const shift = mergePairs->size();
2816 for(unsigned int i = 0; i < splitPairs->size(); ++i)
2817 pairs[shift + i] = (*splitPairs)[i];
2818
2819 std::sort(pairs.begin(), pairs.end(), _pCmp);
2820
2821 return 0;
2822}
2823
2825 vector<pair<double, int>> &plot,
2826 vector<pair<pair<int, int>, double>> *mergePairs,
2827 vector<pair<pair<int, int>, double>> *splitPairs,
2828 vector<pair<pair<int, int>, double>> *pairs) const {
2829
2830 vector<pair<pair<int, int>, double>> defaultPairs{};
2831 if(!pairs) {
2832 pairs = &defaultPairs;
2833 }
2834
2835 if(!pairs->size())
2836 getPersistencePairs(*pairs, mergePairs, splitPairs);
2837
2838 plot.resize(pairs->size());
2839
2840 for(int i = 0; i < (int)plot.size(); i++) {
2841 plot[i].first = (*pairs)[i].second;
2842 if(plot[i].first < Geometry::powIntTen(-REAL_SIGNIFICANT_DIGITS)) {
2844 }
2845 plot[i].second = pairs->size() - i;
2846 }
2847
2848 return 0;
2849}
2850
2852 vector<pair<double, double>> &diagram,
2853 vector<pair<pair<int, int>, double>> *mergePairs,
2854 vector<pair<pair<int, int>, double>> *splitPairs,
2855 vector<pair<pair<int, int>, double>> *pairs) const {
2856
2857 vector<pair<pair<int, int>, double>> defaultPairs{};
2858 if(!pairs) {
2859 pairs = &defaultPairs;
2860 }
2861
2862 if(!pairs->size())
2863 getPersistencePairs(*pairs, mergePairs, splitPairs);
2864
2865 // fast fix :(
2866 diagram.resize(pairs->size());
2867
2868 for(int i = 0; i < (int)pairs->size(); i++) {
2869 if((maximumList_) && (!minimumList_)) {
2870 // split tree
2871 diagram[i].second = (*vertexScalars_)[(*pairs)[i].first.first];
2872 diagram[i].first = (*vertexScalars_)[(*pairs)[i].first.second];
2873 } else {
2874 // join tree or contour tree
2875 diagram[i].first = (*vertexScalars_)[(*pairs)[i].first.first];
2876 diagram[i].second = (*vertexScalars_)[(*pairs)[i].first.second];
2877 }
2878 }
2879
2880 std::sort(diagram.begin(), diagram.end(), _pPairCmp);
2881
2882 return 0;
2883}
2884
2885int ContourTree::simplify(const double &simplificationThreshold,
2887#ifdef TTK_ENABLE_OPENMP
2888#pragma omp parallel sections
2889#endif
2890 {
2891
2892#ifdef TTK_ENABLE_OPENMP
2893#pragma omp section
2894#endif
2895 { mergeTree_.simplify(simplificationThreshold, metric); }
2896
2897#ifdef TTK_ENABLE_OPENMP
2898#pragma omp section
2899#endif
2900 { splitTree_.simplify(simplificationThreshold, metric); }
2901 }
2902
2903 return 0;
2904}
#define ttkNotUsed(x)
Mark function/method parameters that are not used in the function body at all.
Definition BaseClass.h:47
struct filtrationCtCmp filtrationCmp
struct _persistenceCmp _pCmp
struct _persistencePairCmp _pPairCmp
#define REAL_SIGNIFICANT_DIGITS
Definition Os.h:46
virtual SimplexId getVertexNeighborNumber(const SimplexId &vertexId) const
virtual SimplexId getNumberOfVertices() const
virtual int getVertexNeighbor(const SimplexId &vertexId, const int &localNeighborId, SimplexId &neighborId) const
int getUpNodeId() const
Definition ContourTree.h:38
int getDownNodeId() const
Definition ContourTree.h:34
virtual double computeSuperArcMetric(const int &downVertexId, const int &upVertexId, const std::vector< int > &interiorNodeIds)=0
int getPersistenceDiagram(std::vector< std::pair< double, double > > &diagram, std::vector< std::pair< std::pair< int, int >, double > > *mergePairs=nullptr, std::vector< std::pair< std::pair< int, int >, double > > *splitPairs=nullptr, std::vector< std::pair< std::pair< int, int >, double > > *pairs=nullptr) const
int computeSkeleton(unsigned int arcResolution=3) override
int simplify(const double &simplificationThreshold, ContourTreeSimplificationMetric *metric=nullptr) override
int smoothSkeleton(unsigned int skeletonSmoothing) override
int getPersistencePlot(std::vector< std::pair< double, int > > &plot, std::vector< std::pair< std::pair< int, int >, double > > *mergePairs=nullptr, std::vector< std::pair< std::pair< int, int >, double > > *splitPairs=nullptr, std::vector< std::pair< std::pair< int, int >, double > > *pairs=nullptr) const
bool isNodeEligible(const Node *n) const
SubLevelSetTree mergeTree_
int finalizeSuperArc(const int &nodeId, const int &arcId)
SubLevelSetTree splitTree_
int clearSkeleton() override
int getPersistencePairs(std::vector< std::pair< std::pair< int, int >, double > > &pairs, std::vector< std::pair< std::pair< int, int >, double > > *mergePairs=nullptr, std::vector< std::pair< std::pair< int, int >, double > > *splitPairs=nullptr) const override
int debugLevel_
Definition Debug.h:379
int printWrn(const std::string &msg, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cerr) const
Definition Debug.h:159
void setDebugMsgPrefix(const std::string &prefix)
Definition Debug.h:364
virtual int setDebugLevel(const int &debugLevel)
Definition Debug.cpp:147
int printErr(const std::string &msg, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cerr) const
Definition Debug.h:149
int getUpArcId(const int &neighborId) const
int getNumberOfUpArcs() const
int getUpSuperArcId(const int &neighborId) const
int getDownArcId(const int &neighborId) const
double layoutY_
int getNumberOfDownArcs() const
int getNumberOfDownSuperArcs() const
int getVertexId() const
int getNumberOfUpSuperArcs() const
void addUpArcId(const int &upArcId)
double computeSuperArcMetric(const int &downVertexId, const int &upVertexId, const std::vector< int > &interiorNodeIds) override
int clearRoot(const int &vertexId)
int exportPersistenceDiagram(const std::string &fileName="output.plot") const
bool isSosHigherThan(const int &vertexId0, const int &vertexId1) const
int getSkeletonScalars(const std::vector< double > &scalars, std::vector< std::vector< double > > &skeletonScalars) const
void setTriangulation(const AbstractTriangulation *const triangulation)
int moveRegularNode(const Node *n, const Node *oldDown, const Node *oldUp, const Node *newDown, const Node *newUp)
void setMaximumList(std::vector< int > &maximumList)
void setNumberOfVertices(const int &vertexNumber)
std::vector< Node > originalNodeList_
int exportToSvg(const std::string &fileName, const double &scaleX=1, const double &scaleY=1)
std::vector< int > * minimumList_
int clearRegularNode(const int &vertexId)
int appendRegularNode(const int &superArcId, const int &nodeId)
void setMinimumList(std::vector< int > &minimumList)
int getPersistenceDiagram(std::vector< std::pair< double, double > > &diagram, std::vector< std::pair< std::pair< int, int >, double > > *pairs=nullptr) const
const Node * getNode(const int &nodeId) const
int exportPersistenceCurve(const std::string &fileName="output.plot") const
virtual int clearSkeleton()
void setVertexScalars(const std::vector< real > *const vertexScalars)
const AbstractTriangulation * triangulation_
virtual int computeSkeleton(unsigned int arcResolution=3)
int buildSaddleList(std::vector< int > &vertexList) const
std::vector< int > vertex2superArcNode_
std::vector< int > * vertexSoSoffsets_
void setVertexPositions(std::vector< std::vector< double > > *vertexPositions)
std::vector< Arc > arcList_
std::vector< SuperArc > superArcList_
std::vector< SuperArc > originalSuperArcList_
int getNumberOfArcs() const
const Node * getVertexNode(const int &vertexId) const
int getNumberOfNodes() const
std::vector< int > * maximumList_
std::vector< Node > nodeList_
int getNumberOfSuperArcs() const
int exportArcPosToVtk(const int &arcId, const int &pointId, std::vector< int > &vertexIds, const std::vector< float > *origin, const std::vector< float > *voxelSize, std::ofstream &o)
int makeNode(const int &vertexId)
std::vector< int > vertex2node_
const SuperArc * getSuperArc(const int &superArcId) const
std::vector< std::vector< double > > * vertexPositions_
int sample(unsigned int samplingLevel=3)
int exportNodePosToVtk(const int &nodeId, const int &pointId, std::vector< int > &vertexIds, const std::vector< float > *origin, const std::vector< float > *voxelSize, std::ofstream &o)
int makeArc(const int &nodeId0, const int &nodeId1)
virtual int getPersistencePairs(std::vector< std::pair< std::pair< int, int >, double > > &pairs, std::vector< std::pair< std::pair< int, int >, double > > *mergePairs=nullptr, std::vector< std::pair< std::pair< int, int >, double > > *splitPairs=nullptr) const
int buildExtremumList(std::vector< int > &extremumList, const bool &isSubLevelSet=true)
virtual int simplify(const double &simplificationThreshold, ContourTreeSimplificationMetric *metric=nullptr)
int openSuperArc(const int &nodeId)
int exportToVtk(const std::string &fileName, const std::vector< float > *origin=nullptr, const std::vector< float > *voxelSize=nullptr)
int getPersistencePlot(std::vector< std::pair< double, int > > &plot, std::vector< std::pair< std::pair< int, int >, double > > *persistencePairs=nullptr) const
void setVertexSoSoffsets(std::vector< int > *vertexSoSoffsets)
const Node * getNodeUpNeighbor(const Node *n, const int &neighborId) const
int exportNodeColorToVtk(const int &nodeId, std::ofstream &o)
std::vector< int > vertex2superArc_
int getVertexScalar(const int &vertexId, double &scalar)
int closeSuperArc(const int &superArcId, const int &nodeId)
bool isSosLowerThan(const int &vertexId0, const int &vertexId1) const
bool buildPlanarLayout(const double &scaleX, const double &scaleY)
const std::vector< real > * vertexScalars_
virtual int smoothSkeleton(unsigned int skeletonSmoothing)
int clearArc(const int &vertexId0, const int &vertexId1)
int getNumberOfRegularNodes() const
Definition ContourTree.h:70
int getNumberOfBarycenters() const
Definition ContourTree.h:74
void getSample(const int &id, std::vector< int > &sample) const
int getRegularNodeId(const int &arcNodeId) const
Definition ContourTree.h:82
bool isPruned() const
std::vector< std::vector< double > > barycenterList_
void smooth(const std::vector< Node > &nodeList, const std::vector< std::vector< double > > *vertexPositions, bool order=true)
std::vector< int > regularNodeList_
void sortRegularNodes(const std::vector< double > *vertexScalars, const std::vector< int > *vertexOffsets, const std::vector< Node > *nodeList, bool order=true)
int getNumberOfSamples() const
Definition ContourTree.h:78
double getElapsedTime()
Definition Timer.h:15
Union Find implementation for connectivity tracking.
Definition UnionFind.h:17
static UnionFind * makeUnion(UnionFind *uf0, UnionFind *uf1)
Definition UnionFind.h:40
UnionFind * find()
Definition UnionFind.h:99
std::string to_string(__int128)
Definition ripserpy.cpp:99
T powIntTen(const int n)
Compute the nth power of ten.
Definition Geometry.h:403
The Topology ToolKit.
int SimplexId
Identifier type for simplices of any dimension.
Definition DataTypes.h:22
MyCmp(const vector< double > *vertexScalars, const vector< int > *vertexOffsets, const vector< Node > *nodeList, bool isAscendingOrder)
bool isAscendingOrder_
const vector< double > * vertexScalars_
const vector< Node > * nodeList_
const vector< int > * vertexOffsets_
bool operator()(int node1, int node2)
const vector< double > * vertexScalars_
_persistenceCmp3(const vector< double > *vertexScalars)
bool operator()(const pair< pair< int, int >, double > &p0, const pair< pair< int, int >, double > &p1)
bool operator()(const pair< pair< int, int >, double > &p0, const pair< pair< int, int >, double > &p1)
bool operator()(const pair< double, double > &p0, const pair< double, double > &p1)
bool operator()(const pair< bool, pair< double, pair< int, int > > > &v0, const pair< bool, pair< double, pair< int, int > > > &v1) const
printMsg(debug::output::BOLD+" | | | | | . \\ | | (__| | / __/| |_| / __/|__ _|"+debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, stream)