• VTK中Clip/Trim总结


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

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


    前言

    本博文主要介绍VTK中几个常见的Clip/Trim接口,同时介绍下3-matic软件中对应的功能;希望能帮到各位小伙伴,有什么问题欢迎交流学习。

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

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


    目录

    前言

    1. VTK中裁剪接口

    2. vtkClipPolyData 

    3. vtkClipClosedSurface

    4. vtkClipClosedSurface示例

    结论:


    1. VTK中裁剪接口

            vtk中针对剪裁有多个接口,各自有优点和缺点,现详细列出,小伙伴可以有针对性的进行选择接口。裁剪的接口有vtkClipClosedSurface 、vtkClipConvexPolyData 、 vtkClipDataSet 、 vtkClipPolyData 、vtkClipVolume。目前主要介绍vtkClipClosedSurface 、 vtkClipPolyData两个接口。

    效果图

    vtkClipPolyData效果图 

     

    vtkClipClosedSurface效果图 

    两者差异:vtkClipPolyData切割带有锯齿形状且不是封闭的模型;vtkClipClosedSurface通过插值确保切割面为光滑且封闭的。

    2. vtkClipPolyData 

    用途:通过用户定义的隐函数或输入的标量数据,裁剪polygonal data。

            采用隐函数裁剪的方法:定义裁剪隐函数;SetClipFunction; GenerateClipScalarsOn;

    核心算法:

    1. if (this->ClipFunction)
    2. {
    3. vtkFloatArray* tmpScalars = vtkFloatArray::New();
    4. tmpScalars->SetNumberOfTuples(numPts);
    5. inPD = vtkPointData::New();
    6. inPD->ShallowCopy(input->GetPointData()); // copies original
    7. if (this->GenerateClipScalars)
    8. {
    9. inPD->SetScalars(tmpScalars);
    10. }
    11. for (i = 0; i < numPts; i++)
    12. {
    13. //遍历输入数据的每个点,计算是否满足ClipFunction的条件;若ClipFunction为vtkPolyPlane,则判断点是否在PolyLine内,若在内,则s为正数;反之为负数。
    14. s = this->ClipFunction->FunctionValue(inPts->GetPoint(i));
    15. tmpScalars->SetComponent(i, 0, s);
    16. }
    17. clipScalars = tmpScalars;
    18. }
    19. //用上述判定点的结果对cell进行分割
    20. cell->Clip(this->Value, cellScalars, this->Locator, connList, inPD, outPD, inCD, cellId, outCD,
    21. this->InsideOut);

    3. vtkClipClosedSurface

    用途:通过一组切割平面实现对闭合曲面的切割。将输入数据切割未由多边形面组成的闭合曲面。

    约束:输入的曲面不应该有开放的边缘,也不能有任何被两个以上的面共享的边缘。            vtkFeatureEdges过滤器可以用来验证一个数据集是否满足这些条件。此外,输入的面不应该是自相交的,即曲面的各个面应该只与它们的边缘相接触。

    选项:

    a. 如果 "生成轮廓"(GenerateOutline)是打开的,这个过滤器将在剪裁平面与数据相交处生成一个轮廓,如下图所示。

    b. PassPointData;若打开表示将点数据传递给输出,若新点产生时,点数据将会进行插值。此变量默认关闭。

     c. ScalarMode选项将在输出中添加单元格标量,这样生成的面就可以用与原始面不同的颜色显示。可以用与原始表面不同的颜色来显示。

    注意:

    (1)一组切割平面应该是一组凸平面,否则生成的结果可能为空。

    (2)生成的结果为多个平面围成的部分。

    (3)若ScalarMode设置为On时,则是通过标量来映射Mapper的颜色;此时通过

            actor->GetProperty()->SetColor(color);设置颜色时不生效;解决方案:关闭Mapper的

            ScalarVisibility,颜色设置才能生效。

    核心算法:

    1. // Go through the clipping planes and clip the input with each plane
    2. vtkCollectionSimpleIterator iter;
    3. int numPlanes = 0;
    4. if (planes)
    5. {
    6. planes->InitTraversal(iter);
    7. numPlanes = planes->GetNumberOfItems();
    8. }
    9. vtkPlane* plane = nullptr;
    10. for (int planeId = 0; planes && (plane = planes->GetNextPlane(iter)); planeId++)
    11. {
    12. this->UpdateProgress((planeId + 1.0) / (numPlanes + 1.0));
    13. if (this->GetAbortExecute())
    14. {
    15. break;
    16. }
    17. // Is this the last cut plane? If so, generate triangles.
    18. int triangulate = 5;
    19. if (planeId == numPlanes - 1)
    20. {
    21. triangulate = polyMax;
    22. }
    23. // Is this the active plane?
    24. int active = (planeId == this->ActivePlaneId);
    25. // Convert the plane into an easy-to-evaluate function
    26. double pc[4];
    27. plane->GetNormal(pc);
    28. pc[3] = -vtkMath::Dot(pc, plane->GetOrigin());
    29. // Create the clip scalars by evaluating the plane at each point
    30. vtkIdType numPoints = points->GetNumberOfPoints();
    31. pointScalars->SetNumberOfValues(numPoints);
    32. for (vtkIdType pointId = 0; pointId < numPoints; pointId++)
    33. {
    34. double p[3];
    35. points->GetPoint(pointId, p);
    36. //*重要*计算每个点到切平面的距离,若>0表示该点在切平面的法向方向上,若<0表示该点在切平面法向的反方向上
    37. double val = p[0] * pc[0] + p[1] * pc[1] + p[2] * pc[2] + pc[3];
    38. pointScalars->SetValue(pointId, val);
    39. }
    40. // Prepare the output scalars
    41. outLineData->CopyAllocate(inLineData, 0, 0);
    42. outPolyData->CopyAllocate(inPolyData, 0, 0);
    43. // Reset the locator
    44. edgeLocator->Initialize();
    45. // Clip the lines
    46. //*重要*若直线的两点均在切平面法向的相反方向,则过滤掉该直线;若直线的两点均在切平面法向上,则保留该直线;若直线与切平面相交,则对该直线进行插值,保留切平面法向方向上的直线部分。
    47. this->ClipLines(
    48. points, pointScalars, pointData, edgeLocator, lines, newLines, inLineData, outLineData);
    49. // Clip the polys
    50. if (polys)
    51. {
    52. // Get the number of lines remaining after the clipping
    53. vtkIdType numClipLines = newLines->GetNumberOfCells();
    54. // Cut the polys to generate more lines
    55. //*重要*获取组成该多边形的点,若某边与切平面相交则进行插值;
    56. this->ClipAndContourPolys(points, pointScalars, pointData, edgeLocator, triangulate, polys,
    57. newPolys, newLines, inPolyData, outPolyData, outLineData);
    58. // Add scalars for the newly-created contour lines
    59. vtkUnsignedCharArray* scalars =
    60. vtkArrayDownCast(outLineData->GetScalars());
    61. if (scalars)
    62. {
    63. // Set the color to the active color if plane is active
    64. unsigned char* color = colors[1 + active];
    65. unsigned char* activeColor = colors[2];
    66. vtkIdType numLines = newLines->GetNumberOfCells();
    67. for (vtkIdType lineId = numClipLines; lineId < numLines; lineId++)
    68. {
    69. unsigned char oldColor[3];
    70. scalars->GetTypedTuple(lineId, oldColor);
    71. if (numberOfScalarComponents != 3 || oldColor[0] != activeColor[0] ||
    72. oldColor[1] != activeColor[1] || oldColor[2] != activeColor[2])
    73. {
    74. scalars->SetTypedTuple(lineId, color);
    75. }
    76. }
    77. }
    78. // Generate new polys from the cut lines
    79. vtkIdType cellId = newPolys->GetNumberOfCells();
    80. vtkIdType numClipAndContourLines = newLines->GetNumberOfCells();
    81. // Create a polydata for the lines
    82. tmpContourData->SetPoints(points);
    83. tmpContourData->SetLines(newLines);
    84. tmpContourData->BuildCells();
    85. this->TriangulateContours(
    86. tmpContourData, numClipLines, numClipAndContourLines - numClipLines, newPolys, pc);
    87. // Add scalars for the newly-created polys
    88. scalars = vtkArrayDownCast(outPolyData->GetScalars());
    89. if (scalars)
    90. {
    91. unsigned char* color = colors[1 + active];
    92. vtkIdType numCells = newPolys->GetNumberOfCells();
    93. if (numCells > cellId)
    94. {
    95. // The insert allocates space up to numCells-1
    96. scalars->InsertTypedTuple(numCells - 1, color);
    97. for (; cellId < numCells; cellId++)
    98. {
    99. scalars->SetTypedTuple(cellId, color);
    100. }
    101. }
    102. }
    103. // Add scalars to any diagnostic lines that added by
    104. // TriangulateContours(). In usual operation, no lines are added.
    105. scalars = vtkArrayDownCast(outLineData->GetScalars());
    106. if (scalars)
    107. {
    108. unsigned char color[3] = { 0, 255, 255 };
    109. vtkIdType numCells = newLines->GetNumberOfCells();
    110. if (numCells > numClipAndContourLines)
    111. {
    112. // The insert allocates space up to numCells-1
    113. scalars->InsertTypedTuple(numCells - 1, color);
    114. for (vtkIdType lineCellId = numClipAndContourLines; lineCellId < numCells; lineCellId++)
    115. {
    116. scalars->SetTypedTuple(lineCellId, color);
    117. }
    118. }
    119. }
    120. }
    121. // Swap the lines, points, etcetera: old output becomes new input
    122. vtkCellArray* tmp1 = lines;
    123. lines = newLines;
    124. newLines = tmp1;
    125. newLines->Initialize();
    126. if (polys)
    127. {
    128. vtkCellArray* tmp2 = polys;
    129. polys = newPolys;
    130. newPolys = tmp2;
    131. newPolys->Initialize();
    132. }
    133. vtkCellData* tmp4 = inLineData;
    134. inLineData = outLineData;
    135. outLineData = tmp4;
    136. outLineData->Initialize();
    137. vtkCellData* tmp5 = inPolyData;
    138. inPolyData = outPolyData;
    139. outPolyData = tmp5;
    140. outPolyData->Initialize();
    141. }

    4. vtkClipClosedSurface示例

            》vtkAreaPicker:获取裁剪平面

            》vtkClipClosedSurface:完成裁剪

    代码:

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. #include
    11. #include
    12. #include
    13. #include
    14. #include
    15. #include
    16. #include
    17. #include
    18. #include
    19. #include
    20. #include
    21. #include
    22. #include
    23. #include
    24. #include
    25. #include
    26. #include
    27. #include
    28. #include "vtkClipClosedSurface.h"
    29. #include "vtkPlaneCollection.h"
    30. #include "vtkAxesActor.h"
    31. #define VTKISRBP_ORIENT 0
    32. #define VTKISRBP_SELECT 1
    33. namespace {
    34. // Define interaction style
    35. class HighlightInteractorStyle : public vtkInteractorStyleRubberBandPick
    36. {
    37. public:
    38. static HighlightInteractorStyle* New();
    39. vtkTypeMacro(HighlightInteractorStyle, vtkInteractorStyleRubberBandPick);
    40. HighlightInteractorStyle() : vtkInteractorStyleRubberBandPick()
    41. {
    42. this->SelectedMapper = vtkSmartPointer::New();
    43. this->SelectedActor = vtkSmartPointer::New();
    44. this->SelectedActor->SetMapper(SelectedMapper);
    45. }
    46. virtual void OnLeftButtonUp() override
    47. {
    48. // Forward events
    49. vtkInteractorStyleRubberBandPick::OnLeftButtonUp();
    50. if (this->CurrentMode == VTKISRBP_SELECT)
    51. {
    52. vtkNew colors;
    53. vtkPlanes* frustum = static_cast(this->GetInteractor()->GetPicker())->GetFrustum();
    54. vtkNew planeCollection;
    55. int pCount = frustum->GetNumberOfPlanes() - 2;
    56. for (int i = 0; i < pCount; i++)
    57. {
    58. double normal[3];
    59. frustum->GetPlane(i)->GetNormal(normal);
    60. double origin[3];
    61. frustum->GetPlane(i)->GetOrigin(origin);
    62. vtkNew plane;
    63. plane->SetOrigin(origin[0], origin[1], origin[2]);
    64. plane->SetNormal(-normal[0], -normal[1], -normal[2]);
    65. planeCollection->AddItem(plane);
    66. }
    67. vtkNew clipper;
    68. clipper->SetInputData(this->PolyData);
    69. clipper->SetClippingPlanes(planeCollection);
    70. clipper->Update();
    71. if (m_SrcActor != nullptr)
    72. m_SrcActor->VisibilityOff();
    73. this->SelectedMapper->SetInputData(clipper->GetOutput());
    74. this->SelectedActor->GetProperty()->SetColor(1.0000, 0.3882, 0.2784);
    75. this->GetInteractor()->GetRenderWindow()->GetRenderers()->GetFirstRenderer()->AddActor(SelectedActor);
    76. this->GetInteractor()->GetRenderWindow()->Render();
    77. this->HighlightProp(NULL);
    78. }
    79. }
    80. void SetPolyData(vtkSmartPointer polyData)
    81. {
    82. this->PolyData = polyData;
    83. }
    84. vtkActor* m_SrcActor = nullptr;
    85. private:
    86. vtkSmartPointer PolyData;
    87. vtkSmartPointer SelectedActor;
    88. vtkSmartPointer SelectedMapper;
    89. };
    90. vtkStandardNewMacro(HighlightInteractorStyle);
    91. } // namespace
    92. int main(int argc, char* argv[])
    93. {
    94. vtkNew source;
    95. source->SetPhiResolution(49);
    96. source->SetThetaResolution(200);
    97. source->Update();
    98. auto polyData = source->GetOutput();
    99. // Create a mapper and actor
    100. vtkNew mapper;
    101. mapper->SetInputData(polyData);
    102. mapper->ScalarVisibilityOff();
    103. vtkNew actor;
    104. actor->SetMapper(mapper);
    105. actor->GetProperty()->SetPointSize(5);
    106. vtkNew axes;
    107. // Visualize
    108. vtkNew renderer;
    109. renderer->UseHiddenLineRemovalOn();
    110. vtkNew renderWindow;
    111. renderWindow->AddRenderer(renderer);
    112. renderWindow->SetSize(640, 480);
    113. renderWindow->SetWindowName("HighlightSelection");
    114. vtkNew areaPicker;
    115. vtkNew renderWindowInteractor;
    116. renderWindowInteractor->SetPicker(areaPicker);
    117. renderWindowInteractor->SetRenderWindow(renderWindow);
    118. renderer->AddActor(actor);
    119. renderer->AddActor(axes);
    120. renderWindow->Render();
    121. vtkNew style;
    122. style->m_SrcActor = actor;
    123. style->SetPolyData(polyData);
    124. style->SetCurrentRenderer(renderer);
    125. renderWindowInteractor->SetInteractorStyle(style);
    126. renderWindowInteractor->Start();
    127. return EXIT_SUCCESS;
    128. }

    结论:

            本文主要介绍了vtkClipPolyData 和 vtkClipClosedSurface两个接口的使用方法、两者的处理结果和缺点。

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

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

  • 相关阅读:
    达梦数据库(十) -------- mybatis-plus 整合达梦时,自动生成的 sql 语句报错
    计算机毕业设计 基于微信小程序的校园商铺系统的设计与实现 Java实战项目 附源码+文档+视频讲解
    企业如何实时监管员工聊天&红包转账记录?
    ur机械臂cb系统升级以及安装robotiq 夹爪 URcap插件
    适用场景全新升级!扩展 Dragonfly2 作为分布式缓存系统架构 | 龙蜥技术
    SpringBoot项目结合mybatis generator自动生成代码
    MVC模式
    打造千万级流量秒杀系统第四课 系统架构:如何设计秒杀的系统架构?
    Python标准库中内置装饰器@staticmethod@classmethod
    Springboot 整合 Elasticsearch(五):使用RestHighLevelClient操作ES ②
  • 原文地址:https://blog.csdn.net/qq_40041064/article/details/127789425