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);
}
相关推荐
qq_199886872 小时前
第6板块·第4节:构建系统与多文件项目
c++·人工智能·gpu算力
汉克老师4 小时前
GESP2026年9月认证C++三级( 第三部分编程题(2、分割字符串))精讲
c++·gesp·小学生·学c++编程
估值探索者4 小时前
【Python量化系统工程化 #08】关了 SSH 就停?systemd 让脚本开机自启 + 异常自动拉起
java·c++·人工智能·分类·数据挖掘
天若有情6734 小时前
C++花式魔改!手写头文件复刻Java语法,彻底打破编码思维定式
java·c++·语言做语言·jac++
qq_199886875 小时前
第7板块·第3节:CUTLASS 的 GEMM 实现与优化策略
c++·人工智能·gpu算力·cuda
hetao17338375 小时前
2026-09-17 hetao1733837 的刷题记录
c++·算法
shada6 小时前
Boost.Process v2 在旧内核上报 `assign: Bad file descriptor`
c++
别动我齐刘海6 小时前
ROS2 Jazzy + C++ 实战路线——基础学习2
c++·人工智能·vscode·python·学习·机器学习·机器人
朝朝辞暮i7 小时前
C++第 2 课
c++
代码中介商7 小时前
C++ 预约系统实战(三):服务端实现——libevent 事件驱动与业务路由
c++·json·c/s