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);
}
相关推荐
HAPPY酷2 小时前
构造与析构:C++ 中对象的温柔生灭
java·jvm·c++
又见野草2 小时前
C++类和对象(下)
开发语言·c++
春夜喜雨2 小时前
关于内存分配的优化与设计
c++·tcmalloc·malloc·jemallc
范纹杉想快点毕业3 小时前
状态机设计与嵌入式系统开发完整指南从面向过程到面向对象,从理论到实践的全面解析
linux·服务器·数据库·c++·算法·mongodb·mfc
坚定学代码3 小时前
认识 ‘using namespace‘
c++
jiang_changsheng3 小时前
环境管理工具全景图与深度对比
java·c语言·开发语言·c++·python·r语言
LYOBOYI1233 小时前
qml的对象树机制
c++·qt
LeoZY_3 小时前
开源项目精选:Dear ImGui —— 轻量高效的 C++ 即时模式 GUI 框架
开发语言·c++·ui·开源·开源软件
PHOSKEY4 小时前
3D工业相机如何“读透”每一个字符?快速识别、高精度3D测量
数码相机·3d