5#include <vtkCellData.h>
6#include <vtkDataArray.h>
7#include <vtkDataObject.h>
9#include <vtkDoubleArray.h>
10#include <vtkFloatArray.h>
11#include <vtkIdTypeArray.h>
12#include <vtkInformation.h>
14#include <vtkPointData.h>
15#include <vtkPolyData.h>
16#include <vtkSignedCharArray.h>
17#include <vtkUnsignedCharArray.h>
23 SetNumberOfInputPorts(1);
24 SetNumberOfOutputPorts(4);
28 vtkInformation *info) {
30 info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(),
"vtkDataSet");
37 vtkInformation *info) {
38 if(port == 0 || port == 1 || port == 2) {
39 info->Set(vtkDataObject::DATA_TYPE_NAME(),
"vtkPolyData");
41 }
else if(port == 3) {
48template <
typename vtkArrayType,
typename vectorType>
49void setArray(vtkArrayType &vtkArray, vectorType &vector) {
53template <
typename scalarType,
typename triangulationType>
55 vtkPolyData *
const outputCriticalPoints,
56 vtkPolyData *
const outputSeparatrices1,
57 vtkPolyData *
const outputSeparatrices2,
58 const SimplexId *
const inputOffsets,
59 const triangulationType &triangulation) {
61 const int dimensionality = triangulation.getDimensionality();
62 const auto scalars = ttkUtils::GetPointer<scalarType>(inputScalars);
65 criticalPoints_, separatrices1_, separatrices2_, segmentations_, scalars,
66 inputScalars->GetMTime(), inputOffsets, triangulation);
68#ifndef TTK_ENABLE_KAMIKAZE
70 this->
printErr(
"MorseSmaleComplex.execute() error");
77 vtkNew<vtkPoints> points{};
78 vtkNew<vtkSignedCharArray> cellDimensions{};
79 vtkNew<ttkSimplexIdTypeArray> cellIds{};
81 vtkNew<vtkSignedCharArray> isOnBoundary{};
82 vtkNew<ttkSimplexIdTypeArray> PLVertexIdentifiers{};
83 vtkNew<ttkSimplexIdTypeArray> manifoldSizeScalars{};
84 const auto nPoints = criticalPoints_.
points_.size();
86#ifndef TTK_ENABLE_KAMIKAZE
87 if(!points || !cellDimensions || !cellIds || !cellScalars || !isOnBoundary
88 || !PLVertexIdentifiers || !manifoldSizeScalars) {
89 this->
printErr(
"Critical points vtkDataArray allocation problem.");
94 points->SetNumberOfPoints(nPoints);
96 cellDimensions->SetNumberOfComponents(1);
100 cellIds->SetNumberOfComponents(1);
104 cellScalars->SetNumberOfComponents(1);
105 cellScalars->SetName(inputScalars->GetName());
106 cellScalars->SetNumberOfTuples(nPoints);
107#ifdef TTK_ENABLE_OPENMP
108#pragma omp parallel for num_threads(this->threadNumber_)
110 for(
size_t i = 0; i < nPoints; ++i) {
111 points->SetPoint(i, criticalPoints_.
points_[i].data());
112 cellScalars->SetTuple1(
116 isOnBoundary->SetNumberOfComponents(1);
120 PLVertexIdentifiers->SetNumberOfComponents(1);
124 manifoldSizeScalars->SetNumberOfComponents(1);
135 auto pointData = outputCriticalPoints->GetPointData();
136#ifndef TTK_ENABLE_KAMIKAZE
138 this->
printErr(
"outputCriticalPoints has no point data.");
143 pointData->SetScalars(cellDimensions);
144 pointData->AddArray(cellIds);
145 pointData->AddArray(cellScalars);
146 pointData->AddArray(isOnBoundary);
147 pointData->AddArray(PLVertexIdentifiers);
148 pointData->AddArray(manifoldSizeScalars);
155 vtkNew<vtkFloatArray> pointsCoords{};
156 vtkNew<vtkSignedCharArray> smoothingMask{};
157 vtkNew<vtkSignedCharArray> cellDimensions{};
158 vtkNew<ttkSimplexIdTypeArray> cellIds{};
159 vtkNew<ttkSimplexIdTypeArray> sourceIds{};
160 vtkNew<ttkSimplexIdTypeArray> destinationIds{};
161 vtkNew<ttkSimplexIdTypeArray> separatrixIds{};
162 vtkNew<vtkSignedCharArray> separatrixTypes{};
163 vtkNew<vtkDoubleArray> separatrixFunctionMaxima{};
164 vtkNew<vtkDoubleArray> separatrixFunctionMinima{};
165 vtkNew<vtkDoubleArray> separatrixFunctionDiffs{};
166 vtkNew<vtkSignedCharArray> isOnBoundary{};
168#ifndef TTK_ENABLE_KAMIKAZE
169 if(!pointsCoords || !smoothingMask || !cellDimensions || !cellIds
170 || !sourceIds || !destinationIds || !separatrixIds || !separatrixTypes
171 || !separatrixFunctionMaxima || !separatrixFunctionMinima
172 || !separatrixFunctionDiffs || !isOnBoundary) {
173 this->
printErr(
"1-separatrices vtkDataArray allocation problem.");
178 pointsCoords->SetNumberOfComponents(3);
181 smoothingMask->SetNumberOfComponents(1);
185 cellDimensions->SetNumberOfComponents(1);
189 cellIds->SetNumberOfComponents(1);
193 sourceIds->SetNumberOfComponents(1);
197 destinationIds->SetNumberOfComponents(1);
201 separatrixIds->SetNumberOfComponents(1);
205 separatrixTypes->SetNumberOfComponents(1);
209 separatrixFunctionMaxima->SetNumberOfComponents(1);
211 separatrixFunctionMaxima->SetNumberOfTuples(
214 separatrixFunctionMinima->SetNumberOfComponents(1);
216 separatrixFunctionMinima->SetNumberOfTuples(
219 separatrixFunctionDiffs->SetNumberOfComponents(1);
221 separatrixFunctionDiffs->SetNumberOfTuples(
224#ifdef TTK_ENABLE_OPENMP
225#pragma omp parallel for num_threads(this->threadNumber_)
232 separatrixFunctionMinima->SetTuple1(i, min);
233 separatrixFunctionMaxima->SetTuple1(i, max);
234 separatrixFunctionDiffs->SetTuple1(i, max - min);
237 isOnBoundary->SetNumberOfComponents(1);
241 vtkNew<ttkSimplexIdTypeArray> offsets{}, connectivity{};
242 offsets->SetNumberOfComponents(1);
244 connectivity->SetNumberOfComponents(1);
247#ifdef TTK_ENABLE_OPENMP
248#pragma omp parallel for num_threads(this->threadNumber_)
251 offsets->SetTuple1(i, 2 * i);
254 vtkNew<vtkPoints> points{};
255 points->SetData(pointsCoords);
256 outputSeparatrices1->SetPoints(points);
257 vtkNew<vtkCellArray> cells{};
258#ifndef TTK_ENABLE_64BIT_IDS
259 cells->Use32BitStorage();
261 cells->SetData(offsets, connectivity);
262 outputSeparatrices1->SetLines(cells);
264 auto pointData = outputSeparatrices1->GetPointData();
265 auto cellData = outputSeparatrices1->GetCellData();
267#ifndef TTK_ENABLE_KAMIKAZE
268 if(!pointData || !cellData) {
269 this->
printErr(
"outputSeparatrices1 has no point or no cell data.");
274 pointData->AddArray(smoothingMask);
275 pointData->AddArray(cellDimensions);
276 pointData->AddArray(cellIds);
278 cellData->AddArray(sourceIds);
279 cellData->AddArray(destinationIds);
280 cellData->AddArray(separatrixIds);
281 cellData->SetScalars(separatrixTypes);
282 cellData->AddArray(separatrixFunctionMaxima);
283 cellData->AddArray(separatrixFunctionMinima);
284 cellData->AddArray(separatrixFunctionDiffs);
285 cellData->AddArray(isOnBoundary);
289 if(dimensionality == 3
292 vtkNew<vtkFloatArray> pointsCoords{};
293 vtkNew<ttkSimplexIdTypeArray> sourceIds{};
294 vtkNew<ttkSimplexIdTypeArray> separatrixIds{};
295 vtkNew<vtkSignedCharArray> separatrixTypes{};
296 vtkNew<vtkDoubleArray> separatrixFunctionMaxima{};
297 vtkNew<vtkDoubleArray> separatrixFunctionMinima{};
298 vtkNew<vtkDoubleArray> separatrixFunctionDiffs{};
299 vtkNew<vtkSignedCharArray> isOnBoundary{};
301#ifndef TTK_ENABLE_KAMIKAZE
302 if(!pointsCoords || !sourceIds || !separatrixIds || !separatrixTypes
303 || !separatrixFunctionMaxima || !separatrixFunctionMinima
304 || !separatrixFunctionDiffs || !isOnBoundary) {
305 this->
printErr(
"2-separatrices vtkDataArray allocation problem.");
310 pointsCoords->SetNumberOfComponents(3);
313 sourceIds->SetNumberOfComponents(1);
317 separatrixIds->SetNumberOfComponents(1);
321 separatrixTypes->SetNumberOfComponents(1);
325 separatrixFunctionMaxima->SetNumberOfComponents(1);
327 separatrixFunctionMaxima->SetNumberOfTuples(
330 separatrixFunctionMinima->SetNumberOfComponents(1);
332 separatrixFunctionMinima->SetNumberOfTuples(
335 separatrixFunctionDiffs->SetNumberOfComponents(1);
337 separatrixFunctionDiffs->SetNumberOfTuples(
340#ifdef TTK_ENABLE_OPENMP
341#pragma omp parallel for num_threads(this->threadNumber_)
348 separatrixFunctionMinima->SetTuple1(i, min);
349 separatrixFunctionMaxima->SetTuple1(i, max);
350 separatrixFunctionDiffs->SetTuple1(i, max - min);
353 isOnBoundary->SetNumberOfComponents(1);
357 vtkNew<ttkSimplexIdTypeArray> offsets{}, connectivity{};
358 offsets->SetNumberOfComponents(1);
360 connectivity->SetNumberOfComponents(1);
363 vtkNew<vtkPoints> points{};
364 points->SetData(pointsCoords);
365 outputSeparatrices2->SetPoints(points);
366 vtkNew<vtkCellArray> cells{};
367#ifndef TTK_ENABLE_64BIT_IDS
368 cells->Use32BitStorage();
370 cells->SetData(offsets, connectivity);
371 outputSeparatrices2->SetPolys(cells);
373 auto cellData = outputSeparatrices2->GetCellData();
374#ifndef TTK_ENABLE_KAMIKAZE
376 this->
printErr(
"outputSeparatrices2 has no cell data.");
381 cellData->AddArray(sourceIds);
382 cellData->AddArray(separatrixIds);
383 cellData->AddArray(separatrixTypes);
384 cellData->AddArray(separatrixFunctionMaxima);
385 cellData->AddArray(separatrixFunctionMinima);
386 cellData->AddArray(separatrixFunctionDiffs);
387 cellData->AddArray(isOnBoundary);
394 vtkInformationVector **inputVector,
395 vtkInformationVector *outputVector) {
397 const auto input = vtkDataSet::GetData(inputVector[0]);
398 auto outputCriticalPoints = vtkPolyData::GetData(outputVector, 0);
399 auto outputSeparatrices1 = vtkPolyData::GetData(outputVector, 1);
400 auto outputSeparatrices2 = vtkPolyData::GetData(outputVector, 2);
401 auto outputMorseComplexes = vtkDataSet::GetData(outputVector, 3);
403#ifndef TTK_ENABLE_KAMIKAZE
405 this->
printErr(
"Input pointer is NULL.");
408 if(input->GetNumberOfPoints() == 0) {
409 this->
printErr(
"Input has no point.");
412 if(!outputCriticalPoints or !outputSeparatrices1 or !outputSeparatrices2
413 or !outputMorseComplexes) {
414 this->
printErr(
"Output pointers are NULL.");
420 if(triangulation ==
nullptr) {
421 this->
printErr(
"Triangulation is null");
426 const auto inputScalars = this->GetInputArrayToProcess(0, inputVector);
428#ifndef TTK_ENABLE_KAMIKAZE
429 if(inputScalars ==
nullptr) {
436 input, 0, 1, this->ForceInputOffsetScalarField);
438#ifndef TTK_ENABLE_KAMIKAZE
439 if(inputOffsets ==
nullptr) {
443 if(inputOffsets->GetDataType() != VTK_INT
444 and inputOffsets->GetDataType() != VTK_ID_TYPE) {
445 this->
printErr(
"input offset field type not supported.");
450 this->
printMsg(
"Launching computation on field `"
451 + std::string(inputScalars->GetName()) +
"'...");
454 const SimplexId numberOfVertices = triangulation->getNumberOfVertices();
455#ifndef TTK_ENABLE_KAMIKAZE
456 if(!numberOfVertices) {
457 this->
printErr(
"Input has no vertices.");
462 vtkNew<ttkSimplexIdTypeArray> ascendingManifold{};
463 vtkNew<ttkSimplexIdTypeArray> descendingManifold{};
464 vtkNew<ttkSimplexIdTypeArray> morseSmaleManifold{};
465#ifndef TTK_ENABLE_KAMIKAZE
466 if(!ascendingManifold || !descendingManifold || !morseSmaleManifold) {
467 this->
printErr(
"Manifold vtkDataArray allocation problem.");
471 ascendingManifold->SetNumberOfComponents(1);
472 ascendingManifold->SetNumberOfTuples(numberOfVertices);
475 descendingManifold->SetNumberOfComponents(1);
476 descendingManifold->SetNumberOfTuples(numberOfVertices);
479 morseSmaleManifold->SetNumberOfComponents(1);
480 morseSmaleManifold->SetNumberOfTuples(numberOfVertices);
483 this->segmentations_ = {ttkUtils::GetPointer<SimplexId>(ascendingManifold),
484 ttkUtils::GetPointer<SimplexId>(descendingManifold),
485 ttkUtils::GetPointer<SimplexId>(morseSmaleManifold)};
494 inputScalars->GetDataType(), triangulation->getType(),
495 (ret = dispatch<VTK_TT, TTK_TT>(
496 inputScalars, outputCriticalPoints, outputSeparatrices1,
497 outputSeparatrices2, ttkUtils::GetPointer<SimplexId>(inputOffsets),
498 *
static_cast<TTK_TT *
>(triangulation->getData()))));
504 outputMorseComplexes->ShallowCopy(input);
507 vtkPointData *pointData = outputMorseComplexes->GetPointData();
508#ifndef TTK_ENABLE_KAMIKAZE
510 this->
printErr(
"outputMorseComplexes has no point data.");
515 if(ComputeDescendingSegmentation)
516 pointData->AddArray(descendingManifold);
518 pointData->AddArray(ascendingManifold);
521 pointData->AddArray(morseSmaleManifold);
#define ttkNotUsed(x)
Mark function/method parameters that are not used in the function body at all.
static vtkInformationIntegerKey * SAME_DATA_TYPE_AS_INPUT_PORT()
vtkDataArray * GetOrderArray(vtkDataSet *const inputData, const int scalarArrayIdx, const int orderArrayIdx=0, const bool enforceOrderArrayIdx=false)
ttk::Triangulation * GetTriangulation(vtkDataSet *dataSet)
TTK VTK-filter that wraps the morseSmaleComplex processing package.
int dispatch(vtkDataArray *const inputScalars, vtkPolyData *const outputCriticalPoints, vtkPolyData *const outputSeparatrices1, vtkPolyData *const outputSeparatrices2, const SimplexId *const inputOffsets, const triangulationType &triangulation)
int FillInputPortInformation(int port, vtkInformation *info) override
int RequestData(vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector) override
int FillOutputPortInformation(int port, vtkInformation *info) override
static int CellVertexFromPoints(vtkDataSet *const dataSet, vtkPoints *const points)
static void SetVoidArray(vtkDataArray *array, void *data, vtkIdType size, int save)
void setDebugMsgPrefix(const std::string &prefix)
int printMsg(const std::string &msg, const debug::Priority &priority=debug::Priority::INFO, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cout) const
int printErr(const std::string &msg, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cerr) const
bool ComputeSaddleConnectors
bool ComputeDescendingSeparatrices2
bool ComputeDescendingSegmentation
bool ComputeAscendingSeparatrices1
bool ComputeDescendingSeparatrices1
bool ComputeAscendingSeparatrices2
bool ComputeAscendingSegmentation
void setSaddleConnectorsPersistenceThreshold(const double threshold)
void preconditionTriangulation(AbstractTriangulation *const data)
bool ComputeFinalSegmentation
void setReturnSaddleConnectors(const bool state)
int execute(OutputCriticalPoints &outCP, Output1Separatrices &outSeps1, Output2Separatrices &outSeps2, OutputManifold &outManifold, const dataType *const scalars, const size_t scalarsMTime, const SimplexId *const offsets, const triangulationType &triangulation)
bool ReturnSaddleConnectors
double SaddleConnectorsPersistenceThreshold
const char MorseSmaleDestinationIdName[]
const char MorseSmaleSeparatrixDifferenceName[]
const char MorseSmaleManifoldName[]
const char MorseSmaleSeparatrixMaximumName[]
const char MorseSmaleSourceIdName[]
const char MorseSmaleAscendingName[]
const char MorseSmaleCellDimensionName[]
const char MorseSmaleDescendingName[]
const char MorseSmaleCriticalPointsOnBoundaryName[]
const char MorseSmaleCellIdName[]
const char MorseSmaleSeparatrixTypeName[]
const char MorseSmaleManifoldSizeName[]
const char MorseSmaleBoundaryName[]
const char VertexScalarFieldName[]
default name for vertex scalar field
const char MorseSmaleSeparatrixMinimumName[]
const char MorseSmaleSeparatrixIdName[]
const char MaskScalarFieldName[]
default name for mask scalar field
std::vector< ttk::SimplexId > destinationIds_
std::vector< SimplexId > sepFuncMinId_
std::vector< SimplexId > sepFuncMaxId_
std::vector< ttk::SimplexId > separatrixIds_
struct ttk::MorseSmaleComplex::Output1Separatrices::@1 cl
std::vector< char > isOnBoundary_
std::vector< ttk::SimplexId > connectivity_
std::vector< ttk::SimplexId > sourceIds_
std::vector< char > smoothingMask_
std::vector< char > separatrixTypes_
struct ttk::MorseSmaleComplex::Output1Separatrices::@0 pt
std::vector< char > cellDimensions_
std::vector< ttk::SimplexId > cellIds_
std::vector< float > points_
std::vector< ttk::SimplexId > offsets_
std::vector< float > points_
struct ttk::MorseSmaleComplex::Output2Separatrices::@2 pt
std::vector< SimplexId > sepFuncMinId_
std::vector< ttk::SimplexId > sourceIds_
std::vector< char > isOnBoundary_
struct ttk::MorseSmaleComplex::Output2Separatrices::@3 cl
std::vector< ttk::SimplexId > connectivity_
std::vector< char > separatrixTypes_
std::vector< ttk::SimplexId > separatrixIds_
std::vector< SimplexId > sepFuncMaxId_
std::vector< char > cellDimensions_
std::vector< char > isOnBoundary_
std::vector< SimplexId > cellIds_
std::vector< SimplexId > manifoldSize_
std::vector< SimplexId > PLVertexIdentifiers_
std::vector< std::array< float, 3 > > points_
#define ttkVtkTemplateMacro(dataType, triangulationType, call)
vtkStandardNewMacro(ttkMorseSmaleComplex)
void setArray(vtkArrayType &vtkArray, vectorType &vector)