TTK
Loading...
Searching...
No Matches
ttkMergeTreeVisualization.h
Go to the documentation of this file.
1
7
8#pragma once
9
10#include <FTMTree.h>
12
13#include <ttkAlgorithm.h>
14
15// VTK Includes
16#include <vtkAppendFilter.h>
17#include <vtkCellData.h>
18#include <vtkDoubleArray.h>
19#include <vtkFloatArray.h>
20#include <vtkImageData.h>
21#include <vtkIntArray.h>
22#include <vtkPointData.h>
23#include <vtkPoints.h>
24#include <vtkStringArray.h>
25#include <vtkUnstructuredGrid.h>
26
28private:
29 // redefine types
30 using idNode = ttk::ftm::idNode;
31 using SimplexId = ttk::SimplexId;
32 using FTMTree_MT = ttk::ftm::FTMTree_MT;
33
34 // Visualization parameters
35 bool PlanarLayout = false;
36 double DimensionSpacing = 1.;
37 int DimensionToShift = 0;
38 double XShift = 1.0;
39 double YShift = 0.0;
40 double ZShift = 0.0;
41 bool OutputSegmentation = false;
42 int MaximumImportantPairs = 0;
43 int MinimumImportantPairs = 0;
44 bool outputTreeNodeIndex = false;
45 bool isPersistenceDiagram = false;
46 bool convertedToDiagram = false;
47 bool isPDSadMax = true;
48 bool enableBarycenterAlignment = false;
49
50 // Shift mode
51 // -1: None ; 0: Star ; 1: Star Barycenter ; 2: Line ; 3: Double Line
52 int ShiftMode = 0;
53
54 // Offset
55 int iSampleOffset = 0;
56 int noSampleOffset = 0;
57 double prevXMaxOffset = 0;
58
59 // Print only one tree
60 int printTreeId = -1; // -1 for all
61 int printClusterId = -1; // -1 for all
62
63 // Barycenter position according alpha
64 bool BarycenterPositionAlpha = false;
65 double Alpha = 0.5;
66
67 // Used for critical type and for point coordinates
68 std::vector<vtkUnstructuredGrid *> treesNodes;
69 std::vector<std::vector<int>>
70 treesNodeCorrMesh; // used to access treesNodes given input trees
71
72 // Segmentation
73 std::vector<vtkDataSet *> treesSegmentation;
74
75 // Clustering output
76 std::vector<int> clusteringAssignment;
77 std::vector<std::vector<std::vector<std::tuple<idNode, idNode, double>>>>
78 outputMatchingBarycenter;
79
80 // Path layout
81 std::vector<std::vector<
82 std::vector<std::pair<std::pair<ttk::ftm::idNode, ttk::ftm::idNode>,
83 std::pair<ttk::ftm::idNode, ttk::ftm::idNode>>>>>
84 pathMatchings;
85
86 // Barycenter output
87 std::vector<std::vector<float>> allBaryPercentMatch;
88
89 // Temporal Subsampling Output
90 std::vector<bool> interpolatedTrees;
91
92 // Output
93 vtkUnstructuredGrid *vtkOutputNode{};
94 vtkUnstructuredGrid *vtkOutputArc{};
95 vtkDataSet *vtkOutputSegmentation{};
96
97 // Matching output
98 vtkUnstructuredGrid *vtkOutputNode1{}, *vtkOutputNode2{}; // input data
99 std::vector<std::vector<SimplexId>> nodeCorr1, nodeCorr2;
100 vtkUnstructuredGrid *vtkOutputMatching{}; // output
101
102 // Custom array
103 std::vector<std::tuple<std::string, std::vector<double>>> customArrays;
104 std::vector<std::tuple<std::string, std::vector<int>>> customIntArrays;
105 std::vector<std::tuple<std::string, std::vector<std::string>>>
106 customStringArrays;
107
108 // Filled by the algorithm
109 std::vector<std::vector<SimplexId>> nodeCorr;
110 std::vector<double> clusterShift;
111 double prevXMax = 0;
112
113public:
115 ;
116 ~ttkMergeTreeVisualization() override = default;
117 ;
118
119 // ==========================================================================
120 // Getter / Setter
121 // ==========================================================================
122 // Visualization parameters
123 void setPlanarLayout(bool b) {
124 PlanarLayout = b;
125 }
126 void setDimensionSpacing(double d) {
127 DimensionSpacing = d;
128 }
130 DimensionToShift = i;
131 }
132 void setXshift(double shift) {
133 XShift = shift;
134 }
135 void setYshift(double shift) {
136 YShift = shift;
137 }
138 void setZshift(double shift) {
139 ZShift = shift;
140 }
141 void setDimensionsShift(double xShift, double yShift, double zShift) {
142 setXshift(xShift);
143 setYshift(yShift);
144 setZshift(zShift);
145 }
147 OutputSegmentation = b;
148 }
149 void setShiftMode(int mode) {
150 ShiftMode = mode;
151 }
152 void setMaximumImportantPairs(int maxPairs) {
153 MaximumImportantPairs = maxPairs;
154 }
155 void setMinimumImportantPairs(int minPairs) {
156 MinimumImportantPairs = minPairs;
157 }
158
159 void setOutputTreeNodeId(int doOutput) {
160 outputTreeNodeIndex = doOutput;
161 }
162
163 void setIsPersistenceDiagram(bool isPD) {
164 isPersistenceDiagram = isPD;
165 }
166 void setConvertedToDiagram(bool converted) {
167 convertedToDiagram = converted;
168 }
169 void setIsPDSadMax(bool isSadMax) {
170 isPDSadMax = isSadMax;
171 }
172
174 enableBarycenterAlignment = eba;
175 }
176
177 // Offset
178 void setISampleOffset(int offset) {
179 iSampleOffset = offset;
180 }
181 void setNoSampleOffset(int offset) {
182 noSampleOffset = offset;
183 }
184 void setPrevXMaxOffset(double offset) {
185 prevXMaxOffset = offset;
186 }
187
188 // Print only one tree
189 void setPrintTreeId(int id) {
190 printTreeId = id;
191 }
192 void setPrintClusterId(int id) {
193 printClusterId = id;
194 }
195
196 // Barycenter position according alpha
198 BarycenterPositionAlpha = pos;
199 }
200 void setAlpha(double alpha) {
201 Alpha = alpha;
202 }
203
204 // Used for critical type and if not planar layout for point coordinates
205 void setTreesNodes(std::vector<vtkUnstructuredGrid *> &nodes) {
206 treesNodes = nodes;
207 }
208 void setTreesNodeCorrMesh(std::vector<std::vector<int>> &nodeCorrMesh) {
209 treesNodeCorrMesh = nodeCorrMesh;
210 }
211 void setTreesNodes(vtkUnstructuredGrid *nodes) {
212 treesNodes.clear();
213 treesNodes.emplace_back(nodes);
214 }
215 void setTreesNodeCorrMesh(std::vector<int> &nodeCorrMesh) {
216 treesNodeCorrMesh.clear();
217 treesNodeCorrMesh.emplace_back(nodeCorrMesh);
218 }
219
220 // Segmentation
221 void setTreesSegmentation(std::vector<vtkDataSet *> &segmentation) {
222 treesSegmentation = segmentation;
223 }
224 void setTreesSegmentation(vtkDataSet *segmentation) {
225 treesSegmentation.clear();
226 treesSegmentation.emplace_back(segmentation);
227 }
228
229 // Clustering output
230 void setClusteringAssignment(std::vector<int> &asgn) {
231 clusteringAssignment = asgn;
232 }
234 std::vector<std::vector<std::vector<std::tuple<idNode, idNode, double>>>>
235 &matching) {
236 outputMatchingBarycenter = matching;
237 }
238
239 // Path layout
241 std::vector<std::vector<
242 std::vector<std::pair<std::pair<ttk::ftm::idNode, ttk::ftm::idNode>,
243 std::pair<ttk::ftm::idNode, ttk::ftm::idNode>>>>>
244 &matchings) {
245 pathMatchings = matchings;
246 }
248 FTMTree_MT *tree,
249 std::vector<
250 std::vector<std::pair<std::pair<ttk::ftm::idNode, ttk::ftm::idNode>,
251 std::pair<ttk::ftm::idNode, ttk::ftm::idNode>>>>
252 &matchings,
253 bool isFirstTree,
254 std::vector<ttk::ftm::idNode> &pathing,
255 std::vector<int> &pathingID) {
256 pathing = std::vector<idNode>(tree->getNumberOfNodes());
257 pathingID = std::vector<int>(tree->getNumberOfNodes(), -1);
258 std::vector<int> nodeLevel;
259 tree->getAllNodeLevel(nodeLevel);
260 int pathID = 0;
261 std::vector<std::vector<bool>> processed(
262 tree->getNumberOfNodes(),
263 std::vector<bool>(tree->getNumberOfNodes(), false));
264 for(auto &matching : matchings) {
265 for(auto &match : matching) {
266 auto first = (isFirstTree ? match.first.first : match.second.first);
267 auto second = (isFirstTree ? match.first.second : match.second.second);
268 auto lowest = (nodeLevel[first] < nodeLevel[second] ? second : first);
269 auto highest = (nodeLevel[first] < nodeLevel[second] ? first : second);
270 if(processed[lowest][highest])
271 continue;
272 processed[lowest][highest] = true;
273 while(lowest != highest) {
274 pathing[lowest] = highest;
275 pathingID[lowest] = pathID;
276 lowest = tree->getParentSafe(lowest);
277 }
278 if(tree->isRoot(highest)) {
279 pathing[highest] = highest;
280 pathingID[highest] = pathID;
281 }
282 ++pathID;
283 }
284 }
285 }
287 FTMTree_MT *tree,
288 std::vector<std::pair<std::pair<ttk::ftm::idNode, ttk::ftm::idNode>,
289 std::pair<ttk::ftm::idNode, ttk::ftm::idNode>>>
290 &matching,
291 bool isFirstTree,
292 std::vector<ttk::ftm::idNode> &pathing,
293 std::vector<int> &pathingID) {
294 std::vector<
295 std::vector<std::pair<std::pair<ttk::ftm::idNode, ttk::ftm::idNode>,
296 std::pair<ttk::ftm::idNode, ttk::ftm::idNode>>>>
297 matchings{matching};
298 getTreePathing(tree, matchings, isFirstTree, pathing, pathingID);
299 }
300
301 // Barycenter output
302 std::vector<std::vector<float>> getAllBaryPercentMatch() {
303 return allBaryPercentMatch;
304 }
305 void
306 setAllBaryPercentMatch(std::vector<std::vector<float>> &baryPercentMatch) {
307 allBaryPercentMatch = baryPercentMatch;
308 }
309
310 // Temporal Subsampling Output
311 void setInterpolatedTrees(std::vector<bool> &isInterpolatedTrees) {
312 interpolatedTrees = isInterpolatedTrees;
313 }
314
315 // Output
316 void setVtkOutputNode(vtkUnstructuredGrid *vtkNode) {
317 vtkOutputNode = vtkNode;
318 }
319 void setVtkOutputArc(vtkUnstructuredGrid *vtkArc) {
320 vtkOutputArc = vtkArc;
321 }
322 void setVtkOutputSegmentation(vtkDataSet *vtkSegmentation) {
323 vtkOutputSegmentation = vtkSegmentation;
324 }
325
326 // Matching output
327 void setVtkOutputNode1(vtkUnstructuredGrid *vtkNode1) {
328 vtkOutputNode1 = vtkNode1;
329 }
330 void setVtkOutputNode2(vtkUnstructuredGrid *vtkNode2) {
331 vtkOutputNode2 = vtkNode2;
332 }
333 void setNodeCorr1(std::vector<std::vector<SimplexId>> &nodeCorrT) {
334 nodeCorr1 = nodeCorrT;
335 }
336 void setNodeCorr2(std::vector<std::vector<SimplexId>> &nodeCorrT) {
337 nodeCorr2 = nodeCorrT;
338 }
339 void setVtkOutputMatching(vtkUnstructuredGrid *vtkMatching) {
340 vtkOutputMatching = vtkMatching;
341 }
343 std::vector<std::tuple<idNode, idNode, double>> &matching) {
344 outputMatchingBarycenter.resize(1);
345 outputMatchingBarycenter[0].resize(1);
346 outputMatchingBarycenter[0][0] = matching;
347 }
348
349 // Custom array
350 void addCustomArray(std::string &name, std::vector<double> &vec) {
351 customArrays.emplace_back(name, vec);
352 }
353 void addCustomIntArray(std::string &name, std::vector<int> &vec) {
354 customIntArrays.emplace_back(name, vec);
355 }
356 void addCustomStringArray(std::string &name, std::vector<std::string> &vec) {
357 customStringArrays.emplace_back(name, vec);
358 }
360 customArrays.clear();
361 }
363 customIntArrays.clear();
364 }
366 customStringArrays.clear();
367 }
373
374 template <class dataType>
376 std::vector<std::tuple<std::string, std::vector<dataType>>> &cArrays,
377 std::vector<std::vector<dataType>> &cArraysValues,
378 vtkUnstructuredGrid *vtkOutput,
379 int type,
380 int output) {
381 for(unsigned int i = 0; i < cArrays.size(); ++i) {
382 vtkNew<vtkDoubleArray> customDoubleArrayVtk;
383 vtkNew<vtkIntArray> customIntArrayVtk;
384 vtkNew<vtkStringArray> customStringArrayVtk;
385 vtkAbstractArray *customArrayVtk;
386 if(type == 0)
387 customArrayVtk = customDoubleArrayVtk;
388 else if(type == 1)
389 customArrayVtk = customIntArrayVtk;
390 else
391 customArrayVtk = customStringArrayVtk;
392 customArrayVtk->SetName(std::get<0>(cArrays[i]).c_str());
393 customArrayVtk->SetNumberOfTuples(cArraysValues[i].size());
394 for(unsigned int j = 0; j < cArraysValues[i].size(); ++j) {
395 // Add value depending on type (vtkAbstractArray can not be used here)
396 if(type == 0) {
397 double const doubleValue
398 = (*(std::vector<double> *)&(cArraysValues[i]))[j];
399 customDoubleArrayVtk->SetValue(j, doubleValue);
400 } else if(type == 1) {
401 int const intValue = (*(std::vector<int> *)&(cArraysValues[i]))[j];
402 customIntArrayVtk->SetValue(j, intValue);
403 } else {
404 std::string const stringValue
405 = (*(std::vector<std::string> *)&(cArraysValues[i]))[j];
406 customStringArrayVtk->SetValue(j, stringValue);
407 }
408 }
409 if(output == 0)
410 vtkOutput->GetPointData()->AddArray(customArrayVtk);
411 else
412 vtkOutput->GetCellData()->AddArray(customArrayVtk);
413 }
414 }
415
416 void getTreeNodeIdRev(vtkDataArray *treeNodeIdArray,
417 std::vector<int> &treeNodeIdRev) {
418 double valueRange[2];
419 treeNodeIdArray->GetRange(valueRange);
420 int const maxValue = valueRange[1];
421 treeNodeIdRev.clear();
422 treeNodeIdRev.resize(maxValue + 1);
423 for(int i = 0; i < treeNodeIdArray->GetNumberOfValues(); ++i)
424 treeNodeIdRev[treeNodeIdArray->GetTuple1(i)] = i;
425 }
426
427 void copyPointData(vtkUnstructuredGrid *treeNodes,
428 std::vector<int> &nodeCorrT) {
429 if(!treeNodes)
430 return;
431
432 auto treeNodeIdArray = treeNodes->GetPointData()->GetArray("TreeNodeId");
433 std::vector<int> treeNodeIdRev;
434 if(treeNodeIdArray)
435 getTreeNodeIdRev(treeNodeIdArray, treeNodeIdRev);
436
437 for(int i = 0; i < treeNodes->GetPointData()->GetNumberOfArrays(); ++i) {
438 auto dataArray
439 = vtkDataArray::SafeDownCast(treeNodes->GetPointData()->GetArray(i));
440 auto stringArray
441 = vtkStringArray::SafeDownCast(treeNodes->GetPointData()->GetArray(i));
442 vtkAbstractArray *array;
443 if(dataArray)
444 array = dataArray;
445 else if(stringArray)
446 array = stringArray;
447 else
448 continue;
449 auto vecSize = (nodeCorrT.size() == 0 ? array->GetNumberOfValues()
450 : nodeCorrT.size());
451 std::vector<double> vec(vecSize);
452 std::vector<std::string> vecString(vecSize);
453 for(unsigned int j = 0; j < vec.size(); ++j) {
454 int toGet = (nodeCorrT.size() == 0 ? j : nodeCorrT[j]);
455 if(treeNodeIdArray)
456 toGet = (nodeCorrT.size() == 0 ? treeNodeIdRev[j]
457 : treeNodeIdRev[nodeCorrT[j]]);
458 auto value = array->GetVariantValue(toGet);
459 if(dataArray)
460 vec[j] = value.ToDouble();
461 else
462 vecString[j] = value.ToString();
463 }
464 std::string name{array->GetName()};
465 if(dataArray)
466 addCustomArray(name, vec);
467 else
468 addCustomStringArray(name, vecString);
469 }
470 }
471 void copyPointData(vtkUnstructuredGrid *treeNodes) {
472 std::vector<int> nodeCorrT;
473 copyPointData(treeNodes, nodeCorrT);
474 }
475
476 // Filled by the algorithm
477 std::vector<std::vector<SimplexId>> getNodeCorr() {
478 return nodeCorr;
479 }
480 std::vector<double> getClusterShift() {
481 return clusterShift;
482 }
483 double getPrevXMax() {
484 return prevXMax;
485 }
486
487 // ==========================================================================
488 // Matching Visualization
489 // ==========================================================================
490 template <class dataType>
491 void makeMatchingOutput(FTMTree_MT *tree1, FTMTree_MT *tree2) {
492 std::vector<FTMTree_MT *> trees{tree1, tree2};
493 std::vector<FTMTree_MT *> barycenters;
494
495 makeMatchingOutput<dataType>(trees, barycenters);
496 }
497
498 template <class dataType>
499 void makeMatchingOutput(std::vector<FTMTree_MT *> &trees,
500 std::vector<FTMTree_MT *> &barycenters) {
501 int numInputs = trees.size();
502 int NumberOfBarycenters = barycenters.size();
503 bool const clusteringOutput = (NumberOfBarycenters != 0);
504 NumberOfBarycenters
505 = std::max(NumberOfBarycenters, 1); // to always enter the outer loop
506 if(not clusteringOutput)
507 numInputs = 1;
508
509 vtkNew<vtkUnstructuredGrid> vtkMatching{};
510 vtkNew<vtkPoints> pointsM{};
511
512 // Fields
513 vtkNew<vtkIntArray> matchingID{};
514 matchingID->SetName("MatchingID");
515 vtkNew<vtkIntArray> matchingType{};
516 matchingType->SetName("MatchingType");
517 vtkNew<vtkDoubleArray> matchPers{};
518 matchPers->SetName("MeanMatchedPersistence");
519 vtkNew<vtkDoubleArray> costArray{};
520 costArray->SetName("Cost");
521 vtkNew<vtkIntArray> tree1NodeIdField{};
522 tree1NodeIdField->SetName("tree1NodeId");
523 vtkNew<vtkIntArray> tree2NodeIdField{};
524 tree2NodeIdField->SetName("tree2NodeId");
525 vtkNew<vtkIntArray> mergeTree1NodeIdField{};
526 mergeTree1NodeIdField->SetName("mergeTree1NodeId");
527 vtkNew<vtkIntArray> mergeTree2NodeIdField{};
528 mergeTree2NodeIdField->SetName("mergeTree2NodeId");
529 vtkNew<vtkIntArray> isBarycenterNodeField{};
530 isBarycenterNodeField->SetName("isBarycenterNode");
531
532 vtkNew<vtkFloatArray> matchingPercentMatch{};
533 matchingPercentMatch->SetName("MatchingPercentMatch");
534
535 // Iterate through clusters and trees
536 printMsg(
537 "// Iterate through clusters and trees", ttk::debug::Priority::VERBOSE);
538 int count = 0;
539 for(int c = 0; c < NumberOfBarycenters; ++c) {
540 for(int i = 0; i < numInputs; ++i) {
541 if((printTreeId == -1 and printClusterId != -1 and c != printClusterId)
542 or (printTreeId != -1 and printClusterId == -1 and i != printTreeId)
543 or (printTreeId != -1 and printClusterId != -1
544 and (c != printClusterId or i != printTreeId)))
545 continue;
546 for(std::tuple<idNode, idNode, double> match :
547 outputMatchingBarycenter[c][i]) {
548 vtkIdType pointIds[2];
549 idNode tree1NodeId = std::get<0>(match);
550 idNode tree2NodeId = std::get<1>(match);
551 double const cost = std::get<2>(match);
552 FTMTree_MT *tree1;
553 FTMTree_MT *tree2 = trees[i];
554 if(not clusteringOutput) {
555 tree1 = trees[0];
556 tree2 = trees[1];
557 } else
558 tree1 = barycenters[c];
559
560 // Get first point
561 printMsg("// Get first point", ttk::debug::Priority::VERBOSE);
562 SimplexId const pointToGet1 = clusteringOutput
563 ? nodeCorr2[c][tree1NodeId]
564 : nodeCorr1[0][tree1NodeId];
565 double *point1 = vtkOutputNode2->GetPoints()->GetPoint(pointToGet1);
566 const SimplexId nextPointId1 = pointsM->InsertNextPoint(point1);
567 if(not clusteringOutput)
568 isBarycenterNodeField->InsertNextTuple1(0);
569 else
570 isBarycenterNodeField->InsertNextTuple1(1);
571 pointIds[0] = nextPointId1;
572
573 // Get second point
574 printMsg("// Get second point", ttk::debug::Priority::VERBOSE);
575 SimplexId const pointToGet2 = clusteringOutput
576 ? nodeCorr1[i][tree2NodeId]
577 : nodeCorr1[1][tree2NodeId];
578 double *point2 = vtkOutputNode1->GetPoints()->GetPoint(pointToGet2);
579 const SimplexId nextPointId2 = pointsM->InsertNextPoint(point2);
580 isBarycenterNodeField->InsertNextTuple1(0);
581 pointIds[1] = nextPointId2;
582
583 // Add cell
585 vtkMatching->InsertNextCell(VTK_LINE, 2, pointIds);
586
587 // Add arc matching percentage
588 printMsg(
589 "// Add arc matching percentage", ttk::debug::Priority::VERBOSE);
590 if(allBaryPercentMatch.size() != 0)
591 matchingPercentMatch->InsertNextTuple1(
592 allBaryPercentMatch[c][tree1NodeId]);
593
594 // Add tree1 and tree2 node ids
595 printMsg(
596 "// Add tree1 and tree2 node ids", ttk::debug::Priority::VERBOSE);
597 tree1NodeIdField->InsertNextTuple1(pointToGet1);
598 tree2NodeIdField->InsertNextTuple1(pointToGet2);
599 mergeTree1NodeIdField->InsertNextTuple1(tree1NodeId);
600 mergeTree2NodeIdField->InsertNextTuple1(tree2NodeId);
601
602 // Add matching ID
603 matchingID->InsertNextTuple1(count);
604
605 // Add matching type
606 printMsg("// Add matching type", ttk::debug::Priority::VERBOSE);
607 int thisType = 0;
608 int const tree1NodeDown
609 = tree1->getNode(tree1NodeId)->getNumberOfDownSuperArcs();
610 int const tree1NodeUp
611 = tree1->getNode(tree1NodeId)->getNumberOfUpSuperArcs();
612 int const tree2NodeDown
613 = tree2->getNode(tree2NodeId)->getNumberOfDownSuperArcs();
614 int const tree2NodeUp
615 = tree2->getNode(tree2NodeId)->getNumberOfUpSuperArcs();
616 if(tree1NodeDown != 0 and tree1NodeUp != 0 and tree2NodeDown != 0
617 and tree2NodeUp != 0)
618 thisType = 1; // Saddle to Saddle
619 if(tree1NodeDown == 0 and tree1NodeUp != 0 and tree2NodeDown == 0
620 and tree2NodeUp != 0)
621 thisType = 2; // Leaf to leaf
622 if(tree1NodeDown != 0 and tree1NodeUp == 0 and tree2NodeDown != 0
623 and tree2NodeUp == 0)
624 thisType = 3; // Root to root
625 matchingType->InsertNextTuple1(thisType);
626
627 // Add mean matched persistence
628 printMsg(
629 "// Add mean matched persistence", ttk::debug::Priority::VERBOSE);
630 double tree1Pers = tree1->getNodePersistence<dataType>(tree1NodeId);
631 double tree2Pers = tree2->getNodePersistence<dataType>(tree2NodeId);
632 double const meanPersistence = (tree1Pers + tree2Pers) / 2;
633 matchPers->InsertNextTuple1(meanPersistence);
634
635 // Add cost
636 costArray->InsertNextTuple1(cost);
637
638 count++;
639 }
640 }
641 }
642 vtkMatching->SetPoints(pointsM);
643 vtkMatching->GetCellData()->AddArray(matchingType);
644 vtkMatching->GetCellData()->AddArray(matchPers);
645 vtkMatching->GetCellData()->AddArray(matchingID);
646 vtkMatching->GetCellData()->AddArray(costArray);
647 vtkMatching->GetCellData()->AddArray(tree1NodeIdField);
648 vtkMatching->GetCellData()->AddArray(tree2NodeIdField);
649 vtkMatching->GetCellData()->AddArray(mergeTree1NodeIdField);
650 vtkMatching->GetCellData()->AddArray(mergeTree2NodeIdField);
651 vtkMatching->GetPointData()->AddArray(isBarycenterNodeField);
652 if(allBaryPercentMatch.size() != 0)
653 vtkMatching->GetCellData()->AddArray(matchingPercentMatch);
654 vtkOutputMatching->ShallowCopy(vtkMatching);
655 }
656
657 // ==========================================================================
658 // Trees Visualization
659 // ==========================================================================
660 template <class dataType>
661 void makeTreesOutput(FTMTree_MT *tree1) {
662 std::vector<FTMTree_MT *> trees{tree1};
663
665 }
666
667 template <class dataType>
668 void makeTreesOutput(FTMTree_MT *tree1, FTMTree_MT *tree2) {
669 std::vector<FTMTree_MT *> trees{tree1, tree2};
670
672 }
673
674 template <class dataType>
675 void makeTreesOutput(std::vector<FTMTree_MT *> &trees) {
676 std::vector<FTMTree_MT *> barycenters;
677 clusteringAssignment.clear();
678 clusteringAssignment.resize(trees.size(), 0);
679
680 makeTreesOutput<dataType>(trees, barycenters);
681 }
682
683 template <class dataType>
684 void makeTreesOutput(std::vector<FTMTree_MT *> &trees,
685 std::vector<FTMTree_MT *> &barycenters) {
686 int numInputs = trees.size();
687 int const numInputsOri = numInputs;
688 int NumberOfBarycenters = barycenters.size();
689 bool const clusteringOutput = (NumberOfBarycenters != 0);
690 NumberOfBarycenters
691 = std::max(NumberOfBarycenters, 1); // to always enter the outer loop
692 bool alignTrees = trees.size() == 2 and barycenters.size() == 1
693 and enableBarycenterAlignment;
694 bool const embeddedDiagram = not PlanarLayout and isPersistenceDiagram;
695
696 // TreeNodeIdRev
697 for(int i = 0; i < numInputs; ++i) {
698 if(i < (int)treesNodes.size() and treesNodes[i]) {
699 auto treeNodeIdArray
700 = treesNodes[i]->GetPointData()->GetArray("TreeNodeId");
701 if(treeNodeIdArray) {
702 std::vector<int> treeNodeIdRev;
703 getTreeNodeIdRev(treeNodeIdArray, treeNodeIdRev);
704 for(unsigned int j = 0; j < treesNodeCorrMesh[i].size(); ++j)
705 treesNodeCorrMesh[i][j] = treeNodeIdRev[treesNodeCorrMesh[i][j]];
706 }
707 }
708 }
709
710 // Bounds
711 printMsg("Bounds and branching", ttk::debug::Priority::VERBOSE);
712 std::vector<std::tuple<double, double, double, double, double, double>>
713 allBounds(numInputs);
714 for(int i = 0; i < numInputs; ++i) {
715 if(OutputSegmentation and treesSegmentation[i]) {
716 double *tBounds = treesSegmentation[i]->GetBounds();
717 allBounds[i] = std::make_tuple(tBounds[0], tBounds[1], tBounds[2],
718 tBounds[3], tBounds[4], tBounds[5]);
719 } else if(treesNodes.size() != 0 and treesNodes[i] != nullptr) {
720 if(not isPersistenceDiagram)
721 allBounds[i]
722 = getRealBounds(treesNodes[i], trees[i], treesNodeCorrMesh[i]);
723 else {
724 double bounds[6];
725 treesNodes[i]->GetBounds(bounds);
726 allBounds[i] = std::make_tuple(
727 bounds[0], bounds[1], bounds[2], bounds[3], bounds[4], bounds[5]);
728 }
729 } else {
730 allBounds[i] = allBounds[0];
731 }
732 }
733
734 std::vector<std::tuple<double, double, double, double, double, double>>
735 allBaryBounds(barycenters.size());
736 std::vector<std::vector<idNode>> allBaryBranching(barycenters.size()),
737 allBaryPathing(barycenters.size());
738 std::vector<std::vector<int>> allBaryBranchingID(barycenters.size()),
739 allBaryPathingID(barycenters.size());
740 for(size_t c = 0; c < barycenters.size(); ++c) {
741 allBaryBounds[c] = getMaximalBounds(allBounds, clusteringAssignment, c);
742 if(not isPersistenceDiagram)
743 barycenters[c]->getTreeBranching(
744 allBaryBranching[c], allBaryBranchingID[c]);
745 if(pathPlanarLayout_ and !pathMatchings.empty()
746 and !pathMatchings[c].empty())
747 getTreePathing(barycenters[c], pathMatchings[c], true,
748 allBaryPathing[c], allBaryPathingID[c]);
749 }
750 if(not clusteringOutput)
751 allBaryBounds.emplace_back(
752 getMaximalBounds(allBounds, clusteringAssignment, 0));
753
754 // ----------------------------------------------------------------------
755 // Make Trees Output
756 // ----------------------------------------------------------------------
757 printMsg("--- Make Trees Output", ttk::debug::Priority::VERBOSE);
758 std::vector<FTMTree_MT *> const treesOri(trees);
759 if(ShiftMode == 1) { // Star Barycenter
760 trees.clear();
761 clusteringAssignment.clear();
762 for(unsigned int j = 0; j < barycenters.size(); ++j) {
763 trees.emplace_back(barycenters[j]);
764 clusteringAssignment.emplace_back(j);
765 }
766 numInputs = trees.size();
767 }
768 // - Declare VTK arrays
769 vtkNew<vtkUnstructuredGrid> vtkArcs{};
770 vtkNew<vtkPoints> points{};
771
772 // Node fields
773 vtkNew<vtkIntArray> criticalType{};
774 criticalType->SetName(ttk::PersistenceCriticalTypeName);
775 vtkNew<vtkDoubleArray> persistenceNode{};
776 persistenceNode->SetName(ttk::PersistenceName);
777 vtkNew<vtkIntArray> clusterIDNode{};
778 clusterIDNode->SetName("ClusterID");
779 vtkNew<vtkIntArray> isDummyNode{};
780 isDummyNode->SetName("isDummyNode");
781 vtkNew<vtkIntArray> branchNodeID{};
782 branchNodeID->SetName("BranchNodeID");
783 vtkNew<vtkIntArray> pathNodeID{};
784 pathNodeID->SetName("PathNodeID");
785 vtkNew<vtkFloatArray> scalar{};
786 scalar->SetName("Scalar");
787 vtkNew<vtkIntArray> isImportantPairsNode{};
788 isImportantPairsNode->SetName("isImportantPair");
789 vtkNew<vtkIntArray> nodeID{};
790 nodeID->SetName("NodeId"); // Simplex Id
791 vtkNew<vtkIntArray> trueNodeID{};
792 trueNodeID->SetName("TrueNodeId");
793 vtkNew<vtkIntArray> vertexID{};
794 vertexID->SetName(
795 (isPersistenceDiagram ? ttk::VertexScalarFieldName : "VertexId"));
796
797 vtkNew<vtkIntArray> treeIDNode{};
798 treeIDNode->SetName("TreeID");
799 vtkNew<vtkIntArray> branchBaryNodeID{};
800 branchBaryNodeID->SetName("BranchBaryNodeID");
801 vtkNew<vtkIntArray> pathBaryNodeID{};
802 pathBaryNodeID->SetName("PathBaryNodeID");
803 vtkNew<vtkIntArray> isInterpolatedTreeNode{};
804 isInterpolatedTreeNode->SetName("isInterpolatedTree");
805
806 vtkNew<vtkFloatArray> percentMatch{};
807 percentMatch->SetName("PercentMatchNode");
808 vtkNew<vtkFloatArray> persistenceBaryNode{};
809 persistenceBaryNode->SetName("PersistenceBarycenter");
810 vtkNew<vtkIntArray> persistenceBaryOrderNode{};
811 persistenceBaryOrderNode->SetName("PersistenceBarycenterOrder");
812
813 vtkNew<vtkDoubleArray> pairBirthNode{};
814 pairBirthNode->SetName(ttk::PersistenceBirthName);
815
816 vtkNew<vtkFloatArray> treeNodeId{};
817 treeNodeId->SetName("TreeNodeId");
818
819 vtkNew<vtkFloatArray> treeNodeIdOrigin{};
820 treeNodeIdOrigin->SetName("TreeNodeIdOrigin");
821 vtkNew<vtkDoubleArray> coordinates{};
822 coordinates->SetName(ttk::PersistenceCoordinatesName);
823 coordinates->SetNumberOfComponents(3);
824
825 vtkNew<vtkIntArray> isMultiPersPairNode{};
826 isMultiPersPairNode->SetName("isMultiPersPairNode");
827
828 std::vector<std::vector<double>> customArraysValues(customArrays.size());
829 std::vector<std::vector<int>> customIntArraysValues(customIntArrays.size());
830 std::vector<std::vector<std::string>> customStringArraysValues(
831 customStringArrays.size());
832
833 // Arc fields
834 vtkNew<vtkDoubleArray> persistenceArc{};
835 persistenceArc->SetName(ttk::PersistenceName);
836 vtkNew<vtkIntArray> clusterIDArc{};
837 clusterIDArc->SetName("ClusterID");
838 vtkNew<vtkIntArray> isImportantPairsArc{};
839 isImportantPairsArc->SetName("isImportantPair");
840 vtkNew<vtkIntArray> isDummyArc{};
841 isDummyArc->SetName("isDummyArc");
842 vtkNew<vtkIntArray> branchID{};
843 branchID->SetName("BranchID");
844 vtkNew<vtkIntArray> pathID{};
845 pathID->SetName("PathID");
846 vtkNew<vtkIntArray> upNodeId{};
847 upNodeId->SetName("upNodeId");
848 vtkNew<vtkIntArray> downNodeId{};
849 downNodeId->SetName("downNodeId");
850
851 vtkNew<vtkIntArray> treeIDArc{};
852 treeIDArc->SetName((isPersistenceDiagram ? "DiagramID" : "TreeID"));
853 vtkNew<vtkIntArray> branchBaryID{};
854 branchBaryID->SetName("BranchBaryNodeID");
855 vtkNew<vtkIntArray> pathBaryID{};
856 pathBaryID->SetName("PathBaryNodeID");
857 vtkNew<vtkIntArray> isInterpolatedTreeArc{};
858 isInterpolatedTreeArc->SetName("isInterpolatedTree");
859
860 vtkNew<vtkFloatArray> percentMatchArc{};
861 percentMatchArc->SetName("PercentMatchArc");
862 vtkNew<vtkFloatArray> persistenceBaryArc{};
863 persistenceBaryArc->SetName("PersistenceBarycenter");
864 vtkNew<vtkIntArray> persistenceBaryOrderArc{};
865 persistenceBaryOrderArc->SetName("PersistenceBarycenterOrder");
866
867 vtkNew<vtkIntArray> pairIdentifier{};
868 pairIdentifier->SetName(ttk::PersistencePairIdentifierName);
869 vtkNew<vtkIntArray> pairType{};
870 pairType->SetName(ttk::PersistencePairTypeName);
871 vtkNew<vtkIntArray> pairIsFinite{};
872 pairIsFinite->SetName(ttk::PersistenceIsFinite);
873 vtkNew<vtkDoubleArray> pairBirth{};
874 pairBirth->SetName(ttk::PersistenceBirthName);
875
876 vtkNew<vtkIntArray> isMultiPersPairArc{};
877 isMultiPersPairArc->SetName("isMultiPersPairArc");
878
879 std::vector<std::vector<double>> customCellArraysValues(
880 customArrays.size());
881 std::vector<std::vector<int>> customCellIntArraysValues(
882 customIntArrays.size());
883 std::vector<std::vector<std::string>> customCellStringArraysValues(
884 customStringArrays.size());
885
886 // Segmentation
887 vtkNew<vtkAppendFilter> appendFilter{};
888
889 // Internal data
890 int cellCount = 0;
891 int pointCount = 0;
892 bool foundOneInterpolatedTree = false;
893 nodeCorr.clear();
894 nodeCorr.resize(numInputs);
895 clusterShift.clear();
896 clusterShift.resize(NumberOfBarycenters, 0);
897 allBaryPercentMatch.clear();
898 allBaryPercentMatch.resize(NumberOfBarycenters);
899
900 // --------------------------------------------------------
901 // Iterate through all clusters
902 // --------------------------------------------------------
903 printMsg("Iterate through all clusters", ttk::debug::Priority::VERBOSE);
904 double const importantPairsOriginal = importantPairs_;
905 for(int c = 0; c < NumberOfBarycenters; ++c) {
906
907 // Get persistence order
908 std::vector<int> baryPersistenceOrder;
909 if(clusteringOutput and ShiftMode != 1) {
910 baryPersistenceOrder.resize(barycenters[c]->getNumberOfNodes(), -1);
911 std::vector<std::tuple<ttk::ftm::idNode, ttk::ftm::idNode, dataType>>
912 pairsBary;
913 barycenters[c]->getPersistencePairsFromTree<dataType>(pairsBary, false);
914 for(unsigned int j = 0; j < pairsBary.size(); ++j) {
915 int const index = pairsBary.size() - 1 - j;
916 baryPersistenceOrder[std::get<0>(pairsBary[j])] = index;
917 baryPersistenceOrder[std::get<1>(pairsBary[j])] = index;
918 }
919 }
920
921 // Get radius
922 printMsg("// Get radius", ttk::debug::Priority::VERBOSE);
923 double delta_max = 1.0;
924 int noSample = 0 + noSampleOffset;
925 for(int i = 0; i < numInputsOri; ++i) {
926 delta_max = std::max(
927 (std::get<3>(allBounds[i]) - std::get<2>(allBounds[i])), delta_max);
928 delta_max = std::max(
929 (std::get<1>(allBounds[i]) - std::get<0>(allBounds[i])), delta_max);
930 if(clusteringAssignment[i] != c)
931 continue;
932 noSample += 1;
933 }
934 double const radius = delta_max * 2 * DimensionSpacing;
935 int iSample = 0 + iSampleOffset - 1;
936
937 if(c < NumberOfBarycenters - 1)
938 clusterShift[c + 1] = radius * 4 + clusterShift[c];
939
940 // Line/Double line attributes
941 prevXMax = 0 + prevXMaxOffset;
942 std::vector<double> allPrevXMax;
943 double prevYMax = std::numeric_limits<double>::lowest();
944
945 // ------------------------------------------
946 // Iterate through all trees of this cluster
947 // ------------------------------------------
948 printMsg("Iterate through all trees of this cluster",
950 for(int i = 0; i < numInputs; ++i) {
951 if(clusteringAssignment[i] != c)
952 continue;
953
954 iSample += 1;
955
956 if((printTreeId == -1 and printClusterId != -1 and c != printClusterId)
957 or (printTreeId != -1 and printClusterId == -1 and i != printTreeId)
958 or (printTreeId != -1 and printClusterId != -1
959 and (c != printClusterId or i != printTreeId)))
960 continue;
961
962 // Manage important pairs threshold
963 auto fixImportantPairsThreshold
964 = [&importantPairsOriginal, this](FTMTree_MT *tree) {
965 double importantPairs = importantPairsOriginal;
966 if(MaximumImportantPairs > 0 or MinimumImportantPairs > 0) {
967 std::vector<std::tuple<idNode, idNode, dataType>> pairs;
968 tree->getPersistencePairsFromTree(pairs, false);
969 if(MaximumImportantPairs > 0) {
970 int firstIndex = pairs.size() - MaximumImportantPairs;
971 firstIndex
972 = std::max(std::min(firstIndex, int(pairs.size()) - 1), 0);
973 double tempThreshold = 0.999 * std::get<2>(pairs[firstIndex])
974 / std::get<2>(pairs[pairs.size() - 1]);
975 tempThreshold *= 100;
976 importantPairs = std::max(importantPairs, tempThreshold);
977 }
978 if(MinimumImportantPairs > 0) {
979 int firstIndex = pairs.size() - MinimumImportantPairs;
980 firstIndex
981 = std::max(std::min(firstIndex, int(pairs.size()) - 1), 0);
982 double tempThreshold = 0.999 * std::get<2>(pairs[firstIndex])
983 / std::get<2>(pairs[pairs.size() - 1]);
984 tempThreshold *= 100;
985 importantPairs = std::min(importantPairs, tempThreshold);
986 }
987 }
988 return importantPairs;
989 };
990 importantPairs_ = fixImportantPairsThreshold(trees[i]);
991
992 // Get is interpolated tree (temporal subsampling)
993 bool isInterpolatedTree = false;
994 if(interpolatedTrees.size() != 0)
995 isInterpolatedTree = interpolatedTrees[i];
996 foundOneInterpolatedTree |= isInterpolatedTree;
997
998 // Get branching
999 printMsg("// Get branching", ttk::debug::Priority::VERBOSE);
1000 std::vector<idNode> treeBranching, treePathing;
1001 std::vector<int> treeBranchingID, treePathingID;
1002 std::vector<bool> isRootPath;
1003 std::vector<ttk::ftm::idNode> pathOrigin;
1004 if(not isPersistenceDiagram) {
1005 trees[i]->getTreeBranching(treeBranching, treeBranchingID);
1006 if(pathPlanarLayout_ and !pathMatchings.empty()
1007 and !pathMatchings[c].empty()) {
1008 isRootPath.resize(trees[i]->getNumberOfNodes());
1009 std::fill(isRootPath.begin(), isRootPath.end(), false);
1010 pathOrigin.resize(trees[i]->getNumberOfNodes());
1011 if(ShiftMode == 1)
1013 trees[i], pathMatchings[c], true, treePathing, treePathingID);
1014 else
1015 getTreePathing(trees[i], pathMatchings[c][i], false, treePathing,
1016 treePathingID);
1017 bool isFirstTree = (ShiftMode == 1);
1018 std::vector<int> nodeLevel;
1019 trees[i]->getAllNodeLevel(nodeLevel);
1020 for(unsigned int j = 0; j < pathMatchings[c].size(); ++j) {
1021 if((int)j != i and ShiftMode != 1)
1022 continue;
1023 for(auto &match : pathMatchings[c][j]) {
1024 auto first
1025 = (isFirstTree ? match.first.first : match.second.first);
1026 auto second
1027 = (isFirstTree ? match.first.second : match.second.second);
1028 auto lowest
1029 = (nodeLevel[first] < nodeLevel[second] ? second : first);
1030 auto highest
1031 = (nodeLevel[first] < nodeLevel[second] ? first : second);
1032 isRootPath[highest] = true;
1033 pathOrigin[lowest] = highest;
1034 pathOrigin[highest] = lowest;
1035 }
1036 }
1037 }
1038 }
1039
1040 // Get shift
1041 printMsg("// Get shift", ttk::debug::Priority::VERBOSE);
1042 double const angle = 360.0 / noSample * iSample;
1043 double const pi = M_PI;
1044 double diff_x = 0, diff_y = 0;
1045 double const alphaShift
1046 = BarycenterPositionAlpha ? (-radius + 2 * radius * Alpha) * -1 : 0;
1047 switch(ShiftMode) {
1048 case -1:
1049 diff_x = 0.0;
1050 diff_y = 0.0;
1051 break;
1052 case 0: // Star
1053 diff_x
1054 = -1 * radius * std::cos(-1 * angle * pi / 180) + clusterShift[c];
1055 diff_y = -1 * radius * std::sin(-1 * angle * pi / 180);
1056 break;
1057 case 1: // Star Barycenter
1058 diff_x = clusterShift[c] + alphaShift;
1059 diff_y = 0;
1060 break;
1061 case 2: // Line
1062 diff_x = prevXMax + radius;
1063 break;
1064 case 3: // Double Line
1065 diff_x = prevXMax + radius;
1066 if(i >= numInputs / 2) {
1067 diff_y = -(prevYMax + radius / 2);
1068 diff_x = allPrevXMax[i - int(numInputs / 2)] + radius;
1069 } else
1070 allPrevXMax.emplace_back(prevXMax);
1071 break;
1072 default:
1073 break;
1074 }
1075
1076 // isImportantPairVector
1077 auto getIsImportantPairVector
1078 = [this](FTMTree_MT *tree, std::vector<bool> &isImportantPairVector,
1079 double importantPairs) {
1080 isImportantPairVector.resize(tree->getNumberOfNodes());
1081 for(unsigned int n = 0; n < isImportantPairVector.size(); ++n)
1082 isImportantPairVector[n] = tree->isImportantPair<dataType>(
1083 n, importantPairs, excludeImportantPairsLowerValues_,
1085 };
1086 std::vector<bool> isImportantPairVector;
1087 getIsImportantPairVector(
1088 trees[i], isImportantPairVector, importantPairs_);
1089
1090 // Layout correspondence function
1091 auto getLayoutCorr
1092 = [](FTMTree_MT *tree, std::vector<SimplexId> &layoutCorr) {
1093 layoutCorr.resize(tree->getNumberOfNodes());
1094 int cptNode = 0;
1095 std::queue<idNode> queueLayoutCorr;
1096 queueLayoutCorr.emplace(tree->getRoot());
1097 while(!queueLayoutCorr.empty()) {
1098 idNode node = queueLayoutCorr.front();
1099 queueLayoutCorr.pop();
1100
1101 // Push children to the queue
1102 std::vector<idNode> children;
1103 tree->getChildren(node, children);
1104 for(auto child : children)
1105 queueLayoutCorr.emplace(child);
1106
1107 layoutCorr[node] = cptNode;
1108 cptNode += 2;
1109 }
1110 };
1111
1112 // Planar layout
1113 printMsg("// Planar Layout", ttk::debug::Priority::VERBOSE);
1114 std::vector<SimplexId> layoutCorr;
1115 getLayoutCorr(trees[i], layoutCorr);
1116 std::vector<float> layout;
1117 // TODO remove baryMatchingVector if it is not used
1118 std::vector<ttk::ftm::idNode> baryMatchingVector;
1119 // TODO put this declaration just before it is used if the vector is
1120 // not needed elsewhere
1121 std::vector<bool> isImportantPairBaryVector;
1122 if(PlanarLayout) {
1123 double refPersistence;
1124 if(clusteringOutput)
1125 refPersistence = barycenters[0]->getNodePersistence<dataType>(
1126 barycenters[0]->getRoot());
1127 else
1128 refPersistence
1129 = trees[0]->getNodePersistence<dataType>(trees[0]->getRoot());
1130 if(not isPersistenceDiagram) {
1132 trees[i], allBaryBounds[c], refPersistence, layout);
1133 // Planar Layout alignment given barycenter
1134 if(alignTrees and ShiftMode != 1) {
1135 // Create barycenter layout
1136 std::vector<float> layoutBary;
1138 barycenters[0], allBaryBounds[c], refPersistence, layoutBary);
1139 std::vector<SimplexId> layoutBaryCorr;
1140 getLayoutCorr(barycenters[0], layoutBaryCorr);
1141 // Get barycenter important pairs bool vector
1142 double isImportantPairBary
1143 = fixImportantPairsThreshold(barycenters[0]);
1144 getIsImportantPairVector(
1145 barycenters[0], isImportantPairBaryVector, isImportantPairBary);
1146 baryMatchingVector.resize(barycenters[0]->getNumberOfNodes(), -1);
1147 for(auto match : outputMatchingBarycenter[0][i])
1148 baryMatchingVector[std::get<0>(match)] = std::get<1>(match);
1149 std::vector<float> shifts(trees[i]->getNumberOfNodes(), 0);
1150 for(auto match : outputMatchingBarycenter[0][i]) {
1151 // Update tree important pair according barycenter
1152 isImportantPairVector[std::get<1>(match)]
1153 = isImportantPairBaryVector[std::get<0>(match)];
1154 // Update tree layout according barycenter layout
1155 layout[layoutCorr[std::get<1>(match)]]
1156 = layoutBary[layoutBaryCorr[std::get<0>(match)]];
1157 if(not isImportantPairVector[std::get<1>(match)]) {
1158 // Search for birth swap with an important pair
1159 ttk::ftm::idNode node = std::get<0>(match);
1160 while(not isImportantPairBaryVector[node])
1161 node = barycenters[0]->getParentSafe(node);
1162 bool baryNodeSup
1163 = barycenters[0]->getValue<dataType>(node)
1164 > barycenters[0]->getValue<dataType>(std::get<0>(match));
1165 bool treeNodeSup
1166 = trees[i]->getValue<dataType>(baryMatchingVector[node])
1167 > trees[i]->getValue<dataType>(std::get<1>(match));
1168 if((not baryNodeSup and treeNodeSup)
1169 or (baryNodeSup and not treeNodeSup)) {
1170 float shift
1171 = std::abs(layout[layoutCorr[std::get<1>(match)]]
1172 - layoutBary[layoutBaryCorr[node]]);
1173 layout[layoutCorr[std::get<1>(match)]]
1174 = layoutBary[layoutBaryCorr[node]];
1175 std::queue<ttk::ftm::idNode> queueShift;
1176 queueShift.emplace(
1177 trees[i]->getNode(std::get<1>(match))->getOrigin());
1178 while(!queueShift.empty()) {
1179 ttk::ftm::idNode nodeToShift = queueShift.front();
1180 queueShift.pop();
1181 shifts[nodeToShift] += shift;
1182 ttk::ftm::idNode nodeToShiftParent
1183 = trees[i]->getParentSafe(nodeToShift);
1184 if(nodeToShiftParent != std::get<1>(match))
1185 queueShift.emplace(nodeToShiftParent);
1186 std::vector<ttk::ftm::idNode> children;
1187 trees[i]->getChildren(nodeToShift, children);
1188 for(auto &child : children)
1189 queueShift.emplace(child);
1190 }
1191 }
1192 }
1193 }
1194 for(unsigned int s = 0; s < shifts.size(); ++s)
1195 layout[layoutCorr[s]] += shifts[s];
1196 }
1197 } else {
1199 }
1200 }
1201
1202 // Get dimension shift
1203 printMsg("// Get dimension shift", ttk::debug::Priority::VERBOSE);
1204 double diff_z = PlanarLayout ? 0 : -std::get<4>(allBounds[i]);
1205 if(DimensionToShift != 0) { // is not X
1206 float minX = 0;
1207 if(PlanarLayout) {
1208 minX = layout[0];
1209 for(unsigned int l = 0; l < layout.size(); ++l) {
1210 if(l % 2 == 0)
1211 minX = std::min(minX, layout[l]);
1212 }
1213 }
1214 double new_diff_x = PlanarLayout ? -minX : -std::get<0>(allBounds[i]);
1215 bool diffYAllowed
1216 = (not clusteringOutput
1217 or (trees.size() == 2 and barycenters.size() == 1));
1218 if(DimensionToShift == 2) {
1219 // is Z
1220 diff_z = -diff_x;
1221 diff_x = new_diff_x;
1222 } else if(diffYAllowed and DimensionToShift == 1) {
1223 // is Y
1224 diff_y = diff_x;
1225 diff_x = new_diff_x;
1226 } else if(DimensionToShift == 3) {
1227 // Custom
1228 if(diffYAllowed)
1229 diff_y = YShift * diff_x + (1 - YShift) * diff_y;
1230 diff_z = ZShift * -diff_x + (1 - ZShift) * diff_z;
1231 diff_x = XShift * diff_x + (1 - XShift) * new_diff_x;
1232 }
1233 }
1234
1235 // Internal arrays
1236 printMsg("// Internal arrays", ttk::debug::Priority::VERBOSE);
1237 nodeCorr[i].resize(trees[i]->getNumberOfNodes());
1238 std::vector<SimplexId> treeSimplexId(trees[i]->getNumberOfNodes());
1239 std::vector<SimplexId> treeDummySimplexId(trees[i]->getNumberOfNodes());
1240 std::vector<idNode> treeMatching(trees[i]->getNumberOfNodes(), -1);
1241 if(clusteringOutput and ShiftMode != 1)
1242 for(auto match : outputMatchingBarycenter[c][i])
1243 treeMatching[std::get<1>(match)] = std::get<0>(match);
1244 // _ m[i][j] contains the node in treesOri[j] matched to the node i in
1245 // the barycenter
1246 std::vector<std::vector<idNode>> baryMatching(
1247 trees[i]->getNumberOfNodes(),
1248 std::vector<idNode>(
1249 numInputsOri, std::numeric_limits<idNode>::max()));
1250 if(ShiftMode == 1) {
1251 for(size_t j = 0; j < outputMatchingBarycenter[c].size(); ++j)
1252 for(auto match : outputMatchingBarycenter[c][j])
1253 baryMatching[std::get<0>(match)][j] = std::get<1>(match);
1254 allBaryPercentMatch[c].resize(trees[i]->getNumberOfNodes(), 100.0);
1255 }
1256 double minBirth = std::numeric_limits<double>::max(),
1257 maxBirth = std::numeric_limits<double>::lowest();
1258 SimplexId minBirthNode = 0, maxBirthNode = 0;
1259
1260 // ----------------------------
1261 // Tree traversal
1262 // ----------------------------
1263 printMsg("// Tree traversal", ttk::debug::Priority::VERBOSE);
1264 std::queue<idNode> queue;
1265 queue.emplace(trees[i]->getRoot());
1266 while(!queue.empty()) {
1267 idNode const node = queue.front();
1268 queue.pop();
1269 idNode const nodeOrigin = trees[i]->getNode(node)->getOrigin();
1270 idNode const nodeParent = trees[i]->getParentSafe(node);
1271
1272 // Push children to the queue
1273 printMsg(
1274 "// Push children to the queue", ttk::debug::Priority::VERBOSE);
1275 std::vector<idNode> children;
1276 trees[i]->getChildren(node, children);
1277 for(auto child : children)
1278 queue.emplace(child);
1279
1280 // --------------
1281 // Insert point
1282 // --------------
1283 auto getPoint
1284 = [&](vtkUnstructuredGrid *vtu, int pointID, double(&point)[3]) {
1285 if(not vtu)
1286 return;
1287 if(not isPersistenceDiagram or convertedToDiagram) {
1288 double *pointTemp = vtu->GetPoints()->GetPoint(pointID);
1289 for(int k = 0; k < 3; ++k)
1290 point[k] += pointTemp[k];
1291 } else {
1292 for(int k = 0; k < 3; ++k) {
1293 auto array = vtu->GetPointData()->GetArray(
1295 if(array)
1296 point[k] += array->GetComponent(pointID, k);
1297 }
1298 }
1299 };
1300
1301 printMsg("// Get and insert point", ttk::debug::Priority::VERBOSE);
1302 int nodeMesh = -1;
1303 int nodeMeshTreeIndex = -1;
1304 double noMatched = 0.0;
1305 double point[3] = {0, 0, 0};
1306 if(ShiftMode == 1) { // Star barycenter
1307 for(int j = 0; j < numInputsOri; ++j) {
1308 if(baryMatching[node][j] != std::numeric_limits<idNode>::max()) {
1309 nodeMesh = treesNodeCorrMesh[j][baryMatching[node][j]];
1310 if(not PlanarLayout)
1311 getPoint(treesNodes[j], nodeMesh, point);
1312 noMatched += 1;
1313 nodeMeshTreeIndex = j;
1314 }
1315 }
1316 for(int k = 0; k < 3; ++k)
1317 point[k] /= noMatched;
1318 } else if(not isInterpolatedTree and treesNodes.size() != 0
1319 and treesNodes[i] != nullptr) {
1320 nodeMesh = treesNodeCorrMesh[i][node];
1321 if(not PlanarLayout)
1322 getPoint(treesNodes[i], nodeMesh, point);
1323 }
1324 if(PlanarLayout) {
1325 point[0] = layout[layoutCorr[node]];
1326 point[1] = layout[layoutCorr[node] + 1];
1327 point[2] = 0;
1328 }
1329 point[0] += diff_x;
1330 point[1] += diff_y;
1331 point[2] += diff_z;
1332
1333 // Bary percentage matching
1334 if(ShiftMode == 1) { // Star Barycenter
1335 float const percentMatchT = noMatched * 100 / numInputs;
1336 allBaryPercentMatch[c][node] = percentMatchT;
1337 }
1338
1339 // Get x Max and y Min for next iteration if needed (double line mode)
1340 prevXMax = std::max(prevXMax, point[0]);
1341 if(ShiftMode == 3) { // Double line
1342 if(i < numInputs / 2)
1343 prevYMax = std::max(prevYMax, point[1]);
1344 if(i == int(numInputs / 2) - 1)
1345 prevXMax = 0;
1346 }
1347
1348 bool dummyNode
1349 = PlanarLayout and not branchDecompositionPlanarLayout_
1350 and ((!trees[i]->isRoot(node) and !trees[i]->isLeaf(node))
1351 or isPersistenceDiagram);
1352 dummyNode = dummyNode or embeddedDiagram;
1353 if(dummyNode) {
1354 double pointToAdd[3] = {0, 0, 0};
1355 if(embeddedDiagram) {
1356 if(i < (int)treesNodes.size()
1357 and i < (int)treesNodeCorrMesh.size()
1358 and nodeOrigin < treesNodeCorrMesh[i].size())
1359 getPoint(
1360 treesNodes[i], treesNodeCorrMesh[i][nodeOrigin], pointToAdd);
1361 } else {
1362 if(not isPersistenceDiagram) {
1363 // will be modified when processing son
1364 std::copy(
1365 std::begin(point), std::end(point), std::begin(pointToAdd));
1366 } else {
1367 double pdPoint[3] = {
1368 point[0],
1369 point[1]
1370 - (layout[layoutCorr[node] + 1] - layout[layoutCorr[node]]),
1371 0};
1372 std::copy(std::begin(pdPoint), std::end(pdPoint),
1373 std::begin(pointToAdd));
1374 }
1375 }
1376 treeDummySimplexId[node] = points->InsertNextPoint(pointToAdd);
1377 if(not embeddedDiagram) {
1378 if(isPersistenceDiagram) {
1379 if(layout[layoutCorr[node]] < minBirth) {
1380 minBirth = layout[layoutCorr[node]];
1381 minBirthNode = treeDummySimplexId[node];
1382 }
1383 if(layout[layoutCorr[node]] > maxBirth) {
1384 maxBirth = layout[layoutCorr[node]];
1385 maxBirthNode = treeDummySimplexId[node];
1386 }
1387 }
1388 }
1389 }
1390 SimplexId const nextPointId = points->InsertNextPoint(point);
1391 treeSimplexId[node] = nextPointId;
1392 nodeCorr[i][node] = nextPointId;
1393 if(dummyNode and not pathPlanarLayout_)
1394 nodeCorr[i][node] = treeDummySimplexId[node];
1395 if(isPersistenceDiagram)
1396 nodeCorr[i][node] = nextPointId;
1397
1398 idNode const nodeBranching
1399 = ((PlanarLayout and branchDecompositionPlanarLayout_)
1400 or isPersistenceDiagram
1401 ? node
1402 : treeBranching[node]);
1403
1404 // Path Layout Dummy Node
1405 bool pathDummyNode = false;
1406
1407 // --------------
1408 // Insert cell connecting parent
1409 // --------------
1410 printMsg(
1411 "// Add cell connecting parent", ttk::debug::Priority::VERBOSE);
1412 if(!trees[i]->isRoot(node) or isPersistenceDiagram) {
1413 vtkIdType pointIds[2];
1414 pointIds[0] = treeSimplexId[node];
1415
1416 // TODO too many dummy cells are created
1417 bool const dummyCell
1418 = PlanarLayout and not branchDecompositionPlanarLayout_
1419 and (node < treeBranching.size()
1420 and treeBranching[node] == nodeParent)
1421 and !trees[i]->isRoot(nodeParent) and not isPersistenceDiagram;
1422 if(isPersistenceDiagram) {
1423 pointIds[1] = treeDummySimplexId[node];
1424 } else if(PlanarLayout and branchDecompositionPlanarLayout_) {
1425 pointIds[1] = treeSimplexId[treeBranching[node]];
1426 } else if(dummyCell) {
1427 double dummyPoint[3]
1428 = {point[0], layout[layoutCorr[nodeParent] + 1] + diff_y,
1429 0. + diff_z};
1430 SimplexId const dummyPointId = treeDummySimplexId[nodeParent];
1431 points->SetPoint(dummyPointId, dummyPoint);
1432 vtkIdType dummyPointIds[2];
1433 dummyPointIds[0] = dummyPointId;
1434 dummyPointIds[1] = treeSimplexId[nodeParent];
1435 vtkArcs->InsertNextCell(VTK_LINE, 2, dummyPointIds);
1436 pointIds[1] = dummyPointId;
1437 } else
1438 pointIds[1] = treeSimplexId[nodeParent];
1439
1440 // Path Layout Dummy Cell
1441 bool isNodeParentImportant = isImportantPairVector[nodeParent];
1442 bool pathDummyCell = not dummyCell and pathPlanarLayout_
1443 and isNodeParentImportant
1444 and !trees[i]->isRoot(nodeParent);
1445 if(not pathDummyCell and alignTrees and ShiftMode != 1) {
1446 pathDummyCell
1447 = not dummyCell and pathPlanarLayout_
1448 and layout[layoutCorr[node]] != layout[layoutCorr[nodeParent]]
1449 and !trees[i]->isRoot(nodeParent);
1450 }
1451 if(pathDummyCell) {
1452 pathDummyNode = true;
1453 double pathDummyPoint[3]
1454 = {layout[layoutCorr[node]] + diff_x,
1455 layout[layoutCorr[nodeParent] + 1] + diff_y, 0. + diff_z};
1456 SimplexId pathDummyPointId
1457 = points->InsertNextPoint(pathDummyPoint);
1458 vtkIdType pathDummyCellPointIds[2];
1459 pathDummyCellPointIds[0] = pathDummyPointId;
1460 pathDummyCellPointIds[1] = treeSimplexId[nodeParent];
1461 vtkArcs->InsertNextCell(VTK_LINE, 2, pathDummyCellPointIds);
1462 pointIds[1] = pathDummyPointId;
1463 }
1464 vtkArcs->InsertNextCell(VTK_LINE, 2, pointIds);
1465
1466 // --------------
1467 // Arc field
1468 // --------------
1469 int const toAdd = 1 + (dummyCell ? 1 : 0) + (pathDummyCell ? 1 : 0);
1470 for(int toAddT = 0; toAddT < toAdd; ++toAddT) {
1471 // Add arc matching percentage
1472 if(ShiftMode == 1) { // Star Barycenter
1473 auto nodeToGet
1474 = (!isPersistenceDiagram ? allBaryBranching[c][node] : node);
1475 percentMatchArc->InsertNextTuple1(
1476 allBaryPercentMatch[c][nodeToGet]);
1477 }
1478
1479 // Add branch/path bary ID
1480 printMsg(
1481 "// Push arc bary branch id", ttk::debug::Priority::VERBOSE);
1482 if(clusteringOutput and ShiftMode != 1) {
1483 // Branch
1484 int tBranchID = -1;
1485 auto nodeToGet = node;
1486 if(treeMatching[nodeToGet] < allBaryBranchingID[c].size())
1487 tBranchID = allBaryBranchingID[c][treeMatching[nodeToGet]];
1488 branchBaryID->InsertNextTuple1(tBranchID);
1489 // Path
1490 if(pathPlanarLayout_ and !pathMatchings.empty()
1491 and !pathMatchings[c].empty()) {
1492 int tPathID = -1;
1493 nodeToGet = node;
1494 if(treeMatching[nodeToGet] < allBaryPathingID[c].size())
1495 tPathID = allBaryPathingID[c][treeMatching[nodeToGet]];
1496 pathBaryID->InsertNextTuple1(tPathID);
1497 }
1498 }
1499
1500 // Add branch/path ID
1501 if(not isPersistenceDiagram) {
1502 // Branch
1503 int const tBranchID = treeBranchingID[node];
1504 branchID->InsertNextTuple1(tBranchID);
1505 // Path
1506 if(pathPlanarLayout_ and !pathMatchings.empty()
1507 and !pathMatchings[c].empty()) {
1508 int tPathID = treePathingID[node];
1509 pathID->InsertNextTuple1(tPathID);
1510 }
1511 }
1512
1513 // Add up and down nodeId
1514 if(not isPersistenceDiagram) {
1515 upNodeId->InsertNextTuple1(treeSimplexId[nodeParent]);
1516 downNodeId->InsertNextTuple1(treeSimplexId[node]);
1517 }
1518
1519 // Add arc persistence
1520 printMsg(
1521 "// Push arc persistence", ttk::debug::Priority::VERBOSE);
1522 idNode const nodeToGetPers
1523 = (isPersistenceDiagram ? node : nodeBranching);
1524 double const persToAdd
1525 = trees[i]->getNodePersistence<dataType>(nodeToGetPers);
1526 persistenceArc->InsertNextTuple1(persToAdd);
1527
1528 // Add birth
1529 auto birthDeath
1530 = trees[i]->getBirthDeath<dataType>(nodeToGetPers);
1531 pairBirth->InsertNextTuple1(std::get<0>(birthDeath));
1532
1533 // Add arc persistence barycenter and order
1534 if(clusteringOutput and ShiftMode != 1) {
1535 idNode const nodeToGet = nodeBranching;
1536 if(treeMatching[nodeToGet] < allBaryBranchingID[c].size()) {
1537 persistenceBaryArc->InsertTuple1(
1538 cellCount, barycenters[c]->getNodePersistence<dataType>(
1539 treeMatching[nodeToGet]));
1540 persistenceBaryOrderArc->InsertTuple1(
1541 cellCount, baryPersistenceOrder[treeMatching[nodeToGet]]);
1542 }
1543 }
1544
1545 // Add arc cluster ID
1546 clusterIDArc->InsertNextTuple1(clusteringAssignment[i]);
1547
1548 // Add arc tree ID
1549 treeIDArc->InsertNextTuple1(i + iSampleOffset);
1550
1551 // Add isImportantPair
1552 bool isImportant = false;
1553 idNode const nodeToGetImportance = nodeBranching;
1554 isImportant = trees[i]->isImportantPair<dataType>(
1555 nodeToGetImportance, importantPairs_,
1558 isImportantPairsArc->InsertNextTuple1(isImportant);
1559
1560 // Add isDummyArc
1561 bool const isDummy = toAdd >= 2 and toAddT == (toAdd - 2);
1562 isDummyArc->InsertNextTuple1(isDummy);
1563
1564 // Add isInterpolatedTree
1565 isInterpolatedTreeArc->InsertNextTuple1(isInterpolatedTree);
1566
1567 // Add pairIdentifier
1568 pairIdentifier->InsertNextTuple1(treeSimplexId[node]);
1569
1570 // Add isMinMaxPair
1571 bool const isMinMaxPair
1572 = (trees[i]->isRoot(node) and not trees[i]->isLeaf(node))
1573 or (trees[i]->isRoot(nodeOrigin)
1574 and not trees[i]->isLeaf(nodeOrigin));
1575 pairIsFinite->InsertNextTuple1(!isMinMaxPair);
1576
1577 // Add pairType TODO
1578 pairType->InsertNextTuple1(0);
1579
1580 // Add isMultiPersPairArc
1581 bool const isMultiPersPair
1582 = (trees[i]->isMultiPersPair(nodeBranching)
1583 or trees[i]->isMultiPersPair(
1584 trees[i]->getNode(nodeBranching)->getOrigin()));
1585 isMultiPersPairArc->InsertNextTuple1(isMultiPersPair);
1586
1587 // Add custom point arrays to cells
1588 for(unsigned int ca = 0; ca < customArrays.size(); ++ca)
1589 customCellArraysValues[ca].push_back(
1590 std::get<1>(customArrays[ca])[nodeBranching]);
1591 for(unsigned int ca = 0; ca < customIntArrays.size(); ++ca)
1592 customCellIntArraysValues[ca].push_back(
1593 std::get<1>(customIntArrays[ca])[nodeBranching]);
1594 for(unsigned int ca = 0; ca < customStringArrays.size(); ++ca)
1595 customCellStringArraysValues[ca].push_back(
1596 std::get<1>(customStringArrays[ca])[nodeBranching]);
1597
1598 cellCount++;
1599 }
1600 }
1601
1602 // --------------
1603 // Node field
1604 // --------------
1605 int const toAdd = 1 + (dummyNode ? 1 : 0) + (pathDummyNode ? 1 : 0);
1606 for(int toAddT = 0; toAddT < toAdd; ++toAddT) {
1607 bool isPathDummyNode = pathDummyNode and toAdd >= 2
1608 and toAddT == (toAdd - 1)
1609 and !trees[i]->isRoot(node);
1610 auto nodeToGet = (isPathDummyNode ? nodeParent : node);
1611 // Add node id
1612 nodeID->InsertNextTuple1(treeSimplexId[nodeToGet]);
1613
1614 // Add trueNodeId
1615 trueNodeID->InsertNextTuple1(nodeToGet);
1616
1617 // Add VertexId
1618 int nodeVertexId = -1;
1619 if(i < int(treesNodes.size()) and treesNodes[i]) {
1620 auto vertexIdArray = treesNodes[i]->GetPointData()->GetArray(
1621 (isPersistenceDiagram ? ttk::VertexScalarFieldName
1622 : "VertexId"));
1623 if(vertexIdArray and nodeMesh != -1)
1624 nodeVertexId = vertexIdArray->GetTuple1(nodeMesh);
1625 }
1626 vertexID->InsertNextTuple1(nodeVertexId);
1627
1628 // Add node scalar
1629 auto scalarValue = trees[i]->getValue<dataType>(nodeToGet);
1630 scalar->InsertNextTuple1(scalarValue);
1631
1632 // Add criticalType
1633 printMsg("// Add criticalType", ttk::debug::Priority::VERBOSE);
1634 int criticalTypeT = -1;
1635 if(not isPersistenceDiagram) {
1636 if(not isInterpolatedTree) {
1637 if(ShiftMode == 1) {
1638 if(nodeMeshTreeIndex != -1) {
1639 auto array
1640 = treesNodes[nodeMeshTreeIndex]->GetPointData()->GetArray(
1641 "CriticalType");
1642 if(array)
1643 criticalTypeT = array->GetTuple1(nodeMesh);
1644 }
1645 } else if(treesNodes.size() != 0 and treesNodes[i] != nullptr) {
1646 auto array
1647 = treesNodes[i]->GetPointData()->GetArray("CriticalType");
1648 if(array)
1649 criticalTypeT = array->GetTuple1(nodeMesh);
1650 }
1651 } else {
1652 // TODO critical type for interpolated trees
1653 }
1654 } else {
1655 auto locMin = static_cast<int>(ttk::CriticalType::Local_minimum);
1656 auto saddle1 = static_cast<int>(ttk::CriticalType::Saddle1);
1657 auto locMax = static_cast<int>(ttk::CriticalType::Local_maximum);
1658 auto saddle2 = static_cast<int>(ttk::CriticalType::Saddle2);
1659 auto nodeIsRoot = trees[i]->isRoot(node);
1660 criticalTypeT
1661 = (toAddT == 1
1662 ? (isPDSadMax or nodeIsRoot ? locMax : saddle1)
1663 : (not isPDSadMax or nodeIsRoot ? locMin : saddle2));
1664 if(embeddedDiagram) {
1665 bool const nodeSup = trees[i]->getValue<dataType>(node)
1666 > trees[i]->getValue<dataType>(nodeOrigin);
1667 criticalTypeT
1668 = ((nodeSup and toAddT == 1) or (not nodeSup and toAddT == 0)
1669 ? (isPDSadMax or nodeIsRoot ? locMax : saddle1)
1670 : (not isPDSadMax or nodeIsRoot ? locMin : saddle2));
1671 }
1672 }
1673 criticalType->InsertNextTuple1(criticalTypeT);
1674
1675 // Add node matching percentage
1676 if(ShiftMode == 1) // Star Barycenter
1677 percentMatch->InsertNextTuple1(allBaryPercentMatch[c][node]);
1678
1679 // Add node branch/path bary id
1680 printMsg(
1681 "// Add node bary branch id", ttk::debug::Priority::VERBOSE);
1682 if(clusteringOutput and ShiftMode != 1) {
1683 // Branch
1684 int tBranchID = -1;
1685 auto branchNode
1686 = (isPathDummyNode
1687 ? trees[i]->getNode(treeBranching[node])->getOrigin()
1688 : (trees[i]->isLeaf(node) ? node : nodeOrigin));
1689 if(treeMatching[branchNode] < allBaryBranchingID[c].size())
1690 tBranchID = allBaryBranchingID[c][treeMatching[branchNode]];
1691 branchBaryNodeID->InsertNextTuple1(tBranchID);
1692 // Path
1693 if(pathPlanarLayout_ and !pathMatchings.empty()
1694 and !pathMatchings[c].empty()) {
1695 int tPathID = -1;
1696 auto pathNode
1697 = (isPathDummyNode
1698 ? node
1699 : (not isRootPath[node] ? node : pathOrigin[node]));
1700 if(treeMatching[pathNode] < allBaryPathingID[c].size())
1701 tPathID = allBaryPathingID[c][treeMatching[pathNode]];
1702 pathBaryNodeID->InsertNextTuple1(tPathID);
1703 }
1704 }
1705
1706 // Add node branch/path id
1707 if(not isPersistenceDiagram) {
1708 // Branch
1709 auto branchNode
1710 = (isPathDummyNode
1711 ? trees[i]->getNode(treeBranching[node])->getOrigin()
1712 : (trees[i]->isLeaf(node) ? node : nodeOrigin));
1713 int tBranchID = treeBranchingID[branchNode];
1714 branchNodeID->InsertNextTuple1(tBranchID);
1715 // Path
1716 if(pathPlanarLayout_ and !pathMatchings.empty()
1717 and !pathMatchings[c].empty()) {
1718 auto pathNode
1719 = (isPathDummyNode
1720 ? node
1721 : (not isRootPath[node] ? node : pathOrigin[node]));
1722 // auto pathNode = node;
1723 int tPathID = treePathingID[pathNode];
1724 pathNodeID->InsertNextTuple1(tPathID);
1725 }
1726 }
1727
1728 // Add node persistence
1729 printMsg("// Push node persistence", ttk::debug::Priority::VERBOSE);
1730 persistenceNode->InsertNextTuple1(
1731 trees[i]->getNodePersistence<dataType>(node));
1732
1733 // Add birth
1734 auto birthDeath = trees[i]->getBirthDeath<dataType>(node);
1735 pairBirthNode->InsertNextTuple1(std::get<0>(birthDeath));
1736
1737 // Add node persistence barycenter
1738 if(clusteringOutput and ShiftMode != 1) {
1739 if(treeMatching[node] < allBaryBranchingID[c].size()) {
1740 persistenceBaryNode->InsertTuple1(
1741 pointCount, barycenters[c]->getNodePersistence<dataType>(
1742 treeMatching[node]));
1743 persistenceBaryOrderNode->InsertTuple1(
1744 pointCount, baryPersistenceOrder[treeMatching[node]]);
1745 }
1746 }
1747
1748 // Add node clusterID
1749 clusterIDNode->InsertNextTuple1(clusteringAssignment[i]);
1750
1751 // Add node tree ID
1752 treeIDNode->InsertNextTuple1(i + iSampleOffset);
1753
1754 // Add isDummyNode
1755 bool isDummy
1756 = toAdd == 2 and toAddT == 1 and !trees[i]->isRoot(node);
1757 if(pathPlanarLayout_) {
1758 isDummy = (toAdd >= 2 and dummyNode and toAddT == 0
1759 and !trees[i]->isRoot(node));
1760 isDummy = isDummy or isPathDummyNode;
1761 }
1762 isDummyNode->InsertNextTuple1(isDummy);
1763
1764 // Add isInterpolatedTree
1765 isInterpolatedTreeNode->InsertNextTuple1(isInterpolatedTree);
1766
1767 // Add isImportantPair
1768 bool isImportant = isImportantPairVector[nodeToGet];
1769 isImportantPairsNode->InsertNextTuple1(isImportant);
1770
1771 // Add treeNodeId
1772 treeNodeId->InsertNextTuple1(nodeToGet);
1773
1774 // Add treeNodeIdOrigin
1775 treeNodeIdOrigin->InsertNextTuple1(nodeOrigin);
1776
1777 // Add coordinates
1778 printMsg("// Add coordinates", ttk::debug::Priority::VERBOSE);
1779 if(isPersistenceDiagram and !treesNodes.empty()
1780 and ShiftMode != 1) {
1781 double coord[3] = {0.0, 0.0, 0.0};
1782 getPoint(treesNodes[i], treesNodeCorrMesh[i][node], coord);
1783 coordinates->InsertNextTuple3(coord[0], coord[1], coord[2]);
1784 }
1785
1786 // Add isMultiPersPairArc
1787 printMsg("// isMultiPersPairArc", ttk::debug::Priority::VERBOSE);
1788 bool const isMultiPersPair
1789 = (trees[i]->isMultiPersPair(node)
1790 or trees[i]->isMultiPersPair(
1791 trees[i]->getNode(node)->getOrigin()));
1792 isMultiPersPairNode->InsertNextTuple1(isMultiPersPair);
1793
1794 // Add custom arrays
1795 for(unsigned int ca = 0; ca < customArrays.size(); ++ca)
1796 customArraysValues[ca].emplace_back(
1797 std::get<1>(customArrays[ca])[nodeToGet]);
1798 for(unsigned int ca = 0; ca < customIntArrays.size(); ++ca)
1799 customIntArraysValues[ca].emplace_back(
1800 std::get<1>(customIntArrays[ca])[nodeToGet]);
1801 for(unsigned int ca = 0; ca < customStringArrays.size(); ++ca)
1802 customStringArraysValues[ca].emplace_back(
1803 std::get<1>(customStringArrays[ca])[nodeToGet]);
1804
1805 pointCount++;
1806 }
1807
1809 } // end tree traversal
1810
1811 // Add diagonal if isPersistenceDiagram
1812 if(isPersistenceDiagram and not embeddedDiagram) {
1813 vtkIdType pointIds[2];
1814 pointIds[0] = minBirthNode;
1815 pointIds[1] = maxBirthNode;
1816 vtkArcs->InsertNextCell(VTK_LINE, 2, pointIds);
1817 cellCount++;
1818
1819 pairIdentifier->InsertNextTuple1(-1);
1820 pairType->InsertNextTuple1(-1);
1821 persistenceArc->InsertNextTuple1(-1);
1822 pairIsFinite->InsertNextTuple1(0);
1823 pairBirth->InsertNextTuple1(0);
1824
1825 for(unsigned int ca = 0; ca < customArrays.size(); ++ca)
1826 customCellArraysValues[ca].push_back(-1);
1827 for(unsigned int ca = 0; ca < customIntArrays.size(); ++ca)
1828 customCellIntArraysValues[ca].push_back(-1);
1829 for(unsigned int ca = 0; ca < customStringArrays.size(); ++ca)
1830 customCellStringArraysValues[ca].emplace_back("");
1831
1832 isMultiPersPairArc->InsertNextTuple1(0);
1833 clusterIDArc->InsertNextTuple1(clusteringAssignment[i]);
1834 treeIDArc->InsertNextTuple1(i + iSampleOffset);
1835 isImportantPairsArc->InsertNextTuple1(0);
1836 branchBaryID->InsertNextTuple1(-1);
1837 percentMatchArc->InsertNextTuple1(100);
1838 }
1839
1840 // --------------
1841 // Manage segmentation
1842 // --------------
1843 // Use TransformFilter (see commit
1844 // 85600763a8907674b8e57d6ad77ca97640725b30) when issue #513 is
1845 // solved.
1846 printMsg("// Shift segmentation", ttk::debug::Priority::VERBOSE);
1847 if(OutputSegmentation and not PlanarLayout and treesSegmentation[i]) {
1848 vtkNew<vtkUnstructuredGrid> iTreesSegmentationCopy{};
1849 if(ShiftMode != -1)
1850 iTreesSegmentationCopy->DeepCopy(treesSegmentation[i]);
1851 else
1852 iTreesSegmentationCopy->ShallowCopy(treesSegmentation[i]);
1853 auto iVkOutputSegmentationTemp
1854 = vtkUnstructuredGrid::SafeDownCast(iTreesSegmentationCopy);
1855 if(!iVkOutputSegmentationTemp
1856 or !iVkOutputSegmentationTemp->GetPoints()) {
1857 printWrn("Convert segmentation to vtkUnstructuredGrid.");
1858 vtkNew<vtkAppendFilter> appendFilter2{};
1859 appendFilter2->AddInputData(treesSegmentation[i]);
1860 appendFilter2->Update();
1861 iVkOutputSegmentationTemp->ShallowCopy(appendFilter2->GetOutput());
1862 }
1863 if(ShiftMode != -1) {
1864 for(int p = 0;
1865 p < iVkOutputSegmentationTemp->GetPoints()->GetNumberOfPoints();
1866 ++p) {
1867 double *point
1868 = iVkOutputSegmentationTemp->GetPoints()->GetPoint(p);
1869 point[0] += diff_x;
1870 point[1] += diff_y;
1871 point[2] += diff_z;
1872 iVkOutputSegmentationTemp->GetPoints()->SetPoint(p, point);
1873 }
1874 }
1875 appendFilter->AddInputData(iVkOutputSegmentationTemp);
1876 }
1877 printMsg("// Shift segmentation DONE", ttk::debug::Priority::VERBOSE);
1878 }
1879 }
1880 for(int i = persistenceBaryNode->GetNumberOfTuples(); i < pointCount; ++i)
1881 persistenceBaryNode->InsertNextTuple1(0);
1882 for(int i = persistenceBaryArc->GetNumberOfTuples(); i < cellCount; ++i)
1883 persistenceBaryArc->InsertNextTuple1(0);
1884 for(int i = persistenceBaryOrderNode->GetNumberOfTuples(); i < pointCount;
1885 ++i)
1886 persistenceBaryOrderNode->InsertNextTuple1(0);
1887 for(int i = persistenceBaryOrderArc->GetNumberOfTuples(); i < cellCount;
1888 ++i)
1889 persistenceBaryOrderArc->InsertNextTuple1(0);
1890
1891 // --- Add VTK arrays to output
1892 printMsg("// Add VTK arrays to output", ttk::debug::Priority::VERBOSE);
1893 // - Manage node output
1894 // Custom arrays
1895 addVtkCustomArrays(customArrays, customArraysValues, vtkOutputNode, 0, 0);
1897 customIntArrays, customIntArraysValues, vtkOutputNode, 1, 0);
1899 customStringArrays, customStringArraysValues, vtkOutputNode, 2, 0);
1900
1901 // Classical arrays
1902 vtkOutputNode->SetPoints(points);
1903 vtkOutputNode->GetPointData()->AddArray(criticalType);
1904 vtkOutputNode->GetPointData()->AddArray(persistenceNode);
1905 vtkOutputNode->GetPointData()->AddArray(clusterIDNode);
1906 vtkOutputNode->GetPointData()->AddArray(treeIDNode);
1907 vtkOutputNode->GetPointData()->AddArray(trueNodeID);
1908 vtkOutputNode->GetPointData()->AddArray(vertexID);
1909 vtkOutputNode->GetPointData()->AddArray(isImportantPairsNode);
1910 vtkOutputNode->GetPointData()->AddArray(isMultiPersPairNode);
1911 if(not isPersistenceDiagram) {
1912 vtkOutputNode->GetPointData()->AddArray(nodeID);
1913 vtkOutputNode->GetPointData()->AddArray(branchNodeID);
1914 vtkOutputNode->GetPointData()->AddArray(isDummyNode);
1915 if(pathPlanarLayout_ and !pathMatchings.empty()
1916 and !pathMatchings[0].empty())
1917 vtkOutputNode->GetPointData()->AddArray(pathNodeID);
1918 }
1919 if(not branchDecompositionPlanarLayout_ and not isPersistenceDiagram)
1920 vtkOutputNode->GetPointData()->AddArray(scalar);
1921 if(clusteringOutput and ShiftMode != 1) {
1922 vtkOutputNode->GetPointData()->AddArray(branchBaryNodeID);
1923 if(pathPlanarLayout_ and !pathMatchings.empty()
1924 and !pathMatchings[0].empty())
1925 vtkOutputNode->GetPointData()->AddArray(pathBaryNodeID);
1926 vtkOutputNode->GetPointData()->AddArray(persistenceBaryNode);
1927 vtkOutputNode->GetPointData()->AddArray(persistenceBaryOrderNode);
1928 }
1929 if(foundOneInterpolatedTree)
1930 vtkOutputNode->GetPointData()->AddArray(isInterpolatedTreeNode);
1931 if(ShiftMode == 1) // Star Barycenter
1932 vtkOutputNode->GetPointData()->AddArray(percentMatch);
1933 if(outputTreeNodeIndex)
1934 vtkOutputNode->GetPointData()->AddArray(treeNodeId);
1935 if(isPersistenceDiagram) {
1936 vtkOutputNode->GetPointData()->AddArray(treeNodeIdOrigin);
1937 if(!treesNodes.empty() and ShiftMode != 1)
1938 vtkOutputNode->GetPointData()->AddArray(coordinates);
1939 }
1940 vtkOutputNode->GetPointData()->AddArray(pairBirthNode);
1941
1942 // - Manage arc output
1943 // Custom arrays
1944 addVtkCustomArrays(customArrays, customCellArraysValues, vtkArcs, 0, 1);
1946 customIntArrays, customCellIntArraysValues, vtkArcs, 1, 1);
1948 customStringArrays, customCellStringArraysValues, vtkArcs, 2, 1);
1949
1950 // Classical arrays
1951 vtkArcs->SetPoints(points);
1952 vtkArcs->GetCellData()->AddArray(persistenceArc);
1953 vtkArcs->GetCellData()->AddArray(clusterIDArc);
1954 vtkArcs->GetCellData()->AddArray(treeIDArc);
1955 vtkArcs->GetCellData()->AddArray(isImportantPairsArc);
1956 vtkArcs->GetCellData()->AddArray(isMultiPersPairArc);
1957 if(not isPersistenceDiagram) {
1958 vtkArcs->GetCellData()->AddArray(isDummyArc);
1959 vtkArcs->GetCellData()->AddArray(branchID);
1960 if(pathPlanarLayout_ and !pathMatchings.empty()
1961 and !pathMatchings[0].empty())
1962 vtkArcs->GetCellData()->AddArray(pathID);
1963 vtkArcs->GetCellData()->AddArray(upNodeId);
1964 vtkArcs->GetCellData()->AddArray(downNodeId);
1965 }
1966 if(clusteringOutput and ShiftMode != 1) {
1967 vtkArcs->GetCellData()->AddArray(branchBaryID);
1968 if(pathPlanarLayout_ and !pathMatchings.empty()
1969 and !pathMatchings[0].empty())
1970 vtkArcs->GetCellData()->AddArray(pathBaryID);
1971 vtkArcs->GetCellData()->AddArray(persistenceBaryArc);
1972 vtkArcs->GetCellData()->AddArray(persistenceBaryOrderArc);
1973 }
1974 if(foundOneInterpolatedTree)
1975 vtkArcs->GetCellData()->AddArray(isInterpolatedTreeArc);
1976 if(ShiftMode == 1) // Star Barycenter
1977 vtkArcs->GetCellData()->AddArray(percentMatchArc);
1978 if(isPersistenceDiagram) {
1979 vtkArcs->GetCellData()->AddArray(pairIdentifier);
1980 vtkArcs->GetCellData()->AddArray(pairType);
1981 vtkArcs->GetCellData()->AddArray(pairIsFinite);
1982 }
1983 vtkArcs->GetCellData()->AddArray(pairBirth);
1984 if(vtkOutputArc == vtkOutputNode)
1985 vtkArcs->GetPointData()->ShallowCopy(vtkOutputNode->GetPointData());
1986 if(not branchDecompositionPlanarLayout_ and not isPersistenceDiagram)
1987 vtkArcs->GetPointData()->AddArray(scalar);
1988 vtkOutputArc->ShallowCopy(vtkArcs);
1989
1990 // - Manage segmentation output
1991 if(OutputSegmentation and not PlanarLayout
1992 and appendFilter->GetNumberOfInputConnections(0) != 0) {
1993 appendFilter->SetMergePoints(false);
1994 appendFilter->Update();
1995 vtkOutputSegmentation->ShallowCopy(appendFilter->GetOutput());
1996 }
1997
1998 //
1999 if(ShiftMode == 1) // Star Barycenter
2000 trees = treesOri;
2001 }
2002
2003 // ==========================================================================
2004 // Bounds Utils
2005 // ==========================================================================
2006 std::tuple<double, double, double, double, double, double>
2007 getRealBounds(vtkUnstructuredGrid *treeNodes,
2008 FTMTree_MT *tree,
2009 std::vector<int> &nodeCorrT) {
2010 double x_min = std::numeric_limits<double>::max();
2011 double y_min = std::numeric_limits<double>::max();
2012 double z_min = std::numeric_limits<double>::max();
2013 double x_max = std::numeric_limits<double>::lowest();
2014 double y_max = std::numeric_limits<double>::lowest();
2015 double z_max = std::numeric_limits<double>::lowest();
2016 std::queue<idNode> queue;
2017 queue.emplace(tree->getRoot());
2018 while(!queue.empty()) {
2019 idNode const node = queue.front();
2020 queue.pop();
2021 double *point = treeNodes->GetPoints()->GetPoint(nodeCorrT[node]);
2022 x_min = std::min(x_min, point[0]);
2023 x_max = std::max(x_max, point[0]);
2024 y_min = std::min(y_min, point[1]);
2025 y_max = std::max(y_max, point[1]);
2026 z_min = std::min(z_min, point[2]);
2027 z_max = std::max(z_max, point[2]);
2028 std::vector<idNode> children;
2029 tree->getChildren(node, children);
2030 for(auto child : children)
2031 queue.emplace(child);
2032 }
2033 return std::make_tuple(x_min, x_max, y_min, y_max, z_min, z_max);
2034 }
2035
2036 std::tuple<double, double, double, double, double, double>
2037 getRealBounds(vtkUnstructuredGrid *treeNodes, FTMTree_MT *tree) {
2038 std::vector<int> nodeCorrT(tree->getNumberOfNodes());
2039 for(size_t i = 0; i < nodeCorrT.size(); ++i)
2040 nodeCorrT[i] = i;
2041
2042 return getRealBounds(treeNodes, tree, nodeCorrT);
2043 }
2044};
#define M_PI
Definition Os.h:50
void makeTreesOutput(FTMTree_MT *tree1, FTMTree_MT *tree2)
void setTreesSegmentation(std::vector< vtkDataSet * > &segmentation)
void setInterpolatedTrees(std::vector< bool > &isInterpolatedTrees)
std::vector< double > getClusterShift()
void copyPointData(vtkUnstructuredGrid *treeNodes, std::vector< int > &nodeCorrT)
void setDimensionsShift(double xShift, double yShift, double zShift)
void setVtkOutputNode1(vtkUnstructuredGrid *vtkNode1)
void setNodeCorr1(std::vector< std::vector< SimplexId > > &nodeCorrT)
void setOutputMatchingBarycenter(std::vector< std::vector< std::vector< std::tuple< idNode, idNode, double > > > > &matching)
void setVtkOutputSegmentation(vtkDataSet *vtkSegmentation)
void setTreesNodeCorrMesh(std::vector< std::vector< int > > &nodeCorrMesh)
ttkMergeTreeVisualization()=default
void addCustomIntArray(std::string &name, std::vector< int > &vec)
void setVtkOutputMatching(vtkUnstructuredGrid *vtkMatching)
void getTreePathing(FTMTree_MT *tree, std::vector< std::pair< std::pair< ttk::ftm::idNode, ttk::ftm::idNode >, std::pair< ttk::ftm::idNode, ttk::ftm::idNode > > > &matching, bool isFirstTree, std::vector< ttk::ftm::idNode > &pathing, std::vector< int > &pathingID)
void setClusteringAssignment(std::vector< int > &asgn)
void addCustomStringArray(std::string &name, std::vector< std::string > &vec)
void makeTreesOutput(std::vector< FTMTree_MT * > &trees, std::vector< FTMTree_MT * > &barycenters)
std::vector< std::vector< float > > getAllBaryPercentMatch()
std::vector< std::vector< SimplexId > > getNodeCorr()
std::tuple< double, double, double, double, double, double > getRealBounds(vtkUnstructuredGrid *treeNodes, FTMTree_MT *tree)
std::tuple< double, double, double, double, double, double > getRealBounds(vtkUnstructuredGrid *treeNodes, FTMTree_MT *tree, std::vector< int > &nodeCorrT)
void setTreesNodes(vtkUnstructuredGrid *nodes)
void copyPointData(vtkUnstructuredGrid *treeNodes)
void setTreesSegmentation(vtkDataSet *segmentation)
void makeTreesOutput(FTMTree_MT *tree1)
~ttkMergeTreeVisualization() override=default
void setConvertedToDiagram(bool converted)
void makeMatchingOutput(std::vector< FTMTree_MT * > &trees, std::vector< FTMTree_MT * > &barycenters)
void addVtkCustomArrays(std::vector< std::tuple< std::string, std::vector< dataType > > > &cArrays, std::vector< std::vector< dataType > > &cArraysValues, vtkUnstructuredGrid *vtkOutput, int type, int output)
void getTreeNodeIdRev(vtkDataArray *treeNodeIdArray, std::vector< int > &treeNodeIdRev)
void setPathMatchings(std::vector< std::vector< std::vector< std::pair< std::pair< ttk::ftm::idNode, ttk::ftm::idNode >, std::pair< ttk::ftm::idNode, ttk::ftm::idNode > > > > > &matchings)
void setVtkOutputNode2(vtkUnstructuredGrid *vtkNode2)
void setTreesNodeCorrMesh(std::vector< int > &nodeCorrMesh)
void makeTreesOutput(std::vector< FTMTree_MT * > &trees)
void makeMatchingOutput(FTMTree_MT *tree1, FTMTree_MT *tree2)
void setVtkOutputArc(vtkUnstructuredGrid *vtkArc)
void setNodeCorr2(std::vector< std::vector< SimplexId > > &nodeCorrT)
void setVtkOutputNode(vtkUnstructuredGrid *vtkNode)
void setOutputMatching(std::vector< std::tuple< idNode, idNode, double > > &matching)
void addCustomArray(std::string &name, std::vector< double > &vec)
void getTreePathing(FTMTree_MT *tree, std::vector< std::vector< std::pair< std::pair< ttk::ftm::idNode, ttk::ftm::idNode >, std::pair< ttk::ftm::idNode, ttk::ftm::idNode > > > > &matchings, bool isFirstTree, std::vector< ttk::ftm::idNode > &pathing, std::vector< int > &pathingID)
void setTreesNodes(std::vector< vtkUnstructuredGrid * > &nodes)
void setAllBaryPercentMatch(std::vector< std::vector< float > > &baryPercentMatch)
int printWrn(const std::string &msg, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cerr) const
Definition Debug.h:159
std::vector< double > excludeImportantPairsLowerValues_
void persistenceDiagramPlanarLayout(ftm::FTMTree_MT *tree, std::vector< float > &res)
std::vector< double > excludeImportantPairsHigherValues_
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)
void treePlanarLayout(ftm::FTMTree_MT *tree, std::tuple< double, double, double, double, double, double > oldBounds, double refPersistence, std::vector< float > &res)
Node * getNode(idNode nodeId) const
Definition FTMTree_MT.h:393
void getChildren(idNode nodeId, std::vector< idNode > &res) const
idNode getNumberOfNodes() const
Definition FTMTree_MT.h:389
idNode getRoot() const
idNode getParentSafe(idNode nodeId) const
void getAllNodeLevel(std::vector< int > &res) const
dataType getNodePersistence(idNode nodeId) const
bool isRoot(idNode nodeId) const
bool isImportantPair(idNode nodeId, double threshold, std::vector< double > &excludeLower, std::vector< double > &excludeHigher) const
idSuperArc getNumberOfDownSuperArcs() const
Definition FTMNode.h:82
idSuperArc getNumberOfUpSuperArcs() const
Definition FTMNode.h:86
unsigned int idNode
Node index in vect_nodes_.
int SimplexId
Identifier type for simplices of any dimension.
Definition DataTypes.h:22
const char PersistenceName[]
Definition DataTypes.h:80
const char PersistenceCoordinatesName[]
Definition DataTypes.h:78
const char PersistencePairTypeName[]
Definition DataTypes.h:81
const char PersistenceCriticalTypeName[]
Definition DataTypes.h:75
const char PersistenceIsFinite[]
Definition DataTypes.h:82
const char VertexScalarFieldName[]
default name for vertex scalar field
Definition DataTypes.h:35
const char PersistencePairIdentifierName[]
Definition DataTypes.h:79
const char PersistenceBirthName[]
Definition DataTypes.h:76
printMsg(debug::output::BOLD+" | | | | | . \\ | | (__| | / __/| |_| / __/| (_) |"+debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, stream)