LAMPCAE/src/PluginWBFZExchangePlugin/DialogPCLGPMesh.cpp

443 lines
18 KiB
C++
Raw Normal View History

/**
* @file DialogPCLGPMesh.cpp
* @brief None
* @author (3045316072@qq.com)
* @version 2.5.0
* @date 2024/4/5
* @copyright Copyright (c) Since 2024 All rights reserved.
*/
// You may need to build the project (run Qt uic code generator) to get "ui_DialogPCLGPMesh.h"
// resolved
#include "DialogPCLGPMesh.h"
#include "ui_DialogPCLGPMesh.h"
#include "ModuleBase/ThreadTask.h"
#include "PythonModule/PyAgent.h"
#include "MeshData/meshSingleton.h"
#include "MeshData/meshSet.h"
#include <QMenu>
#include <QDebug>
#include <pcl/filters/statistical_outlier_removal.h>
#include <QtWidgets>
#include <QFileDialog>
#include <QFileInfo>
#include "MeshData/meshKernal.h"
#include "PointCloudOperator/PointCloudCommon.h"
#include "Settings/BusAPI.h"
#include "BaseTool.h"
#include "IO/IOConfig.h"
#include "ModuleBase/ThreadControl.h"
#include "ConfigOptions/ConfigOptions.h"
#include "ConfigOptions/MeshConfig.h"
#include "MeshData/meshSingleton.h"
#include "MeshData/meshKernal.h"
#include <vtkSmartPointer.h>
#include <vtkDataSetReader.h>
#include <vtkDataSet.h>
#include <vtkSTLReader.h>
#include <vtkTecplotReader.h>
#include <vtkMultiBlockDataSet.h>
#include <vtkAppendFilter.h>
#include <vtkUnstructuredGrid.h>
#include <vtkUnstructuredGridWriter.h>
#include <vtkAppendFilter.h>
#include <QFileInfo>
#include <QTextCodec>
#include <vtkSTLWriter.h>
#include "Common/DebugLogger.h"
// auto meshData = MeshData::MeshData::getInstance();
namespace MainWidget {
DialogPCLGPMesh::DialogPCLGPMesh(GUI::MainWindow *parent)
: QFDialog(parent), _ui(new Ui::DialogPCLGPMesh), _mw(parent), _selectdlg(new DialogSelectComponents(parent)) {
_ui->setupUi(this);
_ui->geoSelectPoint->setToolTip(tr("Clicked Button Selected Components"));
setWindowTitle(tr("GP Meshing"));
_ui->listWidget->setContextMenuPolicy(Qt::CustomContextMenu);
connect(_ui->geoSelectPoint, &QPushButton::clicked, [=]() {
_selectdlg->clearSelectItems();
_selectdlg->exec();
});
connect(_selectdlg, SIGNAL(selectedComponentsSig(QList<MeshData::MeshSet *>)), this,
SLOT(selectedComponentsSlot(QList<MeshData::MeshSet *>)));
connect(_ui->listWidget, SIGNAL(customContextMenuRequested(const QPoint&)), this,
SLOT(customContextMenuRequestedSlot(const QPoint&)));
}
DialogPCLGPMesh::~DialogPCLGPMesh() {
delete _ui;
_ui = NULL;
delete _selectdlg;
_selectdlg = NULL;
}
void DialogPCLGPMesh::accept() {
if (_components.size() == 0)
return;
QString componentIds;
for (auto component: _components)
componentIds.append(QString(",%1").arg(component->getID()));
componentIds.remove(0, 1);
double SearchRadius = _ui->SearchRadius->value();
double Mu = _ui->Mu->value();
int MaximumNearestNeighbors = _ui->MaximumNearestNeighbors->value();
double MaximumSurfaceAngle = _ui->MaximumSurfaceAngle->value();
double MaximumAngle = _ui->MaximumAngle->value();
double MinimumAngle = _ui->MinimumAngle->value();
QString outfilename = "filter";
for (auto component: _components)
outfilename.append(QString("_%1").arg(component->getName()));
// 确定是否保存结果文件
QMessageBox::StandardButton result =
QMessageBox::critical(this, "info", "save as result ?");
QString filepath =
JoinPath(Setting::BusAPI::instance()->getWorkingDir(), outfilename + "_tmep.pcd");
QString AbFileName = filepath;
if (result == QMessageBox::StandardButton::Ok
|| result == QMessageBox::StandardButton::Yes) {
DebugInfo("outfilename ok ok \n");
QStringList suffixlist = IO::IOConfigure::getMeshExporters();
if (suffixlist.isEmpty()) {
QMessageBox::warning(this, tr("Warning"), tr("The MeshPlugin is not installed !"));
return;
}
QStringList meshsuffix = ConfigOption::ConfigOption::getInstance()
->getMeshConfig()
->getExportSuffix(ConfigOption::MeshDataType::vtkMesh)
.split(";");
QStringList list;
for (QString s: meshsuffix) {
for (int i = 0; i < suffixlist.size(); i++) {
QString suffix = suffixlist.at(i);
if (suffix.contains(s))
list.append(suffix);
}
}
std::sort(list.begin(), list.end());
QString suffixes = list.join(";;");
QString workDir = Setting::BusAPI::instance()->getWorkingDir();
QFileDialog dlg(this, tr("Export mesh"), workDir, suffixes);
dlg.setAcceptMode(QFileDialog::AcceptSave);
if (dlg.exec() != QFileDialog::FileName)
return;
QString aSuffix = dlg.selectedNameFilter();
QString aFileName = dlg.selectedFiles().join(",");
if (!(aFileName.isEmpty())) {
filepath = aFileName;
} else {
}
AbFileName = filepath;
} else { // 不保存成点云数据
}
DebugInfo("outfilename %s \n", AbFileName.toStdString().c_str());
// 启动线程
auto pclremesh =
new WBFZ::PCLGPMesh(AbFileName, WBFZ::PointCloudOperation::POINTCLOUD_MESH, _mainWindow,
componentIds, SearchRadius, Mu, MaximumNearestNeighbors,
MaximumSurfaceAngle, MaximumAngle, MinimumAngle);
ModuleBase::ThreadControl *tc = new ModuleBase::ThreadControl(pclremesh);
emit tc->threadStart(); // emit MSHwriter->start();
DebugInfo("tc overing %s \n", AbFileName.toStdString().c_str());
QFDialog::accept();
DebugInfo("QFDialog::accept() \n");
}
void DialogPCLGPMesh::selectedComponentsSlot(QList<MeshData::MeshSet *> components) {
for (MeshData::MeshSet *set: components) {
if (_components.contains(set))
continue;
_components.append(set);
_ui->listWidget->addItem(set->getName());
}
}
void DialogPCLGPMesh::customContextMenuRequestedSlot(const QPoint &point) {
QListWidgetItem *curItem = _ui->listWidget->itemAt(point);
if (!curItem)
return;
QMenu *menu = new QMenu(this);
QAction *deleteItem = new QAction(tr("delete this item"));
menu->addAction(deleteItem);
connect(menu, &QMenu::triggered, [=]() { removeCurrentItem(curItem); });
menu->exec(QCursor::pos());
}
void DialogPCLGPMesh::removeCurrentItem(QListWidgetItem *curItem) {
auto meshData = MeshData::MeshData::getInstance();
auto meshSet = meshData->getMeshSetByName(curItem->text());
if (!meshSet)
return;
_components.removeOne(meshSet);
_ui->listWidget->removeItemWidget(curItem);
delete curItem;
}
} // namespace MainWidget
namespace WBFZ {
PCLGPMesh::PCLGPMesh(const QString &fileName, WBFZ::PointCloudOperation operation,
GUI::MainWindow *mw, QString componentIds, double SearchRadius, double Mu,
int MaximumNearestNeighbors, double MaximumSurfaceAngle,
double MaximumAngle, double MinimumAngle)
: ModuleBase::ThreadTask(mw), _operation(operation), _fileName(fileName), _componentIds(componentIds), _SearchRadius(SearchRadius), _Mu(Mu), _MaximumNearestNeighbors(MaximumNearestNeighbors), _MaximumSurfaceAngle(MaximumSurfaceAngle), _MaximumAngle(MaximumAngle), _MinimumAngle(MinimumAngle) {
}
PCLGPMesh::~PCLGPMesh() {}
void PCLGPMesh::defaultMeshFinished() {
ModuleBase::ThreadTask::threadTaskFinished();
Py::PythonAgent::getInstance()->unLock();
if (_threadRuning) {
QString information{};
ModuleBase::Message msg;
if (_operation == POINTCLOUD_FILTER || _operation == POINTCLOUD_MESH) {
if (_success) {
// emit _mainwindow->updateMeshTreeSig();
// emit _mainwindow->updateSetTreeSig();
// emit _mainwindow->updateActionStatesSig();
// emit _mainwindow->updateActionsStatesSig();
// emit _mainwindow->getSubWindowManager()->openPreWindowSig();
// emit _mainwindow->updatePreMeshActorSig();
information = QString("Successful resurface Mesh From \"%1\"").arg(_fileName);
msg.type = Common::Message::Normal;
msg.message = information;
qDebug() << "Successful Import Mesh From " << _fileName;
QFileInfo info(_fileName);
QString name = info.fileName();
QString path = info.filePath();
QString suffix = info.suffix().toLower();
if(info.exists()){
if(suffix.toLower().contains("stl")){
suffix="STL(*.stl)";
emit _mainwindow->importMeshSIGN(_fileName,suffix,-1);
}else if(suffix.toLower().contains("vtk")){
suffix="VTK(*.vtk)";
emit _mainwindow->importMeshSIGN(_fileName,suffix,-1);
}else if(suffix.toLower().contains("neu")){
suffix="Gambit(*.neu)";
emit _mainwindow->importMeshSIGN(_fileName,suffix,-1);
}else{
information = QString("Failed Filter From \"%1\"").arg(_fileName);
msg.type = Common::Message::Error;
msg.message = information;
qDebug() << "Failed Import Mesh From " << _fileName;
}
}
} else {
information = QString("Failed resurface From \"%1\"").arg(_fileName);
msg.type = Common::Message::Error;
msg.message = information;
qDebug() << "Failed resurface Mesh From " << _fileName;
}
} else {
}
emit showInformation(information);
emit _mainwindow->printMessageToMessageWindow(msg);
}
qDebug()<<"PCLGPMesh::defaultMeshFinished ModuleBase::ThreadTask::threadTaskFinished";
// Py::PythonAgent::getInstance()->unLock();
}
void PCLGPMesh::setThreadRunState(bool flag) {
_success = flag;
}
void PCLGPMesh::run() {
ModuleBase::ThreadTask::run();
bool result = false;
switch (_operation) {
case POINTCLOUD_MESH:
emit showInformation(tr("POINTCLOUD_MESH From \"%1\"").arg(_fileName));
result = remeshtaskProcess();
setThreadRunState(result);
break;
default:
break;
}
DebugInfo("run ok _success %d _threadRuning %d \n", _success, _threadRuning);
defaultMeshFinished();
}
bool PCLGPMesh::GP(vtkSmartPointer<vtkPolyData>& inpolygon,vtkSmartPointer<vtkPolyData>& polydata) { // 点云处理模块
// 可用变量
double SearchRadius = _SearchRadius;
double Mu = _Mu;
int MaximumNearestNeighbors = _MaximumNearestNeighbors;
double MaximumSurfaceAngle = _MaximumSurfaceAngle;
double MaximumAngle = _MaximumAngle;
double MinimumAngle = _MinimumAngle;
pcl::PointCloud<pcl::PointXYZRGBA>::Ptr cloud_with_rgba(new pcl::PointCloud<pcl::PointXYZRGBA>);
pcl::PointCloud<pcl::PointXYZRGBA>::Ptr cloud_filtered( new pcl::PointCloud<pcl::PointXYZRGBA>);
pcl::PointCloud<pcl::PointXYZRGBA>::Ptr output( new pcl::PointCloud<pcl::PointXYZRGBA>); // 输出结果
pcl::PointCloud<pcl::PointNormal>::Ptr cloud_with_normals(new pcl::PointCloud<pcl::PointNormal>); // 法线向量
pcl::search::KdTree<pcl::PointNormal>::Ptr tree2(new pcl::search::KdTree<pcl::PointNormal>);
pcl::io::vtkPolyDataToPointCloud(inpolygon, *cloud_with_rgba);
PointCloudOperator::PointCloudCommon::NormalEstimation(cloud_with_rgba, cloud_with_normals);
tree2->setInputCloud(cloud_with_normals); // 构建搜索树
std::shared_ptr<pcl::PolygonMesh> mesh (new pcl::PolygonMesh); // 非智能指针,需要释放
pcl::GreedyProjectionTriangulation<pcl::PointNormal> gp3; // 定义三角化对象
gp3.setSearchRadius(SearchRadius); // 设置连接点之间的最大距离(即三角形的最大边长)
gp3.setMu(Mu); // 设置被样本点搜索其临近点的最远距离,为了适应点云密度的变化
gp3.setMaximumNearestNeighbors(MaximumNearestNeighbors); // 设置样本点可搜索的邻域个数
gp3.setMaximumSurfaceAngle(MaximumSurfaceAngle); // 设置某点法线方向偏离样本点法线方向的最大角度
gp3.setMinimumAngle(MinimumAngle); // 设置三角化后得到三角形内角的最小角度
gp3.setMaximumAngle(MaximumAngle); // 设置三角化后得到三角形内角的最大角度
gp3.setNormalConsistency(false); // 设置该参数保证法线朝向一致
gp3.setInputCloud(cloud_with_normals); // 设置输入点云为有向点云
gp3.setSearchMethod(tree2); // 设置搜索方式
gp3.reconstruct(*mesh); // 重建提取三角化 -- 这里会导致程序崩溃,可能存在内存泄露,
// DebugInfo("remesh over GP \n");
// return false;
size_t pointcount = PointCloudOperator::PointCloudCommon::mesh2vtk(*mesh, polydata);
DebugInfo("remesh over ,conver init %d \n", mesh->polygons.size());
//delete mesh;
return true;
}
bool PCLGPMesh::remeshtaskProcess() {
QString componentIds = _componentIds;
emit _mainwindow->printMessage(Common::Message::Normal, "PCLGPMeshAlg");
// 获取vtdataset
QStringList qCompontIds = QString(componentIds).split(',');
MeshData::MeshSet* meshSet = NULL;
MeshData::MeshKernal* meshKernal = NULL;
MeshData::MeshData* meshData = MeshData::MeshData::getInstance();
QString kernalName, transformedName, setType, ids;
// 创建 vtkCellDataToPointData 过滤器
vtkSmartPointer<vtkGeometryFilter> cellToPointFilter = vtkSmartPointer<vtkGeometryFilter>::New();
vtkSmartPointer<vtkPolyData> inpolyData=vtkSmartPointer<vtkPolyData>::New();
vtkSmartPointer<vtkPolyData> polydata = vtkSmartPointer<vtkPolyData>::New();
for (QString compontId: qCompontIds) {
meshSet = meshData->getMeshSetByID(compontId.toInt());
DebugInfo("point count %d : %d \n", compontId.toInt(), meshSet == nullptr);
if (!meshSet)
continue;
QString outfilename = meshSet->getName();
cellToPointFilter->SetInputData(PointCloudOperator::PointCloudCommon::meshSetToVtkDataset(meshSet));
DebugInfo("point count %d \n", compontId.toInt());
}
// 执行过滤操作
cellToPointFilter->Update();
DebugInfo("cellToPointFilter \n");
// 获取过滤后的 vtkPolyData
inpolyData = cellToPointFilter->GetOutput();
if(this->GP(inpolyData,polydata)){
}else{
return false;
}
DebugInfo("outpolyData ");
//vtkDataSet* dataset = vtkDataSet::SafeDownCast(polydata); // dataset =vtkDataSet::SafeDownCast(polydata); // 默认完成 vtkpolydata --> vtkdataset
// outpolyData->Delete(); // 释放指针 ,
// 千万不能释放这个指针,不然程序回调时,会直接内存崩溃
DebugInfo("PCLGPMeshAlg successfully!! wait for writing file dataset : %d \n",nullptr==polydata);
// vtkDataSet*
// dataset=PCLGPMeshAlg(_componentIds,_SearchRadius,_Mu,_MaximumNearestNeighbors,_MaximumSurfaceAngle,_MaximumAngle,_MinimumAngle);
if(nullptr!=polydata){
DebugInfo("PCLGPMeshAlg successfully!! wait for writing file dataset : %d %d\n",polydata->GetNumberOfPoints(),polydata->GetNumberOfCells());
}
QString filepath = _fileName;
QFile outfile_presave(_fileName);
if (outfile_presave.exists()) { // 如果存在文件,就删除
outfile_presave.remove();
}
// 手动释放所有的变量
//return false;
{ // 写出到文件中
// 加载文件
QFileInfo info(filepath);
QString name = info.fileName();
QString path = info.filePath();
QString suffix = info.suffix().toLower();
QTextCodec* codec = QTextCodec::codecForName("GB18030");
QByteArray ba = codec->fromUnicode(filepath);
std::string outFileName = ba.data();
DebugInfo("writing %s suffix %s !! \n", ba.data(), suffix.toStdString().c_str());
if(suffix == "vtk") {
vtkSmartPointer<vtkUnstructuredGridWriter> writer =
vtkSmartPointer<vtkUnstructuredGridWriter>::New();
writer->SetInputData(polydata);
writer->SetFileTypeToBinary();
writer->SetFileName(ba);
writer->Write();
DebugInfo("writing vtk !! \n");
} else if(suffix == "stl") {
QTextCodec* codec = QTextCodec::codecForName("GB18030");
QByteArray ba = codec->fromUnicode(_fileName);
vtkSmartPointer<vtkSTLWriter> writer = vtkSmartPointer<vtkSTLWriter>::New();
writer->SetInputData(polydata);
writer->SetFileTypeToBinary();
writer->SetFileName(ba);
writer->Write();
DebugInfo("writing stl !! \n");
} else {
}
}
// QFileInfo info(_fileName);
// QString name = info.fileName();
// QString path = info.filePath();
// QString suffix = info.suffix().toLower();
DebugInfo("dataset %d _fileName %s \n", nullptr==polydata, _fileName.toStdString().c_str());
if (nullptr == polydata) { } else {
DebugInfo("GP variable start release !! \n");
//dataset->Delete();
//dataset=nullptr;
DebugInfo("GP variable finish release!! \n");
}
QFile outfile(_fileName);
if (outfile.exists()) {
DebugInfo("GP main process sucessfully !! \n");
return true;
} else {
DebugInfo("GP main process fail !! \n");
return false;
}
DebugInfo("GP main process fail !! \n");
return false;
}
} // namespace WBFZ