前言:本博文主要研究Tessellator 的Subdivision实现方式,并对涉及到vtk中的所有相关接口进行研究,以期找出网格Remesh的方法。希望此篇文章也能给其他小伙伴带来帮助!
目录
vtkTessellatorFilter
位置:..\Filter\General
描述:对vtkUnstructuredGrid数据集进行简单的非线性近似为有限元分析单元。
该过滤器遍历输入vtkDataSet中的所有单元格。它对每个单元格进行细分,并使用vtkStreamingTessellator和vtkDataSetEdgeSubdivisionCriterion类来生成使用某种近似度量(编码在特定的vtkDataSetEdgeSubdivisionCriterion::EvaluateLocationAndFields实现中)近似非线性网格的简化。通过向三角测量器注册的回调例程AddATetrahedron、AddATriangle和AddALine,将简化放入过滤器的输出vtkDataSet对象中。
输出网格将具有几何图形和在输入网格的点数据中指定为属性的任何字段。属性的复制标志将被保留,除了法线。
实现过程:
过滤器的主要成员函数是RequestData()。这个函数首先调用SetupOutput(),它为原语回调分配数组和一些临时变量(分别由addattriangle和AddALine调用的OutputTriangle和OutputLine)。每个单元格都被赋予一个初始的镶嵌,这将导致一次或多次调用OutputTetrahedron、OutputTriangle或OutputLine来向OutputMesh添加元素。最后,调用Teardown()来释放过滤器的工作空间。
关联接口
vtkDataSetToUnstructuredGridFilter vtkDataSet vtkStreamingTessellator
vtkDataSetEdgeSubdivisionCriterion
vtkEdgeSubdivisonCriterion
描述:该接口用于判定一个线性近似的非线性几何或范围如何进行细分。该接口的所有子类用于决定分段线性近似(三角形,直线,…)对某些非线性几何应进行细分。这一决定可能基于绝对误差度量(和弦误差)或一些依赖于视图的度量(与设备分辨率相比的和弦误差)或一些抽象度量(颜色误差)。通过实现EvaluateLocationAndFields来完成。
VTK示例
位置:GeometricalObject中应用示例QuadraticTetra&QuadraticTetraDemo。
代码:
#include <vtkActor.h>
#include <vtkDataSetMapper.h>
#include <vtkGlyph3D.h>
#include <vtkMinimalStandardRandomSequence.h>
#include <vtkNamedColors.h>
#include <vtkPoints.h>
#include <vtkProperty.h>
#include <vtkQuadraticTetra.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkSmartPointer.h>
#include <vtkSphereSource.h>
#include <vtkTessellatorFilter.h>
#include <vtkUnstructuredGrid.h>
namespace
{
vtkSmartPointer<vtkUnstructuredGrid> MakeQuadraticTetra();
}
int main (int, char *[])
{
vtkSmartPointer<vtkNamedColors> namedColors =
vtkSmartPointer<vtkNamedColors>::New();
vtkSmartPointer<vtkUnstructuredGrid> uGrid =
MakeQuadraticTetra();
vtkSmartPointer<vtkTessellatorFilter> tessellate =
vtkSmartPointer<vtkTessellatorFilter>::New();
tessellate->SetInputData(uGrid);
vtkSmartPointer<vtkDataSetMapper> mapper =
vtkSmartPointer<vtkDataSetMapper>::New();
mapper->SetInputConnection(tessellate->GetOutputPort());
mapper->ScalarVisibilityOff();
// Create an actor for the grid
vtkSmartPointer<vtkActor> actor =
vtkSmartPointer<vtkActor>::New();
actor->SetMapper(mapper);
actor->GetProperty()->SetDiffuseColor(
namedColors->GetColor3d("Tomato").GetData());
actor->GetProperty()->SetEdgeColor(
namedColors->GetColor3d("IvoryBlack").GetData());
actor->GetProperty()->EdgeVisibilityOn();
vtkSmartPointer<vtkSphereSource> sphereSource =
vtkSmartPointer<vtkSphereSource>::New();
sphereSource->SetRadius(0.02);
vtkSmartPointer<vtkGlyph3D> glyph3D =
vtkSmartPointer<vtkGlyph3D>::New();
glyph3D->SetInputData(uGrid);
glyph3D->SetSourceConnection(sphereSource->GetOutputPort());
glyph3D->ScalingOff();
glyph3D->Update();
vtkSmartPointer<vtkDataSetMapper> glyph3DMapper =
vtkSmartPointer<vtkDataSetMapper>::New();
glyph3DMapper->SetInputConnection(glyph3D->GetOutputPort());
glyph3DMapper->ScalarVisibilityOff();
vtkSmartPointer<vtkActor> glyph3DActor =
vtkSmartPointer<vtkActor>::New();
glyph3DActor->SetMapper(glyph3DMapper);
glyph3DActor->GetProperty()->SetColor(
namedColors->GetColor3d("Banana").GetData());
// Visualize
vtkSmartPointer<vtkRenderer> renderer =
vtkSmartPointer<vtkRenderer>::New();
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->SetWindowName("Quadratic Tetra");
renderWindow->AddRenderer(renderer);
vtkSmartPointer<vtkRenderWindowInteractor> interactor =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
interactor->SetRenderWindow(renderWindow);
renderer->AddActor(actor);
renderer->AddActor(glyph3DActor);
renderer->SetBackground(namedColors->GetColor3d("SlateGray").GetData());
renderWindow->Render();
interactor->Start();
return EXIT_SUCCESS;
}
namespace
{
vtkSmartPointer<vtkUnstructuredGrid> MakeQuadraticTetra()
{
vtkSmartPointer<vtkQuadraticTetra> aTetra =
vtkSmartPointer<vtkQuadraticTetra>::New();
vtkSmartPointer<vtkPoints> points =
vtkSmartPointer<vtkPoints>::New();
double *pcoords = aTetra->GetParametricCoords();
vtkSmartPointer<vtkMinimalStandardRandomSequence> rng =
vtkSmartPointer<vtkMinimalStandardRandomSequence>::New();
points->SetNumberOfPoints(aTetra->GetNumberOfPoints());
rng->SetSeed(5070); // for testing
for (auto i = 0; i < aTetra->GetNumberOfPoints(); ++i)
{
double perturbation[3];
for (auto j = 0; j < 3; ++j)
{
rng->Next();
perturbation[j] = rng->GetRangeValue(-0.1, 0.1);
}
aTetra->GetPointIds()->SetId(i, i);
points->SetPoint(i,
*(pcoords + 3 * i) + perturbation[0],
*(pcoords + 3 * i + 1) + perturbation[1],
*(pcoords + 3 * i + 2) + perturbation[2]);
}
// Add the points and tetra to an unstructured grid
vtkSmartPointer<vtkUnstructuredGrid> uGrid =
vtkSmartPointer<vtkUnstructuredGrid>::New();
uGrid->SetPoints(points);
uGrid->InsertNextCell(aTetra->GetCellType(), aTetra->GetPointIds());
return uGrid;
}
}
结论:
1. vtkTessellatorFilter接口只针对近似线性的非线性几何进行划分。 因此才会出现MakeQuadraticTetra函数中对vtkQuadraticTetra的点进行随机偏移处理。若不进行该操作,不会对vtkQuadraticTetra数据进行Subdivision细分。
2. 细分的程度与参数ChordError相关,参数越小,细分次数越多,网格越细。其次细分次数不能超过MaxSubdivisionNumber。
chordError: 0.035 chordError: 0.01
网格Remesh方法
待更新