判断空间上的点是否在几何图元内,使用vtkSelectEnclosedPoints类;
vtkSelectEnclosedPoints
vtkSelectEnclosedPoints类可以判断标记点是否在封闭表面内。
vtkSelectEnclosedPoints是一个Filter,它计算所有输入点以确定它们是否位于封闭曲面中。过滤器生成一个(0,1)掩码(以vtkDataArray的形式),指示点是在提供的曲面的外部(掩码值=0)还是内部(掩码值=1)(输出vtkDataArray的名称是“SelectedPoints”。)
运行过滤器后,可以通过调用IsInside(ptId)方法来查询点是否在内部/外部。
主要接口
闭合曲面
void SetSurfaceData(vtkPolyData* pd);
void SetSurfaceConnection(vtkAlgorithmOutput* algOutput);
vtkPolyData* GetSurface();
vtkPolyData* GetSurface(vtkInformationVector* sourceInfo);
待判断点
使用vtkDataSetAlgorithm类的SetInputData设置待判定数据集,一般是点数据的vtkPoints
void SetInputData(vtkDataSet*);
查询结果
使用IsInside查询索引为inputPtId的点是否在闭合曲面中,1是在内部;0是在外部;
int IsInside(vtkIdType inputPtId);
int IsInsideSurface(double x[3]);
int IsInsideSurface(double x, double y, double z);
static int IsInsideSurface(double x[3], vtkPolyData* surface, double bds[6], double length,
double tol, vtkAbstractCellLocator* locator, vtkIdList* cellIds, vtkGenericCell* genCell,
vtkIntersectionCounter& counter, vtkRandomPool* poole = nullptr, vtkIdType seqIdx = 0);
示例
判断三个点是否在立方体内
注意:在立方体边上的点,不属于在立方体内部;
#include <vtkVersion.h>
#include <vtkPolyData.h>
#include <vtkPointData.h>
#include <vtkCubeSource.h>
#include <vtkSmartPointer.h>
#include <vtkSelectEnclosedPoints.h>
#include <vtkIntArray.h>
#include <vtkDataArray.h>
#include <vtkVertexGlyphFilter.h>
#include <vtkProperty.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkVertexGlyphFilter.h>
#include "vtk_include.h"
class Test_Clip_Volume {
public:
static void Test() {
vtkNew<vtkCubeSource> cubeSource;
cubeSource->Update();
vtkPolyData* cube = cubeSource->GetOutput();
double testInside[3] = { 0.0, 0.0, 0.0 };
double testOutside[3] = { 0.7, 0.0, 0.0 };
double testBorderOutside[3] = { 0.5, 0.0, 0.0 };
vtkNew<vtkPoints> points;
points->InsertNextPoint(testInside);
points->InsertNextPoint(testOutside);
points->InsertNextPoint(testBorderOutside);
vtkNew<vtkPolyData> pointsPolydata;
pointsPolydata->SetPoints(points);
//Points inside test
vtkNew<vtkSelectEnclosedPoints> selectEnclosedPoints;
selectEnclosedPoints->SetInputData(pointsPolydata);
selectEnclosedPoints->SetSurfaceData(cube);
selectEnclosedPoints->Update();
for (unsigned int i = 0; i < 2; i++){
std::cout << "Point " << i << ": " << selectEnclosedPoints->IsInside(i) << std::endl;
}
vtkDataArray* insideArray = vtkDataArray::SafeDownCast(selectEnclosedPoints->GetOutput()->GetPointData()->GetArray("SelectedPoints"));
for (vtkIdType i = 0; i < insideArray->GetNumberOfTuples(); i++){
std::cout << i << " : " << insideArray->GetComponent(i, 0) << std::endl;
}
//Cube mapper, actor
vtkNew<vtkPolyDataMapper> cubeMapper;
cubeMapper->SetInputConnection(cubeSource->GetOutputPort());
vtkNew<vtkActor> cubeActor;
cubeActor->SetMapper(cubeMapper);
cubeActor->GetProperty()->SetOpacity(0.5);
//First, apply vtkVertexGlyphFilter to make cells around points, vtk only render cells.
vtkNew<vtkVertexGlyphFilter> vertexGlyphFilter;
vertexGlyphFilter->AddInputData(pointsPolydata);
vertexGlyphFilter->Update();
vtkNew<vtkPolyDataMapper> pointsMapper;
pointsMapper->SetInputConnection(vertexGlyphFilter->GetOutputPort());
vtkNew<vtkActor> pointsActor;
pointsActor->SetMapper(pointsMapper);
pointsActor->GetProperty()->SetPointSize(5);//定义点的尺寸大小,这样点才能在画布上显示出来
pointsActor->GetProperty()->SetColor(0.0, 0.0, 1);
//Create a renderer, render window, and interactor
vtkNew<vtkRenderer> renderer;
vtkNew<vtkRenderWindow> renderWindow;
renderWindow->AddRenderer(renderer);
vtkNew<vtkRenderWindowInteractor> renderWindowInteractor;
renderWindowInteractor->SetRenderWindow(renderWindow);
// Add the actor to the scene
renderer->AddActor(cubeActor);
renderer->AddActor(pointsActor);
renderer->SetBackground(.0, 1, .0);
renderWindow->Render();
renderWindowInteractor->Start();
}
};
平面外的点在平面上的投影是否落入圈选的范围
设定四个在XY平面上的点,组成了边长为1的正方形,判断点(1,1,10)在XY平面上的投影是否落入正方形内;
使用vtkPlane的ProjectPoint方法计算点(1,1,10)在XY平面上的投影点(1,1,0);
使用vtkSelectEnclosedPoints类判断投影点(1,1,0)是否在正方形内;
static float x[4][3] = { {0,0,0},{1,0,0},{1,1,0},{0,1,0} };
static vtkIdType pts[4] = {0,1,2,3};
vtkNew<vtkPolyData> cube;
vtkNew<vtkPoints> points;
vtkNew<vtkCellArray> polys;
vtkNew<vtkFloatArray> scalars;
for (int i = 0; i < 4; i++) {
points->InsertPoint(i, x[i]);
scalars->InsertTuple1(i, i);
}
polys->InsertNextCell(4, pts);
cube->SetPoints(points);
cube->SetPolys(polys);
cube->GetPointData()->SetScalars(scalars);
double testInside[3] = { 1, 1, 10.0 };
double project_point[3] = { 0 };
vtkNew<vtkPlane> plane;
plane->SetOrigin(0.0, 0.0, 0.0);
plane->SetNormal(0.0, 0.0, 1.0);
plane->ProjectPoint(testInside, project_point);
vtkNew<vtkPoints> points1;
points1->InsertNextPoint(project_point);
vtkNew<vtkPolyData> pointsPolydata;
pointsPolydata->SetPoints(points1);
vtkNew<vtkSelectEnclosedPoints> selectEnclosedPoints;
selectEnclosedPoints->SetInputData(pointsPolydata);
selectEnclosedPoints->SetSurfaceData(cube);
selectEnclosedPoints->Update();
for (unsigned int i = 0; i < 1; i++)
{
std::cout << "Point " << i << ": " << selectEnclosedPoints->IsInside(i) << std::endl;
}
vtkNew<vtkVertexGlyphFilter> vertexGlyphFilter;
vertexGlyphFilter->AddInputData(pointsPolydata);
vertexGlyphFilter->Update();
vtkNew<vtkPolyDataMapper> pointsMapper;
pointsMapper->SetInputConnection(vertexGlyphFilter->GetOutputPort());
vtkNew<vtkActor> pointsActor;
pointsActor->SetMapper(pointsMapper);
pointsActor->GetProperty()->SetPointSize(5);//定义点的尺寸大小,这样点才能在画布上显示出来
pointsActor->GetProperty()->SetColor(0.0, 0.0, 1);
vtkNew<vtkPolyDataMapper> cubeMapper;
cubeMapper->SetInputData(cube);
cubeMapper->SetScalarRange(0, 7);
vtkNew<vtkActor> cubeActor;
cubeActor->SetMapper(cubeMapper);
vtkNew<vtkCamera> camera;
camera->SetPosition(1, 1, 1);
camera->SetFocalPoint(0, 0, 0);
vtkNew<vtkRenderer> renderer;
renderer->AddActor(pointsActor);
renderer->AddActor(cubeActor);
renderer->SetActiveCamera(camera);
renderer->ResetCamera();
renderer->SetBackground(1, 1, 1);
vtkNew<vtkRenderWindow> renWin;
renWin->AddRenderer(renderer);
renWin->SetSize(300, 300);
vtkNew<vtkRenderWindowInteractor> iren;
iren->SetRenderWindow(renWin);
renWin->Render();
iren->Initialize();
iren->Start();
查询结果显示,0序号的点在四边形中;
注意:在实际开发中,判断点在平面上的投影是否在圈选的范围和判断点是否在几何图元中,这两方面运用很常见,了解怎么计算和使用VTK那些类来计算,也可以试着自己使用线性代数的知识计算这两个方面的代码;有机会在补充自己写的代码;
使用vtkPolygon类的方法PointInPolygon
#include <vtkNew.h>
#include <vtkPoints.h>
#include <vtkPolygon.h>
int main(int, char*[])
{
// Create the polygon
vtkNew<vtkPolygon> polygon;
polygon->GetPoints()->InsertNextPoint(0.0, 0.0, 0.0);
polygon->GetPoints()->InsertNextPoint(1.0, 0.0, 0.0);
polygon->GetPoints()->InsertNextPoint(1.0, 1.0, 0.0);
polygon->GetPoints()->InsertNextPoint(0.0, 1.0, 0.0);
double testIn[3] = {0.5, 0.5, 0.0};
double testOut[3] = {2.0, 0.5, 0.0};
double n[3];
polygon->ComputeNormal(
polygon->GetPoints()->GetNumberOfPoints(),
static_cast<double*>(polygon->GetPoints()->GetData()->GetVoidPointer(0)),
n);
double bounds[6];
polygon->GetPoints()->GetBounds(bounds);
std::cout << "testIn in polygon? "
<< polygon->PointInPolygon(
testIn, polygon->GetPoints()->GetNumberOfPoints(),
static_cast<double*>(
polygon->GetPoints()->GetData()->GetVoidPointer(0)),
bounds, n)
<< std::endl;
std::cout << "testOut in polygon? "
<< polygon->PointInPolygon(
testOut, polygon->GetPoints()->GetNumberOfPoints(),
static_cast<double*>(
polygon->GetPoints()->GetData()->GetVoidPointer(0)),
bounds, n)
<< std::endl;
return EXIT_SUCCESS;
}