// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen // SPDX-License-Identifier: BSD-3-Clause #include "vtkExtractTimeSteps.h" #include "vtkDataObject.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" #include "vtkStreamingDemandDrivenPipeline.h" #include #include #include VTK_ABI_NAMESPACE_BEGIN vtkStandardNewMacro(vtkExtractTimeSteps); vtkExtractTimeSteps::vtkExtractTimeSteps() : UseRange(false) , TimeStepInterval(1) , TimeEstimationMode(PREVIOUS_TIMESTEP) { this->Range[0] = 0; this->Range[1] = 0; } //------------------------------------------------------------------------------ void vtkExtractTimeSteps::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); int count = static_cast(this->TimeStepIndices.size()); os << indent << "Number of Time Steps: " << count << std::endl; if (count > 0) { std::set::iterator it = this->TimeStepIndices.begin(); os << indent << "Time Step Indices: " << *it++; for (int i = 1; i < std::min(count, 4); ++i) { os << ", " << *it++; } if (count > 9) { std::advance(it, count - 8); os << ", ... "; } while (it != this->TimeStepIndices.end()) { os << ", " << *it++; } os << std::endl; } os << indent << "UseRange: " << (this->UseRange ? "true" : "false") << std::endl; os << indent << "Range: " << this->Range[0] << ", " << this->Range[1] << std::endl; os << indent << "TimeStepInterval: " << this->TimeStepInterval << std::endl; os << indent << "TimeEstimationMode: "; switch (this->TimeEstimationMode) { case PREVIOUS_TIMESTEP: os << "Previous Timestep" << std::endl; break; case NEXT_TIMESTEP: os << "Next Timestep" << std::endl; break; case NEAREST_TIMESTEP: os << "Nearest Timestep" << std::endl; break; } } //------------------------------------------------------------------------------ void vtkExtractTimeSteps::AddTimeStepIndex(int timeStepIndex) { if (this->TimeStepIndices.insert(timeStepIndex).second) { this->Modified(); } } void vtkExtractTimeSteps::SetTimeStepIndices(int count, const int* timeStepIndices) { this->TimeStepIndices.clear(); this->TimeStepIndices.insert(timeStepIndices, timeStepIndices + count); this->Modified(); } void vtkExtractTimeSteps::GetTimeStepIndices(int* timeStepIndices) const { std::copy(this->TimeStepIndices.begin(), this->TimeStepIndices.end(), timeStepIndices); } void vtkExtractTimeSteps::GenerateTimeStepIndices(int begin, int end, int step) { if (step != 0) { this->TimeStepIndices.clear(); for (int i = begin; i < end; i += step) { this->TimeStepIndices.insert(i); } this->Modified(); } } namespace { void getTimeSteps(vtkInformation* inInfo, const std::set& timeStepIndices, bool useRange, int* range, int timeStepInterval, std::vector& outTimes) { double* inTimes = inInfo->Get(vtkStreamingDemandDrivenPipeline::TIME_STEPS()); int numTimes = inInfo->Length(vtkStreamingDemandDrivenPipeline::TIME_STEPS()); if (!useRange) { for (std::set::iterator it = timeStepIndices.begin(); it != timeStepIndices.end(); ++it) { if (*it >= 0 && *it < numTimes) { outTimes.push_back(inTimes[*it]); } } } else { for (int i = 0; i < numTimes; ++i) { if (i >= range[0] && i <= range[1]) { if ((i - range[0]) % timeStepInterval == 0) { outTimes.push_back(inTimes[i]); } } } } } } //------------------------------------------------------------------------------ int vtkExtractTimeSteps::RequestInformation( vtkInformation*, vtkInformationVector** inputVector, vtkInformationVector* outputVector) { // get the info objects vtkInformation* outInfo = outputVector->GetInformationObject(0); vtkInformation* inInfo = inputVector[0]->GetInformationObject(0); if (!this->TimeStepIndices.empty() && inInfo->Has(vtkStreamingDemandDrivenPipeline::TIME_STEPS())) { std::vector outTimes; getTimeSteps( inInfo, this->TimeStepIndices, this->UseRange, this->Range, this->TimeStepInterval, outTimes); if (!outTimes.empty()) { outInfo->Set(vtkStreamingDemandDrivenPipeline::TIME_STEPS(), outTimes.data(), static_cast(outTimes.size())); double range[2] = { outTimes.front(), outTimes.back() }; outInfo->Set(vtkStreamingDemandDrivenPipeline::TIME_RANGE(), range, 2); } } return 1; } //------------------------------------------------------------------------------ int vtkExtractTimeSteps::RequestUpdateExtent(vtkInformation* vtkNotUsed(request), vtkInformationVector** inputVector, vtkInformationVector* outputVector) { vtkInformation* inInfo = inputVector[0]->GetInformationObject(0); vtkInformation* outInfo = outputVector->GetInformationObject(0); if (outInfo->Has(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP())) { double updateTime = outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP()); std::vector outTimes; getTimeSteps( inInfo, this->TimeStepIndices, this->UseRange, this->Range, this->TimeStepInterval, outTimes); if (outTimes.empty()) { vtkErrorMacro("Input has no time steps."); return 0; } double inputTime; if (updateTime >= outTimes.back()) { inputTime = outTimes.back(); } else if (updateTime <= outTimes.front()) { inputTime = outTimes.front(); } else { auto gtindex = std::upper_bound(outTimes.begin(), outTimes.end(), updateTime); auto leindex = gtindex - 1; if (updateTime == *leindex) { inputTime = updateTime; } else { switch (this->TimeEstimationMode) { default: case PREVIOUS_TIMESTEP: inputTime = *leindex; break; case NEXT_TIMESTEP: inputTime = *gtindex; break; case NEAREST_TIMESTEP: if (std::abs(updateTime - *leindex) <= std::abs(*gtindex - updateTime)) { inputTime = *leindex; } else { inputTime = *gtindex; } break; } } } inInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP(), inputTime); } return 1; } //------------------------------------------------------------------------------ int vtkExtractTimeSteps::RequestData( vtkInformation*, vtkInformationVector** inputVector, vtkInformationVector* outputVector) { vtkDataObject* inData = vtkDataObject::GetData(inputVector[0], 0); vtkDataObject* outData = vtkDataObject::GetData(outputVector, 0); if (inData && outData) { outData->ShallowCopy(inData); } this->CheckAbort(); return 1; } VTK_ABI_NAMESPACE_END