122 vtkInformationVector **inputVector,
123 vtkInformationVector *outputVector) {
125 const auto input = vtkDataSet::GetData(inputVector[0]);
126 auto outputSkeletonNodes = vtkUnstructuredGrid::GetData(outputVector, 0);
127 auto outputSkeletonArcs = vtkUnstructuredGrid::GetData(outputVector, 1);
128 auto outputSegmentation = vtkDataSet::GetData(outputVector, 2);
130#ifndef TTK_ENABLE_KAMIKAZE
132 this->
printErr(
"Error: input pointer is NULL.");
136 if(!input->GetNumberOfPoints()) {
137 this->
printErr(
"Error: input has no point.");
141 if(!outputSkeletonNodes || !outputSkeletonArcs || !outputSegmentation) {
142 this->
printErr(
"Error: output pointer is NULL.");
150 printWrn(
"Contour tree computation triggered.");
151 printWrn(
"Defaulting to the FTM backend.");
157 printWrn(
"The input is not a regular grid.");
158 printWrn(
"Defaulting to the FTM backend.");
164 && (input->IsA(
"vtkImageData"))) {
165 printMsg(
"Triggering ExTreeM Backend.");
166 const size_t nVertices = input->GetNumberOfPoints();
173 triangulation->preconditionVertexNeighbors();
176 auto scalarArray = this->GetInputArrayToProcess(0, inputVector);
178 this->
printErr(
"Unable to retrieve scalar array.");
183 auto orderArray = this->
GetOrderArray(input, 0, triangulation,
false);
184 auto orderArrayData = ttkUtils::GetPointer<ttk::SimplexId>(orderArray);
186 auto segmentation = vtkDataSet::GetData(outputVector, 2);
187 segmentation->ShallowCopy(input);
188 auto segmentationPD = segmentation->GetPointData();
191 std::string ascendingName = std::string(scalarArray->GetName()) +
"_"
193 std::string descendingName = std::string(scalarArray->GetName()) +
"_"
195 if(!segmentationPD->HasArray(ascendingName.data())
196 || !segmentationPD->HasArray(descendingName.data())) {
198 this->
printWrn(
"TIP: run `ttkPathCompression` first");
199 this->
printWrn(
"for improved performances :)");
201 bool doAscend =
false;
202 bool doDescend =
false;
203 if(!segmentationPD->HasArray(ascendingName.data())) {
206 ascendingManifold->SetNumberOfComponents(1);
207 ascendingManifold->SetNumberOfTuples(nVertices);
208 ascendingManifold->SetName(ascendingName.data());
209 segmentationPD->AddArray(ascendingManifold);
211 if(!segmentationPD->HasArray(descendingName.data())) {
214 descendingManifold->SetNumberOfComponents(1);
215 descendingManifold->SetNumberOfTuples(nVertices);
216 descendingManifold->SetName(descendingName.data());
217 segmentationPD->AddArray(descendingManifold);
226 ttkUtils::GetPointer<ttk::SimplexId>(
227 segmentationPD->GetArray(ascendingName.data())),
228 ttkUtils::GetPointer<ttk::SimplexId>(
229 segmentationPD->GetArray(descendingName.data())),
234 triangulation->getType(),
235 (status = subModule.
execute<T0>(
236 om, ttkUtils::GetPointer<const ttk::SimplexId>(orderArray),
237 *(T0 *)triangulation->getData())));
242 auto ascendingManifold = segmentationPD->GetArray(ascendingName.data());
243 auto descendingManifold = segmentationPD->GetArray(descendingName.data());
245 vtkNew<ttkSimplexIdTypeArray> segmentationId{};
246 segmentationId->SetNumberOfComponents(1);
247 segmentationId->SetNumberOfTuples(nVertices);
248 segmentationId->SetName(
"SegmentationId");
250 vtkNew<vtkCharArray> regionType{};
251 regionType->SetNumberOfComponents(1);
252 regionType->SetNumberOfTuples(nVertices);
253 regionType->SetName(
"RegionType");
259 std::map<ttk::SimplexId, int> cpMap{};
262 std::vector<std::pair<ttk::SimplexId, ttk::SimplexId>>
263 persistencePairsJoin{};
264 std::vector<ttk::ExTreeM::Branch> mergeTreeJoin{};
267#ifdef TTK_ENABLE_OPENMP
268#pragma omp parallel for num_threads(this->threadNumber_)
270 for(
size_t i = 0; i < nVertices; i++) {
271 orderArrayData[i] = nVertices - orderArrayData[i] - 1;
274 triangulation->getType(),
275 (status = exTreeMTree.computePairs<T0>(
276 persistencePairsJoin, cpMap, mergeTreeJoin,
277 ttkUtils::GetPointer<ttk::SimplexId>(segmentationId),
278 ttkUtils::GetPointer<char>(regionType),
279 ttkUtils::GetPointer<ttk::SimplexId>(ascendingManifold),
280 ttkUtils::GetPointer<ttk::SimplexId>(descendingManifold),
283#ifdef TTK_ENABLE_OPENMP
284#pragma omp parallel for num_threads(this->threadNumber_)
286 for(
size_t i = 0; i < nVertices; i++) {
287 orderArrayData[i] = nVertices - orderArrayData[i] - 1;
292 auto outputPoints = vtkUnstructuredGrid::GetData(outputVector, 0);
293 auto outputMergeTreeJoin = vtkUnstructuredGrid::GetData(outputVector, 1);
296 triangulation->getType(),
297 getMergeTree<T0>(outputMergeTreeJoin, mergeTreeJoin, scalarArray,
298 (T0 *)triangulation->getData()));
300 triangulation->getType(),
301 getMergeTreePoints<T0>(outputPoints, cpMap, persistencePairsJoin,
302 scalarArray, (T0 *)triangulation->getData()));
305 std::vector<std::pair<ttk::SimplexId, ttk::SimplexId>>
306 persistencePairsSplit{};
307 std::vector<ttk::ExTreeM::Branch> mergeTreeSplit{};
312 triangulation->getType(),
313 (status = exTreeMTree.computePairs<T0>(
314 persistencePairsSplit, cpMap, mergeTreeSplit,
315 ttkUtils::GetPointer<ttk::SimplexId>(segmentationId),
316 ttkUtils::GetPointer<char>(regionType),
317 ttkUtils::GetPointer<ttk::SimplexId>(descendingManifold),
318 ttkUtils::GetPointer<ttk::SimplexId>(ascendingManifold),
323 auto outputPoints = vtkUnstructuredGrid::GetData(outputVector, 0);
324 auto outputMergeTreeSplit = vtkUnstructuredGrid::GetData(outputVector, 1);
327 triangulation->getType(),
328 getMergeTree<T0>(outputMergeTreeSplit, mergeTreeSplit, scalarArray,
329 (T0 *)triangulation->getData()));
331 triangulation->getType(),
332 getMergeTreePoints<T0>(outputPoints, cpMap, persistencePairsSplit,
333 scalarArray, (T0 *)triangulation->getData()));
336 segmentationPD->AddArray(segmentationId);
337 segmentationPD->AddArray(regionType);
342 vtkDataArray *inputArray = this->GetInputArrayToProcess(0, inputVector);
347 if(input->IsA(
"vtkUnstructuredGrid")) {
352 inputWithId->ShallowCopy(input);
355 vtkNew<vtkConnectivityFilter> connectivity{};
356 connectivity->SetInputData(inputWithId);
357 connectivity->SetExtractionModeToAllRegions();
358 connectivity->ColorRegionsOn();
359 connectivity->Update();
361 nbCC_ = connectivity->GetOutput()
363 ->GetArray(
"RegionId")
372 for(
int cc = 0; cc <
nbCC_; cc++) {
373 vtkNew<vtkThreshold> threshold{};
374 threshold->SetInputConnection(connectivity->GetOutputPort());
375 threshold->SetInputArrayToProcess(
376 0, 0, 0, vtkDataObject::FIELD_ASSOCIATION_CELLS,
"RegionId");
377#if VTK_VERSION_NUMBER < VTK_VERSION_CHECK(9, 2, 0)
378 threshold->ThresholdBetween(cc, cc);
380 threshold->SetThresholdFunction(vtkThreshold::THRESHOLD_BETWEEN);
381 threshold->SetLowerThreshold(cc);
382 threshold->SetUpperThreshold(cc);
392 }
else if(input->IsA(
"vtkPolyData")) {
410#ifndef TTK_ENABLE_KAMIKAZE
411 this->
printErr(
"Error : wrong triangulation.");
418#ifndef TTK_ENABLE_KAMIKAZE
419 this->
printErr(
"Error : wrong input scalars.");
425 this->
printMsg(
"Launching on field "
431 for(
int cc = 0; cc <
nbCC_; cc++) {
441 (
ftmTree_[cc].tree.build<VTK_TT, TTK_TT>(
449 UpdateProgress(0.50);
453#ifndef TTK_ENABLE_KAMIKAZE
454 this->
printErr(
"Error : wrong properties on skeleton nodes.");
460#ifndef TTK_ENABLE_KAMIKAZE
461 this->
printErr(
"Error : wrong properties on skeleton arcs.");
467 outputSegmentation->ShallowCopy(input);
469#ifndef TTK_ENABLE_KAMIKAZE
470 this->
printErr(
"Error : wrong properties on segmentation.");
478#ifdef TTK_ENABLE_FTM_TREE_STATS_TIME