2015-06-18 17:07:31 +00:00
|
|
|
//============================================================================
|
|
|
|
// Copyright (c) Kitware, Inc.
|
|
|
|
// All rights reserved.
|
|
|
|
// See LICENSE.txt for details.
|
|
|
|
// This software is distributed WITHOUT ANY WARRANTY; without even
|
|
|
|
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
|
|
// PURPOSE. See the above copyright notice for more information.
|
|
|
|
//
|
|
|
|
// Copyright 2014 Sandia Corporation.
|
|
|
|
// Copyright 2014 UT-Battelle, LLC.
|
|
|
|
// Copyright 2014 Los Alamos National Security.
|
|
|
|
//
|
|
|
|
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
|
|
|
|
// the U.S. Government retains certain rights in this software.
|
|
|
|
//
|
|
|
|
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
|
|
|
|
// Laboratory (LANL), the U.S. Government retains certain rights in
|
|
|
|
// this software.
|
|
|
|
//============================================================================
|
|
|
|
#ifndef vtk_m_worklet_VertexClustering_h
|
|
|
|
#define vtk_m_worklet_VertexClustering_h
|
|
|
|
|
2015-06-25 15:43:29 +00:00
|
|
|
#include <numeric>
|
|
|
|
|
2015-06-19 20:30:53 +00:00
|
|
|
#include <vtkm/cont/ArrayHandle.h>
|
|
|
|
#include <vtkm/cont/ArrayHandleCounting.h>
|
|
|
|
#include <vtkm/cont/ArrayHandlePermutation.h>
|
|
|
|
|
|
|
|
#include <vtkm/cont/DynamicArrayHandle.h>
|
|
|
|
#include <vtkm/Pair.h>
|
|
|
|
#include <vtkm/worklet/DispatcherMapField.h>
|
|
|
|
#include <vtkm/worklet/WorkletMapField.h>
|
|
|
|
#include <vtkm/cont/DeviceAdapterAlgorithm.h>
|
|
|
|
#include <vtkm/cont/ArrayHandleConstant.h>
|
|
|
|
#include <vtkm/cont/ArrayHandleCompositeVector.h>
|
|
|
|
|
|
|
|
#include <vtkm/cont/Field.h>
|
|
|
|
#include <vtkm/cont/ExplicitConnectivity.h>
|
|
|
|
#include <vtkm/cont/DataSet.h>
|
|
|
|
|
|
|
|
#include <vtkm/worklet/AverageByKey.h>
|
|
|
|
|
2015-06-25 14:52:02 +00:00
|
|
|
//#define __VTKM_VERTEX_CLUSTERING_BENCHMARK
|
|
|
|
//#include <vtkm/cont/Timer.h>
|
2015-06-24 19:13:16 +00:00
|
|
|
|
2015-06-19 18:23:20 +00:00
|
|
|
namespace vtkm{ namespace worklet
|
|
|
|
{
|
2015-06-18 17:07:31 +00:00
|
|
|
|
2015-06-19 20:30:53 +00:00
|
|
|
template <class DeviceAdapter>
|
2015-06-24 19:52:56 +00:00
|
|
|
struct VertexClustering{
|
2015-06-19 20:30:53 +00:00
|
|
|
|
|
|
|
typedef vtkm::Vec<vtkm::Float32,3> Vector3;
|
|
|
|
typedef Vector3 PointType;
|
|
|
|
|
|
|
|
struct GridInfo
|
|
|
|
{
|
|
|
|
int dim[3];
|
|
|
|
Vector3 origin;
|
2015-06-25 15:46:28 +00:00
|
|
|
vtkm::Float64 grid_width;
|
|
|
|
vtkm::Float64 inv_grid_width; // = 1/grid_width
|
2015-06-19 20:30:53 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// input: points output: cid of the points
|
|
|
|
class MapPointsWorklet : public vtkm::worklet::WorkletMapField {
|
|
|
|
private:
|
2015-06-24 19:52:56 +00:00
|
|
|
//const VTKM_EXEC_CONSTANT_EXPORT GridInfo grid;
|
2015-06-24 20:35:11 +00:00
|
|
|
GridInfo grid;
|
2015-06-25 15:43:29 +00:00
|
|
|
|
|
|
|
VTKM_EXEC_EXPORT
|
|
|
|
vtkm::Id min(vtkm::Id a, vtkm::Id b) const {
|
|
|
|
return (a<b)?a:b;
|
|
|
|
}
|
2015-06-19 20:30:53 +00:00
|
|
|
public:
|
|
|
|
typedef void ControlSignature(FieldIn<> , FieldOut<>);
|
|
|
|
typedef void ExecutionSignature(_1, _2);
|
|
|
|
|
2015-06-24 20:35:11 +00:00
|
|
|
VTKM_CONT_EXPORT
|
2015-06-19 20:30:53 +00:00
|
|
|
MapPointsWorklet(const GridInfo &grid_)
|
|
|
|
: grid(grid_)
|
2015-06-25 15:43:29 +00:00
|
|
|
{ }
|
2015-06-19 20:30:53 +00:00
|
|
|
|
|
|
|
/// determine grid resolution for clustering
|
|
|
|
VTKM_EXEC_EXPORT
|
|
|
|
vtkm::Id get_cluster_id( const Vector3 &p) const
|
|
|
|
{
|
|
|
|
Vector3 p_rel = (p - grid.origin) * grid.inv_grid_width;
|
2015-06-25 15:43:29 +00:00
|
|
|
vtkm::Id x = min((vtkm::Id)p_rel[0], grid.dim[0]-1);
|
|
|
|
vtkm::Id y = min((vtkm::Id)p_rel[1], grid.dim[1]-1);
|
|
|
|
vtkm::Id z = min((vtkm::Id)p_rel[2], grid.dim[2]-1);
|
2015-06-19 20:30:53 +00:00
|
|
|
return x + grid.dim[0] * (y + grid.dim[1] * z); // get a unique hash value
|
|
|
|
}
|
|
|
|
|
|
|
|
VTKM_EXEC_EXPORT
|
|
|
|
void operator()(const PointType &point, vtkm::Id &cid) const
|
|
|
|
{
|
|
|
|
cid = get_cluster_id(point);
|
|
|
|
VTKM_ASSERT_CONT(cid>=0); // the id could overflow if too many cells
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class MapCellsWorklet: public vtkm::worklet::WorkletMapField {
|
|
|
|
typedef typename vtkm::cont::ArrayHandle<vtkm::Id> IdArrayHandle;
|
|
|
|
typedef typename IdArrayHandle::ExecutionTypes<DeviceAdapter>::PortalConst IdPortalType;
|
|
|
|
IdPortalType pointIdPortal;
|
|
|
|
IdPortalType pointCidPortal;
|
|
|
|
IdPortalType numIndicesPortal;
|
|
|
|
public:
|
|
|
|
typedef void ControlSignature(FieldIn<> , FieldOut<>);
|
|
|
|
typedef void ExecutionSignature(_1, _2);
|
|
|
|
|
2015-06-24 20:35:11 +00:00
|
|
|
VTKM_CONT_EXPORT
|
2015-06-19 20:30:53 +00:00
|
|
|
MapCellsWorklet(
|
|
|
|
const IdArrayHandle &pointIdArray, // the given point Ids
|
|
|
|
const IdArrayHandle &pointCidArray) // the cluser ids each pointId will map to
|
|
|
|
: pointIdPortal(pointIdArray.PrepareForInput(DeviceAdapter()) ),
|
|
|
|
pointCidPortal( pointCidArray.PrepareForInput(DeviceAdapter()))
|
|
|
|
{ }
|
|
|
|
|
|
|
|
VTKM_EXEC_EXPORT
|
|
|
|
void operator()(const vtkm::Id &pointIdIndex, vtkm::Id3 &cid3) const
|
|
|
|
{
|
2015-06-25 15:43:29 +00:00
|
|
|
//VTKM_ASSERT_CONT(pointIdIndex % 3 == 0); // TODO: may ignore non-triangle cells
|
2015-06-19 20:30:53 +00:00
|
|
|
// assume it's a triangle
|
|
|
|
cid3[0] = pointCidPortal.Get( pointIdPortal.Get(pointIdIndex) );
|
|
|
|
cid3[1] = pointCidPortal.Get( pointIdPortal.Get(pointIdIndex+1) );
|
|
|
|
cid3[2] = pointCidPortal.Get( pointIdPortal.Get(pointIdIndex+2) );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/// pass 3
|
|
|
|
class IndexingWorklet : public vtkm::worklet::WorkletMapField
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
typedef typename vtkm::cont::ArrayHandle<vtkm::Id> IdArrayHandle;
|
|
|
|
private:
|
|
|
|
typedef typename IdArrayHandle::ExecutionTypes<DeviceAdapter>::Portal IdPortalType;
|
|
|
|
IdArrayHandle cidIndexArray;
|
|
|
|
IdPortalType cidIndexRaw;
|
|
|
|
public:
|
|
|
|
typedef void ControlSignature(FieldIn<>, FieldIn<>);
|
|
|
|
typedef void ExecutionSignature(_1, _2);
|
|
|
|
|
|
|
|
VTKM_CONT_EXPORT
|
2015-06-24 18:52:41 +00:00
|
|
|
IndexingWorklet( vtkm::Id n )
|
2015-06-19 20:30:53 +00:00
|
|
|
{
|
|
|
|
cidIndexRaw = cidIndexArray.PrepareForOutput(n, DeviceAdapter() );
|
|
|
|
}
|
|
|
|
|
|
|
|
VTKM_EXEC_EXPORT
|
|
|
|
void operator()(const vtkm::Id &counter, const vtkm::Id &cid) const
|
|
|
|
{
|
|
|
|
cidIndexRaw.Set(cid, counter);
|
|
|
|
}
|
|
|
|
|
|
|
|
VTKM_CONT_EXPORT
|
|
|
|
IdArrayHandle &getOutput()
|
|
|
|
{
|
|
|
|
return cidIndexArray;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class Cid2PointIdWorklet : public vtkm::worklet::WorkletMapField
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
typedef typename vtkm::cont::ArrayHandle<vtkm::Id> IdArrayHandle;
|
|
|
|
private:
|
|
|
|
typedef typename IdArrayHandle::ExecutionTypes<DeviceAdapter>::PortalConst IdPortalType;
|
|
|
|
const IdPortalType cidIndexRaw;
|
|
|
|
public:
|
|
|
|
typedef void ControlSignature(FieldIn<>, FieldOut<>);
|
|
|
|
typedef void ExecutionSignature(_1, _2);
|
|
|
|
|
|
|
|
VTKM_CONT_EXPORT
|
|
|
|
Cid2PointIdWorklet( IdArrayHandle &cidIndexArray )
|
|
|
|
: cidIndexRaw ( cidIndexArray.PrepareForInput(DeviceAdapter()) )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
VTKM_EXEC_EXPORT
|
|
|
|
void operator()(const vtkm::Id3 &cid3, vtkm::Id3 &pointId3) const
|
|
|
|
{
|
|
|
|
if (cid3[0]==cid3[1] || cid3[0]==cid3[2] || cid3[1]==cid3[2])
|
|
|
|
{
|
2015-06-25 15:43:29 +00:00
|
|
|
pointId3[0] = pointId3[1] = pointId3[2] = -1 ; // invalid cell to be removed
|
2015-06-19 20:30:53 +00:00
|
|
|
} else {
|
|
|
|
pointId3[0] = cidIndexRaw.Get( cid3[0] );
|
|
|
|
pointId3[1] = cidIndexRaw.Get( cid3[1] );
|
|
|
|
pointId3[2] = cidIndexRaw.Get( cid3[2] );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class Id3Less{
|
|
|
|
public:
|
2015-06-25 15:43:29 +00:00
|
|
|
VTKM_EXEC_EXPORT
|
|
|
|
bool operator() (const vtkm::Id3 & a, const vtkm::Id3 & b) const
|
|
|
|
{
|
|
|
|
if (a[0] < 0) // invalid id: place at the last after sorting (comparing to 0 is faster than matching -1)
|
|
|
|
return false;
|
|
|
|
return b[0] < 0 ||
|
|
|
|
a[0] < b[0] ||
|
2015-06-25 19:33:25 +00:00
|
|
|
(a[0]==b[0] && a[1] < b[1]) ||
|
|
|
|
(a[0]==b[0] && a[1]==b[1] && a[2] < b[2]);
|
2015-06-25 15:43:29 +00:00
|
|
|
}
|
2015-06-19 20:30:53 +00:00
|
|
|
};
|
|
|
|
|
2015-06-24 18:52:41 +00:00
|
|
|
public:
|
2015-06-25 17:16:16 +00:00
|
|
|
|
2015-06-19 20:30:53 +00:00
|
|
|
///////////////////////////////////////////////////
|
|
|
|
/// \brief VertexClustering: Mesh simplification
|
|
|
|
/// \param ds : dataset
|
|
|
|
/// \param bounds: dataset bounds
|
|
|
|
/// \param nDivisions : number of max divisions per dimension
|
2015-06-25 17:16:16 +00:00
|
|
|
template <class StorageT, class StorageU, class StorageV>
|
|
|
|
void run(const vtkm::cont::ArrayHandle<PointType, StorageT> pointArray,
|
|
|
|
const vtkm::cont::ArrayHandle<vtkm::Id, StorageU> pointIdArray,
|
|
|
|
const vtkm::cont::ArrayHandle<vtkm::Id, StorageV> cellToConnectivityIndexArray,
|
|
|
|
const vtkm::Float64 bounds[6], vtkm::Id nDivisions,
|
|
|
|
vtkm::cont::ArrayHandle<PointType> &output_pointArray,
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Id3> &output_pointId3Array)
|
2015-06-19 20:30:53 +00:00
|
|
|
{
|
|
|
|
/// determine grid resolution for clustering
|
|
|
|
GridInfo gridInfo;
|
|
|
|
{
|
2015-06-25 15:46:28 +00:00
|
|
|
vtkm::Float64 res[3];
|
2015-06-19 20:30:53 +00:00
|
|
|
for (int i=0; i<3; i++)
|
|
|
|
res[i] = (bounds[i*2+1]-bounds[i*2])/nDivisions;
|
2015-06-24 18:52:41 +00:00
|
|
|
gridInfo.grid_width = std::max(res[0], std::max(res[1], res[2]));
|
2015-06-19 20:30:53 +00:00
|
|
|
|
2015-06-25 15:46:28 +00:00
|
|
|
vtkm::Float64 inv_grid_width = gridInfo.inv_grid_width = 1. / gridInfo.grid_width;
|
2015-06-19 20:30:53 +00:00
|
|
|
|
|
|
|
//printf("Bounds: %lf, %lf, %lf, %lf, %lf, %lf\n", bounds[0], bounds[1], bounds[2], bounds[3], bounds[4], bounds[5]);
|
2015-06-24 18:52:41 +00:00
|
|
|
gridInfo.dim[0] = (int)ceil((bounds[1]-bounds[0])*inv_grid_width);
|
|
|
|
gridInfo.dim[1] = (int)ceil((bounds[3]-bounds[2])*inv_grid_width);
|
|
|
|
gridInfo.dim[2] = (int)ceil((bounds[5]-bounds[4])*inv_grid_width);
|
|
|
|
|
|
|
|
// center the mesh in the grids
|
|
|
|
gridInfo.origin[0] = (vtkm::Float32) ((bounds[1]+bounds[0])*0.5 - gridInfo.grid_width*(gridInfo.dim[0])*.5);
|
|
|
|
gridInfo.origin[1] = (vtkm::Float32) ((bounds[3]+bounds[2])*0.5 - gridInfo.grid_width*(gridInfo.dim[1])*.5);
|
|
|
|
gridInfo.origin[2] = (vtkm::Float32) ((bounds[5]+bounds[4])*0.5 - gridInfo.grid_width*(gridInfo.dim[2])*.5);
|
2015-06-19 20:30:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//construct the scheduler that will execute all the worklets
|
2015-06-25 14:52:02 +00:00
|
|
|
#ifdef __VTKM_VERTEX_CLUSTERING_BENCHMARK
|
2015-06-19 20:30:53 +00:00
|
|
|
vtkm::cont::Timer<> timer;
|
2015-06-25 14:52:02 +00:00
|
|
|
#endif
|
2015-06-19 20:30:53 +00:00
|
|
|
|
|
|
|
//////////////////////////////////////////////
|
|
|
|
/// start algorithm
|
|
|
|
|
|
|
|
/// pass 1 : assign points with (cluster) ids based on the grid it falls in
|
|
|
|
///
|
|
|
|
/// map points
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Id> pointCidArray;
|
|
|
|
|
|
|
|
vtkm::worklet::DispatcherMapField<MapPointsWorklet>(MapPointsWorklet(gridInfo))
|
|
|
|
.Invoke(pointArray, pointCidArray );
|
|
|
|
|
2015-06-25 14:52:02 +00:00
|
|
|
#ifdef __VTKM_VERTEX_CLUSTERING_BENCHMARK
|
2015-06-19 20:30:53 +00:00
|
|
|
std::cout << "Time map points (s): " << timer.GetElapsedTime() << std::endl;
|
2015-06-24 19:13:16 +00:00
|
|
|
#endif
|
2015-06-19 20:30:53 +00:00
|
|
|
|
|
|
|
|
|
|
|
/// pass 2 : compute average point position for each cluster,
|
|
|
|
/// using pointCidArray as the key
|
|
|
|
///
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Id> pointCidArrayReduced;
|
|
|
|
vtkm::cont::ArrayHandle<Vector3> repPointArray; // representative point
|
|
|
|
|
2015-06-25 14:52:02 +00:00
|
|
|
vtkm::worklet::
|
2015-06-19 20:30:53 +00:00
|
|
|
AverageByKey( pointCidArray, pointArray, pointCidArrayReduced, repPointArray );
|
|
|
|
|
2015-06-25 14:52:02 +00:00
|
|
|
#ifdef __VTKM_VERTEX_CLUSTERING_BENCHMARK
|
2015-06-19 20:30:53 +00:00
|
|
|
std::cout << "Time after averaging (s): " << timer.GetElapsedTime() << std::endl;
|
2015-06-24 19:13:16 +00:00
|
|
|
#endif
|
2015-06-19 20:30:53 +00:00
|
|
|
|
|
|
|
|
|
|
|
/// Pass 3 : Decimated mesh generation
|
|
|
|
/// For each original triangle, only output vertices from
|
|
|
|
/// three different clusters
|
|
|
|
|
|
|
|
/// map each triangle vertex to the cluser id's
|
|
|
|
/// of the cell vertices
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Id3> cid3Array;
|
|
|
|
|
|
|
|
vtkm::worklet::DispatcherMapField<MapCellsWorklet>(
|
|
|
|
MapCellsWorklet(pointIdArray, pointCidArray)
|
|
|
|
).Invoke(cellToConnectivityIndexArray, cid3Array );
|
|
|
|
|
|
|
|
|
|
|
|
/// preparation: Get the indexes of the clustered points to prepare for new cell array
|
|
|
|
/// The output indexes are stored in the worklet
|
|
|
|
vtkm::cont::ArrayHandleCounting<vtkm::Id> counterArray3(0, pointCidArrayReduced.GetNumberOfValues());
|
|
|
|
IndexingWorklet worklet3 ( gridInfo.dim[0]*gridInfo.dim[1]*gridInfo.dim[2] );
|
|
|
|
|
|
|
|
vtkm::worklet::DispatcherMapField<IndexingWorklet> ( worklet3 )
|
|
|
|
.Invoke(counterArray3, pointCidArrayReduced);
|
|
|
|
|
|
|
|
///
|
|
|
|
/// map: convert each triangle vertices from original point id to the new cluster indexes
|
|
|
|
/// If the triangle is degenerated, set the ids to <-1, -1, -1>
|
|
|
|
///
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Id3> pointId3Array;
|
|
|
|
|
|
|
|
vtkm::worklet::DispatcherMapField<Cid2PointIdWorklet> ( Cid2PointIdWorklet( worklet3.getOutput() ) )
|
|
|
|
.Invoke(cid3Array, pointId3Array);
|
|
|
|
|
|
|
|
|
2015-06-25 14:52:02 +00:00
|
|
|
#ifdef __VTKM_VERTEX_CLUSTERING_BENCHMARK
|
2015-06-19 20:30:53 +00:00
|
|
|
std::cout << "Time before unique (s): " << timer.GetElapsedTime() << std::endl;
|
2015-06-24 19:13:16 +00:00
|
|
|
#endif
|
2015-06-19 20:30:53 +00:00
|
|
|
|
|
|
|
///
|
|
|
|
/// Unique: Decimate replicated cells
|
|
|
|
///
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Id3 > uniquePointId3Array;
|
|
|
|
|
|
|
|
vtkm::cont::DeviceAdapterAlgorithm<DeviceAdapter>::Copy(pointId3Array,uniquePointId3Array);
|
|
|
|
|
2015-06-25 14:52:02 +00:00
|
|
|
#ifdef __VTKM_VERTEX_CLUSTERING_BENCHMARK
|
2015-06-19 20:30:53 +00:00
|
|
|
std::cout << "Time after copy (s): " << timer.GetElapsedTime() << std::endl;
|
2015-06-24 19:13:16 +00:00
|
|
|
#endif
|
2015-06-19 20:30:53 +00:00
|
|
|
|
|
|
|
vtkm::cont::DeviceAdapterAlgorithm<DeviceAdapter>::Sort(uniquePointId3Array, Id3Less());
|
|
|
|
|
2015-06-25 14:52:02 +00:00
|
|
|
#ifdef __VTKM_VERTEX_CLUSTERING_BENCHMARK
|
2015-06-19 20:30:53 +00:00
|
|
|
std::cout << "Time after sort (s): " << timer.GetElapsedTime() << std::endl;
|
2015-06-24 19:13:16 +00:00
|
|
|
#endif
|
2015-06-19 20:30:53 +00:00
|
|
|
|
|
|
|
vtkm::cont::DeviceAdapterAlgorithm<DeviceAdapter>::Unique(uniquePointId3Array);
|
|
|
|
|
2015-06-25 14:52:02 +00:00
|
|
|
#ifdef __VTKM_VERTEX_CLUSTERING_BENCHMARK
|
2015-06-19 20:30:53 +00:00
|
|
|
std::cout << "Time after unique (s): " << timer.GetElapsedTime() << std::endl;
|
2015-06-24 19:13:16 +00:00
|
|
|
#endif
|
2015-06-19 20:30:53 +00:00
|
|
|
|
2015-06-24 18:52:41 +00:00
|
|
|
// remove the last one if invalid
|
2015-06-25 15:43:29 +00:00
|
|
|
vtkm::Id cells = uniquePointId3Array.GetNumberOfValues();
|
|
|
|
if (cells > 0 && uniquePointId3Array.GetPortalConstControl().Get(cells-1) == vtkm::make_Vec<vtkm::Id>(-1,-1,-1) ) {
|
2015-06-24 18:52:41 +00:00
|
|
|
cells-- ;
|
|
|
|
uniquePointId3Array.Shrink(cells);
|
|
|
|
}
|
2015-06-19 20:30:53 +00:00
|
|
|
|
2015-06-25 17:16:16 +00:00
|
|
|
output_pointArray = repPointArray;
|
|
|
|
output_pointId3Array = uniquePointId3Array;
|
|
|
|
|
2015-06-19 20:30:53 +00:00
|
|
|
/// generate output
|
2015-06-25 14:52:02 +00:00
|
|
|
#ifdef __VTKM_VERTEX_CLUSTERING_BENCHMARK
|
2015-06-24 18:52:41 +00:00
|
|
|
std::cout << "number of output points: " << repPointArray.GetNumberOfValues() << std::endl;
|
|
|
|
std::cout << "number of output cells: " << uniquePointId3Array.GetNumberOfValues() << std::endl;
|
2015-06-24 19:13:16 +00:00
|
|
|
#endif
|
2015-06-24 18:52:41 +00:00
|
|
|
|
2015-06-19 20:30:53 +00:00
|
|
|
/// end of algorithm
|
|
|
|
/// Note that there is a cell with ids <-1, -1, -1>.
|
|
|
|
/// The removal of it is deferred to the conversion to VTK
|
|
|
|
/// ////////////////////////////////////////
|
2015-06-25 14:52:02 +00:00
|
|
|
#ifdef __VTKM_VERTEX_CLUSTERING_BENCHMARK
|
2015-06-25 15:46:28 +00:00
|
|
|
vtkm::Float64 t = timer.GetElapsedTime();
|
2015-06-19 20:30:53 +00:00
|
|
|
std::cout << "Time (s): " << t << std::endl;
|
2015-06-24 19:13:16 +00:00
|
|
|
#endif
|
2015-06-19 20:30:53 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
}; // struct VertexClustering
|
|
|
|
|
2015-06-18 17:07:31 +00:00
|
|
|
|
2015-06-19 18:23:20 +00:00
|
|
|
}} // namespace vtkm::worklet
|
2015-06-18 17:07:31 +00:00
|
|
|
|
|
|
|
#endif // vtk_m_worklet_VertexClustering_h
|
|
|
|
|