abort handled properly in eigensolver, ui improvements + ellipsoidDistance implementation
Use of Geometric Tools Engine for ellipsoidDistance computation
This commit is contained in:
@@ -21,6 +21,7 @@ if ( PLUGIN_G3POINT )
|
||||
C:/opt/eigen-3.4.0
|
||||
C:/Users/PaulLeroy/miniconda3/envs/env_4_CloudCompare/include
|
||||
C:/opt/open3d-devel-windows-amd64-0.18.0/include
|
||||
C:/opt/GeometricTools/GTE
|
||||
)
|
||||
|
||||
# Find installed Open3D, which exports Open3D::Open3D
|
||||
|
||||
@@ -34,6 +34,7 @@ public:
|
||||
void segmentAndClusterAndClean();
|
||||
void getBorders();
|
||||
int cluster();
|
||||
void fit();
|
||||
bool processNewStacks(std::vector<std::vector<int>>& stacks, int pointCount);
|
||||
bool merge(XXb& condition);
|
||||
bool keep(Xb& condition);
|
||||
|
||||
@@ -22,6 +22,14 @@ public:
|
||||
void emitSegmentClusterClean(){emit segmentClusterClean();}
|
||||
void emitGetBorders(){emit getBorders();}
|
||||
|
||||
void emitAllClicked(bool state){emit allClicked(state);}
|
||||
void emitOnlyOneClicked(bool state){emit onlyOneClicked(state);}
|
||||
void emitOnlyOneChanged(int idx){emit onlyOneChanged(idx);}
|
||||
void emitFit(){emit fit();}
|
||||
void emitTransparencyChanged(double transparency){emit transparencyChanged(transparency);}
|
||||
|
||||
void emitSignals();
|
||||
|
||||
double getMaxAngle1();
|
||||
double getMaxAngle2();
|
||||
double getMinFlatness();
|
||||
@@ -34,6 +42,8 @@ public:
|
||||
void enableCluster(bool state);
|
||||
void enableClean(bool state);
|
||||
|
||||
void setOnlyOneMax(int idx);
|
||||
|
||||
signals:
|
||||
void segment();
|
||||
void cluster();
|
||||
@@ -42,6 +52,13 @@ signals:
|
||||
void segmentClusterClean();
|
||||
void getBorders();
|
||||
|
||||
void allClicked(bool state);
|
||||
void onlyOneClicked(bool state);
|
||||
void onlyOneChanged(int idx);
|
||||
void transparencyChanged(double transparency);
|
||||
|
||||
void fit();
|
||||
|
||||
private:
|
||||
Ui::qG3PointDialog *ui;
|
||||
};
|
||||
|
||||
@@ -12,10 +12,14 @@
|
||||
#include <ccMainAppInterface.h>
|
||||
#include <ccColorTypes.h>
|
||||
|
||||
#include <set>
|
||||
|
||||
class ccPointCloud;
|
||||
|
||||
class GrainsAsEllipsoids : public ccHObject
|
||||
class GrainsAsEllipsoids : public QObject, public ccHObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
typedef Eigen::Array<bool, Eigen::Dynamic, Eigen::Dynamic> Xb;
|
||||
|
||||
@@ -54,11 +58,13 @@ public:
|
||||
enum Method{
|
||||
DIRECT = 0};
|
||||
|
||||
double ellipsoidDistance(const Eigen::ArrayXd& p, int idx);
|
||||
|
||||
bool explicitToImplicit(const Eigen::Array3f& center, const Eigen::Array3f& radii, const Eigen::Matrix3f &rotationMatrix, Eigen::ArrayXd& parameters);
|
||||
|
||||
bool implicitToExplicit(const Eigen::ArrayXd& parameters, Eigen::Array3f& center, Eigen::Array3f& radii, Eigen::Matrix3f& rotationMatrix);
|
||||
|
||||
Eigen::ArrayXd directFit(const Eigen::ArrayX3d& xyz);
|
||||
bool directFit(const Eigen::ArrayX3d& xyz, Eigen::ArrayXd ¶meters);
|
||||
|
||||
bool fitEllipsoidToGrain(const int grainIndex, Eigen::Array3f& center, Eigen::Array3f& radii, Eigen::Matrix3f& rotationMatrix, const Method& method=DIRECT);
|
||||
|
||||
@@ -71,6 +77,8 @@ public:
|
||||
|
||||
void setUniformValueColor(const ccColor::Rgba &color);
|
||||
|
||||
void drawEllipsoid(CC_DRAW_CONTEXT &context, int idx);
|
||||
|
||||
bool drawEllipsoids(CC_DRAW_CONTEXT &context);
|
||||
|
||||
bool initProgram(QOpenGLContext* context);
|
||||
@@ -81,6 +89,14 @@ public:
|
||||
// from ccHObject
|
||||
void draw(CC_DRAW_CONTEXT& context);
|
||||
|
||||
void setOnlyOne(int i){m_onlyOne = i;}
|
||||
|
||||
void showOnlyOne(bool state){m_showAll =!state;}
|
||||
|
||||
void showAll(bool state);
|
||||
|
||||
void setTransparency(double transparency){m_transparency = transparency;}
|
||||
|
||||
ccPointCloud* m_cloud;
|
||||
ccMainAppInterface* m_app;
|
||||
Eigen::ArrayXi m_localMaximumIndexes;
|
||||
@@ -98,6 +114,11 @@ public:
|
||||
std::vector<Eigen::Array3f> m_center;
|
||||
std::vector<Eigen::Array3f> m_radii;
|
||||
std::vector<Eigen::Matrix3f> m_rotationMatrix;
|
||||
std::set<int> m_fitNotOK;
|
||||
double m_transparency = 1.0;
|
||||
|
||||
int m_onlyOne;
|
||||
bool m_showAll{true};
|
||||
};
|
||||
|
||||
#endif // GRAINSASELLIPSOIDS_H
|
||||
|
||||
+23
-8
@@ -957,6 +957,27 @@ int G3PointAction::cluster()
|
||||
return 0;
|
||||
}
|
||||
|
||||
void G3PointAction::fit()
|
||||
{
|
||||
// plot display grains as ellipsoids
|
||||
m_grainsAsEllipsoids = new GrainsAsEllipsoids(m_cloud, m_app, m_stacks);
|
||||
m_grainsAsEllipsoids->setLocalMaximumIndexes(m_localMaximumIndexes);
|
||||
m_grainColors.reset(new RGBAColorsTableType(getRandomColors(m_localMaximumIndexes.size())));
|
||||
m_grainsAsEllipsoids->setGrainColorsTable(*m_grainColors);
|
||||
m_grainsAsEllipsoids->setName("grains as ellipsoids");
|
||||
|
||||
// add connections with the dialog
|
||||
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);
|
||||
|
||||
m_dlg->setOnlyOneMax(m_stacks.size());
|
||||
m_dlg->emitSignals(); // force to send parameters to m_grainsAsEllipsoids
|
||||
|
||||
m_app->addToDB(m_grainsAsEllipsoids);
|
||||
}
|
||||
|
||||
bool G3PointAction::cleanLabels()
|
||||
{
|
||||
ccLog::Print("[cleanLabels]");
|
||||
@@ -1640,14 +1661,6 @@ void G3PointAction::segment()
|
||||
|
||||
m_app->dispToConsole( "[G3Point] initial segmentation: " + QString::number(nLabels) + " labels", ccMainAppInterface::STD_CONSOLE_MESSAGE );
|
||||
|
||||
// plot display grains as ellipsoids
|
||||
m_grainsAsEllipsoids = new GrainsAsEllipsoids(m_cloud, m_app, m_stacks);
|
||||
m_grainsAsEllipsoids->setLocalMaximumIndexes(m_localMaximumIndexes);
|
||||
m_grainColors.reset(new RGBAColorsTableType(getRandomColors(m_localMaximumIndexes.size())));
|
||||
m_grainsAsEllipsoids->setGrainColorsTable(*m_grainColors);
|
||||
m_grainsAsEllipsoids->setName("grains as ellipsoids");
|
||||
m_app->addToDB(m_grainsAsEllipsoids);
|
||||
|
||||
m_dlg->enableCluster(true);
|
||||
m_dlg->enableClean(true);
|
||||
}
|
||||
@@ -1735,6 +1748,8 @@ void G3PointAction::showDlg()
|
||||
connect(m_dlg, &G3PointDialog::segmentClusterClean, s_g3PointAction, &G3Point::G3PointAction::segmentAndClusterAndClean);
|
||||
connect(m_dlg, &G3PointDialog::getBorders, s_g3PointAction, &G3Point::G3PointAction::getBorders);
|
||||
|
||||
connect(m_dlg, &G3PointDialog::fit, s_g3PointAction, &G3Point::G3PointAction::fit);
|
||||
|
||||
connect(m_dlg, &QDialog::finished, s_g3PointAction, &G3Point::G3PointAction::clean);
|
||||
connect(m_dlg, &QDialog::finished, s_g3PointAction, &G3Point::G3PointAction::resetDlg); // dialog is defined with Qt::WA_DeleteOnClose
|
||||
}
|
||||
|
||||
@@ -18,6 +18,13 @@ G3PointDialog::G3PointDialog(QString cloudName, QWidget *parent)
|
||||
connect(this->ui->pushButtonClean, &QPushButton::clicked, this, &G3PointDialog::emitClean);
|
||||
connect(this->ui->pushButtonSegmentClusterClean, &QPushButton::clicked, this, &G3PointDialog::emitSegmentClusterClean);
|
||||
connect(this->ui->pushButtonGetBorders, &QPushButton::clicked, this, &G3PointDialog::emitGetBorders);
|
||||
|
||||
connect(this->ui->radioButtonAll, &QRadioButton::clicked, this, &G3PointDialog::emitAllClicked);
|
||||
connect(this->ui->radioButtonOnlyOne, &QRadioButton::clicked, this, &::G3PointDialog::emitOnlyOneClicked);
|
||||
connect(this->ui->spinBoxOnlyOne, qOverload<int>(&QSpinBox::valueChanged), this, &::G3PointDialog::emitOnlyOneChanged);
|
||||
|
||||
connect(this->ui->pushButtonFit, &QPushButton::clicked, this, &G3PointDialog::emitFit);
|
||||
connect(this->ui->doubleSpinBoxTransparency, qOverload<double>(&QDoubleSpinBox::valueChanged), this, &G3PointDialog::emitTransparencyChanged);
|
||||
}
|
||||
|
||||
G3PointDialog::~G3PointDialog()
|
||||
@@ -74,3 +81,14 @@ void G3PointDialog::enableClean(bool state)
|
||||
{
|
||||
this->ui->pushButtonClean->setEnabled(state);
|
||||
}
|
||||
|
||||
void G3PointDialog::emitSignals()
|
||||
{
|
||||
emit allClicked(this->ui->radioButtonAll->isChecked());
|
||||
emit emitOnlyOneChanged(this->ui->spinBoxOnlyOne->value());
|
||||
}
|
||||
|
||||
void G3PointDialog::setOnlyOneMax(int max)
|
||||
{
|
||||
this->ui->spinBoxOnlyOne->setMaximum(max);
|
||||
}
|
||||
|
||||
+171
-115
@@ -8,7 +8,10 @@
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
|
||||
std::vector<int> indexes;
|
||||
// from GeometricTools/GTE
|
||||
#include <Mathematics/DistPointHyperellipsoid.h>
|
||||
#include <Mathematics/Vector2.h>
|
||||
#include <Mathematics/Vector3.h>
|
||||
|
||||
GrainsAsEllipsoids::GrainsAsEllipsoids(ccPointCloud *cloud, ccMainAppInterface *app, const std::vector<std::vector<int> >& stacks)
|
||||
: m_cloud(cloud)
|
||||
@@ -24,18 +27,16 @@ GrainsAsEllipsoids::GrainsAsEllipsoids(ccPointCloud *cloud, ccMainAppInterface *
|
||||
// fit all ellipsoids
|
||||
std::cout << "[GrainsAsEllipsoids::GrainsAsEllipsoids] fit " << stacks.size() << " ellipsoids" << std::endl;
|
||||
|
||||
indexes.push_back(268);
|
||||
indexes.push_back(351);
|
||||
|
||||
lockVisibility(false);
|
||||
|
||||
for (int idx : indexes)
|
||||
for (int idx = 0; idx < m_stacks.size(); idx++)
|
||||
{
|
||||
fitEllipsoidToGrain(idx, m_center[idx], m_radii[idx], m_rotationMatrix[idx]);
|
||||
std::cout << "grain " << idx << " stack size " << m_stacks[idx].size() << std::endl;
|
||||
std::cout << "center " << std::endl << m_center[idx] << std::endl;
|
||||
std::cout << "radii " << std::endl << m_radii[idx] << std::endl;
|
||||
std::cout << "rotation matrix " << std::endl << m_rotationMatrix[idx] << std::endl;
|
||||
if (!fitEllipsoidToGrain(idx, m_center[idx], m_radii[idx], m_rotationMatrix[idx]))
|
||||
{
|
||||
m_fitNotOK.insert(idx);
|
||||
ccLog::Warning("[GrainsAsEllipsoids::GrainsAsEllipsoids] fit not possible for grain " + QString::number(idx)
|
||||
+ " of size " + QString::number(m_stacks[idx].size()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,6 +188,67 @@ void GrainsAsEllipsoids::buildInterleavedVertices()
|
||||
|
||||
// ELLIPSOID FITTING
|
||||
|
||||
double GrainsAsEllipsoids::ellipsoidDistance(const Eigen::ArrayXd& p, int idx)
|
||||
{
|
||||
// Compute the mean distance between the points of the grain and the ellipsoid
|
||||
|
||||
// GTE Geometric Tools Engine
|
||||
|
||||
// center
|
||||
gte::Vector3<double> center = {m_center[idx](0), m_center[idx](1), m_center[idx](2)};
|
||||
|
||||
// axis
|
||||
std::array<gte::Vector3<double>, 3> axis;
|
||||
axis[0] = {m_rotationMatrix[idx](0, 0), m_rotationMatrix[idx](1, 0), m_rotationMatrix[idx](2, 0)};
|
||||
axis[1] = {m_rotationMatrix[idx](0, 1), m_rotationMatrix[idx](1, 1), m_rotationMatrix[idx](2, 1)};
|
||||
axis[2] = {m_rotationMatrix[idx](0, 2), m_rotationMatrix[idx](1, 2), m_rotationMatrix[idx](2, 2)};
|
||||
|
||||
// extent
|
||||
gte::Vector3<double> extent = {m_radii[idx](0), m_radii[idx](1), m_radii[idx](2)};
|
||||
|
||||
// create the ellipsoid
|
||||
gte::Ellipsoid3<double> ellipsoid(center, axis, extent);
|
||||
|
||||
gte::DCPQuery<double, gte::Vector3<double>, gte::Ellipsoid3<double>> query;
|
||||
|
||||
std::vector<int> stack = m_stacks[idx];
|
||||
double sum_a = 0; // distances with respect to the ellipsoid
|
||||
double sum_b = 0; // distances with respect to the mean
|
||||
|
||||
//compute gravity center
|
||||
size_t count = m_cloud->size();
|
||||
CCVector3 mean(0, 0, 0);
|
||||
for (int index : m_stacks[idx])
|
||||
{
|
||||
const CCVector3* P = m_cloud->getPoint(index);
|
||||
mean.x += P->x;
|
||||
mean.y += P->y;
|
||||
mean.z += P->z;
|
||||
}
|
||||
mean.x = mean.x / count;
|
||||
mean.y = mean.y / count;
|
||||
mean.z = mean.z / count;
|
||||
|
||||
for (int index : stack)
|
||||
{
|
||||
const CCVector3 *P = m_cloud->getPoint(index);
|
||||
gte::Vector3<double> P_gte = {P->x, P->y, P->z};
|
||||
auto result = query(P_gte, ellipsoid);
|
||||
sum_a = sum_a + pow(result.distance, 2);
|
||||
|
||||
CCVector3 P_minus_min = *P - CCVector3(mean.x, mean.y, mean.z);
|
||||
sum_b = sum_b + P_minus_min.norm2d();
|
||||
}
|
||||
|
||||
double r2 = 1 - sum_a / sum_b;
|
||||
|
||||
// in Matlab
|
||||
// d = (x-xp).^2 + (y-yp).^2 + (z-zp).^2;
|
||||
// r2 = 1 - sum((x-xp).^2 + (y-yp).^2 + (z-zp).^2)./sum((x-mean(x)).^2 + (y-mean(y)).^2 + (z-mean(z)).^2);
|
||||
|
||||
return r2;
|
||||
}
|
||||
|
||||
bool GrainsAsEllipsoids::explicitToImplicit(const Eigen::Array3f& center,
|
||||
const Eigen::Array3f& radii,
|
||||
const Eigen::Matrix3f& rotationMatrix,
|
||||
@@ -301,7 +363,7 @@ bool GrainsAsEllipsoids::implicitToExplicit(const Eigen::ArrayXd& parameters,
|
||||
Eigen::EigenSolver<Eigen::MatrixXd> eigensolver(s.block(0, 0, 3, 3));
|
||||
if (eigensolver.info() != Eigen::Success)
|
||||
{
|
||||
abort();
|
||||
return false;
|
||||
}
|
||||
|
||||
radii = (-s(3, 3) / eigensolver.eigenvalues().array().real()).sqrt().cast<float>();
|
||||
@@ -310,10 +372,8 @@ bool GrainsAsEllipsoids::implicitToExplicit(const Eigen::ArrayXd& parameters,
|
||||
return true;
|
||||
}
|
||||
|
||||
Eigen::ArrayXd GrainsAsEllipsoids::directFit(const Eigen::ArrayX3d& xyz)
|
||||
bool GrainsAsEllipsoids::directFit(const Eigen::ArrayX3d& xyz, Eigen::ArrayXd& parameters)
|
||||
{
|
||||
std::cout << "[GrainsAsEllipsoids::directFit]" << std::endl;
|
||||
|
||||
Eigen::MatrixXd d(xyz.rows(), 10);
|
||||
|
||||
d << xyz(Eigen::all, 0).pow(2).matrix()
|
||||
@@ -345,11 +405,13 @@ Eigen::ArrayXd GrainsAsEllipsoids::directFit(const Eigen::ArrayX3d& xyz)
|
||||
Eigen::GeneralizedEigenSolver<Eigen::MatrixXd> eigensolver(s, c);
|
||||
if (eigensolver.info() != Eigen::Success)
|
||||
{
|
||||
abort();
|
||||
return false;
|
||||
}
|
||||
|
||||
Eigen::ArrayXd eigenValues(10);
|
||||
Eigen::VectorXd eigenValuesAsAMatrix(10);
|
||||
eigenValues = eigensolver.eigenvalues().real();
|
||||
eigenValuesAsAMatrix = eigensolver.eigenvalues().real().matrix();
|
||||
Xb condition = (eigenValues > 0) && (!eigenValues.isInf());
|
||||
|
||||
int flt = condition.count();
|
||||
@@ -381,10 +443,10 @@ Eigen::ArrayXd GrainsAsEllipsoids::directFit(const Eigen::ArrayX3d& xyz)
|
||||
break;
|
||||
case 0: // degenerate case
|
||||
// # single positive eigenvalue becomes near-zero negative eigenvalue due to round-off error
|
||||
eigenValue = finiteValues.abs().minCoeff();
|
||||
eigenValue = eigenValues.abs().minCoeff();
|
||||
for (k = 0; k < 10; k++)
|
||||
{
|
||||
if (eigenValues(k) == eigenValue)
|
||||
if (abs(eigenValues(k)) == eigenValue)
|
||||
{
|
||||
v = eigensolver.eigenvectors()(Eigen::all, k).real();
|
||||
break;
|
||||
@@ -405,14 +467,14 @@ Eigen::ArrayXd GrainsAsEllipsoids::directFit(const Eigen::ArrayX3d& xyz)
|
||||
break;
|
||||
}
|
||||
|
||||
Eigen::ArrayXd p(10);
|
||||
parameters.resize(10);
|
||||
|
||||
p << v(0), v(1), v(2)
|
||||
parameters << v(0), v(1), v(2)
|
||||
, 2 * v(5), 2 * v(4), 2* v(3)
|
||||
, 2 * v(6), 2 * v(7), 2 * v(8)
|
||||
, v(9);
|
||||
|
||||
return p;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GrainsAsEllipsoids::fitEllipsoidToGrain(const int grainIndex,
|
||||
@@ -453,9 +515,15 @@ bool GrainsAsEllipsoids::fitEllipsoidToGrain(const int grainIndex,
|
||||
// The constraint confines the class of ellipsoids to fit to those whose smallest radius is at least half of the
|
||||
// largest radius.
|
||||
|
||||
p = directFit(scale * (grainPoints.cast<double>().rowwise() - means)); // Ellipsoid fit
|
||||
if(!directFit(scale * (grainPoints.cast<double>().rowwise() - means), p)) // Ellipsoid fit
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
implicitToExplicit(p, center, radii, rotationMatrix); // Get the explicit parameters
|
||||
if (!implicitToExplicit(p, center, radii, rotationMatrix)) // Get the explicit parameters
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
@@ -558,62 +626,27 @@ bool GrainsAsEllipsoids::initProgram(QOpenGLContext* context)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GrainsAsEllipsoids::drawEllipsoids(CC_DRAW_CONTEXT& context)
|
||||
void GrainsAsEllipsoids::drawEllipsoid(CC_DRAW_CONTEXT& context, int idx)
|
||||
{
|
||||
QOpenGLFunctions_2_1* glFunc = context.glFunctions<QOpenGLFunctions_2_1>();
|
||||
assert(glFunc != nullptr);
|
||||
|
||||
CCVector3f color;
|
||||
|
||||
// set uniforms
|
||||
QVector4D lightPosition(0, 0, 1, 0);
|
||||
QVector4D lightAmbient(0.3f, 0.3f, 0.3f, 1); // grey
|
||||
QVector4D lightDiffuse(0.7f, 0.7f, 0.7f, 1); // light grey
|
||||
QVector4D lightSpecular(1.0f, 1.0f, 1.0f, 1); // RGB white
|
||||
// QVector4D materialAmbient(0.5f, 0.5f, 0.5f, 1);
|
||||
QVector4D materialDiffuse(0.7f, 0.7f, 0.7f, 1);
|
||||
QVector4D materialSpecular(0.4f, 0.4f, 0.4f, 1);
|
||||
QVector4D materialAmbient(color.x, color.y, color.z, 1);
|
||||
// QVector4D materialDiffuse(color.r / ccColor::MAX, color.g / ccColor::MAX, color.b / ccColor::MAX, 1);
|
||||
// QVector4D materialSpecular(color.r / ccColor::MAX, color.g / ccColor::MAX, color.b / ccColor::MAX, 1);
|
||||
float materialShininess = 16;
|
||||
|
||||
m_program->setUniformValue("lightPosition", lightPosition);
|
||||
m_program->setUniformValue("lightAmbient", lightAmbient);
|
||||
m_program->setUniformValue("lightDiffuse", lightDiffuse);
|
||||
m_program->setUniformValue("lightSpecular", lightSpecular);
|
||||
m_program->setUniformValue("materialDiffuse", materialDiffuse);
|
||||
m_program->setUniformValue("materialSpecular", materialSpecular);
|
||||
m_program->setUniformValue("materialShininess", materialShininess);
|
||||
|
||||
m_program->setAttributeArray("vertexPosition", static_cast<GLfloat*>(vertices.data()), 3);
|
||||
m_program->setAttributeArray("vertexNormal", static_cast<GLfloat*>(normals.data()), 3);
|
||||
m_program->setAttributeArray("vertexTexCoord", static_cast<GLfloat*>(texCoords.data()), 2);
|
||||
|
||||
m_program->enableAttributeArray("vertexPosition");
|
||||
m_program->enableAttributeArray("vertexNormal");
|
||||
m_program->enableAttributeArray("vertexTexCoord");
|
||||
|
||||
QMatrix4x4 projection;
|
||||
QMatrix4x4 modelView;
|
||||
|
||||
//generate random colors
|
||||
std::mt19937 gen(42); // to seed mersenne twister.
|
||||
std::uniform_real_distribution<> dis(0.5, 1.0);
|
||||
std::uniform_real_distribution<> dis2(-1., 1.0);
|
||||
|
||||
for (int idx : indexes)
|
||||
if (!m_fitNotOK.count(idx))
|
||||
{
|
||||
QMatrix4x4 projection;
|
||||
QMatrix4x4 modelView;
|
||||
Eigen::Matrix3f rotation(m_rotationMatrix[idx].transpose());
|
||||
QMatrix4x4 matrixFromFit(rotation(0, 0), rotation(0, 1), rotation(0, 2), m_center[idx](0),
|
||||
rotation(1, 0), rotation(1, 1), rotation(1, 2), m_center[idx](1),
|
||||
rotation(2, 0), rotation(2, 1), rotation(2, 2), m_center[idx](2),
|
||||
0, 0, 0, 1);
|
||||
|
||||
CCVector3f color;
|
||||
|
||||
color = m_grainColors[idx];
|
||||
glFunc->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glFunc->glEnable( GL_BLEND );
|
||||
m_program->setUniformValue("materialAmbient", color.x, color.y, color.z, 0.5);
|
||||
glFunc->glEnable(GL_BLEND);
|
||||
m_program->setUniformValue("materialAmbient", color.x, color.y, color.z, 1.);
|
||||
|
||||
// prepare translation, rotation and scaling
|
||||
glFunc->glPushMatrix(); // save the current matrix
|
||||
@@ -643,9 +676,61 @@ bool GrainsAsEllipsoids::drawEllipsoids(CC_DRAW_CONTEXT& context)
|
||||
|
||||
glFunc->glPopMatrix();
|
||||
}
|
||||
}
|
||||
|
||||
if (false)
|
||||
{ // Matlab 22.36920946, 17.15421478, -11.2193826
|
||||
bool GrainsAsEllipsoids::drawEllipsoids(CC_DRAW_CONTEXT& context)
|
||||
{
|
||||
QOpenGLFunctions_2_1* glFunc = context.glFunctions<QOpenGLFunctions_2_1>();
|
||||
assert(glFunc != nullptr);
|
||||
|
||||
CCVector3f color;
|
||||
|
||||
// set uniforms
|
||||
QVector4D lightPosition(0, 0, 1, 0);
|
||||
QVector4D lightAmbient(0.3f, 0.3f, 0.3f, 1); // grey
|
||||
QVector4D lightDiffuse(0.7f, 0.7f, 0.7f, 1); // light grey
|
||||
QVector4D lightSpecular(1.0f, 1.0f, 1.0f, 1); // RGB white
|
||||
// QVector4D materialAmbient(0.5f, 0.5f, 0.5f, 1);
|
||||
QVector4D materialDiffuse(0.7f, 0.7f, 0.7f, m_transparency);
|
||||
QVector4D materialSpecular(0.4f, 0.4f, 0.4f, 1);
|
||||
QVector4D materialAmbient(color.x, color.y, color.z, 1);
|
||||
// QVector4D materialDiffuse(color.r / ccColor::MAX, color.g / ccColor::MAX, color.b / ccColor::MAX, 1);
|
||||
// QVector4D materialSpecular(color.r / ccColor::MAX, color.g / ccColor::MAX, color.b / ccColor::MAX, 1);
|
||||
float materialShininess = 16;
|
||||
|
||||
m_program->setUniformValue("lightPosition", lightPosition);
|
||||
m_program->setUniformValue("lightAmbient", lightAmbient);
|
||||
m_program->setUniformValue("lightDiffuse", lightDiffuse);
|
||||
m_program->setUniformValue("lightSpecular", lightSpecular);
|
||||
m_program->setUniformValue("materialDiffuse", materialDiffuse);
|
||||
m_program->setUniformValue("materialSpecular", materialSpecular);
|
||||
m_program->setUniformValue("materialShininess", materialShininess);
|
||||
|
||||
m_program->setAttributeArray("vertexPosition", static_cast<GLfloat*>(vertices.data()), 3);
|
||||
m_program->setAttributeArray("vertexNormal", static_cast<GLfloat*>(normals.data()), 3);
|
||||
m_program->setAttributeArray("vertexTexCoord", static_cast<GLfloat*>(texCoords.data()), 2);
|
||||
|
||||
m_program->enableAttributeArray("vertexPosition");
|
||||
m_program->enableAttributeArray("vertexNormal");
|
||||
m_program->enableAttributeArray("vertexTexCoord");
|
||||
|
||||
QMatrix4x4 projection;
|
||||
QMatrix4x4 modelView;
|
||||
|
||||
if (m_showAll)
|
||||
{
|
||||
for (int idx = 0; idx < m_stacks.size(); idx++)
|
||||
{
|
||||
drawEllipsoid(context, idx);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
drawEllipsoid(context, m_onlyOne);
|
||||
}
|
||||
|
||||
if (false) // Matlab fit of grain 351
|
||||
{
|
||||
Eigen::Matrix3f rotation;
|
||||
rotation << -0.1424, -0.8175, -0.5580,
|
||||
-0.9102, -0.1133, 0.3983,
|
||||
@@ -690,44 +775,6 @@ bool GrainsAsEllipsoids::drawEllipsoids(CC_DRAW_CONTEXT& context)
|
||||
glFunc->glPopMatrix();
|
||||
}
|
||||
|
||||
// for (int k = 1; k < m_localMaximumIndexes.size(); k++)
|
||||
// {
|
||||
// if (k==indexOfGrainToFit)
|
||||
// continue;
|
||||
|
||||
// const CCVector3f* center = m_cloud->getPoint(m_localMaximumIndexes[k]);
|
||||
// CCVector3f color = m_grainColors[k];
|
||||
// m_program->setUniformValue("materialAmbient", color.x, color.y, color.z, 1);
|
||||
|
||||
// // prepare translation, rotation and scaling
|
||||
// glFunc->glPushMatrix(); // save the current matrix
|
||||
// // translate
|
||||
// glFunc->glTranslatef(center->x, center->y, center->z);
|
||||
// // rotate
|
||||
// glFunc->glRotatef(90, static_cast<float>(dis2(gen)), static_cast<float>(dis2(gen)), static_cast<float>(dis2(gen)));
|
||||
// // scale
|
||||
// glFunc->glScalef(static_cast<float>(dis(gen)), static_cast<float>(dis(gen)), static_cast<float>(dis(gen)));
|
||||
// // get matrices
|
||||
// glFunc->glGetFloatv(GL_PROJECTION_MATRIX, projection.data());
|
||||
// glFunc->glGetFloatv(GL_MODELVIEW_MATRIX, modelView.data());
|
||||
// m_program->setUniformValue("modelViewProjectionMatrix", projection * modelView);
|
||||
|
||||
// // draw triangles
|
||||
// m_program->setUniformValue("drawLines", 0);
|
||||
// glFunc->glEnable(GL_POLYGON_OFFSET_FILL);
|
||||
// glFunc->glPolygonOffset(1.0, 1.0f); // move polygon backward
|
||||
// glFunc->glDrawElements(GL_TRIANGLES, (unsigned int)indices.size(), GL_UNSIGNED_INT, indices.data());
|
||||
// glFunc->glDisable(GL_POLYGON_OFFSET_FILL);
|
||||
|
||||
// // draw lines
|
||||
// m_program->setUniformValue("drawLines", 1);
|
||||
// glFunc->glDisable(GL_LIGHTING);
|
||||
// glFunc->glDisable(GL_TEXTURE_2D);
|
||||
// glFunc->glDrawElements(GL_LINES, (unsigned int)lineIndices.size(), GL_UNSIGNED_INT, lineIndices.data());
|
||||
|
||||
// glFunc->glPopMatrix();
|
||||
// }
|
||||
|
||||
m_program->disableAttributeArray("vertexPosition");
|
||||
m_program->disableAttributeArray("vertexNormal");
|
||||
m_program->disableAttributeArray("vertexTexCoord");
|
||||
@@ -756,18 +803,18 @@ void GrainsAsEllipsoids::drawGrains(CC_DRAW_CONTEXT& context)
|
||||
// set uniforms
|
||||
m_program->setUniformValue("modelViewProjectionMatrix", projectionModelView);
|
||||
|
||||
// get the coordinates of the local maxima
|
||||
std::vector<CCVector3> semiAxisLengths(m_localMaximumIndexes.size(), CCVector3(1, 1, 1));
|
||||
std::vector<CCVector3f> centers(m_localMaximumIndexes.size());
|
||||
|
||||
// initialize the vector containing the centers of the grains
|
||||
for (int index = 0; index < m_localMaximumIndexes.size(); index++)
|
||||
{
|
||||
centers[index] = *m_cloud->getPoint(m_localMaximumIndexes[index]);
|
||||
}
|
||||
|
||||
if (false)
|
||||
{
|
||||
// get the coordinates of the local maxima
|
||||
std::vector<CCVector3> semiAxisLengths(m_localMaximumIndexes.size(), CCVector3(1, 1, 1));
|
||||
std::vector<CCVector3f> centers(m_localMaximumIndexes.size());
|
||||
|
||||
// initialize the vector containing the centers of the grains
|
||||
for (int index = 0; index < m_localMaximumIndexes.size(); index++)
|
||||
{
|
||||
centers[index] = *m_cloud->getPoint(m_localMaximumIndexes[index]);
|
||||
}
|
||||
|
||||
m_program->setAttributeArray("vertexIn", static_cast<GLfloat*>(vertices.data()), 3);
|
||||
m_program->setAttributeArray("semiAxisLengths", static_cast<GLfloat*>(semiAxisLengths.front().u), 3);
|
||||
|
||||
@@ -801,3 +848,12 @@ void GrainsAsEllipsoids::draw(CC_DRAW_CONTEXT& context)
|
||||
{
|
||||
drawGrains(context);
|
||||
}
|
||||
|
||||
void GrainsAsEllipsoids::showAll(bool state)
|
||||
{
|
||||
m_showAll = state;
|
||||
ccLog::Warning("[GrainsAsEllipsoids::showAll] changed " + QString::number(m_showAll));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
+321
-192
@@ -6,206 +6,335 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>281</width>
|
||||
<height>459</height>
|
||||
<width>303</width>
|
||||
<height>509</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Dialog</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="16" column="0" colspan="2">
|
||||
<widget class="QLabel" name="labelCloud">
|
||||
<property name="text">
|
||||
<string>-</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="1">
|
||||
<widget class="QPushButton" name="pushButtonSegmentCluster">
|
||||
<property name="text">
|
||||
<string>Segment + Cluster</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Min points per grain</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Point size</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Min flatness</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Max angle 1</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="15" column="0">
|
||||
<widget class="QRadioButton" name="radioButtonG3Point">
|
||||
<property name="text">
|
||||
<string>G3Point</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QSpinBox" name="spinBoxPointSize">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>3</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Radius factor</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QSpinBox" name="spinBoxkNN">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>100000</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>20</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QSpinBox" name="spinBoxNMin">
|
||||
<property name="maximum">
|
||||
<number>1000000000</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>50</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QDoubleSpinBox" name="doubleSpinBoxRadiusFactor">
|
||||
<property name="value">
|
||||
<double>0.600000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="1">
|
||||
<widget class="QPushButton" name="pushButtonClean">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Clean</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="1">
|
||||
<widget class="QPushButton" name="pushButtonCluster">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Cluster</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QDoubleSpinBox" name="doubleSpinBoxMinFlatness">
|
||||
<property name="singleStep">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QDoubleSpinBox" name="doubleSpinBoxMaxAngle1">
|
||||
<property name="frame">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::UpDownArrows</enum>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>360.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>60.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="15" column="1">
|
||||
<widget class="QRadioButton" name="radioButtonSteepestSlope">
|
||||
<property name="text">
|
||||
<string>steepest slope</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>kNN</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Max angle 2</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QDoubleSpinBox" name="doubleSpinBoxMaxAngle2">
|
||||
<property name="value">
|
||||
<double>10.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="13" column="1">
|
||||
<widget class="QPushButton" name="pushButtonSegmentClusterClean">
|
||||
<property name="text">
|
||||
<string>Segment + Cluster + Clean</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<widget class="QPushButton" name="pushButtonSegment">
|
||||
<property name="text">
|
||||
<string>Segment</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="14" column="1">
|
||||
<widget class="QPushButton" name="pushButtonGetBorders">
|
||||
<property name="text">
|
||||
<string>Get borders</string>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="tab">
|
||||
<attribute name="title">
|
||||
<string>Segmentation</string>
|
||||
</attribute>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>kNN</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QSpinBox" name="spinBoxkNN">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>100000</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>20</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Radius factor</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QDoubleSpinBox" name="doubleSpinBoxRadiusFactor">
|
||||
<property name="value">
|
||||
<double>0.600000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Max angle 1</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QDoubleSpinBox" name="doubleSpinBoxMaxAngle1">
|
||||
<property name="frame">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::UpDownArrows</enum>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>360.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>60.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Max angle 2</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QDoubleSpinBox" name="doubleSpinBoxMaxAngle2">
|
||||
<property name="value">
|
||||
<double>10.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Min points per grain</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QSpinBox" name="spinBoxNMin">
|
||||
<property name="maximum">
|
||||
<number>1000000000</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>50</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Min flatness</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QDoubleSpinBox" name="doubleSpinBoxMinFlatness">
|
||||
<property name="singleStep">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Point size</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QSpinBox" name="spinBoxPointSize">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>3</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="QPushButton" name="pushButtonSegment">
|
||||
<property name="text">
|
||||
<string>Segment</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<widget class="QPushButton" name="pushButtonCluster">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Cluster</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="1">
|
||||
<widget class="QPushButton" name="pushButtonClean">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Clean</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="1">
|
||||
<widget class="QPushButton" name="pushButtonSegmentCluster">
|
||||
<property name="text">
|
||||
<string>Segment + Cluster</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="1">
|
||||
<widget class="QPushButton" name="pushButtonSegmentClusterClean">
|
||||
<property name="text">
|
||||
<string>Segment + Cluster + Clean</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="1">
|
||||
<widget class="QPushButton" name="pushButtonGetBorders">
|
||||
<property name="text">
|
||||
<string>Get borders</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="13" column="0">
|
||||
<widget class="QRadioButton" name="radioButtonG3Point">
|
||||
<property name="text">
|
||||
<string>G3Point</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="13" column="1">
|
||||
<widget class="QRadioButton" name="radioButtonSteepestSlope">
|
||||
<property name="text">
|
||||
<string>steepest slope</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="14" column="0">
|
||||
<widget class="QLabel" name="labelCloud">
|
||||
<property name="text">
|
||||
<string>-</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_2">
|
||||
<attribute name="title">
|
||||
<string>Fitting</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>Fit ellipsoids</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_2">
|
||||
<item row="0" column="0">
|
||||
<widget class="QPushButton" name="pushButtonFit">
|
||||
<property name="text">
|
||||
<string>Run</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QRadioButton" name="radioButtonDirect">
|
||||
<property name="text">
|
||||
<string>Direct</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Show</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_3">
|
||||
<item row="0" column="0">
|
||||
<widget class="QRadioButton" name="radioButtonAll">
|
||||
<property name="text">
|
||||
<string>All</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QRadioButton" name="radioButtonOnlyOne">
|
||||
<property name="text">
|
||||
<string>Only one</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSpinBox" name="spinBoxOnlyOne"/>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>Transparency</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QDoubleSpinBox" name="doubleSpinBoxTransparency">
|
||||
<property name="maximum">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.050000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="checkBoxWireframes">
|
||||
<property name="text">
|
||||
<string>Wireframes</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QCheckBox" name="checkBoxSurfaces">
|
||||
<property name="text">
|
||||
<string>Surfaces</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
||||
Reference in New Issue
Block a user