Complete Qt6 migration: full clean build green across groups G1-G12 incl. runtime plugin set

new_docker_build.sh gains Group 12 (212 GUI/Data plugins); fixes LtsUtilsGuiDds visibility (LTO-stripped exports), LtsProjectionWorkstation unity name shadow, 6 unity-off dirs (dup file-scope statics, ddsftc INTERFACE sources) and reconfigures BUILD_FILTERMANAGEMENT/BUILD_PLUGINS_SERVICEMONITOR=ON
This commit is contained in:
berrux-dev committed 2026-10-20 09:36:57 +02:00
1 parent 2b957d1edb
commit 598fc2560e
1718 files changed
+126739 -18495

No files matched your search

@@ -4,34 +4,41 @@
# $Author$
#
# The GDAL-based ElevationMap module is not yet migrated to Qt6 (see the
# commented-out entries in ../CMakeLists.txt). LtsElevation still needs an
# ElevationMapManager, so build the compatibility stub that lives in the
# src/ + include/ scaffolding (same API as the Qt5 class, no GDAL).
NGL_ADD_LIBRARY(WS AAR HLA SV situationMapElevationMap SHARED
${CMAKE_SOURCE_DIR}/src/Viewer/SituationMap/ElevationMap/elevation_map_manager.cpp
# The header lives in include/Viewer/SituationMap/ElevationMap, apart from
# the cpp. AUTOMOC only mocs headers that are target sources (or sit next
# to one); MOC_INCLUDES merely feeds moc's own -I flags, not header
# discovery. Listed explicitly, otherwise the vtable/staticMetaObject are
# undefined and the link of libsituationMapElevationMap.so fails.
${CMAKE_SOURCE_DIR}/include/Viewer/SituationMap/ElevationMap/elevation_map_manager.h
# ElevationMap module. The legacy module is GDAL-backed; GDAL is not part of the
# Qt6 / ArcGIS-300 toolchain. Per the established no-GDAL decision, elevation_map.cpp
# is a no-GDAL stand-in (public API preserved; no DEM data loaded) while the rest of
# the module (ElevationMapManager, line_of_sight_calculation) is the real, GDAL-free
# Qt code. This lets the SituationMap layer (MapImpl/SightFanImpl/ElevationMapManager)
# compile and link against the elevation API.
SET(Elevation_SRCS
elevation_map.cpp
elevation_map.h
elevation_map_helper.h
elevation_map_manager.cpp
elevation_map_manager.h
line_of_sight_calculation.cpp
line_of_sight_calculation.h
)
# The stub's ElevationMapManager is a Q_OBJECT class; without AUTOMOC the
# moc symbols (staticMetaObject/vtable) are missing and the link of
# libsituationMapElevationMap.so fails, cascading to every target that
# links it (same pattern as LtsSessionDataDds).
NGL_ADD_LIBRARY2(AAR SV WS HLA situationMapElevationMap SHARED ${Elevation_SRCS})
set_target_properties(situationMapElevationMap PROPERTIES AUTOMOC ON)
NGL_TARGET_INCLUDE_DIRECTORIES(situationMapElevationMap
PUBLIC
# The stub cpp does #include "elevation_map_manager.h" - it lives in
# include/Viewer/SituationMap/ElevationMap/, not next to the source.
${CMAKE_SOURCE_DIR}/include/Viewer/SituationMap/ElevationMap
${CMAKE_SOURCE_DIR}/include
# Consumers include <ElevationMap/elevation_map.h> and the NGL-generated
# <ElevationMap/situationmapelevationmap_export.h>; the parent source/binary
# dirs put the ElevationMap/ subfolder (and the generated export header) on the path.
${CMAKE_CURRENT_SOURCE_DIR}/../
${CMAKE_CURRENT_BINARY_DIR}/../
)
NGL_TARGET_LINK_LIBRARIES(situationMapElevationMap
PRIVATE
situationMapCommon
Qt6::Concurrent
Qt6::Gui
NGLLogger
LtsCoordTrans
PUBLIC
Qt6::Core
LtsUtilsCoreHeaderOnly
)
@@ -0,0 +1,137 @@
/**
* @RDE_HEADER@
* adapting GeISiR source to SituationMap
* $Id$
* $HeadURL$
* $Author$
*/
#include "elevation_map.h"
#include <QFileInfo>
#include <QPolygonF>
#include <QGuiApplication>
#include <limits>
namespace SituationMap
{
// GDAL is not part of the Qt6/ArcGIS-300 build (no GDAL in the toolchain;
// see the no-GDAL ElevationMap stub decision). This translation unit is the
// no-GDAL stand-in for the legacy GDAL-backed reader: the public API is
// preserved (header unchanged) so consumers (MapImpl, ElevationMapManager,
// SightFanImpl) compile and link; elevation data is simply not loaded, so
// queries return defaults / no-coverage. Everything else in the module
// (ElevationMapManager, line_of_sight_calculation) is real, GDAL-free Qt code.
struct ElevationMap::Internal
{
};
ElevationMap::ElevationMap(const QFileInfo &fileInfo)
: m_internal(new Internal())
, m_fileName(fileInfo.absoluteFilePath())
, m_aproximation(false)
, m_valid(false)
, m_logger(getLogger("ElevationMap"))
{
readFromFile();
}
ElevationMap::~ElevationMap()
{
delete m_internal;
}
bool ElevationMap::waitForInitialization()
{
// No asynchronous GDAL read is started, so initialization is already done.
return true;
}
bool ElevationMap::isValid() const
{
return m_valid;
}
QString ElevationMap::filename() const
{
return m_fileName;
}
QRectF ElevationMap::extent() const
{
return QRectF();
}
QPair<double, double> ElevationMap::elexelSize() const
{
return qMakePair(0.0, 0.0);
}
double ElevationMap::elevation(double, double) const
{
return std::numeric_limits<double>::quiet_NaN();
}
double ElevationMap::distance(const QPointF &start, const QPointF &end) const
{
return (end - start).manhattanLength();
}
double ElevationMap::profileDistance(const QPointF &start, const QPointF &end) const
{
return (end - start).manhattanLength();
}
unsigned int ElevationMap::elevationProfile(const QPointF &, const QPointF &, Vec3dVector &) const
{
return 0;
}
bool ElevationMap::contains(const QPointF &) const
{
return false;
}
bool ElevationMap::intersects(const QPolygonF &) const
{
return false;
}
void ElevationMap::LOSProfile(const QPointF &, const QPointF &, LOSVector &)
{
}
int ElevationMap::getElevation(int, int) const
{
return std::numeric_limits<int>::min();
}
double ElevationMap::getElevation(double, double) const
{
return std::numeric_limits<double>::quiet_NaN();
}
double ElevationMap::getOrSubstituteElevation(int, int, double substitute) const
{
return substitute;
}
void ElevationMap::getSamplePoints(const QPointF &, const QPointF &, Vec3dVector &) const
{
}
int ElevationMap::clipp2Map(const QPointF &, const QPointF &, QPointF &, QPointF &) const
{
return 0;
}
bool ElevationMap::readFromFile()
{
// No GDAL: no DEM is read.
m_valid = false;
return false;
}
} // namespace SituationMap
@@ -0,0 +1,168 @@
/**
* @RDE_HEADER@
* adapting GeISiR source to SituationMap
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "elevation_map_helper.h"
#include <ElevationMap/situationmapelevationmap_export.h>
#include <LtsUtilsCore/qpoint3d.h>
#include <Common/situation_map_logging.h>
#include <QFutureWatcher>
#include <QPointF>
#include <QRectF>
#include <QVector>
class QFileInfo;
namespace SituationMap
{
//------------------------------------------------------------------------------------------------------------
// ElevationMap
//------------------------------------------------------------------------------------------------------------
class SITUATIONMAPELEVATIONMAP_EXPORT ElevationMap final
{
friend class ElevationMapManager;
public:
ElevationMap() = delete;
ElevationMap(const ElevationMap &) = delete;
ElevationMap &operator = (const ElevationMap &) = delete;
explicit ElevationMap(const QFileInfo &fileInfo);
~ElevationMap();
bool waitForInitialization();
bool isValid() const;
QString filename() const;
QRectF extent() const;
QPair<double, double> elexelSize() const;
double elevation(double lon, double lat) const; // rad
double distance(const QPointF &start, const QPointF &end) const;
double profileDistance(const QPointF &start, const QPointF &end) const;
unsigned int elevationProfile(const QPointF &start, const QPointF &end, Vec3dVector &elevProfile) const;
void interpolation(bool on) { m_aproximation = on; }
bool interpolation() const { return m_aproximation; }
bool contains(const QPointF &point) const;
bool intersects(const QPolygonF &polygon) const;
// Line of Sight Profile: berücksichtigt Erdkrümmung und WGS84 Erdellipsoid
void LOSProfile(const QPointF &start, const QPointF &end, LOSVector &losProfile);
protected:
int getElevation(int column, int row) const;
double getElevation(double lon, double lat) const;
double getOrSubstituteElevation(int column, int row, double substitute) const;
// getSamplePoints rastert den Vector( start, end) in Lat/Lon entsprechend dem Höhenraster
void getSamplePoints(const QPointF &start, const QPointF &end, Vec3dVector &sPnts) const;
int clipp2Map(const QPointF &start, const QPointF &end, QPointF &cStart, QPointF &cEnd) const;
bool readFromFile();
struct Internal;
Internal *m_internal;
QString m_fileName;
bool m_aproximation;
bool m_valid;
QFutureWatcher<bool> m_gdalReadWatcher;
LOGGER_T m_logger; ///< Interface of the Logging-Facility
}; // ElevationMap
} // SituationMap
/* -----------------------------------------------------------------------------------------------
** CVS-Id/Release ...: $Header$
** -----------------------------------------------------------------------------------------------
**
** Historie:
**
** $Log: not supported by cvs2svn $
** Revision 1.20 2006/09/26 07:51:12 Jörg
** Syntax Fehler unter Suse Linux 10.1 behoben.
**
** Revision 1.19 2006/03/24 09:05:24 klaus
** Elevationprofile: Begrenzung auf Kartengröße aufgehoben ( Clipping)
**
** Revision 1.18 2005/11/09 11:12:27 klaus
** Anpassung an Linux: Kommentar hinter #endif mit "//" versehen
**
** Revision 1.17 2005/08/22 14:15:02 joerg
** typeId()
**
** Revision 1.16 2005/08/12 09:37:44 joerg
** Koordinaten-Umprojezieren bei Wechsel der Projektion
**
** Revision 1.15 2005/04/15 13:04:35 joerg
** Resource Control
**
** Revision 1.14 2005/03/04 14:29:13 klaus
** Elevationmap mit CachedTileList versehen und automatischem Entladen von Tiles
**
** Revision 1.13 2005/03/03 12:37:14 klaus
** dynamischen Laden und Entladen der ElevationTiles für Reliefmap
**
** Revision 1.12 2005/03/01 12:33:12 klaus
** Reliefmap eingeführt, aus Elevationmap entfernt
**
** Revision 1.11 2005/02/25 15:26:41 klaus
** Ergänzung um Reliefkarte
**
** Revision 1.10 2005/02/10 14:13:21 klaus
** Bias in Basisklasse MapObject überführt
**
** Revision 1.9 2005/02/10 13:51:01 klaus
** Bias für SightFans eingeführt
**
** Revision 1.8 2005/02/09 16:53:06 klaus
** 1. Version der SightFans
**
** Revision 1.7 2005/01/26 12:25:41 klaus
** todos bearbeitet, Fehlerrückmeldnugen
**
** Revision 1.6 2004/12/14 09:43:25 klaus
** 7. Erweiterung für Höhenkarten
**
** Revision 1.5 2004/12/07 11:07:20 klaus
** 5. Erweiterung für Höhenkarten
**
** Revision 1.4 2004/12/03 16:24:12 klaus
** 4. Erweiterung für Höhenkarten
**
** Revision 1.3 2004/11/30 13:15:28 klaus
** 3. Erweiterung für Höhenkarten
**
** Revision 1.2 2004/11/23 14:36:14 klaus
** 2. Erweiterung für Höhenkarten
**
**
** ----------------------------------------------------------------------------------------------- */
@@ -0,0 +1,88 @@
/**
* @RDE_HEADER@
* Some functions and struct for ElevationMap/LineOfSight (LOS)
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <LtsUtilsCore/qpoint3d.h>
#include <math.h>
#include <MathUtils/math_const.h>
#include <QPointF>
#include <QVector>
namespace SituationMap
{
inline bool isInIntervall(double x, double x1, double x2)
{
return (((x > x1) && (x < x2)) || (((x > x2) && (x < x1))));
} // inline bool isInIntervall(double x, double x1, double x2)
inline double radiusWGS84(double lat)
{
double sinLAT = sin(lat);
return (MathConst::WGS84_Major_a * sqrt(1.0 - MathConst::WGS84_SQR_EXC * sinLAT * sinLAT));
} // inline double radiusWGS84(double lat)
inline QPointF distance_in_meter_WGS84(const QPointF &start, const QPointF &end) // start, end in LonLat
{
// todo: prüfen ob Distanz zu groß, dann verbesserte Berechnung !!
double lat = (end.y() + start.y()) / 2.0;
double faktorLon = MathConst::WGS84_Major_a * cos(lat); // radiusWGS84(lat) * 2.0 * PI;
double faktorLat = MathConst::WGS84_Minor_b;
return QPointF(faktorLon * (end.x() - start.x()), faktorLat * (end.y() - start.y()));
} // QPointF distance_in_meter_WGS84(const QPointF &start, const QPointF &end)
inline double squareLength(const QPointF &v)
{
return v.x() * v.x() + v.y() * v.y();
} // inline double squareLength(const QPoint & v)
inline double length(const QPointF &v)
{
return sqrt(squareLength(v));
} // inline double length(const QPoint & v)
struct LOSentry // Defines 1 Entry for Line of Sight
{
LOSentry() = default;
LOSentry(double dist, double height) : _dist(dist), _height(height) { ; }
double &dist() { return _dist; }
double &height() { return _height; }
double dist() const { return _dist; }
double height() const { return _height; }
bool isUndefined() const { return std::isnan(_height); }
private:
double _dist = 0; // Distance from Start
double _height = -NAN;
}; /* LOSentry */
using Point3D = LtsUtils::QPoint3D; ///< x = lon ; y = lat , z = elevation/altitude in meters
using LOSVector = QVector<LOSentry>;
using Vec2dVector = QVector<QPointF>;
using Vec3dVector = QVector<Point3D>;
} // SituationMap
@@ -0,0 +1,531 @@
/**
* @RDE_HEADER@
* Manage and combine several ElevationMap
* $Id$
* $HeadURL$
* $Author$
*/
#include "elevation_map_manager.h"
#include "elevation_map.h"
// Qt
#include <QPointer>
#include <QFileInfo>
#include <QRectF>
#include <QPolygonF>
// system
#include <vector>
namespace SituationMap
{
static long s_counter{0};
//------------------------------------------------------------------------------------------------------------
// ElevationMapManager::Private
//------------------------------------------------------------------------------------------------------------
class ElevationMapManager::Private
{
public:
// fine to rough
std::vector<ElevationMap *> m_elevationMapCont;
QRectF m_simpleExtent;
};
//------------------------------------------------------------------------------------------------------------
// ElevationMapManager
//------------------------------------------------------------------------------------------------------------
ElevationMapManager::ElevationMapManager()
: BaseClass()
, d(new Private())
, m_logger(getLogger("ElevationMapManager"))
{
++s_counter;
TRACE_LOG(m_logger) << LOGFUNCTION << " START, s_counter=" << s_counter << " this=" << this;
TRACE_LOG(m_logger) << LOGFUNCTION << " END, s_counter=" << s_counter << " this=" << this;
}
ElevationMapManager::~ElevationMapManager()
{
--s_counter;
TRACE_LOG(m_logger) << LOGFUNCTION << " START, s_counter=" << s_counter << " this=" << this;
cleanupCurrentContent();
delete d;
d = nullptr;
TRACE_LOG(m_logger) << LOGFUNCTION << " END, s_counter=" << s_counter << " this=" << this;
}
int ElevationMapManager::init(const QStringList &filePaths_rough_to_fine)
{
NOTICE_LOG(m_logger) << LOGFUNCTION << " START" << " filePaths_rough_to_fine=" << filePaths_rough_to_fine.join(QStringLiteral(" ; "));
cleanupCurrentContent();
d->m_elevationMapCont.reserve(filePaths_rough_to_fine.size());
int cnt = 0;
for (const QString &filePath : filePaths_rough_to_fine)
{
QFileInfo fileInfo(filePath);
const QString &fileName = fileInfo.absoluteFilePath();
if (!fileInfo.exists())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " elevation data file \'" << fileName << "\' doesn't exists.";
continue;
}
if (!fileInfo.isReadable())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " elevation data file \'" << fileName << "\' isn't readable.";
continue;
}
// ctor will spawn thread via QtConcurrent and read file async:
d->m_elevationMapCont.insert(d->m_elevationMapCont.begin(), new ElevationMap(fileInfo));
++cnt;
} // for
NOTICE_LOG(m_logger) << LOGFUNCTION << " END" << " filePaths_rough_to_fine=" << filePaths_rough_to_fine.join(QStringLiteral(" ; "))
<< ", following number of files are going to be loaded: " << cnt;
return cnt;
}
void ElevationMapManager::cleanupCurrentContent()
{
qDeleteAll(d->m_elevationMapCont);
d->m_elevationMapCont.clear();
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool ElevationMapManager::waitForInitialization()
{
for (ElevationMap *elevationMap : d->m_elevationMapCont)
elevationMap->waitForInitialization();
return isValid();
}
bool ElevationMapManager::isValid() const
{
bool allAreValid = true;
for (const ElevationMap *elevationMap : d->m_elevationMapCont)
allAreValid = allAreValid && elevationMap->isValid();
// FATAL_LOG(m_logger) << LOGFUNCTION << " allAreValid = " << allAreValid;
return allAreValid;
}
double ElevationMapManager::elevation(double lon_rad, double lat_rad, bool *bIsCovered) const
{
// assume, that all children are ready
for (const ElevationMap *elevationMap : d->m_elevationMapCont)
{
// qCritical() << " EMM::elevation: "
// << " lon_rad=" << lon_rad
// << " lat_rad=" << lat_rad
// << " (try: " << elevationMap->filename() << ")...";
double singleResult = elevationMap->elevation(lon_rad, lat_rad);
if (singleResult > -300) // -300 -> ausserhalb der Höhenkarte !!
{
// qCritical() << " EMM::elevation: elevation= " << singleResult << " (taken from: " << elevationMap->filename() << ")";
if (bIsCovered)
*bIsCovered = true;
return singleResult;
}
}
// DEBUG_LOG(m_logger) << LOGFUNCTION << " invalid= "
// << " lon_rad=" << lon_rad
// << " lat_rad=" << lat_rad;
if (bIsCovered)
*bIsCovered = false;
return std::numeric_limits<double>::min();
}
double ElevationMapManager::elevation(double lon_rad, double lat_rad, double defaultValue, bool *bIsCovered) const
{
bool bIsCoveredLocal = false;
const double elevationValue = elevation(lon_rad, lat_rad, &bIsCoveredLocal);
// in any case: if provided, transfer isCovered back to caller
if (bIsCovered)
*bIsCovered = bIsCoveredLocal;
// which value to be returned?
if (!bIsCoveredLocal)
return defaultValue;
return elevationValue;
}
QRectF ElevationMapManager::simpleUnitedExtent() const
{
if (d->m_simpleExtent.isNull())
{
bool bFirst = true;
for (const ElevationMap *elevationMap : d->m_elevationMapCont)
{
const QRectF &singleExtent = elevationMap->extent();
if (bFirst)
{
bFirst = false;
d->m_simpleExtent = singleExtent;
// qCritical() << " bFirst.left " << singleExtent.left() << " bFirst.right " << singleExtent.right();
// qCritical() << " bFirst.top " << singleExtent.top() << " bFirst.bottom " << singleExtent.bottom();
} else {
// prefer following instead QRectF::united (top vs. bottom):
// qCritical() << " next.left " << singleExtent.left() << " secnextright " << singleExtent.right();
// qCritical() << " next.top " << singleExtent.top() << " next.bottom " << singleExtent.bottom();
d->m_simpleExtent.setLeft (std::min(d->m_simpleExtent.left(), singleExtent.left()));
d->m_simpleExtent.setTop (std::max(d->m_simpleExtent.top(), singleExtent.top())); // top - >use max !!!
d->m_simpleExtent.setBottom(std::min(d->m_simpleExtent.bottom(), singleExtent.bottom())); // bottom -> use min
d->m_simpleExtent.setRight (std::max(d->m_simpleExtent.right(), singleExtent.right()));
}
} // for
}
return d->m_simpleExtent;
}
bool ElevationMapManager::contains(const QPointF &point) const
{
for (const ElevationMap *elevationMap : d->m_elevationMapCont)
{
if (elevationMap->contains(point))
return true;
}
return false;
}
void ElevationMapManager::LOSProfile(const QPointF &start, const QPointF &end, LOSVector &losProfile)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (d->m_elevationMapCont.empty())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no elevationMap";
return;
}
waitForInitialization();
QRectF simpleExtentLocal = simpleUnitedExtent();
// qCritical() << " simpleExtent.left " << simpleExtentLocal.left() << " simpleExtent.right " << simpleExtentLocal.right();
// qCritical() << " simpleExtent.top " << simpleExtentLocal.top() << " simpleExtent.bottom " << simpleExtentLocal.bottom();
if (!simpleExtentLocal.contains(start))
{
ERROR_LOG(m_logger) << LOGFUNCTION << " start coordinate not within area"
<< ", start: x=" << start.x() << " ; y=" << start.y()
<< ", area: "
<< " left " << simpleExtentLocal.left() << ", right " << simpleExtentLocal.right()
<< " top " << simpleExtentLocal.top() << ", bottom " << simpleExtentLocal.bottom()
;
return; // ausserhalb der Höhenkarte !!
}
bool clipped = false;
double totalLng;
QPointF startG = start;
QPointF endG = end;
if (!simpleExtentLocal.contains(end)) // Clippen
{
clipped = true;
totalLng = length(endG - startG);
if (endG.x() < simpleExtentLocal.left())
{
double m = (endG.y() - startG.y()) / (endG.x() - startG.x());
double x = simpleExtentLocal.left();
endG.setX(x);
endG.setY(startG.y() + m * (x - startG.x()));
}
else if (endG.x() > simpleExtentLocal.right())
{
double m = (endG.y() - startG.y()) / (endG.x() - startG.x());
double x = simpleExtentLocal.right();
endG.setX(x);
endG.setY(startG.y() + m * (x - startG.x()));
}
if (endG.y() < simpleExtentLocal.bottom())
{
double m = (endG.x() - startG.x()) / (endG.y() - startG.y());
double y = simpleExtentLocal.bottom();
endG.setY(y);
endG.setX(startG.x() + m * (y - startG.y()));
}
else if (endG.y() > simpleExtentLocal.top())
{
double m = (endG.x() - startG.x()) / (endG.y() - startG.y());
double y = simpleExtentLocal.top();
endG.setY(y);
endG.setX(startG.x() + m * (y - startG.y()));
}
}
// Korrektursteigung aufgrund WGS84 Erdellipsoid, Lineare Approximation, Fehler bis 200 km: < 1.0m
double startRadius = radiusWGS84(startG.y());
double corrM = (radiusWGS84(endG.y()) - startRadius) / length(endG - startG);
//
// getSamplePoints(start, end, elevProfile);
// find best elevationMap for equested path {startG, endG}
//
// 1st find maps covering the desired pathG:
const QPolygonF pathG( QVector<QPointF>{startG, endG} );
std::vector<ElevationMap *> coveredElevationMaps;
coveredElevationMaps.reserve(d->m_elevationMapCont.size());
for (auto curItem : qAsConst(d->m_elevationMapCont))
{
if (curItem && curItem->intersects(pathG))
coveredElevationMaps.push_back(curItem);
} // for
if (m_logger.isDebugEnabled())
{
DEBUG_LOG(m_logger) << " coveredElevationMap.size() = " << coveredElevationMaps.size();
for (auto curItem : qAsConst(coveredElevationMaps))
DEBUG_LOG(m_logger) << " coveredElevationMap = " << curItem->filename();
}
// if no maps covers the desired path, stay on old approach: use most bottom elevation map:
if (coveredElevationMaps.empty())
coveredElevationMaps = d->m_elevationMapCont;
// 2nd: find elevation map with highest resolution to achieve best results:
using ELE_VEC_IT = std::vector<ElevationMap*>::iterator;
ELE_VEC_IT eleIt = coveredElevationMaps.begin();
for (ELE_VEC_IT curItem = coveredElevationMaps.begin()+1; curItem != coveredElevationMaps.end(); ++curItem)
{
ElevationMap *elePtr = *curItem;
if (!elePtr)
continue;
if (elePtr->elexelSize().first < (*eleIt)->elexelSize().first)
eleIt = curItem;
} // for
Q_ASSERT_X((*eleIt), "ElevationMapManager::LOSProfile", "eleIt failed");
Vec3dVector elevProfile;
(*eleIt)->getSamplePoints(start, end, elevProfile);
INFO_LOG(m_logger) << "Using ElevationMap '" << (*eleIt)->filename() << "'"
<< " (of size = " << d->m_elevationMapCont.size() << ")"
<< " with_elexelSize " << (*eleIt)->elexelSize().first
<< " -> # SamplePoints = " << elevProfile.size();
for (Vec3dVector::iterator itr = elevProfile.begin(); itr != elevProfile.end(); ++itr)
{
double dist = length(distance_in_meter_WGS84(start, itr->toPointF()));
double height = elevation(itr->x(), itr->y()); // use elevation over all seperate elevationMaps
height += corrM * dist; // WGS84 Erdellipsoid Korrektur
height -= (startRadius * (1 - cos(atan(dist / startRadius)))); // Einbeziehen der Erdkruemmung
// alternativ als Naeherung: height -= ( dist * dist) / (startRadius * 2.0);
losProfile.push_back(LOSentry(dist, height));
}
if (clipped)
losProfile.push_back(LOSentry(totalLng, -NAN));
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
ElevationMapManager::LineOfSight ElevationMapManager::lineOfSightCalculation(const LOSVector &losProfile,
double centerHat,
double objHat) const
{
// Analog zu SightFanImpl::calculateSightBeam
if (losProfile.size() < 2) // Startpunkt undefiniert oder ausserhalb der Karte
{
return LineOfSight::LOS_ERROR;
}
LOSVector::const_iterator itr = losProfile.begin();
const double centerHeight = itr->height() + centerHat;
double d1 = 0.0;
double height1 = itr->height();
// // überspringen bis _innerRadius erreicht ist !
// while( ++itr != losProfile.end())
// {
// double d2 = itr->dist(); // *EarthRadius;
// double height2 = itr->height();
// if( d2 >= m_internal->m_innerRadius)
// {
// height1 = height1 + (m_internal->m_innerRadius - d1) * ( height2 - height1)/(d2 - d1);
// d1 = m_internal->m_innerRadius;
// --itr;
// break;
// }
// d1 = d2;
// height1 = height2;
// }
// bool visible = true;
// SightMode mode = START;
d1 = itr->dist();
double curM = (height1 - centerHeight ) / d1; // bestimmende Steigung
// sBeam.add( SightEntry( d1, START) );
while (++itr != losProfile.end())
{
double d2 = itr->dist(); // *EarthRadius;
double height2 = itr->height();
if (std::isnan(height2)) // Undefined
{
return LineOfSight::LOS_UNDEFINED;
}
double hObj = (height2 + objHat - centerHeight );
double objM = hObj / d2; // Steigung bezogen auf Objekte( Objekte verdecken nicht !)
LineOfSight newMode = ((objM >= curM)) ? LineOfSight::LOS_VISIBLE : LineOfSight::LOS_INVISIBLE;
if (newMode == LineOfSight::LOS_INVISIBLE)
return LineOfSight::LOS_INVISIBLE;
// if (newMode != mode)
// {
// if ( (mode != LineOfSight::LOS_UNDEFINED) && (d2 != d1) )
// {
// // Korrekturwert für Distanz berechnen, unter Berücksichtigung der Objekthoehe !!
// double localM = (height2 - height1) /(d2 - d1);
// // localM == curM kann nicht auftreten, da newMode != mode
// double dCorr = (hObj - (curM * d2)) / (localM - curM);
// if (dCorr < 0.0)
// dCorr = 0.0;
// dCorr = d2 - dCorr;
// if (dCorr < d1)
// dCorr = d1;
// sBeam.add( SightEntry( dCorr, mode) );
// }
// mode = newMode;
// }
double terrM = (height2 - centerHeight) / d2; // Steigung bezogen auf Gelaende
if (terrM >= curM)
{
curM = terrM; // neue bestimmende Steigung
}
// height1 = height2;
// d1 = d2;
} // while
return LineOfSight::LOS_VISIBLE;
}
ElevationMapManager::LineOfSight ElevationMapManager::lineOfSightCalculation(const LtsUtils::QPoint3D &startPointGeo_absZ,
const LtsUtils::QPoint3D &endPointGeo_absZ)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START" << ", startPointGeo_absZ = " << startPointGeo_absZ << ", endPointGeo_absZ = " << endPointGeo_absZ;
if (!isValid())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " Error, LtsElevationManager not valid";
return LineOfSight::LOS_ERROR;
}
// 1st: a) centerHat / startHat:
const double startHat = startPointGeo_absZ.z() - this->elevation(startPointGeo_absZ.x(), startPointGeo_absZ.y(), -10000);
if (startHat < 0)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " Error, startHat is negativ";
return LineOfSight::LOS_ERROR;
}
// 1st: b) endHat / objHat:
const double endHat = endPointGeo_absZ.z() - this->elevation(endPointGeo_absZ.x(), endPointGeo_absZ.y(), -10000);
if (endHat < 0)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " Error, objHat is negativ"
<< ", startPointGeo_absZ=" << startPointGeo_absZ
<< ", endPointGeo_absZ=" << endPointGeo_absZ;
return LineOfSight::LOS_ERROR;
}
SituationMap::ElevationMapManager::LineOfSight eleMapMgrResult = lineOfSightCalculation(startPointGeo_absZ.toPointF(), startHat,
endPointGeo_absZ.toPointF(), endHat);
TRACE_LOG(m_logger) << LOGFUNCTION << " END" << ", startPointGeo = " << startPointGeo_absZ << ", endPointGeo = " << endPointGeo_absZ
<< " -> LineOfSight " << static_cast<int>(eleMapMgrResult);
return eleMapMgrResult;
}
ElevationMapManager::LineOfSight ElevationMapManager::lineOfSightCalculation(const QPointF &startPointGeo, double startHat,
const QPointF &endPointGeo, double endHat)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
<< ", startPointGeo = " << startPointGeo << ", startHat = " << startHat
<< ", endPointGeo = " << endPointGeo << ", endHat = " << endHat ;
if (!isValid())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " Error, LtsElevationManager not valid";
return LineOfSight::LOS_ERROR;
}
if (startHat < 0)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " Error, startHat is negativ";
return LineOfSight::LOS_ERROR;
}
if (endHat < 0)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " Error, endHat is negativ";
return LineOfSight::LOS_ERROR;
}
// 1st: create LOSVector:
SituationMap::LOSVector losProfile;
LOSProfile(startPointGeo, endPointGeo, losProfile);
if (losProfile.size() < 2)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " Error, losProfile not valid"
<< ", losProfile.size = " << losProfile.size();
return LineOfSight::LOS_ERROR;
}
// 2nd: lineOfSightCalculation
SituationMap::ElevationMapManager::LineOfSight eleMapMgrResult = this->lineOfSightCalculation(losProfile, startHat, endHat);
TRACE_LOG(m_logger) << LOGFUNCTION << " END"
<< ", startPointGeo = " << startPointGeo << ", startHat = " << startHat
<< ", endPointGeo = " << endPointGeo << ", endPointHat = " << endHat
<< " -> LineOfSight " << static_cast<int>(eleMapMgrResult);
return eleMapMgrResult;
}
} // SituationMap
@@ -0,0 +1,84 @@
/**
* @RDE_HEADER@
* Manage and combine several ElevationMap
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "elevation_map_helper.h"
#include <ElevationMap/situationmapelevationmap_export.h>
#include <Common/situation_map_logging.h>
#include <QObject>
namespace SituationMap
{
// forward:
class ElevationMap;
//------------------------------------------------------------------------------------------------------------
// ElevationMapManager
//------------------------------------------------------------------------------------------------------------
class SITUATIONMAPELEVATIONMAP_EXPORT ElevationMapManager final : public QObject
{
using BaseClass = QObject;
public:
ElevationMapManager();
ElevationMapManager(const ElevationMapManager &) = delete;
ElevationMapManager &operator = (const ElevationMapManager &) = delete;
~ElevationMapManager();
int init(const QStringList &filePaths_rough_to_fine);
void cleanupCurrentContent();
bool waitForInitialization();
bool isValid() const;
double elevation(double lon_rad, double lat_rad, bool *bIsCovered = nullptr) const;
double elevation(double lon_rad, double lat_rad, double defaultValue, bool *bIsCovered = nullptr) const;
// united extent of seperate files:
QRectF simpleUnitedExtent() const;
bool contains(const QPointF &point) const;
// Line of Sight Profile: berücksichtigt Erdkrümmung und WGS84 Erdellipsoid
void LOSProfile(const QPointF &start, const QPointF &end, LOSVector &losProfile);
/*! \name Line of Sight */
//@{
enum class LineOfSight { LOS_UNDEFINED,
LOS_ERROR,
LOS_VISIBLE,
LOS_INVISIBLE };
LineOfSight lineOfSightCalculation(const LOSVector &losProfile,
double centerHat,
double objHat) const;
LineOfSight lineOfSightCalculation(const LtsUtils::QPoint3D &startPointGeo_absZ,
const LtsUtils::QPoint3D &endPointGeo_absZ);
LineOfSight lineOfSightCalculation(const QPointF &startPointGeo, double startHat,
const QPointF &endPointGeo, double endHat);
//@}
protected:
class Private;
Private *d;
LOGGER_T m_logger; ///< Interface of the Logging-Facility
}; // ElevationMapManager
} // SituationMap
@@ -0,0 +1,229 @@
/**
* @RDE_HEADER@
* LineOfSightCalculation (L400)
* $Id$
* $HeadURL$
* $Author$
* Created by N. Thoden, NLE, 06.04.2020
*/
#include "line_of_sight_calculation.h"
#include "elevation_map.h"
#include <LtsCoordTrans/lts_coord_trans.h>
//
// ESRI / ARCGIS
// if you link libEsriCommonQt, you propably have to add ArcGISQt5Hack AND: # make sure it's loaded *before* libEsriCommonQt.so
// this may effect all executables linking situationMapElevationMap. CHECK!
//
// Qt
#include <QTimer>
#include <QElapsedTimer>
// some helper functions
inline Q_CONSTEXPR double pi() { return M_PI; }
inline Q_CONSTEXPR double deg2rad() { return pi() / 180.; }
inline Q_CONSTEXPR double rad2deg() { return 1. / deg2rad(); }
namespace SituationMap
{
LineOfSightCalculation::LineOfSightCalculation(ElevationMap *elevationMap)
: m_logger(getLogger("LineOfSightCalculation"))
, m_elevationMap(elevationMap)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
LineOfSightCalculation::~LineOfSightCalculation()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
bool LineOfSightCalculation::calculate(ObserverTargetData &observerTarget, unsigned int sampleIntervallMeter)
{
// same checks:
if (!m_elevationMap || !m_elevationMap->isValid())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no elevationMap configured or not valid";
observerTarget.setLineOfSightVisibility(LineOfSightVisibility::Undefined);
return false;
}
if (!observerTarget.isObserverAndTargetValid())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " observer and/or target not valid";
observerTarget.setLineOfSightVisibility(LineOfSightVisibility::Undefined);
return false;
}
if (observerTarget.observer().toPointF() == observerTarget.target().toPointF())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " observer and target are identical regarding x and y";
observerTarget.setLineOfSightVisibility(LineOfSightVisibility::Undefined);
return false;
}
bool success = true;
QElapsedTimer timer;
if (m_logger.isInfoEnabled())
timer.start();
//
//
// consider using ElevationMap::LOSProfile
//
//
// determine how many iterations we need:
double distanceInMeter = distanceMeter(observerTarget.observer(),
observerTarget.target());
//ERROR_LOG(m_logger) << LOGFUNCTION << " distanceMeter = " << distanceInMeter;
int maxNumberOfIterations = distanceInMeter / sampleIntervallMeter; // check visibility every ~5m
// maxNumberOfIterations = 1000000;
if (maxNumberOfIterations<=0)
maxNumberOfIterations = 5;
double distanceFromObserverToTargetAsFraction = 0;
int i = 0;
while (i<maxNumberOfIterations)
{
++i;
/*
z-axis (Elevation) pCandidate
|---------- /
| ----------
| ----------
| ----------
| ----------
|------------------------------------------------------------ xy-axis
^ ^ ^ ^ ^ ^ ^ ^ samples (every ~5meters)
^ ^
ObserverPosition TargetPosition
On every sample position, check if directLineElevation (maximum) is
obstructed by elevationMapElevation (real value)
if (elevationMapElevation>directLineElevation) -> obstructed/break
*/
distanceFromObserverToTargetAsFraction = (double)i/maxNumberOfIterations;
const Point3D &pCandidate = movePoint(observerTarget.observer(),
observerTarget.target(),
distanceFromObserverToTargetAsFraction);
// {
// static Point3D oldCandidate;
// double distanceInMeter = distanceMeter(pCandidate, oldCandidate);
// ERROR_LOG(m_logger) << LOGFUNCTION << " distanceMeter = " << distanceInMeter;
// oldCandidate = pCandidate;
// }
// z is the elevation of a *direct* line:
const double directLineElevation = pCandidate.z();
const double elevationMapElevation = m_elevationMap->elevation(pCandidate.x(), pCandidate.y());
// Coord covered by elevationMap?
if (elevationMapElevation <= std::numeric_limits<int>::min())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " Error, coordinate not covered be elevationData. Finish this LineOfSightCalculation."
<< " i=" << i
<< ", pCandidate = " << pCandidate;
// write back data
observerTarget.setObstacle(pCandidate);
observerTarget.setLineOfSightVisibility(LineOfSightVisibility::Undefined);
// finish the loop:
success = false;
break;
}
// analyze / check visibility:
if (elevationMapElevation>directLineElevation)
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " i=" << i
<< " break - pCandidate = " << pCandidate
<< " -> directLineElevation = " << directLineElevation
<< " -> elevationMapElevation = " << elevationMapElevation;
// write result
observerTarget.setObstacle(pCandidate);
observerTarget.setLineOfSightVisibility(LineOfSightVisibility::Obstructed);
// finish the loop:
break;
} else {
observerTarget.setLineOfSightVisibility(LineOfSightVisibility::Visible);
}
} // while
if (m_logger.isInfoEnabled())
{
INFO_LOG(m_logger) << LOGFUNCTION << " END"
<< ", success = " << success
<< ", " << i << " of "<< maxNumberOfIterations << " iterations"
<< ", distanceFromObserverToTargetAsFraction = " << distanceFromObserverToTargetAsFraction
<< ", pCandidate=" << observerTarget.obstacle()
<< ", lineOfSightVisibility=" << static_cast<int>(observerTarget.lineOfSightVisibility())
<< ", took [ms] " << timer.elapsed();
}
TRACE_LOG(m_logger) << LOGFUNCTION << " END" << ", success = " << success;
return success;
}
Point3D LineOfSightCalculation::movePoint(const Point3D &oberserver, const Point3D &target, double distanceFromObserverToTargetAsFraction) // 0.0 ... 1.0
{
// positions are lon/lat @ rad.
// for evaluation we do that very simple:
// strange, but: using Point3D seems to be faster then using QPointF
const Point3D &dist = target - oberserver;
const Point3D &point = oberserver + (dist * distanceFromObserverToTargetAsFraction);
return point;
}
double LineOfSightCalculation::distanceMeter(const Point3D &oberserver, const Point3D &target)
{
// Try to avoid the dependency to ESRI (keep ArcGISQt5Hack in mind)
// And good accuracy is not required here
// use LtsCoordTrans::distance
// Esri::ArcGISRuntime::Point geom1(oberserver.x()*rad2deg(), oberserver.y()*rad2deg(), oberserver.z(), Esri::ArcGISRuntime::SpatialReference::wgs84());
// Esri::ArcGISRuntime::Point geom2(target.x() *rad2deg(), target.y() *rad2deg(), target.z() , Esri::ArcGISRuntime::SpatialReference::wgs84());
// Esri::ArcGISRuntime::GeometryEngine *gEngine = Esri::ArcGISRuntime::GeometryEngine::instance();
// Esri::ArcGISRuntime::GeodeticDistanceResult geodeticDistanceResult = gEngine->distanceGeodetic(geom1, geom2,
// Esri::ArcGISRuntime::LinearUnitId::Meters,
// Esri::ArcGISRuntime::AngularUnitId::Degrees,
// Esri::ArcGISRuntime::GeodeticCurveType::Geodesic);
// double distance = geodeticDistanceResult.distance();
double distance = LtsCoordTrans::distance(oberserver.toPointF(), target.toPointF());
return distance;
}
} // namespace SituationMap
@@ -0,0 +1,92 @@
/**
* @RDE_HEADER@
* LineOfSightCalculation (L400)
* $Id$
* $HeadURL$
* $Author$
* Created by N. Thoden, NLE, 06.04.2020
*/
#pragma once
#include <ElevationMap/situationmapelevationmap_export.h>
#include <Common/situation_map_logging.h>
#include <LtsUtilsCore/qpoint3d.h>
using Point3D = LtsUtils::QPoint3D; ///< x = lon ; y = lat , z = elevation/altitude in meters
namespace SituationMap
{
// forward
class ElevationMap;
//----------------------------------------------------------------------------
/*!
\brief Define visibility.
*/
enum class LineOfSightVisibility
{
Undefined, /*!< no data at that location? */
Visible,
Obstructed
};
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
class SITUATIONMAPELEVATIONMAP_EXPORT ObserverTargetData
{
public:
explicit ObserverTargetData(const Point3D &oberserver = Point3D(), // z-value: incl. observerHeight
const Point3D &target = Point3D()) // z-value: incl. targetHeight
: m_oberserver(oberserver)
, m_target(target)
{}
const Point3D &observer() const { return m_oberserver; }
const Point3D &target() const { return m_target; }
const Point3D &obstacle() const { return m_obstacle; }
void setObstacle(const Point3D &obstacle) { m_obstacle = obstacle; }
LineOfSightVisibility lineOfSightVisibility() const { return m_visible; }
void setLineOfSightVisibility(const LineOfSightVisibility &visible) { m_visible = visible; }
bool isObserverAndTargetValid() const { return (!m_oberserver.isNull()) && (!m_target.isNull()); }
private:
Point3D m_oberserver;
Point3D m_target;
Point3D m_obstacle;
LineOfSightVisibility m_visible = LineOfSightVisibility::Undefined;
};
//----------------------------------------------------------------------------
class SITUATIONMAPELEVATIONMAP_EXPORT LineOfSightCalculation
{
public:
explicit LineOfSightCalculation(ElevationMap *elevationMap);
~LineOfSightCalculation();
bool calculate(ObserverTargetData &observerTarget, unsigned int sampleIntervallMeter = 5);
protected:
static Point3D movePoint(const Point3D &oberserver,
const Point3D &target,
double distanceFromObserverToTargetAsFraction);
static double distanceMeter(const Point3D &oberserver,
const Point3D &target);
private:
LOGGER_T m_logger; ///< Interface of the Logging-Facility
ElevationMap *m_elevationMap = nullptr;
ObserverTargetData m_observerTarget;
};
} // namespace SituationMap