48 vtkInformationVector **inputVector,
49 vtkInformationVector *outputVector) {
57 vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
58 auto inputMB = vtkMultiBlockDataSet::SafeDownCast(
59 inInfo->Get(vtkDataObject::DATA_OBJECT()));
61 size_t const n = inputMB->GetNumberOfBlocks();
66 {{
"#Trees", std::to_string(n)}, {
"Seed", std::to_string(RandomSeed)}});
71 this->
printMsg(
"Extracting topologies for " + std::to_string(n) +
" trees",
72 debug::Priority::VERBOSE);
73 if(this->
debugLevel_ <
static_cast<int>(debug::Priority::VERBOSE)) {
74 this->
printMsg(
"Extracting topologies for " + std::to_string(n) +
" trees.",
75 0, debug::LineMode::REPLACE);
79 vector<void *> scalars(n);
80 vector<int *> regionSizes(n);
81 vector<int *> segmentationIds(n);
82 vector<int *> segmentations;
83 vector<size_t> segSizes;
84 vector<long long *> topologies(n);
85 vector<size_t> nVertices(n);
86 vector<size_t> nEdges(n);
88 for(
size_t i = 0; i < n; i++) {
89 auto contourTree = vtkUnstructuredGrid::SafeDownCast(inputMB->GetBlock(i));
90 vtkDataSet *segmentation =
nullptr;
93 auto pair = vtkMultiBlockDataSet::SafeDownCast(inputMB->GetBlock(i));
95 if(!pair || pair->GetNumberOfBlocks() != 2) {
96 this->
printErr(
"block " + std::to_string(i)
97 +
" is not an unstructured grid or a pair of "
98 "unstructured grid and segmentation.");
102 contourTree = vtkUnstructuredGrid::SafeDownCast(pair->GetBlock(0));
103 segmentation = vtkDataSet::SafeDownCast(pair->GetBlock(1));
106 this->
printErr(
"block " + std::to_string(i)
107 +
" is not an unstructured grid or a pair of "
108 "unstructured grid and segmentation.");
113 this->
printMsg(
"Block " + std::to_string(i) +
" read from multiblock.",
114 debug::Priority::VERBOSE);
115 if(this->
debugLevel_ <
static_cast<int>(debug::Priority::VERBOSE)) {
116 this->
printMsg(
"Extracting topologies for " + std::to_string(n)
117 +
" trees (" + std::to_string(i) +
"/"
118 + std::to_string(n) +
")",
119 (
float)i / (
float)n, debug::LineMode::REPLACE);
122 nVertices[i] = contourTree->GetNumberOfPoints();
123 nEdges[i] = contourTree->GetNumberOfCells();
128 if(this->GetInputArrayAssociation(0, contourTree) != 0) {
129 printErr(
"Scalar array not point data.");
132 auto scalarArray = this->GetInputArrayToProcess(0, contourTree);
134 printErr(
"No Point Array \"Scalar\" found in contour tree.");
138 scalarType = scalarArray->GetDataType();
141 "Scalar Array read from point data.", debug::Priority::VERBOSE);
146 if(this->GetInputArrayAssociation(1, contourTree) != 1) {
147 printErr(
"Region size array not cell data.");
150 auto regionArray = this->GetInputArrayToProcess(1, contourTree);
152 printErr(
"No Cell Array \"RegionSize\" found in contour tree.");
157 "RegionSize Array read from cell data.", debug::Priority::VERBOSE);
160 if(this->GetInputArrayAssociation(2, contourTree) != 1) {
161 printErr(
"Segmentation Id array not cell data.");
164 auto segArray = this->GetInputArrayToProcess(2, contourTree);
166 printErr(
"No Cell Array \"SegmentationId\" found in contour tree.");
171 "SegmentationId Array read from cell data.", debug::Priority::VERBOSE);
174 auto segArray_segmentation
175 = this->GetInputArrayToProcess(3, segmentation);
178 if(!segArray_segmentation) {
179 printErr(
"No Cell Array \"SegmentationId\" found in segmentation.");
182 segmentations.push_back(
184 this->
printMsg(
"Segmentation read.", debug::Priority::VERBOSE);
185 segSizes.push_back(segArray_segmentation->GetNumberOfValues());
188 auto cells = contourTree->GetCells();
191 for(
int cIdx = 0; cIdx < contourTree->GetNumberOfCells(); cIdx++) {
192 if(cellSizes[cIdx + 1] - cellSizes[cIdx] != 2) {
193 printErr(
"cell " + std::to_string(cIdx) +
" of block "
195 +
" not a line (input not a contour tree).");
203 if(scalarType < 0 || n < 1)
209 "For " + std::to_string(n) +
" trees topologies and data extracted.",
210 debug::Priority::VERBOSE);
211 if(this->
debugLevel_ <
static_cast<int>(debug::Priority::VERBOSE)) {
213 "Extracting topologies for " + std::to_string(n) +
" trees", 1);
216 for(
auto s : segSizes) {
220 this->
printMsg(
"Starting alignment computation.");
224 vector<float> outputVertices;
225 vector<int> outputEdges;
226 vector<long long> outputFrequencies;
227 vector<long long> outputVertexIds;
228 vector<long long> outputBranchIds;
229 vector<long long> outputSegmentationIds;
230 vector<long long> outputArcIds;
246 success = this->execute<VTK_TT>(
247 scalars, regionSizes, segmentationIds, topologies, nVertices, nEdges,
248 segmentations, segSizes,
250 outputVertices, outputFrequencies, outputVertexIds, outputBranchIds,
251 outputSegmentationIds, outputArcIds, outputEdges,
257 printErr(
"base layer execution failed.");
264 this->
printMsg(
"Alignment computed.");
265 this->
printMsg(
"Writing paraview/vtk output.", 0, debug::LineMode::REPLACE);
271 vtkInformation *outInfo = outputVector->GetInformationObject(0);
272 auto alignmentTree = vtkUnstructuredGrid::SafeDownCast(
273 outInfo->Get(vtkDataObject::DATA_OBJECT()));
276 auto prepArray = [](vtkAbstractArray *array,
const string &name,
277 size_t nComponents,
size_t nTuples) {
278 array->SetName(name.data());
279 array->SetNumberOfComponents(nComponents);
280 array->SetNumberOfTuples(nTuples);
284 size_t const nOutputVertices = outputVertices.size();
286 points->SetNumberOfPoints(nOutputVertices);
287 alignmentTree->SetPoints(points);
291 prepArray(freq,
"Frequency", 1, nOutputVertices);
295 prepArray(scalar,
"Scalar", 1, nOutputVertices);
299 prepArray(vertexIDs,
"VertexIDs", n, nOutputVertices);
303 prepArray(branchIDs,
"BranchIDs", 1, nOutputVertices);
307 prepArray(segmentationIDs,
"segmentationIDs", n, nOutputVertices);
308 auto segmentationIDsData
312 prepArray(arcIDs,
"arcIDs", n, nOutputVertices - 1);
316 for(
size_t i = 0; i < nOutputVertices; i++) {
317 pointCoords[i * 3] = i;
318 pointCoords[i * 3 + 1] = outputVertices[i];
319 pointCoords[i * 3 + 2] = 0;
321 freqData[i] = outputFrequencies[i];
322 scalarData[i] = outputVertices[i];
323 branchIDsData[i] = outputBranchIds[i];
325 for(
size_t i = 0; i < outputVertexIds.size(); i++)
326 vertexIDsData[i] = outputVertexIds[i];
327 for(
size_t i = 0; i < outputSegmentationIds.size(); i++)
328 segmentationIDsData[i] = outputSegmentationIds[i];
329 for(
size_t i = 0; i < outputArcIds.size(); i++)
330 arcIDsData[i] = outputArcIds[i];
333 auto pointData = alignmentTree->GetPointData();
334 pointData->AddArray(freq);
335 pointData->AddArray(scalar);
336 pointData->AddArray(vertexIDs);
337 pointData->AddArray(branchIDs);
338 pointData->AddArray(segmentationIDs);
341 size_t const nOutputEdges = outputEdges.size() / 2;
346 auto cellConnectivity = cellArray->GetConnectivityArray();
347 cellConnectivity->SetNumberOfTuples(nOutputEdges * 2);
351 auto cellOffsets = cellArray->GetOffsetsArray();
352 cellOffsets->SetNumberOfTuples(nOutputEdges + 1);
355 for(
size_t i = 0; i < nOutputEdges; i++) {
356 cellOffsetsData[i] = i * 2;
357 cellIds[i * 2] = (vtkIdType)outputEdges[i * 2];
358 cellIds[i * 2 + 1] = (vtkIdType)outputEdges[i * 2 + 1];
360 cellOffsetsData[nOutputEdges] = 2 * nOutputEdges;
362 alignmentTree->SetCells(VTK_LINE, cellArray);
364 alignmentTree->GetCellData()->AddArray(arcIDs);
366 this->
printMsg(
"Writing paraview/vtk output", 1);
368 if(!ExportJSON || ExportPath.length() < 1) {
378 this->
printMsg(
"Writing JSON alignment to \"" + ExportPath +
"\"", 0,
379 debug::LineMode::REPLACE);
384 std::ofstream fileJSON;
385 fileJSON.open(ExportPath +
"/alignment.json");
387 std::vector<std::vector<int>> upEdges(nOutputVertices);
388 std::vector<std::vector<int>> downEdges(nOutputVertices);
390 std::vector<std::vector<int>> alignmentIDs;
391 for(
size_t i = 0; i < n; i++) {
392 std::vector<int>
const vertices_i(nVertices[i], -1);
393 alignmentIDs.push_back(vertices_i);
396 for(
size_t i = 0; i < nOutputEdges; i++) {
397 int const id1 = outputEdges[i * 2];
398 int const id2 = outputEdges[i * 2 + 1];
399 float const v1 = scalar->GetValue(id1);
400 float const v2 = scalar->GetValue(id2);
402 downEdges[id1].push_back(i);
403 upEdges[id2].push_back(i);
405 upEdges[id1].push_back(i);
406 downEdges[id2].push_back(i);
412 fileJSON <<
" \"nodes\": [\n";
414 for(
size_t i = 0; i < nOutputVertices; i++) {
416 fileJSON <<
"\"scalar\": " << scalar->GetValue(i) <<
", ";
417 fileJSON <<
"\"frequency\": " << freq->GetValue(i) <<
", ";
418 for(
size_t j = 0; j < n; j++) {
419 if(vertexIDs->GetComponent(i, j) >= 0)
420 alignmentIDs[j][vertexIDs->GetComponent(i, j)] = i;
422 fileJSON <<
"\"segmentationIDs\": [";
423 for(
size_t j = 0; j < n; j++) {
424 fileJSON << segmentationIDs->GetComponent(i, j);
429 fileJSON <<
"\"upEdgeIDs\": [";
430 for(
size_t j = 0; j < upEdges[i].size(); j++) {
431 fileJSON << upEdges[i][j];
432 if(j < upEdges[i].size() - 1)
436 fileJSON <<
"\"downEdgeIDs\": [";
437 for(
size_t j = 0; j < downEdges[i].size(); j++) {
438 fileJSON << downEdges[i][j];
439 if(j < downEdges[i].size() - 1)
443 fileJSON << (i == nOutputVertices - 1 ?
"}\n" :
"},\n");
448 fileJSON <<
" \"edges\": [\n";
450 for(
size_t i = 0; i < nOutputEdges; i++) {
452 int const id1 = outputEdges[i * 2];
453 int const id2 = outputEdges[i * 2 + 1];
454 fileJSON <<
"\"node1\": " << id1 <<
", \"node2\": " << id2;
455 fileJSON << (i == nOutputEdges - 1 ?
"}\n" :
"},\n");
466 this->
printMsg(
"Writing JSON alignment to \"" + ExportPath +
"\"", 1);
467 this->
printMsg(
"Writing JSON input trees to \"" + ExportPath +
"\"", 0,
468 debug::LineMode::REPLACE);
473 for(
size_t t = 0; t < n; t++) {
475 fileJSON.open(ExportPath +
"/tree" + std::to_string(t) +
".json");
477 upEdges = std::vector<std::vector<int>>(nVertices[t]);
478 downEdges = std::vector<std::vector<int>>(nVertices[t]);
480 for(
size_t i = 0; i < nEdges[t]; i++) {
481 int const id1 = topologies[t][i * 2 + 0];
482 int const id2 = topologies[t][i * 2 + 1];
483 float const v1 = ((
float *)scalars[t])[id1];
484 float const v2 = ((
float *)scalars[t])[id2];
486 downEdges[id1].push_back(i);
487 upEdges[id2].push_back(i);
489 upEdges[id1].push_back(i);
490 downEdges[id2].push_back(i);
496 fileJSON <<
" \"nodes\": [\n";
499 for(
size_t k = 0; k < nOutputVertices; k++) {
500 int const i = vertexIDs->GetComponent(k, t);
503 fileJSON << (first ?
" {" :
",\n {");
504 fileJSON <<
"\"scalar\": " << ((
float *)scalars[t])[i] <<
", ";
505 fileJSON <<
"\"id\": " << alignmentIDs[t][i] <<
", ";
506 fileJSON <<
"\"upEdgeIDs\": [";
507 for(
size_t j = 0; j < upEdges[i].size(); j++) {
508 fileJSON << upEdges[i][j];
509 if(j < upEdges[i].size() - 1)
513 fileJSON <<
"\"downEdgeIDs\": [";
514 for(
size_t j = 0; j < downEdges[i].size(); j++) {
515 fileJSON << downEdges[i][j];
516 if(j < downEdges[i].size() - 1)
524 fileJSON <<
"\n ],\n";
526 fileJSON <<
" \"edges\": [\n";
528 for(
size_t i = 0; i < nEdges[t]; i++) {
530 int const id1 = alignmentIDs[t][topologies[t][i * 2 + 0]];
531 int const id2 = alignmentIDs[t][topologies[t][i * 2 + 1]];
532 fileJSON <<
"\"node1\": " << id1 <<
", \"node2\": " << id2;
533 fileJSON << (i == nEdges[t] - 1 ?
"}\n" :
"},\n");
542 this->
printMsg(
"Writing JSON input trees to \"" + ExportPath +
"\"", 1);