vtkPolyDataNormals gives a slightly other output on Lnx than Win/Mac
We are using several VTK classes/filters and this is the first case when one platform provides different results than the other. It might have looked like a small issue, but consider that we are using VTK together with many other libraries and our workflow goes through Win, Lnx, Mac, so when bugs are hidden between "small differences" it makes tracking/debugging and test coverage process very painful.
Expected:
vtkPolyDataNormals provides the same output in Win, Lnx and Mac.
(The vtkTriangleMeshPointNormals, which is "fast version of vtkPolyDataNormals", returns consistent results)
Observed:
Small differences as in the picture below. I've also attached CentOS7Dbg.log MacOsDbg.log WinDbg.log. Win is Windows 10 VS2022, MacOS XCode13, Linux CentOS7 gcc11, all of them 64bit, C++17.
How to reproduce:
Use below code and attached refAsSeparatedSurfaceMesh1.vtp file to reproduce the problem.
#include <iostream>
#include <vtkSmartPointer.h>
#include <vtkPointData.h>
#include <vtkPolyData.h>
#include "vtkXMLPolyDataReader.h"
#include "vtkPolyDataNormals.h"
#include <vtkTriangleMeshPointNormals.h>
void dumpNormals(vtkDataSet* dataSet)
{
vtkPointData* pd = dataSet->GetPointData();
if (!pd)
{
std::cout << "Missing vtkPointData!" << std::endl;
return;
}
vtkDataArray* normArray = pd->GetNormals();
// normArray->Print(std::cout);
if (!normArray)
{
std::cout << "Missing Normals!" << std::endl;
return;
}
#ifdef __GNUG__
int prec = __FLT_DECIMAL_DIG__;
#else
int prec = FLT_DECIMAL_DIG;
#endif
std::cout << "---" << std::endl;
for (vtkIdType i = 0; i < dataSet->GetNumberOfPoints(); i++)
{
double point[3];
normArray->GetTuple(i, point);
std::cout << std::setprecision(prec) << point[0] << " " << point[1] << " " << point[2] << std::endl;
}
std::cout << "---" << std::endl;
}
int main(int argc, char* argv[])
{
if (argc < 2)
{
std::cerr << "Usage: " << argv[0] << " SurfaceMesh.vtp" << std::endl;
return EXIT_FAILURE;
}
vtkSmartPointer<vtkXMLPolyDataReader> reader = vtkSmartPointer<vtkXMLPolyDataReader>::New();
reader->SetFileName(argv[1]);
reader->Update();
reader->GetOutput()->Register(reader);
vtkPolyData* polyData = reader->GetOutput();
// Generate a report
std::cout << "------------------------" << std::endl
<< "The " << argv[1] << std::endl << " contains a " << polyData->GetClassName()
<< " that has " << polyData->GetNumberOfPoints() << " points." << std::endl;
// Check point data for Normals
// dumpNormals(polyData);
// Remove existing Normals from point data
polyData->GetPointData()->RemoveArray("Normals");
std::cout << "Existing Normals Removed" << std::endl;
// Check Normals - should be absent
dumpNormals(polyData);
// Generate new Normals
vtkSmartPointer<vtkPolyDataNormals> normalGenerator = vtkSmartPointer<vtkPolyDataNormals>::New();
// normalGenerator->SetOutputPointsPrecision(vtkAlgorithm::DesiredOutputPrecision::SINGLE_PRECISION);
// normalGenerator->SetOutputPointsPrecision(vtkAlgorithm::DesiredOutputPrecision::DOUBLE_PRECISION);
normalGenerator->SetInputData(polyData);
normalGenerator->ComputePointNormalsOn();
normalGenerator->ComputeCellNormalsOn();
normalGenerator->Update();
//vtkSmartPointer<vtkTriangleMeshPointNormals> normalGenerator = vtkSmartPointer<vtkTriangleMeshPointNormals>::New();
//normalGenerator->SetInputData(polyData);
//normalGenerator->Update();
// Dump new Normals
std::cout << "Newely generated Normals are:" << std::endl;
dumpNormals(normalGenerator->GetOutput());
return EXIT_SUCCESS;
}
Shape is simple - it is just cylinder.
Thank You in advance!