Merge topic 'convert-to-point-cloud'

8b6c5250d Add a ConvertToPointCloud filter

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !3088
This commit is contained in:
Kenneth Moreland 2023-06-28 18:41:09 +00:00 committed by Kitware Robot
commit 84dc806b8c
7 changed files with 271 additions and 0 deletions

@ -0,0 +1,7 @@
# Added a `ConvertToPointCloud` filter
This filter takes a `DataSet` and returns a point cloud representation that
has a vertex cell associated with each point in it. This is useful for
filling in a `CellSet` for data that has points but no cells. It is also
useful for operations in which you want to throw away the cell geometry and
operate on the data as a collection of disparate points.

@ -8,6 +8,7 @@
## PURPOSE. See the above copyright notice for more information.
##============================================================================
set(geometry_refinement_headers
ConvertToPointCloud.h
Shrink.h
SplitSharpEdges.h
Tetrahedralize.h
@ -17,6 +18,7 @@ set(geometry_refinement_headers
)
set(geometry_refinement_sources
ConvertToPointCloud.cxx
Shrink.cxx
SplitSharpEdges.cxx
Tetrahedralize.cxx

@ -0,0 +1,61 @@
//============================================================================
// 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.
//============================================================================
#include <vtkm/filter/geometry_refinement/ConvertToPointCloud.h>
#include <vtkm/cont/ArrayCopy.h>
#include <vtkm/cont/ArrayHandleIndex.h>
#include <vtkm/cont/CellSetSingleType.h>
#include <vtkm/CellShape.h>
namespace vtkm
{
namespace filter
{
namespace geometry_refinement
{
vtkm::cont::DataSet ConvertToPointCloud::DoExecute(const vtkm::cont::DataSet& input)
{
vtkm::Id numPoints = input.GetNumberOfPoints();
// A connectivity array for a point cloud is easy. All the cells are a vertex with exactly
// one point. So, it can be represented a simple index array (i.e., 0, 1, 2, 3, ...).
vtkm::cont::ArrayHandle<vtkm::Id> connectivity;
vtkm::cont::ArrayCopy(vtkm::cont::ArrayHandleIndex{ numPoints }, connectivity);
vtkm::cont::CellSetSingleType<> cellSet;
cellSet.Fill(numPoints, vtkm::CELL_SHAPE_VERTEX, 1, connectivity);
auto fieldMapper = [&](vtkm::cont::DataSet& outData, vtkm::cont::Field& field) {
if (field.IsCellField())
{
// Cell fields are dropped.
return;
}
else if (this->AssociateFieldsWithCells && field.IsPointField() &&
!input.HasCoordinateSystem(field.GetName()))
{
// The user asked to convert point fields to cell fields. (They are interchangable in
// point clouds.)
outData.AddCellField(field.GetName(), field.GetData());
}
else
{
outData.AddField(field);
}
};
return this->CreateResult(input, cellSet, fieldMapper);
}
}
}
} // namespace vtkm::filter::geometry_refinement

@ -0,0 +1,64 @@
//============================================================================
// 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.
//============================================================================
#ifndef vtk_m_filter_geometry_refinement_ConvertToPointCloud_h
#define vtk_m_filter_geometry_refinement_ConvertToPointCloud_h
#include <vtkm/filter/Filter.h>
#include <vtkm/filter/geometry_refinement/vtkm_filter_geometry_refinement_export.h>
namespace vtkm
{
namespace filter
{
namespace geometry_refinement
{
/// \brief Convert a `DataSet` to a point cloud.
///
/// A point cloud in VTK-m is represented as a data set with "vertex" shape cells.
/// This filter replaces the `CellSet` in a `DataSet` with a `CellSet` of only
/// vertex cells. There will be one cell per point.
///
/// This filter is useful for dropping the cells of any `DataSet` so that you can
/// operate on it as just a collection of points. It is also handy for completing
/// a `DataSet` that does not have a `CellSet` associated with it or has points
/// that do not belong to cells.
///
/// Note that all fields associated with cells are dropped. This is because the
/// cells are dropped.
///
class VTKM_FILTER_GEOMETRY_REFINEMENT_EXPORT ConvertToPointCloud : public vtkm::filter::Filter
{
bool AssociateFieldsWithCells = false;
public:
///@{
/// By default, all the input point fields are kept as point fields in the output.
/// However, the output has exactly one cell per point and it might be easier to
/// treat the fields as cell fields. When this flag is turned on, the point field
/// association is changed to cell.
///
/// Note that any field that is marked as point coordinates will remain as point
/// fields. It is not valid to set a cell field as the point coordinates.
///
VTKM_CONT void SetAssociateFieldsWithCells(bool flag) { this->AssociateFieldsWithCells = flag; }
VTKM_CONT bool GetAssociateFieldsWithCells() const { return this->AssociateFieldsWithCells; }
///@}
protected:
VTKM_CONT vtkm::cont::DataSet DoExecute(const vtkm::cont::DataSet& input) override;
};
}
}
} // namespace vtkm::filter::geometry_refinement
#endif //vtk_m_filter_geometry_refinement_ConvertToPointCloud_h

@ -9,6 +9,7 @@
##============================================================================
set(unit_tests
UnitTestConvertToPointCloud.cxx
UnitTestShrinkFilter.cxx
UnitTestSplitSharpEdgesFilter.cxx
UnitTestTetrahedralizeFilter.cxx

@ -0,0 +1,135 @@
//============================================================================
// 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.
//============================================================================
#include <vtkm/filter/geometry_refinement/ConvertToPointCloud.h>
#include <vtkm/io/VTKDataSetReader.h>
#include <vtkm/cont/testing/Testing.h>
namespace
{
void CheckPointCloudCells(const vtkm::cont::UnknownCellSet& cellSet, vtkm::Id numPoints)
{
// A point cloud has the same number of cells as points. All cells are vertex
// cells with one point. That point index is the same as the cell index.
VTKM_TEST_ASSERT(cellSet.GetNumberOfPoints() == numPoints);
VTKM_TEST_ASSERT(cellSet.GetNumberOfCells() == numPoints);
for (vtkm::Id index = 0; index < numPoints; ++index)
{
VTKM_TEST_ASSERT(cellSet.GetCellShape(index) == vtkm::CELL_SHAPE_VERTEX);
VTKM_TEST_ASSERT(cellSet.GetNumberOfPointsInCell(index) == 1);
vtkm::Id pointId;
cellSet.GetCellPointIds(index, &pointId);
VTKM_TEST_ASSERT(pointId == index);
}
}
void CheckPointCloudCells(const vtkm::cont::DataSet& dataSet, vtkm::Id numPoints)
{
CheckPointCloudCells(dataSet.GetCellSet(), numPoints);
}
void TryConvertToPointCloud(const vtkm::cont::DataSet& dataSet)
{
{
std::cout << " convert to point cloud" << std::endl;
vtkm::filter::geometry_refinement::ConvertToPointCloud convertFilter;
vtkm::cont::DataSet pointCloud = convertFilter.Execute(dataSet);
CheckPointCloudCells(pointCloud, dataSet.GetNumberOfPoints());
for (vtkm::IdComponent coordId = 0; coordId < dataSet.GetNumberOfCoordinateSystems(); ++coordId)
{
const auto& coords = dataSet.GetCoordinateSystem(coordId);
std::cout << " coord system " << coords.GetName() << std::endl;
VTKM_TEST_ASSERT(pointCloud.HasCoordinateSystem(coords.GetName()));
}
for (vtkm::IdComponent fieldId = 0; fieldId < dataSet.GetNumberOfFields(); ++fieldId)
{
const auto& field = dataSet.GetField(fieldId);
std::cout << " field " << field.GetName() << std::endl;
switch (field.GetAssociation())
{
case vtkm::cont::Field::Association::Cells:
VTKM_TEST_ASSERT(!pointCloud.HasField(field.GetName()));
break;
default:
VTKM_TEST_ASSERT(pointCloud.HasField(field.GetName(), field.GetAssociation()));
break;
}
}
}
{
std::cout << " convert to point cloud with cell data" << std::endl;
vtkm::filter::geometry_refinement::ConvertToPointCloud convertFilter;
convertFilter.SetAssociateFieldsWithCells(true);
vtkm::cont::DataSet pointCloud = convertFilter.Execute(dataSet);
CheckPointCloudCells(pointCloud, dataSet.GetNumberOfPoints());
for (vtkm::IdComponent coordId = 0; coordId < dataSet.GetNumberOfCoordinateSystems(); ++coordId)
{
const auto& coords = dataSet.GetCoordinateSystem(coordId);
std::cout << " coord system " << coords.GetName() << std::endl;
VTKM_TEST_ASSERT(pointCloud.HasCoordinateSystem(coords.GetName()));
}
for (vtkm::IdComponent fieldId = 0; fieldId < dataSet.GetNumberOfFields(); ++fieldId)
{
auto& field = dataSet.GetField(fieldId);
std::cout << " field " << field.GetName() << std::endl;
switch (field.GetAssociation())
{
case vtkm::cont::Field::Association::Cells:
VTKM_TEST_ASSERT(!pointCloud.HasField(field.GetName()));
break;
case vtkm::cont::Field::Association::Points:
{
auto correctAssociation = dataSet.HasCoordinateSystem(field.GetName())
? vtkm::cont::Field::Association::Points
: vtkm::cont::Field::Association::Cells;
VTKM_TEST_ASSERT(pointCloud.HasField(field.GetName(), correctAssociation));
}
break;
default:
VTKM_TEST_ASSERT(pointCloud.HasField(field.GetName(), field.GetAssociation()));
break;
}
}
}
}
void TryFile(const std::string& filename)
{
std::cout << "Testing " << filename << std::endl;
std::string fullpath = vtkm::cont::testing::Testing::DataPath(filename);
vtkm::io::VTKDataSetReader reader(fullpath);
TryConvertToPointCloud(reader.ReadDataSet());
}
void Run()
{
TryFile("uniform/simple_structured_points_bin.vtk");
TryFile("rectilinear/DoubleGyre_0.vtk");
TryFile("curvilinear/kitchen.vtk");
TryFile("unstructured/simple_unstructured_bin.vtk");
}
} // anonymous namespace
int UnitTestConvertToPointCloud(int argc, char* argv[])
{
return vtkm::cont::testing::Testing::Run(Run, argc, argv);
}

@ -12,6 +12,7 @@ TEST_DEPENDS
vtkm_filter_field_conversion
vtkm_filter_geometry_refinement
vtkm_filter_vector_analysis
vtkm_io
vtkm_source
TEST_OPTIONAL_DEPENDS
vtkm_rendering_testing