TTK
Loading...
Searching...
No Matches
CTA_contourtree.cpp
Go to the documentation of this file.
1#include <CTA_contourtree.h>
2#include <algorithm>
3#include <cfloat>
4#include <cmath>
5
7
9 int *regionSizes,
10 int *segmentationIds,
11 long long *topology,
12 size_t nVertices,
13 size_t nEdges,
14 std::vector<std::vector<int>> regions) {
15
16 nodes = std::vector<std::shared_ptr<ttk::cta::CTNode>>();
17 arcs = std::vector<std::shared_ptr<ttk::cta::CTEdge>>();
18
19 float minVal = FLT_MAX;
20 float maxVal = -FLT_MAX;
21
22 for(size_t i = 0; i < nVertices; i++) {
23 auto node = std::make_shared<ttk::cta::CTNode>();
24 node->scalarValue = scalars[i];
25 node->edgeList = std::vector<int>();
26 node->branchID = -1;
27 nodes.push_back(node);
28 if(node->scalarValue > maxVal)
29 maxVal = node->scalarValue;
30 if(node->scalarValue < minVal)
31 minVal = node->scalarValue;
32 }
33 int j = 0;
34 for(size_t i = 0; i < nEdges; i++) {
35 auto edge = std::make_shared<ttk::cta::CTEdge>();
36 edge->area = regionSizes[i];
37 edge->segId = segmentationIds[i];
38 if(!regions.empty())
39 edge->region = regions[segmentationIds[i]];
40 std::sort(edge->region.begin(), edge->region.end());
41 // if(!regions.empty()) std::cout << regionSizes[i] << " " <<
42 // regions[segmentationIds[i]].size() << std::endl;
43 edge->node1Idx = topology[j + 0];
44 nodes[topology[j + 0]]->edgeList.push_back(i);
45 edge->node2Idx = topology[j + 1];
46 nodes[topology[j + 1]]->edgeList.push_back(i);
47 edge->scalardistance = std::abs(nodes[edge->node1Idx]->scalarValue
48 - nodes[edge->node2Idx]->scalarValue);
49 edge->volume = edge->area * edge->scalardistance;
50 arcs.push_back(edge);
51 j += 2;
52 }
53
54 for(const std::shared_ptr<ttk::cta::CTNode> &node : nodes) {
55 if(node->edgeList.size() == 0)
56 std::cout << "wtf?\n" << std::flush;
57 if(node->edgeList.size() > 1)
58 node->type = saddleNode;
59 else {
60 const std::shared_ptr<ttk::cta::CTEdge> edge = arcs[node->edgeList[0]];
61 const std::shared_ptr<ttk::cta::CTNode> neighbor
62 = nodes[edge->node1Idx] == node ? nodes[edge->node2Idx]
63 : nodes[edge->node1Idx];
64 if(neighbor->scalarValue > node->scalarValue)
65 node->type = minNode;
66 else
67 node->type = maxNode;
68 }
69 }
70
71 binary = true;
72 for(const std::shared_ptr<ttk::cta::CTNode> &node : nodes) {
73 if(node->edgeList.size() > 3)
74 binary = false;
75 }
76}
77
79
80std::shared_ptr<ttk::cta::Tree> ContourTree::computeRootedTree(
81 const std::shared_ptr<ttk::cta::CTNode> &node,
82 const std::shared_ptr<ttk::cta::CTEdge> &parent,
83 int &id) {
84
85 // initialize tree
86 auto t = std::make_shared<Tree>();
87
88 // set id and increment for later calls
89 t->id = id;
90 id++;
91
92 // set type/label
93 t->type = node->type;
94
95 // set height and size to 0/1. For inner nodes this will be updated while
96 // traversing the children
97 t->size = 1;
98 t->height = 0;
99
100 // compute number of children (depends on whether current node is the root or
101 // not)
102 if(parent == nullptr)
103 t->children = std::vector<std::shared_ptr<Tree>>(node->edgeList.size());
104 else
105 t->children = std::vector<std::shared_ptr<Tree>>(node->edgeList.size() - 1);
106
107 bool parentVisited = false;
108
109 // add neighbors to children
110 for(size_t i = 0; i < node->edgeList.size(); i++) {
111
112 const std::shared_ptr<ttk::cta::CTEdge> edge = arcs[node->edgeList[i]];
113 if(edge == parent) {
114 parentVisited = true;
115 continue;
116 }
117
118 const std::shared_ptr<ttk::cta::CTNode> child
119 = nodes[edge->node1Idx] == node ? nodes[edge->node2Idx]
120 : nodes[edge->node1Idx];
121
122 const std::shared_ptr<Tree> childTree = computeRootedTree(child, edge, id);
123
124 t->children[i - (parentVisited ? 1 : 0)] = childTree;
125
126 t->size += childTree->size;
127
128 if(childTree->height + 1 > t->height)
129 t->height = childTree->height + 1;
130 }
131
132 // get Persistence of parent edge and compute volume
133 if(parent == nullptr) {
134 t->scalardistanceParent = 0.0001;
135 t->volume = 0.0001;
136 } else {
137 t->scalardistanceParent = parent->scalardistance;
138 t->volume = t->scalardistanceParent * parent->area;
139 }
140
141 return t;
142}
143
144std::shared_ptr<ttk::cta::BinaryTree> ContourTree::computeRootedTree_binary(
145 const std::shared_ptr<ttk::cta::CTNode> &node,
146 const std::shared_ptr<ttk::cta::CTEdge> &parent,
147 int &id) {
148
149 // initialize tree
150 auto t = std::make_shared<BinaryTree>();
151
152 // set id and increment for later calls
153 t->id = id;
154 id++;
155
156 // set type/label
157 t->type = node->type;
158 std::shared_ptr<ttk::cta::CTEdge> edge = arcs[node->edgeList[0]];
159 const int nodeIdx
160 = nodes[edge->node1Idx] == node ? edge->node1Idx : edge->node2Idx;
161 t->nodeRefs = std::vector<std::pair<int, int>>();
162 t->nodeRefs.emplace_back(-1, nodeIdx);
163 t->arcRefs = std::vector<std::pair<int, int>>();
164 // if(parent != nullptr)
165 // t->arcRefs.push_back(std::make_pair(-1,parent->segId));
166 if(parent != nullptr) {
167 const int arcRef = arcs[node->edgeList[0]] == parent ? node->edgeList[0]
168 : arcs[node->edgeList[1]] == parent ? node->edgeList[1]
169 : node->edgeList[2];
170 t->arcRefs.emplace_back(-1, arcRef);
171 }
172
173 // set height and size to 0/1. For inner nodes this will be updated while
174 // traversing the children
175 t->size = 1;
176 t->height = 0;
177
178 // children at first into vector
179 std::vector<std::shared_ptr<BinaryTree>> children;
180
181 // add neighbors to children
182 for(size_t i = 0; i < node->edgeList.size(); i++) {
183
184 edge = arcs[node->edgeList[i]];
185
186 if(edge != parent) {
187
188 const std::shared_ptr<ttk::cta::CTNode> child
189 = nodes[edge->node1Idx] == node ? nodes[edge->node2Idx]
190 : nodes[edge->node1Idx];
191
192 const std::shared_ptr<BinaryTree> childTree
193 = computeRootedTree_binary(child, edge, id);
194
195 children.push_back(childTree);
196
197 t->size += childTree->size;
198
199 if(childTree->height + 1 > t->height)
200 t->height = childTree->height + 1;
201 }
202 }
203
204 // children from vector to binary tree
205 t->child1 = children.size() > 0 ? children[0] : nullptr;
206 t->child2 = children.size() > 1 ? children[1] : nullptr;
207
208 t->freq = 1;
209
210 t->scalarValue = node->scalarValue;
211
212 // get Persistence of parent edge and compute volume
213 if(parent == nullptr) {
214 t->scalardistanceParent = 10000;
215 t->area = 10000;
216 t->volume = 10000;
217 t->region = std::vector<int>(1, -1);
218 } else {
219 t->scalardistanceParent = parent->scalardistance;
220 t->area = parent->area;
221 t->volume = t->scalardistanceParent * parent->area;
222 t->region = parent->region;
223 }
224
225 return t;
226}
227
228std::shared_ptr<ttk::cta::BinaryTree> ContourTree::rootAtMax() {
229
230 // get global maximum node to build rooted tree from there
231 float maxVal = -FLT_MAX;
232 std::shared_ptr<ttk::cta::CTNode> globalMax = nullptr;
233
234 for(const std::shared_ptr<ttk::cta::CTNode> &node : nodes) {
235 if(node->scalarValue > maxVal) {
236 globalMax = node;
237 maxVal = node->scalarValue;
238 }
239 }
240
241 int id = 1;
242
243 return computeRootedTree_binary(globalMax, nullptr, id);
244}
245
246std::shared_ptr<ttk::cta::BinaryTree>
247 ContourTree::rootAtNode(const std::shared_ptr<ttk::cta::CTNode> &root) {
248
249 int id = 1;
250
251 // rootedTree = computeRootedTree(root,-1, id);
252 return computeRootedTree_binary(root, nullptr, id);
253}
254
256 return binary;
257}
258
260
261 // find global minimum
262 int minIdx = 0;
263 for(size_t i = 1; i < nodes.size(); i++) {
264 if(nodes[minIdx]->scalarValue > nodes[i]->scalarValue)
265 minIdx = i;
266 }
267
268 // find path to global max
269 const int nextIdx = arcs[nodes[minIdx]->edgeList[0]]->node1Idx == minIdx
270 ? arcs[nodes[minIdx]->edgeList[0]]->node2Idx
271 : arcs[nodes[minIdx]->edgeList[0]]->node1Idx;
272 std::vector<int> maxPath_ = pathToMax(nextIdx, minIdx).second;
273 std::vector<int> maxPath;
274 maxPath.push_back(minIdx);
275 maxPath.insert(maxPath.end(), maxPath_.begin(), maxPath_.end());
276
277 int currID = 0;
278 nodes[minIdx]->branchID = 0;
279 std::stack<std::vector<int>> q;
280 q.push(maxPath);
281
282 while(!q.empty()) {
283
284 std::vector<int> path = q.top();
285 q.pop();
286
287 for(size_t i = 1; i < path.size() - 1; i++) {
288
289 const int idx = path[i];
290
291 for(const int cE : nodes[idx]->edgeList) {
292
293 const int cIdx
294 = arcs[cE]->node1Idx == idx ? arcs[cE]->node2Idx : arcs[cE]->node1Idx;
295 if(cIdx == path[i - 1])
296 continue;
297 if(cIdx == path[i + 1])
298 continue;
299
300 if(nodes[cIdx]->scalarValue > nodes[idx]->scalarValue) {
301 std::vector<int> newPath_ = pathToMax(cIdx, idx).second;
302 std::vector<int> newPath;
303 newPath.push_back(idx);
304 newPath.insert(newPath.end(), newPath_.begin(), newPath_.end());
305 q.push(newPath);
306 } else {
307 std::vector<int> newPath_ = pathToMin(cIdx, idx).second;
308 std::vector<int> newPath;
309 newPath.push_back(idx);
310 newPath.insert(newPath.end(), newPath_.begin(), newPath_.end());
311 q.push(newPath);
312 }
313 }
314
315 nodes[idx]->branchID = currID;
316 }
317
318 // nodes[path.front()]->branchID = currID;
319 nodes[path.back()]->branchID = currID;
320 currID++;
321 }
322}
323
324std::pair<float, std::vector<int>> ContourTree::pathToMax(int root,
325 int parent) {
326
327 std::vector<int> path;
328 path.push_back(root);
329
330 if(nodes[root]->edgeList.size() == 1) {
331 return std::make_pair(nodes[root]->scalarValue, path);
332 }
333
334 std::vector<int> bestPath;
335 float bestVal = -FLT_MAX;
336
337 for(const int cE : nodes[root]->edgeList) {
338
339 const int nextIdx
340 = arcs[cE]->node1Idx == root ? arcs[cE]->node2Idx : arcs[cE]->node1Idx;
341 if(parent == nextIdx)
342 continue;
343 if(nodes[nextIdx]->scalarValue < nodes[root]->scalarValue)
344 continue;
345
346 auto p = pathToMax(nextIdx, root);
347 if(p.first > bestVal) {
348 bestVal = p.first;
349 bestPath = p.second;
350 }
351 }
352
353 path.insert(path.end(), bestPath.begin(), bestPath.end());
354
355 return std::make_pair(bestVal, path);
356}
357
358std::pair<float, std::vector<int>> ContourTree::pathToMin(int root,
359 int parent) {
360
361 std::vector<int> path;
362 path.push_back(root);
363
364 if(nodes[root]->edgeList.size() == 1) {
365 return std::make_pair(nodes[root]->scalarValue, path);
366 }
367
368 std::vector<int> bestPath;
369 float bestVal = FLT_MAX;
370
371 for(const int cE : nodes[root]->edgeList) {
372
373 const int nextIdx
374 = arcs[cE]->node1Idx == root ? arcs[cE]->node2Idx : arcs[cE]->node1Idx;
375 if(parent == nextIdx)
376 continue;
377 if(nodes[nextIdx]->scalarValue > nodes[root]->scalarValue)
378 continue;
379
380 auto p = pathToMin(nextIdx, root);
381 if(p.first < bestVal) {
382 bestVal = p.first;
383 bestPath = p.second;
384 }
385 }
386
387 path.insert(path.end(), bestPath.begin(), bestPath.end());
388
389 return std::make_pair(bestVal, path);
390}
391
392std::pair<std::vector<std::shared_ptr<ttk::cta::CTNode>>,
393 std::vector<std::shared_ptr<ttk::cta::CTEdge>>>
395 return std::make_pair(nodes, arcs);
396}
Contour Tree Data Structure for an unrooted contour tree of unbounded degree for internal use from th...
~ContourTree()
Destructor of internal contour tree class.
std::pair< std::vector< std::shared_ptr< CTNode > >, std::vector< std::shared_ptr< CTEdge > > > getGraph()
ContourTree(float *scalars, int *regionSizes, int *segmentationIds, long long *topology, size_t nVertices, size_t nEdges, std::vector< std::vector< int > > regions={})
std::shared_ptr< BinaryTree > rootAtMax()
std::shared_ptr< BinaryTree > rootAtNode(const std::shared_ptr< CTNode > &root)