386 lines
14 KiB
C++
386 lines
14 KiB
C++
/**
|
|
* @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 "PointCloudOperator/PointCloudMesh.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) {
|
|
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::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> polydata2 = 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();
|
|
qDebug()<<"cellToPointFilter successfully!! wait for writing file dataset : "<<inpolyData->GetNumberOfPoints()<<" "<<inpolyData->GetNumberOfCells();
|
|
if(PointCloudOperator::PointCloudMeshOperator::GP(inpolyData,polydata,_SearchRadius,_Mu,_MaximumNearestNeighbors,_MaximumSurfaceAngle,_MaximumAngle,_MinimumAngle)){
|
|
}else{
|
|
return false;
|
|
}
|
|
|
|
DebugInfo("PCLGPMeshAlg successfully!! wait for writing file dataset : %d \n",nullptr==polydata);
|
|
if(nullptr!=polydata){
|
|
DebugInfo("PCLGPMeshAlg successfully!! wait for writing file dataset : %d %d\n",polydata->GetNumberOfPoints(),polydata->GetNumberOfCells());
|
|
}else{
|
|
return false;
|
|
}
|
|
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 {
|
|
}
|
|
}
|
|
|
|
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
|