TTK
Loading...
Searching...
No Matches
MergeTreeVisualization.h
Go to the documentation of this file.
1
7
8#pragma once
9
10#include <FTMTree.h>
11
12#include <stack>
13
14namespace ttk {
15
16 class MergeTreeVisualization : virtual public Debug {
17 protected:
18 // Visualization parameters
20 bool pathPlanarLayout_ = false;
21 double branchSpacing_ = 1.;
23 double importantPairs_ = 50.; // important pairs threshold
31
32 public:
34 ~MergeTreeVisualization() override = default;
35
36 // ========================================================================
37 // Getter / Setter
38 // ========================================================================
39 // Visualization parameters
43 void setPathPlanarLayout(bool b) {
45 }
46 void setBranchSpacing(double d) {
48 }
52 void setImportantPairs(double d) {
54 }
55 void setImportantPairsSpacing(double d) {
57 }
72
73 // ========================================================================
74 // Branch Decomposition Tree Planar Layout
75 // ========================================================================
76 // TODO manage multi pers pairs
77 template <class dataType>
79 ftm::FTMTree_MT *tree,
80 std::vector<float> &retVec,
81 std::vector<LongSimplexId> &treeSimplexId,
82 std::vector<ftm::idNode> &ttkNotUsed(branching),
83 std::vector<std::vector<ftm::idNode>> &nodeBranching) {
84 ftm::idNode const treeRoot = tree->getRoot();
85 ftm::idNode const treeRootOrigin = tree->getNode(treeRoot)->getOrigin();
86 float const rootY = retVec[treeSimplexId[treeRoot] * 2 + 1];
87 float const rootOriginY = retVec[treeSimplexId[treeRootOrigin] * 2 + 1];
88 float const rootYmin = std::min(rootY, rootOriginY);
89 float const rootYmax = std::max(rootY, rootOriginY);
90 dataType rootPers = tree->getNodePersistence<dataType>(treeRoot);
91 std::vector<std::tuple<float, float>> allNodeSpanX(
92 tree->getNumberOfNodes());
93 std::vector<std::tuple<float, float>> allNodeImportantSpanX(
94 tree->getNumberOfNodes());
95
96 // Compute gap
97 float const nonImportantPairsGap
98 = (rootYmax - rootYmin) * 0.05 * nonImportantPairsSpacing_;
99 float const importantPairsGap
100 = std::max(nonImportantPairsGap, (float)importantPairsSpacing_);
101
102 // Some functions
103 auto compLowerPers = [&](const ftm::idNode a, const ftm::idNode b) {
104 return tree->getNodePersistence<dataType>(a)
105 < tree->getNodePersistence<dataType>(b);
106 };
107 auto compEqUpperPers = [&](const ftm::idNode a, const ftm::idNode b) {
108 return not compLowerPers(a, b);
109 };
110
111 // Go
112 std::vector<ftm::idNode> leaves;
113 tree->getLeavesFromTree(leaves);
114 std::sort(leaves.begin(), leaves.end(), compLowerPers);
115 std::queue<ftm::idNode> queue;
116 for(auto node : leaves)
117 queue.emplace(node);
118 while(!queue.empty()) {
119 ftm::idNode const node = queue.front();
120 queue.pop();
121 ftm::idNode const nodeOrigin = tree->getNode(node)->getOrigin();
122
123 const double nodePers = tree->getNodePersistence<dataType>(node);
124 retVec[treeSimplexId[nodeOrigin] * 2] = 0;
125 retVec[treeSimplexId[nodeOrigin] * 2 + 1]
126 = nodePers / rootPers * (rootYmax - rootYmin) + rootYmin;
127
128 // Positioning nodes in the branch
129 if(tree->isBranchOrigin(nodeOrigin)) {
130 float prevX = 0;
131 std::vector<ftm::idNode> nodeBranchingVector;
132 for(size_t i = 1; i < nodeBranching[nodeOrigin].size(); ++i)
133 nodeBranchingVector.push_back(nodeBranching[nodeOrigin][i]);
134 std::sort(nodeBranchingVector.begin(), nodeBranchingVector.end(),
135 compEqUpperPers);
136
137 // Iterate through each node of the branch
138 int lastIndexImportant = -1;
139 for(size_t i = 0; i < nodeBranchingVector.size(); ++i) {
140 ftm::idNode const nodeBranchingI = nodeBranchingVector[i];
141
142 // Get old node span X
143 float const oldMin = std::get<0>(allNodeSpanX[nodeBranchingI]);
144 float const oldMax = std::get<1>(allNodeSpanX[nodeBranchingI]);
145
146 // Get x spacing
147 float nodeSpacing = 0;
148 if(i > 0) {
149 if(tree->isImportantPair<dataType>(
150 nodeBranchingVector[i], importantPairs_,
153 nodeSpacing = importantPairsGap;
154 } else if(tree->isImportantPair<dataType>(
155 nodeBranchingVector[i - 1], importantPairs_,
158 nodeSpacing = nonImportantPairsProximity_;
159 // prevX =
160 } else {
161 nodeSpacing = nonImportantPairsGap;
162 }
163 } else if(not tree->isImportantPair<dataType>(
164 nodeBranchingVector[i], importantPairs_,
167 and tree->isImportantPair<dataType>(
168 nodeOrigin, importantPairs_,
171 nodeSpacing = nonImportantPairsProximity_;
172 float const newMin = prevX + nodeSpacing;
173 float const shiftX = newMin - oldMin;
174
175 // Set y coordinate according difference in persistence
176 dataType nodeBranchingIPers
177 = tree->getNodePersistence<dataType>(nodeBranchingI);
178 float const shiftY = nodeBranchingIPers * branchSpacing_;
179 float diffY = retVec[treeSimplexId[nodeBranchingI] * 2 + 1];
180 retVec[treeSimplexId[nodeBranchingI] * 2 + 1]
181 = retVec[treeSimplexId[nodeOrigin] * 2 + 1] - shiftY;
182 diffY = retVec[treeSimplexId[nodeBranchingI] * 2 + 1] - diffY;
183
184 // Shift this branch
185 std::queue<ftm::idNode> queueBranching;
186 queueBranching.emplace(nodeBranchingI);
187 while(!queueBranching.empty()) {
188 ftm::idNode const nodeBranchOrigin = queueBranching.front();
189 queueBranching.pop();
190 retVec[treeSimplexId[nodeBranchOrigin] * 2] += shiftX;
191 if(nodeBranchOrigin != nodeBranchingI)
192 retVec[treeSimplexId[nodeBranchOrigin] * 2 + 1] += diffY;
193 if(tree->isBranchOrigin(nodeBranchOrigin))
194 for(auto nodeB : nodeBranching[nodeBranchOrigin])
195 queueBranching.emplace(nodeB);
196 }
197
198 // Update node span X
199 allNodeSpanX[nodeBranchingI]
200 = std::make_tuple(oldMin + shiftX, oldMax + shiftX);
201 float const oldMinImp
202 = std::get<0>(allNodeImportantSpanX[nodeBranchingI]);
203 float const oldMaxImp
204 = std::get<1>(allNodeImportantSpanX[nodeBranchingI]);
205 allNodeImportantSpanX[nodeBranchingI]
206 = std::make_tuple(oldMinImp + shiftX, oldMaxImp + shiftX);
207
208 // Update x base for next iteration
209 prevX = std::get<1>(allNodeSpanX[nodeBranchingI]);
210 if(tree->isImportantPair<dataType>(
211 nodeBranchingVector[i], importantPairs_,
214 lastIndexImportant = i;
215 prevX = std::get<1>(allNodeImportantSpanX[nodeBranchingI]);
216 if(i < nodeBranchingVector.size() - 1
217 and not tree->isImportantPair<dataType>(
218 nodeBranchingVector[i + 1], importantPairs_,
221 float const spanMin
222 = std::get<0>(allNodeSpanX[nodeBranchingVector[0]]);
223 float const spanMax
224 = std::get<1>(allNodeImportantSpanX
225 [nodeBranchingVector[lastIndexImportant]]);
226 prevX = (spanMin + spanMax) / 2;
227 }
228 }
229 } // end for nodeBranching
230
231 // Update node span X
232 float spanMin = std::get<0>(allNodeSpanX[nodeBranchingVector[0]]);
233 if(lastIndexImportant != -1) {
234 float const spanMaxImp = std::get<1>(
235 allNodeImportantSpanX[nodeBranchingVector[lastIndexImportant]]);
236 allNodeImportantSpanX[nodeOrigin]
237 = std::make_tuple(spanMin, spanMaxImp);
238 } else {
239 allNodeImportantSpanX[nodeOrigin] = std::make_tuple(0, 0);
240 spanMin = 0;
241 }
242 float const spanMax = std::get<1>(
243 allNodeSpanX[nodeBranchingVector[nodeBranchingVector.size() - 1]]);
244 allNodeSpanX[nodeOrigin] = std::make_tuple(spanMin, spanMax);
245 } else {
246 allNodeSpanX[nodeOrigin] = std::make_tuple(0, 0);
247 allNodeImportantSpanX[nodeOrigin] = std::make_tuple(0, 0);
248 }
249
250 // Positioning of this node x coordinate
251 float const spanMin = std::get<0>(allNodeImportantSpanX[nodeOrigin]);
252 float const spanMax = std::get<1>(allNodeImportantSpanX[nodeOrigin]);
253 retVec[treeSimplexId[nodeOrigin] * 2] = (spanMin + spanMax) / 2;
254 }
255
256 // Copy coordinates of nodeOrigin
257 for(auto node : leaves)
258 queue.emplace(node);
259 while(!queue.empty()) {
260 ftm::idNode const node = queue.front();
261 queue.pop();
262 ftm::idNode const nodeOrigin = tree->getNode(node)->getOrigin();
263 retVec[treeSimplexId[node] * 2] = retVec[treeSimplexId[nodeOrigin] * 2];
264 retVec[treeSimplexId[node] * 2 + 1]
265 = retVec[treeSimplexId[nodeOrigin] * 2 + 1];
266 }
267 }
268
269 // ========================================================================
270 // Path Planar Layout
271 // ========================================================================
272 // TODO manage multi pers pairs
273 template <class dataType>
275 std::vector<float> &retVec,
276 std::vector<LongSimplexId> &treeSimplexId,
277 std::vector<ftm::idNode> &leaves,
278 double importantPairsGap) {
279 std::queue<ftm::idNode> queue;
280 for(auto &node : leaves)
281 queue.emplace(node);
282 std::vector<std::array<float, 4>> bounds(tree->getNumberOfNodes());
283 std::vector<bool> nodeDone(tree->getNumberOfNodes(), false);
284 std::vector<bool> parentOfImportantPair(tree->getNumberOfNodes(), false);
285 std::vector<unsigned int> childSize(tree->getNumberOfNodes()),
286 noChildDone(tree->getNumberOfNodes(), 0);
287 std::vector<double> lowestValue(tree->getNumberOfNodes());
288 bool isJT = tree->isJoinTree<dataType>();
289 for(unsigned int i = 0; i < tree->getNumberOfNodes(); ++i) {
290 std::vector<ftm::idNode> children;
291 tree->getChildren(i, children);
292 childSize[i] = children.size();
293 }
294 while(!queue.empty()) {
295 ftm::idNode node = queue.front();
296 queue.pop();
297 if(nodeDone[node])
298 continue;
299
300 std::vector<ftm::idNode> children;
301 if(!tree->isLeaf(node) and !tree->isRoot(node))
302 tree->getChildren(node, children);
303
304 // Shift children
305 bool isNodeImportant = tree->isImportantPair<dataType>(
308 if(isNodeImportant) {
309 bounds[node]
310 = {retVec[treeSimplexId[node] * 2], retVec[treeSimplexId[node] * 2],
311 retVec[treeSimplexId[node] * 2 + 1],
312 retVec[treeSimplexId[node] * 2 + 1]};
313 parentOfImportantPair[node] = true;
314 if(!tree->isLeaf(node) and !tree->isRoot(node)) {
315 float nodeX = retVec[treeSimplexId[node] * 2];
316 ftm::idNode child1 = children[0];
317 ftm::idNode child2 = children[1];
318 if(not nodeDone[child1] or not nodeDone[child2])
319 printErr("not nodeDone[child1] or not nodeDone[child2]");
320 if(children.size() != 2)
321 printWrn("children.size() != 2");
322
323 double sign = (lowestValue[child1] > lowestValue[child2] ? -1 : 1);
324 if(isJT)
325 sign *= -1;
326
327 float child1XBound = bounds[child1][(sign == -1 ? 1 : 0)];
328 double child1Shift
329 = -child1XBound + nodeX + sign * importantPairsGap / 2.0;
331 tree, child1, child1Shift, retVec, treeSimplexId);
332 bounds[child1][0] += child1Shift;
333 bounds[child1][1] += child1Shift;
334 float child2XBound = bounds[child2][(sign == -1 ? 0 : 1)];
335 double child2Shift
336 = -child2XBound + nodeX + sign * -1 * importantPairsGap / 2.0;
338 tree, child2, child2Shift, retVec, treeSimplexId);
339 bounds[child2][0] += child2Shift;
340 bounds[child2][1] += child2Shift;
341 }
342 }
343
344 // Update bounds
345 if(!tree->isLeaf(node) and !tree->isRoot(node)) {
346 for(auto &child : children) {
347 bool isChildImportant = tree->isImportantPair<dataType>(
350 if((isChildImportant or parentOfImportantPair[child])
351 and not parentOfImportantPair[node])
352 bounds[node] = bounds[child];
353 if(isChildImportant or parentOfImportantPair[child]) {
354 bounds[node] = {std::min(bounds[node][0], bounds[child][0]),
355 std::max(bounds[node][1], bounds[child][1]),
356 std::min(bounds[node][2], bounds[child][2]),
357 std::max(bounds[node][3], bounds[child][3])};
358 parentOfImportantPair[node] = true;
359 }
360 }
361 }
362
363 // Update lowest value
364 lowestValue[node] = tree->getValue<dataType>(node);
365 for(auto &child : children) {
366 if(isJT)
367 lowestValue[node] = std::min(lowestValue[node], lowestValue[child]);
368 else
369 lowestValue[node] = std::max(lowestValue[node], lowestValue[child]);
370 }
371
372 //
373 nodeDone[node] = true;
374 ftm::idNode parent = tree->getParentSafe(node);
375 noChildDone[parent] += 1;
376 if(noChildDone[parent] == childSize[parent])
377 queue.emplace(parent);
378 }
379 }
380
382 ftm::idNode subtreeRoot,
383 double shift,
384 std::vector<float> &retVec,
385 std::vector<LongSimplexId> &treeSimplexId) {
386 std::queue<ftm::idNode> queue;
387 queue.emplace(subtreeRoot);
388 while(!queue.empty()) {
389 ftm::idNode node = queue.front();
390 queue.pop();
391
392 retVec[treeSimplexId[node] * 2] += shift;
393
394 std::vector<ftm::idNode> children;
395 tree->getChildren(node, children);
396 for(auto &child : children)
397 queue.emplace(child);
398 }
399 }
400
401 // ========================================================================
402 // Merge Tree Planar Layout
403 // ========================================================================
404 // TODO manage multi pers pairs
405 template <class dataType>
407 ftm::FTMTree_MT *tree,
408 std::tuple<double, double, double, double, double, double> oldBounds,
409 double ttkNotUsed(refPersistence),
410 std::vector<float> &retVec) {
412 printMsg("Planar Layout", debug::Priority::VERBOSE);
413
414 // ----------------------------------------------------
415 // Init internal parameters
416 // ----------------------------------------------------
417 Timer t_init;
418 printMsg("Init internal parameters", debug::Priority::VERBOSE);
419
420 auto nPoints = tree->getRealNumberOfNodes();
421 int const outNumberOfPoints = nPoints * 2;
422 retVec.resize(outNumberOfPoints);
423
424 int cptNode = 0;
425 std::vector<LongSimplexId> treeSimplexId(tree->getNumberOfNodes());
426 std::vector<ftm::idNode> branching;
427 std::vector<int> branchingID;
428 std::vector<std::vector<ftm::idNode>> nodeBranching;
429 tree->getTreeBranching(branching, branchingID, nodeBranching);
430
431 std::stringstream ss;
432 ss << "INIT = " << t_init.getElapsedTime();
434
435 // ----------------------------------------------------
436 // Iterate through tree
437 // ----------------------------------------------------
438 Timer t_iterate;
439 printMsg("Iterate through tree", debug::Priority::VERBOSE);
440
441 std::queue<ftm::idNode> queue;
442 ftm::idNode const treeRoot = tree->getRoot();
443 ftm::idNode const treeRootOrigin = tree->getNode(treeRoot)->getOrigin();
444 ftm::idNode const lowestNode = tree->getLowestNode<dataType>(treeRoot);
445 queue.emplace(treeRoot);
446 while(!queue.empty()) {
447 ftm::idNode const node = queue.front();
448 queue.pop();
449
450 // Get and insert point
451 treeSimplexId[node] = cptNode;
452 ++cptNode;
453
454 // Push children to the queue
455 std::vector<ftm::idNode> children;
456 tree->getChildren(node, children);
457 for(size_t i = 0; i < children.size(); ++i) {
458 auto child = children[i];
459 queue.emplace(child);
460 }
461 }
462
463 std::stringstream ss2;
464 ss2 << "ITERATE TREE = " << t_iterate.getElapsedTime();
466
467 // ----------------------------------------------------
468 // Prepositioning coordinates
469 // ----------------------------------------------------
470 std::queue<ftm::idNode> queue2;
471 queue2.emplace(treeRoot);
472 while(!queue2.empty()) {
473 ftm::idNode const node = queue2.front();
474 queue2.pop();
475
476 retVec[treeSimplexId[node] * 2]
477 = tree->getValue<dataType>(branching[node]);
478 retVec[treeSimplexId[node] * 2 + 1] = tree->getValue<dataType>(node);
479
480 // Push children to the queue
481 std::vector<ftm::idNode> children;
482 tree->getChildren(node, children);
483 for(auto child : children)
484 queue2.emplace(child);
485 }
486
487 // ----------------------------------------------------
488 // Rescale coordinates
489 // ----------------------------------------------------
490 Timer t_rescale;
491 printMsg("Rescale coordinates ", debug::Priority::VERBOSE);
492
493 float x_min, y_min, x_max, y_max;
494 x_min = std::numeric_limits<float>::max();
495 y_min = std::numeric_limits<float>::max();
496 x_max = std::numeric_limits<float>::lowest();
497 y_max = std::numeric_limits<float>::lowest();
498 for(int i = 0; i < outNumberOfPoints; i += 2) {
499 x_min = std::min(x_min, retVec[i]);
500 x_max = std::max(x_max, retVec[i]);
501 y_min = std::min(y_min, retVec[i + 1]);
502 y_max = std::max(y_max, retVec[i + 1]);
503 }
504 auto newBounds = std::make_tuple(x_min, x_max, y_min, y_max, 0, 0);
505
506 // TODO correctly manage diff and offset if rescaleTreesIndividually_
507 double diff = std::max((std::get<1>(oldBounds) - std::get<0>(oldBounds)),
508 (std::get<3>(oldBounds) - std::get<2>(oldBounds)));
509 double offset = std::max(std::get<0>(oldBounds), std::get<2>(oldBounds));
511 // diff *= getNodePersistence<dataType>(tree, treeRoot) /
512 // refPersistence;
513 dataType rootVal = tree->getValue<dataType>(treeRoot);
514 dataType lowestNodeVal = tree->getValue<dataType>(lowestNode);
515 diff = (rootVal > lowestNodeVal ? rootVal - lowestNodeVal
516 : lowestNodeVal - rootVal);
517 offset = std::min(rootVal, lowestNodeVal);
518 }
519
520 for(int i = 0; i < outNumberOfPoints; i += 2) {
521 auto divisor1
522 = std::get<1>(newBounds) - std::get<0>(newBounds); // (x_max - x_min)
523 divisor1 = (divisor1 == 0 ? 1 : divisor1);
524 auto divisor2
525 = std::get<3>(newBounds) - std::get<2>(newBounds); // (y_max - y_min)
526 divisor2 = (divisor2 == 0 ? 1 : divisor2);
527
528 // x coordinate
529 retVec[i] = (retVec[i] - std::get<0>(newBounds)) / divisor1;
530 retVec[i] = retVec[i] * diff / 2 + offset;
531
532 // y coordinate
533 retVec[i + 1] = (retVec[i + 1] - std::get<2>(newBounds)) / divisor2;
534 retVec[i + 1] = retVec[i + 1] * diff + offset;
535 }
536
537 std::stringstream ss3;
538 ss3 << "RESCALE COORD. = " << t_rescale.getElapsedTime();
540
541 // ----------------------------------------------------
542 // Call Branch Decomposition Planar Layout if asked
543 // ----------------------------------------------------
546 tree, retVec, treeSimplexId, branching, nodeBranching);
547 return;
548 }
549
550 // ----------------------------------------------------
551 // Scale pairs given persistence
552 // ----------------------------------------------------
553 // Sort leaves by branch depth
554 std::vector<ftm::idNode> leaves;
555 tree->getLeavesFromTree(leaves);
556 std::vector<int> allNodeLevel;
557 tree->getAllNodeLevel(allNodeLevel);
558 auto compLevel = [&](const ftm::idNode a, const ftm::idNode b) {
559 return allNodeLevel[tree->getNode(a)->getOrigin()]
560 > allNodeLevel[tree->getNode(b)->getOrigin()];
561 };
562 std::sort(leaves.begin(), leaves.end(), compLevel);
563
564 // Init some variables
565 float rootY = retVec[treeSimplexId[treeRoot] * 2 + 1];
566 float rootOriginY = retVec[treeSimplexId[lowestNode] * 2 + 1];
567 float rootYmin = std::min(rootY, rootOriginY);
568 float rootYmax = std::max(rootY, rootOriginY);
569
570 Timer t_scale;
571 printMsg("Scale pairs given persistence", debug::Priority::VERBOSE);
572 dataType rootPers = tree->getNodePersistence<dataType>(treeRoot);
573 std::stack<ftm::idNode> stack;
574 for(auto node : leaves)
575 stack.emplace(node);
576 std::vector<bool> nodeDone(tree->getNumberOfNodes(), false);
577 while(!stack.empty()) {
578 ftm::idNode const node = stack.top();
579 stack.pop();
580 nodeDone[node] = true;
581 if(node == treeRoot or node == treeRootOrigin
582 or tree->isNodeAlone(node))
583 continue;
584 dataType nodePers = tree->getNodePersistence<dataType>(node);
585 ftm::idNode const nodeOrigin = tree->getNode(node)->getOrigin();
586
587 // Manage leaf
588 if(tree->isLeaf(node)) {
589 float const nodeDiff = (retVec[treeSimplexId[node] * 2]
590 - retVec[treeSimplexId[nodeOrigin] * 2]);
591 const auto sign = nodeDiff / std::abs(nodeDiff);
592 auto inc = sign * nodePers / rootPers * (rootYmax - rootYmin) / 2;
593 retVec[treeSimplexId[node] * 2]
594 = retVec[treeSimplexId[nodeOrigin] * 2] + inc;
595 // Push nodes in the branch to the stack
596 ftm::idNode nodeParent = tree->getParentSafe(node);
597 ftm::idNode oldNodeParent = -1;
598 while(nodeParent != nodeOrigin) {
599 if(not nodeDone[nodeParent])
600 stack.emplace(nodeParent);
601 else
602 break;
603 oldNodeParent = nodeParent;
604 nodeParent = tree->getParentSafe(nodeParent);
605 if(oldNodeParent == nodeParent) {
606 std::stringstream ss5;
607 ss5 << "treePlanarLayoutImpl oldNodeParent == nodeParent";
609 break;
610 }
611 }
612 }
613 // Manage saddle
614 if(not tree->isLeaf(node) and not tree->isRoot(node)) {
615 float const branchY
616 = retVec[treeSimplexId[tree->getNode(branching[node])->getOrigin()]
617 * 2];
618 retVec[treeSimplexId[node] * 2] = branchY;
619 }
620 }
621 std::stringstream ss5;
622 ss5 << "SCALE PERS. = " << t_scale.getElapsedTime();
624
625 // ----------------------------------------------------
626 // Branches positioning and avoid edges crossing
627 // ----------------------------------------------------
628 Timer t_avoid;
629 printMsg("Avoid edges crossing", debug::Priority::VERBOSE);
630
631 // Init some variables
632 bool isJT = tree->isJoinTree<dataType>();
633 auto compValue = [&](const ftm::idNode a, const ftm::idNode b) {
634 return (isJT
635 ? tree->getValue<dataType>(a) < tree->getValue<dataType>(b)
636 : tree->getValue<dataType>(a) > tree->getValue<dataType>(b));
637 };
638 std::vector<std::tuple<float, float, float, float>> allBranchBounds(
639 tree->getNumberOfNodes());
640 std::vector<std::vector<ftm::idNode>> allBranchOrigins(
641 tree->getNumberOfNodes());
642 std::vector<int> allBranchOriginsSize(tree->getNumberOfNodes());
643 std::queue<ftm::idNode> queueCrossing;
644
645 // ----- Get important and non-important pairs gap and store branch
646 // origins of each branch
647 int maxSize = std::numeric_limits<int>::lowest();
648 for(auto leaf : leaves)
649 queueCrossing.emplace(leaf);
650 while(!queueCrossing.empty()) {
651 ftm::idNode const node = queueCrossing.front();
652 queueCrossing.pop();
653 ftm::idNode const nodeOrigin = tree->getNode(node)->getOrigin();
654
655 // Get saddle nodes in the branch
656 std::tuple<std::vector<ftm::idNode>, std::vector<ftm::idNode>>
657 tupBranchOrigins;
658 tree->getBranchOriginsFromThisBranch(nodeOrigin, tupBranchOrigins);
659 allBranchOrigins[nodeOrigin] = std::get<0>(tupBranchOrigins);
660 std::vector<ftm::idNode> nonBranchOrigins
661 = std::get<1>(tupBranchOrigins);
662 allBranchOrigins[nodeOrigin].insert(allBranchOrigins[nodeOrigin].end(),
663 nonBranchOrigins.begin(),
664 nonBranchOrigins.end());
665 std::sort(allBranchOrigins[nodeOrigin].begin(),
666 allBranchOrigins[nodeOrigin].end(), compValue);
667 allBranchOriginsSize[nodeOrigin] = allBranchOrigins[nodeOrigin].size();
668
669 // Get sizes of sub-branches if they are non-important
670 for(size_t i = 0; i < allBranchOrigins[nodeOrigin].size(); ++i) {
671 ftm::idNode const branchNodeOrigin = allBranchOrigins[nodeOrigin][i];
672 bool const isSubBranchImportant = tree->isImportantPair<dataType>(
673 branchNodeOrigin, importantPairs_,
676 if(not isSubBranchImportant)
677 allBranchOriginsSize[nodeOrigin]
678 += allBranchOriginsSize[branchNodeOrigin];
679 }
680
681 if(tree->isImportantPair<dataType>(nodeOrigin, importantPairs_,
684 maxSize = std::max(maxSize, allBranchOriginsSize[nodeOrigin]);
685 }
686 double const nonImportantPairsGap
687 = (rootYmax - rootYmin) * 0.005 * nonImportantPairsSpacing_;
688 double importantPairsGap = (maxSize)*nonImportantPairsGap * 1.05;
689 bool const customimportantPairsSpacing_
690 = importantPairsGap < importantPairsSpacing_;
691 if(customimportantPairsSpacing_)
692 importantPairsGap = importantPairsSpacing_;
693
694 // ----- Positioning of branches and avoid conflict
695 for(auto leaf : leaves)
696 queueCrossing.emplace(leaf);
697 while(!queueCrossing.empty()) {
698 ftm::idNode const node = queueCrossing.front();
699 queueCrossing.pop();
700 ftm::idNode const nodeOrigin = tree->getNode(node)->getOrigin();
701
702 // Prepositioning of branches
703 // auto restrictedBounds = getBranchBounds(retVec, treeSimplexId,
704 // branching, tree, nodeOrigin, true);
705 auto restrictedBounds
706 = std::make_tuple(retVec[treeSimplexId[node] * 2],
707 retVec[treeSimplexId[node] * 2], 0, 0);
708 for(size_t i = 0; i < allBranchOrigins[nodeOrigin].size(); ++i) {
709 ftm::idNode const branchNodeOrigin = allBranchOrigins[nodeOrigin][i];
710 ftm::idNode const branchNode
711 = tree->getNode(branchNodeOrigin)->getOrigin();
712
713 bool const isSubBranchImportant = tree->isImportantPair<dataType>(
714 branchNodeOrigin, importantPairs_,
717 bool const toLeft = not isSubBranchImportant;
718
719 // float branchNodeOriginXmin =
720 // std::get<0>(allBranchBounds[branchNodeOrigin]);
721 float const branchNodeOriginXmax
722 = std::get<1>(allBranchBounds[branchNodeOrigin]);
723 float shift
724 = toLeft ? std::get<0>(restrictedBounds) - branchNodeOriginXmax :
725 // std::get<1>(restrictedBounds) - branchNodeOriginXmin;
726 std::get<1>(restrictedBounds)
727 - retVec[treeSimplexId[branchNode] * 2];
728 shift += (toLeft ? -1 : 1)
729 * (isSubBranchImportant ? importantPairsGap
730 : nonImportantPairsGap);
731 // shift += (toLeft ? -1 : 1) * nonImportantPairsGap;
732 shiftBranchBounds(retVec, treeSimplexId, branching, allBranchBounds,
733 allBranchOrigins[branchNodeOrigin], tree,
734 branchNodeOrigin, shift);
735 }
736
737 // Shift a branch if conflict with another one
738 for(size_t i = 1; i < allBranchOrigins[nodeOrigin].size(); ++i) {
739 ftm::idNode const branchNodeOrigin = allBranchOrigins[nodeOrigin][i];
740 ftm::idNode const branchNode
741 = tree->getNode(branchNodeOrigin)->getOrigin();
742 for(size_t j = 0; j < i; ++j) {
743 auto first = allBranchBounds[branchNodeOrigin];
744 ftm::idNode const previousBranchNodeOrigin
745 = allBranchOrigins[nodeOrigin][j];
746 auto second = allBranchBounds[previousBranchNodeOrigin];
747
748 bool const branchConflict = isConflictingBranchAndBound(
749 first, second, tree, previousBranchNodeOrigin, retVec,
750 treeSimplexId);
751 if(isConflictingBounds(first, second) or branchConflict) {
752
753 // Get left or right orientation given the branch
754 int const lastIndex = nodeBranching[branchNodeOrigin].size() - 1;
755 bool const isLeft
756 = (retVec
757 [treeSimplexId[nodeBranching[branchNodeOrigin][lastIndex]]
758 * 2]
759 //< retVec[treeSimplexId[nodeOrigin]*2]);
760 < retVec[treeSimplexId[node] * 2]);
761
762 // Get shift
763 float const branchNodeOriginXmax = std::get<1>(first);
764 float const previousbranchNodeOriginXmin = std::get<0>(second);
765 // float branchNodeOriginXmin = std::get<0>(first);
766 float const previousbranchNodeOriginXmax = std::get<1>(second);
767 float shift
768 = isLeft ? previousbranchNodeOriginXmin - branchNodeOriginXmax :
769 // previousbranchNodeOriginXmax - branchNodeOriginXmin;
770 previousbranchNodeOriginXmax
771 - retVec[treeSimplexId[branchNode] * 2];
772 bool const isSubBranchImportant = tree->isImportantPair<dataType>(
773 branchNodeOrigin, importantPairs_,
776 shift += (isLeft ? -1 : 1)
777 * (isSubBranchImportant ? importantPairsGap
778 : nonImportantPairsGap);
779 // shift += (isLeft ? -1 : 1) * nonImportantPairsGap;
780
781 // Shift bounds
782 shiftBranchBounds(retVec, treeSimplexId, branching,
783 allBranchBounds,
784 allBranchOrigins[branchNodeOrigin], tree,
785 branchNodeOrigin, shift);
786 }
787 }
788 } // end for
789
790 // TODO optimize get branch bounds by using results previously computed
791 // Get branch x and y bounds
792 allBranchBounds[nodeOrigin]
793 = getBranchBounds(retVec, treeSimplexId, branching, tree, nodeOrigin);
794 } // end while
795
796 // ----- Correction of important/non-important pairs gap
797 // TODO the gap between important pairs can be higher than the minimum gap
798 // needed to avoid conflict. The gap is computed using the maximum number
799 // of non-important pairs attached to an important pairs. Unfortunately
800 // the real gap can only be computed here, after the conflicts has been
801 // avoided. The maximum real gap must be calculated and propagated to all
802 // important branches and we also need to manage to avoid conflict with
803 // this new gap.
804 // Get real gap
805 double realImportantPairsGap = std::numeric_limits<double>::lowest();
806 /*if(customimportantPairsSpacing_)
807 realImportantPairsGap = importantPairsGap;
808 else{
809 for(auto leaf : leaves)
810 queueCrossing.emplace(leaf);
811 while(!queueCrossing.empty()){
812 ftm::idNode node = queueCrossing.front();
813 queueCrossing.pop();
814 ftm::idNode nodeOrigin = tree->getNode(node)->getOrigin();
815 //if(isRoot(tree, nodeOrigin)) continue; // TODO manage root gap and
816 gap for the others
817
818 bool isBranchImportant = isImportantPair<dataType>(tree, nodeOrigin,
819 importantPairs_); if(not isBranchImportant) continue;
820
821 double gap = retVec[treeSimplexId[node]*2] -
822 std::get<0>(allBranchBounds[nodeOrigin]); realImportantPairsGap =
823 std::max(gap, realImportantPairsGap);
824 }
825 realImportantPairsGap *= 1.05;
826 }*/
827 realImportantPairsGap = importantPairsGap;
828
829 // Shift given real gap
830 for(auto leaf : leaves)
831 queueCrossing.emplace(leaf);
832 while(!queueCrossing.empty()) {
833 ftm::idNode const node = queueCrossing.front();
834 queueCrossing.pop();
835 ftm::idNode const nodeOrigin = tree->getNode(node)->getOrigin();
836
837 bool const isBranchImportant = tree->isImportantPair<dataType>(
840 if(not isBranchImportant)
841 continue;
842
843 for(size_t i = 0; i < allBranchOrigins[nodeOrigin].size(); ++i) {
844 ftm::idNode const branchNodeOrigin = allBranchOrigins[nodeOrigin][i];
845 bool const isSubBranchImportant = tree->isImportantPair<dataType>(
846 branchNodeOrigin, importantPairs_,
849 double shift = 0;
850 if(not isSubBranchImportant) {
851 double const gap = retVec[treeSimplexId[node] * 2]
852 - std::get<0>(allBranchBounds[nodeOrigin]);
853 shift
854 = -(realImportantPairsGap - gap) * nonImportantPairsProximity_;
855 } else {
856 shift = -(importantPairsGap
857 - realImportantPairsGap); // TODO multi shift depending on
858 // conflict
859 }
860 shiftBranchBounds(retVec, treeSimplexId, branching, allBranchBounds,
861 allBranchOrigins[branchNodeOrigin], tree,
862 branchNodeOrigin, shift);
863 }
864 }
865
866 std::stringstream ss6;
867 ss6 << "AVOID CROSSING = " << t_avoid.getElapsedTime();
870
871 // ----------------------------------------------------
872 // Call Path Planar Layout if asked
873 // ----------------------------------------------------
876 tree, retVec, treeSimplexId, leaves, importantPairsGap);
877 return;
878 }
879 }
880
881 template <class dataType>
883 ftm::FTMTree_MT *tree,
884 std::tuple<double, double, double, double, double, double> oldBounds,
885 double refPersistence,
886 std::vector<float> &res) {
887 treePlanarLayoutImpl<dataType>(tree, oldBounds, refPersistence, res);
888 }
889
890 // ========================================================================
891 // Persistence Diagram Planar Layout
892 // ========================================================================
893 template <class dataType>
895 std::vector<float> &res) {
896 res.resize(tree->getRealNumberOfNodes() * 2);
897 int cptNode = 0;
898 std::queue<ftm::idNode> queue;
899 ftm::idNode const treeRoot = tree->getRoot();
900 queue.emplace(treeRoot);
901 while(!queue.empty()) {
902 ftm::idNode const node = queue.front();
903 queue.pop();
904
905 // Get and insert point
906 auto birthDeath = tree->getBirthDeath<dataType>(node);
907 res[cptNode * 2] = std::get<0>(birthDeath);
908 res[cptNode * 2 + 1] = std::get<1>(birthDeath);
909 ++cptNode;
910
911 // Push children to the queue
912 std::vector<ftm::idNode> children;
913 tree->getChildren(node, children);
914 for(auto child : children)
915 queue.emplace(child);
916 }
917 }
918
919 // ========================================================================
920 // Bounds Utils
921 // ========================================================================
922 void printTuple(std::tuple<float, float, float, float> tup) {
924 std::stringstream ss;
925 ss << std::get<0>(tup) << " _ " << std::get<1>(tup) << " _ "
926 << std::get<2>(tup) << " _ " << std::get<3>(tup) << " _ ";
928 }
929
930 // Branchroot must be a non-leaf node
931 std::tuple<float, float, float, float>
932 getBranchBounds(std::vector<float> &retVec,
933 std::vector<LongSimplexId> &treeSimplexId,
934 std::vector<ftm::idNode> &branching,
935 ftm::FTMTree_MT *tree,
936 ftm::idNode branchRoot,
937 bool restricted = false) {
938 float x_min = std::numeric_limits<float>::max();
939 float y_min = std::numeric_limits<float>::max();
940 float x_max = std::numeric_limits<float>::lowest();
941 float y_max = std::numeric_limits<float>::lowest();
942
943 std::queue<ftm::idNode> queue;
944 queue.emplace(branchRoot);
945 while(!queue.empty()) {
946 ftm::idNode const node = queue.front();
947 queue.pop();
948
949 // Skip if we go in the branch in which is branchRoot
950 if(branching[node] != branchRoot
951 and tree->getParentSafe(node) == branchRoot and node != branchRoot)
952 continue;
953
954 // Skip if restricted
955 if(restricted and !tree->isLeaf(node) and branching[node] != branchRoot
956 and node != branchRoot)
957 continue;
958
959 y_min = std::min(y_min, retVec[treeSimplexId[node] * 2 + 1]);
960 y_max = std::max(y_max, retVec[treeSimplexId[node] * 2 + 1]);
961 if(node != branchRoot) {
962 x_min = std::min(x_min, retVec[treeSimplexId[node] * 2]);
963 x_max = std::max(x_max, retVec[treeSimplexId[node] * 2]);
964 }
965
966 std::vector<ftm::idNode> children;
967 tree->getChildren(node, children);
968 for(auto child : children)
969 queue.emplace(child);
970 }
971
972 return std::make_tuple(x_min, x_max, y_min, y_max);
973 }
974
976 std::tuple<float, float, float, float> first,
977 std::tuple<float, float, float, float> second) {
978 return (std::get<0>(first) <= std::get<0>(second) + 1e-6
979 and std::get<0>(second) <= std::get<1>(first) + 1e-6)
980 or (std::get<0>(first) <= std::get<1>(second) + 1e-6
981 and std::get<1>(second) <= std::get<1>(first) + 1e-6);
982 }
983
984 bool isConflictingBoundsX(std::tuple<float, float, float, float> first,
985 std::tuple<float, float, float, float> second) {
986 return isConflictingBoundsXOneWay(first, second)
987 or isConflictingBoundsXOneWay(second, first);
988 }
989
991 std::tuple<float, float, float, float> first,
992 std::tuple<float, float, float, float> second) {
993 return (std::get<2>(first) <= std::get<2>(second) + 1e-6
994 and std::get<2>(second) <= std::get<3>(first) + 1e-6)
995 or (std::get<2>(first) <= std::get<3>(second) + 1e-6
996 and std::get<3>(second) <= std::get<3>(first) + 1e-6);
997 }
998
999 bool isConflictingBoundsY(std::tuple<float, float, float, float> first,
1000 std::tuple<float, float, float, float> second) {
1001 return isConflictingBoundsYOneWay(first, second)
1002 or isConflictingBoundsYOneWay(second, first);
1003 }
1004
1005 bool isConflictingBounds(std::tuple<float, float, float, float> first,
1006 std::tuple<float, float, float, float> second) {
1007 return isConflictingBoundsX(first, second)
1008 and isConflictingBoundsY(first, second);
1009 }
1010
1011 bool
1012 isConflictingBranchAndBound(std::tuple<float, float, float, float> first,
1013 std::tuple<float, float, float, float> second,
1014 ftm::FTMTree_MT *tree,
1015 ftm::idNode branchNodeOrigin,
1016 std::vector<float> &retVec,
1017 std::vector<LongSimplexId> &treeSimplexId) {
1018 float const xBranchNodeOrigin
1019 = retVec[treeSimplexId[branchNodeOrigin] * 2];
1020 float const xBranchNode
1021 = retVec[treeSimplexId[tree->getNode(branchNodeOrigin)->getOrigin()]
1022 * 2];
1023 float const myMin = std::min(xBranchNode, xBranchNodeOrigin);
1024 float const myMax = std::max(xBranchNode, xBranchNodeOrigin);
1025 auto branchBounds = std::make_tuple(myMin, myMax, 0, 0);
1026 return isConflictingBoundsX(first, branchBounds)
1027 and isConflictingBoundsY(first, second);
1028 }
1029
1030 std::tuple<float, float, float, float>
1031 shiftBranchBoundsTuple(std::tuple<float, float, float, float> branchBound,
1032 float realShift) {
1033 return std::make_tuple(std::get<0>(branchBound) + realShift,
1034 std::get<1>(branchBound) + realShift,
1035 std::get<2>(branchBound),
1036 std::get<3>(branchBound));
1037 }
1038
1040 std::vector<float> &retVec,
1041 std::vector<LongSimplexId> &treeSimplexId,
1042 std::vector<ftm::idNode> &branching,
1043 std::vector<std::tuple<float, float, float, float>> &allBranchBounds,
1044 std::vector<ftm::idNode> &branchOrigins,
1045 ftm::FTMTree_MT *tree,
1046 ftm::idNode branchRoot,
1047 float shift) {
1048 std::queue<ftm::idNode> queue;
1049 queue.emplace(branchRoot);
1050 while(!queue.empty()) {
1051 ftm::idNode const node = queue.front();
1052 queue.pop();
1053
1054 if(branching[node] != branchRoot
1055 and tree->getParentSafe(node) == branchRoot and node != branchRoot)
1056 continue;
1057
1058 if(node != branchRoot)
1059 retVec[treeSimplexId[node] * 2] += shift;
1060
1061 std::vector<ftm::idNode> children;
1062 tree->getChildren(node, children);
1063 for(auto child : children)
1064 queue.emplace(child);
1065 }
1066 allBranchBounds[branchRoot]
1067 = shiftBranchBoundsTuple(allBranchBounds[branchRoot], shift);
1068 for(auto node : branchOrigins)
1069 allBranchBounds[node]
1070 = shiftBranchBoundsTuple(allBranchBounds[node], shift);
1071 }
1072
1074 std::tuple<double, double, double, double, double, double> &tup,
1075 std::vector<double> &vec) {
1076 vec = std::vector<double>{std::get<0>(tup), std::get<1>(tup),
1077 std::get<2>(tup), std::get<3>(tup),
1078 std::get<4>(tup), std::get<5>(tup)};
1079 }
1080
1081 std::tuple<double, double, double, double, double, double>
1082 vectorToTuple(std::vector<double> &vec) {
1083 return std::make_tuple(vec[0], vec[1], vec[2], vec[3], vec[4], vec[5]);
1084 }
1085
1086 std::tuple<double, double, double, double, double, double> getMaximalBounds(
1087 std::vector<std::tuple<double, double, double, double, double, double>>
1088 &allBounds,
1089 std::vector<int> &clusteringAssignmentT,
1090 int clusterID) {
1091 double x_min = std::numeric_limits<double>::max();
1092 double y_min = std::numeric_limits<double>::max();
1093 double z_min = std::numeric_limits<double>::max();
1094 double x_max = std::numeric_limits<double>::lowest();
1095 double y_max = std::numeric_limits<double>::lowest();
1096 double z_max = std::numeric_limits<double>::lowest();
1097 for(size_t i = 0; i < allBounds.size(); ++i)
1098 if(clusteringAssignmentT[i] == clusterID) {
1099 x_min = std::min(x_min, std::get<0>(allBounds[i]));
1100 x_max = std::max(x_max, std::get<1>(allBounds[i]));
1101 y_min = std::min(y_min, std::get<2>(allBounds[i]));
1102 y_max = std::max(y_max, std::get<3>(allBounds[i]));
1103 z_min = std::min(z_min, std::get<4>(allBounds[i]));
1104 z_max = std::max(z_max, std::get<5>(allBounds[i]));
1105 }
1106 return std::make_tuple(x_min, x_max, y_min, y_max, z_min, z_max);
1107 }
1108
1109 // ========================================================================
1110 // Utils
1111 // ==========================================================================
1112 void parseExcludeImportantPairsString(std::string &excludeString,
1113 std::vector<double> &excludeVector) {
1114 excludeVector.clear();
1115 if(excludeString.empty())
1116 return;
1117 std::string s{excludeString};
1118 std::string const delimiter = ",";
1119
1120 size_t pos = 0;
1121 std::string token;
1122 while((pos = s.find(delimiter)) != std::string::npos) {
1123 token = s.substr(0, pos);
1124 excludeVector.emplace_back(std::stod(token));
1125 s.erase(0, pos + delimiter.length());
1126 }
1127 excludeVector.emplace_back(std::stod(s));
1128 }
1129 };
1130
1131} // namespace ttk
#define ttkNotUsed(x)
Mark function/method parameters that are not used in the function body at all.
Definition BaseClass.h:47
int printWrn(const std::string &msg, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cerr) const
Definition Debug.h:159
int printErr(const std::string &msg, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cerr) const
Definition Debug.h:149
bool isConflictingBoundsY(std::tuple< float, float, float, float > first, std::tuple< float, float, float, float > second)
void tupleToVector(std::tuple< double, double, double, double, double, double > &tup, std::vector< double > &vec)
void pathPlanarLayout(ftm::FTMTree_MT *tree, std::vector< float > &retVec, std::vector< LongSimplexId > &treeSimplexId, std::vector< ftm::idNode > &leaves, double importantPairsGap)
std::tuple< float, float, float, float > shiftBranchBoundsTuple(std::tuple< float, float, float, float > branchBound, float realShift)
void treePlanarLayoutBDImpl(ftm::FTMTree_MT *tree, std::vector< float > &retVec, std::vector< LongSimplexId > &treeSimplexId, std::vector< ftm::idNode > &ttkNotUsed(branching), std::vector< std::vector< ftm::idNode > > &nodeBranching)
void shiftBranchBounds(std::vector< float > &retVec, std::vector< LongSimplexId > &treeSimplexId, std::vector< ftm::idNode > &branching, std::vector< std::tuple< float, float, float, float > > &allBranchBounds, std::vector< ftm::idNode > &branchOrigins, ftm::FTMTree_MT *tree, ftm::idNode branchRoot, float shift)
void printTuple(std::tuple< float, float, float, float > tup)
void shiftSubtreeBounds(ftm::FTMTree_MT *tree, ftm::idNode subtreeRoot, double shift, std::vector< float > &retVec, std::vector< LongSimplexId > &treeSimplexId)
std::tuple< float, float, float, float > getBranchBounds(std::vector< float > &retVec, std::vector< LongSimplexId > &treeSimplexId, std::vector< ftm::idNode > &branching, ftm::FTMTree_MT *tree, ftm::idNode branchRoot, bool restricted=false)
bool isConflictingBranchAndBound(std::tuple< float, float, float, float > first, std::tuple< float, float, float, float > second, ftm::FTMTree_MT *tree, ftm::idNode branchNodeOrigin, std::vector< float > &retVec, std::vector< LongSimplexId > &treeSimplexId)
void setExcludeImportantPairsLower(std::string &d)
bool isConflictingBounds(std::tuple< float, float, float, float > first, std::tuple< float, float, float, float > second)
std::vector< double > excludeImportantPairsLowerValues_
void treePlanarLayoutImpl(ftm::FTMTree_MT *tree, std::tuple< double, double, double, double, double, double > oldBounds, double ttkNotUsed(refPersistence), std::vector< float > &retVec)
std::tuple< double, double, double, double, double, double > vectorToTuple(std::vector< double > &vec)
void setExcludeImportantPairsHigher(std::string &d)
void persistenceDiagramPlanarLayout(ftm::FTMTree_MT *tree, std::vector< float > &res)
std::vector< double > excludeImportantPairsHigherValues_
bool isConflictingBoundsYOneWay(std::tuple< float, float, float, float > first, std::tuple< float, float, float, float > second)
bool isConflictingBoundsXOneWay(std::tuple< float, float, float, float > first, std::tuple< float, float, float, float > second)
void parseExcludeImportantPairsString(std::string &excludeString, std::vector< double > &excludeVector)
std::tuple< double, double, double, double, double, double > getMaximalBounds(std::vector< std::tuple< double, double, double, double, double, double > > &allBounds, std::vector< int > &clusteringAssignmentT, int clusterID)
bool isConflictingBoundsX(std::tuple< float, float, float, float > first, std::tuple< float, float, float, float > second)
void treePlanarLayout(ftm::FTMTree_MT *tree, std::tuple< double, double, double, double, double, double > oldBounds, double refPersistence, std::vector< float > &res)
~MergeTreeVisualization() override=default
double getElapsedTime()
Definition Timer.h:15
bool isBranchOrigin(idNode nodeId) const
Node * getNode(idNode nodeId) const
Definition FTMTree_MT.h:393
const scalarType & getValue(SimplexId nodeId) const
Definition FTMTree_MT.h:339
void getChildren(idNode nodeId, std::vector< idNode > &res) const
void getTreeBranching(std::vector< idNode > &branching, std::vector< int > &branchingID, std::vector< std::vector< idNode > > &nodeBranching) const
idNode getNumberOfNodes() const
Definition FTMTree_MT.h:389
idNode getRoot() const
idNode getLowestNode(idNode nodeStart) const
idNode getParentSafe(idNode nodeId) const
void getAllNodeLevel(std::vector< int > &res) const
int getRealNumberOfNodes() const
void getLeavesFromTree(std::vector< idNode > &res) const
dataType getNodePersistence(idNode nodeId) const
void getBranchOriginsFromThisBranch(idNode node, std::tuple< std::vector< idNode >, std::vector< idNode > > &res) const
bool isLeaf(idNode nodeId) const
bool isRoot(idNode nodeId) const
std::tuple< dataType, dataType > getBirthDeath(idNode nodeId) const
bool isNodeAlone(idNode nodeId) const
bool isImportantPair(idNode nodeId, double threshold, std::vector< double > &excludeLower, std::vector< double > &excludeHigher) const
SimplexId getOrigin() const
Definition FTMNode.h:64
unsigned int idNode
Node index in vect_nodes_.
TTK base package defining the standard types.
T end(std::pair< T, T > &p)
Definition ripser.cpp:503
T begin(std::pair< T, T > &p)
Definition ripser.cpp:499
printMsg(debug::output::BOLD+" | | | | | . \\ | | (__| | / __/| |_| / __/| (_) |"+debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, stream)