vtkCellLocator::FindClosestPoint: returns incorrect results for certain dataset

Hello,

I am using the method vtkCellLocator::FindClosestPoint and get incorrect results for certain input point coordinates and polydata.

The example code loads a polydata file and uses a vtkCellLocator to find the closest point to the input point with coordinates (110000, 110000, 0). See here:

#include <vtkCellLocator.h>
#include <vtkNew.h>
#include <vtkXMLPolyDataReader.h>

int main(int argc, char *argv[]) {
  // Parse command line arguments
  if (argc != 2) {
    std::cerr << "Usage: " << argv[0] << " Filename(.vtp) e.g. Torso.vtp"
              << std::endl;
    return EXIT_FAILURE;
  }

  std::string filename = argv[1];

  // Read all the data from the file
  vtkNew<vtkXMLPolyDataReader> reader;
  reader->SetFileName(filename.c_str());
  reader->Update();

  // Create the tree
  vtkNew<vtkCellLocator> cellLocator;
  cellLocator->SetDataSet(reader->GetOutputAsDataSet());
  cellLocator->BuildLocator();

  double testPoint[3] = {110000, 110000, 0};

  // Find the closest points to TestPoint
  double closestPoint[3];   // the coordinates of the closest point will be
                            // returned here
  double closestPointDist2; // the squared distance to the closest point will be
                            // returned here
  vtkIdType cellId; // the cell id of the cell containing the closest point will
                    // be returned here
  int subId;        // this is rarely used (in triangle strips only, I believe)
  cellLocator->FindClosestPoint(testPoint, closestPoint, cellId, subId,
                                closestPointDist2);

  std::cout << "Coordinates of closest point: " << closestPoint[0] << " "
            << closestPoint[1] << " " << closestPoint[2] << std::endl;
  std::cout << "Squared distance to closest point: " << closestPointDist2
            << std::endl;
  std::cout << "CellId: " << cellId << std::endl;

  return EXIT_SUCCESS;
}

The input polydata was created with the plane source in paraview.

For a plane with 4 cells

plane_4cells.vtp (4.6 KB)

the expected result is returned:

Coordinates of closest point: 10.5 10.5 0
Squared distance to closest point: 2.41954e+10
CellId: 3

However for a plane with the same bounds but finer mesh

plane_56cells.vtp (8.7 KB)

the result is incorrect:

Coordinates of closest point: 2.122e-314 2.54639e-313 0
Squared distance to closest point: -1
CellId: 20

Note that switching to vtkStaticCellLocator also does not work for plane_56cells.vtp. The results are:

Coordinates of closest point: 7.90505e-323 1.35808e-312 9.88131e-324
Squared distance to closest point: inf
CellId: 80

I am using VTK9.2.6 on Ubuntu 22.04.

Are there any limitations on FindClosestPoint that need to be considered or is this a bug?

what do you mean by incorrect/

How did you figure out what the correct result is?

Hi Spiros,

Thanks for replying, I will try to clarify what I mean.

The 2 files I send in my original post contain the same shape (a square located in the xy plane with its edges oriented parallel to the x- and y-axis) with the same bounds. The only difference is the amount of cells that the square is meshed with. Here are screenshots from Paraview:

The test point in the source code has coordinates (110000, 110000, 0), so the closest point on the mesh should be the point with coordinates (10.5, 10.5, 0), which is the top right corner of the square as indicated in pink in the screenshots. The squared distance from the test point to this point is 2*(110000-10.5)^2=24195380220.5.

This is the result I get, when using the file plane_4cells.vtp with the code in the original post. But with the finer mesh in plane_56cells.vtp, no point is found even though the location of the expected closest point is the same between the 2 vtp files.

Does this clarify the issue?

Do I have this correct: the bounds of your test data is (10,10.5, 10,10.5, 0,0), and your test point is 24,195,380,220.5 distant^2? it is almost certainly a numerical issue. You may have to use a different approach with this kind of variation in scale.

Can you explain why you are testing points so far from the dataset/locator? If I understand your application I might be able to offer suggestions. For example, why are you using CellLocator rather than PointLocator to determine closest points?

Typically in application the locators closely “fit” around the dataset, and subsequent operations on the locator are within, or in close proximity to the dataset (e.g., streamline generation, probing). Operating on a locator/dataset at a far removed distance is not typical, and numerics problems would not surprise me at extreme scale.

Thank you for taking interest in the issue. I am using vtkCellLocator::FindClosestPoint because I am interested in the closest location on the mesh surface, which is not necessarily a point of the mesh.

You are correct that the first example was a bit extreme in terms of the length scales. Here is a second attempt to illustrate the problem.

I have a small quad mesh and 2 points (green and red) for which I want to find the closest point on the mesh.

This is the input polydata:
cellLocatorTest.vtp (6.7 KB)

The code I am using is as follows:

#include <vtkCellLocator.h>
#include <vtkNew.h>
#include <vtkXMLPolyDataReader.h>

int main(int argc, char *argv[]) {
  // Parse command line arguments
  if (argc != 2) {
    std::cerr << "Usage: " << argv[0] << " Filename(.vtp)" << std::endl;
    return EXIT_FAILURE;
  }

  std::string filename = argv[1];

  // Read all the data from the file
  vtkNew<vtkXMLPolyDataReader> reader;
  reader->SetFileName(filename.c_str());
  reader->Update();

  // Create the tree
  vtkNew<vtkCellLocator> cellLocator;
  cellLocator->SetDataSet(reader->GetOutputAsDataSet());
  cellLocator->BuildLocator();

  double closestPoint[3];
  double closestPointDist2;
  vtkIdType cellId;
  int subId;

  {
    double testPoint1[3] = {47990.9, -30695.5, 2041.02};
    cellLocator->FindClosestPoint(testPoint1, closestPoint, cellId, subId,
                                  closestPointDist2);

    std::cout << "testPoint1: " << testPoint1[0] << " " << testPoint1[1] << " "
              << testPoint1[2] << std::endl;
    std::cout << "  Coordinates of closest point: " << closestPoint[0] << " "
              << closestPoint[1] << " " << closestPoint[2] << std::endl;
    std::cout << "  Squared distance to closest point: " << closestPointDist2
              << std::endl;
    std::cout << "  CellId: " << cellId << std::endl;
  }

  {
    double testPoint2[3] = {48000.4, -30689., 2041.17};
    cellLocator->FindClosestPoint(testPoint2, closestPoint, cellId, subId,
                                  closestPointDist2);

    std::cout << "testPoint2: " << testPoint2[0] << " " << testPoint2[1] << " "
              << testPoint2[2] << std::endl;
    std::cout << "  CellId: " << cellId << std::endl;
    std::cout << "  Coordinates of closest point: " << closestPoint[0] << " "
              << closestPoint[1] << " " << closestPoint[2] << std::endl;
    std::cout << "  Squared distance to closest point: " << closestPointDist2
              << std::endl;
    std::cout << "  CellId: " << cellId << std::endl;
  }

  return EXIT_SUCCESS;
}

Running this with cellLocatorTest.vtp as command line parameter gives the following output on my machine (Ubuntu 22.04, VTK9.2.6):

testPoint1: 47990.9 -30695.5 2041.02
  Coordinates of closest point: 47990.9 -30695.5 2041.18
  Squared distance to closest point: 0.0254294
  CellId: 17
testPoint2: 48000.4 -30689 2041.17
  Coordinates of closest point: 0 0 6.95331e-310
  Squared distance to closest point: -1
  CellId: 4

Note that vtkStaticCellLocator returns results for both points. The output for testPoint1 is the same and for testPoint2 I get:

testPoint2: 48000.4 -30689 2041.17
  CellId: 23
  Coordinates of closest point: 48000.4 -30689 2041.29
  Squared distance to closest point: 0.0163977
  CellId: 23

So the question is: Why is there no closest point for testPoint2 with vtkCellLocator?

I’m using VTK master on Ubuntu and things seem to be working fine for me. The results are identical for vtkCellLocator and vtkStaticCellLocator. (FYI I removed the duplicate std::cout in your code.)

/ClosestPoint Data/cellLocatorTest.vtp
testPoint1: 47990.9 -30695.5 2041.02
Coordinates of closest point: 47990.9 -30695.5 2041.18
Squared distance to closest point: 0.0254294
CellId: 17
testPoint2: 48000.4 -30689 2041.17
Coordinates of closest point: 48000.4 -30689 2041.29
Squared distance to closest point: 0.0163977
CellId: 23

I’m not sure what’s going on. Since you seem to be code savvy I recommend that you debug through the code to see what’s going on.

I can confirm that the example with cellLocatorTest.vtp works with the vtkCellLocator from the current master branch (commit: 9e6555bad864e1db941773591cb97c0fa82e0d8c). I get the same results as you for both points.

Comparing master with v9.2.6 shows that a change was made to the vtkCellLocator in this commit:

https://gitlab.kitware.com/vtk/vtk/-/commit/08fb2a1d5e56170c7f4b0eee14f15348f30dfda3

Good to know that this is fixed. Thank you for the feedback!