#include "onf_stepfilterwires.h"
#include "ct_shapedata/ct_linedata.h"
#include "ct_accessor/ct_pointaccessor.h"
ONF_StepFilterWires::ONF_StepFilterWires() : SuperClass()
{
_nbNeigbours = 10;
_distMax = 1.0;
_resGrid = 0.1;
_slopeThreshold = 0.05;
_rmseThreshold = 0.02;
_slopeMax = false;
_rmseMax = false;
}
QString ONF_StepFilterWires::description() const
{
return tr("Filtrage des fils / cables");
}
QString ONF_StepFilterWires::detailledDescription() const
{
return tr("");
}
QString ONF_StepFilterWires::inputDescription() const
{
return SuperClass::inputDescription() + tr("
");
}
QString ONF_StepFilterWires::outputDescription() const
{
return SuperClass::outputDescription() + tr("
");
}
QString ONF_StepFilterWires::detailsDescription() const
{
return tr("");
}
QString ONF_StepFilterWires::URL() const
{
//return tr("STEP URL HERE");
return SuperClass::URL(); //by default URL of the plugin
}
CT_VirtualAbstractStep* ONF_StepFilterWires::createNewInstance() const
{
return new ONF_StepFilterWires();
}
//////////////////// PROTECTED METHODS //////////////////
void ONF_StepFilterWires::declareInputModels(CT_StepInModelStructureManager& manager)
{
manager.addResult(_inResult, tr("Point cloud"));
manager.setZeroOrMoreRootGroup(_inResult, _inZeroOrMoreRootGroup);
manager.addGroup(_inZeroOrMoreRootGroup, _inGroup);
manager.addItem(_inGroup, _inScene, tr("Point cloud"));
}
void ONF_StepFilterWires::declareOutputModels(CT_StepOutModelStructureManager& manager)
{
manager.addResultCopy(_inResult);
manager.addPointAttribute(_inGroup, _outSlope, tr("Slope"));
manager.addPointAttribute(_inGroup, _outRMSE, tr("RMSE"));
manager.addItem(_inGroup, _outSceneKept, tr("Scène conservée"));
manager.addItem(_inGroup, _outSceneWires, tr("fils / cables"));
}
void ONF_StepFilterWires::fillPostInputConfigurationDialog(CT_StepConfigurableDialog* postInputConfigDialog)
{
postInputConfigDialog->addInt("Nombre de voisins à rechercher", "", 1, 9999, _nbNeigbours);
postInputConfigDialog->addDouble("Distance maximum pour les voisins à rechercher", "", 0, 9999 ,2 , _distMax);
postInputConfigDialog->addDouble(tr("Resolution d'optimisation"), "", 0.1, 99999, 2, _resGrid);
postInputConfigDialog->addEmpty();
postInputConfigDialog->addDouble(tr("Seuil de pente"), "", 0, 1, 2, _slopeThreshold);
postInputConfigDialog->addBool(tr("Seuil Maxi pour la pente ?"), "", "", _slopeMax);
postInputConfigDialog->addEmpty();
postInputConfigDialog->addDouble(tr("Seuil de RMSE"), "", 0, 99999, 10, _rmseThreshold);
postInputConfigDialog->addBool(tr("Seuil Maxi pour la RMSE ?"), "", "", _rmseMax);
}
void ONF_StepFilterWires::compute()
{
CT_PointAccessor accessor;
for (CT_StandardItemGroup* grp_inG : _inGroup.iterateOutputs(_inResult))
{
if (isStopped()) {return;}
const CT_AbstractItemDrawableWithPointCloud* scene = grp_inG->singularItem(_inScene);
if (scene != nullptr)
{
const CT_AbstractPointCloudIndex *pointCloudIndex = scene->pointCloudIndex();
CT_Grid3D_Points* grid = CT_Grid3D_Points::createGrid3DFromXYZCoords(scene->minX() - 1.0, scene->minY() - 1.0, scene->minZ() - 1.0,
scene->maxX() + 1.0, scene->maxY() + 1.0, scene->maxZ() + 1.0,
_resGrid, false);
CT_PointIterator it(pointCloudIndex);
while (it.hasNext())
{
it.next();
const CT_Point& pt = it.currentPoint();
size_t index = it.currentGlobalIndex();
grid->addPoint(index, pt(0), pt(1), pt(2));
}
auto slopeSetter = _outSlope.createAttributesSetter(scene->pointCloudIndexRegistered().dynamicCast());
auto rmseSetter = _outRMSE.createAttributesSetter(scene->pointCloudIndexRegistered().dynamicCast());
CT_PointCloudIndexVector *cloudKept = new CT_PointCloudIndexVector();
cloudKept->setSortType(CT_PointCloudIndexVector::NotSorted);
CT_PointCloudIndexVector *cloudWires = new CT_PointCloudIndexVector();
cloudWires->setSortType(CT_PointCloudIndexVector::NotSorted);
float minSlope = std::numeric_limits::max();
float maxSlope = -std::numeric_limits::max();
float minRMSE = std::numeric_limits::max();
float maxRMSE = -std::numeric_limits::max();
size_t cptPt = 0;
CT_PointIterator it2(pointCloudIndex);
while (it2.hasNext())
{
it2.next();
const CT_Point& pt = it2.currentPoint();
size_t index = it2.currentGlobalIndex();
QList indexList;
grid->getPointIndicesIncludingKNearestNeighbours(pt, _nbNeigbours, _distMax, indexList);
QMultiMap sortedIndices;
for (int i = 0 ; i < indexList.size() ; i++)
{
size_t neighbIndex = indexList.at(i);
if (neighbIndex != index)
{
const CT_Point& ptNeighb = accessor.constPointAt(neighbIndex);
double dist = sqrt(pow(pt(0) - ptNeighb(0), 2) + pow(pt(1) - ptNeighb(1), 2) + pow(pt(2) - ptNeighb(2), 2));
if (dist < _distMax)
{
sortedIndices.insert(dist, neighbIndex);
}
}
}
QList pts;
QMapIterator itM(sortedIndices);
int cpt = 0;
while (cpt < _nbNeigbours && itM.hasNext())
{
itM.next();
size_t index = itM.value();
const CT_Point& pt = accessor.constPointAt(index);
pts.append(pt);
cpt++;
}
float slope = 0;
float rmse = 0;
if (pts.size() > 2)
{
CT_LineData* line = CT_LineData::staticCreateLineDataFromPointCloud(pts);
Eigen::Vector3d direction = line->getDirection();
direction.normalize();
slope = float(abs(direction(2)));
rmse = float(line->getRMSE());
bool keepSlope = (slope > float(_slopeThreshold));
if (_slopeMax) {keepSlope = (slope < float(_slopeThreshold));}
bool keepRMSE = (rmse > float(_rmseThreshold));
if (_rmseMax) {keepRMSE = (rmse < float(_rmseThreshold));}
if (keepSlope || keepRMSE)
{
cloudKept->addIndex(index);
} else {
cloudWires->addIndex(index);
}
if (slope < minSlope) {minSlope = slope;}
if (slope > maxSlope) {maxSlope = slope;}
if (rmse < minRMSE) {minRMSE = rmse;}
if (rmse > maxRMSE) {maxRMSE = rmse;}
slopeSetter.setValueWithGlobalIndex(index, slope);
rmseSetter.setValueWithGlobalIndex(index, rmse);
} else {
cloudWires->addIndex(index);
}
cptPt++;
}
if (cloudKept->size() > 0)
{
cloudKept->setSortType(CT_PointCloudIndexVector::SortedInAscendingOrder);
CT_Scene *outSceneKept = new CT_Scene(PS_REPOSITORY->registerPointCloudIndex(cloudKept));
outSceneKept->updateBoundingBox();
grp_inG->addSingularItem(_outSceneKept, outSceneKept);
} else {
delete cloudKept;
}
if (cloudWires->size() > 0)
{
cloudWires->setSortType(CT_PointCloudIndexVector::SortedInAscendingOrder);
CT_Scene *outSceneWires = new CT_Scene(PS_REPOSITORY->registerPointCloudIndex(cloudWires));
outSceneWires->updateBoundingBox();
grp_inG->addSingularItem(_outSceneWires, outSceneWires);
} else {
delete cloudWires;
}
grp_inG->addSingularItem(_outSlope, _outSlope.createAttributeInstance(scene->pointCloudIndexRegistered(), minSlope, maxSlope));
grp_inG->addSingularItem(_outRMSE, _outRMSE.createAttributeInstance(scene->pointCloudIndexRegistered(), minRMSE, maxRMSE));
delete grid;
}
}
}