• VTK-vtkImplicitFunction及其子类介绍


    很高兴在雪易的CSDN遇见你 ,给你糖糖

    欢迎大家加入雪易社区-CSDN社区云 


    前言

    本文主要介绍vtkImplicitFunction接口及其子类的实现原理和用途。希望对各位小伙伴有所帮助!

    感谢各位小伙伴的点赞+关注,小易会继续努力分享,一起进步!

    你的点赞就是我的动力(^U^)ノ~YO

    目录

    1. vtkPlane

    2. vtkPolyPlane

    3. vtkPlanes

    4. vtkImplicitSelectionLoop

    5. vtkBox

    6. vtkCone

    7. vtkCylinder

    8. vtkImplicitBoolean


    1. vtkPlane

    描述:vtkPlane提供了各种平面的计算方法,包括点到面的投影,计算点到面的距离及面的法向量等。

    EvaluateFunction: 返回点到平面的距离(正数表示点在平面法向量一侧;反之相反)。

    2. vtkPolyPlane

    描述:vtkPolyPlane是vtkPolyLine在Z轴方向的拉伸,可以在vtkCutter中使用。

    核心算法实现

    ComputeNormals-->计算每条直线所构成的Plane的法向量

     EvaluateFunction实现原理:

    x点在无限直线p1p2上的投影点在p1p2之间

     x点在无限直线p1p2上的投影点在p1的左侧

     x点在无限直线p1p2上的投影点在p1的右侧

     

     for循环:针对每条线

    a. 获取该线的两点p1,p2;

    b. 计算x点到直线p1,p2的距离(采用点到有限直线距离的计算方法,参考 vtk基础知识 博客);

    c. 若x点到直线的最近点在p1,p2之间,则最小距离为x点到直线的距离;计算x点在直线的左侧or右侧。

    d. 若x点在无限直线p1p2上的投影点在p1的左侧,则最小距离为x点到p1点的距离;计算x点在直线与前一条直线的左侧or右侧。

    e. 若x点在无限直线p1p2上的投影点在p1的右侧,则最小距离为x点到p2点的距离;计算x点在直线与后一条直线的左侧or右侧。

    返回x点到vtkPolyPlane的最近距离,以及方向(左侧为正,右侧为负)。

    注意:计算的结果存在的问题,详见VTK裁剪【3】-vtkClipPolyData&vtkPolyPlane问题_雪易的博客-CSDN博客

    3. vtkPlanes

     描述:vtkPlanes计算平面集的函数值和梯度值,其中平面集必须是凸区域

    函数值为每个平面函数值的最大值,梯度值为函数值处的平面的法向量。

    核心算法实现:计算平面集中的最大函数值

    1. // Evaluate plane equations. Return the largest value.
    2. double vtkPlanes::EvaluateFunction(double x[3])
    3. {
    4. int numPlanes, i;
    5. double val, maxVal;
    6. double normal[3], point[3];
    7. if (!this->Points || !this->Normals)
    8. {
    9. vtkErrorMacro(<< "Please define points and/or normals!");
    10. return VTK_DOUBLE_MAX;
    11. }
    12. if ((numPlanes = this->Points->GetNumberOfPoints()) != this->Normals->GetNumberOfTuples())
    13. {
    14. vtkErrorMacro(<< "Number of normals/points inconsistent!");
    15. return VTK_DOUBLE_MAX;
    16. }
    17. for (maxVal = -VTK_DOUBLE_MAX, i = 0; i < numPlanes; i++)
    18. {
    19. this->Normals->GetTuple(i, normal);
    20. this->Points->GetPoint(i, point);
    21. val = this->Plane->Evaluate(normal, point, x);
    22. if (val > maxVal)
    23. {
    24. maxVal = val;
    25. }
    26. }
    27. return maxVal;
    28. }

    vtkPlanes的定义方法

    1. 通过点集和法向量来进行定义

    注意:vtkPlanes为几个平面的集合,但采用vtkClipPolyData进行切割,并不能得到平面包围区域的集合。

    1. vtkPoints* planesPoints = vtkPoints::New();
    2. vtkDoubleArray* Normals = vtkDoubleArray::New();
    3. Normals->SetNumberOfComponents(3);
    4. Normals->Allocate(3 * countOfHandles);
    5. Normals->SetName("Normals");
    6. Normals->SetNumberOfTuples(countOfHandles);
    7. double v[3], p1[3], p2[3], n[3], n2[3];
    8. for (int i = 0; i < countOfHandles; ++i)
    9. {
    10. rep->GetHandlePosition(i, p1);
    11. rep->GetHandlePosition((i + 1) % countOfHandles, p2);
    12. // The line direction vector
    13. v[0] = p2[0] - p1[0];
    14. v[1] = p2[1] - p1[1];
    15. v[2] = p2[2] - p1[2];
    16. double middlePt[3];
    17. middlePt[0] = (p1[0] + p2[0]) / 2;
    18. middlePt[1] = (p1[1] + p2[1]) / 2;
    19. middlePt[2] = (p1[2] + p2[2]) / 2;
    20. // 'n' is the computed normal.
    21. vtkMath::Cross(v, eye_look, n);
    22. vtkMath::Normalize(n);
    23. planesPoints->InsertNextPoint(middlePt);
    24. Normals->SetTuple(i, n);
    25. }

    1. 通过相机进行定义:

    1. // Position the camera so that we can see the frustum
    2. double viewUp[3] = {0.0,1.0,0.0};
    3. double position[3] = {1.0,0.0,0.0};
    4. PositionCamera(renderer, viewUp, position);
    5. renderer->GetActiveCamera()->Elevation(30);
    6. renderer->GetActiveCamera()->SetViewAngle(10.0);
    7. double planesArray[24];
    8. renderer->GetActiveCamera()->GetFrustumPlanes(1.0, planesArray);
    9. vtkSmartPointer planes =
    10. vtkSmartPointer::New();
    11. planes->SetFrustumPlanes(planesArray);

    2. 通过BoundingBox定义

    1. vtkSmartPointer sphereSource =
    2. vtkSmartPointer::New();
    3. sphereSource->Update();
    4. double bounds[6];
    5. sphereSource->GetOutput()->GetBounds(bounds);
    6. vtkSmartPointer box =
    7. vtkSmartPointer::New();
    8. box->SetNumberOfPoints(8);
    9. double xMin, xMax, yMin, yMax, zMin, zMax;
    10. xMin = bounds[0]; xMax = bounds[1];
    11. yMin = bounds[2]; yMax = bounds[3];
    12. zMin = bounds[4]; zMax = bounds[5];
    13. box->SetPoint(0, xMax, yMin, zMax);
    14. box->SetPoint(1, xMax, yMin, zMin);
    15. box->SetPoint(2, xMax, yMax, zMin);
    16. box->SetPoint(3, xMax, yMax, zMax);
    17. box->SetPoint(4, xMin, yMin, zMax);
    18. box->SetPoint(5, xMin, yMin, zMin);
    19. box->SetPoint(6, xMin, yMax, zMin);
    20. box->SetPoint(7, xMin, yMax, zMax);
    21. vtkSmartPointer planesIntersection =
    22. vtkSmartPointer::New();
    23. planesIntersection->SetBounds(bounds);
    24. int intersects = planesIntersection->IntersectsRegion(box);

    4. vtkImplicitSelectionLoop

     描述:vtkImplicitSelectionLoop由一组点构成的不规则的环路,可以计算隐函数的函数值和梯度值。环路可以是凹多边形,构成环路的点集也不需要共面。但是当环路投影到环路定义的平面上时,环路必须是非自相交的。

    核心算法实现(计算点x的隐函数值):

    a. 计算Loop中点集的法线normal;

    b. 定义法线normal和点集构成的平面;

    c. 将循环的每个点投影到上述平面上,形成多边形;

    d. 计算点x到多边形边界的距离,以及是否在多边形内(负值为多边形内;正值为多边形外);

    1. // Evaluate plane equations. Return smallest absolute value.
    2. double vtkImplicitSelectionLoop::EvaluateFunction(double x[3])
    3. {
    4. int i, numPts;
    5. double xProj[3];
    6. double t, dist2, minDist2, closest[3];
    7. int inside = 0;
    8. if (this->InitializationTime < this->GetMTime())
    9. {
    10. this->Initialize();
    11. }
    12. // Initialize may change the number of points
    13. numPts = this->Polygon->Points->GetNumberOfPoints();
    14. // project point onto plane
    15. vtkPlane::ProjectPoint(x, this->Origin, this->Normal, xProj);
    16. // determine whether it's in the selection loop and then evaluate point
    17. // in polygon only if absolutely necessary.
    18. if (xProj[0] >= this->Bounds[0] && xProj[0] <= this->Bounds[1] && xProj[1] >= this->Bounds[2] &&
    19. xProj[1] <= this->Bounds[3] && xProj[2] >= this->Bounds[4] && xProj[2] <= this->Bounds[5] &&
    20. this->Polygon->PointInPolygon(xProj, numPts,
    21. vtkArrayDownCast(this->Polygon->Points->GetData())->GetPointer(0),
    22. this->Bounds, this->Normal) == 1)
    23. {
    24. inside = 1;
    25. }
    26. // determine distance to boundary
    27. for (minDist2 = VTK_DOUBLE_MAX, i = 0; i < numPts; i++)
    28. {
    29. double p1[3], p2[3];
    30. this->Polygon->Points->GetPoint(i, p1);
    31. this->Polygon->Points->GetPoint((i + 1) % numPts, p2);
    32. dist2 = vtkLine::DistanceToLine(xProj, p1, p2, t, closest);
    33. if (dist2 < minDist2)
    34. {
    35. minDist2 = dist2;
    36. }
    37. }
    38. minDist2 = static_cast<double>(sqrt(minDist2));
    39. return (inside ? -minDist2 : minDist2);
    40. }

    应用实例:

    对vtkPolyData数据进行剪切,并没有获取良好的边界,如下图所示。

     

    5. vtkBox

    描述:vtkBox是由轴对齐的边界框构成,并由此计算隐函数值和梯度值。Box的每条边都正交与所有其他边,所有面都正交与x-y-z轴。也可以通过vtkImplicitFunction支持的转换矩阵来定位不同方向的定位框。

    6. vtkCone

    描述:vtkCone是通过圆锥来计算隐函数值和梯度值。圆锥顶点位于原点,其旋转轴与x轴重合;角度是指旋转轴与锥体边的夹角。也可以通过vtkImplicitFunction支持的转换矩阵来定位不同方向的定位框。

    7. vtkCylinder

    描述:vtkCylinder使用F(r)=r^2- radius ^2计算的圆柱来计算隐式函数和函数梯度。默认情况下,圆柱体以原点为中心,旋转轴沿着y轴。可以通过设置center和axis来重新定义旋转的中心和轴。

    注意:圆柱体的范围是无限的。要在建模操作中截断圆柱体,请结合使用vtkImplicitBoolean和剪切平面来进行操作。

    8. vtkImplicitBoolean

    描述:

    应用实例1. 将多个平面进行求交,对PolyData进行Clip和Cutter,但得到的结果不太理想,如下图所示。并没有获得整齐的边界

    应用实例2. 将多个平面放入到vtkPlanes中,仍不能得到整齐的边界。

    1. vtkPoints* planesPoints = vtkPoints::New();
    2. vtkDoubleArray* Normals = vtkDoubleArray::New();
    3. Normals->SetNumberOfComponents(3);
    4. Normals->Allocate(3 * countOfHandles);
    5. Normals->SetName("Normals");
    6. Normals->SetNumberOfTuples(countOfHandles);
    7. double v[3], p1[3], p2[3], n[3], n2[3];
    8. auto boolean =
    9. vtkSmartPointer::New();
    10. boolean->SetOperationTypeToUnion();
    11. for (int i = 0; i < countOfHandles; ++i)
    12. {
    13. rep->GetHandlePosition(i, p1);
    14. rep->GetHandlePosition((i + 1) % countOfHandles, p2);
    15. // The line direction vector
    16. v[0] = p2[0] - p1[0];
    17. v[1] = p2[1] - p1[1];
    18. v[2] = p2[2] - p1[2];
    19. double middlePt[3];
    20. middlePt[0] = (p1[0] + p2[0]) / 2;
    21. middlePt[1] = (p1[1] + p2[1]) / 2;
    22. middlePt[2] = (p1[2] + p2[2]) / 2;
    23. // 'n' is the computed normal.
    24. vtkMath::Cross(v, eye_look, n);
    25. vtkMath::Normalize(n);
    26. planesPoints->InsertNextPoint(middlePt);
    27. Normals->SetTuple(i, n);
    28. vtkPlane* tmpPlane = vtkPlane::New();
    29. tmpPlane->SetNormal(n);
    30. tmpPlane->SetOrigin(middlePt);
    31. boolean->AddFunction(tmpPlane);
    32. }
    33. vtkNew planes;
    34. planes->SetPoints(planesPoints);
    35. planes->SetNormals(Normals);
    36. vtkSmartPointer planesClipper = vtkSmartPointer::New();
    37. planesClipper->SetInputData(m_selectObject->GetPolyData());
    38. planesClipper->SetClipFunction(boolean);
    39. //planesClipper->SetValue(0.);
    40. planesClipper->Update();
    41. if (planesClipper->GetOutput())
    42. {
    43. emit sendTrimResult(planesClipper->GetOutput());
    44. }

    结论:

            本文主要介绍vtkImplicitFunction接口及其子类的实现原理和用途。

    感谢各位小伙伴的点赞+关注,小易会继续努力分享,一起进步!

    你的赞赏是我的最最最最大的动力(^U^)ノ~YO

  • 相关阅读:
    使用VBA打印PDF文件
    【Network】网络基础扫盲
    2022暑期学校C++课程设计课题
    Java线程池的知识
    SQL分页查询,SQL的LIMIT语句用法,SQL如何实现分页查询,SpringBoot实现分页查询。
    K线形态识别_旭日东升
    Kafka系列之:深入理解Kafka Topic数据保留策略
    第5章 - 二阶多智能体系统的协同控制 --> 连续时间含时延系统一致性
    vue页面批量引入组件
    csapp深入理解计算机系统 bomb lab(1)phase_1
  • 原文地址:https://blog.csdn.net/qq_40041064/article/details/127979704