TTK
Loading...
Searching...
No Matches
ttkTopologicalSkeleton.cpp
Go to the documentation of this file.
1#include <ttkMacros.h>
3#include <ttkUtils.h>
4
5#include <vtkCellData.h>
6#include <vtkDataArray.h>
7#include <vtkDataObject.h>
8#include <vtkDataSet.h>
9#include <vtkDoubleArray.h>
10#include <vtkFloatArray.h>
11#include <vtkIdTypeArray.h>
12#include <vtkInformation.h>
13#include <vtkNew.h>
14#include <vtkPointData.h>
15#include <vtkPolyData.h>
16#include <vtkSignedCharArray.h>
17#include <vtkUnsignedCharArray.h>
18
20
22 this->setDebugMsgPrefix("TopologicalSkeleton");
23 SetNumberOfInputPorts(1);
24 SetNumberOfOutputPorts(4);
25}
26
28 vtkInformation *info) {
29 if(port == 0) {
30 info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataSet");
31 return 1;
32 }
33 return 0;
34}
35
37 vtkInformation *info) {
38 if(port == 0 || port == 1 || port == 2) {
39 info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkPolyData");
40 return 1;
41 } else if(port == 3) {
43 return 1;
44 }
45 return 0;
46}
47
48template <typename vtkArrayType, typename vectorType>
49void setArray(vtkArrayType &vtkArray, vectorType &vector) {
50 ttkUtils::SetVoidArray(vtkArray, vector.data(), vector.size(), 1);
51}
52
53template <typename scalarType, typename triangulationType>
54int ttkTopologicalSkeleton::dispatch(vtkDataArray *const inputVectors,
55 vtkPolyData *const outputCriticalPoints,
56 vtkPolyData *const outputSeparatrices1,
57 vtkPolyData *const outputSeparatrices2,
58 const triangulationType &triangulation) {
59
60 const int dimensionality = triangulation.getDimensionality();
61 const auto vectors = ttkUtils::GetPointer<scalarType>(inputVectors);
62
63 const int ret = this->execute(criticalPoints_, separatrices1_, separatrices2_,
64 segmentations_, vectors,
65 inputVectors->GetMTime(), triangulation);
66
67#ifndef TTK_ENABLE_KAMIKAZE
68 if(ret != 0) {
69 this->printErr("TopologicalSkeleton.execute() error");
70 return -1;
71 }
72#endif
73
74 // critical points
75 {
76 vtkNew<vtkPoints> points{};
77 vtkNew<vtkSignedCharArray> cellDimensions{};
78 vtkNew<ttkSimplexIdTypeArray> cellIds{};
79 vtkNew<vtkSignedCharArray> isOnBoundary{};
80 vtkNew<ttkSimplexIdTypeArray> PLVertexIdentifiers{};
81 vtkNew<ttkSimplexIdTypeArray> manifoldSizeScalars{};
82 const auto nPoints = criticalPoints_.points_.size();
83
84#ifndef TTK_ENABLE_KAMIKAZE
85 if(!points || !cellDimensions || !cellIds || !isOnBoundary
86 || !PLVertexIdentifiers || !manifoldSizeScalars) {
87 this->printErr("Critical points vtkDataArray allocation problem.");
88 return -1;
89 }
90#endif
91
92 points->SetNumberOfPoints(nPoints);
93
94 cellDimensions->SetNumberOfComponents(1);
95 cellDimensions->SetName("CellDimension");
96 setArray(cellDimensions, criticalPoints_.cellDimensions_);
97
98 cellIds->SetNumberOfComponents(1);
99 cellIds->SetName("CellId");
100 setArray(cellIds, criticalPoints_.cellIds_);
101
102#ifdef TTK_ENABLE_OPENMP
103#pragma omp parallel for num_threads(this->threadNumber_)
104#endif // TTK_ENABLE_OPENMP
105 for(size_t i = 0; i < nPoints; ++i) {
106 points->SetPoint(i, criticalPoints_.points_[i].data());
107 }
108
109 isOnBoundary->SetNumberOfComponents(1);
110 isOnBoundary->SetName("IsOnBoundary");
111 setArray(isOnBoundary, criticalPoints_.isOnBoundary_);
112
113 PLVertexIdentifiers->SetNumberOfComponents(1);
114 PLVertexIdentifiers->SetName(ttk::VertexScalarFieldName);
115 setArray(PLVertexIdentifiers, criticalPoints_.PLVertexIdentifiers_);
116
117 manifoldSizeScalars->SetNumberOfComponents(1);
118 manifoldSizeScalars->SetName("ManifoldSize");
120 criticalPoints_.manifoldSize_.resize(nPoints);
121 std::fill(criticalPoints_.manifoldSize_.begin(),
122 criticalPoints_.manifoldSize_.end(), -1);
123 }
124 setArray(manifoldSizeScalars, criticalPoints_.manifoldSize_);
125
126 ttkUtils::CellVertexFromPoints(outputCriticalPoints, points);
127
128 auto pointData = outputCriticalPoints->GetPointData();
129#ifndef TTK_ENABLE_KAMIKAZE
130 if(!pointData) {
131 this->printErr("outputCriticalPoints has no point data.");
132 return -1;
133 }
134#endif
135
136 pointData->SetScalars(cellDimensions);
137 pointData->AddArray(cellIds);
138 pointData->AddArray(isOnBoundary);
139 pointData->AddArray(PLVertexIdentifiers);
140 pointData->AddArray(manifoldSizeScalars);
141 }
142
143 // 1-separatrices
147
148 vtkNew<vtkFloatArray> pointsCoords{};
149 vtkNew<vtkSignedCharArray> smoothingMask{};
150 vtkNew<vtkSignedCharArray> cellDimensions{};
151 vtkNew<ttkSimplexIdTypeArray> cellIds{};
152 vtkNew<ttkSimplexIdTypeArray> sourceIds{};
153 vtkNew<ttkSimplexIdTypeArray> destinationIds{};
154 vtkNew<ttkSimplexIdTypeArray> separatrixIds{};
155 vtkNew<vtkSignedCharArray> separatrixTypes{};
156 vtkNew<vtkSignedCharArray> isOnBoundary{};
157 vtkNew<vtkSignedCharArray> isOrbit{};
158
159#ifndef TTK_ENABLE_KAMIKAZE
160 if(!pointsCoords || !smoothingMask || !cellDimensions || !cellIds
161 || !sourceIds || !destinationIds || !separatrixIds || !separatrixTypes
162 || !isOnBoundary || !isOrbit) {
163 this->printErr("1-separatrices vtkDataArray allocation problem.");
164 return -1;
165 }
166#endif
167
168 pointsCoords->SetNumberOfComponents(3);
169 setArray(pointsCoords, separatrices1_.pt.points_);
170
171 smoothingMask->SetNumberOfComponents(1);
172 smoothingMask->SetName(ttk::MaskScalarFieldName);
173 setArray(smoothingMask, separatrices1_.pt.smoothingMask_);
174
175 cellDimensions->SetNumberOfComponents(1);
176 cellDimensions->SetName("CellDimension");
177 setArray(cellDimensions, separatrices1_.pt.cellDimensions_);
178
179 cellIds->SetNumberOfComponents(1);
180 cellIds->SetName("CellId");
181 setArray(cellIds, separatrices1_.pt.cellIds_);
182
183 sourceIds->SetNumberOfComponents(1);
184 sourceIds->SetName("SourceId");
185 setArray(sourceIds, separatrices1_.cl.sourceIds_);
186
187 destinationIds->SetNumberOfComponents(1);
188 destinationIds->SetName("DestinationId");
189 setArray(destinationIds, separatrices1_.cl.destinationIds_);
190
191 separatrixIds->SetNumberOfComponents(1);
192 separatrixIds->SetName("SeparatrixId");
193 setArray(separatrixIds, separatrices1_.cl.separatrixIds_);
194
195 separatrixTypes->SetNumberOfComponents(1);
196 separatrixTypes->SetName("SeparatrixType");
197 setArray(separatrixTypes, separatrices1_.cl.separatrixTypes_);
198
199 isOnBoundary->SetNumberOfComponents(1);
200 isOnBoundary->SetName("NumberOfCriticalPointsOnBoundary");
201 setArray(isOnBoundary, separatrices1_.cl.isOnBoundary_);
202
203 isOrbit->SetNumberOfComponents(1);
204 isOrbit->SetName("IsAnOrbit");
205 setArray(isOrbit, separatrices1_.cl.isOrbit_);
206
207 vtkNew<ttkSimplexIdTypeArray> offsets{}, connectivity{};
208 offsets->SetNumberOfComponents(1);
209 offsets->SetNumberOfTuples(separatrices1_.cl.numberOfCells_ + 1);
210 connectivity->SetNumberOfComponents(1);
211 setArray(connectivity, separatrices1_.cl.connectivity_);
212
213#ifdef TTK_ENABLE_OPENMP
214#pragma omp parallel for num_threads(this->threadNumber_)
215#endif // TTK_ENABLE_OPENMP
216 for(SimplexId i = 0; i < separatrices1_.cl.numberOfCells_ + 1; ++i) {
217 offsets->SetTuple1(i, 2 * i);
218 }
219
220 vtkNew<vtkPoints> points{};
221 points->SetData(pointsCoords);
222 outputSeparatrices1->SetPoints(points);
223 vtkNew<vtkCellArray> cells{};
224#ifndef TTK_ENABLE_64BIT_IDS
225 cells->Use32BitStorage();
226#endif // TTK_ENABLE_64BIT_IDS
227 cells->SetData(offsets, connectivity);
228 outputSeparatrices1->SetLines(cells);
229
230 auto pointData = outputSeparatrices1->GetPointData();
231 auto cellData = outputSeparatrices1->GetCellData();
232
233#ifndef TTK_ENABLE_KAMIKAZE
234 if(!pointData || !cellData) {
235 this->printErr("outputSeparatrices1 has no point or no cell data.");
236 return -1;
237 }
238#endif
239
240 pointData->AddArray(smoothingMask);
241 pointData->AddArray(cellDimensions);
242 pointData->AddArray(cellIds);
243
244 cellData->AddArray(sourceIds);
245 cellData->AddArray(destinationIds);
246 cellData->AddArray(separatrixIds);
247 cellData->SetScalars(separatrixTypes);
248 cellData->AddArray(isOnBoundary);
249 cellData->AddArray(isOrbit);
250 }
251
252 // 2-separatrices
253 if(dimensionality == 3
255
256 vtkNew<vtkFloatArray> pointsCoords{};
257 vtkNew<ttkSimplexIdTypeArray> sourceIds{};
258 vtkNew<ttkSimplexIdTypeArray> separatrixIds{};
259 vtkNew<vtkSignedCharArray> separatrixTypes{};
260 vtkNew<vtkSignedCharArray> isOnBoundary{};
261
262#ifndef TTK_ENABLE_KAMIKAZE
263 if(!pointsCoords || !sourceIds || !separatrixIds || !separatrixTypes
264 || !isOnBoundary) {
265 this->printErr("2-separatrices vtkDataArray allocation problem.");
266 return -1;
267 }
268#endif
269
270 pointsCoords->SetNumberOfComponents(3);
271 setArray(pointsCoords, separatrices2_.pt.points_);
272
273 sourceIds->SetNumberOfComponents(1);
274 sourceIds->SetName("SourceId");
275 setArray(sourceIds, separatrices2_.cl.sourceIds_);
276
277 separatrixIds->SetNumberOfComponents(1);
278 separatrixIds->SetName("SeparatrixId");
279 setArray(separatrixIds, separatrices2_.cl.separatrixIds_);
280
281 separatrixTypes->SetNumberOfComponents(1);
282 separatrixTypes->SetName("SeparatrixType");
283 setArray(separatrixTypes, separatrices2_.cl.separatrixTypes_);
284
285 isOnBoundary->SetNumberOfComponents(1);
286 isOnBoundary->SetName("NumberOfCriticalPointsOnBoundary");
287 setArray(isOnBoundary, separatrices2_.cl.isOnBoundary_);
288
289 vtkNew<ttkSimplexIdTypeArray> offsets{}, connectivity{};
290 offsets->SetNumberOfComponents(1);
291 setArray(offsets, separatrices2_.cl.offsets_);
292 connectivity->SetNumberOfComponents(1);
293 setArray(connectivity, separatrices2_.cl.connectivity_);
294
295 vtkNew<vtkPoints> points{};
296 points->SetData(pointsCoords);
297 outputSeparatrices2->SetPoints(points);
298 vtkNew<vtkCellArray> cells{};
299#ifndef TTK_ENABLE_64BIT_IDS
300 cells->Use32BitStorage();
301#endif // TTK_ENABLE_64BIT_IDS
302 cells->SetData(offsets, connectivity);
303 outputSeparatrices2->SetPolys(cells);
304
305 auto cellData = outputSeparatrices2->GetCellData();
306#ifndef TTK_ENABLE_KAMIKAZE
307 if(!cellData) {
308 this->printErr("outputSeparatrices2 has no cell data.");
309 return -1;
310 }
311#endif
312
313 cellData->AddArray(sourceIds);
314 cellData->AddArray(separatrixIds);
315 cellData->AddArray(separatrixTypes);
316 cellData->AddArray(isOnBoundary);
317 }
318
319 return ret;
320}
321
323 vtkInformationVector **inputVector,
324 vtkInformationVector *outputVector) {
325
326 const auto input = vtkDataSet::GetData(inputVector[0]);
327 auto outputCriticalPoints = vtkPolyData::GetData(outputVector, 0);
328 auto outputSeparatrices1 = vtkPolyData::GetData(outputVector, 1);
329 auto outputSeparatrices2 = vtkPolyData::GetData(outputVector, 2);
330 auto outputMorseComplexes = vtkDataSet::GetData(outputVector, 3);
331
332#ifndef TTK_ENABLE_KAMIKAZE
333 if(!input) {
334 this->printErr("Input pointer is NULL.");
335 return -1;
336 }
337 if(input->GetNumberOfPoints() == 0) {
338 this->printErr("Input has no point.");
339 return -1;
340 }
341 if(!outputCriticalPoints or !outputSeparatrices1 or !outputSeparatrices2
342 or !outputMorseComplexes) {
343 this->printErr("Output pointers are NULL.");
344 return -1;
345 }
346#endif
347
348 const auto triangulation = ttkAlgorithm::GetTriangulation(input);
349 if(triangulation == nullptr) {
350 this->printErr("Triangulation is null");
351 return 0;
352 }
353 this->preconditionTriangulation(triangulation);
354
355 const auto inputValues = this->GetInputArrayToProcess(0, inputVector);
356
357#ifndef TTK_ENABLE_KAMIKAZE
358 if(inputValues == nullptr) {
359 this->printErr("wrong vectors.");
360 return -1;
361 }
362#endif
363
364 this->printMsg("Launching computation on field `"
365 + std::string(inputValues->GetName()) + "'...");
366
367 // morse complexes
368 const SimplexId numberOfVertices = triangulation->getNumberOfVertices();
369#ifndef TTK_ENABLE_KAMIKAZE
370 if(!numberOfVertices) {
371 this->printErr("Input has no vertices.");
372 return -1;
373 }
374#endif
375
376 vtkNew<ttkSimplexIdTypeArray> ascendingManifold{};
377 vtkNew<ttkSimplexIdTypeArray> descendingManifold{};
378 vtkNew<ttkSimplexIdTypeArray> morseSmaleManifold{};
379#ifndef TTK_ENABLE_KAMIKAZE
380 if(!ascendingManifold || !descendingManifold || !morseSmaleManifold) {
381 this->printErr("Manifold vtkDataArray allocation problem.");
382 return -1;
383 }
384#endif
385 ascendingManifold->SetNumberOfComponents(1);
386 ascendingManifold->SetNumberOfTuples(numberOfVertices);
387 ascendingManifold->SetName("AscendingManifold");
388
389 descendingManifold->SetNumberOfComponents(1);
390 descendingManifold->SetNumberOfTuples(numberOfVertices);
391 descendingManifold->SetName("DescendingManifold");
392
393 morseSmaleManifold->SetNumberOfComponents(1);
394 morseSmaleManifold->SetNumberOfTuples(numberOfVertices);
395 morseSmaleManifold->SetName("IntersectingManifold");
396
397 this->segmentations_ = {ttkUtils::GetPointer<SimplexId>(ascendingManifold),
398 ttkUtils::GetPointer<SimplexId>(descendingManifold),
399 ttkUtils::GetPointer<SimplexId>(morseSmaleManifold)};
400
404
405 int ret{};
406
408 inputValues->GetDataType(), triangulation->getType(),
410 inputValues, outputCriticalPoints, outputSeparatrices1,
411 outputSeparatrices2, *static_cast<TTK_TT *>(triangulation->getData()))));
412
413 if(ret != 0) {
414 return -1;
415 }
416
417 outputMorseComplexes->ShallowCopy(input);
418 // morse complexes
420 vtkPointData *pointData = outputMorseComplexes->GetPointData();
421#ifndef TTK_ENABLE_KAMIKAZE
422 if(!pointData) {
423 this->printErr("outputMorseComplexes has no point data.");
424 return -1;
425 }
426#endif
427
428 if(ComputeDescendingSegmentation)
429 pointData->AddArray(descendingManifold);
431 pointData->AddArray(ascendingManifold);
434 pointData->AddArray(morseSmaleManifold);
435 }
436
437 return !ret;
438}
#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)
TTK VTK-filter that wraps the topologicalSkeleton processing package.
int dispatch(vtkDataArray *const inputVectors, vtkPolyData *const outputCriticalPoints, vtkPolyData *const outputSeparatrices1, vtkPolyData *const outputSeparatrices2, const triangulationType &triangulation)
int RequestData(vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector) override
int FillOutputPortInformation(int port, vtkInformation *info) override
int FillInputPortInformation(int port, vtkInformation *info) override
static int CellVertexFromPoints(vtkDataSet *const dataSet, vtkPoints *const points)
Definition ttkUtils.cpp:329
static DT * GetPointer(vtkDataArray *array, vtkIdType start=0)
Definition ttkUtils.h:59
static void SetVoidArray(vtkDataArray *array, void *data, vtkIdType size, int save)
Definition ttkUtils.cpp:280
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
void setRunSimplification(const bool state)
void setFullOrbits(const bool fullOrbits)
void preconditionTriangulation(AbstractTriangulation *const data)
int execute(OutputCriticalPoints &outCP, Output1Separatrices &outSeps1, Output2Separatrices &outSeps2, OutputManifold &outManifold, const dataType *const vectors, const size_t vectorsMTime, const triangulationType &triangulation)
void setSimplificationThreshold(const double threshold)
int SimplexId
Identifier type for simplices of any dimension.
Definition DataTypes.h:22
const char VertexScalarFieldName[]
default name for vertex scalar field
Definition DataTypes.h:35
const char MaskScalarFieldName[]
default name for mask scalar field
Definition DataTypes.h:32
#define ttkVtkTemplateMacro(dataType, triangulationType, call)
Definition ttkMacros.h:69
void setArray(vtkArrayType &vtkArray, vectorType &vector)
void setArray(vtkArrayType &vtkArray, vectorType &vector)
vtkStandardNewMacro(ttkTopologicalSkeleton)
printMsg(debug::output::BOLD+" | | | | | . \\ | | (__| | / __/| |_| / __/| (_) |"+debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, stream)