17 vtkUnstructuredGrid *vtu,
20 const auto pd = vtu->GetPointData();
21 const auto cd = vtu->GetCellData();
22 const auto points = vtu->GetPoints();
25 dbg.
printWrn(
"VTU diagram with NULL Point Data");
29 dbg.
printWrn(
"VTU diagram with NULL Cell Data");
32 if(points ==
nullptr) {
38 const auto pairId = ttkSimplexIdTypeArray::SafeDownCast(
47 const auto vertexId = ttkSimplexIdTypeArray::SafeDownCast(
51 const auto coords = vtkFloatArray::SafeDownCast(
54 const bool embed = coords ==
nullptr;
56 if(pairId ==
nullptr) {
57 dbg.
printWrn(
"Missing PairIdentifier cell data array");
60 if(pairType ==
nullptr) {
61 dbg.
printWrn(
"Missing PairType cell data array");
64 if(pairPers ==
nullptr) {
65 dbg.
printWrn(
"Missing Persistence cell data array");
68 if(vertexId ==
nullptr) {
69 dbg.
printWrn(
"Missing ttkVertexScalarField point data array");
72 if(critType ==
nullptr) {
73 dbg.
printWrn(
"Missing CriticalType point data array");
76 if(birthScalars ==
nullptr) {
77 dbg.
printWrn(
"Missing Birth cell data array");
80 if(isFinite ==
nullptr) {
81 dbg.
printWrn(
"Missing IsFinite cell data array");
85 int nPairs = pairId->GetNumberOfTuples();
88 for(
int i = 0; i < nPairs; i++) {
89 if(pairId->GetTuple1(i) != -1) {
90 pairId->SetTuple1(i, i);
98 dbg.
printWrn(
"Diagram has no pairs");
102 diagram.resize(nPairs);
105 for(
int i = 0; i < nPairs; ++i) {
107 const auto pId = pairId->GetValue(i);
113 const auto i0 = 2 * i + 0;
114 const auto i1 = 2 * i + 1;
116 const auto v0 = vertexId->GetValue(i0);
117 const auto v1 = vertexId->GetValue(i1);
121 const auto pType = pairType->GetValue(i);
122 const auto pers = pairPers->GetTuple1(i);
123 const auto birth = birthScalars->GetTuple1(i);
124 const auto isFin =
static_cast<bool>(isFinite->GetTuple1(i));
126 std::array<float, 3> coordsBirth{}, coordsDeath{};
129 std::array<double, 3> tmp{};
132 points->GetPoint(i0, tmp.data());
133 coordsBirth = {
static_cast<float>(tmp[0]),
static_cast<float>(tmp[1]),
134 static_cast<float>(tmp[2])};
135 points->GetPoint(i1, tmp.data());
136 coordsDeath = {
static_cast<float>(tmp[0]),
static_cast<float>(tmp[1]),
137 static_cast<float>(tmp[2])};
139 coords->GetTuple(i0, tmp.data());
140 coordsBirth = {
static_cast<float>(tmp[0]),
static_cast<float>(tmp[1]),
141 static_cast<float>(tmp[2])};
142 coords->GetTuple(i1, tmp.data());
143 coordsDeath = {
static_cast<float>(tmp[0]),
static_cast<float>(tmp[1]),
144 static_cast<float>(tmp[2])};
158 vtkDataArray *
const inputScalars,
161 const bool embedInDomain) {
163 if(diagram.empty()) {
168 const auto pd = vtu->GetPointData();
169 const auto cd = vtu->GetCellData();
171 if(pd ==
nullptr || cd ==
nullptr) {
172 dbg.
printWrn(
"Grid has no point data or no cell data");
178 vtkNew<ttkSimplexIdTypeArray> vertsId{};
180 vertsId->SetNumberOfTuples(2 * diagram.size());
181 pd->AddArray(vertsId);
183 vtkNew<vtkIntArray> critType{};
185 critType->SetNumberOfTuples(2 * diagram.size());
186 pd->AddArray(critType);
188 vtkNew<vtkFloatArray> coordsScalars{};
191 coordsScalars->SetNumberOfComponents(3);
193 coordsScalars->SetNumberOfTuples(2 * diagram.size());
194 pd->AddArray(coordsScalars);
199 vtkNew<ttkSimplexIdTypeArray> pairsId{};
201 pairsId->SetNumberOfTuples(diagram.size());
202 cd->AddArray(pairsId);
204 vtkNew<vtkIntArray> pairsDim{};
206 pairsDim->SetNumberOfTuples(diagram.size());
207 cd->AddArray(pairsDim);
211 persistence->SetNumberOfTuples(diagram.size());
212 cd->AddArray(persistence);
216 birthScalars->SetNumberOfTuples(diagram.size());
217 cd->AddArray(birthScalars);
219 vtkNew<vtkUnsignedCharArray> isFinite{};
221 isFinite->SetNumberOfTuples(diagram.size());
222 cd->AddArray(isFinite);
226 vtkNew<vtkPoints> points{};
227 points->SetNumberOfPoints(2 * diagram.size());
228 vtkNew<vtkIdTypeArray> offsets{}, connectivity{};
229 offsets->SetNumberOfComponents(1);
230 offsets->SetNumberOfTuples(diagram.size() + 1);
231 connectivity->SetNumberOfComponents(1);
232 connectivity->SetNumberOfTuples(2 * diagram.size());
234#ifdef TTK_ENABLE_OPENMP
235#pragma omp parallel for num_threads(dbg.getThreadNumber())
237 for(
size_t i = 0; i < diagram.size(); ++i) {
238 const auto &pair{diagram[i]};
239 const auto i0{2 * i + 0}, i1{2 * i + 1};
242 i0, pair.birth.coords[0], pair.birth.coords[1], pair.birth.coords[2]);
244 i1, pair.death.coords[0], pair.death.coords[1], pair.death.coords[2]);
246 points->SetPoint(i0, pair.birth.sfValue, pair.birth.sfValue, 0);
247 points->SetPoint(i1, pair.birth.sfValue, pair.death.sfValue, 0);
250 connectivity->SetTuple1(i0, i0);
251 connectivity->SetTuple1(i1, i1);
252 offsets->SetTuple1(i, 2 * i);
255 vertsId->SetTuple1(i0, pair.birth.id);
256 vertsId->SetTuple1(i1, pair.death.id);
257 critType->SetTuple1(i0,
static_cast<ttk::SimplexId>(pair.birth.type));
258 critType->SetTuple1(i1,
static_cast<ttk::SimplexId>(pair.death.type));
261 coordsScalars->SetTuple3(
262 i0, pair.birth.coords[0], pair.birth.coords[1], pair.birth.coords[2]);
263 coordsScalars->SetTuple3(
264 i1, pair.death.coords[0], pair.death.coords[1], pair.death.coords[2]);
268 pairsId->SetTuple1(i, i);
269 persistence->SetTuple1(i, pair.persistence());
270 birthScalars->SetTuple1(i, pair.birth.sfValue);
271 isFinite->SetTuple1(i, pair.isFinite);
273 i, (pair.dim == 2 && pair.isFinite) ? dim - 1 : pair.dim);
275 offsets->SetTuple1(diagram.size(), connectivity->GetNumberOfTuples());
277 vtkNew<vtkCellArray> cells{};
278 cells->SetData(offsets, connectivity);
279 vtu->SetPoints(points);
280 vtu->SetCells(VTK_LINE, cells);
284 const auto lastPair = std::max_element(diagram.begin(), diagram.end());
286 std::array<vtkIdType, 2> diag{
287 0, 2 * std::distance(diagram.begin(), lastPair)};
288 vtu->InsertNextCell(VTK_LINE, 2, diag.data());
289 pairsId->InsertTuple1(diagram.size(), -1);
290 pairsDim->InsertTuple1(diagram.size(), -1);
291 isFinite->InsertTuple1(diagram.size(),
false);
293 const auto maxPersistence = diagram[0].persistence();
294 persistence->InsertTuple1(diagram.size(), 2 * maxPersistence);
296 birthScalars->InsertTuple1(diagram.size(), 0);
303 vtkUnstructuredGrid *
const outputDiagram,
309 vtkNew<vtkThreshold> threshold{};
310 threshold->SetInputDataObject(0, inputDiagram);
311 threshold->SetInputArrayToProcess(0, 0, 0,
312 vtkDataObject::FIELD_ASSOCIATION_CELLS,
314#if VTK_VERSION_NUMBER < VTK_VERSION_CHECK(9, 2, 0)
315 threshold->ThresholdByUpper(0);
317 threshold->SetThresholdFunction(vtkThreshold::THRESHOLD_UPPER);
318 threshold->SetUpperThreshold(0);
323 auto diagonalLess = threshold->GetOutput();
324 auto diagonalLessData = diagonalLess->GetPointData();
326 const auto critCoordinates = vtkFloatArray::SafeDownCast(
330 vtkNew<vtkFloatArray> coords{};
331 coords->DeepCopy(critCoordinates);
332 coords->SetName(
"Points");
333 diagonalLess->GetPoints()->SetData(coords);
336 outputDiagram->ShallowCopy(diagonalLess);
339 outputDiagram->GetFieldData()->ShallowCopy(inputDiagram->GetFieldData());
341 dbg.
printMsg(
"Projected Persistence Diagram inside domain", 1.0,
376 vtkUnstructuredGrid *
const outputDiagram,
381 outputDiagram->ShallowCopy(inputDiagram);
383 auto pointData = outputDiagram->GetPointData();
388 if(birth ==
nullptr || pers ==
nullptr) {
389 dbg.
printWrn(
"Missing Birth or Persistence arrays");
394 vtkNew<vtkFloatArray> coords{};
395 coords->DeepCopy(inputDiagram->GetPoints()->GetData());
397 pointData->AddArray(coords);
399 vtkNew<vtkPoints> points{};
400 const auto nPoints = inputDiagram->GetNumberOfPoints();
401 points->SetNumberOfPoints(nPoints);
403 if(birth->GetNumberOfTuples() != nPoints / 2
404 || pers->GetNumberOfTuples() != nPoints / 2) {
405 dbg.
printWrn(
"Wrong number of tuples for Birth or Persistence arrays");
409 switch(birth->GetDataType()) {
410 vtkTemplateMacro(
getCoords(points, ttkUtils::GetPointer<VTK_TT>(birth),
411 ttkUtils::GetPointer<VTK_TT>(pers), nPoints,
415 outputDiagram->SetPoints(points);
418 std::array<vtkIdType, 2> diag{0, 2 * (outputDiagram->GetNumberOfCells() - 1)};
419 outputDiagram->InsertNextCell(VTK_LINE, 2, diag.data());
422 auto cellData = outputDiagram->GetCellData();
423 auto pairIdentifierScalars = vtkIntArray::SafeDownCast(
425 auto extremumIndexScalars = vtkIntArray::SafeDownCast(
431 pairIdentifierScalars->InsertNextTuple1(-1);
432 extremumIndexScalars->InsertNextTuple1(-1);
433 isFinite->InsertNextTuple1(0);
435 persistenceScalars->InsertNextTuple1(2 * persistenceScalars->GetTuple1(0));
437 birthScalars->InsertNextTuple1(0);
440 outputDiagram->GetFieldData()->ShallowCopy(inputDiagram->GetFieldData());
442 dbg.
printMsg(
"Projected Persistence Diagram back to 2D", 1.0,