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

366 lines
12 KiB
C++
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* @RDE_HEADER@
* TerrainProfileProcessor
* $Id$
* $HeadURL$
* $Author$
*/
// Own
#include "terrain_profile_processor.h"
#include "map_impl.h"
#include <GraphicalObjects/graphical_object_path.h>
#include <Map/object_factory.h>
#include <Map/situation_map_utils.h>
#include <Map/coord_translation_functor.h>
#include <MapImpl/layer_factory_impl.h>
// ESRI
#include <arcgis/GeometryEngine.h>
#include <arcgis/PolylineBuilder.h>
// Qt
namespace SituationMap
{
//-----------------------------------------------------------------------------
// class ViewshedBase
//-----------------------------------------------------------------------------
TerrainProfileProcessor::TerrainProfileProcessor(QObject *parent)
: QObject(parent)
, m_logger(getLogger("TerrainProfileProcessor"))
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
TerrainProfileProcessor::~TerrainProfileProcessor()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START, id=" << m_id;
removeUserInput();
// maybe clear the view of m_terrainProfileDialog here?
TRACE_LOG(m_logger) << LOGFUNCTION << " END, id=" << m_id;
}
bool TerrainProfileProcessor::init(SituationMap::MapImpl *mapImpl, long id)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
m_id = id;
m_initialized = false;
m_mapImpl = mapImpl;
m_srMap = m_mapImpl->getEsriSpatialReference();
LayerFactoryImpl &layerFactoryImpl = m_mapImpl->layerFactoryImpl();
m_toolsLayername = layerFactoryImpl.toolLayer();
if (!m_surface)
m_surface = layerFactoryImpl.baseSurface();
if (m_surface && m_surface->loadStatus() == Esri::ArcGISRuntime::LoadStatus::Loaded)
m_initialized = true;
else
{
Esri::ArcGISRuntime::LoadStatus ls = Esri::ArcGISRuntime::LoadStatus::Unknown;
if (m_surface)
ls = m_surface->loadStatus();
ERROR_LOG(m_logger) << LOGFUNCTION
<< " d->m_surface = " << m_surface
<< " d->m_surface->loadStatus = " << ls;
}
if (!m_locationToElevationBulk.init(m_mapImpl, m_surface))
{
ERROR_LOG(m_logger) << LOGFUNCTION << " locationToElevationBulk.init() failed";
return false;
}
connect(&m_locationToElevationBulk, &LocationToElevationBulk::locationsToElevationsCompleted,
this, &TerrainProfileProcessor::onLocationsToElevationsCompleted, Qt::UniqueConnection);
TRACE_LOG(m_logger) << LOGFUNCTION << " END" << " m_initialized=" << m_initialized;
return m_initialized;
}
bool TerrainProfileProcessor::start(const TerrainProfileParameter &terrainProfileParameter)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
<< " terrainProfileParameter=" << terrainProfileParameter
<< " m_srMap.wkid=" << m_srMap.wkid();
// don´t allow more than one at once:
if (m_inProgress)
return false;
m_inProgress = true;
m_terrainProfileParameter = terrainProfileParameter;
removeUserInput();
displayUserInput();
// densify
const Esri::ArcGISRuntime::Polyline &polylineOut_Map = densifiy(m_terrainProfileParameter);
// calculate distance
// bulk location to elevation
const Esri::ArcGISRuntime::ImmutablePart &immutablePart = polylineOut_Map.parts().part(0);
const int size = immutablePart.pointCount();
for (int i = 0; i < size; ++i)
{
const Esri::ArcGISRuntime::Point &esriMapLocation = immutablePart.point(i);
// DEBUG_LOG(m_logger) << LOGFUNCTION << " esriMapLocation: " << QPointF(esriMapLocation.x(), esriMapLocation.y());
m_locationToElevationBulk.addLocation(esriMapLocation);
}
m_locationToElevationBulk.start();
TRACE_LOG(m_logger) << LOGFUNCTION << " END" << " m_viewshedInProgress=" << m_inProgress;
return true;
}
QVector<QPair<QPointF, double> > TerrainProfileProcessor::results() const
{
return m_locationToElevationBulk.results();
}
void TerrainProfileProcessor::setTerrainProfileDialog(QPointer<TerrainProfileDialog> &terrainProfileDialog)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
m_terrainProfileDialog = terrainProfileDialog;
if (m_terrainProfileDialog)
{
m_terrainProfileDialog->setMap(m_mapImpl);
// mousePositionChanged
connect(m_terrainProfileDialog.data(), &TerrainProfileDialog::mousePositionChanged,
this, &TerrainProfileProcessor::onDialogMousePositionChanged, Qt::UniqueConnection);
// handle destruction of according dialog:
connect(terrainProfileDialog.data(), &TerrainProfileDialog::destroyed,
this, &TerrainProfileProcessor::deleteLater);
}
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
Esri::ArcGISRuntime::Polyline TerrainProfileProcessor::densifiy(TerrainProfileParameter &terrainProfileParameter)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
<< " terrainProfileParameter=" << terrainProfileParameter;
//
// PosCont to EsriPolyline:
//
Esri::ArcGISRuntime::PolylineBuilder polylineBuilder(m_srMap, this);
for (const Point3D &coord : qAsConst(terrainProfileParameter.m_coordinates))
{
// geo to map (polylineBuilder uses map also)
const Point3D &p3D = m_mapImpl->coordTranslationFunctor()->geographicToMap(coord);
polylineBuilder.addPoint(Esri::ArcGISRuntime::Point(p3D.x(), p3D.y(), p3D.z()));
}
const Esri::ArcGISRuntime::Polyline &polylineIn = polylineBuilder.toPolyline();
terrainProfileParameter.m_length =
Esri::ArcGISRuntime::GeometryEngine::lengthGeodetic(polylineIn,
Esri::ArcGISRuntime::LinearUnit::meters(),
Esri::ArcGISRuntime::GeodeticCurveType::Geodesic);
const int numberCoords = 50;
double maxSegmenthLength = terrainProfileParameter.m_length / numberCoords;
INFO_LOG(m_logger) << LOGFUNCTION << " START"
<< " lengthMeter=" << terrainProfileParameter.m_length
<< " numberCoords=" << numberCoords
<< " maxSegmenthLength=" << maxSegmenthLength;
const Esri::ArcGISRuntime::Geometry &geometryOut = Esri::ArcGISRuntime::GeometryEngine::densifyGeodetic(polylineIn,
maxSegmenthLength,
Esri::ArcGISRuntime::LinearUnit::meters(),
Esri::ArcGISRuntime::GeodeticCurveType::Geodesic);
const Esri::ArcGISRuntime::Polyline polylineOut(geometryOut);
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
<< " lengthMeter=" << terrainProfileParameter.m_length
<< " numberCoords=" << numberCoords
<< " maxSegmenthLength=" << maxSegmenthLength
<< " polylineOut.parts().part(0).pointCount()=" << polylineOut.parts().part(0).pointCount();
return polylineOut;
}
void TerrainProfileProcessor::displayUserInput()
{
displayInputLine();
displayInputVertices();
}
void TerrainProfileProcessor::removeUserInput()
{
removeInputLine();
removeInputVertices();
removeCurrentMarker();
}
void TerrainProfileProcessor::displayInputLine()
{
// create
if (!m_polyline)
{
m_polyline = m_mapImpl->objectFactory().create<Polyline>(m_toolsLayername,
QStringLiteral("TerrainProfileLineId%1").arg(m_id));
m_polyline->setLineStyle(LineStyle(m_color, 3));
m_polyline->setScaleEnable(true);
m_polyline->setPickable(false);
}
// apply data
m_polyline->setPositions(m_terrainProfileParameter.m_coordinates);
// update
if (!m_polyline->updateView())
ERROR_LOG(m_logger) << LOGFUNCTION << " polyline::updateView failed";
}
void TerrainProfileProcessor::removeInputLine()
{
if (m_polyline)
m_polyline->removeMySelf();
m_polyline.reset();
}
void TerrainProfileProcessor::displayInputVertices()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
PositionCont coordinates = m_terrainProfileParameter.m_coordinates;
const int size = coordinates.size();
if (size < 1)
return;
m_markerCont.resize(size);
int idx = 0;
QMutableVectorIterator<RefPointer<GeoImage>> it(m_markerCont);
while (it.hasNext())
{
RefPointer<GeoImage> &marker = it.next();
if (!marker.valid())
{
marker = m_mapImpl->objectFactory().create<GeoImage>(m_toolsLayername,
QStringLiteral("TerrainProfileLineId%1_idx%2").arg(m_id).arg(idx));
marker->setProxyMarker(MarkerSymbolType::Circle);
marker->setProxyMarkerColor(m_color);
marker->setProxyMarkerSize(7);
marker->setPickable(false);
}
marker->setOrigin(coordinates[idx]);
// update
if (!marker->updateView())
ERROR_LOG(m_logger) << LOGFUNCTION << " marker::updateView failed";
++idx;
} // while
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
void TerrainProfileProcessor::removeInputVertices()
{
QMutableVectorIterator<RefPointer<GeoImage>> it(m_markerCont);
while (it.hasNext())
{
RefPointer<GeoImage> &marker = it.next();
if (marker)
marker->removeMySelf();
}
m_markerCont.clear();
}
void TerrainProfileProcessor::displayCurrentMarker(const Point3D &pointGeo)
{
// create
if (!m_currentMarker)
{
m_currentMarker = m_mapImpl->objectFactory().create<GeoImage>(m_toolsLayername,
QStringLiteral("TerrainProfileLineId%1_currentMarker").arg(m_id));
m_currentMarker->setProxyMarker(MarkerSymbolType::Circle);
m_currentMarker->setProxyMarkerColor(Qt::blue);
m_currentMarker->setProxyMarkerSize(10);
m_currentMarker->setPickable(false);
}
// apply data
m_currentMarker->setOrigin(pointGeo);
// update
if (!m_currentMarker->updateView())
ERROR_LOG(m_logger) << LOGFUNCTION << " m_currentMarker::updateView failed";
}
void TerrainProfileProcessor::removeCurrentMarker()
{
if (m_currentMarker)
m_currentMarker->removeMySelf();
m_currentMarker.reset();
}
void TerrainProfileProcessor::onLocationsToElevationsCompleted()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START" << " m_locationToElevationBulk.size()=" << m_locationToElevationBulk.size();
const QVector<QPair<QPointF, double>> &results = m_locationToElevationBulk.results();
if (m_logger.isDebugEnabled())
for (const QPair<QPointF, double> &item : qAsConst(results))
DEBUG_LOG(m_logger) << LOGFUNCTION << " location = " << item.first << " elevation = " << item.second;
TRACE_LOG(m_logger) << LOGFUNCTION << " START" << " results.size()=" << results.size();
// The caller should set TerrainProfileDialog on this signal:
emit locationsToElevationsCompleted(m_id);
// maybe (better hopefully) the caller (via finishedCallback of TerrainProfileImpl)
// has updated our m_terrainProfileParameter !?!
if (m_terrainProfileDialog)
{
m_terrainProfileDialog->setData(this->results());
QVector<QPointF> marks;
marks.reserve(m_terrainProfileParameter.m_coordinates.size());
for (const Point3D &coord : qAsConst(m_terrainProfileParameter.m_coordinates))
{
// geo to map
const Point3D &p3D = m_mapImpl->coordTranslationFunctor()->geographicToMap(coord);
marks.append(p3D.toPointF());
}
m_terrainProfileDialog->setMarks(marks);
} else {
ERROR_LOG(m_logger) << LOGFUNCTION << " no dialog";
}
m_inProgress = false;
}
void TerrainProfileProcessor::onDialogMousePositionChanged(const QPointF &curPos)
{
const Point3D &curPosGeo = Point3D::fromQPointF( m_mapImpl->coordTranslationFunctor()->mapToGeographic(curPos) );
displayCurrentMarker(curPosGeo);
}
} // namespace SituationMap