17 MyCmp(
const vector<double> *vertexScalars,
18 const vector<int> *vertexOffsets,
19 const vector<Node> *nodeList,
20 bool isAscendingOrder)
26 int const vertex1 = (*nodeList_)[node1].getVertexId();
27 int const vertex2 = (*nodeList_)[node2].getVertexId();
29 = ((*vertexScalars_)[vertex1] < (*vertexScalars_)[vertex2])
31 && (*vertexOffsets_)[vertex1] < (*vertexOffsets_)[vertex2]);
40 bool operator()(
const pair<
bool, pair<
double, pair<int, int>>> &v0,
41 const pair<
bool, pair<
double, pair<int, int>>> &v1)
const {
44 return ((v0.second.first < v1.second.first)
45 || ((v0.second.first == v1.second.first)
46 && (v0.second.second.first < v1.second.second.first)));
48 return ((v0.second.first > v1.second.first)
49 || ((v0.second.first == v1.second.first)
50 && (v0.second.second.first > v1.second.second.first)));
57 const pair<pair<int, int>,
double> &p1) {
59 return p0.second < p1.second;
70 const pair<pair<int, int>,
double> &p1) {
72 > (*vertexScalars_)[p1.first.first];
80 const pair<double, double> &p1) {
81 return p0.first < p1.first;
86 const vector<vector<double>> *vertexPositions,
92 for(
unsigned int i = 0; i < barycenterList.size(); ++i)
93 barycenterList[i].resize(3);
107 for(
unsigned int k = 0; k < 3; ++k) {
108 p0[k] = (*vertexPositions)[down_vId][k];
109 p1[k] = (*vertexPositions)[up_vId][k];
115 for(
unsigned int k = 0; k < 3; ++k)
119 for(
int i = 1; i < N - 1; ++i) {
120 for(
unsigned int k = 0; k < 3; ++k)
125 for(
unsigned int k = 0; k < 3; ++k)
128 for(
unsigned int k = 0; k < 3; ++k)
129 barycenterList[0][k] = (p0[k] + p1[k]) * 0.5;
133 for(
int i = 0; i < N; ++i) {
134 for(
unsigned int k = 0; k < 3; ++k)
141 const vector<int> *vertexOffsets,
142 const vector<Node> *nodeList,
144 MyCmp const cmp(vertexScalars, vertexOffsets, nodeList, order);
153 const int &downVertexId,
154 const int &upVertexId,
155 const vector<int> &
ttkNotUsed(interiorNodeIds)) {
160 double downScalar = 0, upScalar = 0;
165 return fabs(upScalar - downScalar);
182 if(
superArcList_[superArcId].getNumberOfRegularNodes() == 1) {
213 vector<UnionFind> seeds;
214 vector<vector<int>> seedSuperArcs;
216 vector<UnionFind *> starSets;
220 UnionFind *seed =
nullptr, *firstUf =
nullptr;
222 const vector<int> *extremumList =
nullptr;
224 bool isMergeTree =
true;
245 seeds.resize(extremumList->size());
246 seedSuperArcs.resize(seeds.size());
248 for(
int i = 0; i < (int)extremumList->size(); i++) {
250 vertexSeeds[(*extremumList)[i]] = &(seeds[i]);
256 pair<bool, pair<double, pair<int, int>>> v;
257 v.first = isMergeTree;
258 v.second.first = (*vertexScalars_)[(*extremumList)[i]];
259 v.second.second.first = (*vertexSoSoffsets_)[(*extremumList)[i]];
260 v.second.second.second = (*extremumList)[i];
262 filtrationFront.insert(v);
270 vertexId = filtrationFront.begin()->second.second.second;
271 filtrationFront.erase(filtrationFront.begin());
280 for(
SimplexId i = 0; i < neighborNumber; i++) {
283 if(vertexSeeds[nId]) {
284 seed = vertexSeeds[nId]->
find();
285 starSets.push_back(seed);
290 else if(seed != firstUf)
294 if(!visitedVertices[nId]) {
296 pair<bool, pair<double, pair<int, int>>> v;
297 v.first = isMergeTree;
298 v.second.first = (*vertexScalars_)[nId];
299 v.second.second.first = (*vertexSoSoffsets_)[nId];
300 v.second.second.second = nId;
302 filtrationFront.insert(v);
303 visitedVertices[nId] =
true;
307 if(!vertexSeeds[vertexId]) {
311 int const newNodeId =
makeNode(vertexId);
316 for(
int i = 0; i < (int)starSets.size(); i++) {
317 int const seedId = starSets[i] - &(seeds[0]);
319 for(
int j = 0; j < (int)seedIds.size(); j++) {
320 if(seedIds[j] == seedId) {
326 seedIds.push_back(seedId);
329 for(
int i = 0; i < (int)seedIds.size(); i++) {
331 = seedSuperArcs[seedIds[i]][seedSuperArcs[seedIds[i]].size() - 1];
335 int const seedId = vertexSeeds[vertexId] - &(seeds[0]);
336 if(!filtrationFront.empty())
337 seedSuperArcs[seedId].push_back(
openSuperArc(newNodeId));
338 }
else if(starSets.size()) {
340 int const seedId = starSets[0] - &(seeds[0]);
342 = seedSuperArcs[seedId][seedSuperArcs[seedId].size() - 1];
344 if(filtrationFront.empty()) {
354 visitedVertices[vertexId] =
true;
356 }
while(!filtrationFront.empty());
358 const std::string tree = isMergeTree ?
"JoinTree" :
"SplitTree";
360 tree +
" computed", 1.0, timer.
getElapsedTime(), this->threadNumber_);
361 this->
printMsg(std::vector<std::vector<std::string>>{
380 for(
int i = 0; i <
nodeList_[nodeId0].getNumberOfUpArcs(); i++) {
389 for(
int i = 0; i <
nodeList_[nodeId1].getNumberOfDownArcs(); i++) {
408 if(!((
nodeList_[nodeId].getNumberOfDownArcs() == 1)
409 && (
nodeList_[nodeId].getNumberOfUpArcs() == 1)))
412 const int downArcId =
nodeList_[nodeId].getDownArcId(0),
413 upArcId =
nodeList_[nodeId].getUpArcId(0);
415 int const upNodeId =
arcList_[upArcId].getUpNodeId();
422 arcList_[downArcId].setUpNodeId(upNodeId);
425 for(
int i = 0; i <
nodeList_[upNodeId].getNumberOfDownArcs(); i++) {
426 if(
nodeList_[upNodeId].getDownArcId(i) == upArcId) {
432 nodeList_[upNodeId].addDownArcId(downArcId);
444 if((
nodeList_[nodeId].getNumberOfDownArcs() == 1)
445 && (!
nodeList_[nodeId].getNumberOfUpArcs())) {
457 vector<int> &vertexIds,
458 const vector<float> *origin,
459 const vector<float> *voxelSize,
462 vector<float> myOrigin(3), myVoxelSize(3);
465 myOrigin = *(origin);
467 myOrigin[0] = myOrigin[1] = myOrigin[2] = 0;
471 myVoxelSize = *(voxelSize);
473 myVoxelSize[0] = myVoxelSize[1] = myVoxelSize[2] = 1;
476 double const offset = myVoxelSize[0];
483 v = (*vertexPositions_)[
nodeList_[downNodeId].vertexId_];
485 for(
int i = 0; i < 3; i++) {
487 v[i] /= myVoxelSize[i];
491 o << v[0] <<
" " << v[1] <<
" " << v[2] << endl;
492 vertexIds.push_back(pointId);
494 v = (*vertexPositions_)[
nodeList_[downNodeId].vertexId_];
496 for(
int i = 0; i < 3; i++) {
498 v[i] /= myVoxelSize[i];
502 o << v[0] <<
" " << v[1] <<
" " << v[2] << endl;
503 vertexIds.push_back(pointId + 1);
505 v = (*vertexPositions_)[
nodeList_[downNodeId].vertexId_];
507 for(
int i = 0; i < 3; i++) {
509 v[i] /= myVoxelSize[i];
513 o << v[0] <<
" " << v[1] <<
" " << v[2] << endl;
514 vertexIds.push_back(pointId + 2);
516 v = (*vertexPositions_)[
nodeList_[downNodeId].vertexId_];
518 for(
int i = 0; i < 3; i++) {
520 v[i] /= myVoxelSize[i];
524 o << v[0] <<
" " << v[1] <<
" " << v[2] << endl;
525 vertexIds.push_back(pointId + 3);
527 v = (*vertexPositions_)[
nodeList_[upNodeId].vertexId_];
529 for(
int i = 0; i < 3; i++) {
531 v[i] /= myVoxelSize[i];
535 o << v[0] <<
" " << v[1] <<
" " << v[2] << endl;
536 vertexIds.push_back(pointId + 4);
538 v = (*vertexPositions_)[
nodeList_[upNodeId].vertexId_];
540 for(
int i = 0; i < 3; i++) {
542 v[i] /= myVoxelSize[i];
546 o << v[0] <<
" " << v[1] <<
" " << v[2] << endl;
547 vertexIds.push_back(pointId + 5);
549 v = (*vertexPositions_)[
nodeList_[upNodeId].vertexId_];
551 for(
int i = 0; i < 3; i++) {
553 v[i] /= myVoxelSize[i];
557 o << v[0] <<
" " << v[1] <<
" " << v[2] << endl;
558 vertexIds.push_back(pointId + 6);
560 v = (*vertexPositions_)[
nodeList_[upNodeId].vertexId_];
562 for(
int i = 0; i < 3; i++) {
564 v[i] /= myVoxelSize[i];
568 o << v[0] <<
" " << v[1] <<
" " << v[2] << endl;
569 vertexIds.push_back(pointId + 7);
576 for(
int i = 0; i < 8; i++) {
578 if(!
nodeList_[nodeId].downSuperArcList_.size()) {
586 }
else if(!
nodeList_[nodeId].upSuperArcList_.size()) {
603 vector<int> &vertexIds,
604 const vector<float> *origin,
605 const vector<float> *voxelSize,
608 vector<float> myOrigin(3), myVoxelSize(3);
611 myOrigin = *(origin);
613 myOrigin[0] = myOrigin[1] = myOrigin[2] = 0;
617 myVoxelSize = *(voxelSize);
619 myVoxelSize[0] = myVoxelSize[1] = myVoxelSize[2] = 1;
622 double const offset = myVoxelSize[0];
626 v = (*vertexPositions_)[
nodeList_[nodeId].vertexId_];
628 for(
int i = 0; i < 3; i++) {
630 v[i] /= myVoxelSize[i];
636 o << v[0] <<
" " << v[1] <<
" " << v[2] << endl;
637 vertexIds.push_back(pointId);
639 v = (*vertexPositions_)[
nodeList_[nodeId].vertexId_];
641 for(
int i = 0; i < 3; i++) {
643 v[i] /= myVoxelSize[i];
648 o << v[0] <<
" " << v[1] <<
" " << v[2] << endl;
649 vertexIds.push_back(pointId + 1);
651 v = (*vertexPositions_)[
nodeList_[nodeId].vertexId_];
653 for(
int i = 0; i < 3; i++) {
655 v[i] /= myVoxelSize[i];
660 o << v[0] <<
" " << v[1] <<
" " << v[2] << endl;
661 vertexIds.push_back(pointId + 2);
663 v = (*vertexPositions_)[
nodeList_[nodeId].vertexId_];
665 for(
int i = 0; i < 3; i++) {
667 v[i] /= myVoxelSize[i];
672 o << v[0] <<
" " << v[1] <<
" " << v[2] << endl;
673 vertexIds.push_back(pointId + 3);
675 v = (*vertexPositions_)[
nodeList_[nodeId].vertexId_];
677 for(
int i = 0; i < 3; i++) {
679 v[i] /= myVoxelSize[i];
684 o << v[0] <<
" " << v[1] <<
" " << v[2] << endl;
685 vertexIds.push_back(pointId + 4);
687 v = (*vertexPositions_)[
nodeList_[nodeId].vertexId_];
689 for(
int i = 0; i < 3; i++) {
691 v[i] /= myVoxelSize[i];
696 o << v[0] <<
" " << v[1] <<
" " << v[2] << endl;
697 vertexIds.push_back(pointId + 5);
699 v = (*vertexPositions_)[
nodeList_[nodeId].vertexId_];
701 for(
int i = 0; i < 3; i++) {
703 v[i] /= myVoxelSize[i];
708 o << v[0] <<
" " << v[1] <<
" " << v[2] << endl;
709 vertexIds.push_back(pointId + 6);
711 v = (*vertexPositions_)[
nodeList_[nodeId].vertexId_];
713 for(
int i = 0; i < 3; i++) {
715 v[i] /= myVoxelSize[i];
720 o << v[0] <<
" " << v[1] <<
" " << v[2] << endl;
721 vertexIds.push_back(pointId + 7);
727 vector<pair<double, int>> persistencePlot;
731 ofstream file(fileName.data(), ios::out);
737 for(
int i = 0; i < (int)persistencePlot.size(); i++) {
740 <<
" " << persistencePlot[i].second << endl;
750 vector<pair<double, double>> diagram;
754 ofstream file(fileName.data(), ios::out);
760 for(
int i = 0; i < (int)diagram.size(); i++) {
762 << diagram[i].first << endl;
764 << diagram[i].second << endl;
766 << diagram[i].first << endl;
775 const double &scaleX,
776 const double &scaleY) {
786 double minY = -1, maxY = -1;
828 string const dotFileName = fileName +
".dot";
830 ofstream dotFile(dotFileName.data(), ios::out);
833 this->
printErr(
"Could not open file `" + dotFileName +
"'!");
837 dotFile <<
"digraph \"";
842 dotFile <<
" Tree\"{" << endl;
844 double minValue = 0, maxValue = 0;
846 if((!i) || (minValue > (*vertexScalars_)[i])) {
847 minValue = (*vertexScalars_)[i];
849 if((!i) || (maxValue < (*vertexScalars_)[i])) {
850 maxValue = (*vertexScalars_)[i];
862 dotFile <<
" \"f = ";
863 dotFile << (*vertexScalars_)[
nodeList_[downNodeId].vertexId_];
865 dotFile <<
"\\n p = ("
866 << (*vertexPositions_)[
nodeList_[downNodeId].vertexId_][0]
868 << (*vertexPositions_)[
nodeList_[downNodeId].vertexId_][1]
870 << (*vertexPositions_)[
nodeList_[downNodeId].vertexId_][2]
873 dotFile <<
"\" -> \"f = ";
874 dotFile << (*vertexScalars_)[
nodeList_[upNodeId].vertexId_];
876 dotFile <<
"\\n p = ("
877 << (*vertexPositions_)[
nodeList_[upNodeId].vertexId_][0] <<
" "
878 << (*vertexPositions_)[
nodeList_[upNodeId].vertexId_][1] <<
" "
879 << (*vertexPositions_)[
nodeList_[upNodeId].vertexId_][2] <<
")";
881 dotFile <<
"\"" << endl;
885 for(
int i = 0; i < (int)
nodeList_.size(); i++) {
887 if((
nodeList_[i].downSuperArcList_.size())
888 || (
nodeList_[i].upSuperArcList_.size())) {
891 dotFile <<
" \"f = ";
892 dotFile << (*vertexScalars_)[
nodeList_[i].vertexId_];
894 dotFile <<
"\\n p = ("
895 << (*vertexPositions_)[
nodeList_[i].vertexId_][0] <<
" "
896 << (*vertexPositions_)[
nodeList_[i].vertexId_][1] <<
" "
897 << (*vertexPositions_)[
nodeList_[i].vertexId_][2] <<
")";
906 if(!
nodeList_[i].upSuperArcList_.size()) {
908 dotFile <<
"fillcolor=green,";
909 }
else if(!
nodeList_[i].downSuperArcList_.size()) {
911 dotFile <<
"fillcolor=blue,fontcolor=white,";
913 dotFile <<
"fillcolor=lightyellow,shape=diamond,";
920 if(!
nodeList_[i].upSuperArcList_.size()) {
922 dotFile <<
"fillcolor=blue,fontcolor=white,";
923 }
else if(!
nodeList_[i].downSuperArcList_.size()) {
925 dotFile <<
"fillcolor=green,";
927 dotFile <<
"fillcolor=lightyellow,shape=diamond,";
931 dotFile <<
"style=filled,";
934 dotFile <<
"pos=\"" <<
nodeList_[i].layoutX_ <<
", "
945 dotFile <<
"}" << endl;
949 stringstream commandLine;
950 commandLine <<
"dot -Kneato -Tsvg " << dotFileName <<
" -o " << fileName
952 this->
printMsg(
"Calling GraphViz to generate the SVG file.");
953 this->
printMsg(
"This may take a long time...");
955 int const cmdRet = system(commandLine.str().data());
957 if((!cmdRet) || (cmdRet == 256)) {
959 "Output file `" + fileName +
"' generated", 1.0, t.
getElapsedTime(), 1);
961 this->
printErr(
"Could not find the `GraphViz' package!");
962 this->
printErr(
"Please install it and re-run this program.");
971 const vector<float> *origin,
972 const vector<float> *voxelSize) {
980 ofstream o(fileName.data(), ios::out);
983 this->
printErr(
"Could not open file `" + fileName +
"'!");
987 int superArcNumber = 0;
994 nodeNumber = superArcNumber + 1;
996 int pointNumber = 0, cellNumber = 0;
997 pointNumber = 8 * nodeNumber + 8 * superArcNumber;
998 cellNumber = nodeNumber + superArcNumber;
1000 vector<bool> nodeColorOut(
nodeList_.size(),
false);
1001 vector<bool> nodePosOut(
nodeList_.size(),
false);
1002 vector<bool> nodeMeshOut(
nodeList_.size(),
false);
1003 vector<vector<int>> nodeIds(
nodeList_.size());
1006 o <<
"<?xml version=\"1.0\"?>" << endl;
1007 o <<
"<VTKFile type=\"UnstructuredGrid\" version=\"0.1\""
1008 <<
" byte_order=\"LittleEndian\">" << endl;
1009 o <<
" <UnstructuredGrid>" << endl;
1010 o <<
" <Piece NumberOfPoints=\"" << pointNumber <<
"\" NumberOfCells=\""
1011 << cellNumber <<
"\">";
1012 o <<
" <PointData Scalars=\"Color Code\">" << endl;
1013 o <<
" <DataArray type=\"Float32\" Name=\"Critical Color\""
1014 <<
" format=\"ascii\" NumberOfComponents=\"1\">" << endl;
1022 if(!nodeColorOut[downNodeId]) {
1026 nodeColorOut[downNodeId] =
true;
1028 if(!nodeColorOut[upNodeId]) {
1032 nodeColorOut[upNodeId] =
true;
1041 for(
int j = 0; j < 8; j++) {
1047 o <<
" </DataArray>" << endl;
1048 o <<
" </PointData>" << endl;
1052 o <<
" <Points>" << endl;
1053 o <<
" <DataArray type=\"Float32\" NumberOfComponents=\"3\""
1054 <<
" format=\"ascii\">" << endl;
1062 if(!nodePosOut[downNodeId]) {
1065 downNodeId, pointId, nodeIds[downNodeId], origin, voxelSize, o);
1066 nodePosOut[downNodeId] =
true;
1070 if(!nodePosOut[upNodeId]) {
1073 upNodeId, pointId, nodeIds[upNodeId], origin, voxelSize, o);
1074 nodePosOut[upNodeId] =
true;
1088 o <<
" </DataArray>" << endl;
1089 o <<
" </Points>" << endl;
1092 o <<
" <Cells>" << endl;
1094 o <<
" <DataArray type=\"Int32\" Name=\"connectivity\""
1095 <<
" format=\"ascii\">" << endl;
1102 if(!nodeMeshOut[downNodeId]) {
1103 o <<
" " << nodeIds[downNodeId][0] <<
" "
1104 << nodeIds[downNodeId][1] <<
" " << nodeIds[downNodeId][2] <<
" "
1105 << nodeIds[downNodeId][3] <<
" " << nodeIds[downNodeId][4] <<
" "
1106 << nodeIds[downNodeId][5] <<
" " << nodeIds[downNodeId][6] <<
" "
1107 << nodeIds[downNodeId][7] << endl;
1108 nodeMeshOut[downNodeId] =
true;
1110 if(!nodeMeshOut[upNodeId]) {
1111 o <<
" " << nodeIds[upNodeId][0] <<
" " << nodeIds[upNodeId][1]
1112 <<
" " << nodeIds[upNodeId][2] <<
" " << nodeIds[upNodeId][3] <<
" "
1113 << nodeIds[upNodeId][4] <<
" " << nodeIds[upNodeId][5] <<
" "
1114 << nodeIds[upNodeId][6] <<
" " << nodeIds[upNodeId][7] << endl;
1115 nodeMeshOut[upNodeId] =
true;
1121 o <<
" " << arcIds[i][0] <<
" " << arcIds[i][1] <<
" "
1122 << arcIds[i][2] <<
" " << arcIds[i][3] <<
" " << arcIds[i][4] <<
" "
1123 << arcIds[i][5] <<
" " << arcIds[i][6] <<
" " << arcIds[i][7] << endl;
1127 o <<
" </DataArray>" << endl;
1129 o <<
" <DataArray type=\"Int32\" Name=\"offsets\""
1130 <<
" format=\"ascii\">" << endl;
1132 for(
int i = 0; i < nodeNumber; i++) {
1133 o <<
" " << pointId << endl;
1136 for(
int i = 0; i < superArcNumber; i++) {
1137 o <<
" " << pointId << endl;
1140 o <<
" </DataArray>" << endl;
1142 o <<
" <DataArray type=\"Int32\" Name=\"types\""
1143 <<
" format=\"ascii\">" << endl;
1144 for(
int i = 0; i < nodeNumber; i++) {
1147 for(
int i = 0; i < superArcNumber; i++) {
1150 o <<
" </DataArray>" << endl;
1152 o <<
" </Cells>" << endl;
1153 o <<
" </Piece>" << endl;
1154 o <<
" </UnstructuredGrid>" << endl;
1155 o <<
"</VTKFile>" << endl;
1178 const bool &isSubLevelSet) {
1190 vector<pair<bool, pair<double, pair<int, int>>>> tmpList;
1194 bool isExtremum =
true;
1196 for(
SimplexId j = 0; j < neighborNumber; j++) {
1217 pair<bool, pair<double, pair<int, int>>> entry;
1218 entry.first = isSubLevelSet;
1219 entry.second.first = (*vertexScalars_)[i];
1220 entry.second.second.first = (*vertexSoSoffsets_)[i];
1221 entry.second.second.second = i;
1222 tmpList.push_back(entry);
1228 extremumList.resize(tmpList.size());
1229 for(
int i = 0; i < (int)extremumList.size(); i++) {
1230 extremumList[i] = tmpList[i].second.second.second;
1244 if((superArcId < 0) || (superArcId >= (
int)
superArcList_.size()))
1247 if((nodeId < 0) || (nodeId >= (
int)
nodeList_.size()))
1252 nodeList_[nodeId].addDownSuperArcId(superArcId);
1270 vector<pair<double, double>> &diagram,
1271 vector<pair<pair<int, int>,
double>> *pairs)
const {
1273 vector<pair<pair<int, int>,
double>> defaultPairs{};
1275 pairs = &defaultPairs;
1282 diagram.resize(pairs->size());
1284 for(
int i = 0; i < (int)pairs->size(); i++) {
1287 diagram[i].second = (*vertexScalars_)[(*pairs)[i].first.first];
1288 diagram[i].first = (*vertexScalars_)[(*pairs)[i].first.second];
1291 diagram[i].first = (*vertexScalars_)[(*pairs)[i].first.first];
1292 diagram[i].second = (*vertexScalars_)[(*pairs)[i].first.second];
1296 std::sort(diagram.begin(), diagram.end(),
_pPairCmp);
1302 vector<pair<pair<int, int>,
double>> &pairs,
1303 std::vector<std::pair<std::pair<int, int>,
double>> *
ttkNotUsed(mergePairs),
1304 std::vector<std::pair<std::pair<int, int>,
double>> *
ttkNotUsed(
1305 splitPairs))
const {
1312 bool isMergeTree =
true;
1317 isMergeTree =
false;
1322 pairs.resize(extremumList->size());
1335 double extremumScalar = 0;
1336 double saddleScalar = 0;
1339 extremumScalar = (*vertexScalars_)[nodeId];
1340 saddleScalar = (*vertexScalars_)[saddleId];
1342 pairs[leafId].first.first = nodeId;
1343 pairs[leafId].first.second = saddleId;
1344 pairs[leafId].second = fabs(saddleScalar - extremumScalar);
1345 float const persistence = pairs[leafId].second;
1346 if(isnan(persistence))
1347 pairs[leafId].second = 0;
1350 min2arc[nodeId] = i;
1356 sort(pairs.begin(), pairs.end(),
_pCmp);
1360 for(
unsigned int i = 0; i < pairs.size(); ++i) {
1361 pairedSaddles[pairs[i].first.second]++;
1364 for(
unsigned int j = i + 1; j < pairs.size(); ++j) {
1365 if((pairs[j].first.second == pairs[i].first.second)
1366 && (pairedSaddles[pairs[i].first.second] + 1
1368 ->getNumberOfDownSuperArcs())) {
1385 if(pairedSaddles[saddleId]
1386 < (
getVertexNode(saddleId))->getNumberOfDownSuperArcs() - 1) {
1388 double extremumScalar = 0;
1389 double saddleScalar = 0;
1391 extremumScalar = (*vertexScalars_)[pairs[j].first.first];
1392 saddleScalar = (*vertexScalars_)[saddleId];
1393 pairs[j].first.second = saddleId;
1394 pairs[j].second = fabs(saddleScalar - extremumScalar);
1395 float const persistence = pairs[j].second;
1396 if(isnan(persistence))
1397 pairs[j].second = 0;
1405 sort(pairs.begin() + j, pairs.end(),
_pCmp);
1426 float const persistence = pairs.back().second;
1427 if(isnan(persistence))
1428 pairs.back().second = 0;
1433 std::string
const pairtype = isMergeTree ?
"(0-1)" :
"(1-2)";
1434 std::string
const pairextr = isMergeTree ?
"min" :
"max";
1437 std::vector<std::vector<std::string>>{
1438 {
"#" + pairtype +
" pairs", std::to_string(pairs.size())}},
1440 for(
const auto &p : pairs) {
1442 std::vector<std::vector<std::string>>{
1443 {
"#" + pairextr, std::to_string(p.first.first)},
1444 {
"#saddles", std::to_string(p.first.second)},
1445 {
"Persistence", std::to_string(p.second)}},
1449 this->
printMsg(std::to_string(pairs.size()) +
" persistence pairs computed",
1456 vector<pair<double, int>> &plot,
1457 vector<pair<pair<int, int>,
double>> *persistencePairs)
const {
1459 vector<pair<pair<int, int>,
double>> defaultPersistencePairs{};
1460 if(!persistencePairs) {
1461 persistencePairs = &defaultPersistencePairs;
1464 if(!persistencePairs->size())
1467 plot.resize(persistencePairs->size());
1469 for(
int i = 0; i < (int)plot.size(); i++) {
1470 plot[i].first = (*persistencePairs)[i].second;
1474 plot[i].second = persistencePairs->size() - i;
1481 const double &scaleY) {
1484 this->
printErr(
"Contour tree planar layout not implemented.");
1485 this->
printErr(
"Planar layout is only implemented for merge-trees.");
1510 vector<bool> inFront(
nodeList_.size(),
false);
1511 vector<int> node2LeafNumber(
nodeList_.size(), 0);
1521 if(!
nodeList_[downNodeId].downSuperArcList_.size()) {
1522 pair<bool, pair<double, pair<int, int>>> n;
1524 n.second.first = (*vertexScalars_)[
nodeList_[downNodeId].vertexId_];
1525 n.second.second.first
1526 = (*vertexSoSoffsets_)[
nodeList_[downNodeId].vertexId_];
1527 n.second.second.second =
nodeList_[downNodeId].vertexId_;
1530 node2LeafNumber[downNodeId] = 1;
1531 inFront[downNodeId] =
true;
1539 int const vertexId = front.begin()->second.second.second;
1540 front.erase(front.begin());
1545 for(
int i = 0; i < (int)
nodeList_[nodeId].downSuperArcList_.size(); i++) {
1546 int const arcId =
nodeList_[nodeId].downSuperArcList_[i];
1549 node2LeafNumber[nodeId] += node2LeafNumber[childId];
1553 for(
int i = 0; i < (int)
nodeList_[nodeId].upSuperArcList_.size(); i++) {
1554 int const arcId =
nodeList_[nodeId].upSuperArcList_[i];
1557 if(!inFront[parentId]) {
1558 pair<bool, pair<double, pair<int, int>>> n;
1560 n.second.first = (*vertexScalars_)[
nodeList_[parentId].vertexId_];
1561 n.second.second.first
1562 = (*vertexSoSoffsets_)[
nodeList_[parentId].vertexId_];
1563 n.second.second.second =
nodeList_[parentId].vertexId_;
1566 node2LeafNumber[parentId] = 0;
1567 inFront[parentId] =
true;
1571 }
while(!front.empty());
1583 if(!
nodeList_[upNodeId].upSuperArcList_.size()) {
1595 vector<pair<double, double>> nodeInterval(
1596 nodeList_.size(), pair<double, double>(0, 1));
1597 queue<int> nodeQueue;
1601 nodeQueue.push(rootId);
1605 int const nodeId = nodeQueue.front();
1611 if((
nodeList_[nodeId].downSuperArcList_.size()) && (nodeId != subRootId)
1612 && (nodeId != rootId)) {
1614 int const arcId =
nodeList_[nodeId].downSuperArcList_[0];
1617 ratio = node2LeafNumber[childId] / ((double)node2LeafNumber[nodeId]);
1627 = nodeInterval[nodeId].first
1628 + ratio * (nodeInterval[nodeId].second - nodeInterval[nodeId].first);
1635 for(
int i = 0; i < (int)
nodeList_[nodeId].downSuperArcList_.size(); i++) {
1636 int const arcId =
nodeList_[nodeId].downSuperArcList_[i];
1639 ratio = node2LeafNumber[childId] / ((double)node2LeafNumber[nodeId]);
1643 nodeInterval[childId].first = nodeInterval[nodeId].first + xOffset;
1644 nodeInterval[childId].second
1645 = nodeInterval[childId].first
1646 + ratio * (nodeInterval[nodeId].second - nodeInterval[nodeId].first);
1647 xOffset = nodeInterval[childId].second;
1649 nodeQueue.push(childId);
1652 }
while(!nodeQueue.empty());
1665 for(
int i = 0; i < (int)
nodeList_.size(); i++) {
1690 if((nodeId0 < 0) || (nodeId0 >= (
int)
nodeList_.size()))
1692 if((nodeId1 < 0) || (nodeId1 >= (
int)
nodeList_.size()))
1724 if((nodeId < 0) || (nodeId >= (
int)
nodeList_.size()))
1736 const int &vertexId1)
const {
1745 const int &vertexId1)
const {
1754 const Node *oldDown,
1756 const Node *newDown,
1757 const Node *newUp) {
1765 if(
arcList_[arcId].getDownNodeId() == nodeId) {
1818 stringstream
const msg;
1824 int minCount = 0, saddleCount = 0, maxCount = 0, regularCount = 0;
1833 std::vector<std::vector<std::string>>{
1834 {
"Id", std::to_string(i),
"VertId", std::to_string(n->
getVertexId()),
1857 if((up) && (down)) {
1860 std::vector<std::vector<std::string>>{
1861 {
"Id", std::to_string(i),
"D",
1863 std::to_string(up->getNumberOfUpSuperArcs()),
"V",
1873 std::vector<std::vector<std::string>>{
1883 std::vector<std::vector<std::string>>{
1884 {
"#Minima", std::to_string(minCount)},
1885 {
"#Saddles", std::to_string(saddleCount)},
1886 {
"#Maxima", std::to_string(maxCount)},
1887 {
"#Regular", std::to_string(regularCount)},
1889 std::to_string(minCount + saddleCount + maxCount + regularCount)},
1907 if(metric ==
nullptr) {
1908 metric = &defaultMetric;
1911 metric->
tree_ =
this;
1923 this->
printErr(
"Contour tree simplification not implemented.");
1924 this->
printErr(
"Simplification is only implemented for merge-trees.");
1928 int simplifiedArcNumber = 0;
1929 double maximumMetricScore = 0;
1941 if(!simplificationThreshold)
1946 vector<pair<real, int>>
const regularNodeList;
1948 int arcToSimplify = -1;
1949 double currentScore = 0, minScore;
1964 if(!
nodeList_[downNodeId].downSuperArcList_.size()) {
1971 this->
printWrn(
"Out-of-range score! (user-defined metric)");
1973 if(currentScore < minScore) {
1975 minScore = currentScore;
1982 if(minScore > simplificationThreshold)
1985 if(minScore > maximumMetricScore)
1986 maximumMetricScore = minScore;
1988 if(arcToSimplify == -1)
1992 int const downNodeId =
superArcList_[arcToSimplify].downNodeId_;
1993 int const upNodeId =
superArcList_[arcToSimplify].upNodeId_;
1995 int pivotId = upNodeId;
1996 int leafId = downNodeId;
1998 if(!
nodeList_[downNodeId].downSuperArcList_.size()) {
2001 leafId = downNodeId;
2004 bool const isSimpleSaddle = (
nodeList_[pivotId].downSuperArcList_.size()
2005 +
nodeList_[pivotId].upSuperArcList_.size()
2010 for(
int i = 0; i < (int)
nodeList_[pivotId].downSuperArcList_.size(); i++) {
2011 if(
nodeList_[pivotId].downSuperArcList_[i] != arcToSimplify) {
2012 brotherId =
nodeList_[pivotId].downSuperArcList_[i];
2017 int const brotherExtremityId =
superArcList_[brotherId].downNodeId_;
2019 int const parentId =
nodeList_[pivotId].upSuperArcList_[0];
2022 if(isSimpleSaddle) {
2028 if(isSimpleSaddle) {
2030 i < (int)
nodeList_[brotherExtremityId].upSuperArcList_.size(); i++) {
2031 if(
nodeList_[brotherExtremityId].upSuperArcList_[i] == brotherId) {
2032 nodeList_[brotherExtremityId].upSuperArcList_[i] = parentId;
2038 for(
int i = 0; i < (int)
nodeList_[pivotId].downSuperArcList_.size();
2040 if(
nodeList_[pivotId].downSuperArcList_[i] == arcToSimplify) {
2041 nodeList_[pivotId].downSuperArcList_.erase(
2042 nodeList_[pivotId].downSuperArcList_.begin() + i);
2049 if(isSimpleSaddle) {
2063 superArcList_[parentId].regularNodeList_.push_back(pivotId);
2073 simplifiedArcNumber++;
2082 superArcList_[brotherId].regularNodeList_.push_back(leafId);
2086 simplifiedArcNumber++;
2088 }
while(minScore < simplificationThreshold);
2100 this->threadNumber_);
2102 this->
printMsg(std::to_string(simplifiedArcNumber)
2103 +
" super-arcs pruned (threshold="
2104 + std::to_string(simplificationThreshold) +
")",
2108 "Biggest simplification metric score: " + std::to_string(maximumMetricScore)
2118 vector<double> barycenter(3);
2128 for(
unsigned int k = 0; k < 3; ++k)
2131 for(
unsigned int k = 0; k <
sample.size(); ++k) {
2134 for(
unsigned int l = 0; l < 3; ++l)
2138 for(
unsigned int k = 0; k < 3; ++k)
2139 barycenter[k] /=
sample.size();
2152 const vector<double> &scalars,
2153 vector<vector<double>> &skeletonScalars)
const {
2154 skeletonScalars.clear();
2186 fmax = scalars[nodeMaxVId];
2187 fmin = scalars[nodeMinVId];
2197 for(
unsigned int k = 0; k <
sample.size(); ++k) {
2200 f += scalars[vertexId];
2207 skeletonScalars[i].push_back((f0 + f1) / 2);
2216 skeletonScalars[i].push_back((f0 + f1) / 2);
2232 for(
unsigned int i = 0; i < skeletonSmoothing; ++i) {
2247 vector<vector<int>> sampleList(samplingLevel);
2255 for(
unsigned int j = 0; j < samplingLevel; ++j)
2256 sampleList[j].clear();
2259 int nodeMaxId, nodeMinId;
2260 int nodeMaxVId, nodeMinVId;
2274 fmax = (*vertexScalars_)[nodeMaxVId];
2275 fmin = (*vertexScalars_)[nodeMinVId];
2277 delta = (fmax - fmin) / samplingLevel;
2285 f = (*vertexScalars_)[vertexId];
2287 for(
unsigned int k = 0; k < samplingLevel; ++k) {
2288 if(f <= (k + 1) * delta + fmin) {
2289 sampleList[k].push_back(nodeId);
2296 for(
unsigned int j = 0; j < sampleList.size(); ++j)
2332 std::vector<int> localVertSoSoffsets{};
2344 std::vector<int> minimumVec, maximumVec;
2350 bool isMin =
true, isMax =
true;
2352 for(
SimplexId j = 0; j < neighborNumber; j++) {
2357 || (((*vertexScalars_)[nId] == (*vertexScalars_)[i])
2366 if((!isMin) && (!isMax))
2370 if((isMin) && (!isMax))
2372 if((isMax) && (!isMin))
2376#ifdef TTK_ENABLE_OPENMP
2377#pragma omp parallel sections
2381#ifdef TTK_ENABLE_OPENMP
2395#ifdef TTK_ENABLE_OPENMP
2420 this->
printMsg(std::vector<std::vector<std::string>>{
2436 queue<const Node *> nodeQueue;
2437 const Node *mergeNode =
nullptr, *splitNode =
nullptr;
2441 int const initQueueSize = (int)nodeQueue.size();
2446 nodeQueue.push(mergeNode);
2452 nodeQueue.push(splitNode);
2457 if((
int)nodeQueue.size() == initQueueSize)
2460 const Node *n0 =
nullptr, *n1 =
nullptr, *other =
nullptr;
2464 n0 = nodeQueue.front();
2467#ifndef TTK_ENABLE_KAMIKAZE
2479 if(!((other->getNumberOfUpArcs())
2480 && (other->getNumberOfDownArcs() > 1))) {
2489 newNode1 =
makeNode(n1->getVertexId());
2496 if((other->getNumberOfDownArcs() == 1)
2497 && (other->getNumberOfUpArcs() == 1)) {
2515 if(nodeQueue.empty())
2529 if(!((other->getNumberOfUpArcs())
2530 && (other->getNumberOfDownArcs() > 1))) {
2539 newNode1 =
makeNode(n1->getVertexId());
2544 if((other->getNumberOfDownArcs() == 1)
2545 && (other->getNumberOfUpArcs() == 1)) {
2558 if(nodeQueue.empty())
2563 }
while(nodeQueue.size());
2572 this->
printErr(
"Incomplete contour tree! ("
2573 + std::to_string(
nodeList_.size()) +
" vs. "
2578 "MergeTree and SplitTree combined", 1.0, timer.
getElapsedTime(), 1);
2585 vector<bool> inQueue(
nodeList_.size(),
false);
2586 queue<int> nodeIdQueue;
2588 for(
int i = 0; i < (int)
nodeList_.size(); i++) {
2589 if(!
nodeList_[i].getNumberOfDownArcs()) {
2590 nodeIdQueue.push(i);
2595 while(nodeIdQueue.size()) {
2597 int const nodeId = nodeIdQueue.front();
2600 for(
int i = 0; i <
nodeList_[nodeId].getNumberOfUpArcs(); i++) {
2603 if(!inQueue[nextNodeId]) {
2604 nodeIdQueue.push(nextNodeId);
2605 inQueue[nextNodeId] =
true;
2615 if((nodeId < 0) || (nodeId >= (
int)
nodeList_.size()))
2617 if((arcId < 0) || (arcId >=
nodeList_[nodeId].getNumberOfUpArcs()))
2622 int currentNodeId = nodeId;
2626 if(
nodeList_[currentNodeId].getNumberOfUpArcs()) {
2627 if(currentNodeId != nodeId) {
2642 }
while((currentNodeId != nodeId)
2643 && (
nodeList_[currentNodeId].getNumberOfUpArcs() == 1)
2644 && (
nodeList_[currentNodeId].getNumberOfDownArcs() == 1));
2646 if(currentNodeId != nodeId) {
2648 nodeList_[currentNodeId].addDownSuperArcId(superArcId);
2651 return currentNodeId;
2656#ifndef TTK_ENABLE_KAMIKAZE
2662 const Node *merge =
nullptr, *split =
nullptr;
2673 && (((split->getNumberOfDownArcs() < 2) && (split->getNumberOfUpArcs()))
2675 || ((split->getNumberOfDownArcs() == 1)
2676 && (!split->getNumberOfUpArcs())))) {
2686 if((!split->getNumberOfDownArcs()) && (split->getNumberOfUpArcs())
2699#ifdef TTK_ENABLE_OPENMP
2700#pragma omp parallel sections
2703#ifdef TTK_ENABLE_OPENMP
2708#ifdef TTK_ENABLE_OPENMP
2713#ifdef TTK_ENABLE_OPENMP
2723#ifdef TTK_ENABLE_OPENMP
2724#pragma omp parallel sections
2727#ifdef TTK_ENABLE_OPENMP
2732#ifdef TTK_ENABLE_OPENMP
2737#ifdef TTK_ENABLE_OPENMP
2747#ifdef TTK_ENABLE_OPENMP
2748#pragma omp parallel sections
2751#ifdef TTK_ENABLE_OPENMP
2756#ifdef TTK_ENABLE_OPENMP
2761#ifdef TTK_ENABLE_OPENMP
2771 vector<pair<pair<int, int>,
double>> &pairs,
2772 vector<pair<pair<int, int>,
double>> *mergePairs,
2773 vector<pair<pair<int, int>,
double>> *splitPairs)
const {
2777 vector<pair<pair<int, int>,
double>> defaultMergePairs{};
2779 mergePairs = &defaultMergePairs;
2781 vector<pair<pair<int, int>,
double>> defaultSplitPairs{};
2783 splitPairs = &defaultSplitPairs;
2786 if(!mergePairs->size() || !splitPairs->size()) {
2787#ifdef TTK_ENABLE_OPENMP
2788#pragma omp parallel sections
2792#ifdef TTK_ENABLE_OPENMP
2796 if(!mergePairs->size())
2800#ifdef TTK_ENABLE_OPENMP
2804 if(!splitPairs->size())
2810 pairs.resize(mergePairs->size() + splitPairs->size());
2812 for(
unsigned int i = 0; i < mergePairs->size(); ++i)
2813 pairs[i] = (*mergePairs)[i];
2815 unsigned int const shift = mergePairs->size();
2816 for(
unsigned int i = 0; i < splitPairs->size(); ++i)
2817 pairs[shift + i] = (*splitPairs)[i];
2819 std::sort(pairs.begin(), pairs.end(),
_pCmp);
2825 vector<pair<double, int>> &plot,
2826 vector<pair<pair<int, int>,
double>> *mergePairs,
2827 vector<pair<pair<int, int>,
double>> *splitPairs,
2828 vector<pair<pair<int, int>,
double>> *pairs)
const {
2830 vector<pair<pair<int, int>,
double>> defaultPairs{};
2832 pairs = &defaultPairs;
2838 plot.resize(pairs->size());
2840 for(
int i = 0; i < (int)plot.size(); i++) {
2841 plot[i].first = (*pairs)[i].second;
2845 plot[i].second = pairs->size() - i;
2852 vector<pair<double, double>> &diagram,
2853 vector<pair<pair<int, int>,
double>> *mergePairs,
2854 vector<pair<pair<int, int>,
double>> *splitPairs,
2855 vector<pair<pair<int, int>,
double>> *pairs)
const {
2857 vector<pair<pair<int, int>,
double>> defaultPairs{};
2859 pairs = &defaultPairs;
2866 diagram.resize(pairs->size());
2868 for(
int i = 0; i < (int)pairs->size(); i++) {
2871 diagram[i].second = (*vertexScalars_)[(*pairs)[i].first.first];
2872 diagram[i].first = (*vertexScalars_)[(*pairs)[i].first.second];
2875 diagram[i].first = (*vertexScalars_)[(*pairs)[i].first.first];
2876 diagram[i].second = (*vertexScalars_)[(*pairs)[i].first.second];
2880 std::sort(diagram.begin(), diagram.end(),
_pPairCmp);
2887#ifdef TTK_ENABLE_OPENMP
2888#pragma omp parallel sections
2892#ifdef TTK_ENABLE_OPENMP
2897#ifdef TTK_ENABLE_OPENMP
#define ttkNotUsed(x)
Mark function/method parameters that are not used in the function body at all.
struct filtrationCtCmp filtrationCmp
struct _persistenceCmp _pCmp
struct _persistencePairCmp _pPairCmp
#define REAL_SIGNIFICANT_DIGITS
virtual SimplexId getVertexNeighborNumber(const SimplexId &vertexId) const
virtual SimplexId getNumberOfVertices() const
virtual int getVertexNeighbor(const SimplexId &vertexId, const int &localNeighborId, SimplexId &neighborId) const
int getDownNodeId() const
virtual double computeSuperArcMetric(const int &downVertexId, const int &upVertexId, const std::vector< int > &interiorNodeIds)=0
int getPersistenceDiagram(std::vector< std::pair< double, double > > &diagram, std::vector< std::pair< std::pair< int, int >, double > > *mergePairs=nullptr, std::vector< std::pair< std::pair< int, int >, double > > *splitPairs=nullptr, std::vector< std::pair< std::pair< int, int >, double > > *pairs=nullptr) const
int computeSkeleton(unsigned int arcResolution=3) override
int simplify(const double &simplificationThreshold, ContourTreeSimplificationMetric *metric=nullptr) override
int smoothSkeleton(unsigned int skeletonSmoothing) override
int getPersistencePlot(std::vector< std::pair< double, int > > &plot, std::vector< std::pair< std::pair< int, int >, double > > *mergePairs=nullptr, std::vector< std::pair< std::pair< int, int >, double > > *splitPairs=nullptr, std::vector< std::pair< std::pair< int, int >, double > > *pairs=nullptr) const
bool isNodeEligible(const Node *n) const
SubLevelSetTree mergeTree_
int finalizeSuperArc(const int &nodeId, const int &arcId)
SubLevelSetTree splitTree_
int clearSkeleton() override
int getPersistencePairs(std::vector< std::pair< std::pair< int, int >, double > > &pairs, std::vector< std::pair< std::pair< int, int >, double > > *mergePairs=nullptr, std::vector< std::pair< std::pair< int, int >, double > > *splitPairs=nullptr) const override
int printWrn(const std::string &msg, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cerr) const
void setDebugMsgPrefix(const std::string &prefix)
virtual int setDebugLevel(const int &debugLevel)
int printErr(const std::string &msg, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cerr) const
int getUpArcId(const int &neighborId) const
int getNumberOfUpArcs() const
int getUpSuperArcId(const int &neighborId) const
int getDownArcId(const int &neighborId) const
int getNumberOfDownArcs() const
int getNumberOfDownSuperArcs() const
int getNumberOfUpSuperArcs() const
void addUpArcId(const int &upArcId)
double computeSuperArcMetric(const int &downVertexId, const int &upVertexId, const std::vector< int > &interiorNodeIds) override
int clearRoot(const int &vertexId)
int exportPersistenceDiagram(const std::string &fileName="output.plot") const
bool isSosHigherThan(const int &vertexId0, const int &vertexId1) const
int getSkeletonScalars(const std::vector< double > &scalars, std::vector< std::vector< double > > &skeletonScalars) const
void setTriangulation(const AbstractTriangulation *const triangulation)
int moveRegularNode(const Node *n, const Node *oldDown, const Node *oldUp, const Node *newDown, const Node *newUp)
void setMaximumList(std::vector< int > &maximumList)
void setNumberOfVertices(const int &vertexNumber)
std::vector< Node > originalNodeList_
int exportToSvg(const std::string &fileName, const double &scaleX=1, const double &scaleY=1)
std::vector< int > * minimumList_
int clearRegularNode(const int &vertexId)
int appendRegularNode(const int &superArcId, const int &nodeId)
void setMinimumList(std::vector< int > &minimumList)
int getPersistenceDiagram(std::vector< std::pair< double, double > > &diagram, std::vector< std::pair< std::pair< int, int >, double > > *pairs=nullptr) const
const Node * getNode(const int &nodeId) const
int exportPersistenceCurve(const std::string &fileName="output.plot") const
virtual int clearSkeleton()
void setVertexScalars(const std::vector< real > *const vertexScalars)
const AbstractTriangulation * triangulation_
virtual int computeSkeleton(unsigned int arcResolution=3)
int buildSaddleList(std::vector< int > &vertexList) const
bool maintainRegularVertices_
std::vector< int > vertex2superArcNode_
std::vector< int > * vertexSoSoffsets_
void setVertexPositions(std::vector< std::vector< double > > *vertexPositions)
std::vector< Arc > arcList_
std::vector< SuperArc > superArcList_
std::vector< SuperArc > originalSuperArcList_
int getNumberOfArcs() const
const Node * getVertexNode(const int &vertexId) const
int getNumberOfNodes() const
std::vector< int > * maximumList_
std::vector< Node > nodeList_
int getNumberOfSuperArcs() const
int exportArcPosToVtk(const int &arcId, const int &pointId, std::vector< int > &vertexIds, const std::vector< float > *origin, const std::vector< float > *voxelSize, std::ofstream &o)
int makeNode(const int &vertexId)
std::vector< int > vertex2node_
const SuperArc * getSuperArc(const int &superArcId) const
std::vector< std::vector< double > > * vertexPositions_
int sample(unsigned int samplingLevel=3)
int exportNodePosToVtk(const int &nodeId, const int &pointId, std::vector< int > &vertexIds, const std::vector< float > *origin, const std::vector< float > *voxelSize, std::ofstream &o)
int makeArc(const int &nodeId0, const int &nodeId1)
virtual int getPersistencePairs(std::vector< std::pair< std::pair< int, int >, double > > &pairs, std::vector< std::pair< std::pair< int, int >, double > > *mergePairs=nullptr, std::vector< std::pair< std::pair< int, int >, double > > *splitPairs=nullptr) const
int buildExtremumList(std::vector< int > &extremumList, const bool &isSubLevelSet=true)
virtual int simplify(const double &simplificationThreshold, ContourTreeSimplificationMetric *metric=nullptr)
int openSuperArc(const int &nodeId)
int exportToVtk(const std::string &fileName, const std::vector< float > *origin=nullptr, const std::vector< float > *voxelSize=nullptr)
int getPersistencePlot(std::vector< std::pair< double, int > > &plot, std::vector< std::pair< std::pair< int, int >, double > > *persistencePairs=nullptr) const
void setVertexSoSoffsets(std::vector< int > *vertexSoSoffsets)
const Node * getNodeUpNeighbor(const Node *n, const int &neighborId) const
int exportNodeColorToVtk(const int &nodeId, std::ofstream &o)
std::vector< int > vertex2superArc_
int getVertexScalar(const int &vertexId, double &scalar)
int closeSuperArc(const int &superArcId, const int &nodeId)
bool isSosLowerThan(const int &vertexId0, const int &vertexId1) const
bool buildPlanarLayout(const double &scaleX, const double &scaleY)
const std::vector< real > * vertexScalars_
virtual int smoothSkeleton(unsigned int skeletonSmoothing)
int clearArc(const int &vertexId0, const int &vertexId1)
int getNumberOfRegularNodes() const
int getNumberOfBarycenters() const
void getSample(const int &id, std::vector< int > &sample) const
int getRegularNodeId(const int &arcNodeId) const
std::vector< std::vector< double > > barycenterList_
void smooth(const std::vector< Node > &nodeList, const std::vector< std::vector< double > > *vertexPositions, bool order=true)
std::vector< int > regularNodeList_
void sortRegularNodes(const std::vector< double > *vertexScalars, const std::vector< int > *vertexOffsets, const std::vector< Node > *nodeList, bool order=true)
int getNumberOfSamples() const
Union Find implementation for connectivity tracking.
static UnionFind * makeUnion(UnionFind *uf0, UnionFind *uf1)
T powIntTen(const int n)
Compute the nth power of ten.
int SimplexId
Identifier type for simplices of any dimension.
MyCmp(const vector< double > *vertexScalars, const vector< int > *vertexOffsets, const vector< Node > *nodeList, bool isAscendingOrder)
const vector< double > * vertexScalars_
const vector< Node > * nodeList_
const vector< int > * vertexOffsets_
bool operator()(int node1, int node2)
const vector< double > * vertexScalars_
_persistenceCmp3(const vector< double > *vertexScalars)
bool operator()(const pair< pair< int, int >, double > &p0, const pair< pair< int, int >, double > &p1)
bool operator()(const pair< pair< int, int >, double > &p0, const pair< pair< int, int >, double > &p1)
bool operator()(const pair< double, double > &p0, const pair< double, double > &p1)
bool operator()(const pair< bool, pair< double, pair< int, int > > > &v0, const pair< bool, pair< double, pair< int, int > > > &v1) const
printMsg(debug::output::BOLD+" | | | | | . \\ | | (__| | / __/| |_| / __/|__ _|"+debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, stream)