diff --git a/vtkm/filter/MapFieldPermutation.cxx b/vtkm/filter/MapFieldPermutation.cxx index 62a908763..d7948fae6 100644 --- a/vtkm/filter/MapFieldPermutation.cxx +++ b/vtkm/filter/MapFieldPermutation.cxx @@ -11,16 +11,75 @@ #include #include +#include +#include -#include -#include #include +#include + #include namespace { +template +struct MapPermutationWorklet : vtkm::worklet::WorkletMapField +{ + T InvalidValue; + + explicit MapPermutationWorklet(T invalidValue) + : InvalidValue(invalidValue) + { + } + + using ControlSignature = void(FieldIn permutationIndex, WholeArrayIn input, FieldOut output); + + template + VTKM_EXEC void operator()(vtkm::Id permutationIndex, InputPortalType inputPortal, T& output) const + { + if ((permutationIndex >= 0) && (permutationIndex < inputPortal.GetNumberOfValues())) + { + output = inputPortal.Get(permutationIndex); + } + else + { + output = this->InvalidValue; + } + } +}; + +// For simplicity, the invalid value is specified as a single type (vtkm::Float64), and this is +// often a non-finite value, which is not well represented by integer types. This function does its +// best to find a reasonable cast for the value. +template +T CastInvalidValue(vtkm::Float64 invalidValue) +{ + using ComponentType = typename vtkm::VecTraits::BaseComponentType; + + if (std::is_same::NumericTag>::value) + { + // Casting to integer types + if (vtkm::IsFinite(invalidValue)) + { + return T(static_cast(invalidValue)); + } + else if (vtkm::IsInf(invalidValue) && (invalidValue > 0)) + { + return T(std::numeric_limits::max()); + } + else + { + return T(std::numeric_limits::min()); + } + } + else + { + // Not an integer type. Assume can be directly cast + return T(static_cast(invalidValue)); + } +} + struct DoMapFieldPermutation { bool CalledMap = false; @@ -28,11 +87,13 @@ struct DoMapFieldPermutation template void operator()(const vtkm::cont::ArrayHandle& inputArray, const vtkm::cont::ArrayHandle& permutation, - vtkm::cont::VariantArrayHandle& output) + vtkm::cont::VariantArrayHandle& output, + vtkm::Float64 invalidValue) { vtkm::cont::ArrayHandle outputArray; - vtkm::cont::ArrayCopy(vtkm::cont::make_ArrayHandlePermutation(permutation, inputArray), - outputArray); + MapPermutationWorklet worklet(CastInvalidValue(invalidValue)); + vtkm::cont::Invoker invoke; + invoke(worklet, permutation, inputArray, outputArray); output = vtkm::cont::VariantArrayHandle(outputArray); this->CalledMap = true; } @@ -42,12 +103,13 @@ struct DoMapFieldPermutation bool vtkm::filter::MapFieldPermutation(const vtkm::cont::Field& inputField, const vtkm::cont::ArrayHandle& permutation, - vtkm::cont::Field& outputField) + vtkm::cont::Field& outputField, + vtkm::Float64 invalidValue) { vtkm::cont::VariantArrayHandle outputArray; DoMapFieldPermutation functor; inputField.GetData().ResetTypes().CastAndCall( - vtkm::filter::PolicyDefault::StorageList{}, functor, permutation, outputArray); + vtkm::filter::PolicyDefault::StorageList{}, functor, permutation, outputArray, invalidValue); if (functor.CalledMap) { outputField = vtkm::cont::Field(inputField.GetName(), inputField.GetAssociation(), outputArray); @@ -61,10 +123,12 @@ bool vtkm::filter::MapFieldPermutation(const vtkm::cont::Field& inputField, bool vtkm::filter::MapFieldPermutation(const vtkm::cont::Field& inputField, const vtkm::cont::ArrayHandle& permutation, - vtkm::cont::DataSet& outputData) + vtkm::cont::DataSet& outputData, + vtkm::Float64 invalidValue) { vtkm::cont::Field outputField; - bool success = vtkm::filter::MapFieldPermutation(inputField, permutation, outputField); + bool success = + vtkm::filter::MapFieldPermutation(inputField, permutation, outputField, invalidValue); if (success) { outputData.AddField(outputField); diff --git a/vtkm/filter/MapFieldPermutation.h b/vtkm/filter/MapFieldPermutation.h index cd62d17d5..7a4fc168c 100644 --- a/vtkm/filter/MapFieldPermutation.h +++ b/vtkm/filter/MapFieldPermutation.h @@ -39,10 +39,15 @@ namespace filter /// `true`, then the results in `outputField` are valid. If it is `false`, then `outputField` /// should not be used. /// +/// If an invalid index is given in the permutation array (i.e. less than 0 or greater than the +/// size of the array), then the resulting outputField will be given `invalidValue` (converted as +/// best as possible to the correct data type). +/// VTKM_FILTER_EXPORT VTKM_CONT bool MapFieldPermutation( const vtkm::cont::Field& inputField, const vtkm::cont::ArrayHandle& permutation, - vtkm::cont::Field& outputField); + vtkm::cont::Field& outputField, + vtkm::Float64 invalidValue = vtkm::Nan()); /// \brief Maps a field by permuting it by a given index array. /// @@ -62,10 +67,15 @@ VTKM_FILTER_EXPORT VTKM_CONT bool MapFieldPermutation( /// `true`, then `outputData` has the permuted field. If it is `false`, then the field is not /// placed in `outputData`. /// +/// If an invalid index is given in the permutation array (i.e. less than 0 or greater than the +/// size of the array), then the resulting outputField will be given `invalidValue` (converted as +/// best as possible to the correct data type). +/// VTKM_FILTER_EXPORT VTKM_CONT bool MapFieldPermutation( const vtkm::cont::Field& inputField, const vtkm::cont::ArrayHandle& permutation, - vtkm::cont::DataSet& outputData); + vtkm::cont::DataSet& outputData, + vtkm::Float64 invalidValue = vtkm::Nan()); } } // namespace vtkm::filter