4#include <vtkInformation.h>
5#include <vtkInformationVector.h>
6#include <vtkSmartPointer.h>
7#include <vtkStreamingDemandDrivenPipeline.h>
10#include <vtkMultiBlockDataSet.h>
12#include <vtkUnstructuredGrid.h>
14#include <vtkCellArray.h>
15#include <vtkCellData.h>
16#include <vtkFieldData.h>
17#include <vtkIdTypeArray.h>
18#include <vtkPointData.h>
19#include <vtkSignedCharArray.h>
20#include <vtkThreshold.h>
31 this->SetNumberOfInputPorts(1);
32 this->SetNumberOfOutputPorts(1);
39 case VTK_MULTIBLOCK_DATA_SET:
40 return "vtkMultiBlockDataSet";
41 case VTK_UNSTRUCTURED_GRID:
42 return "vtkUnstructuredGrid";
46 return "vtkImageData";
56 info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(),
"vtkMultiBlockDataSet");
57 info->Append(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(),
"vtkDataObject");
70 if(this->OutputType != -1) {
72 if(DTName.length() < 1) {
73 this->
printErr(
"Unsupported output type");
76 info->Set(vtkDataObject::DATA_TYPE_NAME(), DTName.data());
88 vtkInformationVector **
ttkNotUsed(inputVector),
89 vtkInformationVector *outputVector) {
93 auto outInfo = outputVector->GetInformationObject(0);
95 vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), this->ImageExtent, 6);
101static int doubleVectorToString(std::string &str,
102 const std::vector<double> &vec) {
103 std::stringstream ss;
106 ss.seekp(-1, ss.cur);
107 str = ss.str().substr(0, ss.str().size() - 1);
112 vtkDataObject *input,
113 const std::vector<double> &indices,
114 const bool &extractTuples)
const {
116 std::string indicesString =
"";
117 doubleVectorToString(indicesString, indices);
120 std::string extentString =
"";
121 if(this->OutputType == VTK_IMAGE_DATA) {
122 extentString =
"[" + std::to_string(this->ImageExtent[0]);
123 for(
int i = 1; i < 6; i++)
124 extentString +=
"," + std::to_string(this->ImageExtent[i]);
130 "Block" + std::string(extractTuples ?
" Tuples" :
"")},
131 {
"Output Type", outputDataTypeName + extentString},
132 {
"Indices",
"[" + indicesString +
"]"}});
136 this->
printMsg(
"Extracting blocks [" + indicesString +
"]", 0,
139 auto inputAsMB = vtkMultiBlockDataSet::SafeDownCast(input);
141 this->
printErr(
"Block mode requires 'vtkMultiBlockDataSet' input.");
145 if(this->OutputType != -1 && extractTuples) {
146 this->
printErr(
"Block Tuple mode requires auto output.");
150 if(this->OutputType == -1) {
152 auto outputAsMB = vtkMultiBlockDataSet::SafeDownCast(output);
155 int nComponents = inputAsMB->GetNumberOfBlocks();
157 for(
size_t i = 0; i < indices.size(); i++) {
159 outputAsMB->SetBlock(i, tuple);
161 size_t tupleIndex = (size_t)indices[i];
162 for(
int c = 0; c < nComponents; c++) {
164 = vtkMultiBlockDataSet::SafeDownCast(inputAsMB->GetBlock(c));
166 this->
printErr(
"Block Tuple Mode requires a vtkMultiBlockDataSet "
167 "that contains vtkMultiBlockDataSets as input.");
170 if(tupleIndex >= blockAsMB->GetNumberOfBlocks()) {
172 "Index out of range (" + std::to_string(tupleIndex) +
"/"
173 + std::to_string(blockAsMB->GetNumberOfBlocks()) +
").");
177 auto block = blockAsMB->GetBlock(tupleIndex);
180 copy->ShallowCopy(block);
181 tuple->SetBlock(c, copy);
185 for(
size_t i = 0; i < indices.size(); i++) {
186 size_t blockIndex = (size_t)indices[i];
187 if(blockIndex >= inputAsMB->GetNumberOfBlocks()) {
188 this->
printErr(
"Index out of range (" + std::to_string(blockIndex)
189 +
"/" + std::to_string(inputAsMB->GetNumberOfBlocks())
194 auto block = inputAsMB->GetBlock(blockIndex);
196 copy->ShallowCopy(block);
197 outputAsMB->SetBlock(i, copy);
202 if(indices.size() != 1) {
204 "If OutputType is specified then only one block can be extracted.");
208 size_t blockIndex = (size_t)indices[0];
209 if(blockIndex < inputAsMB->GetNumberOfBlocks()) {
210 auto block = inputAsMB->GetBlock(blockIndex);
211 if(output->GetDataObjectType() != block->GetDataObjectType()) {
212 this->
printErr(
"BlockType does not match OutputType");
215 output->ShallowCopy(block);
218 this->
printErr(
"Index out of range (" + std::to_string(blockIndex) +
"/"
219 + std::to_string(inputAsMB->GetNumberOfBlocks()) +
").");
225 auto inFD = input->GetFieldData();
226 auto outFD = output->GetFieldData();
227 for(
int i = 0; i < inFD->GetNumberOfArrays(); i++)
228 outFD->AddArray(inFD->GetArray(i));
230 this->
printMsg(
"Extracting blocks [" + indicesString +
"]", 1);
236 vtkDataObject *input,
237 const std::vector<double> &indices)
const {
239 std::string indicesString =
"";
240 doubleVectorToString(indicesString, indices);
244 {{
"Extraction Mode",
"Rows"}, {
"Indices",
"[" + indicesString +
"]"}});
249 this->
printMsg(
"Extracting rows [" + indicesString +
"]", 0,
252 size_t nValues = indices.size();
253 auto inputAsT = vtkTable::SafeDownCast(input);
254 auto outputAsT = vtkTable::SafeDownCast(output);
255 if(!inputAsT || !outputAsT) {
256 this->
printErr(
"Row mode requires 'vtkTable' input/output.");
260 size_t nRows = inputAsT->GetNumberOfRows();
261 size_t nCols = inputAsT->GetNumberOfColumns();
263 for(
size_t j = 0; j < nValues; j++)
264 if(((
size_t)indices[j]) >= nRows || indices[j] < 0) {
265 this->
printErr(
"Index out of range (" + std::to_string((
size_t)indices[j])
266 +
"/" + std::to_string(nRows) +
").");
271 for(
size_t i = 0; i < nCols; i++) {
272 auto iColumn = inputAsT->GetColumn(i);
276 oColumn->SetName(iColumn->GetName());
277 oColumn->SetNumberOfComponents(iColumn->GetNumberOfComponents());
278 oColumn->SetNumberOfTuples(nValues);
279 for(
size_t j = 0; j < nValues; j++)
280 oColumn->SetTuple(j, indices[j], iColumn);
282 outputAsT->AddColumn(oColumn);
285 outputAsT->GetFieldData()->ShallowCopy(inputAsT->GetFieldData());
288 "Extracting rows [" + indicesString +
"]", 1, t.
getElapsedTime());
293template <
typename DT>
296 const size_t &nValues,
298 const std::vector<DT> &min,
299 const std::vector<DT> &max,
300 const size_t &threadNumber) {
301 const size_t nPivotValues = min.size();
303#ifdef TTK_ENABLE_OPENMP
304#pragma omp parallel for num_threads(threadNumber)
306 for(
size_t i = 0; i < nValues; i++) {
307 const DT &v = values[i];
309 bool hasToBeMarked =
false;
310 for(
size_t j = 0; j < nPivotValues; j++) {
311 if(min[j] <= v && v <= max[j]) {
312 hasToBeMarked =
true;
317 mask[i] = hasToBeMarked ? 1 : 0;
324template <
typename DT>
327 const std::vector<double> &pivotValues,
328 const size_t &nValues,
331 const size_t &threadNumber) {
333 const size_t nPivotValues = pivotValues.size();
334 std::vector<DT> pivotValuesMin(nPivotValues);
335 std::vector<DT> pivotValuesMax(nPivotValues);
337 const DT delta = std::numeric_limits<DT>::is_integer
339 : std::numeric_limits<DT>::epsilon();
341 for(
size_t i = 0; i < nPivotValues; i++) {
343 switch(validationMode) {
345 pivotValuesMin[i] = std::numeric_limits<DT>::lowest();
346 pivotValuesMax[i] = ((DT)pivotValues[i]) - delta;
351 pivotValuesMin[i] = std::numeric_limits<DT>::lowest();
352 pivotValuesMax[i] = ((DT)pivotValues[i]);
358 pivotValuesMin[i] = ((DT)pivotValues[i]);
359 pivotValuesMax[i] = ((DT)pivotValues[i]);
364 pivotValuesMin[i] = ((DT)pivotValues[i]);
365 pivotValuesMax[i] = std::numeric_limits<DT>::max();
370 pivotValuesMin[i] = ((DT)pivotValues[i]) + delta;
371 pivotValuesMax[i] = std::numeric_limits<DT>::max();
377 int status = computeMask_<DT>(
378 mask, nValues, values, pivotValuesMin, pivotValuesMax, threadNumber);
381 for(
size_t i = 0; i < nValues; i++)
382 mask[i] = mask[i] == 0 ? 1 : 0;
388 vtkDataObject *input,
389 const std::vector<double> &expressionValues) {
396 auto inputAsDS = vtkDataSet::SafeDownCast(input);
397 auto outputAsDS = vtkDataSet::SafeDownCast(output);
398 if(!inputAsDS || !outputAsDS) {
399 this->
printErr(
"Masks can only be computed on vtkDataSet inputs.");
404 auto inputArray = this->GetInputArrayToProcess(0, input);
405 if(!inputArray || inputArray->GetNumberOfComponents() != 1) {
406 this->
printErr(
"Unable to retrieve input scalar array.");
409 std::string inputArrayName = inputArray->GetName();
410 const int inputArrayAssociation = this->GetInputArrayAssociation(0, input);
411 if(inputArrayAssociation != 0 && inputArrayAssociation != 1) {
412 this->
printErr(
"Geometry extraction requires point or cell data.");
415 const bool isPointDataArray = this->GetInputArrayAssociation(0, input) == 0;
418 std::string expressionValuesString =
"";
419 doubleVectorToString(expressionValuesString, expressionValues);
420 const std::string ValidationModeS[6] = {
"<",
"<=",
"==",
"!=",
">=",
">"};
421 std::string msg =
"Computing Mask: '" + inputArrayName +
"' "
422 + ValidationModeS[
static_cast<int>(this->ValidationMode)]
423 +
" [" + expressionValuesString +
"]";
428 const size_t nInPoints = inputAsDS->GetNumberOfPoints();
429 const size_t nInCells = inputAsDS->GetNumberOfCells();
430 const size_t nOutValues = isPointDataArray ? nInPoints : nInCells;
433 maskArray->SetName(
"Mask");
434 maskArray->SetNumberOfTuples(nOutValues);
435 auto maskArrayData = ttkUtils::GetPointer<signed char>(maskArray);
439 switch(inputArray->GetDataType()) {
441 status = computeMask<VTK_TT>(maskArrayData, expressionValues, nOutValues,
442 ttkUtils::GetPointer<VTK_TT>(inputArray),
446 this->
printErr(
"Unable to compute mask");
451 outputAsDS->ShallowCopy(inputAsDS);
453 outputAsDS->GetPointData()->AddArray(maskArray);
455 outputAsDS->GetCellData()->AddArray(maskArray);
463 vtkDataObject *input,
464 const std::vector<double> &expressionValues) {
466 auto inputAsDS = vtkDataSet::SafeDownCast(input);
467 auto outputAsDS = vtkDataSet::SafeDownCast(output);
468 if(!inputAsDS || !outputAsDS) {
469 this->
printErr(
"Geometry mode requires vtkDataSet input.");
475 if(!this->
AddMaskArray(maskOutput, inputAsDS, expressionValues))
479 outputAsDS->ShallowCopy(maskOutput);
485 auto outputAsUG = vtkUnstructuredGrid::SafeDownCast(output);
488 "Geometry Extraction requires vtkUnstructuredGrid input/output");
492 const bool isPointDataArray = this->GetInputArrayAssociation(0, input) == 0;
495 threshold->SetInputDataObject(maskOutput);
496 threshold->SetInputArrayToProcess(
497 0, 0, 0, isPointDataArray ? 0 : 1,
"Mask");
498#if VTK_VERSION_NUMBER < VTK_VERSION_CHECK(9, 2, 0)
499 threshold->ThresholdByUpper(0.5);
501 threshold->SetThresholdFunction(vtkThreshold::THRESHOLD_UPPER);
502 threshold->SetUpperThreshold(0.5);
507 outputAsDS->ShallowCopy(threshold->GetOutput());
510 outputAsDS->GetPointData()->RemoveArray(
"Mask");
512 outputAsDS->GetCellData()->RemoveArray(
"Mask");
523 vtkDataArray *valueArray) {
524 std::set<DT> uniqueValues;
526 if(uniqueValueArray->GetDataType() != valueArray->GetDataType())
530 = valueArray->GetNumberOfTuples() * valueArray->GetNumberOfComponents();
531 auto valueArrayData = ttkUtils::GetPointer<DT>(valueArray);
532 for(
size_t i = 0; i < nValues; i++)
533 uniqueValues.insert(valueArrayData[i]);
535 size_t nUniqueValues = uniqueValues.size();
537 uniqueValueArray->SetNumberOfComponents(1);
538 uniqueValueArray->SetNumberOfTuples(nUniqueValues);
540 auto uniqueValueArrayData = ttkUtils::GetPointer<DT>(uniqueValueArray);
541 auto it = uniqueValues.begin();
542 for(
size_t i = 0; i < nUniqueValues; i++) {
543 uniqueValueArrayData[i] = *it;
551 vtkDataObject *input,
552 const std::vector<double> &indices) {
553 size_t nValues = indices.size();
555 auto inputArray = this->GetInputArrayToProcess(0, input);
557 this->
printErr(
"Unable to retrieve input array.");
560 std::string inputArrayName = inputArray->GetName();
562 output->ShallowCopy(input);
564 if(this->ExtractUniqueValues) {
566 this->
printMsg(
"Extracting unique values from '" + inputArrayName +
"'", 0,
569 auto uniqueValueArray
571 uniqueValueArray->SetName(
572 (
"Unique" + std::string(inputArrayName.data())).data());
575 switch(inputArray->GetDataType()) {
577 status = createUniqueValueArray<VTK_TT>(uniqueValueArray, inputArray));
580 this->
printErr(
"Unable to compute unique values.");
584 output->GetFieldData()->AddArray(uniqueValueArray);
586 this->
printMsg(
"Extracting unique values from '" + inputArrayName +
"'", 1,
590 std::string indicesString =
"";
591 doubleVectorToString(indicesString, indices);
593 this->
printMsg(
"Extracting values at [" + indicesString +
"] from '"
594 + inputArrayName +
"'",
599 outputArray->SetName(
600 (
"Extracted" + std::string(inputArray->GetName())).data());
601 outputArray->SetNumberOfComponents(inputArray->GetNumberOfComponents());
602 outputArray->SetNumberOfTuples(indices.size());
604 for(
size_t i = 0; i < nValues; i++) {
605 size_t index = (size_t)indices[i];
606 size_t inputArraySize = inputArray->GetNumberOfTuples();
607 if(index < inputArraySize) {
608 outputArray->SetTuple(i, index, inputArray);
610 this->
printErr(
"Index out of range (" + std::to_string(i) +
"/"
611 + std::to_string(inputArraySize) +
").");
616 output->GetFieldData()->AddArray(outputArray);
618 this->
printMsg(
"Extracting values at [" + indicesString +
"] from '"
619 + inputArrayName +
"'",
627 vtkDataObject *input,
628 const std::vector<double> &indices) {
631 std::string indicesString;
632 doubleVectorToString(indicesString, indices);
633 this->
printMsg(
"Extracting array with idx [" + indicesString +
"] from "
634 + std::string(this->ArrayAttributeType == 0 ?
"point"
635 : this->ArrayAttributeType == 1 ?
"cell"
640 output->ShallowCopy(input);
642 auto outputAsDS = vtkDataSet::SafeDownCast(output);
644 this->
printErr(
"Array extraction requires vtkDataSet input.");
648 vtkFieldData *inputAttribute
649 = this->ArrayAttributeType == 0 ? outputAsDS->GetPointData()
650 : this->ArrayAttributeType == 1 ? outputAsDS->GetCellData()
651 : outputAsDS->GetFieldData();
653 if(indices.size() != 1) {
654 this->
printErr(
"Array extraction can only extract exactly one array.");
658 if(indices[0] < 0 || indices[0] >= inputAttribute->GetNumberOfArrays()) {
659 this->
printErr(
"Index out of bounds.");
663 auto inputArray = inputAttribute->GetArray(indices[0]);
665 copy->ShallowCopy(inputArray);
666 copy->SetName(this->OutputArrayName.data());
669 outputAttribute->AddArray(copy);
671 this->ArrayAttributeType == 0
672 ? outputAsDS->GetPointData()->ShallowCopy(outputAttribute)
673 : this->ArrayAttributeType == 1
674 ? outputAsDS->GetCellData()->ShallowCopy(outputAttribute)
675 : outputAsDS->GetFieldData()->ShallowCopy(outputAttribute);
677 this->
printMsg(
"Extracting array with indices [" + indicesString +
"] from "
678 + std::string(this->ArrayAttributeType == 0 ?
"point"
679 : this->ArrayAttributeType == 1 ?
"cell"
691 vtkInformationVector **inputVector,
692 vtkInformationVector *outputVector) {
694 auto input = vtkDataObject::GetData(inputVector[0]);
695 auto output = vtkDataObject::GetData(outputVector);
700 std::string finalExpressionString;
702 std::string errorMsg;
704 input->GetFieldData(), finalExpressionString,
711 std::vector<double> values;
714 auto mode = this->ExtractionMode;
716 if(input->IsA(
"vtkMultiBlockDataSet"))
718 else if(input->IsA(
"vtkTable"))
721 this->
printErr(
"Unable to automatically determine extraction mode.");
731 && input->IsA(
"vtkMultiBlockDataSet")) {
732 inputAsMB->ShallowCopy(input);
733 nBlocks = inputAsMB->GetNumberOfBlocks();
735 for(
size_t b = 0; b < nBlocks; b++) {
736 auto inputBlock = inputAsMB->GetBlock(b);
745 outputAsMB->SetBlock(b, outputBlock);
747 output->ShallowCopy(outputAsMB);
749 inputAsMB->SetBlock(0, input);
750 outputAsMB->SetBlock(0, output);
771 for(
size_t b = 0; b < nBlocks; b++)
773 outputAsMB->GetBlock(b), inputAsMB->GetBlock(b), values))
778 for(
size_t b = 0; b < nBlocks; b++)
780 outputAsMB->GetBlock(b), inputAsMB->GetBlock(b), values))
785 for(
size_t b = 0; b < nBlocks; b++)
787 outputAsMB->GetBlock(b), inputAsMB->GetBlock(b), values))
792 this->
printErr(
"Unsupported Extraction Mode");
#define TTK_FORCE_USE(x)
Force the compiler to use the function/method parameter.
#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()
static int replaceVariables(const std::string &iString, vtkFieldData *fieldData, std::string &oString, std::string &errorMsg)
static int stringListToDoubleVector(const std::string &iString, std::vector< double > &v)
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