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);
}
相关推荐
初夏睡觉10 小时前
c++1.3(变量与常量,简单数学运算详解),草稿公放
开发语言·c++
阿拉斯攀登10 小时前
从入门到实战:CMake 与 Android JNI/NDK 开发全解析
android·linux·c++·yolo·cmake
筱璦13 小时前
期货软件开发 - C# 调用 HQChart 指标计算 C++ 动态库
c++·microsoft·c#
不想写代码的星星14 小时前
C++ 内存管理:分区、自定义分配器、常见问题与检测工具
c++
-许平安-14 小时前
MCP项目笔记九(插件 bacio-quote)
c++·笔记·ai·plugin·mcp
沉鱼.4414 小时前
第十三届题目
c语言·c++·算法
liulilittle15 小时前
C++ 无锁编程:单停多发送场景高性能方案
服务器·开发语言·c++·高性能·无锁·原子
无限进步_15 小时前
【C++】巧用静态变量与构造函数:一种非常规的求和实现
开发语言·c++·git·算法·leetcode·github·visual studio
小超超爱学习993715 小时前
大数乘法,超级简单模板
开发语言·c++·算法
xyx-3v17 小时前
qt创建新工程
开发语言·c++·qt