Initial commit

This commit is contained in:
torsten committed 2026-08-13 18:33:10 +02:00
commit b7d90b9afe
16245 files changed
+3396666

No files matched your search

+880
View File
@@ -0,0 +1,880 @@
/**
* @RDE_HEADER@
* Interface-Implementation of Viewshed
* $Id$
* $HeadURL$
* $Author$
*/
// Own
#include "viewshed_impl.h"
#include "viewshed_analysis.h"
#include "viewshed_geo_processing.h"
#include "layer_factory_impl.h"
#include "coord_translation_functor_impl.h"
#include <LtsCoordTrans/lts_coord_trans.h>
#include <Map/object_factory.h>
#include <Map/sight_fan.h>
#include <MathUtils/math_const.h>
#include <MathUtils/simple_helper.h>
#include "Rubberbands/rubberband_factory.h"
// Qt
namespace SituationMap
{
class ViewshedImpl::Private
{
public:
Private() = default;
~Private() = default;
// ESRI data:
// Own data:
SituationMap::MapImpl *m_mapImpl = nullptr;
QPointer<RB::RubberbandBase> m_rubbandBase = nullptr;
QString m_url;
Esri::ArcGISRuntime::GraphicsOverlay *m_graphicsLayer = nullptr; // graphicsLayer used in 2D
ViewshedParameter m_viewshedParameter;
using COUNTER_T = long;
static COUNTER_T m_viewshedCounter;
QMap<COUNTER_T, ViewshedBase* > m_viewshedMap;
QMap<COUNTER_T, SightFan*> m_sightFanMap;
}; // class ViewshedImpl::Private
//-----------------------------------------------------------------------------
ViewshedImpl::Private::COUNTER_T ViewshedImpl::Private::m_viewshedCounter = 0;
//-----------------------------------------------------------------------------
// class ViewshedImpl
//-----------------------------------------------------------------------------
ViewshedImpl::ViewshedImpl(SituationMap::MapImpl *mapImpl)
: BaseClass()
, m_logger(getLogger("ViewshedImpl"))
, d(new Private)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
d->m_mapImpl = mapImpl;
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
ViewshedImpl::~ViewshedImpl()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
this->remove();
delete d;
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
void ViewshedImpl::setViewshedUrl(const QString &viewshedServiceUrl)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START, viewshedServiceUrl='" << viewshedServiceUrl << "'";
d->m_url = viewshedServiceUrl;
if (d->m_url.isEmpty())
{
// only demo!!! 10.2.6!? http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Elevation/ESRI_Elevation_World/GPServer/Viewshed
// only demo!!! V100.2 https://sampleserver6.arcgisonline.com/arcgis/rest/services/Elevation/ESRI_Elevation_World/GPServer/Viewshed
d->m_url = QLatin1String("https://sampleserver6.arcgisonline.com/arcgis/rest/services/Elevation/ESRI_Elevation_World/GPServer/Viewshed"); // only demo!!!
}
TRACE_LOG(m_logger) << LOGFUNCTION << " END, d->m_url'" << d->m_url << "'";
}
bool ViewshedImpl::isReady()
{
init();
bool isReady = (d->m_graphicsLayer) && d->m_mapImpl->isReady();
if (!isReady)
{
DEBUG_LOG(m_logger) << LOGFUNCTION
<< " d->m_url.isEmpty() = " << d->m_url.isEmpty()
<< " d->m_graphicsLayer = " << d->m_graphicsLayer
<< " d->m_mapImpl->isReady() = " << d->m_mapImpl->isReady();
}
return isReady;
}
bool ViewshedImpl::create()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (!isReady())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " failed, not ready";
return false;
}
// remove all former
this->remove();
// remove any pending/active rubberbands of our map:
RB::Rubberband::deleteAllActiveRubberbands(d->m_mapImpl);
// d->m_rubbandBase; should be cleared now
const Mode mode = d->m_mapImpl->mode();
switch (mode) {
case Mode::Mode_2D:
d->m_rubbandBase = createRubberband2D();
break;
case Mode::Mode_3D:
d->m_rubbandBase = createRubberband3D();
break;
default:
ERROR_LOG(m_logger) << LOGFUNCTION << " mode (" << mode << ")" << " does not support viewshed";
return false;
}
return true;
}
bool ViewshedImpl::create(double alpha, double innerRadius, double observerHeight, double targetHeight, double beamAngle)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (!isReady())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " failed, not ready";
return false;
}
if (alpha < 0.0) alpha = 0.0;
if (alpha > 1.0) alpha = 1.0;
if (beamAngle < 0.5) beamAngle = 0.5;
// remove all former
this->remove();
// remove any pending/active rubberbands of our map:
RB::Rubberband::deleteAllActiveRubberbands(d->m_mapImpl);
d->m_viewshedParameter.innerRadius = innerRadius;
d->m_viewshedParameter.observerHeight = observerHeight;
d->m_viewshedParameter.targetHeight = targetHeight;
d->m_viewshedParameter.dAngle = beamAngle*MathConst::pi/180.0; // grad to rad
d->m_viewshedParameter.alpha = alpha;
const Mode mode = d->m_mapImpl->mode();
switch (mode) {
case Mode::Mode_2D:
d->m_rubbandBase = createSightFanRubberband2D();
break;
case Mode::Mode_3D:
d->m_rubbandBase = createSightFanRubberband3D();
break;
default:
ERROR_LOG(m_logger) << LOGFUNCTION << " mode (" << mode << ")" << " does not support viewshed";
return false;
}
return true;
// d->m_rubbandBase; should be cleared now
}
long ViewshedImpl::create(const ViewshedParameter &viewshedParameter)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
<< " viewshedParameter: " << viewshedParameter;
if (!isReady())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " failed, not ready";
return -1;
}
// store current values:
d->m_viewshedParameter = viewshedParameter;
ViewshedBase *viewshed = nullptr;
// GPU-based viewshed (viewshedAnalysis) is today supported for 3D only:
const Mode mode = d->m_mapImpl->mode();
switch (mode) {
case Mode::Mode_2D:
viewshed = create_viewshedGP(d->m_viewshedParameter);
break;
case Mode::Mode_3D:
viewshed = create_viewshedAnalysis(d->m_viewshedParameter);
break;
default:
ERROR_LOG(m_logger) << LOGFUNCTION << " mode (" << mode << ")" << " does not support viewshed";
return -1;
}
if (!viewshed)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " creation of viewshed failed" << " mode (" << mode << ")";
return -1;
}
d->m_viewshedMap[++d->m_viewshedCounter] = viewshed;
emit viewshedFinished(d->m_viewshedCounter);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return d->m_viewshedCounter;
} // long ViewshedImpl::create(const ViewshedParameter &viewshedParameter)
bool ViewshedImpl::modify(long viewshedId, double alpha, double innerRadius, double observerHeight, double targetHeight, double beamAngle)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (!isReady())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " failed, not ready";
return false;
}
if (alpha < 0.0) alpha = 0.0;
if (alpha > 1.0) alpha = 1.0;
if (beamAngle < 0.5) beamAngle = 0.5;
if (viewshedId < 0) viewshedId = d->m_viewshedCounter;
if (d->m_sightFanMap.contains(viewshedId))
{
SightFan *sightFan = d->m_sightFanMap[viewshedId];
d->m_viewshedParameter.innerRadius = innerRadius;
d->m_viewshedParameter.observerHeight = observerHeight;
d->m_viewshedParameter.targetHeight = targetHeight;
d->m_viewshedParameter.dAngle = beamAngle * MathConst::pi / 180.0; // grad to rad
d->m_viewshedParameter.noBeams = MathConst::pi_two / d->m_viewshedParameter.dAngle;
d->m_viewshedParameter.alpha = alpha;
sightFan->setAlpha( d->m_viewshedParameter.alpha );
sightFan->setInnerRadius( d->m_viewshedParameter.innerRadius );
sightFan->setCenterHat( d->m_viewshedParameter.observerHeight );
sightFan->setObjectHat( d->m_viewshedParameter.targetHeight );
sightFan->setdeltaAngle( d->m_viewshedParameter.dAngle );
sightFan->setNoOfFans( d->m_viewshedParameter.noBeams );
sightFan->show();
return true;
}
return false;
} // bool ViewshedImpl::modify(long viewshedId, double alpha, double innerRadius, double observerHeight, double targetHeight, double beamAngle)
ViewshedBase *ViewshedImpl::create_viewshedGP(const ViewshedParameter &viewshedParameter)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
<< " viewshedParameter: " << viewshedParameter;
if (!d->m_graphicsLayer)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no graphicsLayer for viewshed";
return nullptr;
}
if (d->m_url.isEmpty())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no url for viewshed";
return nullptr;
}
ViewshedGeoProcessing *viewshed = new ViewshedGeoProcessing(d->m_url, d->m_graphicsLayer, d->m_mapImpl->getEsriSpatialReference());
if (!viewshed->init(d->m_mapImpl))
{
ERROR_LOG(m_logger) << LOGFUNCTION << " init failed";
delete viewshed;
return nullptr;
}
// coordTranslation:
CoordTranslationFunctor *coordTransFunctor = d->m_mapImpl->coordTranslationFunctor();
const QPointF &viewshedPointTranslated = coordTransFunctor ? coordTransFunctor->geographicToMap(viewshedParameter.viewshedOrigin_latLon) : QPointF();
DEBUG_LOG(m_logger) << LOGFUNCTION
<< " viewshedParameter= " << viewshedParameter;
if (!viewshed->execute(viewshedPointTranslated, // Map-Coord
viewshedParameter.outerRadius,
viewshedParameter.observerHeight))
{
ERROR_LOG(m_logger) << LOGFUNCTION << " executing GeoProcessing viewshed failed.";
delete viewshed;
return nullptr;
}
return viewshed;
} // ViewshedBase *ViewshedImpl::create_viewshedGP(const ViewshedParameter &viewshedParameter)
ViewshedBase *ViewshedImpl::create_viewshedAnalysis(const ViewshedParameter &viewshedParameter)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
<< " viewshedParameter: " << viewshedParameter;
if (!d->m_mapImpl->getEsriSceneGraphicsView())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " getEsriSceneGraphicsView failed for viewsheds";
return nullptr;
}
ViewshedAnalysis *viewshed = new ViewshedAnalysis(d->m_mapImpl->getEsriSceneGraphicsView());
// rad to degree
const double factor = 180 / MathConst::pi;
const QPointF &centerDegree = viewshedParameter.viewshedOrigin_latLon * factor;
if (!viewshed->execute(centerDegree, // degree
viewshedParameter.outerRadius,
viewshedParameter.observerHeight))
{
ERROR_LOG(m_logger) << LOGFUNCTION << " executing analysis viewshed failed.";
delete viewshed;
return nullptr;
}
return viewshed;
} // ViewshedBase *ViewshedImpl::create_viewshedAnalysis(const ViewshedParameter &viewshedParameter)
void ViewshedImpl::remove(long viewshedId)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
<< " viewshedId=" << viewshedId;
//if (viewshedId < 0)
{
// ok, not special viewshed is adressed --> remove all
for (ViewshedBase *viewshed : qAsConst(d->m_viewshedMap))
delete viewshed;
d->m_viewshedMap.clear();
for (SightFan *sightFan : qAsConst(d->m_sightFanMap))
{
if (sightFan)
sightFan->removeMySelf();
}
d->m_sightFanMap.clear();
return;
}
if (d->m_viewshedMap.contains(viewshedId))
{
delete d->m_viewshedMap[viewshedId];
d->m_viewshedMap.remove(viewshedId);
TRACE_LOG(m_logger) << LOGFUNCTION << " END"
<< " viewshedId=" << viewshedId;
return;
}
if (d->m_sightFanMap.contains(viewshedId))
{
d->m_sightFanMap[viewshedId]->removeMySelf();
d->m_sightFanMap[viewshedId] = nullptr;
d->m_sightFanMap.remove(viewshedId);
TRACE_LOG(m_logger) << LOGFUNCTION << " END"
<< " viewshedId=" << viewshedId;
return;
}
ERROR_LOG(m_logger) << LOGFUNCTION << " viewShedId not found, id=" << viewshedId;
}
ViewshedParameter ViewshedImpl::getViewshedParameter(long viewshedId, bool *ok) const
{
if (ok)
*ok = false;
if (viewshedId < 0)
viewshedId = d->m_viewshedCounter;
if (d->m_sightFanMap.contains(viewshedId))
{
const SightFan *sightFan = d->m_sightFanMap[viewshedId];
if (sightFan)
{
ViewshedParameter vp;
vp.viewshedOrigin_latLon = sightFan->center();
vp.observerHeight = sightFan->centerHat();
vp.targetHeight = sightFan->objectHat();
vp.innerRadius = sightFan->innerRadius();
vp.outerRadius = sightFan->radius();
vp.startAngle = sightFan->startAngle();
vp.dAngle = sightFan->dAngle();
vp.alpha = sightFan->alpha();
vp.noBeams = sightFan->noOfFans();
if (ok)
*ok = true;
return vp;
}
}
return d->m_viewshedParameter;
} // const ViewshedParameter & ViewshedImpl::getViewshedParameter(long viewshedId = -1, bool *ok = nullptr)
void ViewshedImpl::init()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (!d->m_graphicsLayer)
{
LayerFactoryImpl &layerFactory = d->m_mapImpl->layerFactoryImpl();
const QString &toolsLayername = layerFactory.toolLayer();
d->m_graphicsLayer = layerFactory.getGraphicsLayer(toolsLayername);
}
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
RB::RubberbandEllipse *ViewshedImpl::createRubberband2D()
{
// remove any pending/active rubberbands of our map:
RB::Rubberband::deleteAllActiveRubberbands(d->m_mapImpl);
RB::RubberbandEllipse *rubberband =
d->m_mapImpl->rubberbandFactory().create<SituationMap::RB::RubberbandEllipse>(this);
if (!rubberband || !rubberband->rubberbandIsAlive())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " create2D failed";
return nullptr;
}
rubberband->setAutoDelete(true);
rubberband->constrainQuadratic(true);
rubberband->constrainOrthogonal(true);
// rubberband->minWidth(radiusMin * 2); // Should be 2*radiusMin
// rubberband->maxWidth(radiusMax * 2); // Should be 2*radiusMax
connect(rubberband, &SituationMap::RB::Rubberband::abort, this, &ViewshedImpl::onRbAbort, Qt::UniqueConnection);
connect(rubberband, &SituationMap::RB::Rubberband::apply, this, &ViewshedImpl::onRb2DApply, Qt::UniqueConnection);
return rubberband;
}
RB::RubberbandEllipse *ViewshedImpl::createSightFanRubberband2D()
{
// remove any pending/active rubberbands of our map:
RB::Rubberband::deleteAllActiveRubberbands(d->m_mapImpl);
RB::RubberbandEllipse *rubberband =
d->m_mapImpl->rubberbandFactory().create<SituationMap::RB::RubberbandEllipse>(this);
if (!rubberband || !rubberband->rubberbandIsAlive())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " create2D failed";
return nullptr;
}
rubberband->setAutoDelete(true);
rubberband->constrainQuadratic(true);
rubberband->constrainOrthogonal(true);
rubberband->enableSector(false); // set enableSector to true to allow sector sight fans instead of full circles
rubberband->minWidth(d->m_viewshedParameter.innerRadius * 3); // radius should be larger than innerRadius
// rubberband->maxWidth(radiusMax * 2); // Should be 2*radiusMax
connect(rubberband, &SituationMap::RB::Rubberband::abort, this, &ViewshedImpl::onRbAbort, Qt::UniqueConnection);
connect(rubberband, &SituationMap::RB::Rubberband::apply, this, &ViewshedImpl::onSightFanRb2DApply, Qt::UniqueConnection);
return rubberband;
} // RB::RubberbandEllipse *ViewshedImpl::createSightFanRubberband2D()
RB::RubberbandMultiPointFeature3D *ViewshedImpl::createSightFanRubberband3D()
{
// remove any pending/active rubberbands of our map:
RB::Rubberband::deleteAllActiveRubberbands(d->m_mapImpl);
RB::RubberbandMultiPointFeature3D *rubberband =
d->m_mapImpl->rubberbandFactory().create3D<RB::RubberbandMultiPointFeature3D>(this);
if (!rubberband || !rubberband->rubberbandIsAlive())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " create3D failed";
return nullptr;
}
rubberband->setAutoDelete(true);
rubberband->enableCircular(true);
// rubberband->constrainQuadratic(true);
// rubberband->constrainOrthogonal(true);
connect(rubberband, &SituationMap::RB::Rubberband::abort, this, &ViewshedImpl::onRbAbort, Qt::UniqueConnection);
connect(rubberband, &SituationMap::RB::Rubberband::apply, this, &ViewshedImpl::onSightFanRb3DApply, Qt::UniqueConnection);
return rubberband;
} // RB::RubberbandMultiPointFeature3D *ViewshedImpl::createSightFanRubberband3D()
RB::RubberbandMultiPointFeature3D *ViewshedImpl::createRubberband3D()
{
// remove any pending/active rubberbands of our map:
RB::Rubberband::deleteAllActiveRubberbands(d->m_mapImpl);
RB::RubberbandMultiPointFeature3D *rubberband =
d->m_mapImpl->rubberbandFactory().create3D<RB::RubberbandMultiPointFeature3D>(this);
if (!rubberband || !rubberband->rubberbandIsAlive())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " create3D failed";
return nullptr;
}
rubberband->setAutoDelete(true);
rubberband->enableCircular(true);
// rubberband->constrainQuadratic(true);
// rubberband->constrainOrthogonal(true);
connect(rubberband, &SituationMap::RB::Rubberband::abort, this, &ViewshedImpl::onRbAbort, Qt::UniqueConnection);
connect(rubberband, &SituationMap::RB::Rubberband::apply, this, &ViewshedImpl::onSightFanRb3DApply, Qt::UniqueConnection);
return rubberband;
}
void ViewshedImpl::onRbAbort(RB::RubberbandBase *rbnd)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (!rbnd)
return;
DEBUG_LOG(m_logger) << LOGFUNCTION << " rb abort";
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
void ViewshedImpl::onSightFanRb2DApply(RB::RubberbandBase *rbnd)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (!rbnd)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no rubberband";
return;
}
RB::RubberbandEllipse *ellipse = static_cast<RB::RubberbandEllipse *>(rbnd);
const QString &toolLayerName = d->m_mapImpl->layerFactoryImpl().toolLayer();
double diameter;
double dummy;
QPointF direction;
ellipse->rectangleParameter( d->m_viewshedParameter.viewshedOrigin_latLon, diameter, dummy, direction );
if (diameter > 0.0)
{
d->m_viewshedParameter.outerRadius = diameter * 0.5;
if (ellipse->hasSector())
{
double startAngle = SituationMap::MathUtils::getMathAngle(ellipse->sectorStart());
double endAngle = SituationMap::MathUtils::getMathAngle(ellipse->sectorEnd());
if (startAngle > endAngle)
{
startAngle -= MathConst::pi_two;
}
d->m_viewshedParameter.noBeams = ceil( (endAngle - startAngle) / d->m_viewshedParameter.dAngle );
d->m_viewshedParameter.startAngle = startAngle;
}
else
{
d->m_viewshedParameter.startAngle = 0.0;
d->m_viewshedParameter.noBeams = MathConst::pi_two / d->m_viewshedParameter.dAngle;
}
ObjectFactory &objFac = d->m_mapImpl->objectFactory();
SightFan *sightFan = objFac.create<SituationMap::SightFan>(toolLayerName).take();
if (sightFan)
{
sightFan->initFan( d->m_viewshedParameter.viewshedOrigin_latLon
, d->m_viewshedParameter.observerHeight
, d->m_viewshedParameter.targetHeight
, d->m_viewshedParameter.outerRadius
, d->m_viewshedParameter.innerRadius
, d->m_viewshedParameter.startAngle
, d->m_viewshedParameter.dAngle
, d->m_viewshedParameter.noBeams
, d->m_viewshedParameter.alpha );
long sightFanId = ++d->m_viewshedCounter;
d->m_sightFanMap[sightFanId] = sightFan;
emit viewshedFinished(sightFanId);
// create a RubberbandPointFeature to let the user move around the sight fan
RB::RubberbandPointFeature *moveRB = d->m_mapImpl->rubberbandFactory().create<RB::RubberbandPointFeature>(this);
if (moveRB)
{
moveRB->setAutoDelete(true);
moveRB->enableModificationState();
moveRB->setCoordinateVector(QVector<QPointF>() << sightFan->center());
std::function<bool(SituationMap::RB::RubberbandBase*)> moveSightFan = [this, sightFanId](SituationMap::RB::RubberbandBase* rbBase) -> bool
{
SituationMap::RB::RubberbandPointFeature *rubberPFeat = dynamic_cast<SituationMap::RB::RubberbandPointFeature*>(rbBase);
SightFan * sightFan = d->m_sightFanMap[sightFanId];
if (nullptr == sightFan)
{
if (rubberPFeat) rubberPFeat->deleteMySelf();
return false;
}
if (rubberPFeat)
{
const QPointF & loc = rubberPFeat->singleCoordinate();
sightFan->move(loc);
}
return true;
};
moveRB->installExternalUpdate(moveSightFan);
}
} // if sightFan
} // if diameter
} // void ViewshedImpl::onSightFanRb2DApply(RB::RubberbandBase *rbnd)
void ViewshedImpl::onSightFanRb3DApply(RB::RubberbandBase *rbnd)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (!rbnd)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no rubberband";
return;
}
RB::RubberbandMultiPointFeature3D *rubberband = static_cast<RB::RubberbandMultiPointFeature3D *>(rbnd);
const QString &toolLayerName = d->m_mapImpl->layerFactoryImpl().toolLayer();
const QVector<QPointF> &data = rubberband->coordinateVector(RB::CoordinateSystem::Map); // 3D -> RB::CoordinateSystem::Map -> degree
if (data.isEmpty())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " rubberband failed!?";
return;
}
if (data.size() < 2)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " insufficiant number of coords";
return;
}
ViewshedParameter viewshedParameter;
// degree to rad
const double factor = MathConst::pi / 180.0;
const QPointF &center = data.at(0) * factor;
// viewshedParameter.viewshedOrigin_latLon = center;
{
static Esri::ArcGISRuntime::GeometryEngine *gEngine = Esri::ArcGISRuntime::GeometryEngine::instance();
const Esri::ArcGISRuntime::SpatialReference &sr = d->m_mapImpl->getEsriSpatialReference();
QPointF coord = data.at(0);
Esri::ArcGISRuntime::Point geom1(coord.x(), coord.y(), sr);
coord = data.at(1);
Esri::ArcGISRuntime::Point geom2(coord.x(), coord.y(), sr);
Esri::ArcGISRuntime::GeodeticDistanceResult geodeticDistanceResult = gEngine->distanceGeodetic(geom1, geom2,
Esri::ArcGISRuntime::LinearUnitId::Meters,
Esri::ArcGISRuntime::AngularUnitId::Degrees,
Esri::ArcGISRuntime::GeodeticCurveType::Geodesic);
viewshedParameter.outerRadius = geodeticDistanceResult.distance();
}
unsigned int noBeams = floor((MathConst::pi_two) / d->m_viewshedParameter.dAngle);
ObjectFactory &objFac = d->m_mapImpl->objectFactory();
RefPointer<SightFan> objRef = objFac.create<SituationMap::SightFan>(toolLayerName);
SightFan *sightFan = objRef.get();
if (sightFan)
{
if (d->m_viewshedParameter.innerRadius*1.5 > viewshedParameter.outerRadius)
{
viewshedParameter.outerRadius = d->m_viewshedParameter.innerRadius*1.5;
}
sightFan->initFan(center
, d->m_viewshedParameter.observerHeight
, d->m_viewshedParameter.targetHeight
, viewshedParameter.outerRadius
, d->m_viewshedParameter.innerRadius
, 0.0
, d->m_viewshedParameter.dAngle
, noBeams
, d->m_viewshedParameter.alpha );
long sightFanId = ++d->m_viewshedCounter;
d->m_sightFanMap[sightFanId] = sightFan;
emit viewshedFinished(sightFanId);
// create a RubberbandPointFeature3D to let the user move around the sight fan
RB::RubberbandPointFeature3D *moveRB = d->m_mapImpl->rubberbandFactory().create3D<RB::RubberbandPointFeature3D>(this);
if (moveRB)
{
moveRB->setAutoDelete(true);
moveRB->enableModificationState();
moveRB->setCoordinateVector(QVector<QPointF>() << sightFan->center());
std::function<bool(SituationMap::RB::RubberbandBase*)> moveSightFan3D = [this, sightFanId](SituationMap::RB::RubberbandBase* rbBase) -> bool
{
SituationMap::RB::RubberbandPointFeature3D *rubberPFeat = dynamic_cast<SituationMap::RB::RubberbandPointFeature3D*>(rbBase);
SightFan * sightFan = d->m_sightFanMap[sightFanId];
if (nullptr == sightFan)
{
if (rubberPFeat) rubberPFeat->deleteMySelf();
return false;
}
if (rubberPFeat)
{
const QPointF & loc = rubberPFeat->singleCoordinate();
sightFan->move(loc);
}
return true;
};
moveRB->installExternalUpdate(moveSightFan3D);
}
}
} // void ViewshedImpl::onSightFanRb3DApply(RB::RubberbandBase *rbnd)
void ViewshedImpl::onRb2DApply(RB::RubberbandBase *rbnd)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (!rbnd)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no rubberband";
return;
}
RB::RubberbandEllipse *ellipse = static_cast<RB::RubberbandEllipse *>(rbnd);
const QVector<QPointF> &data = ellipse->rectangleVerticies();
const LtsCoordTrans::UtmCoordinate p0(LtsCoordTrans::UtmCoordinate::fromGeographic(data.at(0)));
const LtsCoordTrans::UtmCoordinate p1(LtsCoordTrans::UtmCoordinate::fromGeographic(data.at(2), p0.zone));
const QPointF &center = ellipse->centerPoint();
double radius = fabs((p0.x - p1.x) / 2);
// 23.03.2018, N. Thoden
// LegatusBremen201803151510.gpk contains dem with cell size of ~ 50m
// So the inner_radius has to be >= 50m
// And of course: outer_radius > inner_radius
// So outerRadius > 60
if (radius < 100.0)
radius = 100.0;
ViewshedParameter viewshedParameter;
viewshedParameter.viewshedOrigin_latLon = center;
viewshedParameter.outerRadius = radius;
long id = this->create(viewshedParameter);
if (id < 0)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " rubberband failed!?";
}
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
void ViewshedImpl::onRb3DApply(RB::RubberbandBase *rbnd)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (!rbnd)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no rubberband";
return;
}
RB::RubberbandMultiPointFeature3D *rubberband = static_cast<RB::RubberbandMultiPointFeature3D *>(rbnd);
const QVector<QPointF> &data = rubberband->coordinateVector(RB::CoordinateSystem::Map); // 3D -> RB::CoordinateSystem::Map -> degree
if (data.isEmpty())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " rubberband failed!?";
return;
}
if (data.size() < 2)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " insufficiant number of coords";
return;
}
ViewshedParameter viewshedParameter;
// degree to rad
const double factor = MathConst::pi / 180.0;
const QPointF &center = data.at(0) * factor;
viewshedParameter.viewshedOrigin_latLon = center;
{
static Esri::ArcGISRuntime::GeometryEngine *gEngine = Esri::ArcGISRuntime::GeometryEngine::instance();
const Esri::ArcGISRuntime::SpatialReference &sr = d->m_mapImpl->getEsriSpatialReference();
QPointF coord = data.at(0);
Esri::ArcGISRuntime::Point geom1(coord.x(), coord.y(), sr);
coord = data.at(1);
Esri::ArcGISRuntime::Point geom2(coord.x(), coord.y(), sr);
Esri::ArcGISRuntime::GeodeticDistanceResult geodeticDistanceResult = gEngine->distanceGeodetic(geom1, geom2,
Esri::ArcGISRuntime::LinearUnitId::Meters,
Esri::ArcGISRuntime::AngularUnitId::Degrees,
Esri::ArcGISRuntime::GeodeticCurveType::Geodesic);
viewshedParameter.outerRadius = geodeticDistanceResult.distance();
}
long id = this->create(viewshedParameter);
if (id < 0)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " rubberband failed!?";
}
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
} // namespace SituationMap