From 8ec1d44da3ccb037811bf65120a3135a15a5dad1 Mon Sep 17 00:00:00 2001
From: Thomas Galland <thomas.galland@kitware.com>
Date: Thu, 14 Nov 2024 09:47:05 +0100
Subject: [PATCH] vtkHyperTreeGridAxisCut: add test with coincident plane

---
 Filters/HyperTree/Testing/CMakeLists.txt      |   1 +
 Filters/HyperTree/Testing/Cxx/CMakeLists.txt  |   1 +
 ...tHyperTreeGrid3DAxisCutCoincidentPlane.cxx | 148 ++++++++++++++++++
 ...reeGrid3DAxisCutCoincidentPlane.png.sha512 |   1 +
 .../HTG/htg_for_axis_aligned_cut.htg.sha512   |   1 +
 5 files changed, 152 insertions(+)
 create mode 100644 Filters/HyperTree/Testing/Cxx/TestHyperTreeGrid3DAxisCutCoincidentPlane.cxx
 create mode 100644 Filters/HyperTree/Testing/Data/Baseline/TestHyperTreeGrid3DAxisCutCoincidentPlane.png.sha512
 create mode 100644 Testing/Data/HTG/htg_for_axis_aligned_cut.htg.sha512

diff --git a/Filters/HyperTree/Testing/CMakeLists.txt b/Filters/HyperTree/Testing/CMakeLists.txt
index c9fccd33c7c..317b82a6a72 100644
--- a/Filters/HyperTree/Testing/CMakeLists.txt
+++ b/Filters/HyperTree/Testing/CMakeLists.txt
@@ -5,6 +5,7 @@ vtk_module_test_data(
   Data/HTG/binary_3D_333_mask.htg
   Data/HTG/donut_XZ_shift_2d.htg
   Data/HTG/ghost.htg
+  Data/HTG/htg_for_axis_aligned_cut.htg
   Data/HTG/shell_3d.htg
   Data/HTG/single_cell_3d.htg
   Data/HTG/three_cells_3d.htg
diff --git a/Filters/HyperTree/Testing/Cxx/CMakeLists.txt b/Filters/HyperTree/Testing/Cxx/CMakeLists.txt
index 6e8a41d9d8e..f4ec43c05ab 100644
--- a/Filters/HyperTree/Testing/Cxx/CMakeLists.txt
+++ b/Filters/HyperTree/Testing/Cxx/CMakeLists.txt
@@ -11,6 +11,7 @@
 
 set(test_sources
   TestHyperTreeGrid2DInterfaceShift.cxx
+  TestHyperTreeGrid3DAxisCutCoincidentPlane.cxx
   TestHyperTreeGrid3DIntercepts.cxx
   TestHyperTreeGrid3DInterface.cxx
   TestHyperTreeGrid3DSimpleInterface.cxx
diff --git a/Filters/HyperTree/Testing/Cxx/TestHyperTreeGrid3DAxisCutCoincidentPlane.cxx b/Filters/HyperTree/Testing/Cxx/TestHyperTreeGrid3DAxisCutCoincidentPlane.cxx
new file mode 100644
index 00000000000..654d2d4d6c6
--- /dev/null
+++ b/Filters/HyperTree/Testing/Cxx/TestHyperTreeGrid3DAxisCutCoincidentPlane.cxx
@@ -0,0 +1,148 @@
+// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
+// SPDX-License-Identifier: BSD-3-Clause
+
+#include "vtkCamera.h"
+#include "vtkDataSetMapper.h"
+#include "vtkHyperTreeGrid.h"
+#include "vtkHyperTreeGridAxisCut.h"
+#include "vtkHyperTreeGridGeometry.h"
+#include "vtkNew.h"
+#include "vtkOutlineSource.h"
+#include "vtkProperty.h"
+#include "vtkRegressionTestImage.h"
+#include "vtkRenderWindow.h"
+#include "vtkRenderWindowInteractor.h"
+#include "vtkRenderer.h"
+#include "vtkTestUtilities.h"
+#include "vtkXMLHyperTreeGridReader.h"
+
+#include <limits>
+
+/**
+ * Test the behavior of vtkHyperTreeGridAxisCut when the cutting plane is coincident with some faces
+ * of the HTG cells geometry. In such cases, the plan should be considered as "inside" if it is
+ * coincident with the oposite faces of the cell origin.
+ */
+int TestHyperTreeGrid3DAxisCutCoincidentPlane(int argc, char* argv[])
+{
+  // Read HTG test data
+  std::string filename =
+    vtkTestUtilities::ExpandDataFileName(argc, argv, "Data/HTG/htg_for_axis_aligned_cut.htg");
+  vtkNew<vtkXMLHyperTreeGridReader> htgReader;
+  htgReader->SetFileName(filename.c_str());
+  htgReader->Update();
+
+  // Compute HTG bounds
+  vtkHyperTreeGrid* htg = htgReader->GetOutput();
+  if (!htg)
+  {
+    cerr << "Unable to read input HTG (" + filename + ")";
+    return EXIT_FAILURE;
+  }
+  std::array<double, 6> bounds;
+  htg->GetBounds(bounds.data());
+
+  // Define test plane positions
+  std::array<double, 4> planePositions = {
+    0.014799999999999994,                                     // Coincident, inside the HTG
+    bounds[1] + std::numeric_limits<double>::epsilon() * 0.5, // Coincident, htg boundary
+    bounds[1] + std::numeric_limits<double>::epsilon(),       // Outside
+    bounds[0],                                                // Outside
+  };
+
+  std::array<double, 4> expectedNbOfCutCells = { 110, 11, 0, 0 };
+  std::array<vtkSmartPointer<vtkHyperTreeGrid>, 4> cuts;
+
+  vtkNew<vtkHyperTreeGridAxisCut> cutter;
+  cutter->SetInputData(htg);
+  cutter->SetPlaneNormalAxis(0); // X
+
+  // Test cut results
+  for (unsigned int i = 0; i < 4; i++)
+  {
+    cutter->SetPlanePosition(planePositions[i]);
+    cutter->Update();
+
+    vtkHyperTreeGrid* cut = cutter->GetHyperTreeGridOutput();
+    if (!cut)
+    {
+      std::cerr << "Unable to retrieve the HTG cut " << i << "." << endl;
+      return EXIT_FAILURE;
+    }
+    if (cut->GetNumberOfCells() != expectedNbOfCutCells[i])
+    {
+      cerr << "Wrong number of cells in the HTG slice. Expected 110, got "
+           << cut->GetNumberOfCells() << endl;
+      return EXIT_FAILURE;
+    }
+
+    // Store cut
+    cuts[i] = vtkSmartPointer<vtkHyperTreeGrid>::New();
+    cuts[i]->DeepCopy(cut);
+  }
+
+  // Geometry
+  vtkNew<vtkOutlineSource> htgOutline;
+  htgOutline->SetBounds(bounds.data());
+  vtkNew<vtkHyperTreeGridGeometry> geometryCutIn;
+  geometryCutIn->SetInputData(cuts[0]);
+  vtkNew<vtkHyperTreeGridGeometry> geometryCutOut;
+  geometryCutOut->SetInputData(cuts[1]);
+
+  // Mappers
+  vtkMapper::SetResolveCoincidentTopologyToPolygonOffset();
+  vtkNew<vtkDataSetMapper> mapperCutIn;
+  mapperCutIn->SetInputConnection(geometryCutIn->GetOutputPort());
+  vtkNew<vtkDataSetMapper> mapperCutBound;
+  mapperCutBound->SetInputConnection(geometryCutOut->GetOutputPort());
+  vtkNew<vtkDataSetMapper> mapperHTG;
+  mapperHTG->SetInputConnection(htgOutline->GetOutputPort());
+
+  // Actors
+  vtkNew<vtkActor> actorCutIn;
+  actorCutIn->SetMapper(mapperCutIn);
+  actorCutIn->GetProperty()->SetRepresentationToSurface();
+  actorCutIn->GetProperty()->SetEdgeVisibility(true);
+  vtkNew<vtkActor> actorCutBound;
+  actorCutBound->SetMapper(mapperCutBound);
+  actorCutBound->GetProperty()->SetRepresentationToSurface();
+  actorCutBound->GetProperty()->SetEdgeVisibility(true);
+  vtkNew<vtkActor> actorHTG;
+  actorHTG->SetMapper(mapperHTG);
+
+  // Camera
+  vtkNew<vtkCamera> camera;
+  camera->SetPosition(.5, .5, 0.);
+
+  // Renderer
+  vtkNew<vtkRenderer> renderer;
+  renderer->SetActiveCamera(camera);
+  renderer->AddActor(actorCutIn);
+  renderer->AddActor(actorCutBound);
+  renderer->AddActor(actorHTG);
+  renderer->ResetCamera();
+
+  // Render window
+  vtkNew<vtkRenderWindow> renWin;
+  renWin->AddRenderer(renderer);
+  renWin->SetSize(400, 400);
+  renWin->SetMultiSamples(0);
+
+  // Interactor
+  vtkNew<vtkRenderWindowInteractor> iren;
+  iren->SetRenderWindow(renWin);
+
+  // Render and test against baseline
+  renWin->Render();
+  int retVal = vtkRegressionTestImageThreshold(renWin, 0.05);
+  if (retVal == vtkRegressionTester::DO_INTERACTOR)
+  {
+    iren->Start();
+  }
+  else if (retVal == vtkRegressionTester::FAILED)
+  {
+    return EXIT_FAILURE;
+  }
+
+  return EXIT_SUCCESS;
+}
diff --git a/Filters/HyperTree/Testing/Data/Baseline/TestHyperTreeGrid3DAxisCutCoincidentPlane.png.sha512 b/Filters/HyperTree/Testing/Data/Baseline/TestHyperTreeGrid3DAxisCutCoincidentPlane.png.sha512
new file mode 100644
index 00000000000..e33016a2571
--- /dev/null
+++ b/Filters/HyperTree/Testing/Data/Baseline/TestHyperTreeGrid3DAxisCutCoincidentPlane.png.sha512
@@ -0,0 +1 @@
+dcbb8448789801e79ea8dbf9ad4c7c908dc1f3d85d8512ea18041d6c32cf94a85aa74778f75b26eaca8a4691ee71413420228352ae6118591842a9cebba72370
diff --git a/Testing/Data/HTG/htg_for_axis_aligned_cut.htg.sha512 b/Testing/Data/HTG/htg_for_axis_aligned_cut.htg.sha512
new file mode 100644
index 00000000000..cff670cbf12
--- /dev/null
+++ b/Testing/Data/HTG/htg_for_axis_aligned_cut.htg.sha512
@@ -0,0 +1 @@
+c56d68404de41e13ccc4f063cb24ca94ab78195394ce1fac6cccf5ae005efdbc88001ebaac030a7cf7bdc2a5a8800f16e2910ce79d0bbe7e82d2d99a7659bd15
-- 
GitLab