From 1261e459d3e6d3b23c4fc5d7ac9c3b046012d769 Mon Sep 17 00:00:00 2001 From: Sujin Philip Date: Mon, 10 Apr 2023 16:14:50 -0400 Subject: [PATCH] Clip: Remove unused points The clip filter used to copy the input points and point fields as is, regardless of if they were actually part of the output. With this change, we track which input points are actually part of the output and copy only those values. Address: #112 --- docs/changelog/clip-remove-unused-points.md | 9 +++ .../testing/UnitTestClipWithFieldFilter.cxx | 4 +- ...UnitTestClipWithImplicitFunctionFilter.cxx | 12 ++-- vtkm/filter/contour/worklet/Clip.h | 63 ++++++++++++++++--- 4 files changed, 70 insertions(+), 18 deletions(-) create mode 100644 docs/changelog/clip-remove-unused-points.md diff --git a/docs/changelog/clip-remove-unused-points.md b/docs/changelog/clip-remove-unused-points.md new file mode 100644 index 000000000..860c01ac3 --- /dev/null +++ b/docs/changelog/clip-remove-unused-points.md @@ -0,0 +1,9 @@ +# Clip now doesn't copy unused points from the input to the output + +Previously, clip would just copy all the points and point data from the input to the output, +and only append the new points. This would affect the bounds computation of the result. +If the caller wanted to remove the unused points, they had to run the CleanGrid filter +on the result. + +With this change, clip now keeps track of which inputs are actually part of the output +and copies only those points. diff --git a/vtkm/filter/contour/testing/UnitTestClipWithFieldFilter.cxx b/vtkm/filter/contour/testing/UnitTestClipWithFieldFilter.cxx index 3e854f9d0..92a42c8e2 100644 --- a/vtkm/filter/contour/testing/UnitTestClipWithFieldFilter.cxx +++ b/vtkm/filter/contour/testing/UnitTestClipWithFieldFilter.cxx @@ -70,8 +70,8 @@ void TestClipExplicit() vtkm::cont::ArrayHandle resultArrayHandle; temp.AsArrayHandle(resultArrayHandle); - vtkm::Float32 expected[7] = { 1, 2, 1, 0, 0.5, 0.5, 0.5 }; - for (int i = 0; i < 7; ++i) + vtkm::Float32 expected[6] = { 1, 2, 1, 0.5, 0.5, 0.5 }; + for (int i = 0; i < 6; ++i) { VTKM_TEST_ASSERT(test_equal(resultArrayHandle.ReadPortal().Get(i), expected[i]), "Wrong result for Clip fliter on triangle explicit data"); diff --git a/vtkm/filter/contour/testing/UnitTestClipWithImplicitFunctionFilter.cxx b/vtkm/filter/contour/testing/UnitTestClipWithImplicitFunctionFilter.cxx index d8f0e834b..928fbe8d9 100644 --- a/vtkm/filter/contour/testing/UnitTestClipWithImplicitFunctionFilter.cxx +++ b/vtkm/filter/contour/testing/UnitTestClipWithImplicitFunctionFilter.cxx @@ -71,11 +71,11 @@ void TestClipStructured(vtkm::Float64 offset) vtkm::cont::ArrayHandle resultArrayHandle; temp.AsArrayHandle(resultArrayHandle); - VTKM_TEST_ASSERT(resultArrayHandle.GetNumberOfValues() == 13, + VTKM_TEST_ASSERT(resultArrayHandle.GetNumberOfValues() == 12, "Wrong number of points in the output dataset"); - vtkm::Float32 expected[13] = { 1, 1, 1, 1, 0, 1, 1, 1, 1, 0.25, 0.25, 0.25, 0.25 }; - for (int i = 0; i < 13; ++i) + vtkm::Float32 expected[12] = { 1, 1, 1, 1, 1, 1, 1, 1, 0.25, 0.25, 0.25, 0.25 }; + for (int i = 0; i < 12; ++i) { VTKM_TEST_ASSERT(test_equal(resultArrayHandle.ReadPortal().Get(i), expected[i]), "Wrong result for ClipWithImplicitFunction fliter on sturctured quads data"); @@ -107,11 +107,11 @@ void TestClipStructuredInverted() vtkm::cont::ArrayHandle resultArrayHandle; temp.AsArrayHandle(resultArrayHandle); - VTKM_TEST_ASSERT(resultArrayHandle.GetNumberOfValues() == 13, + VTKM_TEST_ASSERT(resultArrayHandle.GetNumberOfValues() == 5, "Wrong number of points in the output dataset"); - vtkm::Float32 expected[13] = { 1, 1, 1, 1, 0, 1, 1, 1, 1, 0.25, 0.25, 0.25, 0.25 }; - for (int i = 0; i < 13; ++i) + vtkm::Float32 expected[5] = { 0, 0.25, 0.25, 0.25, 0.25 }; + for (int i = 0; i < 5; ++i) { VTKM_TEST_ASSERT(test_equal(resultArrayHandle.ReadPortal().Get(i), expected[i]), "Wrong result for ClipWithImplicitFunction fliter on sturctured quads data"); diff --git a/vtkm/filter/contour/worklet/Clip.h b/vtkm/filter/contour/worklet/Clip.h index 10c8e76ed..19ffcfc80 100644 --- a/vtkm/filter/contour/worklet/Clip.h +++ b/vtkm/filter/contour/worklet/Clip.h @@ -10,6 +10,7 @@ #ifndef vtkm_m_worklet_Clip_h #define vtkm_m_worklet_Clip_h +#include #include #include #include @@ -325,6 +326,7 @@ public: FieldInCell clipStats, ExecObject clipTables, ExecObject connectivityObject, + WholeArrayOut pointsOnlyConnectivityIndices, WholeArrayOut edgePointReverseConnectivity, WholeArrayOut edgePointInterpolation, WholeArrayOut inCellReverseConnectivity, @@ -349,7 +351,8 @@ public: _11, _12, _13, - _14); + _14, + _15); template & clippingData, ConnectivityObject& connectivityObject, + IdArrayType& pointsOnlyConnectivityIndices, IdArrayType& edgePointReverseConnectivity, EdgeInterpolationPortalType& edgePointInterpolation, IdArrayType& inCellReverseConnectivity, @@ -388,6 +392,8 @@ public: // Start Indices to keep track of interpolation points for new cell. vtkm::Id inCellInterpPointIndex = clipStats.NumberOfInCellInterpPoints; vtkm::Id inCellEdgeInterpIndex = clipStats.NumberOfInCellEdgeIndices; + // Start index of connectivityPointsOnly + vtkm::Id pointsOnlyConnectivityIndicesIndex = connectivityIndex - edgeIndex - inCellIndex; // Iterate over the shapes for the current cell and begin to fill connectivity. vtkm::Id numberOfCells = clippingData.ValueAt(clipIndex++); @@ -471,6 +477,8 @@ public: } else if (entry >= 100) // existing vertex { + pointsOnlyConnectivityIndices.Set(pointsOnlyConnectivityIndicesIndex++, + connectivityIndex); connectivityObject.SetConnectivity(connectivityIndex++, points[entry - 100]); } else // case of a new edge point @@ -588,6 +596,7 @@ public: bool invert) { vtkm::cont::Invoker invoke; + // Create the required output fields. vtkm::cont::ArrayHandle clipStats; vtkm::cont::ArrayHandle clipTableIndices; @@ -610,6 +619,10 @@ public: shapes, numberOfIndices, connectivity, offsets, total); //Begin Process of Constructing the new CellSet. + vtkm::cont::ArrayHandle pointsOnlyConnectivityIndices; + pointsOnlyConnectivityIndices.Allocate(total.NumberOfIndices - total.NumberOfEdgeIndices - + total.NumberOfInCellIndices); + vtkm::cont::ArrayHandle edgePointReverseConnectivity; edgePointReverseConnectivity.Allocate(total.NumberOfEdgeIndices); vtkm::cont::ArrayHandle edgeInterpolation; @@ -635,6 +648,7 @@ public: cellSetStats, this->ClipTablesInstance, connectivityObject, + pointsOnlyConnectivityIndices, edgePointReverseConnectivity, edgeInterpolation, cellPointReverseConnectivity, @@ -648,6 +662,30 @@ public: clipTableIndices.ReleaseResources(); cellSetStats.ReleaseResources(); + // extract only the used points from the input + { + vtkm::cont::ArrayHandle pointMask; + pointMask.AllocateAndFill(scalars.GetNumberOfValues(), 0); + + auto pointsOnlyConnectivity = + vtkm::cont::make_ArrayHandlePermutation(pointsOnlyConnectivityIndices, connectivity); + + invoke( + vtkm::worklet::RemoveUnusedPoints::GeneratePointMask{}, pointsOnlyConnectivity, pointMask); + + vtkm::worklet::ScatterCounting scatter(pointMask, true); + auto pointMapInputToOutput = scatter.GetInputToOutputMap(); + this->PointMapOutputToInput = scatter.GetOutputToInputMap(); + pointMask.ReleaseResources(); + + invoke(vtkm::worklet::RemoveUnusedPoints::TransformPointIndices{}, + pointsOnlyConnectivity, + pointMapInputToOutput, + pointsOnlyConnectivity); + + pointsOnlyConnectivityIndices.ReleaseResources(); + } + // Get unique EdgeInterpolation : unique edge points. // LowerBound for edgeInterpolation : get index into new edge points array. // LowerBound for cellPointEdgeInterpolation : get index into new edge points array. @@ -670,7 +708,7 @@ public: EdgeInterpolation::LessThanOp()); cellPointEdgeInterpolation.ReleaseResources(); - this->EdgePointsOffset = scalars.GetNumberOfValues(); + this->EdgePointsOffset = this->PointMapOutputToInput.GetNumberOfValues(); this->InCellPointsOffset = this->EdgePointsOffset + this->EdgePointsInterpolation.GetNumberOfValues(); @@ -691,7 +729,7 @@ public: invoke(scatterInCellPointConnectivity, cellPointReverseConnectivity, connectivity); vtkm::cont::CellSetExplicit<> output; - vtkm::Id numberOfPoints = scalars.GetNumberOfValues() + + vtkm::Id numberOfPoints = this->PointMapOutputToInput.GetNumberOfValues() + this->EdgePointsInterpolation.GetNumberOfValues() + total.NumberOfInCellPoints; vtkm::cont::ConvertNumComponentsToOffsets(numberOfIndices, offsets); @@ -833,21 +871,25 @@ public: this->InterpolationKeys.BuildArrays(this->InCellInterpolationKeys, KeysSortType::Unstable); } - vtkm::Id numberOfOriginalValues = input.GetNumberOfValues(); + vtkm::Id numberOfVertexPoints = this->PointMapOutputToInput.GetNumberOfValues(); vtkm::Id numberOfEdgePoints = this->EdgePointsInterpolation.GetNumberOfValues(); vtkm::Id numberOfInCellPoints = this->InterpolationKeys.GetUniqueKeys().GetNumberOfValues(); - // Copy over the original values. They are still part of the output. (Unused points are - // not culled. Use CleanGrid for that.) - output.Allocate(numberOfOriginalValues + numberOfEdgePoints + numberOfInCellPoints); - vtkm::cont::Algorithm::CopySubRange(input, 0, numberOfOriginalValues, output); + output.Allocate(numberOfVertexPoints + numberOfEdgePoints + numberOfInCellPoints); + + // Copy over the original values that are still part of the output. + vtkm::cont::Algorithm::CopySubRange( + vtkm::cont::make_ArrayHandlePermutation(this->PointMapOutputToInput, input), + 0, + numberOfVertexPoints, + output); // Interpolate all new points that lie on edges of the input mesh. vtkm::cont::Invoker invoke; invoke(PerformEdgeInterpolations{}, this->EdgePointsInterpolation, input, - vtkm::cont::make_ArrayHandleView(output, numberOfOriginalValues, numberOfEdgePoints)); + vtkm::cont::make_ArrayHandleView(output, numberOfVertexPoints, numberOfEdgePoints)); // Perform a gather on the output to get all the required values for calculation of centroids // using the interpolation info array. @@ -857,7 +899,7 @@ public: this->InterpolationKeys, toReduceValues, vtkm::cont::make_ArrayHandleView( - output, numberOfOriginalValues + numberOfEdgePoints, numberOfInCellPoints)); + output, numberOfVertexPoints + numberOfEdgePoints, numberOfInCellPoints)); } vtkm::cont::ArrayHandle GetCellMapOutputToInput() const @@ -871,6 +913,7 @@ private: vtkm::cont::ArrayHandle InCellInterpolationKeys; vtkm::cont::ArrayHandle InCellInterpolationInfo; vtkm::cont::ArrayHandle CellMapOutputToInput; + vtkm::cont::ArrayHandle PointMapOutputToInput; vtkm::Id EdgePointsOffset; vtkm::Id InCellPointsOffset; vtkm::worklet::Keys InterpolationKeys;