Wolman + Angles (dip and azimuth) implemented

This commit is contained in:
Paul Leroy
2025-02-28 15:14:18 +01:00
parent 0f8bd0a329
commit 1c3e619fe5
27 changed files with 787 additions and 186 deletions
+6 -1
View File
@@ -11,7 +11,12 @@ if ( PLUGIN_G3POINT )
AddPlugin( NAME ${PROJECT_NAME} )
set(QG3POINT_PLUGIN_VERSION "0.3+")
target_sources(G3PointPlugin
PRIVATE
ui/WolmanCustomPlot.ui
)
set(QG3POINT_PLUGIN_VERSION "0.4")
add_subdirectory( include )
add_subdirectory( src )
Binary file not shown.

After

Width:  |  Height:  |  Size: 471 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 421 B

+44
View File
@@ -0,0 +1,44 @@
#ifndef ANGLESCUSTOMPLOT_H
#define ANGLESCUSTOMPLOT_H
#include <QWidget>
#include <qcustomplot.h>.h>
namespace Ui {
class AnglesCustomPlot;
}
class AnglesCustomPlot : public QCustomPlot
{
public:
explicit AnglesCustomPlot(const QVector<double>& data, const QString& xLabel, int nbBins,
QWidget *parent = nullptr);
~AnglesCustomPlot();
bool computeHistogram(const QVector<double>& data);
void createQCPBars(const QString &xLabel);
void rescale();
void mouseDoubleClickEvent(QMouseEvent *event) override;
QSharedPointer<QCPBarsDataContainer> dataContainer(){return m_bars->data();}
private:
Ui::AnglesCustomPlot *ui;
QVector<double> m_axis;
QVector<double> m_histogram;
QString m_label;
QCPBars* m_bars;
int m_nbBins;
};
#endif // ANGLESCUSTOMPLOT_H
+4 -2
View File
@@ -1,12 +1,14 @@
target_sources( ${PROJECT_NAME}
PRIVATE
${CMAKE_CURRENT_LIST_DIR}/ActionA.h
${CMAKE_CURRENT_LIST_DIR}/G3PointAction.h
${CMAKE_CURRENT_LIST_DIR}/G3Point.h
${CMAKE_CURRENT_LIST_DIR}/G3PointDialog.h
${CMAKE_CURRENT_LIST_DIR}/GrainsAsEllipsoids.h
${CMAKE_CURRENT_LIST_DIR}/qG3PointDisclaimer.h
${CMAKE_CURRENT_LIST_DIR}/G3PointDisclaimer.h
${CMAKE_CURRENT_LIST_DIR}/AnglesCustomPlot.h
${CMAKE_CURRENT_LIST_DIR}/WolmanCustomPlot.h
${CMAKE_CURRENT_LIST_DIR}/G3PointPlots.h
)
target_include_directories( ${PROJECT_NAME}
@@ -11,6 +11,10 @@
#include <GrainsAsEllipsoids.h>
#include <AnglesCustomPlot.h>
#include <G3PointPlots.h>
#pragma once
class ccMainAppInterface;
@@ -36,6 +40,8 @@ public:
bool cluster();
void fit();
void exportResults();
void plots();
void showWolman(const Eigen::ArrayXf& d_sample);
bool wolman();
bool angles();
bool processNewStacks(std::vector<std::vector<int>>& newStacks, int pointCount);
@@ -107,6 +113,8 @@ private:
static std::shared_ptr<G3PointAction> s_g3PointAction;
QSharedPointer<GrainsAsEllipsoids> m_grainsAsEllipsoids;
static std::shared_ptr<G3PointPlots> s_g3PointPlots;
GrainsAsEllipsoids* m_grainsAsEllipsoids;
};
}
+4 -2
View File
@@ -4,7 +4,7 @@
#include <QDialog>
namespace Ui {
class qG3PointDialog;
class G3PointDialog;
}
class G3PointDialog : public QDialog
@@ -43,6 +43,8 @@ public:
double getMinFlatness();
int getNMin();
int getkNN();
int getWolmanNbIter();
int getAnglesNbBins();
double getRadiusFactor();
bool isSteepestSlope();
@@ -73,7 +75,7 @@ signals:
void glPointSize(int size);
private:
Ui::qG3PointDialog *ui;
Ui::G3PointDialog *ui;
};
#endif // QG3POINTDIALOG_H
@@ -1,5 +1,5 @@
#ifndef QG3POINTDISCLAIMER_H
#define QG3POINTDISCLAIMER_H
#ifndef G3POINTDISCLAIMER_H
#define G3POINTDISCLAIMER_H
#include <QDialog>
@@ -9,13 +9,13 @@ namespace Ui {
class G3PointDisclaimer;
}
class qG3PointDisclaimer : public QDialog
class G3PointDisclaimer : public QDialog
{
Q_OBJECT
public:
explicit qG3PointDisclaimer(QWidget *parent = nullptr);
~qG3PointDisclaimer();
explicit G3PointDisclaimer(QWidget *parent = nullptr);
~G3PointDisclaimer();
static bool show(ccMainAppInterface* app);
@@ -26,4 +26,4 @@ private:
Ui::G3PointDisclaimer *ui;
};
#endif // QG3POINTDISCLAIMER_H
#endif // G3POINTDISCLAIMER_H
+37
View File
@@ -0,0 +1,37 @@
#ifndef G3POINTPLOTS_H
#define G3POINTPLOTS_H
#include <QWidget>
#include <qcustomplot.h>
namespace Ui {
class G3PointPlots;
}
class G3PointPlots : public QWidget
{
Q_OBJECT
public:
explicit G3PointPlots(QString title, QWidget *parent = nullptr);
~G3PointPlots();
void readSettings();
void addToTabWidget(QWidget* widget);
template<typename SharedDataContainer>
bool exportToCSV(QString filename, SharedDataContainer container) const;
void onExportToCSV();
void onExportToImage();
void closeEvent(QCloseEvent *event) override;
private:
Ui::G3PointPlots *ui;
};
#endif // G3POINTPLOTS_H
+1
View File
@@ -34,6 +34,7 @@ public:
GrainsAsEllipsoids(ccMainAppInterface *app);
GrainsAsEllipsoids(ccPointCloud *cloud, ccMainAppInterface* app, const std::vector<std::vector<int> >& stacks, const RGBAColorsTableType& colors);
~GrainsAsEllipsoids();
//! Set the path for shaders
void setShaderPath();
+61 -5
View File
@@ -1,21 +1,77 @@
#ifndef WOLMANCUSTOMPLOT_H
#define WOLMANCUSTOMPLOT_H
#include <QWidget>
#include <qcustomplot.h>
// Eigen
#include <Eigen/Geometry>
namespace Ui {
class WolmanCustomPlot;
}
class WolmanCustomPlot : public QCustomPlot
//! QCustomPlot: vertical bar with text along side
class QCPBarsWithText : public QCPBars
{
Q_OBJECT
public:
explicit WolmanCustomPlot(QWidget *parent = nullptr);
~WolmanCustomPlot();
QCPBarsWithText(QCPAxis* keyAxis, QCPAxis* valueAxis) : QCPBars(keyAxis,valueAxis), m_textOnTheLeft(false) {}
void setText(QString text) { m_text = QStringList(text); }
void appendText(QString text) { m_text.append(text); }
void setTextAlignment(bool left) { m_textOnTheLeft = left; }
protected:
QStringList m_text;
bool m_textOnTheLeft;
// reimplemented virtual draw method
virtual void draw(QCPPainter *painter)
{
if (!mKeyAxis || !mValueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
//switch to standard display
QCPBars::draw(painter);
int fontHeight = painter->fontMetrics().height();
if (!data()->isEmpty())
{
double& key = data()->begin()->key;
double& value = data()->begin()->value;
QPointF P = coordsToPixels(key, value);
//apply a small shift
int margin = 5; //in pixels
if (m_textOnTheLeft)
margin = -margin;
P.setX(P.x() + margin);
//we draw at the 'base' line
P.setY(P.y() + fontHeight);
for (int i=0; i<m_text.size(); ++i)
{
QPointF Pstart = P;
if (m_textOnTheLeft)
Pstart.setX(P.x() - painter->fontMetrics().width(m_text[i]));
painter->drawText(Pstart,m_text[i]);
P.setY(P.y() + fontHeight);
}
}
}
};
class WolmanCustomPlot : public QWidget
{
public:
WolmanCustomPlot(const Eigen::ArrayXf& d_sample);
QSharedPointer<QCPGraphDataContainer> dataContainer(){return m_graph->data();}
QCPGraph* m_graph;
private:
Ui::WolmanCustomPlot *ui;
+2
View File
@@ -2,5 +2,7 @@
<qresource prefix="/CC/plugin/G3PointPlugin">
<file>info.json</file>
<file>images/icon.png</file>
<file>images/smallCSVFile.png</file>
<file>images/dbImageSymbol.png</file>
</qresource>
</RCC>
+131
View File
@@ -0,0 +1,131 @@
#include "AnglesCustomPlot.h"
#include "ui_AnglesCustomPlot.h"
#include <ScalarField.h>
#include <ccLog.h>
AnglesCustomPlot::AnglesCustomPlot(const QVector<double> &data, const QString &xLabel, int nbBins, QWidget *parent):
ui(new Ui::AnglesCustomPlot),
m_label(xLabel),
m_bars(nullptr),
m_nbBins(nbBins)
{
setProperty("TypeOfCustomPlot", "AnglesCustomPlot");
ui->setupUi(this);
setWindowTitle(m_label);
computeHistogram(data);
createQCPBars(m_label + " [°]");
m_bars->rescaleAxes();
}
AnglesCustomPlot::~AnglesCustomPlot()
{
delete ui;
}
//! Default number of classes for associated histogram
static const unsigned MAX_HISTOGRAM_SIZE = 512;
bool AnglesCustomPlot::computeHistogram(const QVector<double>& data)
{
double minData = *std::min_element(data.begin(), data.end());
double maxData = *std::max_element(data.begin(), data.end());
double range = maxData - minData;
if (range == 0 || data.size() == 0)
{
//can't build histogram of a flat field
return false;
}
else
{
unsigned count = data.size();
unsigned numberOfBins;
if (m_nbBins == -1) // compute number of bins automatically
{
numberOfBins = static_cast<unsigned>(ceil(sqrt(static_cast<double>(count))));
numberOfBins = std::max<unsigned>(std::min<unsigned>(numberOfBins, MAX_HISTOGRAM_SIZE), 4);
}
else // use number of bins
{
numberOfBins = m_nbBins;
}
m_axis.resize(numberOfBins);
for (unsigned i = 0; i < numberOfBins; i++)
{
m_axis[i] = minData + i * range / numberOfBins;
}
//reserve memory
try
{
m_histogram.resize(numberOfBins);
}
catch (const std::bad_alloc&)
{
ccLog::Warning("[computeHistogram] Failed to allocate histogram!");
}
std::fill(m_histogram.begin(), m_histogram.end(), 0);
//compute histogram
ScalarType step = static_cast<ScalarType>(numberOfBins) / range;
for (unsigned i = 0; i < count; ++i)
{
const ScalarType& val = data[i];
if (CCCoreLib::ScalarField::ValidValue(val))
{
unsigned bin = static_cast<unsigned>((val - minData) * step);
++m_histogram[std::min(bin, numberOfBins - 1)];
}
}
}
return true;
}
void AnglesCustomPlot::createQCPBars(const QString& xLabel)
{
//clear previous display
if (m_bars)
{
this->removePlottable(m_bars);
m_bars = nullptr;
}
m_bars = new QCPBars(xAxis, yAxis);
m_bars->setAntialiased(false); // gives more crisp, pixel aligned bar borders
m_bars->setPen(QPen(QColor(0, 168, 140).lighter(130)));
m_bars->setBrush(QColor(0, 168, 140));
m_bars->setWidth(m_axis[1] - m_axis[0]);
m_bars->setData(m_axis, m_histogram);
xAxis->setLabel(xLabel);
yAxis->setLabel("Counts");
setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);
}
void AnglesCustomPlot::rescale()
{
// set ranges appropriate to show data
if (m_bars)
{
m_bars->rescaleAxes();
replot();
}
}
void AnglesCustomPlot::mouseDoubleClickEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton)
{
rescale();
}
QCustomPlot::mouseDoubleClickEvent(event);
}
+4 -2
View File
@@ -1,10 +1,12 @@
target_sources( ${PROJECT_NAME}
PRIVATE
${CMAKE_CURRENT_LIST_DIR}/ActionA.cpp
${CMAKE_CURRENT_LIST_DIR}/G3PointAction.cpp
${CMAKE_CURRENT_LIST_DIR}/G3Point.cpp
${CMAKE_CURRENT_LIST_DIR}/G3PointDialog.cpp
${CMAKE_CURRENT_LIST_DIR}/GrainsAsEllipsoids.cpp
${CMAKE_CURRENT_LIST_DIR}/qG3PointDisclaimer.cpp
${CMAKE_CURRENT_LIST_DIR}/G3PointDisclaimer.cpp
${CMAKE_CURRENT_LIST_DIR}/AnglesCustomPlot.cpp
${CMAKE_CURRENT_LIST_DIR}/WolmanCustomPlot.cpp
${CMAKE_CURRENT_LIST_DIR}/G3PointPlots.cpp
)
+1 -1
View File
@@ -35,7 +35,7 @@
#include "G3Point.h"
#include "ActionA.h"
#include "G3PointAction.h"
ccHObject* G3PointFactory::buildObject(const QString& metaName)
{
+52 -126
View File
@@ -1,4 +1,4 @@
#include "ActionA.h"
#include "G3PointAction.h"
// CCPluginAPI
#include <ccMainAppInterface.h>
@@ -42,13 +42,15 @@
#include <set>
#include <G3PointDialog.h>
#include <qG3PointDisclaimer.h>
#include <G3PointDisclaimer.h>
#include <WolmanCustomPlot.h>
namespace G3Point
{
std::shared_ptr<G3PointAction> G3PointAction::s_g3PointAction;
std::shared_ptr<G3PointPlots> G3PointAction::s_g3PointPlots;
G3PointAction::G3PointAction(ccPointCloud *cloud, ccMainAppInterface *app)
: m_app(app)
, m_dlg(nullptr)
@@ -71,9 +73,11 @@ G3PointAction::~G3PointAction()
void G3PointAction::GetG3PointAction(ccPointCloud *cloud, ccMainAppInterface *app)
{
//disclaimer accepted?
if (!qG3PointDisclaimer::show(app))
if (!G3PointDisclaimer::show(app))
return;
s_g3PointPlots.reset(new G3PointPlots(cloud->getName()));
if (!s_g3PointAction) // create the singleton if needed
{
s_g3PointAction.reset(new G3PointAction(cloud, app));
@@ -613,8 +617,12 @@ bool G3PointAction::exportLocalMaximaAsCloud(const Eigen::ArrayXi& localMaximumI
m_app->removeFromDB(child, true);
}
parent->addChild(cloud, ccHObject::DP_PARENT_OF_OTHER, 0);
// parent->addChild(cloud, ccHObject::DP_PARENT_OF_OTHER, 0);
// m_app->addToDB(cloud);
m_cloud->addChild(cloud);
m_app->addToDB(cloud);
cloud->setEnabled(false);
return true;
@@ -1008,24 +1016,26 @@ void G3PointAction::fit()
// plot display grains as ellipsoids
m_grainColors.reset(new RGBAColorsTableType(getRandomColors(m_localMaximumIndexes.size())));
m_grainsAsEllipsoids.reset(new GrainsAsEllipsoids(m_cloud, m_app, m_stacks, *m_grainColors));
m_grainsAsEllipsoids = new GrainsAsEllipsoids(m_cloud, m_app, m_stacks, *m_grainColors);
m_grainsAsEllipsoids->setName("g3point_ellipsoids");
// add connections with the dialog
connect(m_dlg, &G3PointDialog::onlyOneClicked, m_grainsAsEllipsoids.data(), &GrainsAsEllipsoids::showOnlyOne);
connect(m_dlg, &G3PointDialog::allClicked, m_grainsAsEllipsoids.data(), &GrainsAsEllipsoids::showAll);
connect(m_dlg, &G3PointDialog::onlyOneChanged, m_grainsAsEllipsoids.data(), &GrainsAsEllipsoids::setOnlyOne);
connect(m_dlg, &G3PointDialog::transparencyChanged, m_grainsAsEllipsoids.data(), &GrainsAsEllipsoids::setTransparency);
connect(m_dlg, &G3PointDialog::drawSurfaces, m_grainsAsEllipsoids.data(), &GrainsAsEllipsoids::drawSurfaces);
connect(m_dlg, &G3PointDialog::drawLines, m_grainsAsEllipsoids.data(), &GrainsAsEllipsoids::drawLines);
connect(m_dlg, &G3PointDialog::drawPoints, m_grainsAsEllipsoids.data(), &GrainsAsEllipsoids::drawPoints);
connect(m_dlg, &G3PointDialog::glPointSize, m_grainsAsEllipsoids.data(), &GrainsAsEllipsoids::setGLPointSize);
connect(m_dlg, &G3PointDialog::onlyOneClicked, m_grainsAsEllipsoids, &GrainsAsEllipsoids::showOnlyOne);
connect(m_dlg, &G3PointDialog::allClicked, m_grainsAsEllipsoids, &GrainsAsEllipsoids::showAll);
connect(m_dlg, &G3PointDialog::onlyOneChanged, m_grainsAsEllipsoids, &GrainsAsEllipsoids::setOnlyOne);
connect(m_dlg, &G3PointDialog::transparencyChanged, m_grainsAsEllipsoids, &GrainsAsEllipsoids::setTransparency);
connect(m_dlg, &G3PointDialog::drawSurfaces, m_grainsAsEllipsoids, &GrainsAsEllipsoids::drawSurfaces);
connect(m_dlg, &G3PointDialog::drawLines, m_grainsAsEllipsoids, &GrainsAsEllipsoids::drawLines);
connect(m_dlg, &G3PointDialog::drawPoints, m_grainsAsEllipsoids, &GrainsAsEllipsoids::drawPoints);
connect(m_dlg, &G3PointDialog::glPointSize, m_grainsAsEllipsoids, &GrainsAsEllipsoids::setGLPointSize);
m_dlg->setOnlyOneMax(m_stacks.size());
m_dlg->emitSignals(); // force to send parameters to m_grainsAsEllipsoids
m_cloud->getParent()->addChild(m_grainsAsEllipsoids.data());
m_app->addToDB(m_cloud);
// m_cloud->getParent()->addChild(m_grainsAsEllipsoids.get());
// m_app->addToDB(m_cloud);
m_cloud->addChild(m_grainsAsEllipsoids);
m_app->addToDB(m_grainsAsEllipsoids);
m_app->updateUI();
}
@@ -1084,33 +1094,25 @@ double std_dev(const T &vec)
return std::sqrt((vec - vec.mean()).square().sum() / (vec.size() - 1));
}
void showWolman(const Eigen::ArrayXf& d_sample)
void G3PointAction::plots()
{
angles();
}
void G3PointAction::showWolman(const Eigen::ArrayXf& d_sample)
{
// QCustomPlot
WolmanCustomPlot* wolmanCustomPlot = new WolmanCustomPlot();
QCPGraph* graph = wolmanCustomPlot->addGraph();
QVector<double> x_data(d_sample.size());
QVector<double> y_data(d_sample.size());
for (int k = 0; k < d_sample.size(); k++)
{
x_data[k] = d_sample(k);
y_data[k] = (static_cast<double>(k)) / static_cast<double>(d_sample.size());
}
std::sort(x_data.begin(), x_data.end());
graph->setData(x_data, y_data);
graph->rescaleAxes();
// give the axes some labels:
wolmanCustomPlot->xAxis->setScaleType(QCPAxis::stLogarithmic);
wolmanCustomPlot->xAxis->setLabel("Diameter [mm]");
wolmanCustomPlot->yAxis->setLabel("CDF");
wolmanCustomPlot->show();
if (!s_g3PointPlots)
s_g3PointPlots.reset(new G3PointPlots(m_cloud->getName()));
s_g3PointPlots->addToTabWidget(new WolmanCustomPlot(d_sample));
s_g3PointPlots->show();
}
bool G3PointAction::wolman()
{
int n_iter = 10;
int n_iter = m_dlg->getWolmanNbIter();
if (m_grainsAsEllipsoids.isNull())
if (!m_grainsAsEllipsoids)
{
ccLog::Error("[G3PointAction::wolman] no ellipsoid, not possible to do Wolman analysis");
return false;
@@ -1169,7 +1171,7 @@ bool G3PointAction::wolman()
{
float r0 = dist(urbg);
float r1 = dist(urbg);
std::cout << r0 << ", " << r1 << "," << std::endl;
// std::cout << r0 << ", " << r1 << "," << std::endl;
x_grid = arange(x.minCoeff() - r0 * dx, x.maxCoeff(), dx);
y_grid = arange(y.minCoeff() - r1 * dx, y.maxCoeff(), dx);
int nx = x_grid.size();
@@ -1246,93 +1248,20 @@ bool G3PointAction::wolman()
return true;
}
//! Default number of classes for associated histogram
static const unsigned MAX_HISTOGRAM_SIZE = 512;
bool computeHistogram(const QVector<double>& data, QVector<double>& axis, QVector<double>& histogram)
{
double minData = *std::min_element(data.begin(), data.end());
double maxData = *std::max_element(data.begin(), data.end());
double range = maxData - minData;
if (range == 0 || data.size() == 0)
{
//can't build histogram of a flat field
return false;
}
else
{
unsigned count = data.size();
unsigned numberOfBins = static_cast<unsigned>(ceil(sqrt(static_cast<double>(count))));
// numberOfBins = std::max<unsigned>(std::min<unsigned>(numberOfBins, MAX_HISTOGRAM_SIZE), 4);
numberOfBins = 10;
axis.resize(numberOfBins);
for (int i = 0; i < numberOfBins; i++)
{
axis[i] = minData + i * range / numberOfBins;
}
//reserve memory
try
{
histogram.resize(numberOfBins);
}
catch (const std::bad_alloc&)
{
ccLog::Warning("[computeHistogram] Failed to allocate histogram!");
}
std::fill(histogram.begin(), histogram.end(), 0);
//compute histogram
ScalarType step = static_cast<ScalarType>(numberOfBins) / range;
for (unsigned i = 0; i < count; ++i)
{
const ScalarType& val = data[i];
if (CCCoreLib::ScalarField::ValidValue(val))
{
unsigned bin = static_cast<unsigned>((val - minData) * step);
++histogram[std::min(bin, numberOfBins - 1)];
}
}
}
return true;
}
void showHistogram(const QVector<double>& data)
{
// QCustomPlot
WolmanCustomPlot* anglesCustomPlot = new WolmanCustomPlot();
QVector<double> axis;
QVector<double> histogram;
computeHistogram(data, axis, histogram);
QCPBars *regen = new QCPBars(anglesCustomPlot->xAxis, anglesCustomPlot->yAxis);
regen->setData(axis, histogram);
regen->rescaleAxes();
regen->setPen(QPen(QColor(0, 168, 140).lighter(130)));
regen->setBrush(QColor(0, 168, 140));
anglesCustomPlot->xAxis->setLabel("Azimut [°]");
anglesCustomPlot->yAxis->setLabel("Counts");
anglesCustomPlot->show();
}
bool G3PointAction::angles()
{
if (m_grainsAsEllipsoids.isNull())
if (!m_grainsAsEllipsoids)
{
ccLog::Error("[G3PointAction::angles] no ellipsoid, not possible to do angles analysis");
return false;
}
float delta = 1e32;
int n_ellipsoids = m_grainsAsEllipsoids->m_rotationMatrix.size();
size_t n_ellipsoids = m_grainsAsEllipsoids->m_rotationMatrix.size();
QVector<double> granuloAngleMView(n_ellipsoids);
QVector<double> granuloAngleXView(n_ellipsoids);
for (int i = 0; i < n_ellipsoids; i++)
for (size_t i = 0; i < n_ellipsoids; i++)
{
float u, v, w;
@@ -1370,18 +1299,12 @@ bool G3PointAction::angles()
}
// QCustomPlot
WolmanCustomPlot* anglesCustomPlot = new WolmanCustomPlot();
QVector<double> axis;
QVector<double> histogram;
computeHistogram(granuloAngleMView, axis, histogram);
QCPBars *regen = new QCPBars(anglesCustomPlot->xAxis, anglesCustomPlot->yAxis);
regen->setData(axis, histogram);
regen->rescaleAxes();
regen->setPen(QPen(QColor(0, 168, 140).lighter(130)));
regen->setBrush(QColor(0, 168, 140));
anglesCustomPlot->xAxis->setLabel("Azimut [°]");
anglesCustomPlot->yAxis->setLabel("Counts");
anglesCustomPlot->show();
if (!s_g3PointPlots)
s_g3PointPlots.reset(new G3PointPlots(m_cloud->getName()));
int nbBins = m_dlg->getAnglesNbBins();
s_g3PointPlots->addToTabWidget(new AnglesCustomPlot(granuloAngleMView, "Azimut", nbBins));
s_g3PointPlots->addToTabWidget(new AnglesCustomPlot(granuloAngleXView, "Dip", nbBins));
s_g3PointPlots->show();
return true;
}
@@ -2017,7 +1940,7 @@ void G3PointAction::showDlg()
connect(m_dlg, &G3PointDialog::fit, s_g3PointAction.get(), &G3Point::G3PointAction::fit);
connect(m_dlg, &G3PointDialog::exportResults, s_g3PointAction.get(), &G3Point::G3PointAction::exportResults);
connect(m_dlg, &G3PointDialog::wolman, s_g3PointAction.get(), &G3Point::G3PointAction::wolman);
connect(m_dlg, &G3PointDialog::angles, s_g3PointAction.get(), &G3Point::G3PointAction::angles);
connect(m_dlg, &G3PointDialog::angles, s_g3PointAction.get(), &G3Point::G3PointAction::plots);
connect(m_dlg, &QDialog::finished, s_g3PointAction.get(), &G3Point::G3PointAction::clean);
connect(m_dlg, &QDialog::finished, s_g3PointAction.get(), &G3Point::G3PointAction::resetDlg); // dialog is defined with Qt::WA_DeleteOnClose
@@ -2116,7 +2039,11 @@ bool G3PointAction::setCloud(ccPointCloud *cloud)
+ QString::number(nPointsInGrains) + "/" + QString::number(cloud->size())
+ " points belonging to " + QString::number(newStacks.size()) + " grains");
std::cout << "[d] processNewStacks" << std::endl;
processNewStacks(newStacks, nPointsInGrains);
std::cout << "[e]" << std::endl;
}
return true;
@@ -2125,7 +2052,6 @@ bool G3PointAction::setCloud(ccPointCloud *cloud)
void G3PointAction::setKNN()
{
m_kNN = m_dlg->getkNN();
std::cout << "kNN " << m_kNN << std::endl;
}
void G3PointAction::createAction(ccMainAppInterface *appInterface)
+29 -2
View File
@@ -1,11 +1,11 @@
#include "G3PointDialog.h"
#include "ui_qG3PointDialog.h"
#include "ui_G3PointDialog.h"
#include <QSettings>
G3PointDialog::G3PointDialog(QString cloudName, QWidget *parent)
: QDialog(parent)
, ui(new Ui::qG3PointDialog)
, ui(new Ui::G3PointDialog)
{
ui->setupUi(this);
@@ -54,6 +54,12 @@ void G3PointDialog::readSettings()
// max angle 1
double maxAngle1 = settings.value("maxAngle1", 60).toDouble();
this->ui->doubleSpinBoxRadiusFactor->setValue(maxAngle1);
// wolmanNbIter
int wolmanNbIter = settings.value("wolmanNbIter", 20).toInt();
this->ui->spinBoxWolmanNbIter->setValue(wolmanNbIter);
// anglesNbBins
int anglesNbBins = settings.value("anglesNbBins", 10).toInt();
this->ui->spinBoxAnglesNbBins->setValue(anglesNbBins);
}
void G3PointDialog::writeSettings()
@@ -67,6 +73,10 @@ void G3PointDialog::writeSettings()
settings.setValue("radiusFactor", ui->doubleSpinBoxRadiusFactor->value());
// max angle 1
settings.setValue("maxAngle1", ui->doubleSpinBoxMaxAngle1->value());
// wolmanNbIter
settings.setValue("wolmanNbIter", ui->spinBoxWolmanNbIter->value());
// anglesNbBins
settings.setValue("anglesNbBins", ui->spinBoxAnglesNbBins->value());
}
double G3PointDialog::getMaxAngle1()
@@ -94,6 +104,23 @@ int G3PointDialog::getkNN()
return this->ui->spinBoxkNN->value();
}
int G3PointDialog::getWolmanNbIter()
{
return this->ui->spinBoxWolmanNbIter->value();
}
int G3PointDialog::getAnglesNbBins()
{
if (this->ui->radioButtonAutoNbBins->isChecked())
{
return -1;
}
else
{
return this->ui->spinBoxAnglesNbBins->value();
}
}
double G3PointDialog::getRadiusFactor()
{
return ui->doubleSpinBoxRadiusFactor->value();
@@ -1,5 +1,5 @@
#include "qG3PointDisclaimer.h"
#include "ui_qG3PointDisclaimer.h"
#include "G3PointDisclaimer.h"
#include "ui_G3PointDisclaimer.h"
//qCC_plugins
#include <ccMainAppInterface.h>
@@ -7,9 +7,9 @@
//Qt
#include <QMainWindow>
bool qG3PointDisclaimer::s_disclaimerAccepted = false;
bool G3PointDisclaimer::s_disclaimerAccepted = false;
qG3PointDisclaimer::qG3PointDisclaimer(QWidget *parent)
G3PointDisclaimer::G3PointDisclaimer(QWidget *parent)
: QDialog(parent)
, ui(new Ui::G3PointDisclaimer)
{
@@ -34,17 +34,17 @@ qG3PointDisclaimer::qG3PointDisclaimer(QWidget *parent)
ui->labelCompilationInformation->setText(compilationInfo);
}
qG3PointDisclaimer::~qG3PointDisclaimer()
G3PointDisclaimer::~G3PointDisclaimer()
{
delete ui;
}
bool qG3PointDisclaimer::show(ccMainAppInterface *app)
bool G3PointDisclaimer::show(ccMainAppInterface *app)
{
if ( !s_disclaimerAccepted )
{
//if the user "cancels" it, then he refuses the disclaimer
s_disclaimerAccepted = qG3PointDisclaimer(app ? app->getMainWindow() : 0).exec();
s_disclaimerAccepted = G3PointDisclaimer(app ? app->getMainWindow() : 0).exec();
}
return s_disclaimerAccepted;
+166
View File
@@ -0,0 +1,166 @@
#include "G3PointPlots.h"
#include "ui_G3PointPlots.h"
// CCPluginAPI
#include <ccPersistentSettings.h>
/// qCC_db
#include <ccFileUtils.h>
// qcc_io
#include <ImageFileFilter.h>
#include <QTextStream>
#include <QSettings>
#include <AnglesCustomPlot.h>
#include <WolmanCustomPlot.h>
G3PointPlots::G3PointPlots(QString title, QWidget *parent)
: QWidget(parent)
, ui(new Ui::G3PointPlots)
{
ui->setupUi(this);
readSettings();
setWindowTitle(title);
connect(this->ui->exportCSVToolButton, &QToolButton::clicked, this, &G3PointPlots::onExportToCSV);
connect(this->ui->exportImage, &QToolButton::clicked, this, &G3PointPlots::onExportToImage);
}
G3PointPlots::~G3PointPlots()
{
delete ui;
}
void G3PointPlots::closeEvent(QCloseEvent *event)
{
QSettings settings("OSERen", "qG3Point");
settings.setValue("G3PointPlots/geometry", saveGeometry());
// settings.setValue("windowState", saveState());
QWidget::closeEvent(event);
}
void G3PointPlots::readSettings()
{
QSettings settings("OSERen", "qG3Point");
restoreGeometry(settings.value("G3PointPlots/geometry").toByteArray());
}
void G3PointPlots::addToTabWidget(QWidget* widget)
{
this->ui->tabWidget->addTab(widget, widget->windowTitle());
this->ui->tabWidget->setCurrentWidget(widget);
}
template<typename SharedDataContainer>
bool G3PointPlots::exportToCSV(QString filename, SharedDataContainer container) const
{
QFile file(filename);
if (!file.open(QFile::WriteOnly | QFile::Text))
{
ccLog::Warning(QString("[SF/SF] Failed to save plot to file '%1'").arg(filename));
return false;
}
QTextStream stream(&file);
stream.setRealNumberPrecision(12);
stream.setRealNumberNotation(QTextStream::FixedNotation);
//header
stream << "angle [°], counts" << endl;
//data
{
for (auto item : *container)
{
stream << item.key << " " << item.value << endl;
}
}
file.close();
ccLog::Print(QString("[SF/SF] File '%1' saved").arg(filename));
return true;
}
typedef QSharedPointer<QCPBarsDataContainer> SharedBarsDataContainer;
typedef QSharedPointer<QCPGraphDataContainer> SharedGraphDataContainer;
void G3PointPlots::onExportToCSV()
{
// get current tab widget
QWidget* currentWidget = this->ui->tabWidget->currentWidget();
//persistent settings
QSettings settings;
settings.beginGroup(ccPS::SaveFile());
QString currentPath = settings.value(ccPS::CurrentPath(), ccFileUtils::defaultDocPath()).toString();
currentPath += QString("/") + currentWidget->windowTitle() + ".csv";
//ask for a filename
QString filename = QFileDialog::getSaveFileName(this, "Select output file", currentPath, "*.csv");
if (filename.isEmpty())
{
//process cancelled by user
return;
}
//save last saving location
settings.setValue(ccPS::CurrentPath(), QFileInfo(filename).absolutePath());
settings.endGroup();
if (currentWidget->property("TypeOfCustomPlot").toString() == "AnglesCustomPlot")
{
exportToCSV<SharedBarsDataContainer>(filename,
static_cast<AnglesCustomPlot*>(currentWidget)->dataContainer());
}
else if (currentWidget->property("TypeOfCustomPlot").toString() == "WolmanCustomPlot")
{
exportToCSV<SharedGraphDataContainer>(filename,
static_cast<WolmanCustomPlot*>(currentWidget)->dataContainer());
}
}
void G3PointPlots::onExportToImage()
{
QWidget* currentWidget = this->ui->tabWidget->currentWidget();
//persistent settings
QSettings settings;
settings.beginGroup(ccPS::SaveFile());
QString currentPath = settings.value(ccPS::CurrentPath(), ccFileUtils::defaultDocPath()).toString();
QString outputFilename = ImageFileFilter::GetSaveFilename("Select output file",
currentWidget->windowTitle(),
currentPath,
this);
if (outputFilename.isEmpty())
{
//process cancelled by user (or error)
return;
}
//save current export path to persistent settings
settings.setValue(ccPS::CurrentPath(), QFileInfo(outputFilename).absolutePath());
settings.endGroup();
//save the widget as an image file
QPixmap image = currentWidget->grab();
if (image.save(outputFilename))
{
ccLog::Print(QString("[SF/SF] Image '%1' successfully saved").arg(outputFilename));
}
else
{
ccLog::Error(QString("Failed to save file '%1'").arg(outputFilename));
}
}
+6 -2
View File
@@ -12,7 +12,7 @@
#include <iostream>
#include <fstream>
#include <ActionA.h>
#include <G3PointAction.h>
// from GeometricTools/GTE
// #include <Mathematics/DistPointHyperellipsoid.h>
@@ -30,6 +30,8 @@ GrainsAsEllipsoids::GrainsAsEllipsoids(ccMainAppInterface *app)
setShaderPath();
}
GrainsAsEllipsoids::~GrainsAsEllipsoids(){}
GrainsAsEllipsoids::GrainsAsEllipsoids(ccPointCloud *cloud, ccMainAppInterface *app, const std::vector<std::vector<int> >& stacks, const RGBAColorsTableType& colors)
: m_cloud(cloud)
, m_app(app)
@@ -237,7 +239,9 @@ bool GrainsAsEllipsoids::exportResultsAsCloud()
cloud->showColors(true);
cloud->setPointSize(9);
m_cloud->getParent()->addChild(cloud, ccHObject::DP_PARENT_OF_OTHER, 0);
// m_cloud->getParent()->addChild(cloud, ccHObject::DP_PARENT_OF_OTHER, 0);
// m_app->addToDB(cloud);
m_cloud->addChild(cloud);
m_app->addToDB(cloud);
return true;
+21 -6
View File
@@ -1,13 +1,28 @@
#include "WolmanCustomPlot.h"
#include "ui_WolmanCustomPlot.h"
WolmanCustomPlot::WolmanCustomPlot(QWidget *parent):
WolmanCustomPlot::WolmanCustomPlot(const Eigen::ArrayXf &d_sample):
ui(new Ui::WolmanCustomPlot)
{
ui->setupUi(this);
}
setProperty("TypeOfCustomPlot", "WolmanCustomPlot");
WolmanCustomPlot::~WolmanCustomPlot()
{
delete ui;
ui->setupUi(this);
setWindowTitle("Wolman");
m_graph = this->ui->customPlot->addGraph();
QVector<double> x_data(d_sample.size());
QVector<double> y_data(d_sample.size());
for (int k = 0; k < d_sample.size(); k++)
{
x_data[k] = d_sample(k);
y_data[k] = (static_cast<double>(k)) / static_cast<double>(d_sample.size());
}
std::sort(x_data.begin(), x_data.end());
m_graph->setData(x_data, y_data);
m_graph->rescaleAxes();
// give the axes some labels:
this->ui->customPlot->xAxis->setScaleType(QCPAxis::stLogarithmic);
this->ui->customPlot->xAxis->setLabel("Diameter [mm]");
this->ui->customPlot->yAxis->setLabel("CDF");
}
+19
View File
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AnglesCustomPlot</class>
<widget class="QWidget" name="AnglesCustomPlot">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
</widget>
<resources/>
<connections/>
</ui>
+4 -3
View File
@@ -1,6 +1,7 @@
target_sources( ${PROJECT_NAME}
PRIVATE
${CMAKE_CURRENT_LIST_DIR}/qG3PointDialog.ui
${CMAKE_CURRENT_LIST_DIR}/qG3PointDisclaimer.ui
${CMAKE_CURRENT_LIST_DIR}/WolmanCustomPlot.ui
${CMAKE_CURRENT_LIST_DIR}/G3PointDialog.ui
${CMAKE_CURRENT_LIST_DIR}/G3PointDisclaimer.ui
${CMAKE_CURRENT_LIST_DIR}/AnglesCustomPlot.ui
${CMAKE_CURRENT_LIST_DIR}/G3PointPlots.ui
)
+91 -20
View File
@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>qG3PointDialog</class>
<widget class="QDialog" name="qG3PointDialog">
<class>G3PointDialog</class>
<widget class="QDialog" name="G3PointDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>357</width>
<width>384</width>
<height>608</height>
</rect>
</property>
@@ -347,24 +347,95 @@
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButtonExportResults">
<property name="text">
<string>Export results</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButtonWolman">
<property name="text">
<string>Wolman</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButtonAngles">
<property name="text">
<string>Angles</string>
<widget class="QGroupBox" name="groupBox_6">
<property name="title">
<string>Outputs</string>
</property>
<layout class="QGridLayout" name="gridLayout" columnstretch="1,0,0,0,0,0">
<item row="3" column="0" colspan="6">
<widget class="QPushButton" name="pushButtonExportResults">
<property name="text">
<string>Export results as a cloud</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QPushButton" name="pushButtonAngles">
<property name="text">
<string>Angles</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QLabel" name="label_8">
<property name="font">
<font>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>Nb bins:</string>
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QRadioButton" name="radioButtonAutoNbBins">
<property name="text">
<string>Auto</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="4">
<widget class="QRadioButton" name="radioButtonFixNbBins">
<property name="text">
<string>Fix</string>
</property>
</widget>
</item>
<item row="2" column="5">
<widget class="QSpinBox" name="spinBoxAnglesNbBins">
<property name="buttonSymbols">
<enum>QAbstractSpinBox::ButtonSymbols::NoButtons</enum>
</property>
<property name="minimum">
<number>10</number>
</property>
<property name="maximum">
<number>512</number>
</property>
</widget>
</item>
<item row="1" column="5">
<widget class="QSpinBox" name="spinBoxWolmanNbIter">
<property name="buttonSymbols">
<enum>QAbstractSpinBox::ButtonSymbols::NoButtons</enum>
</property>
<property name="minimum">
<number>3</number>
</property>
<property name="maximum">
<number>1000000</number>
</property>
</widget>
</item>
<item row="1" column="4">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Nb iterations</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="4">
<widget class="QPushButton" name="pushButtonWolman">
<property name="text">
<string>Wolman</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
+69
View File
@@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>G3PointPlots</class>
<widget class="QWidget" name="G3PointPlots">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>751</width>
<height>641</height>
</rect>
</property>
<property name="windowTitle">
<string>G3Point plots</string>
</property>
<layout class="QGridLayout" name="gridLayout" rowstretch="1,0" columnstretch="1,0">
<item row="0" column="0" rowspan="2">
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>-1</number>
</property>
</widget>
</item>
<item row="0" column="1">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QToolButton" name="exportCSVToolButton">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../qG3POINT.qrc">
<normaloff>:/CC/plugin/G3PointPlugin/images/smallCSVFile.png</normaloff>:/CC/plugin/G3PointPlugin/images/smallCSVFile.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="exportImage">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../qG3POINT.qrc">
<normaloff>:/CC/plugin/G3PointPlugin/images/dbImageSymbol.png</normaloff>:/CC/plugin/G3PointPlugin/images/dbImageSymbol.png</iconset>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="1">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>560</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources>
<include location="../qG3POINT.qrc"/>
</resources>
<connections/>
</ui>
+13
View File
@@ -13,7 +13,20 @@
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout" rowstretch="1">
<item row="0" column="0" colspan="2">
<widget class="QCustomPlot" name="customPlot" native="true"/>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>QCustomPlot</class>
<extends>QWidget</extends>
<header>qcustomplot.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>