TTK
Loading...
Searching...
No Matches
ttkContourTree.cpp
Go to the documentation of this file.
1#include <ttkContourTree.h>
2#include <ttkMacros.h>
3#include <ttkUtils.h>
4
5// VTK includes
6#include <vtkConnectivityFilter.h>
7#include <vtkImageData.h>
8#include <vtkInformation.h>
9#include <vtkInformationVector.h>
10#include <vtkPolyData.h>
11#include <vtkThreshold.h>
12#include <vtkVersionMacros.h>
13
15
17 this->setDebugMsgPrefix("ContourTree");
18 SetNumberOfInputPorts(1);
19 SetNumberOfOutputPorts(3);
21}
22
23int ttkContourTree::FillInputPortInformation(int port, vtkInformation *info) {
24 if(port == 0) {
25 info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataSet");
26 return 1;
27 }
28 return 0;
29}
30
31int ttkContourTree::FillOutputPortInformation(int port, vtkInformation *info) {
32 if(port == 0 || port == 1) {
33 info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkUnstructuredGrid");
34 return 1;
35 } else if(port == 2) {
37 return 1;
38 }
39 return 0;
40}
41
42int ttkContourTree::RequestData(vtkInformation *ttkNotUsed(request),
43 vtkInformationVector **inputVector,
44 vtkInformationVector *outputVector) {
45
46 const auto input = vtkDataSet::GetData(inputVector[0]);
47 auto outputSkeletonNodes = vtkUnstructuredGrid::GetData(outputVector, 0);
48 auto outputSkeletonArcs = vtkUnstructuredGrid::GetData(outputVector, 1);
49 auto outputSegmentation = vtkDataSet::GetData(outputVector, 2);
50
51#ifndef TTK_ENABLE_KAMIKAZE
52 if(!input) {
53 this->printErr("Error: input pointer is NULL.");
54 return 0;
55 }
56
57 if(!input->GetNumberOfPoints()) {
58 this->printErr("Error: input has no point.");
59 return 0;
60 }
61
62 if(!outputSkeletonNodes || !outputSkeletonArcs || !outputSegmentation) {
63 this->printErr("Error: output pointer is NULL.");
64 return 0;
65 }
66#endif
67
68 // Arrays
69
70 vtkDataArray *inputArray = this->GetInputArrayToProcess(0, inputVector);
71 if(!inputArray)
72 return 0;
73
74 // Connected components
75 if(input->IsA("vtkUnstructuredGrid")) {
76 // This data set may have several connected components,
77 // we need to apply the FTM Tree for each one of these components
78 // We then reconstruct the global tree using an offset mechanism
80 inputWithId->ShallowCopy(input);
81 identify(inputWithId);
82
83 vtkNew<vtkConnectivityFilter> connectivity{};
84 connectivity->SetInputData(inputWithId);
85 connectivity->SetExtractionModeToAllRegions();
86 connectivity->ColorRegionsOn();
87 connectivity->Update();
88
89 nbCC_ = connectivity->GetOutput()
90 ->GetCellData()
91 ->GetArray("RegionId")
92 ->GetRange()[1]
93 + 1;
95
96 if(nbCC_ > 1) {
97 // Warning, in case of several connected components, the ids seen by
98 // the base code will not be consistent with those of the original
99 // mesh
100 for(int cc = 0; cc < nbCC_; cc++) {
101 vtkNew<vtkThreshold> threshold{};
102 threshold->SetInputConnection(connectivity->GetOutputPort());
103 threshold->SetInputArrayToProcess(
104 0, 0, 0, vtkDataObject::FIELD_ASSOCIATION_CELLS, "RegionId");
105#if VTK_VERSION_NUMBER < VTK_VERSION_CHECK(9, 2, 0)
106 threshold->ThresholdBetween(cc, cc);
107#else
108 threshold->SetThresholdFunction(vtkThreshold::THRESHOLD_BETWEEN);
109 threshold->SetLowerThreshold(cc);
110 threshold->SetUpperThreshold(cc);
111#endif
112 threshold->Update();
114 connected_components_[cc]->ShallowCopy(threshold->GetOutput());
115 }
116 } else {
117 connected_components_[0] = inputWithId;
118 }
119 } else if(input->IsA("vtkPolyData")) {
120 // NOTE: CC check should not be implemented on a per vtk module layer.
121 nbCC_ = 1;
124 connected_components_[0]->ShallowCopy(input);
126 } else {
127 nbCC_ = 1;
130 connected_components_[0]->ShallowCopy(input);
132 }
133
134 // now proceed for each triangulation obtained.
135
136 if(preconditionTriangulation() == 0) {
137#ifndef TTK_ENABLE_KAMIKAZE
138 this->printErr("Error : wrong triangulation.");
139 return 0;
140#endif
141 }
142
143 // Fill the vector of scalar/offset, cut the array in pieces if needed
144 if(getScalars() == 0) {
145#ifndef TTK_ENABLE_KAMIKAZE
146 this->printErr("Error : wrong input scalars.");
147 return 0;
148#endif
149 }
150 getOffsets();
151
152 this->printMsg("Launching on field "
153 + std::string{inputScalars_[0]->GetName()});
154
155 ttk::ftm::idNode acc_nbNodes = 0;
156
157 // Build tree
158 for(int cc = 0; cc < nbCC_; cc++) {
159 ftmTree_[cc].tree.setVertexScalars(
161 ftmTree_[cc].tree.setVertexSoSoffsets(offsets_[cc].data());
162 ftmTree_[cc].tree.setTreeType(ttk::ftm::TreeType::Contour);
163 ftmTree_[cc].tree.setSegmentation(GetWithSegmentation());
164 ftmTree_[cc].tree.setNormalizeIds(GetWithNormalize());
165
166 ttkVtkTemplateMacro(inputArray->GetDataType(),
167 triangulation_[cc]->getType(),
168 (ftmTree_[cc].tree.build<VTK_TT, TTK_TT>(
169 (TTK_TT *)triangulation_[cc]->getData())));
170
171 ftmTree_[cc].offset = acc_nbNodes;
172 acc_nbNodes += ftmTree_[cc]
173 .tree.getTree(ttk::ftm::TreeType::Contour)
174 ->getNumberOfNodes();
175 }
176
177 UpdateProgress(0.50);
178
179 // Construct output
180 if(getSkeletonNodes(outputSkeletonNodes) == 0) {
181#ifndef TTK_ENABLE_KAMIKAZE
182 this->printErr("Error : wrong properties on skeleton nodes.");
183 return 0;
184#endif
185 }
186
187 if(getSkeletonArcs(outputSkeletonArcs) == 0) {
188#ifndef TTK_ENABLE_KAMIKAZE
189 this->printErr("Error : wrong properties on skeleton arcs.");
190 return 0;
191#endif
192 }
193
194 if(GetWithSegmentation()) {
195 outputSegmentation->ShallowCopy(input);
196 if(getSegmentation(outputSegmentation) == 0) {
197#ifndef TTK_ENABLE_KAMIKAZE
198 this->printErr("Error : wrong properties on segmentation.");
199 return 0;
200#endif
201 }
202 }
203
204 UpdateProgress(1);
205
206#ifdef TTK_ENABLE_FTM_TREE_STATS_TIME
207 printCSVStats();
208#endif
209
210 return 1;
211}
212
214 // should be called after getScalars for inputScalars_ needs to be filled
215
216 offsets_.resize(nbCC_);
217 for(int cc = 0; cc < nbCC_; cc++) {
218 const auto offsets
221
222 offsets_[cc].resize(connected_components_[cc]->GetNumberOfPoints());
223
224 for(size_t i = 0; i < offsets_[cc].size(); i++) {
225 offsets_[cc][i] = offsets->GetTuple1(i);
226 }
227
228#ifndef TTK_ENABLE_KAMIKAZE
229 if(offsets_[cc].empty()) {
230 this->printMsg(
231 {"Error : wrong input offset scalar field for ", std::to_string(cc)},
233 return 0;
234 }
235#endif
236 }
237
238 return 1;
239}
240
242 inputScalars_.resize(nbCC_);
243 for(int cc = 0; cc < nbCC_; cc++) {
244 inputScalars_[cc]
245 = this->GetInputArrayToProcess(0, connected_components_[cc]);
246
247#ifndef TTK_ENABLE_KAMIKAZE
248 if(!inputScalars_[cc]) {
249 this->printMsg({"Error : input scalar ", std::to_string(cc),
250 " field pointer is null."},
252 return 0;
253 }
254#endif
255 }
256
257 return 1;
258}
259
261 triangulation_.resize(nbCC_);
262 ftmTree_ = std::vector<ttk::ftm::LocalFTM>(nbCC_);
263
264 for(int cc = 0; cc < nbCC_; cc++) {
267#ifndef TTK_ENABLE_KAMIKAZE
268 if(!triangulation_[cc]) {
269 this->printErr("Error : ttkTriangulation::getTriangulation() is null.");
270 return 0;
271 }
272#endif
273
274 ftmTree_[cc].tree.setDebugLevel(debugLevel_);
275 ftmTree_[cc].tree.setThreadNumber(threadNumber_);
276 ftmTree_[cc].tree.preconditionTriangulation(triangulation_[cc]);
277
278#ifndef TTK_ENABLE_KAMIKAZE
279 if(triangulation_[cc]->isEmpty()) {
280 this->printMsg({"Error : ttkTriangulation on connected component",
281 std::to_string(cc), " allocation problem."},
283 return 0;
284 }
285#endif
286 }
287 return 1;
288}
289
290// protected
#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 filter for the computation of contour trees.
bool GetWithSegmentation() const
int preconditionTriangulation()
int FillInputPortInformation(int port, vtkInformation *info) override
int RequestData(vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector) override
bool GetWithNormalize() const
int FillOutputPortInformation(int port, vtkInformation *info) override
std::vector< ttk::Triangulation * > triangulation_
std::vector< vtkDataArray * > inputScalars_
int getSegmentation(vtkDataSet *outputSegmentation)
ttk::ftm::Params params_
int getSkeletonNodes(vtkUnstructuredGrid *outputSkeletonNodes)
std::vector< std::vector< ttk::SimplexId > > offsets_
int getSkeletonArcs(vtkUnstructuredGrid *outputSkeletonArcs)
void identify(vtkDataSet *ds) const
std::vector< vtkSmartPointer< vtkDataSet > > connected_components_
std::vector< ttk::ftm::LocalFTM > ftmTree_
static void * GetVoidPointer(vtkDataArray *array, vtkIdType start=0)
Definition ttkUtils.cpp:226
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
std::string to_string(__int128)
Definition ripserpy.cpp:99
unsigned int idNode
Node index in vect_nodes_.
vtkStandardNewMacro(ttkContourTree)
#define ttkVtkTemplateMacro(dataType, triangulationType, call)
Definition ttkMacros.h:69
printMsg(debug::output::BOLD+" | | | | | . \\ | | (__| | / __/| |_| / __/|__ _|"+debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, stream)