415 lines
12 KiB
C++
Executable File
415 lines
12 KiB
C++
Executable File
/**
|
|
* @RDE_HEADER@
|
|
* Interface-Implementation of TerrainProfile
|
|
* $Id$
|
|
* $HeadURL$
|
|
* $Author$
|
|
*/
|
|
|
|
// Own
|
|
#include "terrain_profile_impl.h"
|
|
#include "terrain_profile_processor.h"
|
|
#include "layer_factory_impl.h"
|
|
#include "coord_translation_functor_impl.h"
|
|
#include <LtsCoordTrans/lts_coord_trans.h>
|
|
#include <LtsWidgets/lts_global_wait_dialog.h>
|
|
|
|
#include "Rubberbands/rubberband_factory.h"
|
|
|
|
|
|
//ESRI
|
|
#include <arcgis/Surface.h>
|
|
|
|
|
|
// Qt
|
|
#include <QList>
|
|
#include <QVector>
|
|
#include <QPair>
|
|
|
|
|
|
#include <functional>
|
|
|
|
namespace SituationMap
|
|
{
|
|
|
|
class TerrainProfileImpl::Private
|
|
{
|
|
public:
|
|
Private() = default;
|
|
~Private() = default;
|
|
|
|
// ESRI data:
|
|
|
|
// Own data:
|
|
SituationMap::MapImpl *m_mapImpl = nullptr;
|
|
Esri::ArcGISRuntime::Surface *m_surface = nullptr;
|
|
|
|
TerrainProfileParameter m_terrainProfileParameter;
|
|
QPointer<RB::RubberbandBase> m_rubbandBase = nullptr;
|
|
|
|
using COUNTER_T = long;
|
|
static COUNTER_T m_terrainProfileCounter;
|
|
QMap<COUNTER_T, QPointer<TerrainProfileProcessor>> m_terrainProfileMap;
|
|
|
|
std::function< bool(long id, const QVector<QPair<QPointF, double>> &)> m_finishedCallback;
|
|
|
|
}; // class TerrainProfileImpl::Private
|
|
//-----------------------------------------------------------------------------
|
|
|
|
TerrainProfileImpl::Private::COUNTER_T TerrainProfileImpl::Private::m_terrainProfileCounter = 0;
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// class TerrainProfileImpl
|
|
//-----------------------------------------------------------------------------
|
|
TerrainProfileImpl::TerrainProfileImpl(SituationMap::MapImpl *mapImpl)
|
|
: BaseClass()
|
|
, QObject()
|
|
, m_logger(getLogger("TerrainProfileImpl"))
|
|
, d(new Private)
|
|
{
|
|
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
|
d->m_mapImpl = mapImpl;
|
|
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
|
}
|
|
|
|
TerrainProfileImpl::~TerrainProfileImpl()
|
|
{
|
|
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
|
this->remove();
|
|
delete d;
|
|
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
|
}
|
|
|
|
bool TerrainProfileImpl::isReady()
|
|
{
|
|
init();
|
|
bool isReady =
|
|
d->m_surface && d->m_surface->loadStatus() == Esri::ArcGISRuntime::LoadStatus::Loaded &&
|
|
d->m_mapImpl->isReady();
|
|
|
|
if (!isReady)
|
|
{
|
|
Esri::ArcGISRuntime::LoadStatus ls = Esri::ArcGISRuntime::LoadStatus::Unknown;
|
|
if (d->m_surface)
|
|
ls = d->m_surface->loadStatus();
|
|
DEBUG_LOG(m_logger) << LOGFUNCTION
|
|
<< " d->m_surface = " << d->m_surface
|
|
<< " d->m_surface->loadStatus = " << ls
|
|
<< " d->m_mapImpl->isReady() = " << d->m_mapImpl->isReady();
|
|
}
|
|
return isReady;
|
|
}
|
|
|
|
void TerrainProfileImpl::setFinishedCallback(const std::function< bool(long id, const QVector<QPair<QPointF, double> > &)> &finishedCallback)
|
|
{
|
|
d->m_finishedCallback = finishedCallback;
|
|
}
|
|
|
|
void TerrainProfileImpl::setTerrainProfileDialog(long id, QPointer<TerrainProfileDialog> &terrainProfileDialog)
|
|
{
|
|
if (!d->m_terrainProfileMap.contains(id))
|
|
{
|
|
ERROR_LOG(m_logger) << LOGFUNCTION
|
|
<< " no proc found for id = " << id;
|
|
return;
|
|
}
|
|
QPointer<TerrainProfileProcessor> proc = d->m_terrainProfileMap[id];
|
|
if (!proc)
|
|
return;
|
|
proc->setTerrainProfileDialog(terrainProfileDialog);
|
|
}
|
|
|
|
bool TerrainProfileImpl::create()
|
|
{
|
|
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
|
|
|
if (!isReady())
|
|
{
|
|
ERROR_LOG(m_logger) << LOGFUNCTION << " failed, not ready";
|
|
return false;
|
|
}
|
|
|
|
// 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;
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
long TerrainProfileImpl::create(const TerrainProfileParameter &terrainProfileParameter)
|
|
{
|
|
DEBUG_LOG(m_logger) << LOGFUNCTION << " START" << " terrainProfileParameter: " << terrainProfileParameter;
|
|
|
|
if (!isReady())
|
|
{
|
|
ERROR_LOG(m_logger) << LOGFUNCTION << " failed, not ready";
|
|
return -1;
|
|
}
|
|
|
|
// remove all former
|
|
this->remove();
|
|
|
|
|
|
// store current values:
|
|
d->m_terrainProfileParameter = terrainProfileParameter;
|
|
|
|
TerrainProfileProcessor *proc = new TerrainProfileProcessor();
|
|
|
|
if (!proc->init(d->m_mapImpl, d->m_terrainProfileCounter))
|
|
{
|
|
ERROR_LOG(m_logger) << LOGFUNCTION << " init of TerrainProfileProcessor failed";
|
|
delete proc;
|
|
return -1;
|
|
}
|
|
d->m_terrainProfileMap[d->m_terrainProfileCounter++] = proc;
|
|
|
|
connect(proc, &TerrainProfileProcessor::locationsToElevationsCompleted,
|
|
this, &TerrainProfileImpl::onLocationsToElevationsCompleted, Qt::UniqueConnection);
|
|
|
|
// GlobalWaitDialog
|
|
LtsWidgets::LtsGlobalWaitDialog::getInstance()->wait();
|
|
|
|
proc->start(d->m_terrainProfileParameter);
|
|
|
|
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
|
return d->m_terrainProfileCounter;
|
|
}
|
|
|
|
void TerrainProfileImpl::remove(long terrainProfileId)
|
|
{
|
|
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
|
|
<< " terrainProfileId=" << terrainProfileId;
|
|
|
|
if (terrainProfileId < 0)
|
|
{
|
|
for (const QPointer<TerrainProfileProcessor> &proc : qAsConst(d->m_terrainProfileMap))
|
|
delete proc;
|
|
d->m_terrainProfileMap.clear();
|
|
return;
|
|
}
|
|
|
|
if (d->m_terrainProfileMap.contains(terrainProfileId))
|
|
{
|
|
QPointer<TerrainProfileProcessor> proc = d->m_terrainProfileMap[terrainProfileId];
|
|
if (proc)
|
|
delete d->m_terrainProfileMap[terrainProfileId];
|
|
d->m_terrainProfileMap.remove(terrainProfileId);
|
|
}
|
|
else
|
|
ERROR_LOG(m_logger) << LOGFUNCTION << " terrainProfileId not found, id=" << terrainProfileId;
|
|
|
|
TRACE_LOG(m_logger) << LOGFUNCTION << " END"
|
|
<< " terrainProfileId=" << terrainProfileId;
|
|
}
|
|
|
|
|
|
void TerrainProfileImpl::init()
|
|
{
|
|
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
|
|
|
if (!d->m_mapImpl)
|
|
{
|
|
ERROR_LOG(m_logger) << LOGFUNCTION << " no mapImpl";
|
|
return;
|
|
}
|
|
|
|
const LayerFactoryImpl &layerFactoryImpl = d->m_mapImpl->layerFactoryImpl();
|
|
if (!d->m_surface)
|
|
d->m_surface = layerFactoryImpl.baseSurface();
|
|
|
|
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
|
}
|
|
|
|
RB::RubberbandMultiPointFeature *TerrainProfileImpl::createRubberband2D()
|
|
{
|
|
// remove any pending/active rubberbands of our map:
|
|
RB::Rubberband::deleteAllActiveRubberbands(d->m_mapImpl);
|
|
|
|
RB::RubberbandMultiPointFeature *rubberband =
|
|
d->m_mapImpl->rubberbandFactory().create<SituationMap::RB::RubberbandMultiPointFeature>(this);
|
|
|
|
if (!rubberband || !rubberband->rubberbandIsAlive())
|
|
{
|
|
ERROR_LOG(m_logger) << LOGFUNCTION << " create2D failed";
|
|
return nullptr;
|
|
}
|
|
rubberband->setAutoDelete(true);
|
|
|
|
connect(rubberband, &SituationMap::RB::Rubberband::abort, this, &TerrainProfileImpl::onRbAbort, Qt::UniqueConnection);
|
|
connect(rubberband, &SituationMap::RB::Rubberband::apply, this, &TerrainProfileImpl::onRb2DApply, Qt::UniqueConnection);
|
|
|
|
return rubberband;
|
|
}
|
|
|
|
/*
|
|
RB::RubberbandMultiPointFeature3D *TerrainProfileImpl::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->constrainQuadratic(true);
|
|
// rubberband->constrainOrthogonal(true);
|
|
|
|
connect(rubberband, &SituationMap::RB::Rubberband::abort, this, &TerrainProfileImpl::onRbAbort, Qt::UniqueConnection);
|
|
connect(rubberband, &SituationMap::RB::Rubberband::apply, this, &TerrainProfileImpl::onRb3DApply, Qt::UniqueConnection);
|
|
|
|
return rubberband;
|
|
}
|
|
*/
|
|
|
|
void TerrainProfileImpl::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 TerrainProfileImpl::onRb2DApply(RB::RubberbandBase *rbnd)
|
|
{
|
|
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
|
if (!rbnd)
|
|
{
|
|
ERROR_LOG(m_logger) << LOGFUNCTION << " no rubberband";
|
|
return;
|
|
}
|
|
|
|
RB::RubberbandMultiPointFeature *polyline = static_cast<RB::RubberbandMultiPointFeature *>(rbnd);
|
|
|
|
TerrainProfileParameter para;
|
|
para.m_coordinates = convert2D3D(polyline->coordinateVector(RB::CoordinateSystem::Geo));
|
|
|
|
long id = this->create(para);
|
|
|
|
if (id < 0)
|
|
ERROR_LOG(m_logger) << LOGFUNCTION << " rubberband failed!?";
|
|
TRACE_LOG(m_logger) << LOGFUNCTION << " END"
|
|
<< " para.m_coordinates.size()= " << para.m_coordinates.size();
|
|
}
|
|
|
|
void TerrainProfileImpl::onLocationsToElevationsCompleted(long id)
|
|
{
|
|
TRACE_LOG(m_logger) << LOGFUNCTION << " START" << ", id=" << id;
|
|
|
|
// GlobalWaitDialog
|
|
LtsWidgets::LtsGlobalWaitDialog::getInstance()->done();
|
|
|
|
const auto it = d->m_terrainProfileMap.find(id);
|
|
|
|
// if (it == d->m_terrainProfileMap.constEnd())
|
|
// {
|
|
// ERROR_LOG(m_logger) << LOGFUNCTION << " rubberband failed!?";
|
|
// return;
|
|
// }
|
|
|
|
QPointer<TerrainProfileProcessor> proc = it.value();
|
|
|
|
if (!proc)
|
|
return;
|
|
|
|
const QVector<QPair<QPointF, double>> &resultList = proc->results();
|
|
|
|
INFO_LOG(m_logger) << LOGFUNCTION << " START"
|
|
<< " id =" << id
|
|
<< " m_locationToElevationBulk.resultList().size()=" << resultList.size();
|
|
|
|
if (d->m_finishedCallback)
|
|
d->m_finishedCallback(id, resultList);
|
|
else
|
|
WARNING_LOG(m_logger) << LOGFUNCTION << " NO exe CallBack!?";
|
|
|
|
TRACE_LOG(m_logger) << LOGFUNCTION << " END" << ", id=" << id;
|
|
}
|
|
|
|
/*
|
|
void TerrainProfileImpl::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 = M_PI / 180.0;
|
|
const QPointF ¢er = data.at(0) * factor;
|
|
viewshedParameter.viewshedOrigin_latLon = center;
|
|
|
|
|
|
if (data.size() >= 2)
|
|
{
|
|
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
|