TTK
Loading...
Searching...
No Matches
ttkReebGraph.cpp
Go to the documentation of this file.
1#include "ttkReebGraph.h"
2#include <ttkMacros.h>
3#include <ttkUtils.h>
4
5// only used on the cpp
6#include <vtkConnectivityFilter.h>
7#include <vtkDataObject.h>
8#include <vtkInformation.h>
9
10using namespace ttk::ftr;
11
13
15 this->setDebugMsgPrefix("FTRGraph");
16 this->SetNumberOfInputPorts(1);
17 this->SetNumberOfOutputPorts(3);
18}
19
20int ttkReebGraph::FillInputPortInformation(int port, vtkInformation *info) {
21 if(port == 0) {
22 info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataSet");
23 return 1;
24 }
25 return 0;
26}
27
28int ttkReebGraph::FillOutputPortInformation(int port, vtkInformation *info) {
29 if(port == 0 || port == 1) {
30 info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkUnstructuredGrid");
31 return 1;
32 } else if(port == 2) {
34 return 1;
35 }
36 return 0;
37}
38
40 const idSuperArc arcId,
41 vtkPoints *points,
42 vtkUnstructuredGrid *skeletonArcs,
43 ttk::ftr::ArcData &arcData) {
44 const SuperArc &arc = graph.getArc(arcId);
45 float pointCoord[3];
46 const idNode upNodeId = arc.getUpNodeId();
47 const idNode downNodeId = arc.getDownNodeId();
48
49#ifndef TTK_ENABLE_KAMIKAZE
50 if(upNodeId == nullNode || downNodeId == nullNode) {
51 this->printErr("NULL NODES IN SKELETON " + graph.printArc(arcId));
52 return 1;
53 }
54#endif
55
56 const idVertex upVertId = graph.getNode(upNodeId).getVertexIdentifier();
57 const idVertex downVertId = graph.getNode(downNodeId).getVertexIdentifier();
58
59 vtkIdType pointIds[2];
60 if(arcData.points.count(downVertId)) {
61 pointIds[0] = arcData.points[downVertId];
62 } else {
63 triangulation_->getVertexPoint(
64 downVertId, pointCoord[0], pointCoord[1], pointCoord[2]);
65 pointIds[0] = points->InsertNextPoint(pointCoord);
66 arcData.points.emplace(downVertId, pointIds[0]);
67 arcData.setPointInfo(graph, arcId, pointIds[0]);
68 }
69
70 for(const idVertex regV : arc.segmentation()) {
71
72 // for regular mask to be set by the boundary vertices correctly
73 if(regV == downVertId || regV == upVertId)
74 continue;
75
76 if(arcData.points.count(regV)) {
77 pointIds[1] = arcData.points[regV];
78 } else {
79 triangulation_->getVertexPoint(
80 regV, pointCoord[0], pointCoord[1], pointCoord[2]);
81 pointIds[1] = points->InsertNextPoint(pointCoord);
82 arcData.points.emplace(regV, pointIds[1]);
83 arcData.setPointInfo(graph, arcId, pointIds[1], true);
84 }
85 if(pointIds[0] != pointIds[1]) {
86 vtkIdType const nextCellId
87 = skeletonArcs->InsertNextCell(VTK_LINE, 2, pointIds);
88 arcData.setArcInfo(graph, arcId, nextCellId);
89 }
90 pointIds[0] = pointIds[1];
91 }
92
93 if(arcData.points.count(upVertId)) {
94 pointIds[1] = arcData.points[upVertId];
95 } else {
96 triangulation_->getVertexPoint(
97 upVertId, pointCoord[0], pointCoord[1], pointCoord[2]);
98 pointIds[1] = points->InsertNextPoint(pointCoord);
99 arcData.points.emplace(upVertId, pointIds[1]);
100 arcData.setPointInfo(graph, arcId, pointIds[1]);
101 }
102 if(pointIds[0] != pointIds[1]) {
103 vtkIdType const nextCellId
104 = skeletonArcs->InsertNextCell(VTK_LINE, 2, pointIds);
105 arcData.setArcInfo(graph, arcId, nextCellId);
106 }
107
108 return 0;
109}
110
112 const idSuperArc arcId,
113 vtkPoints *points,
114 vtkUnstructuredGrid *skeletonArcs,
115 ttk::ftr::ArcData &arcData) {
116 float pointCoord[3];
117 const idNode upNodeId = graph.getArc(arcId).getUpNodeId();
118 const idNode downNodeId = graph.getArc(arcId).getDownNodeId();
119
120#ifndef TTK_ENABLE_KAMIKAZE
121 if(upNodeId == nullNode || downNodeId == nullNode) {
122 this->printErr("NULL NODES IN SKELETON " + graph.printArc(arcId));
123 return 1;
124 }
125#endif
126
127 const idVertex upVertId = graph.getNode(upNodeId).getVertexIdentifier();
128 const idVertex downVertId = graph.getNode(downNodeId).getVertexIdentifier();
129
130 // Mesh skeleton
131 vtkIdType pointIds[2];
132 if(arcData.points.count(downVertId)) {
133 pointIds[0] = arcData.points[downVertId];
134 } else {
135 triangulation_->getVertexPoint(
136 downVertId, pointCoord[0], pointCoord[1], pointCoord[2]);
137 pointIds[0] = points->InsertNextPoint(pointCoord);
138 arcData.points.emplace(downVertId, pointIds[0]);
139 arcData.setPointInfo(graph, arcId, pointIds[0]);
140 }
141 if(arcData.points.count(upVertId)) {
142 pointIds[1] = arcData.points[upVertId];
143 } else {
144 triangulation_->getVertexPoint(
145 upVertId, pointCoord[0], pointCoord[1], pointCoord[2]);
146 pointIds[1] = points->InsertNextPoint(pointCoord);
147 arcData.points.emplace(upVertId, pointIds[1]);
148 arcData.setPointInfo(graph, arcId, pointIds[1]);
149 }
150 vtkIdType const nextCellId
151 = skeletonArcs->InsertNextCell(VTK_LINE, 2, pointIds);
152
153 // Scalar arrays
154 arcData.setArcInfo(graph, arcId, nextCellId);
155 return 0;
156}
157
159 const idSuperArc arcId,
160 vtkPoints *points,
161 vtkUnstructuredGrid *skeletonArcs,
162 ttk::ftr::ArcData &arcData) {
163 const SuperArc &arc = graph.getArc(arcId);
164 float pointCoord[3];
165 const idNode upNodeId = arc.getUpNodeId();
166 const idNode downNodeId = arc.getDownNodeId();
167
168 const double scalarMin
169 = inputScalars_->GetTuple1(graph.getNode(downNodeId).getVertexIdentifier());
170 const double scalarMax
171 = inputScalars_->GetTuple1(graph.getNode(upNodeId).getVertexIdentifier());
172 const double delta = (scalarMax - scalarMin) / (params_.samplingLvl + 1);
173
174#ifndef TTK_ENABLE_KAMIKAZE
175 if(upNodeId == nullNode || downNodeId == nullNode) {
176 this->printErr("NULL NODES IN SKELETON " + graph.printArc(arcId));
177 return 1;
178 }
179#endif
180
181 const idVertex upVertId = graph.getNode(upNodeId).getVertexIdentifier();
182 const idVertex downVertId = graph.getNode(downNodeId).getVertexIdentifier();
183
184 vtkIdType pointIds[2];
185 if(arcData.points.count(downVertId)) {
186 pointIds[0] = arcData.points[downVertId];
187 } else {
188 triangulation_->getVertexPoint(
189 downVertId, pointCoord[0], pointCoord[1], pointCoord[2]);
190 pointIds[0] = points->InsertNextPoint(pointCoord);
191 arcData.points.emplace(downVertId, pointIds[0]);
192 arcData.setPointInfo(graph, arcId, pointIds[0]);
193 }
194
195 float sum[3]{};
196 int chunk = 0;
197 double scalarLimit = scalarMin + delta;
198
199 for(const idVertex regV : arc.segmentation()) {
200
201 // for regular mask to be set by the boundary vertices correctly
202 if(regV == downVertId || regV == upVertId)
203 continue;
204
205 triangulation_->getVertexPoint(
206 regV, pointCoord[0], pointCoord[1], pointCoord[2]);
207 const double scalar = inputScalars_->GetTuple1(regV);
208 if(scalar < scalarLimit) {
209 sum[0] += pointCoord[0];
210 sum[1] += pointCoord[1];
211 sum[2] += pointCoord[2];
212 ++chunk;
213 } else {
214 if(chunk) {
215 sum[0] /= chunk;
216 sum[1] /= chunk;
217 sum[2] /= chunk;
218
219 // do not use memorized points as even if a point already exist it is
220 // from another vertex and should not be used
221 pointIds[1] = points->InsertNextPoint(sum);
222 arcData.points.emplace(regV, pointIds[1]);
223 arcData.setPointInfo(graph, arcId, pointIds[1], true);
224
225 if(pointIds[0] != pointIds[1]) {
226 vtkIdType const nextCellId
227 = skeletonArcs->InsertNextCell(VTK_LINE, 2, pointIds);
228 arcData.setArcInfo(graph, arcId, nextCellId);
229 }
230
231 pointIds[0] = pointIds[1];
232 }
233
234 // reset for next iteration
235 scalarLimit += delta;
236 sum[0] = 0;
237 sum[1] = 0;
238 sum[2] = 0;
239 chunk = 0;
240 }
241 }
242
243 if(arcData.points.count(upVertId)) {
244 pointIds[1] = arcData.points[upVertId];
245 } else {
246 triangulation_->getVertexPoint(
247 upVertId, pointCoord[0], pointCoord[1], pointCoord[2]);
248 pointIds[1] = points->InsertNextPoint(pointCoord);
249 arcData.points.emplace(upVertId, pointIds[1]);
250 arcData.setPointInfo(graph, arcId, pointIds[1]);
251 }
252 if(pointIds[0] != pointIds[1]) {
253 vtkIdType const nextCellId
254 = skeletonArcs->InsertNextCell(VTK_LINE, 2, pointIds);
255 arcData.setArcInfo(graph, arcId, nextCellId);
256 }
257
258 return 0;
259}
260
261template <typename VTK_TT, typename TTK_TT>
264 static_cast<TTK_TT *>(triangulation_->getData()));
265
266 // common parameters
267 ftrGraph_.setParams(params_);
268 ftrGraph_.setDebugLevel(this->debugLevel_);
269 // reeb graph parameters
270 ftrGraph_.setScalars(ttkUtils::GetVoidPointer(inputScalars_));
271 // TODO: SimplexId -> template to int + long long?
272 ftrGraph_.setVertexSoSoffsets(
273 static_cast<ttk::SimplexId *>(ttkUtils::GetVoidPointer(offsets_)));
274 // build
275 this->printMsg("Starting computation on field: "
276 + std::string{inputScalars_->GetName()});
277 ftrGraph_.build();
278 // get output
279 graph = std::move(ftrGraph_.extractOutputGraph());
280
281 return 0;
282}
283
284int ttkReebGraph::RequestData(vtkInformation *ttkNotUsed(request),
285 vtkInformationVector **inputVector,
286 vtkInformationVector *outputVector) {
287
288 // Input
289 mesh_ = vtkDataSet::GetData(inputVector[0]);
290
291 // Output
292 auto outputSkeletonNodes = vtkUnstructuredGrid::GetData(outputVector, 0);
293 auto outputSkeletonArcs = vtkUnstructuredGrid::GetData(outputVector, 1);
294 auto outputSegmentation = vtkDataSet::GetData(outputVector, 2);
295
296 // Skeleton
297 Graph graph;
298
299 triangulation_ = ttkAlgorithm::GetTriangulation(mesh_);
300#ifndef TTK_ENABLE_KAMIKAZE
301 if(!triangulation_) {
302 this->printErr("ttkTriangulation::getTriangulation() is null.");
303 return -1;
304 }
305 if(triangulation_->isEmpty()) {
306 this->printErr(
307 "ttkTriangulation on connected component allocation problem.");
308 return -1;
309 }
310#endif
311
312 // gives parameters to the params_ structure
313 params_.debugLevel = debugLevel_;
314 params_.threadNumber = threadNumber_;
315
316 // Scalar field related
317 inputScalars_ = this->GetInputArrayToProcess(0, inputVector);
318 if(inputScalars_ == nullptr) {
319 this->printErr("input scalar field pointer is null.");
320 return -3;
321 }
322
323 offsets_ = this->GetOrderArray(
324 mesh_, 0, triangulation_, false, 1, ForceInputOffsetScalarField);
325
326 // compute graph
327 ttkVtkTemplateMacro(inputScalars_->GetDataType(), triangulation_->getType(),
328 (dispatch<VTK_TT, TTK_TT>(graph)));
329
330 UpdateProgress(0.50);
331
332 // Construct output
333 if(getSkeletonNodes(graph, outputSkeletonNodes)) {
334#ifndef TTK_ENABLE_KAMIKAZE
335 this->printErr("wrong properties on skeleton nodes.");
336 return -7;
337#endif
338 }
339
340 if(getSkeletonArcs(graph, outputSkeletonArcs)) {
341#ifndef TTK_ENABLE_KAMIKAZE
342 this->printErr("wrong properties on skeleton arcs.");
343 return -8;
344#endif
345 }
346
347 if(GetWithSegmentation() && getSegmentation(graph, outputSegmentation)) {
348#ifndef TTK_ENABLE_KAMIKAZE
349 this->printErr("wrong properties on segmentation.");
350 return -9;
351#endif
352 }
353
354 UpdateProgress(1);
355
356 return 1;
357}
358
360 vtkDataSet *outputSegmentation) {
361 outputSegmentation->ShallowCopy(mesh_);
362
363 const idVertex numberOfVertices = mesh_->GetNumberOfPoints();
364 ttk::ftr::VertData vertData(numberOfVertices);
365
366 // TODO parallel
367 for(idVertex v = 0; v < numberOfVertices; ++v) {
368 vertData.setVertexInfo(graph, v);
369 }
370
371 vertData.addArrays(outputSegmentation, params_);
372
373 return 0;
374}
375
377 vtkUnstructuredGrid *outputSkeletonArcs) {
378 const idSuperArc nbArcs = graph.getNumberOfArcs();
379
380 idSuperArc nbFinArc = 0;
381 switch(params_.samplingLvl) {
382 case -1:
383 // loops may create more arcs
384 nbFinArc = triangulation_->getNumberOfVertices() * 1.5;
385 break;
386 case 0:
387 nbFinArc = graph.getNumberOfVisibleArcs();
388 break;
389 default:
390 nbFinArc = graph.getNumberOfVisibleArcs() * (params_.samplingLvl + 1);
391 break;
392 }
393
394 ttk::ftr::ArcData arcData(nbFinArc);
395 vtkNew<vtkUnstructuredGrid> arcs{};
396 vtkNew<vtkPoints> const points{};
397
398 for(idSuperArc arcId = 0; arcId < nbArcs; ++arcId) {
399 if(!graph.getArc(arcId).isVisible())
400 continue;
401
402 switch(params_.samplingLvl) {
403 case -1:
404 addCompleteSkeletonArc(graph, arcId, points, arcs, arcData);
405 break;
406 case 0:
407 addDirectSkeletonArc(graph, arcId, points, arcs, arcData);
408 break;
409 default:
410 addSampledSkeletonArc(graph, arcId, points, arcs, arcData);
411 break;
412 }
413 }
414
415 arcs->SetPoints(points);
416 arcData.addArrays(arcs, params_);
417 outputSkeletonArcs->ShallowCopy(arcs);
418
419 return 0;
420}
421
423 vtkUnstructuredGrid *outputSkeletonNodes) {
424 const idNode nbNodes = graph.getNumberOfNodes();
425
426 ttk::ftr::NodeData nodeData(nbNodes);
427 vtkNew<vtkUnstructuredGrid> nodes{};
428 vtkNew<vtkPoints> points{};
429
430 for(idNode nodeId = 0; nodeId < nbNodes; nodeId++) {
431 const ttk::ftr::idVertex vertId
432 = graph.getNode(nodeId).getVertexIdentifier();
433 float point[3];
434 triangulation_->getVertexPoint(vertId, point[0], point[1], point[2]);
435 points->InsertNextPoint(point);
436
437 double const scalar = inputScalars_->GetTuple1(vertId);
438 nodeData.addNode(graph, nodeId, scalar);
439 }
440
441 ttkUtils::CellVertexFromPoints(nodes, points);
442 nodeData.addArrays(nodes->GetPointData(), params_);
443
444 outputSkeletonNodes->ShallowCopy(nodes);
445
446 return 0;
447}
448
449// protected
450
451void ttkReebGraph::identify(vtkDataSet *ds) const {
452 vtkNew<vtkIntArray> identifiers{};
453 const vtkIdType nbPoints = ds->GetNumberOfPoints();
454 identifiers->SetName("VertexIdentifier");
455 identifiers->SetNumberOfComponents(1);
456 identifiers->SetNumberOfTuples(nbPoints);
457
458 for(int i = 0; i < nbPoints; i++) {
459 identifiers->SetTuple1(i, i);
460 }
461
462 ds->GetPointData()->AddArray(identifiers);
463}
#define ttkNotUsed(x)
Mark function/method parameters that are not used in the function body at all.
Definition BaseClass.h:47
static vtkInformationIntegerKey * SAME_DATA_TYPE_AS_INPUT_PORT()
ttk::Triangulation * GetTriangulation(vtkDataSet *dataSet)
vtkDataArray * GetOrderArray(vtkDataSet *const inputData, const int scalarArrayIdx, ttk::Triangulation *triangulation, const bool getGlobalOrder=false, const int orderArrayIdx=0, const bool enforceOrderArrayIdx=false)
TTK VTK-filter for the computation of Reeb Graphs.
int getSkeletonNodes(const ttk::ftr::Graph &graph, vtkUnstructuredGrid *outputSkeletonNodes)
void identify(vtkDataSet *ds) const
int addCompleteSkeletonArc(const ttk::ftr::Graph &graph, const ttk::ftr::idSuperArc arcId, vtkPoints *points, vtkUnstructuredGrid *skeletonArcs, ttk::ftr::ArcData &arcData)
int getSegmentation(const ttk::ftr::Graph &graph, vtkDataSet *outputSegmentation)
int RequestData(vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector) override
int FillInputPortInformation(int port, vtkInformation *info) override
int addSampledSkeletonArc(const ttk::ftr::Graph &graph, const ttk::ftr::idSuperArc arcId, vtkPoints *points, vtkUnstructuredGrid *skeletonArcs, ttk::ftr::ArcData &arcData)
int addDirectSkeletonArc(const ttk::ftr::Graph &graph, const ttk::ftr::idSuperArc arcId, vtkPoints *points, vtkUnstructuredGrid *skeletonArcs, ttk::ftr::ArcData &arcData)
int dispatch(ttk::ftr::Graph &graph)
int getSkeletonArcs(const ttk::ftr::Graph &graph, vtkUnstructuredGrid *outputSkeletonArcs)
int FillOutputPortInformation(int port, vtkInformation *info) override
bool GetWithSegmentation() const
static void * GetVoidPointer(vtkDataArray *array, vtkIdType start=0)
Definition ttkUtils.cpp:226
static int CellVertexFromPoints(vtkDataSet *const dataSet, vtkPoints *const points)
Definition ttkUtils.cpp:328
int debugLevel_
Definition Debug.h:379
void setDebugMsgPrefix(const std::string &prefix)
Definition Debug.h:364
int printErr(const std::string &msg, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cerr) const
Definition Debug.h:149
AbstractTriangulation * getData()
Triangulation::Type getType() const
int getVertexPoint(const SimplexId &vertexId, float &x, float &y, float &z) const override
bool isEmpty() const override
SimplexId getNumberOfVertices() const override
TTK FTRGraph processing package.
Definition FTRGraph.h:77
void setVertexSoSoffsets(SimplexId *sos)
Definition FTRGraph.h:198
void setScalars(const void *scalars)
Scalar field used to compute the Reeb Graph.
Definition FTRGraph.h:188
int setDebugLevel(const int &lvl) override
Control the verbosity of the base code.
Definition FTRGraph.h:177
Graph && extractOutputGraph()
Definition FTRGraph.h:160
void setParams(const Params &p)
Definition FTRGraph.h:182
TTK FTRGraph graph skeleton.
Definition Graph.h:38
idNode getNumberOfNodes() const
Definition Graph.h:84
idSuperArc getNumberOfArcs() const
Definition Graph.h:88
std::string printArc(const idSuperArc arcId) const
Definition Graph.cpp:54
const SuperArc & getArc(const idSuperArc id) const
Definition Graph.h:121
const Node & getNode(const idNode id) const
Definition Graph.h:113
idSuperArc getNumberOfVisibleArcs() const
Definition Graph.h:92
idVertex getVertexIdentifier() const
Definition FTRNode.h:34
TTK FTRGraph graph arc.
Definition FTRSuperArc.h:30
idNode getUpNodeId() const
Definition FTRSuperArc.h:48
idNode getDownNodeId() const
Definition FTRSuperArc.h:57
const decltype(segmentation_) & segmentation() const
bool isVisible() const
Definition FTRSuperArc.h:89
long unsigned int idSuperArc
SuperArc index in vect_superArcs_.
SimplexId idVertex
Vertex index in scalars_.
unsigned int idNode
Node index in vect_nodes_.
int SimplexId
Identifier type for simplices of any dimension.
Definition DataTypes.h:22
std::map< ttk::ftr::idVertex, vtkIdType > points
void setPointInfo(const ttk::ftr::Graph &ttkNotUsed(graph), const ttk::ftr::idSuperArc ttkNotUsed(a), const vtkIdType skeletonVert, bool r=false)
void addArrays(vtkUnstructuredGrid *arcs, ttk::ftr::Params ttkNotUsed(params))
void setArcInfo(const ttk::ftr::Graph &graph, const ttk::ftr::idSuperArc a, const vtkIdType skeletonCell)
void addNode(const ttk::ftr::Graph &graph, const ttk::ftr::idNode n, const double scalar)
void addArrays(vtkPointData *pointData, ttk::ftr::Params ttkNotUsed(params))
void setVertexInfo(const ttk::ftr::Graph &graph, const ttk::ftr::idVertex v)
void addArrays(vtkDataSet *segmentation, ttk::ftr::Params ttkNotUsed(params))
#define ttkVtkTemplateMacro(dataType, triangulationType, call)
Definition ttkMacros.h:69
vtkStandardNewMacro(ttkReebGraph)
printMsg(debug::output::BOLD+" | | | | | . \\ | | (__| | / __/| |_| / __/|__ _|"+debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, stream)