项目qt中vtk显示pcl的点云类贴出
#pragma once
#include <cstdlib>
#include <vector>
#include <string>
#include <iostream>
#include <set>
#include <iostream>
//qt
#include <QMouseEvent>
#include <QFileDialog>
#include <QMessageBox>
#include <QDebug>
#include <QElapsedTimer>
//pcl
#include <pcl/io/ply_io.h>
#include <pcl/PolygonMesh.h>
#include <pcl/common/io.h>
#include <pcl/surface/gp3.h>
#include <pcl/io/vtk_lib_io.h>
#include <pcl/point_types.h>
#include <pcl/visualization/pcl_visualizer.h>
//vtk
#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2)
VTK_MODULE_INIT(vtkInteractionStyle)
#include <vtkActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkGenericOpenGLRenderWindow.h>
#include <vtkAxesActor.h>
#include <vtkPointPicker.h>
#include <QVTKOpenGLNativeWidget.h>
#include <vtkCellLocator.h>
VTK_MODULE_INIT(vtkRenderingVolumeOpenGL2)
VTK_MODULE_INIT(vtkRenderingFreeType)
#include "cloud.h"
#define INFO_CLOUD_ID "info_cloud_id"
#define INFO_TEXT "info_text"
//struct Coord
//{
// QString id;
// double scale;
// Eigen::Affine3f pose;
// Coord() : id("reference"), scale(1.0), pose(Eigen::Affine3f::Identity()) {}
// Coord(QString id_, double scale_, Eigen::Affine3f pose_) : id(id_), scale(scale_), pose(pose_) {}
//};
//点云可视化类,控制点云显示
class CloudViewer : public QVTKOpenGLNativeWidget
{
Q_OBJECT
public:
explicit CloudViewer(QWidget* parent = nullptr);
~CloudViewer();
protected:
vtkSmartPointer<vtkPointPicker> m_picker;
//???CInstallConfigFile m_pCInstallConfigFile;
QList<int> weldSelectList;
QList<int> selectCountList;
// 处理所有鼠标事件
bool event(QEvent* e) override
{
QVTKOpenGLNativeWidget::event(e); // 保留默认交互[1](@ref)
switch (e->type())
{
case QEvent::MouseMove:
handleHover(static_cast<QMouseEvent*>(e));
return true;
case QEvent::MouseButtonPress:
if (static_cast<QMouseEvent*>(e)->button() == Qt::LeftButton)
handleClick(static_cast<QMouseEvent*>(e));
return true;
default:
return QVTKOpenGLNativeWidget::event(e);
}
}
// 处理悬停事件(带节流优化)
void handleHover(QMouseEvent* e)
{
static QElapsedTimer timer;
if (timer.elapsed() < 60)
return; // 30ms节流防止卡顿[7](@ref)
timer.start();
double worldPos[3];
if (convertToWorldSpace(e->pos(), worldPos))
{
pcl::PointXYZ P;
P.x = worldPos[0];
P.y = worldPos[1];
P.z = worldPos[2];
pcl::PointXYZ tmp1, tmp2;
if (m_endpoints.size() <= 0)
{
// qDebug()<<"没有垂直焊缝和水平焊缝!";
return ;
}
//当之前鼠标上的焊缝远离时
for (int j = 0; j < selectCountList.length(); ++j)
{
int selectCount = selectCountList[j];
if (j != selectCountList.length() - 1)
{
changeSelect(selectCount, false);
selectCountList.removeAt(j);
j -= 1;
}
}
if (selectCountList.length() == 1)
{
int selectCount = selectCountList[0];
if (selectCount >= 0)
{
tmp1.x = m_endpoints[selectCount][0];
tmp1.y = m_endpoints[selectCount][1];
tmp1.z = m_endpoints[selectCount][2];
tmp2.x = m_endpoints[selectCount][3];
tmp2.y = m_endpoints[selectCount][4];
tmp2.z = m_endpoints[selectCount][5];
float distance = optimizedDistanceToSegment(P, tmp1, tmp2);
if (distance > 10)
{
//qDebug()<<"distance quxiao : "<<QString::number(0)<<" "<<QString::number(distance);
changeSelect(selectCount, false);
selectCountList.clear();
}
}
}
if (m_endpoints.size() <= 0)
{
qDebug() << "没有垂直焊缝和水平焊缝!";
return ;
}
int count = m_endpoints.size();
// qDebug()<<"count :"<<count;
// bool ifDirections;
float minDistance = 10; //判断最小距离
int current = -1;
for (int i = 0; i < count; ++i)
{
tmp1.x = m_endpoints[i][0];
tmp1.y = m_endpoints[i][1];
tmp1.z = m_endpoints[i][2];
tmp2.x = m_endpoints[i][3];
tmp2.y = m_endpoints[i][4];
tmp2.z = m_endpoints[i][5];
float distance = optimizedDistanceToSegment(P, tmp1, tmp2);
if (distance <= 10)
{
if (distance < minDistance)
{
minDistance = distance;
if (selectCountList.contains(current) && current >= 0)
{
changeSelect(current, false);
selectCountList.removeAt(current);
}
current = i;
// qDebug()<<"distance : "<<QString::number(i)<<" "<<QString::number(distance);
}
}
}
if (current >= 0)
{
changeSelect(current, true);
selectCountList.append(current);
}
}
}
float optimizedDistanceToSegment(const pcl::PointXYZ& P,const pcl::PointXYZ& A,const pcl::PointXYZ& B)
{
const float epsilon = 1e-6f;
Eigen::Vector3f AP(P.x - A.x, P.y - A.y, P.z - A.z);
Eigen::Vector3f AB(B.x - A.x, B.y - A.y, B.z - A.z);
float ab_sqr_norm = AB.squaredNorm();
if (ab_sqr_norm < epsilon)
{
return AP.norm(); // A和B重合
}
float t = AP.dot(AB) / ab_sqr_norm;
if (t <= 0.0f)
{
return AP.norm(); // 最近点为A
}
else if (t >= 1.0f)
{
Eigen::Vector3f BP(P.x - B.x, P.y - B.y, P.z - B.z);
return BP.norm(); // 最近点为B
}
else
{
Eigen::Vector3f projection = A.getVector3fMap() + t * AB;
return (P.getVector3fMap() - projection).norm(); // 垂足距离
}
}
// 处理点击事件
void handleClick(QMouseEvent* e)
{
double worldPos[3];
if (convertToWorldSpace(e->pos(), worldPos))
{
// qDebug() << "Click:" << worldPos[0] << worldPos[1] << worldPos[2];
// qDebug()<<" selectCountList "<<selectCountList;
// qDebug()<<" weldSelectList "<<weldSelectList;
if (selectCountList.length() > 0)
{
for (int i = 0; i < weldSelectList.size(); ++i)
{
if (weldSelectList[i] == selectCountList[selectCountList.length() - 1])
{
// qDebug()<<"取消显示效果+++++++++++!!!";
//???updateWeleSelect(selectCountList[selectCountList.length() - 1] + 1, false);
weldSelectList.removeAt(i);
emit cloudUpdateWeleSelect(selectCountList[selectCountList.length() - 1], false);
// qDebug()<<"发送信号!!!";
return;
}
}
//???updateWeleSelect(selectCountList[selectCountList.length() - 1] + 1, true);
emit cloudUpdateWeleSelect(selectCountList[selectCountList.length() - 1], true);
weldSelectList.append(selectCountList[selectCountList.length() - 1]);
}
}
}
// 坐标转换核心方法(支持HiDPI)
bool convertToWorldSpace(const QPoint& screenPos, double* worldPos)
{
auto iren = this->renderWindow()->GetInteractor();
// 处理HiDPI缩放[4](@ref)
const qreal dpr = devicePixelRatioF();
const int vtkX = static_cast<int>(screenPos.x() * dpr);
const int vtkY = static_cast<int>(this->height() * dpr - screenPos.y() * dpr); // Y轴翻转[4](@ref)
// 执行拾取操作
if (m_picker->Pick(vtkX, vtkY, 0, iren->FindPokedRenderer(vtkX, vtkY)))
{
m_picker->GetPickPosition(worldPos);
// 验证是否为有效点云数据
vtkActor* pickedActor = m_picker->GetActor();
if (pickedActor && pickedActor->GetMapper()->GetInput())
return true;
}
return false;
}
private:
//界面初始化
void init(void);
public:
//刷新
void updateWindow(void);
//重置相机
void resetCamera(void);
//加载并显示PCD点云文件 并返回点云指针
Cloud::Ptr loadCloudFile(void);
//加载点云
void loadCloud(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud);
//显示点云
void viewCloud(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, const std::string name);
//加载并显示XYZ类型点云文件(异常)
void loadXYZCloud(void);
//更新点云
void updateCloud(const Cloud::Ptr& cloud, const Cloud::Ptr& new_cloud);
//保存点云到文件
void saveCloud(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, const std::string name);
//添加点云
void addPointCloud(const Cloud::Ptr& cloud);
void addPointCloud(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, const std::string name);
void addPointCloud(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> color, const std::string name);
//移除点云
void removePointCloud(const QString& id);
//设置点云点大小
void setPointCloudSize(const QString& id, float size);
//设置点云颜色[@cloud 点云对象 @rgb 点云颜色]
void setPointCloudColor(const Cloud::Ptr& cloud, const stRGB& rgb = Color::White);
//设置点云颜色[ @id 点云id @rgb 点云颜色]
void setPointCloudColor(const QString& id, const stRGB& rgb = Color::White);
//添加点云包围盒
void addBox(const Cloud::Ptr& cloud);
//添加箭头[@pt1 起始点 @pt2 终止点 @id 箭头id @display_length 是否展示长度 @rgb 箭头颜色]
void addArrow(const PointXYZRGBN& pt1, const PointXYZRGBN& pt2, const QString& id = "arrow", bool display_length = false, const stRGB& rgb = Color::White);
//添加多边形[ @cloud 点云对象 @id 多边形id @rgb 多边形颜色]
void addPolygon(const Cloud::Ptr& cloud, const QString& id = "polygon", const stRGB& rgb = Color::White);
//加载并显示mesh文件
pcl::PolygonMesh loadMeshFile(void);
//移除模型
void removeShape(const QString& id);
//去除Mesh图像
void removePolygoMesh();
//添加面片图像
void addPolygoMesh(pcl::PolygonMesh& mesh, const QString& id = "mesh");
//设置以面片形式显示
void setRepresentationToSurfaceForAllActors();
//去除所有点云对象
void removeAllPointClouds();
//去除所有形状对象
void removeAllShapes();
//屏幕2D坐标映射为
PointXYZRGBN displayToWorld(const PointXY& xy);
//添加相对屏幕的2D多边形
void addPolygon2D(const std::vector<PointXY>& points, const QString& id = "polyline", const stRGB& rgb = Color::White);
//检查具有给定ID的点云、模型或坐标是否已添加到视图中。
bool contains(const QString& id);
//显示信息 [参数说明: @text 文本信息 @level 信息位置 1-10 @rgb 文本颜色]
void showInfo(const QString& text, int level, const stRGB& rgb = Color::White);
// 生成直线点云
pcl::PointCloud<pcl::PointXYZ>::Ptr generateLineCloud(const pcl::PointXYZ& start_pt, const pcl::PointXYZ& end_pt, float step_size );
//选择和取消焊缝
void updateWeleSelect(int count, bool flag);
//实时获取坐标 动态效果 是否选择当前焊缝
void changeSelect(int count, bool flag);
//单点选取 [@p 屏幕2D坐标点 @return int 选中点云的点索引]
int singlePick(const PointXY& p);
//多边形选取 [@points 屏幕2D多边形顶点 @cloud 选取的点云 @in_out 选择是否反向 @std::vector<int> 选中点云的点索引集合]
std::vector<int> areaPick(const std::vector<PointXY>& points, const Cloud::Ptr& cloud, bool in_out = false);
//设置是否可以和界面坐标交互
void setInteractorEnable(const bool& enable);
//加载XYZ点云文件拆分文件信息 [@string_input 输入字符串 @string_output 输出字符串 @delema1 字符串]
void split(std::string& string_input, std::vector<std::string>& string_output, std::string& delema1);
//?????
void setPointCloudRenderingProperties(const int size, const std::string name);
protected:
void resizeEvent(QResizeEvent* size);
void mousePressEvent(QMouseEvent* event);
void mouseReleaseEvent(QMouseEvent* event);
void mouseMoveEvent(QMouseEvent* event);
signals:
void cloudUpdateWeleSelect(int count, bool flag);
void sizeChanged(const QSize& size);
void viewerPose(Eigen::Affine3f);
void mouseLeftPressed(const PointXY& pt);
void mouseLeftReleased(const PointXY& pt);
void mouseRightPressed(const PointXY& pt);
void mouseRightReleased(const PointXY& pt);
void mouseMoved(const PointXY& pt);
public:
boost::shared_ptr<pcl::visualization::PCLVisualizer> m_viewer;
private:
Q_DISABLE_COPY(CloudViewer);
//显示对象id
bool m_show_id;
//信息级别
int m_info_level;
//上一个id
QString m_last_id;
//渲染器对象
vtkSmartPointer<vtkRenderer> m_render;
//渲染窗口对象
vtkSmartPointer<vtkGenericOpenGLRenderWindow> m_renderwindow;
//坐标系对象
vtkSmartPointer<vtkOrientationMarkerWidget> m_axes;
std::vector<std::vector<float>> m_endpoints;
};
实现部分
#include "cloudviewer.h"
#include <cstdlib>
#include <vector>
#include <fstream>
#include <string>
#include <iostream>
#if _MSC_VER >= 1600
#pragma execution_character_set("utf-8")
#endif
class PCLDisableInteractorStyle : public vtkInteractorStyleTrackballCamera
{
public:
static PCLDisableInteractorStyle* New();
vtkTypeMacro(PCLDisableInteractorStyle, vtkInteractorStyleTrackballCamera);
void OnRightButtonDown() override
{
//qDebug()<<"长按事件触发";
// 触发平移操作
this->StartPan();
this->InvokeEvent(vtkCommand::RightButtonPressEvent, nullptr);
}
void OnRightButtonUp() override
{
// qDebug()<<"长按事件触发";
this->EndPan();
this->InvokeEvent(vtkCommand::RightButtonReleaseEvent, nullptr);
}
};
vtkStandardNewMacro(PCLDisableInteractorStyle);
CloudViewer::CloudViewer(QWidget* parent) : QVTKOpenGLNativeWidget(parent)
, m_show_id(true)
, m_info_level(0)
, m_last_id("")
, m_render(vtkSmartPointer<vtkRenderer>::New())
, m_renderwindow(vtkSmartPointer<vtkGenericOpenGLRenderWindow>::New())
, m_axes(vtkSmartPointer<vtkOrientationMarkerWidget>::New())
{
this->setAttribute(Qt::WA_NoMousePropagation, true);
init();
//??????
QString weldSelectStr;//??????????? = m_pCInstallConfigFile.getUnifiedWeldSelect();
QStringList weldList = weldSelectStr.split(",");
for (int i = 0; i < weldList.size(); ++i)
{
weldSelectList.append(weldList[i].split("~")[0].toInt());
}
}
CloudViewer::~CloudViewer()
{
}
void CloudViewer::init(void)
{
m_renderwindow->AddRenderer(m_render);
m_viewer.reset(new pcl::visualization::PCLVisualizer(m_render, m_renderwindow, "viewer", false));
this->setRenderWindow(m_viewer->getRenderWindow());
m_viewer->setupInteractor(this->interactor(), this->renderWindow());
m_viewer->setBackgroundColor((double)150.0 / 255.0, (double)150.0 / 255.0, (double)150.0 / 255.0);
vtkSmartPointer<vtkAxesActor> actor = vtkSmartPointer<vtkAxesActor>::New();
m_axes->SetOutlineColor(0.9300, 0.5700, 0.1300);
m_axes->SetOrientationMarker(actor);
m_axes->SetInteractor(m_viewer->getRenderWindow()->GetInteractor());
m_axes->SetViewport(0.9, 0, 1, 0.15);
m_axes->SetEnabled(true);
m_axes->InteractiveOn();
m_axes->InteractiveOff();
m_viewer->getRenderWindow()->Render();
// 获取渲染窗口交互器
auto interactor = m_viewer->getRenderWindow()->GetInteractor();
interactor->SetInteractorStyle(PCLDisableInteractorStyle::New());
m_picker = vtkSmartPointer<vtkPointPicker>::New();
m_picker->SetTolerance(0.005); // 拾取精度优化[1](@ref)
// m_picker->UseCellsOn(); // 启用基于单元的拾取
this->setMouseTracking(true); // 启用悬停追踪
this->renderWindow()->GetInteractor()->SetPicker(m_picker); // 绑定拾取器[7](@ref)
}
void CloudViewer::updateWindow(void)
{
m_viewer->resetCamera();
m_viewer->getRenderWindow()->Render();
}
void CloudViewer::resetCamera(void)
{
m_viewer->resetCamera();
m_viewer->getRenderWindow()->Render();
}
Cloud::Ptr CloudViewer::loadCloudFile(void)
{
QString filter = "all(*.*);;ply(*.ply);;pcd(*.pcd)";
QString filename = QFileDialog::getOpenFileName(this, "Open PointCloud", "./", filter);
Cloud::Ptr mycloud(new Cloud);
QFileInfo fileinfo(filename);
if (fileinfo.suffix() == "pcd")
pcl::io::loadPCDFile(filename.toLocal8Bit().toStdString(), *mycloud);
else if (fileinfo.suffix() == "ply")
pcl::io::loadPLYFile(filename.toLocal8Bit().toStdString(), *mycloud);
else
return NULL;
addPointCloud(mycloud);
return mycloud;
}
void CloudViewer::loadCloud(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud)
{
m_viewer->removeAllPointClouds();
//QString filter = "all(*.*);;ply(*.ply);;pcd(*.pcd)";
//QString filename = QFileDialog::getOpenFileName(NULL, "Open PointCloud", "./", filter);
//QFileInfo fileinfo(filename);
//int result = -1;
//if (fileinfo.suffix() == "pcd")
// result = pcl::io::loadPCDFile(filename.toLocal8Bit().toStdString(), *cloud);
//else if (fileinfo.suffix() == "ply")
// result = pcl::io::loadPLYFile(filename.toLocal8Bit().toStdString(), *cloud);
//else
//{
// qDebug() << "no type";
// return;
//}
//if (result == -1)
//{
// qDebug() << "load failed";
// return;
//}
// remove NaN
cloud->is_dense = false;
viewCloud(cloud, "cloud");
//qDebug() << "load " << filename << " complete";
}
void CloudViewer::viewCloud(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, const std::string name)
{
//m_viewer->removeAllPointClouds();
//updateWindow();
//qDebug() << "清空点云!!";
if (!m_viewer->contains(name))
m_viewer->addPointCloud<pcl::PointXYZ>(cloud, name);
else
{
m_viewer->updatePointCloud(cloud, name);
}
updateWindow();
}
void CloudViewer::loadXYZCloud()
{
QString path = QFileDialog::getOpenFileName(this, "Open PointCloud", ".", "Open XYZ files(*.xyz)");
Cloud::Ptr mycloud(new Cloud);
std::ifstream inf;
bool flag = false;
try
{
inf.open(path.toStdString());
}
catch (const std::exception&)
{
return;
}
std::string sline;//每一行
std::vector<std::string>string_output;
std::string Delema = " ";
pcl::PointXYZRGBNormal point3d;
while (getline(inf, sline))
{
int i = 0;
split(sline, string_output, Delema);
point3d.x = stold(string_output[i]);
point3d.y = stold(string_output[i + 1]);
point3d.z = stold(string_output[i + 2]);
point3d.r = 0;
point3d.g = 0;
point3d.b = 0;
point3d.normal_x = 1;
point3d.normal_y = 0;
point3d.normal_z = 0;
string_output.clear();
mycloud->push_back(point3d);
}
inf.close();
addPointCloud(mycloud);
}
void CloudViewer::updateCloud(const Cloud::Ptr& cloud, const Cloud::Ptr& new_cloud)
{
if (cloud == nullptr || new_cloud == nullptr) return;
if (cloud != new_cloud) cloud->swap(*new_cloud);
cloud->update();
addPointCloud(cloud);
addBox(cloud);
}
void CloudViewer::saveCloud(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, const std::string name)
{
pcl::io::savePCDFileBinary(name, *cloud);
}
void CloudViewer::addPointCloud(const Cloud::Ptr& cloud)
{
if (!m_viewer->contains(cloud->id().toStdString()))
m_viewer->addPointCloud<PointXYZRGBN>(cloud, cloud->id().toStdString());
else
{
pcl::visualization::PointCloudColorHandlerRGBField<PointXYZRGBN> rgb(cloud);
m_viewer->updatePointCloud<PointXYZRGBN>(cloud, rgb, cloud->id().toStdString());
}
if (cloud->pointSize() != 1)
m_viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE,
cloud->pointSize(), cloud->id().toStdString());
if (cloud->opacity() != 1)
m_viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_OPACITY,
cloud->opacity(), cloud->id().toStdString());
m_viewer->getRenderWindow()->Render();
resetCamera();
}
void CloudViewer::addPointCloud(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, const std::string name)
{
m_viewer->addPointCloud(cloud, name);
m_viewer->getRenderWindow()->Render();
}
void CloudViewer::addPointCloud(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> color, const std::string name)
{
m_viewer->addPointCloud(cloud, color, name);
m_viewer->getRenderWindow()->Render();
}
void CloudViewer::removePointCloud(const QString& id)
{
m_viewer->removePointCloud(id.toStdString());
m_viewer->getRenderWindow()->Render();
}
void CloudViewer::setPointCloudSize(const QString& id, float size)
{
m_viewer->setPointCloudRenderingProperties(
pcl::visualization::PCL_VISUALIZER_POINT_SIZE, size, id.toStdString(), 0);
m_viewer->getRenderWindow()->Render();
}
void CloudViewer::setPointCloudColor(const Cloud::Ptr& cloud, const stRGB& rgb)
{
pcl::visualization::PointCloudColorHandlerCustom<PointXYZRGBN> color(cloud, rgb.r, rgb.g, rgb.b);
m_viewer->updatePointCloud(cloud, color, cloud->id().toStdString());
m_viewer->getRenderWindow()->Render();
}
void CloudViewer::setPointCloudColor(const QString& id, const stRGB& rgb)
{
m_viewer->setPointCloudRenderingProperties(
pcl::visualization::PCL_VISUALIZER_COLOR, rgb.rf(), rgb.gf(), rgb.bf(), id.toStdString());
m_viewer->getRenderWindow()->Render();
}
void CloudViewer::addBox(const Cloud::Ptr& cloud)
{
if (!m_viewer->contains(cloud->boxId().toStdString()))
m_viewer->addCube(cloud->box().translation, cloud->box().rotation,
cloud->box().width, cloud->box().height,
cloud->box().depth, cloud->boxId().toStdString());
else
{
m_viewer->removeShape(cloud->boxId().toStdString());
m_viewer->addCube(cloud->box().translation, cloud->box().rotation,
cloud->box().width, cloud->box().height,
cloud->box().depth, cloud->boxId().toStdString());
}
m_viewer->setShapeRenderingProperties(pcl::visualization::PCL_VISUALIZER_REPRESENTATION,
pcl::visualization::PCL_VISUALIZER_REPRESENTATION_WIREFRAME,
cloud->boxId().toStdString());
m_viewer->setShapeRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR, cloud->boxColor().rf(),
cloud->boxColor().gf(), cloud->boxColor().bf(), cloud->boxId().toStdString());
m_viewer->getRenderWindow()->Render();
}
void CloudViewer::addArrow(const PointXYZRGBN& pt1, const PointXYZRGBN& pt2, const QString& id, bool display_length, const stRGB& rgb)
{
if (!m_viewer->contains(id.toStdString()))
m_viewer->addArrow(pt1, pt2, rgb.rf(), rgb.gf(), rgb.bf(), display_length, id.toStdString());
else
{
m_viewer->removeShape(id.toStdString());
m_viewer->addArrow(pt1, pt2, rgb.rf(), rgb.gf(), rgb.bf(), display_length, id.toStdString());
m_viewer->getRenderWindow()->Render();
}
}
void CloudViewer::addPolygon(const Cloud::Ptr& cloud, const QString& id, const stRGB& rgb)
{
if (!m_viewer->contains(id.toStdString()))
m_viewer->addPolygon<PointXYZRGBN>(cloud, rgb.rf(), rgb.gf(), rgb.bf(), id.toStdString());
else
{
m_viewer->removeShape(id.toStdString());
m_viewer->addPolygon<PointXYZRGBN>(cloud, rgb.rf(), rgb.gf(), rgb.bf(), id.toStdString());
}
m_viewer->getRenderWindow()->Render();
}
pcl::PolygonMesh CloudViewer::loadMeshFile(void)
{
QString filename = QFileDialog::getOpenFileName(this, "Open PointCloud", ".", "Open PLY files(*.ply)");
pcl::PolygonMesh mesh;
pcl::io::loadPolygonFilePLY(filename.toStdString(), mesh);
removePolygoMesh();
removeAllShapes();
removeAllPointClouds();
addPolygoMesh(mesh, "mesh");
setRepresentationToSurfaceForAllActors(); //网格模型以面片形式显示
return mesh;
}
void CloudViewer::removeShape(const QString& id)
{
m_viewer->removeShape(id.toStdString());
m_viewer->getRenderWindow()->Render();
}
void CloudViewer::removePolygoMesh()
{
m_viewer->removePolygonMesh();
m_viewer->getRenderWindow()->Render();
}
void CloudViewer::addPolygoMesh(pcl::PolygonMesh& mesh, const QString& id)
{
m_viewer->addPolygonMesh(mesh, id.toStdString());
m_viewer->getRenderWindow()->Render();
}
void CloudViewer::setRepresentationToSurfaceForAllActors()
{
m_viewer->setRepresentationToSurfaceForAllActors();
m_viewer->getRenderWindow()->Render();
}
void CloudViewer::removeAllPointClouds()
{
m_viewer->removeAllPointClouds();
m_viewer->getRenderWindow()->Render();
}
void CloudViewer::removeAllShapes()
{
m_viewer->removeAllShapes();
m_viewer->getRenderWindow()->Render();
}
PointXYZRGBN CloudViewer::displayToWorld(const PointXY& pos)
{
double point[4];
m_render->SetDisplayPoint(pos.x, pos.y, 0.1);
m_render->DisplayToWorld();
m_render->GetWorldPoint(point);
return PointXYZRGBN(point[0], point[1], point[2], 0, 0, 0);
}
void CloudViewer::addPolygon2D(const std::vector<PointXY>& points, const QString& id, const stRGB& rgb)
{
Cloud::Ptr cloud(new Cloud);
for (auto& i : points)
{
PointXYZRGBN point = this->displayToWorld(i);
cloud->push_back(point);
}
this->addPolygon(cloud, id, rgb);
}
bool CloudViewer::contains(const QString& id)
{
return m_viewer->contains(id.toStdString());
}
void CloudViewer::showInfo(const QString& text, int level, const stRGB& rgb)
{
m_info_level = std::max(m_info_level, level);
std::string id = INFO_TEXT + std::to_string(level);
if (!m_viewer->contains(id))
m_viewer->addText(text.toStdString(), 10, this->height() - 25 * level, 12, rgb.rf(), rgb.gf(), rgb.bf(), id);
else
m_viewer->updateText(text.toStdString(), 10, this->height() - 25 * level, 12, rgb.rf(), rgb.gf(), rgb.bf(), id);
connect(this, &CloudViewer::sizeChanged, [=](QSize size)
{ m_viewer->updateText(text.toStdString(), 10, size.height() - 25 * level, 12, rgb.rf(), rgb.gf(), rgb.bf(), id); });
m_viewer->getRenderWindow()->Render();
}
pcl::PointCloud<pcl::PointXYZ>::Ptr CloudViewer::generateLineCloud(const pcl::PointXYZ& start_pt, const pcl::PointXYZ& end_pt, float step_size)
{
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
// 计算直线方向向量
Eigen::Vector3f dir = Eigen::Vector3f(end_pt.x - start_pt.x,end_pt.y - start_pt.y,end_pt.z - start_pt.z);
// 直线总长度
float length = dir.norm();
dir.normalize(); // 单位化方向向量
// 沿直线方向按步长生成点
for (float t = 0; t <= length; t += step_size)
{
pcl::PointXYZ pt;
pt.x = start_pt.x + dir.x() * t;
pt.y = start_pt.y + dir.y() * t;
pt.z = start_pt.z + dir.z() * t;
cloud->push_back(pt);
}
// 确保终点被包含
cloud->push_back(end_pt);
return cloud;
}
void CloudViewer::updateWeleSelect(int count, bool flag)
{
QString lineStr = "line_" + QString::number(count);
m_viewer->removePointCloud(lineStr.toStdString());
pcl::PointXYZ tmp1, tmp2;
tmp1.x = m_endpoints[count - 1][0];
tmp1.y = m_endpoints[count - 1][1];
tmp1.z = m_endpoints[count - 1][2];
tmp2.x = m_endpoints[count - 1][3];
tmp2.y = m_endpoints[count - 1][4];
tmp2.z = m_endpoints[count - 1][5];
pcl::PointCloud<pcl::PointXYZ>::Ptr line_cloud = generateLineCloud(tmp1, tmp2, 0.01f);
if (flag) {
pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> rgb(line_cloud, 0, 255, 0);
m_viewer->addPointCloud<pcl::PointXYZ>(line_cloud, rgb, "line_" + std::to_string(count));
}
else {
pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> rgb(line_cloud, 0, 0, 0);
m_viewer->addPointCloud<pcl::PointXYZ>(line_cloud, rgb, "line_" + std::to_string(count));
}
m_viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "line_" + std::to_string(count));
m_viewer->spinOnce();
m_viewer->getRenderWindow()->Render();
}
void CloudViewer::changeSelect(int count, bool flag)
{
//????暂时屏蔽
//count += 1;
//QString lineStr = "line_" + QString::number(count);
//if (flag)
// m_viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 8, lineStr.toStdString());
//else
// m_viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, lineStr.toStdString());
//m_viewer->spinOnce();
//m_viewer->getRenderWindow()->Render();
}
int CloudViewer::singlePick(const PointXY& pos)
{
vtkSmartPointer<vtkPointPicker> m_point_picker = vtkSmartPointer<vtkPointPicker>::New();
m_renderwindow->GetInteractor()->SetPicker(m_point_picker);
if (!m_point_picker)
return -1;
m_renderwindow->GetInteractor()->StartPickCallback();
vtkRenderer* ren = this->interactor()->FindPokedRenderer(pos.x, pos.y);
m_point_picker->Pick(pos.x, pos.y, 0.0, ren);
return (static_cast<int>(m_point_picker->GetPointId()));
}
std::vector<int> CloudViewer::areaPick(const std::vector<PointXY>& points, const Cloud::Ptr& cloud, bool in_out)
{
int size = points.size();
float constant[99], multiple[99];
int i, j = size - 1;
for (i = 0; i < size; i++)
{
if (points[j].y == points[i].y)
{
constant[i] = points[i].x;
multiple[i] = 0;
}
else
{
constant[i] = points[i].x - (points[i].y * points[j].x) / (points[j].y - points[i].y) +
(points[i].y * points[i].x) / (points[j].y - points[i].y);
multiple[i] = (points[j].x - points[i].x) / (points[j].y - points[i].y);
}
j = i;
}
std::vector<int> indices;
for (size_t i = 0; i < cloud->size(); i++)
{
m_render->SetWorldPoint(cloud->points[i].x, cloud->points[i].y, cloud->points[i].z, 1);
m_render->WorldToDisplay();
double p[3];
m_render->GetDisplayPoint(p);
bool oddNodes = in_out, current = points[size - 1].y > p[1], previous;
for (int m = 0; m < size; m++)
{
previous = current;
current = points[m].y > p[1];
if (current != previous)
oddNodes ^= p[1] * multiple[m] + constant[m] < p[0];
}
if (oddNodes) indices.push_back(i);
}
return indices;
}
void CloudViewer::setInteractorEnable(const bool& enable)
{
if (!enable)
{
vtkNew<PCLDisableInteractorStyle> style;
m_renderwindow->GetInteractor()->SetInteractorStyle(style);
}
else
{
vtkNew<pcl::visualization::PCLVisualizerInteractorStyle> style;
m_renderwindow->GetInteractor()->SetInteractorStyle(style);
}
m_viewer->getRenderWindow()->Render();
}
void CloudViewer::split(std::string& string_input, std::vector<std::string>& string_output, std::string& delema1)
{
std::string::size_type start = string_input.find_first_not_of(delema1, 0); //找到第一个不为delema1的下标
std::string::size_type pose = string_input.find_first_of(delema1, start); //找到第一个delema1的下标
while (std::string::npos != start || std::string::npos != pose) //当即没有delema1也没有字符的时候结束
{
string_output.push_back(string_input.substr(start, pose - start));
start = string_input.find_first_not_of(delema1, pose); //更新start 从pose开始
pose = string_input.find_first_of(delema1, start); //更新pose,从start开始再次寻找
}
}
void CloudViewer::setPointCloudRenderingProperties(const int size, const std::string name)
{
m_viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, size, name);
m_viewer->getRenderWindow()->Render();
}
void CloudViewer::resizeEvent(QResizeEvent* size)
{
emit sizeChanged(size->size());
return QVTKOpenGLNativeWidget::resizeEvent(size);
}
void CloudViewer::mousePressEvent(QMouseEvent* event)
{
//qDebug()<<"cloudview press";
if (event->button() == Qt::LeftButton)
{
emit mouseLeftPressed(PointXY(m_renderwindow->GetInteractor()->GetEventPosition()[0],
m_renderwindow->GetInteractor()->GetEventPosition()[1]));
}
else if (event->button() == Qt::RightButton)
{
emit mouseRightPressed(PointXY(m_renderwindow->GetInteractor()->GetEventPosition()[0],
m_renderwindow->GetInteractor()->GetEventPosition()[1]));
}
return QVTKOpenGLNativeWidget::mousePressEvent(event);
}
void CloudViewer::mouseReleaseEvent(QMouseEvent* event)
{
if (event->button() == Qt::LeftButton)
{
emit viewerPose(m_viewer->getViewerPose());
emit mouseLeftReleased(PointXY(m_renderwindow->GetInteractor()->GetEventPosition()[0],
m_renderwindow->GetInteractor()->GetEventPosition()[1]));
}
else if (event->button() == Qt::RightButton)
{
emit mouseRightReleased(PointXY(m_renderwindow->GetInteractor()->GetEventPosition()[0],
m_renderwindow->GetInteractor()->GetEventPosition()[1]));
}
return QVTKOpenGLNativeWidget::mouseReleaseEvent(event);
}
void CloudViewer::mouseMoveEvent(QMouseEvent* event)
{
emit mouseMoved(PointXY(m_renderwindow->GetInteractor()->GetEventPosition()[0],
m_renderwindow->GetInteractor()->GetEventPosition()[1]));
return QVTKOpenGLNativeWidget::mouseReleaseEvent(event);
}
有需要的自取,我就不贴图了
