mesh decimation: vtkBinnedDecimation low quality mesh result vs vtkQuadricDecimation

I want to do stl file decimation in parallel, so I tried vtkBinnedDecimation. The simplified fineness is bad than what using vtkQuadricDecimation.

The origin STL file is 7.3M:
porsche.zip (3.0 MB)

Test using vtkBinnedDecimation

#define GLOG_NO_ABBREVIATED_SEVERITIES

#include <glog/logging.h>
#include <gtest/gtest.h>

#include <vtkBinnedDecimation.h>
#include <vtkSTLReader.h>
#include <vtkSTLWriter.h>
#include <vtkSmartPointer.h>

#include <boost/dll.hpp>
#include <chrono>
#include <cmath>
#include <filesystem>

namespace fs = std::filesystem;

TEST(VTK, binnedDecimation) {
  const auto dir_path = boost::dll::program_location().parent_path();
  const auto input_stl_path = fs::path(dir_path.string()) / "input.stl";
  const auto output_stl_path = fs::path(dir_path.string()) / "output.stl";

  const auto t0 = std::chrono::steady_clock::now();
  const double decimation_ratio = 3;

  // Read the input mesh
  vtkSmartPointer<vtkSTLReader> reader = vtkSmartPointer<vtkSTLReader>::New();
  reader->SetFileName(input_stl_path.c_str());
  reader->Update();
  vtkSmartPointer<vtkPolyData> inputMesh = reader->GetOutput();

  const auto input_mesh_num = inputMesh->GetNumberOfCells();
  const auto input_mesh_axis_num = std::pow(input_mesh_num, 1.0 / 3.0);
  const auto dim = input_mesh_axis_num / std::pow(decimation_ratio, 1.0 / 3.0);
  LOG(INFO) << "input mesh num: " << input_mesh_num << ". input mesh num per axis: " << input_mesh_axis_num << ". dim "
            << dim << std::endl;

  // Create the decimation filter
  auto mesh0 = vtkSmartPointer<vtkBinnedDecimation>::New();
  mesh0->SetInputData(inputMesh);
  mesh0->AutoAdjustNumberOfDivisionsOn();
  mesh0->SetNumberOfDivisions(dim, dim, dim);
  mesh0->ProducePointDataOn();
  mesh0->ProduceCellDataOn();
  mesh0->Update();

  // Write the decimated mesh
  vtkSmartPointer<vtkSTLWriter> writer = vtkSmartPointer<vtkSTLWriter>::New();
  writer->SetFileName(output_stl_path.c_str());
  writer->SetInputConnection(mesh0->GetOutputPort());
  writer->Write();

  const auto t1 = std::chrono::steady_clock::now();
  const auto dur = std::chrono::duration_cast<std::chrono::milliseconds>(t1 - t0).count();
  LOG(INFO) << "vtkQuadricDecimation time: " << dur << " ms\n";
}

The simplified stl file is 4.2M:

Test using vtkQuadricDecimation

#define GLOG_NO_ABBREVIATED_SEVERITIES

#include <glog/logging.h>
#include <gtest/gtest.h>

#include <vtkPolyData.h>
#include <vtkQuadricDecimation.h>
#include <vtkSTLReader.h>
#include <vtkSTLWriter.h>
#include <vtkSmartPointer.h>

#include <boost/dll.hpp>
#include <chrono>
#include <filesystem>

namespace fs = std::filesystem;

TEST(VTK, DECIMATION) {
  const auto dir_path = boost::dll::program_location().parent_path();
  const auto input_stl_path = fs::path(dir_path.string()) / "input.stl";

  const auto t0 = std::chrono::steady_clock::now();

  auto reader = vtkSmartPointer<vtkSTLReader>::New();
  reader->SetFileName(input_stl_path.c_str());
  reader->Update();
  vtkSmartPointer<vtkPolyData> inputMesh = reader->GetOutput();

  // 2. do decimation
  vtkSmartPointer<vtkQuadricDecimation> decimationFilter = vtkSmartPointer<vtkQuadricDecimation>::New();
  decimationFilter->SetInputData(inputMesh);
  decimationFilter->SetTargetReduction(0.5); // Set the desired reduction factor
  decimationFilter->Update();
  vtkSmartPointer<vtkPolyData> outputMesh = decimationFilter->GetOutput();

  // 3. output decimation meshes to output stl file
  auto writer = vtkSmartPointer<vtkSTLWriter>::New();
  const auto output_stl_path = fs::path(dir_path.string()) / "output.stl";
  writer->SetFileName(output_stl_path.c_str());
  writer->SetFileTypeToBinary();
  writer->SetInputData(outputMesh);
  writer->Write();

  const auto t1 = std::chrono::steady_clock::now();
  const auto dur = std::chrono::duration_cast<std::chrono::milliseconds>(t1 - t0).count();
  LOG(INFO) << "vtkQuadricDecimation time: " << dur << " ms\n";
}

The simplified stl file is 3.7M:

Compare two simplified stl files

vtkBinnedDecimation get less vertices / faces than vtkQuadricDecimation, but the result stl file is large than what generated by vtkQuadricDecimation.

Does any suggestions for the test code ?

The whole point of vtkBinnedDecimation is that it trades off mesh quality for speed. For example, it’s typically used in interactive systems like ParaView to on the fly produce a representation that can be generated and interacted with when moving the object / camera. You can improve the results somewhat by playing around with the dimensions (dim in your example). Note that you are setting the binning dimensions but at the same time setting AutoAdjust - pick one or the other. Finally, using vtkStaticCleanPolyData / vtkCleanPolyData after binning to eliminate unused points in the output. As noted in the class documentation, the input points are used in the output to avoid reproducing points - the cleaning filters should fix this I believe.

``