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

+587
View File
@@ -0,0 +1,587 @@
/**
* @RDE_HEADER@
* Interface-Implementation of AirSupport
* $Id$
* $HeadURL$
* $Author$
*/
// Own
#include "air_support_impl.h"
#include <MapImpl/map_impl.h>
#include <MapImpl/object_container_impl.h>
#include <MapImpl/layer_factory_impl.h>
#include <GraphicalObjects/graphical_object_path.h>
#include <GraphicalObjects/graphical_object_text.h>
#include <MapObjectsImpl/participant_impl.h>
// ESRI
#include <arcgis/GeometryEngine.h>
#include <arcgis/PolylineBuilder.h>
// Qt
namespace SituationMap
{
const int AIR_SUPPORT_LINE_WIDTH = 2;
class AirSupportImpl::Private
{
public:
Private() = default;
~Private()
{
removeAesBuffer();
removeAFP();
removeALP();
m_pm_AFP = nullptr;
m_pm_ALP = nullptr;
m_aesBuffer = nullptr;
}
// ESRI data:
Esri::ArcGISRuntime::GraphicsOverlay *m_graphicsLayer = nullptr;
// Own data:
MapImpl *m_mapImpl = nullptr;
UniqueMapId m_referencedObject = INVALID_MAP_ID;
QString m_debugInfo; // will be appended by consecutive number
UniqueMapId m_uniqueMapId;
QColor m_color = Qt::black;
GraphicalObjectPictureMarker *m_pm_AFP = nullptr;
GraphicalObjectPictureMarker *m_pm_ALP = nullptr;
GraphicalObjectPath *m_aesBuffer = nullptr;
QMap<int, QSharedPointer<GraphicalObjectPath> > m_cont; /// one polyline per subsidiary line
typedef QMapIterator<int, QSharedPointer<GraphicalObjectPath>> MAP_IT_T;
// int m_drawOrder = 0;
GraphicalObjectPictureMarker *getAFP()
{
if (!m_pm_AFP)
{
QString debugInfo = QStringLiteral("%1#Marker(AFP)").arg(m_debugInfo);
m_pm_AFP = new GraphicalObjectPictureMarker(m_mapImpl->getEsriGeoView(),
m_graphicsLayer,
debugInfo,
m_uniqueMapId);
m_pm_AFP->setMarkerSymbol(MarkerSymbolType::Circle, 10, Qt::black);
}
return m_pm_AFP;
}
void removeAFP()
{
delete m_pm_AFP;
m_pm_AFP = nullptr;
}
GraphicalObjectPictureMarker *getALP()
{
if (!m_pm_ALP)
{
QString debugInfo = QStringLiteral("%1#Marker(ALP)").arg(m_debugInfo);
m_pm_ALP = new GraphicalObjectPictureMarker(m_mapImpl->getEsriGeoView(),
m_graphicsLayer,
debugInfo,
m_uniqueMapId);
m_pm_ALP->setMarkerSymbol(MarkerSymbolType::Circle, 10, Qt::black);
}
return m_pm_ALP;
}
void removeALP()
{
delete m_pm_ALP;
m_pm_ALP = nullptr;
}
GraphicalObjectPath *getAesBuffer()
{
if (!m_aesBuffer)
{
QString debugInfo = QStringLiteral("%1#AesBuffer").arg(m_debugInfo);
m_aesBuffer = new GraphicalObjectPath(GraphicalObjectPathType::Polygon,
m_mapImpl->getEsriGeoView(),
m_graphicsLayer,
debugInfo,
m_uniqueMapId);
m_aesBuffer->setFillStyle(FillStyle(FillPattern::Null));
}
return m_aesBuffer;
}
void removeAesBuffer()
{
delete m_aesBuffer;
m_aesBuffer = nullptr;
}
bool hasPathObject(int key) { return m_cont.contains(key); }
QList<int> keysInUse() { return m_cont.keys(); }
void removePathObject(int key) { m_cont.remove(key); }
void clearPathObjects() { m_cont.clear(); }
QSharedPointer<GraphicalObjectPath> getPathObject(int key)
{
if (m_cont[key].isNull())
{
QString debugInfo = QStringLiteral("%1#SubsidiaryLine(%2)").arg(m_debugInfo).arg(key);
GraphicalObjectPath *temp = new GraphicalObjectPath(GraphicalObjectPathType::Polyline,
m_mapImpl->getEsriGeoView(),
m_graphicsLayer,
debugInfo,
m_uniqueMapId);
if (temp)
m_cont[key] = QSharedPointer<GraphicalObjectPath>(temp);
}
return m_cont[key];
}
}; // class AirSupportImpl::Private
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// class AirSupportImpl
//-----------------------------------------------------------------------------
AirSupportImpl::AirSupportImpl(const QString &debugInfo)
: AirSupport() // Interface
, BaseClass(debugInfo) // Implementation
, d(new Private)
, m_logger(getLogger("AirSupportImpl"))
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
AirSupportImpl::~AirSupportImpl()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
delete d;
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
void AirSupportImpl::setUniqueId(const UniqueMapId &uniqueId)
{
BaseClass::setUniqueId(uniqueId);
d->m_uniqueMapId = m_uniqueMapId;
}
void AirSupportImpl::setReferencedObject(const UniqueMapId &referencedObject)
{
d->m_referencedObject = referencedObject;
}
bool AirSupportImpl::updateViewImpl()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
<< " m_debugInfo=" << m_debugInfo
<< " symbol=" << m_symbol.value().sidc
<< " visibility=" << m_visibility
<< " visiTechn=" << m_visibilityTechnical
<< " visiTact=" << m_visibilityTactical
<< " this->drawOrder=" << this->drawOrder()
<< " this->positions()=" << this->positions();
// m_mainGraphicalObject stores the outline/'bounding box' (techn and tact)
// Those geometry should never be visible.
// The text of should be visible.
this->setVisibilityOfGeometry(false);
if (this->positions().size() < 2)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " number of coordinates is not sufficiant"
<< " (#coord=" << this->positions().size() << ")";
return false;
}
if (m_mainGraphicalObject)
d->m_color = m_mainGraphicalObject->lineStyle().lineColor();
bool success = BaseClass::updateViewImpl();
if (!success)
ERROR_LOG(m_logger) << LOGFUNCTION << " updateViewImpl failed";
// real work:
//
// First, draw AFP and ALP
//
// AFP
{
Point3D coordTranslated = getCoordinateTranslated(COORD_INDEX_AFP);
if (coordTranslated.isNull())
{
d->removeAFP();
} else {
GraphicalObjectPictureMarker *pm = d->getAFP();
pm->setMarkerSymbol(MarkerSymbolType::Circle, 10, d->m_color);
pm->setOrigin(coordTranslated);
pm->setVisibility(m_visibility && m_visibilityTechnical);
pm->setScale(m_mainGraphicalObject->scale());
pm->setDrawOrder(m_mainGraphicalObject->drawOrder());
if (!pm->updateView())
ERROR_LOG(m_logger) << LOGFUNCTION << " updateView failed";
}
}
// ALP
{
Point3D coordTranslated = getCoordinateTranslated(COORD_INDEX_ALP);
if (coordTranslated.isNull())
{
d->removeALP();
} else {
GraphicalObjectPictureMarker *pm = d->getALP();
pm->setMarkerSymbol(MarkerSymbolType::Circle, 10, d->m_color);
pm->setOrigin(coordTranslated);
pm->setVisibility(m_visibility && m_visibilityTechnical);
pm->setScale(m_mainGraphicalObject->scale());
pm->setDrawOrder(m_mainGraphicalObject->drawOrder());
if (!pm->updateView())
ERROR_LOG(m_logger) << LOGFUNCTION << " updateView failed";
}
}
//
// delegate remaining to onMapExtentChanged
//
TRACE_LOG(m_logger) << LOGFUNCTION << " END, success=" << success;
return success;
}
bool AirSupportImpl::onMapExtentChanged()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
bool success = BaseClass::onMapExtentChanged();
if (!m_mainGraphicalObject)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no m_mainGraphicalObject yet";
return false;
}
// 1. create aesBuffer;
updateViewImplBuffer();
// 2. and see, if Alp is within:
bool contains = bufferContainsAlp(); // buffer and alp must exist!!!
DEBUG_LOG(m_logger) << LOGFUNCTION << " buffer contains Alp: " << contains;
// Line Afp Alp
Point3D start = this->getCoordinateTranslated(COORD_INDEX_AFP);
Point3D end = this->getCoordinateTranslated(COORD_INDEX_ALP);
if (end.isNull())
updateViewImplLineAfpAlp(false, Point3D(), Point3D());
else
updateViewImplLineAfpAlp(true, start, end);
// Line Alp Aes
start = this->getCoordinateTranslated(COORD_INDEX_ALP);
end = this->getCoordinateTranslated(COORD_INDEX_AES);
// try to replace end by intersection with Aes:
Point3D intersection = this->intersectionAesAndLineAlpAes();
DEBUG_LOG(m_logger) << " intersectionAes " << intersection;
if (!intersection.isNull())
end = intersection;
// try to replace end by intersection with buffer of Aes:
if (d->m_aesBuffer)
{
intersection = this->intersectionBufferAndLineAlpAes();
DEBUG_LOG(m_logger) << " intersectionBuffer " << intersection;
if (!intersection.isNull())
end = intersection;
}
// Maybe 3rd coordinate is not provided?
if (start.isNull() || end.isNull())
updateViewImplLineAlpAes(false, Point3D(), Point3D());
else
updateViewImplLineAlpAes(!contains, start, end);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return success;
}
bool AirSupportImpl::updateViewImplBuffer()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
DEBUG_LOG(m_logger) << LOGFUNCTION << " pixelSize= " << m_mapImpl->pixelSizeMeter();
if (m_mapImpl->pixelSizeMeter() < 1)
{
d->removeAesBuffer();
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
double bufferDistance = m_mapImpl->pixelSizeMeter() * 100;
DEBUG_LOG(m_logger) << LOGFUNCTION << " bufferDistance= " << bufferDistance;
if (bufferDistance > 2000)
bufferDistance = 2000;
// AesBuffer of referenced object
if (!isUniqueMapIdValid(d->m_referencedObject))
{
// This can happen, if the object is just created:
DEBUG_LOG(m_logger) << LOGFUNCTION << " m_referencedObject is invalid"
<< " (m_referencedObject=" << d->m_referencedObject << ")";
return false;
}
AbstractMapObject *amo = d->m_mapImpl->objectContainer().getObject(d->m_referencedObject);
if (!amo)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " m_referencedObject not found"
<< " (m_referencedObject=" << d->m_referencedObject << ")";
return false;
}
QVector<Point3D> resultVec = MathUtils::GeometryEngine::buffer(amo, bufferDistance);
GraphicalObjectPath *buffer = d->getAesBuffer();
if (buffer)
{
buffer->setVisibility(m_visibility && m_visibilityTechnical);
buffer->setScale(m_mainGraphicalObject->scale());
buffer->setLineStyle(LineStyle(d->m_color, AIR_SUPPORT_LINE_WIDTH, LinePattern::Solid));
buffer->setPositions(resultVec);
buffer->setDrawOrder(m_mainGraphicalObject->drawOrder());
if (!buffer->updateView())
ERROR_LOG(m_logger) << LOGFUNCTION << " updateView failed";
}
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
void AirSupportImpl::updateViewImplLineAfpAlp(bool show, const Point3D &start, const Point3D &end)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (show)
{
QSharedPointer<GraphicalObjectPath> line = d->getPathObject(LINE_INDEX_AFP_ALP);
if (line)
{
line->setVisibility(m_visibility && m_visibilityTechnical);
line->setScale(m_mainGraphicalObject->scale());
line->setDrawOrder(m_mainGraphicalObject->drawOrder());
line->setLineStyle(LineStyle(d->m_color, AIR_SUPPORT_LINE_WIDTH, LinePattern::Dash));
PositionCont posCont;
posCont.reserve(2);
posCont.append(start);
posCont.append(end);
line->setPositions(posCont);
if (!line->updateView())
ERROR_LOG(m_logger) << LOGFUNCTION << " updateView failed";
}
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
else
d->removePathObject(LINE_INDEX_AFP_ALP);
}
void AirSupportImpl::updateViewImplLineAlpAes(bool show, const Point3D &start, const Point3D &end)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (show)
{
QSharedPointer<GraphicalObjectPath> line = d->getPathObject(LINE_INDEX_ALP_AES);
if (line)
{
line->setVisibility(m_visibility && m_visibilityTechnical);
line->setScale(m_mainGraphicalObject->scale());
line->setDrawOrder(m_mainGraphicalObject->drawOrder());
line->setLineStyle(LineStyle(d->m_color, AIR_SUPPORT_LINE_WIDTH, LinePattern::Solid));
PositionCont posCont;
posCont.reserve(2);
posCont.append(start);
posCont.append(end);
line->setPositions(posCont);
if (!line->updateView())
ERROR_LOG(m_logger) << LOGFUNCTION << " updateView failed";
}
}
else
d->removePathObject(LINE_INDEX_ALP_AES);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
bool AirSupportImpl::bufferContainsAlp()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
Esri::ArcGISRuntime::Geometry geoHull;
if (d->m_aesBuffer)
geoHull = d->m_aesBuffer->getGraphicGeometry();
Esri::ArcGISRuntime::Geometry pntToCheck;
if (d->getALP())
pntToCheck = d->getALP()->getGraphicGeometry();
bool contains = false;
if (!geoHull.isEmpty() && !pntToCheck.isEmpty())
contains = Esri::ArcGISRuntime::GeometryEngine::contains(geoHull, pntToCheck);
TRACE_LOG(m_logger) << LOGFUNCTION << " END, contains" << contains;
return contains;
}
Point3D AirSupportImpl::intersectionBufferAndLineAlpAes()
{
Esri::ArcGISRuntime::Geometry geo1;
if (d->m_aesBuffer)
geo1 = d->m_aesBuffer->getGraphicGeometry();
if (geo1.isEmpty())
return Point3D();
Esri::ArcGISRuntime::Geometry geo2 = geometryOfLine(getCoordinateTranslated(COORD_INDEX_ALP),
getCoordinateTranslated(COORD_INDEX_AES));
if (geo2.isEmpty())
return Point3D();
return intersection(geo1, geo2);
}
Point3D AirSupportImpl::intersectionAesAndLineAlpAes()
{
AbstractMapObject *amo = d->m_mapImpl->objectContainer().getObject(d->m_referencedObject);
AbstractMapObjectImpl *mapObjImpl = dynamic_cast<AbstractMapObjectImpl *>(amo);
if (!mapObjImpl)
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " m_referencedObject not found/dynamic_cast failed"
<< " (m_referencedObject=" << d->m_referencedObject << ")";
return Point3D();
}
Esri::ArcGISRuntime::Geometry geo1;
if (mapObjImpl)
geo1 = mapObjImpl->getEsriGeometry();
if (geo1.isEmpty())
return Point3D();
Esri::ArcGISRuntime::Geometry geo2 = geometryOfLine(getCoordinateTranslated(COORD_INDEX_ALP),
getCoordinateTranslated(COORD_INDEX_AES));
if (geo2.isEmpty())
return Point3D();
return intersection(geo1, geo2);
}
Point3D AirSupportImpl::intersection(const Esri::ArcGISRuntime::Geometry &geo1, const Esri::ArcGISRuntime::Geometry &geo2)
{
if (geo1.isEmpty() || geo2.isEmpty())
return Point3D();
Esri::ArcGISRuntime::Geometry geoResult =
Esri::ArcGISRuntime::GeometryEngine::intersection(geo1, geo2);
DEBUG_LOG(m_logger) << LOGFUNCTION << " geoInter = " << geoResult.toJson();
DEBUG_LOG(m_logger) << LOGFUNCTION << " geoInter dimension = " << geoResult.dimension();
Esri::ArcGISRuntime::Point intersectPoint;
if (geoResult.dimension() == 1) // dim 1 -> Lines and Polyline
{
Esri::ArcGISRuntime::Polyline polylineResult(geoResult);
if (polylineResult.parts().part(0).pointCount() > 0)
intersectPoint = polylineResult.parts().part(0).startPoint();
}
else if (geoResult.dimension() == 0)
{
intersectPoint = Esri::ArcGISRuntime::Point(geoResult); // This is not tested yet
}
DEBUG_LOG(m_logger) << LOGFUNCTION << " intersectPoint = " << intersectPoint.toJson();
if (std::isnan(intersectPoint.x()) ||
std::isnan(intersectPoint.y()) ||
std::isnan(intersectPoint.z()))
return Point3D();
Point3D intersection(intersectPoint.x(),
intersectPoint.y(),
intersectPoint.z());
return intersection;
}
Esri::ArcGISRuntime::Geometry AirSupportImpl::geometryOfLine(const Point3D &start, const Point3D &end)
{
Esri::ArcGISRuntime::PolylineBuilder polylineBuilder(m_mapImpl->getEsriSpatialReference());
polylineBuilder.addPoint(Esri::ArcGISRuntime::Point(start.x(), start.y()));
polylineBuilder.addPoint(Esri::ArcGISRuntime::Point(end.x(), end.y()));
const Esri::ArcGISRuntime::Geometry &geo = polylineBuilder.toGeometry();
return geo;
}
bool AirSupportImpl::init(MapImpl *mapImpl, const QString &logicalLayerName)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
// no symbol required
bool success = BaseClass::init(mapImpl, logicalLayerName, GraphicalObjectPathType::Polyline);
setLineStyle(LineStyle(Qt::black, 1));
if (!success)
ERROR_LOG(m_logger) << LOGFUNCTION << " init failed";
// set some values to Private:
d->m_mapImpl = m_mapImpl;
d->m_debugInfo = m_debugInfo;
d->m_uniqueMapId = m_uniqueMapId;
d->m_graphicsLayer = m_graphicsLayer;
TRACE_LOG(m_logger) << LOGFUNCTION << " END, success=" << success;
return success;
}
Point3D AirSupportImpl::getCoordinateTranslated(int idx) const
{
if (idx < 0 || idx > 2)
return Point3D();
const PositionCont &posContTranslated = m_positions.positionsTranslated();
if (idx >= posContTranslated.size())
return Point3D();
return posContTranslated[idx];
}
} // namespace SituationMap