目的
想通过鼠标左键实现点云旋转变换
遇到问题
操作点云时进不去vtk鼠标控件的回调函数
解决方式
无意间看到这位老哥的博文PCL1.12.1+VTK9.1+Qt5.14.2VS创建Qt项目在widget上显示点云,其中提到QOpenGLWidget界面实时刷新问题
即viewer调用回调函数后增加一行代码,实现界面的重新渲染
Viewer->getRenderWindow()->Render();
自己实现代码参考
QtWidgetsApplication_PCL.h
class QtWidgetsApplication_PCL : public QMainWindow
{
Q_OBJECT
public:
QtWidgetsApplication_PCL(QWidget *parent = nullptr);
~QtWidgetsApplication_PCL();
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud;
int flag , xb, yb;
static void pp_callback(const pcl::visualization::MouseEvent& event, void* args);//回调函数设置成静态函数方便访问 类成员
private slots:
void showCloud();
private:
Ui::QtWidgetsApplication_PCLClass ui;
pcl::visualization::PCLVisualizer::Ptr view;
};
对于回调函数放入类中的实现方式参考这篇博客其中将回调函数第二个参数从以前的结构体换成类对象感觉受益匪浅。
QtWidgetsApplication_PCL.cpp
QtWidgetsApplication_PCL::QtWidgetsApplication_PCL(QWidget *parent)
: QMainWindow(parent)
{
//在构造函数中为指针构造对象
cloud.reset(new pcl::PointCloud<pcl::PointXYZ>);
flag = 0, xb = 0, yb = 0;
ui.setupUi(this);
//这部分是结合QT的QVTKOpenGLNativeWidget控件和vtk显示点云的部分
vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
vtkSmartPointer<vtkGenericOpenGLRenderWindow> renderWindow = vtkSmartPointer<vtkGenericOpenGLRenderWindow>::New();
renderWindow->AddRenderer(renderer);
view.reset(new pcl::visualization::PCLVisualizer(renderer, renderWindow, "viewer", false));
ui.openGLWidget->setRenderWindow(view->getRenderWindow());
view->setupInteractor(ui.openGLWidget->interactor(), ui.openGLWidget->renderWindow());
//connect按钮和槽函数
connect(ui.pushButton, &QPushButton::clicked, this, &QtWidgetsApplication_PCL::showCloud);
}
QtWidgetsApplication_PCL::~QtWidgetsApplication_PCL()
{}
//回调函数实现
void QtWidgetsApplication_PCL::pp_callback(const pcl::visualization::MouseEvent& event, void* args)
{
//将类的指针传给data从而访问类的成员
QtWidgetsApplication_PCL* data = (QtWidgetsApplication_PCL*)args;
if (event.getButton() == pcl::visualization::MouseEvent::LeftButton && data->flag == 0) {
data->xb = event.getX();
data->yb = event.getY();
qDebug() << "left button location: " << event.getX() << " " << event.getY() ;
data->flag = 1;
}
//鼠标控制点云旋转实现的比较粗糙,看看就好,直接照搬vtk中鼠标事件使用
if (event.getButton() == pcl::visualization::MouseEvent::RightButton) {
qDebug() << "right button location: " << event.getX() << " " << event.getY() ;
int k = 1;
if (sqrt(pow(event.getX(), 2) + pow(event.getY(), 2)) <= 100)k = -1;
float theta = (M_PI / 180) * k;
Eigen::Affine3f transform = Eigen::Affine3f::Identity();
transform.rotate(Eigen::AngleAxisf(theta, Eigen::Vector3f::UnitZ()));
pcl::transformPointCloud(*data->cloud, *data->cloud, transform);
data->view->removeAllPointClouds();
data->view->addPointCloud(data->cloud, "cloud1");
}
if (data->flag == 1 &&
event.getType() == pcl::visualization::MouseEvent::MouseButtonRelease)
{
qDebug() << "release button location: " << event.getX() << " " << event.getY();
int xchange = event.getX() - data->xb;
int ychange = event.getY() - data->yb;
int changesg = abs(xchange) > abs(ychange) ? 1 : 0;
int nchange = abs(xchange) > abs(ychange) ? xchange : ychange;
float theta = (M_PI / 180) * nchange / 10;
Eigen::Affine3f transform = Eigen::Affine3f::Identity();
if (changesg)transform.rotate(Eigen::AngleAxisf(theta, Eigen::Vector3f::UnitY()));
else transform.rotate(Eigen::AngleAxisf(theta, Eigen::Vector3f::UnitX()));
pcl::transformPointCloud(*data->cloud, *data->cloud, transform);
data->view->removeAllPointClouds();
data->view->addPointCloud(data->cloud, "cloud1");
data->flag = 0;
}
}
//按钮控件的槽函数,点击显示点云
void QtWidgetsApplication_PCL::showCloud() {
pcl::io::loadPCDFile("rabbit.pcd", *cloud);
view->addPointCloud(cloud, "cloud");
view->resetCamera(); //视角
view->registerMouseCallback(pp_callback, this);
//重新进行界面渲染,并且回调函数也被使用了,神来之笔
view->getRenderWindow()->Render();
}