mirror of
https://gitlab.kitware.com/vtk/vtk-m
synced 2024-10-05 01:49:02 +00:00
Allow floating-point isovalues for contours of integer fields
The flying edges version of the contouring filter converted the isovalues provided into the same type as the field. This is fine for a floating point field, but for an integer field the isovalue was truncated to the nearest integer. This is problematic because it is common to provide a fractional isovalue (usually N + 0.5) for integer fields to avoid degenerate cases of the contour intersecting vertices. It also means the behavior changes between an integer type that is directly supported (like a `signed char`) or an integer type that is not directly supported and converted to a floating point field (like potentially a `char`). This change updates the worklets to allow the isovalue to have a different type than the field and to always use a floating point type for the isovalue.
This commit is contained in:
parent
4571db1249
commit
8fc341e716
17
docs/changelog/contour-int-isovalue.md
Normal file
17
docs/changelog/contour-int-isovalue.md
Normal file
@ -0,0 +1,17 @@
|
||||
# Allow floating-point isovalues for contours of integer fields
|
||||
|
||||
The flying edges version of the contouring filter converted the isovalues
|
||||
provided into the same type as the field. This is fine for a floating point
|
||||
field, but for an integer field the isovalue was truncated to the nearest
|
||||
integer.
|
||||
|
||||
This is problematic because it is common to provide a fractional isovalue
|
||||
(usually N + 0.5) for integer fields to avoid degenerate cases of the
|
||||
contour intersecting vertices. It also means the behavior changes between
|
||||
an integer type that is directly supported (like a `signed char`) or an
|
||||
integer type that is not directly supported and converted to a floating
|
||||
point field (like potentially a `char`).
|
||||
|
||||
This change updates the worklets to allow the isovalue to have a different
|
||||
type than the field and to always use a floating point type for the
|
||||
isovalue.
|
@ -63,10 +63,11 @@ vtkm::cont::DataSet ContourFlyingEdges::DoExecute(const vtkm::cont::DataSet& inD
|
||||
auto resolveFieldType = [&](const auto& concrete) {
|
||||
// use std::decay to remove const ref from the decltype of concrete.
|
||||
using T = typename std::decay_t<decltype(concrete)>::ValueType;
|
||||
std::vector<T> ivalues(this->IsoValues.size());
|
||||
using IVType = std::conditional_t<(sizeof(T) > 4), vtkm::Float64, vtkm::FloatDefault>;
|
||||
std::vector<IVType> ivalues(this->IsoValues.size());
|
||||
for (std::size_t i = 0; i < ivalues.size(); ++i)
|
||||
{
|
||||
ivalues[i] = static_cast<T>(this->IsoValues[i]);
|
||||
ivalues[i] = static_cast<IVType>(this->IsoValues[i]);
|
||||
}
|
||||
|
||||
if (this->GenerateNormals && !this->GetComputeFastNormals())
|
||||
|
@ -66,13 +66,14 @@ public:
|
||||
void ReleaseCellMapArrays() { this->SharedState.CellIdMap.ReleaseResources(); }
|
||||
|
||||
// Filter called without normals generation
|
||||
template <typename ValueType,
|
||||
template <typename IVType,
|
||||
typename ValueType,
|
||||
typename CoordsType,
|
||||
typename StorageTagField,
|
||||
typename CoordinateType,
|
||||
typename StorageTagVertices>
|
||||
vtkm::cont::CellSetSingleType<> Run(
|
||||
const std::vector<ValueType>& isovalues,
|
||||
const std::vector<IVType>& isovalues,
|
||||
const vtkm::cont::CellSetStructured<3>& cells,
|
||||
const CoordsType& coordinateSystem,
|
||||
const vtkm::cont::ArrayHandle<ValueType, StorageTagField>& input,
|
||||
@ -87,14 +88,15 @@ public:
|
||||
}
|
||||
|
||||
// Filter called with normals generation
|
||||
template <typename ValueType,
|
||||
template <typename IVType,
|
||||
typename ValueType,
|
||||
typename CoordsType,
|
||||
typename StorageTagField,
|
||||
typename CoordinateType,
|
||||
typename StorageTagVertices,
|
||||
typename StorageTagNormals>
|
||||
vtkm::cont::CellSetSingleType<> Run(
|
||||
const std::vector<ValueType>& isovalues,
|
||||
const std::vector<IVType>& isovalues,
|
||||
const vtkm::cont::CellSetStructured<3>& cells,
|
||||
const CoordsType& coordinateSystem,
|
||||
const vtkm::cont::ArrayHandle<ValueType, StorageTagField>& input,
|
||||
|
@ -40,7 +40,8 @@ vtkm::Id extend_by(vtkm::cont::ArrayHandle<T, S>& handle, vtkm::Id size)
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
template <typename ValueType,
|
||||
template <typename IVType,
|
||||
typename ValueType,
|
||||
typename CoordsType,
|
||||
typename StorageTagField,
|
||||
typename StorageTagVertices,
|
||||
@ -50,7 +51,7 @@ template <typename ValueType,
|
||||
vtkm::cont::CellSetSingleType<> execute(
|
||||
const vtkm::cont::CellSetStructured<3>& cells,
|
||||
const CoordsType coordinateSystem,
|
||||
const std::vector<ValueType>& isovalues,
|
||||
const std::vector<IVType>& isovalues,
|
||||
const vtkm::cont::ArrayHandle<ValueType, StorageTagField>& inputField,
|
||||
vtkm::cont::ArrayHandle<vtkm::Vec<CoordinateType, 3>, StorageTagVertices>& points,
|
||||
vtkm::cont::ArrayHandle<vtkm::Vec<NormalType, 3>, StorageTagNormals>& normals,
|
||||
@ -82,7 +83,7 @@ vtkm::cont::CellSetSingleType<> execute(
|
||||
{
|
||||
auto multiContourCellOffset = sharedState.CellIdMap.GetNumberOfValues();
|
||||
auto multiContourPointOffset = sharedState.InterpolationWeights.GetNumberOfValues();
|
||||
ValueType isoval = isovalues[i];
|
||||
IVType isoval = isovalues[i];
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// PASS 1: Process all of the voxel edges that compose each row. Determine the
|
||||
@ -100,7 +101,7 @@ vtkm::cont::CellSetSingleType<> execute(
|
||||
// Additionally GPU's does significantly better when you do an initial fill
|
||||
// and write only non-below values
|
||||
//
|
||||
ComputePass1<ValueType> worklet1(isoval, pdims);
|
||||
ComputePass1<IVType> worklet1(isoval, pdims);
|
||||
vtkm::cont::TryExecuteOnDevice(invoke.GetDevice(),
|
||||
launchComputePass1{},
|
||||
worklet1,
|
||||
|
@ -147,9 +147,13 @@ struct ComputePass1 : public vtkm::worklet::WorkletVisitPointsWithCells
|
||||
|
||||
struct launchComputePass1
|
||||
{
|
||||
template <typename DeviceAdapterTag, typename T, typename StorageTagField, typename... Args>
|
||||
template <typename DeviceAdapterTag,
|
||||
typename IVType,
|
||||
typename T,
|
||||
typename StorageTagField,
|
||||
typename... Args>
|
||||
VTKM_CONT bool LaunchXAxis(DeviceAdapterTag device,
|
||||
const ComputePass1<T>& worklet,
|
||||
const ComputePass1<IVType>& worklet,
|
||||
const vtkm::cont::ArrayHandle<T, StorageTagField>& inputField,
|
||||
vtkm::cont::ArrayHandle<vtkm::UInt8>& edgeCases,
|
||||
vtkm::cont::CellSetStructured<2>& metaDataMesh2D,
|
||||
@ -162,9 +166,13 @@ struct launchComputePass1
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename DeviceAdapterTag, typename T, typename StorageTagField, typename... Args>
|
||||
template <typename DeviceAdapterTag,
|
||||
typename IVType,
|
||||
typename T,
|
||||
typename StorageTagField,
|
||||
typename... Args>
|
||||
VTKM_CONT bool LaunchYAxis(DeviceAdapterTag device,
|
||||
const ComputePass1<T>& worklet,
|
||||
const ComputePass1<IVType>& worklet,
|
||||
const vtkm::cont::ArrayHandle<T, StorageTagField>& inputField,
|
||||
vtkm::cont::ArrayHandle<vtkm::UInt8>& edgeCases,
|
||||
vtkm::cont::CellSetStructured<2>& metaDataMesh2D,
|
||||
|
@ -42,6 +42,7 @@ struct launchComputePass4
|
||||
}
|
||||
|
||||
template <typename DeviceAdapterTag,
|
||||
typename IVType,
|
||||
typename T,
|
||||
typename CoordsType,
|
||||
typename StorageTagField,
|
||||
@ -50,7 +51,7 @@ struct launchComputePass4
|
||||
typename NormalType>
|
||||
VTKM_CONT bool LaunchXAxis(DeviceAdapterTag device,
|
||||
vtkm::Id vtkmNotUsed(newPointSize),
|
||||
T isoval,
|
||||
IVType isoval,
|
||||
CoordsType coordinateSystem,
|
||||
const vtkm::cont::ArrayHandle<T, StorageTagField>& inputField,
|
||||
vtkm::cont::ArrayHandle<vtkm::UInt8> edgeCases,
|
||||
@ -67,7 +68,7 @@ struct launchComputePass4
|
||||
vtkm::cont::Invoker invoke(device);
|
||||
if (sharedState.GenerateNormals)
|
||||
{
|
||||
ComputePass4XWithNormals<T> worklet4(
|
||||
ComputePass4XWithNormals<IVType> worklet4(
|
||||
isoval, this->PointDims, this->CellWriteOffset, this->PointWriteOffset);
|
||||
invoke(worklet4,
|
||||
metaDataMesh2D,
|
||||
@ -87,7 +88,7 @@ struct launchComputePass4
|
||||
}
|
||||
else
|
||||
{
|
||||
ComputePass4X<T> worklet4(
|
||||
ComputePass4X<IVType> worklet4(
|
||||
isoval, this->PointDims, this->CellWriteOffset, this->PointWriteOffset);
|
||||
invoke(worklet4,
|
||||
metaDataMesh2D,
|
||||
@ -109,6 +110,7 @@ struct launchComputePass4
|
||||
}
|
||||
|
||||
template <typename DeviceAdapterTag,
|
||||
typename IVType,
|
||||
typename T,
|
||||
typename CoordsType,
|
||||
typename StorageTagField,
|
||||
@ -117,7 +119,7 @@ struct launchComputePass4
|
||||
typename NormalType>
|
||||
VTKM_CONT bool LaunchYAxis(DeviceAdapterTag device,
|
||||
vtkm::Id newPointSize,
|
||||
T isoval,
|
||||
IVType isoval,
|
||||
CoordsType coordinateSystem,
|
||||
const vtkm::cont::ArrayHandle<T, StorageTagField>& inputField,
|
||||
vtkm::cont::ArrayHandle<vtkm::UInt8> edgeCases,
|
||||
@ -133,7 +135,7 @@ struct launchComputePass4
|
||||
{
|
||||
vtkm::cont::Invoker invoke(device);
|
||||
|
||||
ComputePass4Y<T> worklet4(
|
||||
ComputePass4Y<IVType> worklet4(
|
||||
isoval, this->PointDims, this->CellWriteOffset, this->PointWriteOffset);
|
||||
invoke(worklet4,
|
||||
metaDataMesh2D,
|
||||
@ -149,7 +151,8 @@ struct launchComputePass4
|
||||
sharedState.CellIdMap);
|
||||
|
||||
//This needs to be done on array handle view ( start = this->PointWriteOffset, len = newPointSize)
|
||||
ComputePass5Y<T> worklet5(this->PointDims, this->PointWriteOffset, sharedState.GenerateNormals);
|
||||
ComputePass5Y<IVType> worklet5(
|
||||
this->PointDims, this->PointWriteOffset, sharedState.GenerateNormals);
|
||||
|
||||
invoke(worklet5,
|
||||
vtkm::cont::make_ArrayHandleView(
|
||||
|
Loading…
Reference in New Issue
Block a user