如何正确使用VTK ConstrainedDelaunay2D?

How to correctly use VTK ConstrainedDelaunay2D?

我从VTK ConstrainedDelaunay2D example开始,加上自己的观点:

#include <vtkSmartPointer.h>
#include <vtkDelaunay2D.h>

#include <vtkCellArray.h>
#include <vtkProperty.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkPoints.h>
#include <vtkPolyData.h>
#include <vtkPolygon.h>
#include <vtkMath.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkNamedColors.h>
#include <vtkVersionMacros.h> // For version macros

int main(int, char *[])
{
  vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
  
  int ptsHeight = 400;
  std::vector<std::vector<int>> pts{ {166, 127},{103, 220},{166, 190},{174, 291},{189, 226},{227, 282},{213, 187},{242, 105},{196, 131},{182, 83} };
  for (size_t i = 0; i < pts.size(); i++)
  {
      // !important: flip y
      int x = pts[i][0];
      int y = ptsHeight - pts[i][1];
      points->InsertNextPoint(x, y, 0);
  }

  vtkSmartPointer<vtkPolyData> aPolyData = vtkSmartPointer<vtkPolyData>::New();
  aPolyData->SetPoints(points);

  // Create a cell array to store the polygon in
  vtkSmartPointer<vtkCellArray> aCellArray = vtkSmartPointer<vtkCellArray>::New();

  // Define a polygonal hole with a clockwise polygon
  vtkSmartPointer<vtkPolygon> aPolygon = vtkSmartPointer<vtkPolygon>::New();

  for (unsigned int i = 0; i < pts.size(); i++)
  {
      aPolygon->GetPointIds()->InsertNextId(i); 
  }

  aCellArray->InsertNextCell(aPolygon);

  // Create a polydata to store the boundary. The points must be the
  // same as the points we will triangulate.
  vtkSmartPointer<vtkPolyData> boundary =
   vtkSmartPointer<vtkPolyData>::New();
  boundary->SetPoints(aPolyData->GetPoints());
  boundary->SetPolys(aCellArray);

  // Triangulate the grid points
  vtkSmartPointer<vtkDelaunay2D> delaunay =
   vtkSmartPointer<vtkDelaunay2D>::New();
  delaunay->SetInputData(aPolyData);
  delaunay->SetSourceData(boundary);

  // Visualize
  vtkSmartPointer<vtkPolyDataMapper> meshMapper =
    vtkSmartPointer<vtkPolyDataMapper>::New();
  meshMapper->SetInputConnection(delaunay->GetOutputPort());
  
  vtkSmartPointer<vtkNamedColors> colors =
    vtkSmartPointer<vtkNamedColors>::New();

  vtkSmartPointer<vtkActor> meshActor =
    vtkSmartPointer<vtkActor>::New();
  meshActor->SetMapper(meshMapper);
  meshActor->GetProperty()->EdgeVisibilityOn();
  meshActor->GetProperty()->SetEdgeColor(colors->GetColor3d("Peacock").GetData());
  meshActor->GetProperty()->SetInterpolationToFlat();
  meshActor->GetProperty()->SetBackfaceCulling(true);

  // Create a renderer, render window, and interactor
  vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
  vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
  renderWindow->AddRenderer(renderer);

  vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
  renderWindowInteractor->SetRenderWindow(renderWindow);

  // Add the actor to the scene
  renderer->AddActor(meshActor);
  //renderer->AddActor(boundaryActor);
  renderer->SetBackground(colors->GetColor3d("Mint").GetData());

  // Render and interact
  renderWindow->SetSize(640, 480);
  renderWindow->Render();
  renderWindowInteractor->Start();

  return EXIT_SUCCESS;
} 

我遇到了两个问题:

  1. 如果我翻转 Y 坐标,我会得到不同的结果:这是为什么?
  2. 为什么有些面指向错误的方向(翻转正常/错误绕组)?

这是第一期的意思:

如果我不翻转 Y 坐标,我会得到这个:

如果我不翻转 Y 轴而是以相反的顺序插入边界多边形,我会得到相同的效果:

for (unsigned int i = 0; i < pts.size(); i++)
  {
      aPolygon->GetPointIds()->InsertNextId(pts.size() - 1 - i); 
  }

我不认为我完全理解 boundary/constraint 是如何工作的。 我认为无论顶点是否垂直翻转,相同的点都应该产生相同的三角剖分。 (我怀疑索引的顺序会改变?)

关于第二个问题(不可预知的翻转脸)我不确定最好的前进方向是什么。我查看了 vtkDelaunay2D class,但找不到任何相关内容。 (我尝试过将投影平面模式设置为VTK_DELAUNAY_XY_PLANE,但似乎没有影响输出)

我也尝试过使用 vtkPolyDataNormals 但没有输出:

vtkSmartPointer<vtkPolyDataNormals> normalGenerator = vtkSmartPointer<vtkPolyDataNormals>::New();
normalGenerator->SetInputData(delaunay->GetOutput());
normalGenerator->ComputePointNormalsOff();
normalGenerator->ComputeCellNormalsOn();
normalGenerator->FlipNormalsOn();
normalGenerator->Update();

normalGenerator 的输出有 0 个单元格和点)

有没有办法计算二维点列表的约束 delaunay 三角剖分并确保所有面都指向相同的方向? (如果是这样,怎么做?是否可以单独使用 vtkDelaunay2D class 或是否有必要使用其他过滤器?)

欢迎任何 hints/tips :)

顺便说一句,我正在使用 VTK 8.2。

y 方向的翻转有效地反转了面的方向(顺时针变为逆时针,就像在镜子中一样)。 我不确定我能否重现您上面的示例。 python 中的快速测试似乎给出了预期的行为,也许您可​​以从 this 开始并将其映射到您的 c++ 版本:

import vedo

pts = [
    [166, 127],
    [103, 220],
    [166, 190],
    [174, 291],
    [189, 226],
    [227, 282],
    [213, 187],
    [242, 105],
    [196, 131],
    [182, 83],
]

ids = [[2,4,6], [0,2,8]]  # faces to erase by pt-index (clockwise)
dly = vedo.delaunay2D(pts, mode='xy', boundaries=ids)
dly.c('grey5').lc('red4').lw(2)

labels = vedo.Points(pts).labels('id').z(1)

vedo.show(labels, dly, axes=1)