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);
691 = std::max(NumberOfBarycenters, 1);
692 bool alignTrees = trees.size() == 2 and barycenters.size() == 1
693 and enableBarycenterAlignment;
694 bool const embeddedDiagram = not PlanarLayout and isPersistenceDiagram;
697 for(
int i = 0; i < numInputs; ++i) {
698 if(i < (
int)treesNodes.size() and treesNodes[i]) {
700 = treesNodes[i]->GetPointData()->GetArray(
"TreeNodeId");
701 if(treeNodeIdArray) {
702 std::vector<int> treeNodeIdRev;
704 for(
unsigned int j = 0; j < treesNodeCorrMesh[i].size(); ++j)
705 treesNodeCorrMesh[i][j] = treeNodeIdRev[treesNodeCorrMesh[i][j]];
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)
722 =
getRealBounds(treesNodes[i], trees[i], treesNodeCorrMesh[i]);
725 treesNodes[i]->GetBounds(bounds);
726 allBounds[i] = std::make_tuple(
727 bounds[0], bounds[1], bounds[2], bounds[3], bounds[4], bounds[5]);
730 allBounds[i] = allBounds[0];
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) {
742 if(not isPersistenceDiagram)
743 barycenters[c]->getTreeBranching(
744 allBaryBranching[c], allBaryBranchingID[c]);
746 and !pathMatchings[c].empty())
748 allBaryPathing[c], allBaryPathingID[c]);
750 if(not clusteringOutput)
751 allBaryBounds.emplace_back(
758 std::vector<FTMTree_MT *>
const treesOri(trees);
761 clusteringAssignment.clear();
762 for(
unsigned int j = 0; j < barycenters.size(); ++j) {
763 trees.emplace_back(barycenters[j]);
764 clusteringAssignment.emplace_back(j);
766 numInputs = trees.size();
769 vtkNew<vtkUnstructuredGrid> vtkArcs{};
770 vtkNew<vtkPoints> points{};
773 vtkNew<vtkIntArray> criticalType{};
775 vtkNew<vtkDoubleArray> persistenceNode{};
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");
791 vtkNew<vtkIntArray> trueNodeID{};
792 trueNodeID->SetName(
"TrueNodeId");
793 vtkNew<vtkIntArray> vertexID{};
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");
806 vtkNew<vtkFloatArray> percentMatch{};
807 percentMatch->SetName(
"PercentMatchNode");
808 vtkNew<vtkFloatArray> persistenceBaryNode{};
809 persistenceBaryNode->SetName(
"PersistenceBarycenter");
810 vtkNew<vtkIntArray> persistenceBaryOrderNode{};
811 persistenceBaryOrderNode->SetName(
"PersistenceBarycenterOrder");
813 vtkNew<vtkDoubleArray> pairBirthNode{};
816 vtkNew<vtkFloatArray> treeNodeId{};
817 treeNodeId->SetName(
"TreeNodeId");
819 vtkNew<vtkFloatArray> treeNodeIdOrigin{};
820 treeNodeIdOrigin->SetName(
"TreeNodeIdOrigin");
821 vtkNew<vtkDoubleArray> coordinates{};
823 coordinates->SetNumberOfComponents(3);
825 vtkNew<vtkIntArray> isMultiPersPairNode{};
826 isMultiPersPairNode->SetName(
"isMultiPersPairNode");
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());
834 vtkNew<vtkDoubleArray> persistenceArc{};
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");
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");
860 vtkNew<vtkFloatArray> percentMatchArc{};
861 percentMatchArc->SetName(
"PercentMatchArc");
862 vtkNew<vtkFloatArray> persistenceBaryArc{};
863 persistenceBaryArc->SetName(
"PersistenceBarycenter");
864 vtkNew<vtkIntArray> persistenceBaryOrderArc{};
865 persistenceBaryOrderArc->SetName(
"PersistenceBarycenterOrder");
867 vtkNew<vtkIntArray> pairIdentifier{};
869 vtkNew<vtkIntArray> pairType{};
871 vtkNew<vtkIntArray> pairIsFinite{};
873 vtkNew<vtkDoubleArray> pairBirth{};
876 vtkNew<vtkIntArray> isMultiPersPairArc{};
877 isMultiPersPairArc->SetName(
"isMultiPersPairArc");
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());
887 vtkNew<vtkAppendFilter> appendFilter{};
892 bool foundOneInterpolatedTree =
false;
894 nodeCorr.resize(numInputs);
895 clusterShift.clear();
896 clusterShift.resize(NumberOfBarycenters, 0);
897 allBaryPercentMatch.clear();
898 allBaryPercentMatch.resize(NumberOfBarycenters);
905 for(
int c = 0; c < NumberOfBarycenters; ++c) {
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>>
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;
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)
934 double const radius = delta_max * 2 * DimensionSpacing;
935 int iSample = 0 + iSampleOffset - 1;
937 if(c < NumberOfBarycenters - 1)
938 clusterShift[c + 1] = radius * 4 + clusterShift[c];
941 prevXMax = 0 + prevXMaxOffset;
942 std::vector<double> allPrevXMax;
943 double prevYMax = std::numeric_limits<double>::lowest();
948 printMsg(
"Iterate through all trees of this cluster",
950 for(
int i = 0; i < numInputs; ++i) {
951 if(clusteringAssignment[i] != c)
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)))
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;
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);
978 if(MinimumImportantPairs > 0) {
979 int firstIndex = pairs.size() - MinimumImportantPairs;
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);
988 return importantPairs;
993 bool isInterpolatedTree =
false;
994 if(interpolatedTrees.size() != 0)
995 isInterpolatedTree = interpolatedTrees[i];
996 foundOneInterpolatedTree |= isInterpolatedTree;
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);
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());
1013 trees[i], pathMatchings[c],
true, treePathing, treePathingID);
1015 getTreePathing(trees[i], pathMatchings[c][i],
false, treePathing,
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)
1023 for(
auto &match : pathMatchings[c][j]) {
1025 = (isFirstTree ? match.first.first : match.second.first);
1027 = (isFirstTree ? match.first.second : match.second.second);
1029 = (nodeLevel[first] < nodeLevel[second] ? second : first);
1031 = (nodeLevel[first] < nodeLevel[second] ? first : second);
1032 isRootPath[highest] =
true;
1033 pathOrigin[lowest] = highest;
1034 pathOrigin[highest] = lowest;
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;
1054 = -1 * radius * std::cos(-1 * angle * pi / 180) + clusterShift[c];
1055 diff_y = -1 * radius * std::sin(-1 * angle * pi / 180);
1058 diff_x = clusterShift[c] + alphaShift;
1062 diff_x = prevXMax + radius;
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;
1070 allPrevXMax.emplace_back(prevXMax);
1077 auto getIsImportantPairVector
1078 = [
this](FTMTree_MT *tree, std::vector<bool> &isImportantPairVector,
1079 double importantPairs) {
1081 for(
unsigned int n = 0; n < isImportantPairVector.size(); ++n)
1086 std::vector<bool> isImportantPairVector;
1087 getIsImportantPairVector(
1092 = [](FTMTree_MT *tree, std::vector<SimplexId> &layoutCorr) {
1095 std::queue<idNode> queueLayoutCorr;
1096 queueLayoutCorr.emplace(tree->
getRoot());
1097 while(!queueLayoutCorr.empty()) {
1098 idNode node = queueLayoutCorr.front();
1099 queueLayoutCorr.pop();
1102 std::vector<idNode> children;
1104 for(
auto child : children)
1105 queueLayoutCorr.emplace(child);
1107 layoutCorr[node] = cptNode;
1114 std::vector<SimplexId> layoutCorr;
1115 getLayoutCorr(trees[i], layoutCorr);
1116 std::vector<float> layout;
1118 std::vector<ttk::ftm::idNode> baryMatchingVector;
1121 std::vector<bool> isImportantPairBaryVector;
1123 double refPersistence;
1124 if(clusteringOutput)
1125 refPersistence = barycenters[0]->getNodePersistence<dataType>(
1126 barycenters[0]->getRoot());
1129 = trees[0]->getNodePersistence<dataType>(trees[0]->getRoot());
1130 if(not isPersistenceDiagram) {
1132 trees[i], allBaryBounds[c], refPersistence, layout);
1134 if(alignTrees and ShiftMode != 1) {
1136 std::vector<float> layoutBary;
1138 barycenters[0], allBaryBounds[c], refPersistence, layoutBary);
1139 std::vector<SimplexId> layoutBaryCorr;
1140 getLayoutCorr(barycenters[0], layoutBaryCorr);
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]) {
1152 isImportantPairVector[std::get<1>(match)]
1153 = isImportantPairBaryVector[std::get<0>(match)];
1155 layout[layoutCorr[std::get<1>(match)]]
1156 = layoutBary[layoutBaryCorr[std::get<0>(match)]];
1157 if(not isImportantPairVector[std::get<1>(match)]) {
1160 while(not isImportantPairBaryVector[node])
1161 node = barycenters[0]->getParentSafe(node);
1163 = barycenters[0]->getValue<dataType>(node)
1164 > barycenters[0]->getValue<dataType>(std::get<0>(match));
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)) {
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;
1177 trees[i]->getNode(std::get<1>(match))->getOrigin());
1178 while(!queueShift.empty()) {
1181 shifts[nodeToShift] += shift;
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);
1194 for(
unsigned int s = 0; s < shifts.size(); ++s)
1195 layout[layoutCorr[s]] += shifts[s];
1204 double diff_z = PlanarLayout ? 0 : -std::get<4>(allBounds[i]);
1205 if(DimensionToShift != 0) {
1209 for(
unsigned int l = 0; l < layout.size(); ++l) {
1211 minX = std::min(minX, layout[l]);
1214 double new_diff_x = PlanarLayout ? -minX : -std::get<0>(allBounds[i]);
1216 = (not clusteringOutput
1217 or (trees.size() == 2 and barycenters.size() == 1));
1218 if(DimensionToShift == 2) {
1221 diff_x = new_diff_x;
1222 }
else if(diffYAllowed and DimensionToShift == 1) {
1225 diff_x = new_diff_x;
1226 }
else if(DimensionToShift == 3) {
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;
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);
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);
1256 double minBirth = std::numeric_limits<double>::max(),
1257 maxBirth = std::numeric_limits<double>::lowest();
1258 SimplexId minBirthNode = 0, maxBirthNode = 0;
1264 std::queue<idNode> queue;
1265 queue.emplace(trees[i]->getRoot());
1266 while(!queue.empty()) {
1267 idNode
const node = queue.front();
1269 idNode
const nodeOrigin = trees[i]->getNode(node)->getOrigin();
1270 idNode
const nodeParent = trees[i]->getParentSafe(node);
1275 std::vector<idNode> children;
1276 trees[i]->getChildren(node, children);
1277 for(
auto child : children)
1278 queue.emplace(child);
1284 = [&](vtkUnstructuredGrid *vtu,
int pointID, double(&point)[3]) {
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];
1292 for(
int k = 0; k < 3; ++k) {
1293 auto array = vtu->GetPointData()->GetArray(
1296 point[k] += array->GetComponent(pointID, k);
1303 int nodeMeshTreeIndex = -1;
1304 double noMatched = 0.0;
1305 double point[3] = {0, 0, 0};
1306 if(ShiftMode == 1) {
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);
1313 nodeMeshTreeIndex = j;
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);
1325 point[0] = layout[layoutCorr[node]];
1326 point[1] = layout[layoutCorr[node] + 1];
1334 if(ShiftMode == 1) {
1335 float const percentMatchT = noMatched * 100 / numInputs;
1336 allBaryPercentMatch[c][node] = percentMatchT;
1340 prevXMax = std::max(prevXMax, point[0]);
1341 if(ShiftMode == 3) {
1342 if(i < numInputs / 2)
1343 prevYMax = std::max(prevYMax, point[1]);
1344 if(i ==
int(numInputs / 2) - 1)
1350 and ((!trees[i]->isRoot(node) and !trees[i]->isLeaf(node))
1351 or isPersistenceDiagram);
1352 dummyNode = dummyNode or embeddedDiagram;
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())
1360 treesNodes[i], treesNodeCorrMesh[i][nodeOrigin], pointToAdd);
1362 if(not isPersistenceDiagram) {
1365 std::begin(point), std::end(point), std::begin(pointToAdd));
1367 double pdPoint[3] = {
1370 - (layout[layoutCorr[node] + 1] - layout[layoutCorr[node]]),
1372 std::copy(std::begin(pdPoint), std::end(pdPoint),
1373 std::begin(pointToAdd));
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];
1383 if(layout[layoutCorr[node]] > maxBirth) {
1384 maxBirth = layout[layoutCorr[node]];
1385 maxBirthNode = treeDummySimplexId[node];
1390 SimplexId
const nextPointId = points->InsertNextPoint(point);
1391 treeSimplexId[node] = nextPointId;
1392 nodeCorr[i][node] = nextPointId;
1394 nodeCorr[i][node] = treeDummySimplexId[node];
1395 if(isPersistenceDiagram)
1396 nodeCorr[i][node] = nextPointId;
1398 idNode
const nodeBranching
1400 or isPersistenceDiagram
1402 : treeBranching[node]);
1405 bool pathDummyNode =
false;
1412 if(!trees[i]->isRoot(node) or isPersistenceDiagram) {
1413 vtkIdType pointIds[2];
1414 pointIds[0] = treeSimplexId[node];
1417 bool const dummyCell
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];
1425 pointIds[1] = treeSimplexId[treeBranching[node]];
1426 }
else if(dummyCell) {
1427 double dummyPoint[3]
1428 = {point[0], layout[layoutCorr[nodeParent] + 1] + diff_y,
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;
1438 pointIds[1] = treeSimplexId[nodeParent];
1441 bool isNodeParentImportant = isImportantPairVector[nodeParent];
1443 and isNodeParentImportant
1444 and !trees[i]->isRoot(nodeParent);
1445 if(not pathDummyCell and alignTrees and ShiftMode != 1) {
1448 and layout[layoutCorr[node]] != layout[layoutCorr[nodeParent]]
1449 and !trees[i]->isRoot(nodeParent);
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;
1464 vtkArcs->InsertNextCell(VTK_LINE, 2, pointIds);
1469 int const toAdd = 1 + (dummyCell ? 1 : 0) + (pathDummyCell ? 1 : 0);
1470 for(
int toAddT = 0; toAddT < toAdd; ++toAddT) {
1472 if(ShiftMode == 1) {
1474 = (!isPersistenceDiagram ? allBaryBranching[c][node] : node);
1475 percentMatchArc->InsertNextTuple1(
1476 allBaryPercentMatch[c][nodeToGet]);
1482 if(clusteringOutput and ShiftMode != 1) {
1485 auto nodeToGet = node;
1486 if(treeMatching[nodeToGet] < allBaryBranchingID[c].size())
1487 tBranchID = allBaryBranchingID[c][treeMatching[nodeToGet]];
1488 branchBaryID->InsertNextTuple1(tBranchID);
1491 and !pathMatchings[c].empty()) {
1494 if(treeMatching[nodeToGet] < allBaryPathingID[c].size())
1495 tPathID = allBaryPathingID[c][treeMatching[nodeToGet]];
1496 pathBaryID->InsertNextTuple1(tPathID);
1501 if(not isPersistenceDiagram) {
1503 int const tBranchID = treeBranchingID[node];
1504 branchID->InsertNextTuple1(tBranchID);
1507 and !pathMatchings[c].empty()) {
1508 int tPathID = treePathingID[node];
1509 pathID->InsertNextTuple1(tPathID);
1514 if(not isPersistenceDiagram) {
1515 upNodeId->InsertNextTuple1(treeSimplexId[nodeParent]);
1516 downNodeId->InsertNextTuple1(treeSimplexId[node]);
1522 idNode
const nodeToGetPers
1523 = (isPersistenceDiagram ? node : nodeBranching);
1524 double const persToAdd
1525 = trees[i]->getNodePersistence<dataType>(nodeToGetPers);
1526 persistenceArc->InsertNextTuple1(persToAdd);
1530 = trees[i]->getBirthDeath<dataType>(nodeToGetPers);
1531 pairBirth->InsertNextTuple1(std::get<0>(birthDeath));
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]]);
1546 clusterIDArc->InsertNextTuple1(clusteringAssignment[i]);
1549 treeIDArc->InsertNextTuple1(i + iSampleOffset);
1552 bool isImportant =
false;
1553 idNode
const nodeToGetImportance = nodeBranching;
1554 isImportant = trees[i]->isImportantPair<dataType>(
1558 isImportantPairsArc->InsertNextTuple1(isImportant);
1561 bool const isDummy = toAdd >= 2 and toAddT == (toAdd - 2);
1562 isDummyArc->InsertNextTuple1(isDummy);
1565 isInterpolatedTreeArc->InsertNextTuple1(isInterpolatedTree);
1568 pairIdentifier->InsertNextTuple1(treeSimplexId[node]);
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);
1578 pairType->InsertNextTuple1(0);
1581 bool const isMultiPersPair
1582 = (trees[i]->isMultiPersPair(nodeBranching)
1583 or trees[i]->isMultiPersPair(
1584 trees[i]->getNode(nodeBranching)->getOrigin()));
1585 isMultiPersPairArc->InsertNextTuple1(isMultiPersPair);
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]);
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);
1612 nodeID->InsertNextTuple1(treeSimplexId[nodeToGet]);
1615 trueNodeID->InsertNextTuple1(nodeToGet);
1618 int nodeVertexId = -1;
1619 if(i <
int(treesNodes.size()) and treesNodes[i]) {
1620 auto vertexIdArray = treesNodes[i]->GetPointData()->GetArray(
1623 if(vertexIdArray and nodeMesh != -1)
1624 nodeVertexId = vertexIdArray->GetTuple1(nodeMesh);
1626 vertexID->InsertNextTuple1(nodeVertexId);
1629 auto scalarValue = trees[i]->getValue<dataType>(nodeToGet);
1630 scalar->InsertNextTuple1(scalarValue);
1634 int criticalTypeT = -1;
1635 if(not isPersistenceDiagram) {
1636 if(not isInterpolatedTree) {
1637 if(ShiftMode == 1) {
1638 if(nodeMeshTreeIndex != -1) {
1640 = treesNodes[nodeMeshTreeIndex]->GetPointData()->GetArray(
1643 criticalTypeT = array->GetTuple1(nodeMesh);
1645 }
else if(treesNodes.size() != 0 and treesNodes[i] !=
nullptr) {
1647 = treesNodes[i]->GetPointData()->GetArray(
"CriticalType");
1649 criticalTypeT = array->GetTuple1(nodeMesh);
1659 auto nodeIsRoot = trees[i]->isRoot(node);
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);
1668 = ((nodeSup and toAddT == 1) or (not nodeSup and toAddT == 0)
1669 ? (isPDSadMax or nodeIsRoot ? locMax : saddle1)
1670 : (not isPDSadMax or nodeIsRoot ? locMin : saddle2));
1673 criticalType->InsertNextTuple1(criticalTypeT);
1677 percentMatch->InsertNextTuple1(allBaryPercentMatch[c][node]);
1682 if(clusteringOutput and ShiftMode != 1) {
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);
1694 and !pathMatchings[c].empty()) {
1699 : (not isRootPath[node] ? node : pathOrigin[node]));
1700 if(treeMatching[pathNode] < allBaryPathingID[c].size())
1701 tPathID = allBaryPathingID[c][treeMatching[pathNode]];
1702 pathBaryNodeID->InsertNextTuple1(tPathID);
1707 if(not isPersistenceDiagram) {
1711 ? trees[i]->getNode(treeBranching[node])->getOrigin()
1712 : (trees[i]->isLeaf(node) ? node : nodeOrigin));
1713 int tBranchID = treeBranchingID[branchNode];
1714 branchNodeID->InsertNextTuple1(tBranchID);
1717 and !pathMatchings[c].empty()) {
1721 : (not isRootPath[node] ? node : pathOrigin[node]));
1723 int tPathID = treePathingID[pathNode];
1724 pathNodeID->InsertNextTuple1(tPathID);
1730 persistenceNode->InsertNextTuple1(
1731 trees[i]->getNodePersistence<dataType>(node));
1734 auto birthDeath = trees[i]->getBirthDeath<dataType>(node);
1735 pairBirthNode->InsertNextTuple1(std::get<0>(birthDeath));
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]]);
1749 clusterIDNode->InsertNextTuple1(clusteringAssignment[i]);
1752 treeIDNode->InsertNextTuple1(i + iSampleOffset);
1756 = toAdd == 2 and toAddT == 1 and !trees[i]->isRoot(node);
1758 isDummy = (toAdd >= 2 and dummyNode and toAddT == 0
1759 and !trees[i]->isRoot(node));
1760 isDummy = isDummy or isPathDummyNode;
1762 isDummyNode->InsertNextTuple1(isDummy);
1765 isInterpolatedTreeNode->InsertNextTuple1(isInterpolatedTree);
1768 bool isImportant = isImportantPairVector[nodeToGet];
1769 isImportantPairsNode->InsertNextTuple1(isImportant);
1772 treeNodeId->InsertNextTuple1(nodeToGet);
1775 treeNodeIdOrigin->InsertNextTuple1(nodeOrigin);
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]);
1788 bool const isMultiPersPair
1789 = (trees[i]->isMultiPersPair(node)
1790 or trees[i]->isMultiPersPair(
1791 trees[i]->getNode(node)->getOrigin()));
1792 isMultiPersPairNode->InsertNextTuple1(isMultiPersPair);
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]);
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);
1819 pairIdentifier->InsertNextTuple1(-1);
1820 pairType->InsertNextTuple1(-1);
1821 persistenceArc->InsertNextTuple1(-1);
1822 pairIsFinite->InsertNextTuple1(0);
1823 pairBirth->InsertNextTuple1(0);
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(
"");
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);
1847 if(OutputSegmentation and not PlanarLayout and treesSegmentation[i]) {
1848 vtkNew<vtkUnstructuredGrid> iTreesSegmentationCopy{};
1850 iTreesSegmentationCopy->DeepCopy(treesSegmentation[i]);
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());
1863 if(ShiftMode != -1) {
1865 p < iVkOutputSegmentationTemp->GetPoints()->GetNumberOfPoints();
1868 = iVkOutputSegmentationTemp->GetPoints()->GetPoint(p);
1872 iVkOutputSegmentationTemp->GetPoints()->SetPoint(p, point);
1875 appendFilter->AddInputData(iVkOutputSegmentationTemp);
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;
1886 persistenceBaryOrderNode->InsertNextTuple1(0);
1887 for(
int i = persistenceBaryOrderArc->GetNumberOfTuples(); i < cellCount;
1889 persistenceBaryOrderArc->InsertNextTuple1(0);
1897 customIntArrays, customIntArraysValues, vtkOutputNode, 1, 0);
1899 customStringArrays, customStringArraysValues, vtkOutputNode, 2, 0);
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);
1916 and !pathMatchings[0].empty())
1917 vtkOutputNode->GetPointData()->AddArray(pathNodeID);
1920 vtkOutputNode->GetPointData()->AddArray(scalar);
1921 if(clusteringOutput and ShiftMode != 1) {
1922 vtkOutputNode->GetPointData()->AddArray(branchBaryNodeID);
1924 and !pathMatchings[0].empty())
1925 vtkOutputNode->GetPointData()->AddArray(pathBaryNodeID);
1926 vtkOutputNode->GetPointData()->AddArray(persistenceBaryNode);
1927 vtkOutputNode->GetPointData()->AddArray(persistenceBaryOrderNode);
1929 if(foundOneInterpolatedTree)
1930 vtkOutputNode->GetPointData()->AddArray(isInterpolatedTreeNode);
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);
1940 vtkOutputNode->GetPointData()->AddArray(pairBirthNode);
1946 customIntArrays, customCellIntArraysValues, vtkArcs, 1, 1);
1948 customStringArrays, customCellStringArraysValues, vtkArcs, 2, 1);
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);
1961 and !pathMatchings[0].empty())
1962 vtkArcs->GetCellData()->AddArray(pathID);
1963 vtkArcs->GetCellData()->AddArray(upNodeId);
1964 vtkArcs->GetCellData()->AddArray(downNodeId);
1966 if(clusteringOutput and ShiftMode != 1) {
1967 vtkArcs->GetCellData()->AddArray(branchBaryID);
1969 and !pathMatchings[0].empty())
1970 vtkArcs->GetCellData()->AddArray(pathBaryID);
1971 vtkArcs->GetCellData()->AddArray(persistenceBaryArc);
1972 vtkArcs->GetCellData()->AddArray(persistenceBaryOrderArc);
1974 if(foundOneInterpolatedTree)
1975 vtkArcs->GetCellData()->AddArray(isInterpolatedTreeArc);
1977 vtkArcs->GetCellData()->AddArray(percentMatchArc);
1978 if(isPersistenceDiagram) {
1979 vtkArcs->GetCellData()->AddArray(pairIdentifier);
1980 vtkArcs->GetCellData()->AddArray(pairType);
1981 vtkArcs->GetCellData()->AddArray(pairIsFinite);
1983 vtkArcs->GetCellData()->AddArray(pairBirth);
1984 if(vtkOutputArc == vtkOutputNode)
1985 vtkArcs->GetPointData()->ShallowCopy(vtkOutputNode->GetPointData());
1987 vtkArcs->GetPointData()->AddArray(scalar);
1988 vtkOutputArc->ShallowCopy(vtkArcs);
1991 if(OutputSegmentation and not PlanarLayout
1992 and appendFilter->GetNumberOfInputConnections(0) != 0) {
1993 appendFilter->SetMergePoints(
false);
1994 appendFilter->Update();
1995 vtkOutputSegmentation->ShallowCopy(appendFilter->GetOutput());