Files
qt5-legatus-legacy/Lts/Viewer/SituationMap/MapImpl/terrain_profile_impl.cpp
T
2026-08-13 18:33:10 +02:00

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 &center = 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