Files
cc-treeiso-plugin/src/qTreeIso.cpp
T

239 lines
7.9 KiB
C++
Raw Normal View History

2023-06-18 23:29:36 +02:00
//#######################################################################################
2023-05-04 19:22:59 -06:00
//# #
//# CLOUDCOMPARE PLUGIN: qTreeIso #
//# #
//# This program is free software; you can redistribute it and/or modify #
//# it under the terms of the GNU General Public License as published by #
//# the Free Software Foundation; version 2 or later of the License. #
//# #
//# This program is distributed in the hope that it will be useful, #
//# but WITHOUT ANY WARRANTY; without even the implied warranty of #
//# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
//# GNU General Public License for more details. #
//# #
//# Please cite the following paper if you find this tool helpful #
//# #
//# Xi, Z.; Hopkinson, C. 3D Graph-Based Individual-Tree Isolation (Treeiso) #
//# from Terrestrial Laser Scanning Point Clouds. Remote Sens. 2022, 14, 6116. #
//# https://doi.org/10.3390/rs14236116 #
//# #
//# Our work relies on the cut-pursuit algorithm, please also consider citing: #
//# Landrieu, L.; Obozinski, G. Cut Pursuit: Fast Algorithms to Learn Piecewise #
//# Constant Functions on General Weighted Graphs. SIAM J. Imaging Sci. #
//# 2017, 10, 17241766. #
//# #
//# Copyright © #
//# Artemis Lab, Department of Geography & Environment #
//# University of Lethbridge, Canada #
//# #
//# #
//# Zhouxin Xi and Chris Hopkinson; #
//# truebelief2010@gmail.com; c.hopkinson@uleth.ca #
//# #
//#######################################################################################
// A Matlab version shared via:
// https://github.com/truebelief/artemis_treeiso
#include "qTreeIso.h"
//Qt
#include <QApplication>
#include <QProgressDialog>
#include <QMainWindow>
#include <QComboBox>
#include <QElapsedTimer>
#include <QMessageBox>
2023-05-04 19:22:59 -06:00
//Local
#include "ccTreeIsoDlg.h"
2023-05-04 19:22:59 -06:00
#include "qTreeIsoCommands.h"
//System
#include <iostream>
#include <vector>
#include <string>
#include <assert.h>
//qCC_db
#include <ccGenericPointCloud.h>
#include <ccPointCloud.h>
#include <ccHObjectCaster.h>
#include <ccOctree.h>
#include <ccMesh.h>
//TreeIso
#include <TreeIso.h>
2023-05-04 19:22:59 -06:00
qTreeIso::qTreeIso(QObject* parent)
: QObject(parent)
, ccStdPluginInterface(":/CC/plugin/qTreeIso/info.json")
, m_action(nullptr)
{
}
void qTreeIso::onNewSelection(const ccHObject::Container& selectedEntities)
{
if (m_action)
{
bool hasCloud = false;
for (ccHObject* entity : selectedEntities)
{
if (entity && entity->isA(CC_TYPES::POINT_CLOUD))
{
hasCloud = true;
break;
}
}
m_action->setEnabled(hasCloud);
}
}
QList<QAction *> qTreeIso::getActions()
{
if (!m_action)
{
m_action = new QAction(getName(), this);
2023-05-04 19:22:59 -06:00
m_action->setToolTip(getDescription());
m_action->setIcon(getIcon());
//connect appropriate signal
connect(m_action, &QAction::triggered, this, &qTreeIso::doAction);
}
return { m_action };
}
void qTreeIso::doAction()
{
Parameters parameters;
ccTreeIsoDlg treeisoDlg(m_app->getMainWindow());
2023-05-04 19:22:59 -06:00
connect(treeisoDlg.pushButtonInitSeg, &QPushButton::clicked, [&]
{
parameters.min_nn1 = treeisoDlg.spinBoxK1->value();
parameters.reg_strength1 = treeisoDlg.doubleSpinBoxLambda1->value();;
parameters.decimate_res1 = treeisoDlg.doubleSpinBoxDecRes1->value();
2023-05-04 19:22:59 -06:00
2023-05-29 15:19:56 +02:00
init_segs(parameters, &treeisoDlg);
});
2023-05-04 19:22:59 -06:00
connect(treeisoDlg.pushButtonInterSeg, &QPushButton::clicked, [&]
{
parameters.min_nn2 = treeisoDlg.spinBoxK2->value();
parameters.reg_strength2 = treeisoDlg.doubleSpinBoxLambda2->value();
parameters.decimate_res2 = treeisoDlg.doubleSpinBoxDecRes2->value();
parameters.max_gap = treeisoDlg.doubleSpinBoxMaxGap->value();
2023-05-29 15:19:56 +02:00
intermediate_segs(parameters, &treeisoDlg);
});
connect(treeisoDlg.pushButtonReseg, &QPushButton::clicked, [&]
{
parameters.rel_height_length_ratio = treeisoDlg.doubleSpinBoxRelHLRatio->value();
parameters.vertical_weight = treeisoDlg.doubleSpinBoxVWeight->value();
2023-05-29 15:19:56 +02:00
final_segs(parameters, &treeisoDlg);
});
treeisoDlg.pushButtonInitSeg->setEnabled(true);
if (treeisoDlg.exec())
2023-05-04 19:22:59 -06:00
{
if (m_app)
{
m_app->refreshAll();
}
else
{
// m_app should have already been initialized by CC when plugin is loaded!
assert(false);
}
2023-05-04 19:22:59 -06:00
}
}
2023-05-29 15:19:56 +02:00
void qTreeIso::init_segs(const Parameters& parameters, QWidget* parent/*=nullptr*/)
2023-05-04 19:22:59 -06:00
{
// display the progress dialog
2023-05-29 15:19:56 +02:00
QProgressDialog* progressDlg = new QProgressDialog(parent);
progressDlg->setWindowTitle("TreeIso Step 1. Initial segmention");
progressDlg->setLabelText(tr("Computing...."));
progressDlg->setCancelButton(nullptr);
progressDlg->setRange(0, 0); // infinite progress bar
progressDlg->show();
if (!TreeIso::Init_seg(parameters.min_nn1, parameters.reg_strength1, parameters.decimate_res1, m_app, progressDlg))
2023-05-04 19:22:59 -06:00
{
m_app->dispToConsole("Not enough memory", ccMainAppInterface::ERR_CONSOLE_MESSAGE);
return;
}
progressDlg->close();
2023-05-04 19:22:59 -06:00
QApplication::processEvents();
2023-05-04 19:22:59 -06:00
m_app->updateUI();
m_app->refreshAll();
}
2023-05-29 15:19:56 +02:00
void qTreeIso::intermediate_segs(const Parameters& parameters, QWidget* parent/*=nullptr*/)
2023-05-04 19:22:59 -06:00
{
// display the progress dialog
2023-05-29 15:19:56 +02:00
QProgressDialog* progressDlg = new QProgressDialog(parent);
progressDlg->setWindowTitle("TreeIso Step 2. Interim segmention");
progressDlg->setLabelText(tr("Computing...."));
progressDlg->setCancelButton(nullptr);
progressDlg->setRange(0, 0); // infinite progress bar
progressDlg->show();
2023-05-04 19:22:59 -06:00
if (!TreeIso::Intermediate_seg(parameters.min_nn2, parameters.reg_strength2, parameters.decimate_res2, parameters.max_gap, m_app, progressDlg))
2023-05-04 19:22:59 -06:00
{
progressDlg->hide();
2023-05-04 19:22:59 -06:00
QApplication::processEvents();
m_app->updateUI();
m_app->refreshAll();
return;
}
progressDlg->hide();
2023-05-04 19:22:59 -06:00
QApplication::processEvents();
2023-05-04 19:22:59 -06:00
m_app->updateUI();
m_app->refreshAll();
}
2023-05-29 15:19:56 +02:00
void qTreeIso::final_segs(const Parameters& parameters, QWidget* parent/*=nullptr*/)
2023-05-04 19:22:59 -06:00
{
// display the progress dialog
2023-05-29 15:19:56 +02:00
QProgressDialog* progressDlg = new QProgressDialog(parent);
progressDlg->setWindowTitle("TreeIso Step 3. Final segmention");
progressDlg->setLabelText(tr("Computing...."));
progressDlg->setCancelButton(nullptr);
progressDlg->setRange(0, 0); // infinite progress bar
progressDlg->show();
if (!TreeIso::Final_seg(parameters.min_nn2, parameters.rel_height_length_ratio, parameters.vertical_weight, m_app, progressDlg))
2023-05-04 19:22:59 -06:00
{
progressDlg->hide();
2023-05-04 19:22:59 -06:00
QApplication::processEvents();
m_app->updateUI();
m_app->refreshAll();
return;
}
progressDlg->close();
2023-05-04 19:22:59 -06:00
QApplication::processEvents();
2023-05-04 19:22:59 -06:00
m_app->updateUI();
m_app->refreshAll();
}
void qTreeIso::registerCommands(ccCommandLineInterface* cmd)
{
if (!cmd)
{
assert(false);
return;
}
cmd->registerCommand(ccCommandLineInterface::Command::Shared(new CommandTreeIso));
}