/****************************************************************************
Copyright (C) 2010-2016 the Office National des Forêts (ONF), France
All rights reserved.
Contact : alexandre.piboule@onf.fr
Developers : Alexandre PIBOULE (ONF)
This file is part of Computree version 2.0.
Computree 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, either version 3 of the License, or
(at your option) any later version.
Computree 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.
You should have received a copy of the GNU General Public License
along with Computree. If not, see .
*****************************************************************************/
#include "onf_stepcomputeocclusionspace.h"
// Inclusion of used ItemDrawable classes
#include "tools/onf_countvisitor.h"
#include "tools/onf_nullifytraversedcellvisitor.h"
#include "ct_log/ct_logmanager.h"
#include
#include
ONF_StepComputeOcclusionsSpace::ONF_StepComputeOcclusionsSpace() : SuperClass()
{
_res = 0.03;
_distThreshold = 0.3;
_gridMode = 3;
_xBase = 0.0;
_yBase = 0.0;
_zBase = 0.0;
_xDim = int(10.0/_res);
_yDim = int(10.0/_res);
_zDim = int(20.0/_res);
}
QString ONF_StepComputeOcclusionsSpace::description() const
{
// Gives the descrption to print in the GUI
return tr("Compute occlusions space");
}
QString ONF_StepComputeOcclusionsSpace::detailledDescription() const
{
return tr("Cette étape calcul les zones d'occlusion : une certain distance derrière les impacts (points). "
"Si un autre rayon passe au même endroit (avant l'impact) l'occlusion est effacée. ");
}
QString ONF_StepComputeOcclusionsSpace::inputDescription() const
{
return SuperClass::inputDescription() + tr("
");
}
QString ONF_StepComputeOcclusionsSpace::outputDescription() const
{
return SuperClass::outputDescription() + tr("
");
}
QString ONF_StepComputeOcclusionsSpace::detailsDescription() const
{
return tr("");
}
CT_VirtualAbstractStep* ONF_StepComputeOcclusionsSpace::createNewInstance() const
{
// Creates an instance of this step
return new ONF_StepComputeOcclusionsSpace();
}
void ONF_StepComputeOcclusionsSpace::declareInputModels(CT_StepInModelStructureManager& manager)
{
manager.addResult(_inResult, tr("Scène(s)"));
manager.setZeroOrMoreRootGroup(_inResult, _inZeroOrMoreRootGroup);
manager.addGroup(_inZeroOrMoreRootGroup, _inRootGroup);
manager.addGroup(_inRootGroup, _inGroup, tr("Scan"));
manager.addItem(_inGroup, _inScene, tr("Scène"));
manager.addItem(_inGroup, _inScanner, tr("Scanner"));
}
void ONF_StepComputeOcclusionsSpace::declareOutputModels(CT_StepOutModelStructureManager& manager)
{
manager.addResultCopy(_inResult);
manager.addItem(_inGroup, _outGrid, tr("Occlusion space"));
}
void ONF_StepComputeOcclusionsSpace::fillPostInputConfigurationDialog(CT_StepConfigurableDialog* postInputConfigDialog)
{
postInputConfigDialog->addDouble(tr("Resolution of the grids"),tr("meters"),0.0001,10000,2, _res );
postInputConfigDialog->addDouble(tr("Distance Threshold"), "m", 0, std::numeric_limits::max(), 4, _distThreshold);
postInputConfigDialog->addEmpty();
postInputConfigDialog->addText(tr("Reference for (minX, minY, minZ) corner of the grid :"),"", "");
CT_ButtonGroup &bg_gridMode = postInputConfigDialog->addButtonGroup(_gridMode);
postInputConfigDialog->addExcludeValue("", "", tr("Default mode : Bounding box of the scene"), bg_gridMode, 0);
postInputConfigDialog->addExcludeValue("", "", tr("Custom mode : Relative to folowing coordinates:"), bg_gridMode, 1);
postInputConfigDialog->addExcludeValue("", "", tr("Custom mode : Relative to folowing coordinates + custom dimensions:"), bg_gridMode, 2);
postInputConfigDialog->addExcludeValue("", "", tr("Custom mode : centered on folowing coordinates + custom dimensions:"), bg_gridMode, 3);
postInputConfigDialog->addDouble(tr("X coordinate:"), "", -std::numeric_limits::max(), std::numeric_limits::max(), 4, _xBase);
postInputConfigDialog->addDouble(tr("Y coordinate:"), "", -std::numeric_limits::max(), std::numeric_limits::max(), 4, _yBase);
postInputConfigDialog->addDouble(tr("Z coordinate:"), "", -std::numeric_limits::max(), std::numeric_limits::max(), 4, _zBase);
postInputConfigDialog->addInt(tr("X dimension:"), "cells", 1, 1000000, _xDim);
postInputConfigDialog->addInt(tr("Y dimension:"), "cells", 1, 1000000, _yDim);
postInputConfigDialog->addInt(tr("Z dimension:"), "cells", 1, 1000000, _zDim);
}
void ONF_StepComputeOcclusionsSpace::compute()
{
for (CT_StandardItemGroup* rootGroup : _inRootGroup.iterateOutputs(_inResult))
{
QMap > pointsOfView;
// Global limits of generated grids
double xMin = std::numeric_limits::max();
double yMin = std::numeric_limits::max();
double zMin = std::numeric_limits::max();
double xMax = -std::numeric_limits::max();
double yMax = -std::numeric_limits::max();
double zMax = -std::numeric_limits::max();
double xMinScene = std::numeric_limits::max();
double yMinScene = std::numeric_limits::max();
double zMinScene = std::numeric_limits::max();
double xMaxScene = -std::numeric_limits::max();
double yMaxScene = -std::numeric_limits::max();
double zMaxScene = -std::numeric_limits::max();
double xMinScanner = std::numeric_limits::max();
double yMinScanner = std::numeric_limits::max();
double zMinScanner = std::numeric_limits::max();
double xMaxScanner = -std::numeric_limits::max();
double yMaxScanner = -std::numeric_limits::max();
double zMaxScanner = -std::numeric_limits::max();
int nscenes = 0;
for (const CT_StandardItemGroup* group : rootGroup->groups(_inGroup))
{
for (const CT_AbstractItemDrawableWithPointCloud* scene : group->singularItems(_inScene))
{
const CT_Scanner* scanner = group->singularItem(_inScanner);
if (scanner != nullptr)
{
nscenes++;
pointsOfView.insert(const_cast(group), QPair(scene, scanner));
Eigen::Vector3d min, max;
scene->boundingBox(min, max);
if (min.x() < xMinScene) {xMinScene = min.x();}
if (min.y() < yMinScene) {yMinScene = min.y();}
if (min.z() < zMinScene) {zMinScene = min.z();}
if (max.x() > xMaxScene) {xMaxScene = max.x();}
if (max.y() > yMaxScene) {yMaxScene = max.y();}
if (max.z() > zMaxScene) {zMaxScene = max.z();}
if (scanner->centerX() < xMinScanner) {xMinScanner = scanner->centerX();}
if (scanner->centerY() < yMinScanner) {yMinScanner = scanner->centerY();}
if (scanner->centerZ() < zMinScanner) {zMinScanner = scanner->centerZ();}
if (scanner->centerX() > xMaxScanner) {xMaxScanner = scanner->centerX();}
if (scanner->centerY() > yMaxScanner) {yMaxScanner = scanner->centerY();}
if (scanner->centerZ() > zMaxScanner) {zMaxScanner = scanner->centerZ();}
}
}
}
if (_gridMode == 0) {
xMin = std::min(xMinScene, xMinScanner);
yMin = std::min(yMinScene, yMinScanner);
zMin = std::min(zMinScene, zMinScanner);
xMax = std::max(xMaxScene, xMaxScanner);
yMax = std::max(yMaxScene, yMaxScanner);
zMax = std::max(zMaxScene, zMaxScanner);
} else if (_gridMode == 1) {
double xMinAdjusted = std::min(xMinScene, xMinScanner);
double yMinAdjusted = std::min(yMinScene, yMinScanner);
double zMinAdjusted = std::min(zMinScene, zMinScanner);
double xMaxAdjusted = std::max(xMaxScene, xMaxScanner);
double yMaxAdjusted = std::max(yMaxScene, yMaxScanner);
double zMaxAdjusted = std::max(zMaxScene, zMaxScanner);
xMin = _xBase;
yMin = _yBase;
zMin = _zBase;
while (xMin < xMinAdjusted) {xMin += _res;}
while (yMin < yMinAdjusted) {yMin += _res;}
while (zMin < zMinAdjusted) {zMin += _res;}
while (xMin > xMinAdjusted) {xMin -= _res;}
while (yMin > yMinAdjusted) {yMin -= _res;}
while (zMin > zMinAdjusted) {zMin -= _res;}
xMax = xMin + _res;
yMax = yMin + _res;
zMax = zMin + _res;
while (xMax < xMaxAdjusted) {xMax += _res;}
while (yMax < yMaxAdjusted) {yMax += _res;}
while (zMax < zMaxAdjusted) {zMax += _res;}
} else if (_gridMode == 2) {
xMin = _xBase;
yMin = _yBase;
zMin = _zBase;
xMax = xMin + _res*_xDim;
yMax = yMin + _res*_yDim;
zMax = zMin + _res*_zDim;
bool enlarged = false;
while (xMin > xMinScanner) {xMin -= _res; enlarged = true;}
while (yMin > yMinScanner) {yMin -= _res; enlarged = true;}
while (zMin > zMinScanner) {zMin -= _res; enlarged = true;}
while (xMax < xMaxScanner) {xMax += _res; enlarged = true;}
while (yMax < yMaxScanner) {yMax += _res; enlarged = true;}
while (zMax < zMaxScanner) {zMax += _res; enlarged = true;}
if (enlarged)
{
PS_LOG->addMessage(LogInterface::warning, LogInterface::step, tr("Dimensions spécifiées ne contenant pas les positions de scans : la grille a du être élargie !"));
}
} else {
xMin = _xBase - _res*_xDim;
yMin = _yBase - _res*_yDim;
zMin = _zBase - _res*_zDim;
xMax = _xBase + _res*_xDim;
yMax = _yBase + _res*_yDim;
zMax = _zBase + _res*_zDim;
bool enlarged = false;
while (xMin > xMinScanner) {xMin -= _res; enlarged = true;}
while (yMin > yMinScanner) {yMin -= _res; enlarged = true;}
while (zMin > zMinScanner) {zMin -= _res; enlarged = true;}
while (xMax < xMaxScanner) {xMax += _res; enlarged = true;}
while (yMax < yMaxScanner) {yMax += _res; enlarged = true;}
while (zMax < zMaxScanner) {zMax += _res; enlarged = true;}
if (enlarged)
{
PS_LOG->addMessage(LogInterface::warning, LogInterface::step, tr("Dimensions spécifiées ne contenant pas les positions de scans : la grille a du être élargie !"));
}
}
xMin -= _res;
yMin -= _res;
zMin -= _res;
xMax += _res;
yMax += _res;
zMax += _res;
// Declaring the output grids
CT_Grid3D_Sparse* occlGrid = CT_Grid3D_Sparse::createGrid3DFromXYZCoords(xMin, yMin, zMin, xMax, yMax, zMax, _res, -1, 0, true);
//group->addSingularItem(occlGrid);
setProgress(10);
int cpt = 0;
int cpt2 = 0;
double progressPart = 40.0 / double(nscenes);
// 1) Count the number of occluded beams traversing the cell within _threshold
QMapIterator > it(pointsOfView);
while (it.hasNext())
{
it.next();
const CT_AbstractItemDrawableWithPointCloud* scene = it.value().first;
const CT_Scanner* scanner =it.value().second;
const CT_AbstractPointCloudIndex *pointCloudIndex = scene->pointCloudIndex();
size_t npts = pointCloudIndex->size();
Eigen::Vector3d bot, top;
occlGrid->getMinCoordinates(bot);
occlGrid->getMaxCoordinates(top);
QList list;
ONF_CountVisitor countVisitor(occlGrid);
list.append(&countVisitor);
// Creates traversal algorithm
CT_Grid3DWooTraversalAlgorithm algo(occlGrid, false, list);
CT_Beam beam;
CT_PointIterator itP(pointCloudIndex);
while (itP.hasNext())
{
const CT_Point &point = itP.next().currentPoint();
Eigen::Vector3d dir = point - scanner->position();
dir.normalize();
Eigen::Vector3d endPoint = point + dir * _distThreshold;
// Get the next ray
beam.setOrigin(point);
beam.setDirection(dir);
if (beam.intersect(bot, top))
{
algo.compute(beam, &endPoint);
}
if (++cpt % 10000 == 0) {setProgress(float(progressPart*cpt / npts + progressPart*cpt2 + 10.0));}
}
++cpt2;
cpt = 0;
}
cpt = 0;
cpt2 = 0;
// 1) Clean cells traversed by beams
it.toFront();
while (it.hasNext() && !isStopped())
{
it.next();
const CT_AbstractItemDrawableWithPointCloud* scene = it.value().first;
const CT_Scanner* scanner =it.value().second;
const CT_AbstractPointCloudIndex *pointCloudIndex = scene->pointCloudIndex();
size_t npts = pointCloudIndex->size();
Eigen::Vector3d bot, top;
occlGrid->getMinCoordinates(bot);
occlGrid->getMaxCoordinates(top);
QList list;
ONF_NullifyTraveserdCellVisitor nullptrifyVisitor(occlGrid);
list.append(&nullptrifyVisitor);
// Creates traversal algorithm
CT_Grid3DWooTraversalAlgorithm algo(occlGrid, false, list);
CT_Beam beam;
CT_PointIterator itP(pointCloudIndex);
while (itP.hasNext())
{
const CT_Point &point = itP.next().currentPoint();
Eigen::Vector3d dir = scanner->position() - point;
dir.normalize();
// Get the next ray
beam.setOrigin(point);
beam.setDirection(dir);
if (beam.intersect(bot, top))
{
Eigen::Vector3d posi = scanner->position();
algo.compute(beam, &posi);
}
if (++cpt % 10000 == 0) {setProgress(float(progressPart*cpt / npts + progressPart*cpt2 + 50.0));}
}
++cpt2;
cpt = 0;
}
occlGrid->computeMinMax();
setProgress(90.0f);
rootGroup->addSingularItem(_outGrid, occlGrid);
}
setProgress(100.0f);
}