From 21a58a294c0336e50cb6d643f6496c59940083fc Mon Sep 17 00:00:00 2001 From: Jay Date: Sat, 19 Aug 2023 02:57:13 +0000 Subject: [PATCH] add multi plane for clip --- vtkm/ImplicitFunction.h | 79 +++++++++++++++++- .../cont/testing/UnitTestImplicitFunction.cxx | 36 +++++++++ ...UnitTestClipWithImplicitFunctionFilter.cxx | 81 ++++++++++++++++--- 3 files changed, 181 insertions(+), 15 deletions(-) diff --git a/vtkm/ImplicitFunction.h b/vtkm/ImplicitFunction.h index 993c46eb3..e5544a6d8 100644 --- a/vtkm/ImplicitFunction.h +++ b/vtkm/ImplicitFunction.h @@ -12,8 +12,8 @@ #include #include +#include #include - #include // For interface class only. @@ -654,6 +654,77 @@ private: Vector Center; }; +//============================================================================ +/// \brief Implicit function for a MultiPlane +/// +/// A MultiPlane contains multiple planes. Each plane is defined by a point and a normal to the plane. +/// MaxNumPlanes specifies the maximum number of planes it can hold. We can assign another MultiPlane with +/// a smaller number of planes to the current MultiPlane. +template +class VTKM_ALWAYS_EXPORT MultiPlane + : public vtkm::internal::ImplicitFunctionBase> +{ +public: + using Scalar = vtkm::FloatDefault; + using Vector = vtkm::Vec; + VTKM_CONT MultiPlane() = default; + template + VTKM_CONT MultiPlane(const MultiPlane& src) + : Planes(src.GetPlanes()) + { + } + template + VTKM_CONT MultiPlane& operator=(const MultiPlane& src) + { + this->Planes = vtkm::VecVariable{ src.GetPlanes() }; + } + VTKM_CONT void AddPlane(const Vector& origin, const Vector& normal) + { + VTKM_ASSERT(this->Planes.GetNumberOfComponents() < MaxNumPlanes); + this->Planes.Append(Plane(origin, normal)); + } + VTKM_CONT vtkm::Plane GetPlane(int idx) + { + VTKM_ASSERT((idx >= 0) && (idx < MaxNumPlanes)); + return this->Planes[idx]; + } + VTKM_CONT vtkm::VecVariable GetPlanes() const { return this->Planes; } + VTKM_EXEC_CONT Scalar Value(const Vector& point) const + { + Scalar maxVal = vtkm::NegativeInfinity(); + vtkm::IdComponent NumPlanes = this->Planes.GetNumberOfComponents(); + for (vtkm::IdComponent index = 0; index < NumPlanes; ++index) + { + const Vector& p = this->Planes[index].GetOrigin(); + const Vector& n = this->Planes[index].GetNormal(); + const Scalar val = vtkm::Dot(point - p, n); + maxVal = vtkm::Max(maxVal, val); + } + return maxVal; + } + VTKM_EXEC_CONT Vector Gradient(const Vector& point) const + { + Scalar maxVal = vtkm::NegativeInfinity(); + vtkm::IdComponent maxValIdx = 0; + vtkm::IdComponent NumPlanes = Planes.GetNumberOfComponents(); + for (vtkm::IdComponent index = 0; index < NumPlanes; ++index) + { + const Vector& p = this->Planes[index].GetOrigin(); + const Vector& n = this->Planes[index].GetNormal(); + Scalar val = vtkm::Dot(point - p, n); + if (val > maxVal) + { + maxVal = val; + maxValIdx = index; + } + } + return this->Planes[maxValIdx].GetNormal(); + } + +private: + vtkm::VecVariable Planes; +}; + namespace detail { @@ -751,13 +822,15 @@ class ImplicitFunctionGeneral vtkm::Cylinder, vtkm::Frustum, vtkm::Plane, - vtkm::Sphere> + vtkm::Sphere, + vtkm::MultiPlane<3>> { using Superclass = vtkm::ImplicitFunctionMultiplexer; + vtkm::Sphere, + vtkm::MultiPlane<3>>; public: using Superclass::Superclass; diff --git a/vtkm/cont/testing/UnitTestImplicitFunction.cxx b/vtkm/cont/testing/UnitTestImplicitFunction.cxx index 34bd3fe97..d5bdad12c 100644 --- a/vtkm/cont/testing/UnitTestImplicitFunction.cxx +++ b/vtkm/cont/testing/UnitTestImplicitFunction.cxx @@ -331,6 +331,41 @@ void TestSphere() vtkm::Vec3f{ -2.0f, 0.0f, 0.0f } } }); } +void TestMultiPlane() +{ + std::cout << "Testing vtkm::MultiPlane\n"; + std::cout << " 3 axis aligned planes intersected at (1, 1, 1)" << std::endl; + vtkm::MultiPlane<3> TriplePlane; + //insert xy plane + TriplePlane.AddPlane(vtkm::Vec3f{ 1.0f, 1.0f, 0.0f }, vtkm::Vec3f{ 0.0f, 0.0f, 1.0f }); + //insert yz plane + TriplePlane.AddPlane(vtkm::Vec3f{ 0.0f, 1.0f, 1.0f }, vtkm::Vec3f{ 1.0f, 0.0f, 0.0f }); + //insert xz plane + TriplePlane.AddPlane(vtkm::Vec3f{ 1.0f, 0.0f, 1.0f }, vtkm::Vec3f{ 0.0f, 1.0f, 0.0f }); + Try(TriplePlane, + { { 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f } }, + { { + vtkm::Vec3f{ 0.0f, 0.0f, 1.0f }, + vtkm::Vec3f{ 1.0f, 0.0f, 0.0f }, + vtkm::Vec3f{ 0.0f, 0.0f, 1.0f }, + vtkm::Vec3f{ 0.0f, 0.0f, 1.0f }, + vtkm::Vec3f{ 0.0f, 1.0f, 0.0f }, + vtkm::Vec3f{ 1.0f, 0.0f, 0.0f }, + vtkm::Vec3f{ 0.0f, 0.0f, 1.0f }, + vtkm::Vec3f{ 0.0f, 0.0f, 1.0f }, + } }); + std::cout << " test MultiPlane copy" << std::endl; + vtkm::MultiPlane<4> QuadPlane1(TriplePlane); + vtkm::MultiPlane<4> QuadPlane2 = TriplePlane; + for (int i = 0; i < 3; i++) + { + VTKM_TEST_ASSERT(QuadPlane1.GetPlane(i).GetOrigin() == TriplePlane.GetPlane(i).GetOrigin()); + VTKM_TEST_ASSERT(QuadPlane1.GetPlane(i).GetNormal() == TriplePlane.GetPlane(i).GetNormal()); + VTKM_TEST_ASSERT(QuadPlane2.GetPlane(i).GetOrigin() == TriplePlane.GetPlane(i).GetOrigin()); + VTKM_TEST_ASSERT(QuadPlane1.GetPlane(i).GetNormal() == TriplePlane.GetPlane(i).GetNormal()); + } +} + void Run() { TestBox(); @@ -338,6 +373,7 @@ void Run() TestFrustum(); TestPlane(); TestSphere(); + TestMultiPlane(); } } // anonymous namespace diff --git a/vtkm/filter/contour/testing/UnitTestClipWithImplicitFunctionFilter.cxx b/vtkm/filter/contour/testing/UnitTestClipWithImplicitFunctionFilter.cxx index 928fbe8d9..055865ae0 100644 --- a/vtkm/filter/contour/testing/UnitTestClipWithImplicitFunctionFilter.cxx +++ b/vtkm/filter/contour/testing/UnitTestClipWithImplicitFunctionFilter.cxx @@ -12,13 +12,12 @@ #include #include - namespace { using Coord3D = vtkm::Vec3f; -vtkm::cont::DataSet MakeTestDatasetStructured() +vtkm::cont::DataSet MakeTestDatasetStructured2D() { static constexpr vtkm::Id xdim = 3, ydim = 3; static const vtkm::Id2 dim(xdim, ydim); @@ -39,11 +38,30 @@ vtkm::cont::DataSet MakeTestDatasetStructured() return ds; } -void TestClipStructured(vtkm::Float64 offset) +vtkm::cont::DataSet MakeTestDatasetStructured3D() { - std::cout << "Testing ClipWithImplicitFunction Filter on Structured data" << std::endl; + static constexpr vtkm::Id xdim = 3, ydim = 3, zdim = 3; + static const vtkm::Id3 dim(xdim, ydim, zdim); + static constexpr vtkm::Id numVerts = xdim * ydim * zdim; + vtkm::Float32 scalars[numVerts]; + for (vtkm::Id i = 0; i < numVerts; i++) + { + scalars[i] = static_cast(i * 0.1); + } + scalars[13] = 0.0f; + vtkm::cont::DataSet ds; + ds = vtkm::cont::DataSetBuilderUniform::Create( + dim, vtkm::Vec3f(-1.0f, -1.0f, -1.0f), vtkm::Vec3f(1, 1, 1)); + ds.AddPointField("scalars", scalars, numVerts); + return ds; +} - vtkm::cont::DataSet ds = MakeTestDatasetStructured(); +void TestClipStructuredSphere(vtkm::Float64 offset) +{ + std::cout << "Testing ClipWithImplicitFunction Filter on Structured data with Sphere function" + << std::endl; + + vtkm::cont::DataSet ds = MakeTestDatasetStructured2D(); vtkm::Vec3f center(1, 1, 0); @@ -82,11 +100,13 @@ void TestClipStructured(vtkm::Float64 offset) } } -void TestClipStructuredInverted() +void TestClipStructuredInvertedSphere() { - std::cout << "Testing ClipWithImplicitFunctionInverted Filter on Structured data" << std::endl; + std::cout + << "Testing ClipWithImplicitFunctionInverted Filter on Structured data with Sphere function" + << std::endl; - vtkm::cont::DataSet ds = MakeTestDatasetStructured(); + vtkm::cont::DataSet ds = MakeTestDatasetStructured2D(); vtkm::Vec3f center(1, 1, 0); vtkm::FloatDefault radius(0.5); @@ -118,13 +138,50 @@ void TestClipStructuredInverted() } } +void TestClipStructuredInvertedMultiPlane() +{ + std::cout << "Testing TestClipStructured Filter on Structured data with MultiPlane function" + << std::endl; + vtkm::cont::DataSet ds = MakeTestDatasetStructured3D(); + vtkm::filter::contour::ClipWithImplicitFunction clip; + vtkm::MultiPlane<3> TriplePlane; + //set xy plane + TriplePlane.AddPlane(vtkm::Vec3f{ 1.0f, 1.0f, 0.0f }, vtkm::Vec3f{ 0.0f, 0.0f, 1.0f }); + //set yz plane + TriplePlane.AddPlane(vtkm::Vec3f{ 0.0f, 1.0f, 1.0f }, vtkm::Vec3f{ 1.0f, 0.0f, 0.0f }); + //set xz plane + TriplePlane.AddPlane(vtkm::Vec3f{ 1.0f, 0.0f, 1.0f }, vtkm::Vec3f{ 0.0f, 1.0f, 0.0f }); + clip.SetInvertClip(true); + clip.SetImplicitFunction(TriplePlane); + clip.SetFieldsToPass("scalars"); + auto outputData = clip.Execute(ds); + + VTKM_TEST_ASSERT(outputData.GetNumberOfCoordinateSystems() == 1, + "Wrong number of coordinate systems in the output dataset"); + VTKM_TEST_ASSERT(outputData.GetNumberOfFields() == 2, + "Wrong number of fields in the output dataset"); + VTKM_TEST_ASSERT(outputData.GetNumberOfCells() == 1, + "Wrong number of cells in the output dataset"); + vtkm::cont::UnknownArrayHandle temp = outputData.GetField("scalars").GetData(); + vtkm::cont::ArrayHandle resultArrayHandle; + temp.AsArrayHandle(resultArrayHandle); + vtkm::Float32 expected[4] = { 0.0f, 0.1f, 0.3f, 0.9f }; + for (int i = 0; i < 4; ++i) + { + VTKM_TEST_ASSERT(test_equal(resultArrayHandle.ReadPortal().Get(i), expected[i]), + "Wrong result for ClipWithImplicitFunction fliter on sturctured data in " + "TestClipStructuredInvertedMultiPlane"); + } +} + void TestClip() { //todo: add more clip tests - TestClipStructured(-0.2); - TestClipStructured(0.0); - TestClipStructured(0.2); - TestClipStructuredInverted(); + TestClipStructuredSphere(-0.2); + TestClipStructuredSphere(0.0); + TestClipStructuredSphere(0.2); + TestClipStructuredInvertedSphere(); + TestClipStructuredInvertedMultiPlane(); } } // anonymous namespace