#include <QtGui>
#include "qQueryMesh.h"
#include <ccMesh.h>
#include <ccLog.h>
#include <ccPolyline.h>
#include <ccPointCloud.h>
#include <ccGLWindowInterface.h>
#include <fstream>
#include <cmath>
qQueryMesh::qQueryMesh(QObject *parent)
: QObject(parent)
, ccStdPluginInterface(":/CC/plugin/qQueryMesh/info.json")
, m_action(nullptr)
{
}
void qQueryMesh::onNewSelection(const ccHObject::Container &selectedEntities)
{
if (m_action == nullptr)
{
return;
}
for (ccHObject *entity : selectedEntities)
{
if (!entity)
continue;
// Stampiamo il nome dell'entità
ccLog::Print(QString("Oggetto selezionato: %1").arg(entity->getName()));
// Determiniamo il tipo dell'entità
if (entity->isKindOf(CC_TYPES::MESH))
{
ccLog::Print("Tipo: Mesh");
ccMesh *mesh = static_cast<ccMesh *>(entity);
ccPointCloud *vertices = dynamic_cast<ccPointCloud *>(mesh->getAssociatedCloud());
if (!vertices)
{
ccLog::Print("Errore: impossibile ottenere il PointCloud associato alla mesh");
continue;
}
// Colora tutti i vertici di grigio
ccColor::Rgb color(128, 128, 128);
for (unsigned i = 0; i < vertices->size(); ++i)
vertices->setPointColor(i, color);
// Mostra i colori sulla mesh
mesh->showColors(true);
mesh->prepareDisplayForRefresh();
if (mesh->hasNormals())
{
if (vertices->size() < 3)
continue;
CCVector3 avgNormal(0, 0, 0);
CCVector3 centroid(0, 0, 0);
double A = 0.0;
double B = 0.0;
double C = 0.0;
double D = 0.0;
unsigned triCount = mesh->size();
for (unsigned i = 0; i < triCount; ++i)
{
CCCoreLib::VerticesIndexes *tri = mesh->getTriangleVertIndexes(i);
if (!tri)
continue;
const CCVector3 *pA = vertices->getPoint(tri->i1);
const CCVector3 *pB = vertices->getPoint(tri->i2);
const CCVector3 *pC = vertices->getPoint(tri->i3);
// centroide per il calcolo di D
centroid += (*pA + *pB + *pC) / 3.0f;
// normale triangolo
CCVector3 AB = *pB - *pA;
CCVector3 AC = *pC - *pA;
CCVector3 N = AB.cross(AC);
N.normalize();
avgNormal += N;
}
if (triCount > 0)
{
avgNormal.normalize();
centroid /= static_cast<PointCoordinateType>(triCount);
// piano: Ax + By + Cz + D = 0
A = avgNormal.x;
B = avgNormal.y;
C = avgNormal.z;
D = -(A * centroid.x + B * centroid.y + C * centroid.z);
ccLog::Print(QString("Piano mesh: normale=(%1,%2,%3), D=%4")
.arg(A)
.arg(B)
.arg(C)
.arg(D));
}
// Calcolo della normale media
CCVector3 normalSum(0, 0, 0);
unsigned count = 0;
for (unsigned i = 0; i < mesh->size(); ++i) // numero di triangoli
{
const CCCoreLib::VerticesIndexes *tri = mesh->getTriangleVertIndexes(i);
if (!tri)
continue;
const CCVector3 *p0 = vertices->getPoint(tri->i1);
const CCVector3 *p1 = vertices->getPoint(tri->i2);
const CCVector3 *p2 = vertices->getPoint(tri->i3);
CCVector3 v1 = *p1 - *p0;
CCVector3 v2 = *p2 - *p0;
CCVector3 N = v1.cross(v2);
if (N.norm2() > 0)
{
N.normalize();
normalSum += N;
++count;
}
}
if (count > 0)
{
normalSum /= static_cast<PointCoordinateType>(count);
normalSum.normalize();
ccLog::Print(QString("Normale media: (%1, %2, %3)")
.arg(normalSum.x)
.arg(normalSum.y)
.arg(normalSum.z));
}
// Scrittura in CSV in append
// coseni direttori
double norm = sqrt(A * A + B * B + C * C);
double l = A / norm;
double m = B / norm;
double n = C / norm;
// angoli in radianti → gradi
double alpha = acos(l) * 180.0 / M_PI;
double beta = acos(m) * 180.0 / M_PI;
double gamma = acos(n) * 180.0 / M_PI;
const char *filename = "/home/luca/dati.csv";
bool writeHeader = false;
{
std::ifstream checkFile(filename);
if (!checkFile.good() || checkFile.peek() == std::ifstream::traits_type::eof())
writeHeader = true;
}
std::ofstream file(filename, std::ios::app);
if (file.is_open())
{
if (writeHeader)
{
file << "A,B,C,D,alpha,beta,gamma\n";
}
file << A << "," << B << "," << C << "," << D << ","
<< alpha << "," << beta << "," << gamma << "\n";
file.close();
}
}
else
{
ccLog::Print("Mesh senza normali");
}
}
else if (entity->isKindOf(CC_TYPES::POLY_LINE))
{
ccLog::Print("Tipo: Polilinea");
}
else if (entity->isKindOf(CC_TYPES::POINT_CLOUD))
{
ccLog::Print("Tipo: Point Cloud");
}
else
{
ccLog::Print("Tipo: Altro");
}
}
// abilita se è selezionato un tema poligonale
bool hasPoly = false;
for (ccHObject *obj : selectedEntities)
{
if (obj && obj->isKindOf(CC_TYPES::POLY_LINE))
{
hasPoly = true;
break;
}
}
m_action->setEnabled(hasPoly);
}
QList<QAction *> qQueryMesh::getActions()
{
if (!m_action)
{
m_action = new QAction(getName(), this);
m_action->setToolTip(getDescription());
m_action->setIcon(getIcon());
connect(m_action, &QAction::triggered, this, [this]()
{
if (!m_app)
return;
const ccHObject::Container& selected = m_app->getSelectedEntities();
if (selected.empty())
{
ccLog::Warning("[qQueryPolygon] No polygon selected!");
return;
}
for (ccHObject* obj : selected)
{
if (!obj || !obj->isKindOf(CC_TYPES::POLY_LINE))
continue;
ccPolyline* poly = static_cast<ccPolyline*>(obj);
if (!poly)
continue;
ccPointCloud* vertices = static_cast<ccPointCloud*>(poly->getAssociatedCloud());
if (!vertices)
continue;
// ---- INFO ----
QString info;
info += QString("Polygon: %1\n").arg(poly->getName());
info += QString("Vertices: %1\n").arg(vertices->size());
info += QString("Closed: %1\n").arg(poly->isClosed() ? "Yes" : "No");
PointCoordinateType length = poly->computeLength();
info += QString("\nPerimeter length: %1").arg(length);
ccLog::Print(info);
// ---- HIGHLIGHT ----
poly->setColor(ccColor::red); // change line color
poly->setWidth(4); // make it thicker
poly->showColors(true);
if (m_app->getActiveGLWindow())
m_app->getActiveGLWindow()->redraw();
} });
}
return {m_action};
}