基于vtk实现两个物体的碰撞检测以及踩坑注意事项。

vtk中的vtkSelectEnclosedPoints用于判断polydata模型在相对运动过程中是否发生碰撞。

原理:判断polydta1中的点是否在polydata2曲面的内部,如果在内部即发生碰撞,如果所有点都不在内部即两个polydata没有发生碰撞。原理类似于点是否在面内的判断方法,以点得到一条线段,判断其与面的交点,依据该点两侧交点个数的奇偶性判断,如果两侧交点均为偶数则在面外,如果为奇数则在面内,下图作为参考。(具体详见https://blog.csdn.net/lynon/article/details/82015834

tips:以下是几个使用过程中,需要注意的地方,如果不注意真的会坑死(亲身体验)。

(1)用于碰撞检测的两个polydata需要是封闭曲面,否则结果不可预测,下面介绍一下如何判断polydata曲面是否为封闭性。

    vtkSmartPointer<vtkFeatureEdges> featureEdges = vtkSmartPointer<vtkFeatureEdges>::New();                 
	featureEdges->SetInputData(polydata2);
	featureEdges->BoundaryEdgesOn();
	featureEdges->FeatureEdgesOff();
	featureEdges->ManifoldEdgesOff();
	featureEdges->NonManifoldEdgesOff();
	featureEdges->Update();
	int numberOfOpenEdges = featureEdges->GetOutput()->GetNumberOfCells();
	if (numberOfOpenEdges)
	{
		std::cout << "该模型不是封闭的......." << std::endl;
	}
	else
	{
		std::cout << "该模型是封闭的......." << std::endl;
	}

(2)vtkSelectEnclosedPoints需要设置容差,否则结果也是不可预测。

完整代码:

第一步:读取stl文件得到polydata文件,分别为polydata1和polydata2

    QString stlPath1 = "1.stl";
    QFile fi(stlPath1);
    vtkSmartPointer<vtkSTLReader> reader1 = vtkSmartPointer<vtkSTLReader>::New();
    if (fi.exists())
    {
	    reader1->SetFileName(stlPath1.toStdString().c_str());
	    reader1->Update();
    }
    vtkPolyData* polydata1 = reader1->GetOutput();

    QString stlPath2 = "2.stl";
    QFile fi(stlPath2);
    vtkSmartPointer<vtkSTLReader> reader2 = vtkSmartPointer<vtkSTLReader>::New();
    if (fi.exists())
    {
	    reader2->SetFileName(stlPath2.toStdString().c_str());
	    reader2->Update();
    }
    vtkPolyData* polydata2 = reader2->GetOutput();

第二步:碰撞检测

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

	vtkSmartPointer<vtkSelectEnclosedPoints> selectEnclosedPoints = vtkSmartPointer<vtkSelectEnclosedPoints>::New();
	selectEnclosedPoints->SetInputData(points);
	selectEnclosedPoints->SetSurfaceData(polydata2);
	selectEnclosedPoints->SetTolerance(0.00001);
	selectEnclosedPoints->Update();


	bool inside = false;
	
	for (int i = 0; i < cuppoints->GetNumberOfPoints(); ++i)
	{
		if (selectEnclosedPoints->IsInside(i) == 1)
		{
            //发生碰撞
			inside = true;
			break;
		}
	}

 

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页