Select input point from cluster rather than averaging.

This is a bit counterintuitive, but choosing a random point from each
cluster rather than averaging them gives a better visual result. The
averages poorly represent an surface that runs through the grid block and
tends to bias the output points towards the center of each block, creating
very noticeable grid artifacts that look blocky.
This commit is contained in:
Allison Vacanti 2017-09-07 17:16:50 -04:00
parent 28e76ddbfd
commit 5dee7c6a5d

@ -34,7 +34,6 @@
#include <vtkm/cont/DeviceAdapterAlgorithm.h>
#include <vtkm/cont/DynamicArrayHandle.h>
#include <vtkm/worklet/AverageByKey.h>
#include <vtkm/worklet/DispatcherMapField.h>
#include <vtkm/worklet/DispatcherMapTopology.h>
#include <vtkm/worklet/WorkletMapField.h>
@ -221,40 +220,6 @@ vtkm::cont::ArrayHandle<T> copyFromVec(vtkm::cont::ArrayHandle<vtkm::Vec<T, N>>
return result;
}
template <typename KeyArrayIn, typename KeyArrayOut, typename DeviceAdapter>
class AverageByKeyDynamicValue
{
private:
typedef typename KeyArrayIn::ValueType KeyType;
public:
VTKM_CONT
AverageByKeyDynamicValue(const KeyArrayIn& inputKeys,
KeyArrayOut& outputKeys,
vtkm::cont::DynamicArrayHandle& outputValues)
: InputKeys(inputKeys)
, OutputKeys(&outputKeys)
, OutputValues(&outputValues)
{
}
template <typename ValueArrayIn>
VTKM_CONT void operator()(const ValueArrayIn& coordinates) const
{
typedef typename ValueArrayIn::ValueType ValueType;
vtkm::cont::ArrayHandle<ValueType> outArray;
vtkm::worklet::AverageByKey::Run(
InputKeys, coordinates, *(this->OutputKeys), outArray, DeviceAdapter());
*(this->OutputValues) = vtkm::cont::DynamicArrayHandle(outArray);
}
private:
KeyArrayIn InputKeys;
KeyArrayOut* OutputKeys;
vtkm::cont::DynamicArrayHandle* OutputValues;
};
} // namespace internal
struct VertexClustering
@ -504,17 +469,20 @@ public:
timer.Reset();
#endif
/// pass 2 : compute average point position for each cluster,
/// using pointCidArray as the key
///
vtkm::cont::ArrayHandle<vtkm::Id> pointCidArrayReduced;
vtkm::cont::DynamicArrayHandle repPointArray; // representative point
/// pass 2 : Reduce each cluster to a single point from the cluster.
/// Choosing a random point from the input gives a better visual
/// result than a simple average in the common case of surface
/// geometry, as the average results in a blocky output with
/// obvious grid artifacts.
vtkm::cont::DynamicArrayHandle repPointArray; // representative points
vtkm::cont::ArrayHandle<vtkm::Id> repPointCidArray; // rep point cluster ids
{
auto tmp = internal::SortAndUniqueIndices(pointCidArray, DeviceAdapter());
repPointCidArray = internal::ConcretePermutationArray(tmp, pointCidArray, DeviceAdapter());
internal::AverageByKeyDynamicValue<vtkm::cont::ArrayHandle<vtkm::Id>,
vtkm::cont::ArrayHandle<vtkm::Id>,
DeviceAdapter>
averageByKey(pointCidArray, pointCidArrayReduced, repPointArray);
CastAndCall(coordinates, averageByKey);
internal::DynamicPermutationFunctor<DeviceAdapter> functor(tmp, repPointArray);
CastAndCall(coordinates, functor);
}
#ifdef __VTKM_VERTEX_CLUSTERING_BENCHMARK
std::cout << "Time after averaging (s): " << timer.GetElapsedTime() << std::endl;
@ -564,10 +532,10 @@ public:
cidIndexArray.PrepareForOutput(gridInfo.dim[0] * gridInfo.dim[1] * gridInfo.dim[2],
DeviceAdapter());
vtkm::worklet::DispatcherMapField<IndexingWorklet, DeviceAdapter>().Invoke(pointCidArrayReduced,
vtkm::worklet::DispatcherMapField<IndexingWorklet, DeviceAdapter>().Invoke(repPointCidArray,
cidIndexArray);
pointCidArrayReduced.ReleaseResources();
repPointCidArray.ReleaseResources();
///
/// map: convert each triangle vertices from original point id to the new cluster indexes