#include "onf_stepcomputehillshaderaster.h"
ONF_StepComputeHillShadeRaster::ONF_StepComputeHillShadeRaster() : SuperClass()
{
_azimut = 315.0;
_altitude = 45.0;
}
QString ONF_StepComputeHillShadeRaster::description() const
{
return tr("Créer un raster ombré");
}
QString ONF_StepComputeHillShadeRaster::detailledDescription() const
{
return tr("Formula from https://pro.arcgis.com/fr/pro-app/tool-reference/3d-analyst/how-hillshade-works.htm");
}
QString ONF_StepComputeHillShadeRaster::URL() const
{
//return tr("STEP URL HERE");
return SuperClass::URL(); //by default URL of the plugin
}
CT_VirtualAbstractStep* ONF_StepComputeHillShadeRaster::createNewInstance() const
{
return new ONF_StepComputeHillShadeRaster();
}
QString ONF_StepComputeHillShadeRaster::inputDescription() const
{
return SuperClass::inputDescription() + tr("
");
}
QString ONF_StepComputeHillShadeRaster::outputDescription() const
{
return SuperClass::outputDescription() + tr("
");
}
QString ONF_StepComputeHillShadeRaster::detailsDescription() const
{
return tr("");
}
//////////////////// PROTECTED METHODS //////////////////
void ONF_StepComputeHillShadeRaster::declareInputModels(CT_StepInModelStructureManager& manager)
{
manager.addResult(_inResult, tr("MNE"));
manager.setZeroOrMoreRootGroup(_inResult, _inZeroOrMoreRootGroup);
manager.addGroup(_inZeroOrMoreRootGroup, _inGroup);
manager.addItem(_inGroup, _inDEM, tr("MNE"));
}
void ONF_StepComputeHillShadeRaster::declareOutputModels(CT_StepOutModelStructureManager& manager)
{
manager.addResultCopy(_inResult);
manager.addItem(_inGroup, _outHillShade, tr("Ombrage"));
}
void ONF_StepComputeHillShadeRaster::fillPostInputConfigurationDialog(CT_StepConfigurableDialog* postInputConfigDialog)
{
postInputConfigDialog->addDouble(tr("Azimut"), "°", 0, 360, 2, _azimut);
postInputConfigDialog->addDouble(tr("Altitude"), "°", 0, 90, 2, _altitude);
}
void ONF_StepComputeHillShadeRaster::compute()
{
double zenith_rad = (90.0 - _altitude) * M_PI / 180.0;
double azimuth_math = 360.0 - _azimut + 90.0;
if (azimuth_math >= 360.0) {azimuth_math -= 360.0;}
double azimuth_rad = azimuth_math * M_PI / 180.0;
for (CT_StandardItemGroup* grp : _inGroup.iterateOutputs(_inResult))
{
for (const CT_Image2D* dem : grp->singularItems(_inDEM))
{
if (isStopped()) {return;}
CT_Image2D* hillshade = new CT_Image2D(dem->minX(), dem->minY(), dem->xdim(), dem->ydim(), dem->resolution(), dem->level(), 0, 0);
grp->addSingularItem(_outHillShade, hillshade);
for (int xx = 0 ; xx < hillshade->xdim() ; xx++)
{
for (int yy = 0 ; yy < hillshade->ydim() ; yy++)
{
// formula from https://pro.arcgis.com/fr/pro-app/tool-reference/3d-analyst/how-hillshade-works.htm
float e = dem->value(xx, yy);
if (!qFuzzyCompare(e, dem->NA()))
{
float a = dem->value(xx - 1, yy - 1);
float b = dem->value(xx , yy - 1);
float c = dem->value(xx + 1, yy - 1);
float d = dem->value(xx - 1, yy );
float f = dem->value(xx + 1, yy );
float g = dem->value(xx - 1, yy + 1);
float h = dem->value(xx , yy + 1);
float i = dem->value(xx + 1, yy + 1);
if (qFuzzyCompare(a, dem->NA())) {a = e;}
if (qFuzzyCompare(b, dem->NA())) {b = e;}
if (qFuzzyCompare(c, dem->NA())) {c = e;}
if (qFuzzyCompare(d, dem->NA())) {d = e;}
if (qFuzzyCompare(f, dem->NA())) {f = e;}
if (qFuzzyCompare(g, dem->NA())) {g = e;}
if (qFuzzyCompare(h, dem->NA())) {h = e;}
if (qFuzzyCompare(i, dem->NA())) {i = e;}
float dzdx = ((c + 2.0f*f + i) - (a + 2.0f*d + g)) / (8.0f * float(hillshade->resolution()));
float dzdy = ((g + 2.0f*h + i) - (a + 2.0f*b + c)) / (8.0f * float(hillshade->resolution()));
double slope_radians = std::atan(std::sqrt(double(dzdx)*double(dzdx) + double(dzdy)*double(dzdy)));
double aspect_rad = 0;
if (!qFuzzyCompare(dzdx, 0))
{
aspect_rad = std::atan2(double(dzdy), double(- dzdx));
if (aspect_rad < 0)
{
aspect_rad = 2.0 * M_PI + aspect_rad;
}
} else {
if (dzdy > 0)
{
aspect_rad = M_PI / 2.0;
}
else if (dzdy < 0)
{
aspect_rad = 2.0 * M_PI - M_PI / 2.0;
} else
{
aspect_rad = 0;
}
}
double hillshadeVal = 255.0 * ((cos(zenith_rad) * cos(slope_radians)) + (sin(zenith_rad) * sin(slope_radians) * cos(azimuth_rad - aspect_rad)));
hillshade->setValue(xx, yy, static_cast(hillshadeVal));
}
}
}
hillshade->computeMinMax();
}
}
}