求两个多边形数据 vtkPolyData 的相交线
2016-09-13 11:39
666 查看
vtkIntersectionPolyDataFilter
【简介】
该滤波器计算两个多边形数据 vtkPolyData 的交集。
其第一个输出是 交集线集( a set of lines );
第二个和第三个输出分别为第一和第二个输入 vtkPolyData.
如果需要,后两个输出可以被相交线分割。
【示例】
可以看出使用是非常简单的,
【类实现部分】
输入两个多边形数据信息,调用Update() 函数就可以得到像个多边形数据相交的数据信息:
【类实现过程的分析】
其实内部还有很多东西是可以学习的,接下来就分析一下 这个类的源代码:
可以看出该类的基类是 vtkPolyDataAlgorithm ,所以这个类中最为重要的函数就是
通过前面文章的分析可以知道,该类调用 Update() 函数的过程中系统会自动调用这个 RequestData() 这个函数。
该类的实现部分:
分析:
对输入的两个面数据 mesh0 + mesh1 分别建立一个 vtkOBBTree
两个OBB树调用 IntersectWithOBBTree() , 遍历两个树的每个节点,并通过调用 FindTriangleIntersections() 函数找所有的相交线,作为第一个输出
每个面数据调用 SplitMesh() 函数 将面重新三角化,作为第二三个输出,通过调用 intersectionPolyDataFilter->SetSplitFirstOutput(0); 来决定是否重新三角化,如果用不到重新三角化的数据,可以将 off 掉这个功能,加速。
对于输入面的重新三角化的结果:
图中蓝色为相交面,绿色为源数据信息,红色为重新三角化后的输出数据。
【内部分析】
第一个有趣的地方:
(这样子看,觉得这个挺好的)
第二个有趣的地方:
类的定义出就写着 Private implementation to hide STL.
第一个公有函数:
遍历两个树中某两个节点中的每个 cell ,调用函数 TriangleTriangleIntersection 求出两个三角形相交的线,相交线段的两个端点 outpt0, outpt1
我自己觉得比较麻烦的地方就是为了 vtkIntersectionPolyDataFilter::Impl *info 这个变量各种成员属性的赋值,可能是最近变笨了,所以对于有很多属性的类有点迷茫,会忘记、混淆。。。
对于vtkIdTypeArray的操作也不熟
【简介】
该滤波器计算两个多边形数据 vtkPolyData 的交集。
其第一个输出是 交集线集( a set of lines );
第二个和第三个输出分别为第一和第二个输入 vtkPolyData.
如果需要,后两个输出可以被相交线分割。
【示例】
#include <vtkActor.h> #include <vtkIntersectionPolyDataFilter.h> #include <vtkPolyDataMapper.h> #include <vtkProperty.h> #include <vtkRenderer.h> #include <vtkRenderWindow.h> #include <vtkRenderWindowInteractor.h> #include <vtkSmartPointer.h> #include <vtkSphereSource.h> int main(int, char *[]) { vtkSmartPointer<vtkSphereSource> sphereSource1 = vtkSmartPointer<vtkSphereSource>::New(); sphereSource1->SetCenter(0.0, 0.0, 0.0); sphereSource1->SetRadius(2.0f); sphereSource1->Update(); vtkSmartPointer<vtkPolyDataMapper> sphere1Mapper = vtkSmartPointer<vtkPolyDataMapper>::New(); sphere1Mapper->SetInputConnection( sphereSource1->GetOutputPort() ); sphere1Mapper->ScalarVisibilityOff(); vtkSmartPointer<vtkActor> sphere1Actor = vtkSmartPointer<vtkActor>::New(); sphere1Actor->SetMapper( sphere1Mapper ); //sphere1Actor->GetProperty()->SetOpacity(.7); sphere1Actor->GetProperty()->SetColor(1,0,0); sphere1Actor->GetProperty()->SetRepresentationToWireframe(); vtkSmartPointer<vtkSphereSource> sphereSource2 = vtkSmartPointer<vtkSphereSource>::New(); sphereSource2->SetCenter(1.0, 0.0, 0.0); sphereSource2->SetRadius(2.0f); vtkSmartPointer<vtkPolyDataMapper> sphere2Mapper = vtkSmartPointer<vtkPolyDataMapper>::New(); sphere2Mapper->SetInputConnection( sphereSource2->GetOutputPort() ); sphere2Mapper->ScalarVisibilityOff(); vtkSmartPointer<vtkActor> sphere2Actor = vtkSmartPointer<vtkActor>::New(); sphere2Actor->SetMapper( sphere2Mapper ); //sphere2Actor->GetProperty()->SetOpacity(.7); sphere2Actor->GetProperty()->SetColor(0,1,0); sphere2Actor->GetProperty()->SetRepresentationToWireframe(); vtkSmartPointer<vtkIntersectionPolyDataFilter> intersectionPolyDataFilter = vtkSmartPointer<vtkIntersectionPolyDataFilter>::New(); intersectionPolyDataFilter->SetInputConnection( 0, sphereSource1->GetOutputPort() ); intersectionPolyDataFilter->SetInputConnection( 1, sphereSource2->GetOutputPort() ); intersectionPolyDataFilter->Update(); vtkSmartPointer<vtkPolyDataMapper> intersectionMapper = vtkSmartPointer<vtkPolyDataMapper>::New(); intersectionMapper->SetInputConnection( intersectionPolyDataFilter->GetOutputPort() ); intersectionMapper->ScalarVisibilityOff(); vtkSmartPointer<vtkActor> intersectionActor = vtkSmartPointer<vtkActor>::New(); intersectionActor->SetMapper( intersectionMapper ); vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New(); renderer->AddViewProp(sphere1Actor); renderer->AddViewProp(sphere2Actor); renderer->AddViewProp(intersectionActor); intersectionActor->GetProperty()->SetColor(0,0,1); vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New(); renderWindow->AddRenderer( renderer ); vtkSmartPointer<vtkRenderWindowInteractor> renWinInteractor = vtkSmartPointer<vtkRenderWindowInteractor>::New(); renWinInteractor->SetRenderWindow( renderWindow ); renderWindow->Render(); renWinInteractor->Start(); return EXIT_SUCCESS; }
可以看出使用是非常简单的,
【类实现部分】
vtkSmartPointer<vtkIntersectionPolyDataFilter> intersectionPolyDataFilter = vtkSmartPointer<vtkIntersectionPolyDataFilter>::New(); intersectionPolyDataFilter->SetInputConnection( 0, sphereSource1->GetOutputPort() ); intersectionPolyDataFilter->SetInputConnection( 1, sphereSource2->GetOutputPort() ); intersectionPolyDataFilter->Update();
输入两个多边形数据信息,调用Update() 函数就可以得到像个多边形数据相交的数据信息:
intersectionMapper->SetInputConnection( <span style="background-color: rgb(255, 153, 255);">intersectionPolyDataFilter->GetOutputPort()</span> );
【类实现过程的分析】
其实内部还有很多东西是可以学习的,接下来就分析一下 这个类的源代码:
可以看出该类的基类是 vtkPolyDataAlgorithm ,所以这个类中最为重要的函数就是
int | RequestData (vtkInformation *,vtkInformationVector **, vtkInformationVector *) |
该类的实现部分:
int vtkIntersectionPolyDataFilter::RequestData(vtkInformation* vtkNotUsed(request), vtkInformationVector** inputVector, vtkInformationVector* outputVector) { vtkInformation* inInfo0 = inputVector[0]->GetInformationObject(0); vtkInformation* inInfo1 = inputVector[1]->GetInformationObject(0); vtkInformation* outIntersectionInfo = outputVector->GetInformationObject(0); vtkInformation* outPolyDataInfo0 = outputVector->GetInformationObject(1); vtkInformation* outPolyDataInfo1 = outputVector->GetInformationObject(2); vtkPolyData *input0 = vtkPolyData::SafeDownCast(inInfo0->Get(vtkDataObject::DATA_OBJECT())); vtkPolyData *input1 = vtkPolyData::SafeDownCast(inInfo1->Get(vtkDataObject::DATA_OBJECT())); vtkPolyData *outputIntersection = vtkPolyData::SafeDownCast(outIntersectionInfo->Get(vtkDataObject::DATA_OBJECT())); vtkSmartPointer< vtkPoints > outputIntersectionPoints = vtkSmartPointer< vtkPoints >::New(); outputIntersection->SetPoints(outputIntersectionPoints); vtkPolyData *outputPolyData0 = vtkPolyData::SafeDownCast(outPolyDataInfo0->Get(vtkDataObject::DATA_OBJECT())); vtkPolyData *outputPolyData1 = vtkPolyData::SafeDownCast(outPolyDataInfo1->Get(vtkDataObject::DATA_OBJECT())); // Set up new poly data for the inputs to build cells and links. vtkSmartPointer< vtkPolyData > mesh0 = vtkSmartPointer< vtkPolyData >::New(); mesh0->DeepCopy(input0); vtkSmartPointer< vtkPolyData > mesh1 = vtkSmartPointer< vtkPolyData >::New(); mesh1->DeepCopy(input1); // Find the triangle-triangle intersections between mesh0 and mesh1 vtkSmartPointer< vtkOBBTree > obbTree0 = vtkSmartPointer< vtkOBBTree >::New(); obbTree0->SetDataSet(mesh0); obbTree0->SetNumberOfCellsPerNode(10); obbTree0->SetMaxLevel(1000000); obbTree0->SetTolerance(1e-6); obbTree0->AutomaticOn(); obbTree0->BuildLocator(); vtkSmartPointer< vtkOBBTree > obbTree1 = vtkSmartPointer< vtkOBBTree >::New(); obbTree1->SetDataSet(mesh1); obbTree1->SetNumberOfCellsPerNode(10); obbTree1->SetMaxLevel(1000000); obbTree1->SetTolerance(1e-6); obbTree1->AutomaticOn(); obbTree1->BuildLocator(); // Set up the structure for determining exact triangle-triangle intersections. vtkIntersectionPolyDataFilter::Impl *impl = new vtkIntersectionPolyDataFilter::Impl(); impl->Mesh[0] = mesh0; impl->Mesh[1] = mesh1; impl->OBBTree1 = obbTree1; vtkSmartPointer< vtkCellArray > lines = vtkSmartPointer< vtkCellArray >::New(); outputIntersection->SetLines(lines); impl->IntersectionLines = lines; // Add cell data arrays that map the intersection line to the cells // it splits. impl->CellIds[0] = vtkIdTypeArray::New(); impl->CellIds[0]->SetName("Input0CellID"); outputIntersection->GetCellData()->AddArray(impl->CellIds[0]); impl->CellIds[0]->Delete(); impl->CellIds[1] = vtkIdTypeArray::New(); impl->CellIds[1]->SetName("Input1CellID"); outputIntersection->GetCellData()->AddArray(impl->CellIds[1]); impl->CellIds[1]->Delete(); impl->PointCellIds[0] = vtkIdTypeArray::New(); impl->PointCellIds[0]->SetName("PointCellsIDs"); impl->PointCellIds[1] = vtkIdTypeArray::New(); impl->PointCellIds[1]->SetName("PointCellsIDs"); double bounds0[6], bounds1[6]; mesh0->GetBounds(bounds0); mesh1->GetBounds(bounds1); for (int i = 0; i < 3; i++) { int minIdx = 2*i; int maxIdx = 2*i+1; if (bounds1[minIdx] < bounds0[minIdx]) { bounds0[minIdx] = bounds1[minIdx]; } if (bounds1[maxIdx] > bounds0[maxIdx]) { bounds0[maxIdx] = bounds1[maxIdx]; } } vtkSmartPointer< vtkPointLocator > pointMerger = vtkSmartPointer< vtkPointLocator >::New(); pointMerger->SetTolerance(1e-6); pointMerger->InitPointInsertion(outputIntersection->GetPoints(), bounds0); impl->PointMerger = pointMerger; // This performs the triangle intersection search obbTree0->IntersectWithOBBTree (obbTree1, 0, vtkIntersectionPolyDataFilter::Impl::FindTriangleIntersections, impl); // Split the first output if so desired if ( this->SplitFirstOutput ) { // 默认执行 mesh0->BuildLinks(); impl->SplitMesh(0, outputPolyData0, outputIntersection); } else { outputPolyData0->ShallowCopy( mesh0 ); } // Split the second output if desired if ( this->SplitSecondOutput ) { mesh1->BuildLinks(); impl->SplitMesh(1, outputPolyData1, outputIntersection); } else { outputPolyData1->ShallowCopy( mesh1 ); } impl->PointCellIds[0]->Delete(); impl->PointCellIds[1]->Delete(); delete impl; return 1; }
分析:
对输入的两个面数据 mesh0 + mesh1 分别建立一个 vtkOBBTree
两个OBB树调用 IntersectWithOBBTree() , 遍历两个树的每个节点,并通过调用 FindTriangleIntersections() 函数找所有的相交线,作为第一个输出
每个面数据调用 SplitMesh() 函数 将面重新三角化,作为第二三个输出,通过调用 intersectionPolyDataFilter->SetSplitFirstOutput(0); 来决定是否重新三角化,如果用不到重新三角化的数据,可以将 off 掉这个功能,加速。
对于输入面的重新三角化的结果:
图中蓝色为相交面,绿色为源数据信息,红色为重新三角化后的输出数据。
【内部分析】
第一个有趣的地方:
typedef struct _CellEdgeLine { vtkIdType CellId; vtkIdType EdgeId; vtkIdType LineId; } CellEdgeLineType; typedef std::multimap< vtkIdType, CellEdgeLineType > PointEdgeMapType; typedef PointEdgeMapType::iterator PointEdgeMapIteratorType;根据之后代码的分析,我才发现,这个地方主要是为了实现 multimap 的遍历:
PointEdgeMapType *PointEdgeMap[2]; PointEdgeMapIteratorType iterLower = this->PointEdgeMap[index]->lower_bound( ptId ); PointEdgeMapIteratorType iterUpper = this->PointEdgeMap[index]->upper_bound( ptId ); while (iterLower != iterUpper) { if ( iterLower->second.CellId == cellId ) { return; } ++iterLower; }
(这样子看,觉得这个挺好的)
第二个有趣的地方:
类的定义出就写着 Private implementation to hide STL.
class vtkIntersectionPolyDataFilter::Impl { public: Impl(); virtual ~Impl(); static int FindTriangleIntersections(vtkOBBNode *node0, vtkOBBNode *node1, vtkMatrix4x4 *transform, void *arg); int SplitMesh(int inputIndex, vtkPolyData *output, vtkPolyData *intersectionLines); protected: vtkCellArray* SplitCell(vtkPolyData *input, vtkIdType cellId, vtkIdType *cellPts, IntersectionMapType *map, vtkPolyData *interLines); void AddToPointEdgeMap(int index, vtkIdType ptId, double x[3], vtkPolyData *mesh, vtkIdType cellId, vtkIdType edgeId, vtkIdType lineId, vtkIdType triPts[3]); void SplitIntersectionLines(int inputIndex, vtkPolyData *sourceMesh, vtkPolyData *splitLines); public: vtkPolyData *Mesh[2]; vtkOBBTree *OBBTree1; // Stores the intersection lines. vtkCellArray *IntersectionLines; // Cell data that indicates in which cell each intersection // lies. One array for each output surface. vtkIdTypeArray *CellIds[2]; // Map from points to the cells that contain them. Used for point // data interpolation. For points on the edge between two cells, it // does not matter which cell is recorded because the interpolation // will be the same. One array for each output surface. vtkIdTypeArray *PointCellIds[2]; // Merging filter used to convert intersection lines from "line // soup" to connected polylines. vtkPointLocator *PointMerger; // Map from cell ID to intersection line. IntersectionMapType *IntersectionMap[2]; // Map from point to an edge on which it resides, the ID of the // cell, and the ID of the line. PointEdgeMapType *PointEdgeMap[2]; protected: Impl(const Impl&); // purposely not implemented void operator=(const Impl&); // purposely not implemented };
第一个公有函数:
int vtkIntersectionPolyDataFilter::Impl ::FindTriangleIntersections(vtkOBBNode *node0, vtkOBBNode *node1, vtkMatrix4x4 *transform, void *arg) { vtkIntersectionPolyDataFilter::Impl *info = reinterpret_cast<vtkIntersectionPolyDataFilter::Impl*>(arg); vtkPolyData *mesh0 = info->Mesh[0]; vtkPolyData *mesh1 = info->Mesh[1]; vtkOBBTree *obbTree1 = info->OBBTree1; vtkCellArray *intersectionLines = info->IntersectionLines;<span style="white-space:pre"> </span>// 相交线的几何信息 vtkIdTypeArray *intersectionCellIds0 = info->CellIds[0];<span style="white-space:pre"> </span>// mesh0中每个相交三角形cell 的 cellID vtkIdTypeArray *intersectionCellIds1 = info->CellIds[1];<span style="white-space:pre"> </span>// mesh1中每个相交三角形cell 的 cellID vtkPointLocator *pointMerger = info->PointMerger;<span style="white-space:pre"> </span>// 相交线的点的信息 int numCells0 = node0->Cells->GetNumberOfIds(); int retval = 0; // 遍历节点0中所有的CellID for (vtkIdType id0 = 0; id0 < numCells0; id0++) { vtkIdType cellId0 = node0->Cells->GetId(id0); int type0 = mesh0->GetCellType(cellId0); if (type0 == VTK_TRIANGLE) { vtkIdType npts0, *triPtIds0; mesh0->GetCellPoints(cellId0, npts0, triPtIds0); double triPts0[3][3]; // 当前Cell 中所有点(也就是3个点)的坐标 for (vtkIdType id = 0; id < npts0; id++) { mesh0->GetPoint(triPtIds0[id], triPts0[id]); } // 判断当前得到的三角形是不是与 Tree1 的 node1 上的三角形相交 // Returns true if triangle (optionally transformed) intersects node. if (obbTree1->TriangleIntersectsNode (node1, triPts0[0], triPts0[1], triPts0[2], transform)) { int numCells1 = node1->Cells->GetNumberOfIds(); for (vtkIdType id1 = 0; id1 < numCells1; id1++) { vtkIdType cellId1 = node1->Cells->GetId(id1); int type1 = mesh1->GetCellType(cellId1); if (type1 == VTK_TRIANGLE) { // See if the two cells actually intersect. If they do, // add an entry into the intersection maps and add an // intersection line. vtkIdType npts1, *triPtIds1; mesh1->GetCellPoints(cellId1, npts1, triPtIds1); double triPts1[3][3]; // tree1 中 node1 所包含的 Cells 中所有点(也就是3个点)的坐标 for (vtkIdType id = 0; id < npts1; id++) { mesh1->GetPoint(triPtIds1[id], triPts1[id]); } // 判断是否两个三角形相交 int coplanar = 0; double outpt0[3], outpt1[3]; int intersects = vtkIntersectionPolyDataFilter::TriangleTriangleIntersection (triPts0[0], triPts0[1], triPts0[2], triPts1[0], triPts1[1], triPts1[2], coplanar, outpt0, outpt1); // 三角形共面 : coplanar = 1 if ( coplanar ) { // Coplanar triangle intersection is not handled. // This intersection will not be included in the output. intersects = 0; continue; } // 两个三角形相交线,并且线段有长度不相同 if ( intersects && ( outpt0[0] != outpt1[0] || outpt0[1] != outpt1[1] || outpt0[2] != outpt1[2] ) ) { // 存储相交相交线段的信息 vtkIdType lineId = intersectionLines->GetNumberOfCells(); intersectionLines->InsertNextCell(2); vtkIdType ptId0, ptId1; pointMerger->InsertUniquePoint(outpt0, ptId0); pointMerger->InsertUniquePoint(outpt1, ptId1); intersectionLines->InsertCellPoint(ptId0); intersectionLines->InsertCellPoint(ptId1); intersectionCellIds0->InsertNextValue(cellId0); // 当前 Tree0.node0 对应的 cellID intersectionCellIds1->InsertNextValue(cellId1); // 当前 Tree1.node1 对应的 cellID // Map from points to the cells that contain them, 每个点都是临近两个cell info->PointCellIds[0]->InsertValue( ptId0, cellId0 ); // Tree0.node0.cell0所对应的点 info->PointCellIds[0]->InsertValue( ptId1, cellId0 ); info->PointCellIds[1]->InsertValue( ptId0, cellId1 ); // Tree1.node1.cell1所对应的点 info->PointCellIds[1]->InsertValue( ptId1, cellId1 ); // IntersectionMap[0]: Tree0.node0.cell0 所对应的相交线的ID info->IntersectionMap[0]->insert(std::make_pair(cellId0, lineId)); info->IntersectionMap[1]->insert(std::make_pair(cellId1, lineId)); // Check which edges of cellId0 and cellId1 outpt0 and // outpt1 are on, if any. for (vtkIdType edgeId = 0; edgeId < 3; edgeId++) { info->AddToPointEdgeMap(0, ptId0, outpt0, mesh0, cellId0, edgeId, lineId, triPtIds0); info->AddToPointEdgeMap(0, ptId1, outpt1, mesh0, cellId0, edgeId, lineId, triPtIds0); info->AddToPointEdgeMap(1, ptId0, outpt0, mesh1, cellId1, edgeId, lineId, triPtIds1); info->AddToPointEdgeMap(1, ptId1, outpt1, mesh1, cellId1, edgeId, lineId, triPtIds1); } retval++; } } } } } } return retval; }
遍历两个树中某两个节点中的每个 cell ,调用函数 TriangleTriangleIntersection 求出两个三角形相交的线,相交线段的两个端点 outpt0, outpt1
我自己觉得比较麻烦的地方就是为了 vtkIntersectionPolyDataFilter::Impl *info 这个变量各种成员属性的赋值,可能是最近变笨了,所以对于有很多属性的类有点迷茫,会忘记、混淆。。。
对于vtkIdTypeArray的操作也不熟
// Insert data at a specified position in the array. void vtkIdTypeArray::InsertValue (vtkIdType id, vtkIdType f ) // Insert data at the end of the array. Return its location in the array. vtkIdType vtkIdTypeArray::InsertNextValue (vtkIdType f)
相关文章推荐
- 第24章 VTK(一)
- 第24章 VTK(二)
- vtkGPUVolumeRayCastMapper (Examples)
- vtk中实现裁剪
- VTK输出AVI录像文件要点
- VTK中文解决方案
- vtk学习笔记 --- 显示label之vtkLabelPlacementMapper
- 实现图像的缩放
- VTK类视频 切片移动直线获取灰度值
- vtk实现保存窗口为图像
- QT与VTK的结合开发(2)
- VTK学习笔记之图像处理
- 利用VTK显示文件读取进度模态对话框
- vtk交互
- vtk计算Polydata的面积和体积
- vtk获取内存中图像数据
- VTK拾取相关的类
- vtk 图像处理 多种 操作
- 在VTK下/OpenGL环境下显示汉字
- 在VTK下/OpenGL环境下显示汉字