VTK用鼠标画线+VTK坐标转换问题+实例

本人在用VTK实现在渲染窗口上用鼠标画线的探究过程。

要在窗口上用鼠标画线首先要做的就是重写鼠标交互事件,于是就在官方网站找到重写鼠标响应事件的demo,然后再更改官方的demo,实现自己需要的功能。我的想法是:

1.获取鼠标左键按下时的坐标。

2.获取鼠标左键上弹时的坐标。

3.用这两个点连接一条线。

遇到的问题时,智能获取到相对于窗口的坐标点,而不是世界相对世界坐标的坐标点。导致的结果就是画线的位置并不是鼠标左键按下和上弹的连线。


在VS下实现的代码如下(没有用cmake管理,直接在vs下做的):

包含一些我在实现的过程中调试的过程,已经注释:

#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkSphereSource.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkSmartPointer.h>
#include <vtkPointPicker.h>
#include <vtkCamera.h>
#include <vtkInteractorStyleTrackballCamera.h>
#include <vtkNamedColors.h>
#include <vtkObjectFactory.h>
#include<vtkLine.h>
#include<vtkProperty.h>
#include<vtkPolyLine.h>
#include<vtkUnstructuredGrid.h>
#include<vtkDataSetMapper.h>
#include<vtkLineSource.h>
#include<vtkRendererCollection.h>
#include<vtkCellPicker.h>
#include "vtkAutoInit.h" 
VTK_MODULE_INIT(vtkRenderingOpenGL2); // VTK was built with vtkRenderingOpenGL2
VTK_MODULE_INIT(vtkInteractionStyle);
// Define interaction style
vtkSmartPointer<vtkRenderer> renderer;
double point1[3]{ 0 };
double point2[3]{ 0 };
double WorldPoint[3]{ 0 };
double WorldPoint1[3]{ 0 };
int *clickPos;
int *clickPos1;
class customMouseInteractorStyle : public vtkInteractorStyleTrackballCamera
{
public:
	static customMouseInteractorStyle* New();
	vtkTypeMacro(customMouseInteractorStyle, vtkInteractorStyleTrackballCamera);
	virtual void OnLeftButtonDown()
	{
		std::cout << "Pressed left mouse button." << std::endl;
		// Forward events
	//	vtkInteractorStyleTrackballCamera::OnLeftButtonDown();
//		int* clickPos = this->GetInteractor()->GetEventPosition();
	    clickPos = this->GetInteractor()->GetEventPosition();
		
		point1[0] = clickPos[0];
		point1[1] = clickPos[1];
		
		renderer->SetDisplayPoint(point1[0], point1[1], 0);
		renderer->DisplayToWorld();
		WorldPoint[0] = (renderer->GetWorldPoint())[0];
		WorldPoint[1] = (renderer->GetWorldPoint())[1];
		WorldPoint[2] = (renderer->GetWorldPoint())[2];

//		double* worldPosition = picker->GetPickPosition();
	//	std::cout << worldPosition[0] << "\t" << worldPosition[1] << std::endl;
	//	std::cout << WorldPoint[0]<< std::endl << WorldPoint[1]<<  std::endl;
	}
	virtual void OnLeftButtonUp()
	{
		std::cout << "Pressed left mouse up." << std::endl;
		vtkIdType  pts[2]{ 0,1 };
		// Forward events
		//	vtkInteractorStyleTrackballCamera::OnLeftButtonDown();
		//		int* clickPos = this->GetInteractor()->GetEventPosition();
		clickPos1 = this->GetInteractor()->GetEventPosition();
		point2[0] = clickPos1[0];
		point2[1] = clickPos1[1];
//		std::cout << clickPos[0] << std::endl << clickPos[1] << std::endl  << std::endl ;
		std::cout << point1[0] << std::endl << point1[1] << std::endl;
		std::cout << clickPos1[0] << std::endl << clickPos1[1] << std::endl ;

		renderer->SetDisplayPoint(point2[0], point2[1], 0);
		renderer->DisplayToWorld();
		WorldPoint1[0] = (renderer->GetWorldPoint())[0];
		WorldPoint1[1] = (renderer->GetWorldPoint())[1];
		WorldPoint1[2] = (renderer->GetWorldPoint())[2];
		one way
		//renderer->SetDisplayPoint(point1);
		//renderer->SetDisplayPoint(point2);
		//renderer->DisplayToWorld();
		//vtkSmartPointer<vtkPoints>points = vtkSmartPointer<vtkPoints>::New();
		//points->InsertNextPoint(point1[0], point1[1], 0);
		//points->InsertNextPoint(clickPos1[0], clickPos1[1], 0);
		//vtkSmartPointer<vtkPolyLine>polyline = vtkSmartPointer<vtkPolyLine>::New();
		//polyline->GetPointIds()->SetNumberOfIds(2);
		//polyline->GetPointIds()->SetId(0, 0);
		//polyline->GetPointIds()->SetId(1, 1);
		//vtkSmartPointer<vtkUnstructuredGrid>grid= vtkSmartPointer<vtkUnstructuredGrid>::New();
		//grid->Allocate(1, 1);
		//grid->InsertNextCell(polyline->GetCellType(), polyline->GetPointIds());
		//grid->SetPoints(points);
		//vtkSmartPointer<vtkDataSetMapper>mapper= vtkSmartPointer<vtkDataSetMapper>::New();
		//mapper->SetInputData(grid);
		//vtkSmartPointer<vtkActor> actor1 = vtkSmartPointer<vtkActor>::New();
		//actor1->SetMapper(mapper);
		//actor1->GetProperty()->SetColor(1.0, 0.0, 0.0); //设置颜色
		//
		//renderer->AddActor(actor1);
		//
		//renderer->GetRenderWindow()->GetInteractor()->Initialize();
		//renderer->GetRenderWindow()->GetInteractor()->Render();
	//	renderer->GetRenderWindow()->Start();
		the second way
	//	double* p = renderer->GetActors()->GetLastActor()->GetOrigin();
		
		vtkSmartPointer<vtkLineSource> lineSource = vtkSmartPointer<vtkLineSource>::New();
		lineSource->SetPoint1(WorldPoint);
		lineSource->SetPoint2(WorldPoint1);
		vtkSmartPointer<vtkPolyDataMapper> mapper =
			vtkSmartPointer<vtkPolyDataMapper>::New();
		mapper->SetInputConnection(lineSource->GetOutputPort());
		vtkSmartPointer<vtkActor> actor1 = vtkSmartPointer<vtkActor>::New();
		actor1->SetMapper(mapper);
		actor1->GetProperty()->SetColor(1.0, 0.0, 0.0);
		
	//	actor1->SetOrigin(0, 0,0);
		this->Interactor->GetRenderWindow()->GetRenderers()->GetFirstRenderer()->AddActor(actor1);
		renderer->GetRenderWindow()->GetInteractor()->Initialize();
		renderer->GetRenderWindow()->GetInteractor()->Render();
	//	vtkSmartPointer<vtkCellArray>lines = vtkSmartPointer<vtkCellArray>::New();
		lines->InsertNextCell(2);
	//	lines->InsertNextCell(2, pts);
	//	vtkSmartPointer<vtkPolyData>polydata = vtkSmartPointer<vtkPolyData>::New();
	//	polydata->SetPoints(points);
	//	polydata->SetPolys(lines);
	//	vtkSmartPointer<vtkPolyDataMapper>linemapper = vtkSmartPointer<vtkPolyDataMapper>::New();
	//	linemapper->SetInputData(polydata); //测试划线
	//	vtkSmartPointer<vtkProperty>linepro = vtkSmartPointer<vtkProperty>::New();
	//	
	//	linepro->SetColor(0, 0, 0);
	//	linepro->SetOpacity(1); //透明度
	//	vtkSmartPointer<vtkActor>lineact = vtkSmartPointer<vtkActor>::New();
	//	lineact->SetMapper(linemapper);
	//	lineact->SetProperty(linepro);
	//	
	//	renderer->AddActor(lineact);
	//	renderer->GetRenderWindow()->Start();

		/*vtkSmartPointer<vtkRenderer>render = vtkSmartPointer<vtkRenderer>::New();
		render->AddActor(lineact);
		vtkSmartPointer<vtkRenderWindow>renwin = vtkSmartPointer<vtkRenderWindow>::New();
		renwin->AddRenderer(render);
		vtkSmartPointer<vtkRenderWindowInteractor>iren = vtkSmartPointer<vtkRenderWindowInteractor>::New();
		iren->SetRenderWindow(renwin);
		iren->Initialize();
		iren->Start();*/

//		renderer->Render();
		
	}

	virtual void OnMiddleButtonDown()
	{
		std::cout << "Pressed middle mouse button." << std::endl;
		// Forward events
		vtkInteractorStyleTrackballCamera::OnMiddleButtonDown();
	}

	virtual void OnRightButtonDown()
	{
		std::cout << "Pressed right mouse button." << std::endl;
		// Forward events
		vtkInteractorStyleTrackballCamera::OnRightButtonDown();
	}

};

vtkStandardNewMacro(customMouseInteractorStyle);

int main(int, char *[])
{

	vtkSmartPointer<vtkSphereSource> sphereSource =
		vtkSmartPointer<vtkSphereSource>::New();
	sphereSource->SetCenter(0.0, 0.0, 0.0);
	sphereSource->SetRadius(5.0);
	sphereSource->Update();

	vtkSmartPointer<vtkPolyDataMapper> mapper =
		vtkSmartPointer<vtkPolyDataMapper>::New();
	mapper->SetInputConnection(sphereSource->GetOutputPort());

	vtkSmartPointer<vtkActor> actor =
		vtkSmartPointer<vtkActor>::New();
	actor->SetMapper(mapper);

	vtkSmartPointer<vtkNamedColors> colors =
		vtkSmartPointer<vtkNamedColors>::New();

	renderer =
		vtkSmartPointer<vtkRenderer>::New();
	renderer->SetBackground(colors->GetColor3d("Slate_grey").GetData());
	renderer->AddActor(actor);

	vtkSmartPointer<vtkRenderWindow> renderWindow =
		vtkSmartPointer<vtkRenderWindow>::New();
	renderWindow->AddRenderer(renderer);

	vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
		vtkSmartPointer<vtkRenderWindowInteractor>::New();
	renderWindowInteractor->SetRenderWindow(renderWindow);

	vtkSmartPointer<customMouseInteractorStyle> style =
		vtkSmartPointer<customMouseInteractorStyle>::New();
	renderWindowInteractor->SetInteractorStyle(style);

	renderWindowInteractor->Initialize();
	renderWindowInteractor->Start();

	return EXIT_SUCCESS;
}

结果如下:


关于坐标系的理论就不说了,大家都有买书,书上都有示意图,只是书上可能没有这样的实例。

参考:

VTK官网上鼠标事件自定义:https://lorensen.github.io/VTKExamples/site/Cxx/Interaction/MouseEvents/

坐标转换问题参考了:http://tieba.baidu.com/p/4873446950

这个bug搞了两天,希望可以帮到遇到同样问题的人,节约时间,少走一点弯路。

  • 3
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
在Qt中使用VTK库,可以实现VTK的可视化功能,并且可以通过Qt的事件机制来处理鼠标点击事件。下面是一个简单的示例代码,演示了如何在VTK中处理鼠标左键点击事件: 首先,需要在Qt中创建一个VTK窗口,并将其作为一个QWidget的子类来使用。然后,通过重写QWidget的鼠标事件函数来处理鼠标点击事件。 ```cpp #include <QVTKWidget.h> #include <vtkRenderWindow.h> #include <vtkRenderer.h> #include <vtkRenderWindowInteractor.h> #include <vtkSmartPointer.h> #include <vtkCommand.h> class MyVTKWidget : public QVTKWidget { public: MyVTKWidget(QWidget* parent = nullptr) : QVTKWidget(parent) { // 创建VTK渲染器和交互器 renderer = vtkSmartPointer<vtkRenderer>::New(); interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New(); interactor->SetRenderWindow(GetRenderWindow()); GetRenderWindow()->AddRenderer(renderer); // 设置交互器样式为默认样式 interactor->SetInteractorStyle(vtkSmartPointer<vtkInteractorStyleTrackballCamera>::New()); // 添加鼠标左键点击事件监听器 vtkSmartPointer<MouseClickListener> clickListener = vtkSmartPointer<MouseClickListener>::New(); clickListener->SetVTKWidget(this); interactor->AddObserver(vtkCommand::LeftButtonPressEvent, clickListener); } private: vtkSmartPointer<vtkRenderer> renderer; vtkSmartPointer<vtkRenderWindowInteractor> interactor; class MouseClickListener : public vtkCommand { public: static MouseClickListener* New() { return new MouseClickListener; } void SetVTKWidget(MyVTKWidget* widget) { vtkWidget = widget; } virtual void Execute(vtkObject* caller, unsigned long eventId, void* callData) { if (eventId == vtkCommand::LeftButtonPressEvent) { // 处理鼠标左键点击事件 vtkRenderWindowInteractor* interactor = static_cast<vtkRenderWindowInteractor*>(caller); int* pos = interactor->GetEventPosition(); // 在这里可以根据鼠标点击的位置进行相应的操作 // 输出鼠标点击的位置 std::cout << "Mouse left button clicked at position: " << pos[0] << ", " << pos[1] << std::endl; } } private: MyVTKWidget* vtkWidget; }; }; int main(int argc, char** argv) { QApplication app(argc, argv); // 创建一个Qt窗口 QWidget window; window.resize(800, 600); // 创建一个VTK窗口,并将其添加到Qt窗口中 MyVTKWidget vtkWidget(&window); vtkWidget.resize(800, 600); window.show(); return app.exec(); } ``` 在上述代码中,我们创建了一个名为`MyVTKWidget`的类,继承自`QVTKWidget`,并重写了鼠标事件函数`Execute`。在`MyVTKWidget`的构造函数中,我们创建了VTK渲染器和交互器,并将其与VTK窗口关联起来。然后,我们创建了一个名为`MouseClickListener`的内部类,继承自`vtkCommand`,用于处理鼠标左键点击事件。在`MouseClickListener`的`Execute`函数中,我们可以根据鼠标点击的位置进行相应的操作。 请注意,上述代码只是一个简单示例,实际使用时可能需要根据具体需求进行修改和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值