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 this->printErr("Error : wrong triangulation.");
138 return 0;
139 }
140
141 // Fill the vector of scalar/offset, cut the array in pieces if needed
142 if(getScalars() == 0) {
143#ifndef TTK_ENABLE_KAMIKAZE
144 this->printErr("Error : wrong input scalars.");
145 return 0;
146#endif
147 }
148 getOffsets();
149
150 this->printMsg("Launching on field "
151 + std::string{inputScalars_[0]->GetName()});
152
153 ttk::ftm::idNode acc_nbNodes = 0;
154
155 // Build tree
156 for(int cc = 0; cc < nbCC_; cc++) {
157 ftmTree_[cc].tree.setVertexScalars(
159 ftmTree_[cc].tree.setVertexSoSoffsets(offsets_[cc].data());
160 ftmTree_[cc].tree.setTreeType(ttk::ftm::TreeType::Contour);
161 ftmTree_[cc].tree.setSegmentation(GetWithSegmentation());
162 ftmTree_[cc].tree.setNormalizeIds(GetWithNormalize());
163
164 ttkVtkTemplateMacro(inputArray->GetDataType(),
165 triangulation_[cc]->getType(),
166 (ftmTree_[cc].tree.build<VTK_TT, TTK_TT>(
167 (TTK_TT *)triangulation_[cc]->getData())));
168
169 ftmTree_[cc].offset = acc_nbNodes;
170 acc_nbNodes += ftmTree_[cc]
171 .tree.getTree(ttk::ftm::TreeType::Contour)
172 ->getNumberOfNodes();
173 }
174
175 UpdateProgress(0.50);
176
177 // Construct output
178 if(getSkeletonNodes(outputSkeletonNodes) == 0) {
179#ifndef TTK_ENABLE_KAMIKAZE
180 this->printErr("Error : wrong properties on skeleton nodes.");
181 return 0;
182#endif
183 }
184
185 if(getSkeletonArcs(outputSkeletonArcs) == 0) {
186#ifndef TTK_ENABLE_KAMIKAZE
187 this->printErr("Error : wrong properties on skeleton arcs.");
188 return 0;
189#endif
190 }
191
192 if(GetWithSegmentation()) {
193 outputSegmentation->ShallowCopy(input);
194 if(getSegmentation(outputSegmentation) == 0) {
195#ifndef TTK_ENABLE_KAMIKAZE
196 this->printErr("Error : wrong properties on segmentation.");
197 return 0;
198#endif
199 }
200 }
201
202 UpdateProgress(1);
203
204#ifdef TTK_ENABLE_FTM_TREE_STATS_TIME
205 printCSVStats();
206#endif
207
208 return 1;
209}
210
212 // should be called after getScalars for inputScalars_ needs to be filled
213
214 offsets_.resize(nbCC_);
215 for(int cc = 0; cc < nbCC_; cc++) {
216 const auto offsets
219
220 offsets_[cc].resize(connected_components_[cc]->GetNumberOfPoints());
221
222 for(size_t i = 0; i < offsets_[cc].size(); i++) {
223 offsets_[cc][i] = offsets->GetTuple1(i);
224 }
225
226#ifndef TTK_ENABLE_KAMIKAZE
227 if(offsets_[cc].empty()) {
228 this->printMsg(
229 {"Error : wrong input offset scalar field for ", std::to_string(cc)},
231 return 0;
232 }
233#endif
234 }
235
236 return 1;
237}
238
240 inputScalars_.resize(nbCC_);
241 for(int cc = 0; cc < nbCC_; cc++) {
242 inputScalars_[cc]
243 = this->GetInputArrayToProcess(0, connected_components_[cc]);
244
245#ifndef TTK_ENABLE_KAMIKAZE
246 if(!inputScalars_[cc]) {
247 this->printMsg({"Error : input scalar ", std::to_string(cc),
248 " field pointer is null."},
250 return 0;
251 }
252#endif
253 }
254
255 return 1;
256}
257
259 triangulation_.resize(nbCC_);
260 ftmTree_ = std::vector<ttk::ftm::LocalFTM>(nbCC_);
261
262 for(int cc = 0; cc < nbCC_; cc++) {
265 if(!triangulation_[cc]) {
266 this->printErr("Error : ttkTriangulation::getTriangulation() is null.");
267 return 0;
268 }
269
270 ftmTree_[cc].tree.setDebugLevel(debugLevel_);
271 ftmTree_[cc].tree.setThreadNumber(threadNumber_);
272 ftmTree_[cc].tree.preconditionTriangulation(triangulation_[cc]);
273
274#ifndef TTK_ENABLE_KAMIKAZE
275 if(triangulation_[cc]->isEmpty()) {
276 this->printMsg({"Error : ttkTriangulation on connected component",
277 std::to_string(cc), " allocation problem."},
279 return 0;
280 }
281#endif
282 }
283 return 1;
284}
285
286// 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
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)