VTK系列1:在屏幕绘制多边形

VTK中在屏幕绘制多边形

背景介绍

最近项目需要实现一个多边形的功能,通过vtkInteractorStyleDrawPolygon虽然可以进行绘制,但其使用方法是要鼠标左键按下不松,移动时绘制多边形,导致屏幕会闪烁,因此需要自定义绘制方法。

具体需求

1、鼠标左键按下,记录当前点

2、鼠标移动时,绘制上一个点到鼠标当前位置的线

3、当记录的点大于3时,以鼠标当前位置绘制多边形

4、右键结束绘制

实现方法

要实现以上功能,需要自定义VTK交互,继承vtkInteractorStyleTrackballCamera,使用 vtkPoints 存储屏幕像素坐标,通过 vtkActor2D 和 vtkPolyDataMapper2D 显示线条。

接下来看下主要调用方法:通过一个按钮控制是否绘制多边形

cpp 复制代码
void MainWindow::OnClipPointCloudBtn(bool bChecked)
{
	if (bChecked)
	{
		if (m_polygonStyle == nullptr)
		{
			m_polygonStyle = vtkSmartPointer<PolygonRubberBandStyle>::New();
			m_polygonStyle->AddToRenderer(m_Controls->RegistrationWidget_2->renderWindow()->GetRenderers()->GetFirstRenderer());

		}
		this->m_Controls->RegistrationWidget_2->renderWindow()->GetInteractor()->SetInteractorStyle(m_polygonStyle);
	}
	else
	{
		// 恢复为标准 TrackballCamera(或其他默认)
		auto defaultStyle = vtkSmartPointer<vtkInteractorStyleTrackballCamera>::New();
		//恢复交互样式
     this->m_Controls->RegistrationWidget_2->renderWindow()->GetInteractor()->SetInteractorStyle(defaultStyle);
	}

	
}

头文件

cpp 复制代码
class PolygonRubberBandStyle :
	public vtkInteractorStyleTrackballCamera
{
public:
	static PolygonRubberBandStyle* New() { return new PolygonRubberBandStyle; }

	vtkTypeMacro(PolygonRubberBandStyle, vtkInteractorStyleTrackballCamera);
public:
	void AddToRenderer(vtkRenderer* ren);
	PolygonRubberBandStyle();

	// 鼠标按下:确定一个新顶点
	void OnLeftButtonDown() override;
	// 鼠标移动:绘制预览线
	void OnMouseMove() override;
	void OnRightButtonDown() override;

private:
	void Update2DDrawing(int curX, int curY);
	void ExecuteClipping();
private:
	std::vector<std::vector<double>> PixelPoints; // 存储像素坐标
	vtkSmartPointer<vtkPoints> Points2D;
	vtkSmartPointer<vtkPolyData> PolyData2D;
	vtkSmartPointer<vtkActor2D> Actor2D;

};

cpp文件

cpp 复制代码
PolygonRubberBandStyle::PolygonRubberBandStyle()
{
	// 1. 设置 2D 辅助线 (Overlay)
	this->Points2D = vtkSmartPointer<vtkPoints>::New();
	this->Points2D->SetDataTypeToDouble(); // 关键:强制设为 Double 类型
	this->PolyData2D = vtkSmartPointer<vtkPolyData>::New();
	this->PolyData2D->SetPoints(this->Points2D);

	auto mapper2D = vtkSmartPointer<vtkPolyDataMapper2D>::New();
	mapper2D->SetInputData(this->PolyData2D);

	this->Actor2D = vtkSmartPointer<vtkActor2D>::New();
	this->Actor2D->SetMapper(mapper2D);
	this->Actor2D->GetProperty()->SetColor(0.0, 1.0, 0.0); // 绿色 2D 线
	this->Actor2D->GetProperty()->SetLineWidth(2.0);
}

// 鼠标按下:确定一个新顶点
void PolygonRubberBandStyle::OnLeftButtonDown() {
	int* pos = this->GetInteractor()->GetEventPosition();
	this->PixelPoints.push_back({ (double)pos[0], (double)pos[1], 0.0 });
	this->Update2DDrawing(pos[0], pos[1]);
}

// 鼠标移动:绘制预览线
void PolygonRubberBandStyle::OnMouseMove() {
	if (!this->PixelPoints.empty()) {
		int* pos = this->GetInteractor()->GetEventPosition();
		this->Update2DDrawing(pos[0], pos[1]);
	}
	vtkInteractorStyleTrackballCamera::OnMouseMove();
}
void PolygonRubberBandStyle::OnRightButtonDown()
{
	if (this->PixelPoints.size() < 3) return;
	// 清理并刷新
	this->PixelPoints.clear();
	this->Points2D->Reset();
	this->PolyData2D->Modified();
	this->GetInteractor()->GetRenderWindow()->Render();
}


void PolygonRubberBandStyle::Update2DDrawing(int curX, int curY) {
	this->Points2D->Reset();
	for (const auto& pt : this->PixelPoints) {
		this->Points2D->InsertNextPoint(pt[0], pt[1], 0);
	}
	this->Points2D->InsertNextPoint(curX, curY, 0); // 预览当前鼠标

	auto polyLine = vtkSmartPointer<vtkPolyLine>::New();
	int n = this->Points2D->GetNumberOfPoints();
	polyLine->GetPointIds()->SetNumberOfIds(n + 1);
	for (int i = 0; i < n; ++i) polyLine->GetPointIds()->SetId(i, i);
	polyLine->GetPointIds()->SetId(n, 0); // 闭合

	auto cells = vtkSmartPointer<vtkCellArray>::New();
	cells->InsertNextCell(polyLine);
	this->PolyData2D->SetLines(cells);
	this->PolyData2D->Modified();
	this->GetInteractor()->GetRenderWindow()->Render();
}

void PolygonRubberBandStyle::AddToRenderer(vtkRenderer* ren) {
	this->SetDefaultRenderer(ren);
	ren->AddActor2D(this->Actor2D);
}
相关推荐
casual~1 小时前
第?个质数(埃氏筛算法)
数据结构·c++·算法
Elnaij1 小时前
从C++开始的编程生活(20)——AVL树
开发语言·c++
hanbr1 小时前
【C++ STL核心】vector:最常用的动态数组容器(第九天核心)
开发语言·c++
仰泳的熊猫2 小时前
题目2308:蓝桥杯2019年第十届省赛真题-旋转
数据结构·c++·算法·蓝桥杯
lzksword2 小时前
C++ Builder XE OpenDialog1打开多文件并显示xls与xlsx二种格式文件
java·前端·c++
niceffking3 小时前
C++内部类的ISO约定和语法细节
开发语言·c++
艾莉丝努力练剑3 小时前
【脉脉】AI创作者崛起:掌握核心工具,在AMA互动中共同成长
运维·服务器·c++·人工智能·安全·企业·脉脉
码界奇点4 小时前
基于ASP.NET Core的内容管理系统设计与实现
c++·后端·车载系统·毕业设计·asp.net·源代码管理
2401_883035464 小时前
C++20概念(Concepts)入门指南
开发语言·c++·算法
91刘仁德5 小时前
C++ 内存管理
android·c语言·数据结构·c++·经验分享·笔记·算法