[VTK] VTK deletes the specified triangle surface of the 3D model

VTK deletes the specified triangle surface of the 3D model


The content of this article is carried over from the previous one: VTK frame selection surface picking patch - only select the front surface

Realize deleting the triangle patch selected by the mouse box


Effect preview

insert image description here

insert image description here


Function Description

Use the R keyboard to switch between the interactive mode and the frame selection mode, and delete the triangle faces selected by the frame in the model.


method introduction

  • Use the vtkInteractorStyleRubberBandPick interactive method to realize frame selection. (Switch between interactive mode and frame selection mode by R key)

  • Use vtkAreaPicker to collect frame selection information. VTK also provides vtkCellPicker, but CellPicker can only select an object, not a collection.

  • Use the IntersectWithLine function in vtkCellLocator, use the ray casting method to find the cell near the camera side, and then use vtkPolyDataConnectivityFilter to find the surface connected to the nearest cell, that is, the front surface.

  • In the early stage, vtkIdFilter is used to process the original model, and the id number of the triangle cell is stored in the cell's attribute in advance (that is, vtkCellData). After processing the model through other Filters, the original Cell id number can be obtained by reading the cell's attribute. Then use the id number to return to the original model to access itself.

  • To find out the mesh to be deleted, you need to call the BuildLinks function of vtkPolyData to establish the topological link between the cell and the point, and then use the DeleteCell function to delete the corresponding mesh, otherwise an error will be reported, and finally use the RemoveDeletedCells function to submit the delete operation to remove these deleted cells (The DeleteCell function only marks the mesh for deletion, but does not actually remove it), and finally calls the Modified function to submit the modification operation of the model.

  • Detailed comments have been written in the source code.


source code

The complete code can be compiled and run directly

#include <vtkPolyData.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyleRubberBandPick.h>
#include <vtkAreaPicker.h>
#include <vtkCommand.h>
#include <vtkCallbackCommand.h>
#include <vtkIdFilter.h>
#include <vtkExtractPolyDataGeometry.h>
#include <vtkSphereSource.h>
#include <vtkPlanes.h>
#include <vtkDataSetMapper.h>
#include <vtkProperty.h>
#include <vtkCellLocator.h>
#include <vtkCamera.h>
#include <vtkPolyDataConnectivityFilter.h>
#include <vtkIdTypeArray.h>
#include <vtkCellData.h>

/*
* 定义命令:
* 使用vtkInteractorStyleRubberBandPick交互方式时,会自动触发vtkAreaPicker
* 交互时框选的信息会存储在vtkAreaPicker中
* 将vtkAreaPicker的结束拾取事件绑定vtkPickerCallback
* 类似QT中信号与槽的机制
* vtkAreaPicker触发结束拾取信号,然后执行vtkPickerCallback中的Execute函数
*/
class vtkPickerCallback : public vtkCommand
{
    
    
public:
	//@brief 定义New函数(固定格式)
	static vtkPickerCallback* New() {
    
    return new vtkPickerCallback;}
	//@brief 定义Execute函数(vtkCommand中的Execute为纯虚函数,必须要实现)
	virtual void Execute(vtkObject* caller, unsigned long, void*);
	void SetPolyData(vtkPolyData* input);
	void SetRenderer(vtkRenderer* input);
	
private:
	vtkPolyData* polyData;				//需要处理的几何数据
	vtkRenderer* renderer;				//需要调用的渲染器

	vtkDataSetMapper* mapper;			//用于显示框选面片的mapper
	vtkActor* actor;					//用于显示框选面片的actor
};

int main()
{
    
    
	//****************创建球体*****************
	vtkSphereSource* sphere = vtkSphereSource::New();
	sphere->SetThetaResolution(18);
	sphere->SetPhiResolution(18);
	sphere->SetRadius(10);
	sphere->SetCenter(0, 0, 0);
	sphere->Update();

	//****************创建Mapper***************
	vtkPolyDataMapper* mapper = vtkPolyDataMapper::New();
	mapper->SetInputConnection(sphere->GetOutputPort());
	//换成此语句效果一致:mapper->SetInputData(sphere->GetOutput());
	
	//****************创建Actor****************
	vtkActor* actor = vtkActor::New();
	actor->SetMapper(mapper);

	//****************创建渲染器***************
	vtkRenderer* renderer = vtkRenderer::New();
	renderer->AddActor(actor);

	//****************创建渲染窗口*************
	vtkRenderWindow* renderWindow = vtkRenderWindow::New();
	renderWindow->AddRenderer(renderer);
	
	//****************创建交互器***************
	vtkRenderWindowInteractor* renderWindowInteractor = vtkRenderWindowInteractor::New();

	//****************创建交互方式*************
	vtkInteractorStyleRubberBandPick* interactorStyle = vtkInteractorStyleRubberBandPick::New();

	//****************创建拾取回调函数*********
	vtkPickerCallback* callback = vtkPickerCallback::New();
	callback->SetPolyData(sphere->GetOutput());
	callback->SetRenderer(renderer);

	//****************创建区域拾取器***********
	vtkAreaPicker* areaPicker = vtkAreaPicker::New();
	areaPicker->AddObserver(vtkCommand::EndPickEvent, callback);		//为“结束拾取”事件绑定“拾取回调函数”
	
	renderWindowInteractor->SetRenderWindow(renderWindow);				//为交互器设置渲染窗口
	renderWindowInteractor->SetInteractorStyle(interactorStyle);		//为交互器设置交互方式
	renderWindowInteractor->SetPicker(areaPicker);						//为交互器设置拾取器

	renderWindowInteractor->Start();

	return 0;
}

void vtkPickerCallback::Execute(vtkObject* caller, unsigned long, void*)
{
    
    
	//通过反射获取调用者
	vtkAreaPicker* areaPicker = static_cast<vtkAreaPicker*>(caller);
	//获取框选的视锥体(由六个面组成)
	vtkPlanes* frustum = areaPicker->GetFrustum();
	//提前标记几何数据的CellId
	vtkIdFilter* idFilter = vtkIdFilter::New();
	idFilter->SetInputData(polyData);
	idFilter->SetCellIdsArrayName("OriginalCellId");
	idFilter->Update();
	//提取视锥体内的模型
	vtkExtractPolyDataGeometry* extract = vtkExtractPolyDataGeometry::New();
	extract->SetInputConnection(idFilter->GetOutputPort());
	extract->SetImplicitFunction(frustum);
	extract->Update();
	if (!extract->GetOutput()->GetPolys())
	{
    
    
		return;
	}
	//创建面片定位器
	vtkCellLocator* locator = vtkCellLocator::New();
	locator->SetDataSet(extract->GetOutput());
	locator->BuildLocator();
	//----------利用光线投射的方法寻找更靠近摄像机的面片------------
	double rayStart[3];				//光线起点坐标:设置为摄像机位置
	double rayDirection[3];			//光线方向向量:设置为框选数据包围盒的中心
	renderer->GetActiveCamera()->GetPosition(rayStart);
	extract->GetOutput()->GetCenter(rayDirection);
	double xyz[3];
	double t;
	double pcoords[3];
	int subId;
	vtkIdType cellId = -1;			//记录光线击中的面片Id号
	locator->IntersectWithLine(rayStart, rayDirection, 0.0001, t, xyz, pcoords, subId, cellId);
	//-----------利用找到的面片获取相连的面
	vtkPolyDataConnectivityFilter* connectivity = vtkPolyDataConnectivityFilter::New();
	connectivity->SetInputConnection(extract->GetOutputPort());
	connectivity->SetExtractionModeToCellSeededRegions();
	connectivity->InitializeSeedList();
	connectivity->AddSeed(cellId);
	connectivity->Update();

	//--------删除框选面片----------
	//提取框选面片的原始面片ID
	vtkIdTypeArray* ids = dynamic_cast<vtkIdTypeArray*>(connectivity->GetOutput()->GetCellData()->GetArray("OriginalCellId"));
	//要删除面片前必须先执行建立拓扑链接
	polyData->BuildLinks();
	if (!ids)
	{
    
    
		return;
	}
	for (int i = 0; i < ids->GetNumberOfValues(); i++)
	{
    
    
		vtkIdType id = ids->GetValue(i);
		polyData->DeleteCell(id);
	}
	//提交删除面片操作
	polyData->RemoveDeletedCells();
	polyData->Modified();
	//刷新渲染器
	renderer->Render();
}

void vtkPickerCallback::SetPolyData(vtkPolyData* input)
{
    
    
	polyData = input;
}

void vtkPickerCallback::SetRenderer(vtkRenderer* input)
{
    
    
	renderer = input;
	//初始化用于显示框选面片的mapper和actor
	mapper = vtkDataSetMapper::New();
	actor = vtkActor::New();
	actor->SetMapper(mapper);
}

Guess you like

Origin blog.csdn.net/qq_37366618/article/details/127315624