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

+517
View File
@@ -0,0 +1,517 @@
/**
* @RDE_HEADER@
* Interface-Implementation of ObjectIndicator
* $Id$
* $HeadURL$
* $Author$
*/
// Own
#include "object_indicator_impl.h"
#include <MapImpl/map_impl.h>
#include <Map/bounding_box.h>
#include <Map/object_factory.h>
#include <MapImpl/abstract_map_object_impl.h>
#include <ElevationMap/elevation_map_manager.h>
#include <MathUtils/simple_helper.h>
// ESRI
#include <arcgis/MapGraphicsView.h>
#include <arcgis/SceneGraphicsView.h>
// Qt
#include <QGraphicsView>
#include <cassert>
namespace SituationMap
{
//-----------------------------------------------------------------------------
// class ObjectIndicatorImpl
//-----------------------------------------------------------------------------
ObjectIndicatorImpl::ObjectIndicatorImpl()
: BaseClass()
, m_logger(getLogger("ObjectIndicatorImpl"))
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
m_markerSize = 15; // size of filled circle at the origin (indicating the center of the map)
m_lineWidth = 3; // lineWidth of (dashed) line from origin to target
// updateTimer:
m_updateTimer = new QTimer(this);
m_updateTimer->setSingleShot(true);
m_updateTimer->setInterval(100);
connect(m_updateTimer, &QTimer::timeout, this, &ObjectIndicatorImpl::updateImpl);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
bool ObjectIndicatorImpl::init(MapImpl *mapImpl)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
m_mapImpl = mapImpl;
if (!m_mapImpl)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " m_map_impl is nullptr, init failed";
return false;
}
// to ensure graceful shutdown: (remove QGraphicsItems BEFORE qGraphicsScene/qGraphicsView is destroyed:
connect(m_mapImpl, &Map::beginDestroy, this, &ObjectIndicatorImpl::onMapDestroyed, Qt::UniqueConnection);
m_qGraphicsView = static_cast<QGraphicsView *>(m_mapImpl->getEsriQGraphicsView());
if (m_qGraphicsView)
m_qGraphicsScene = m_qGraphicsView->scene();
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
ObjectIndicatorImpl::~ObjectIndicatorImpl()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
remove();
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
UniqueMapId ObjectIndicatorImpl::mapObjectToPointTo()
{
return m_uniqueIdToPointTo;
}
void ObjectIndicatorImpl::setMapObjectToPointTo(const UniqueMapId &newUniqueId, bool setSelected, int lifetimeMsec)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START, newUniqueId = " << newUniqueId
<< ", (old m_uniqueIdToPointTo = " << m_uniqueIdToPointTo
<< ", lifetimeMsec=" << lifetimeMsec;
m_targetGeo2D = QPointF();
connect(m_mapImpl, &MapImpl::extentChangedDelayed,
this, &ObjectIndicatorImpl::update, Qt::UniqueConnection);
if (m_uniqueIdToPointTo != newUniqueId)
{
addRemoveCallback(m_uniqueIdToPointTo, AddRemove::Remove);
m_uniqueIdToPointTo = newUniqueId;
addRemoveCallback(m_uniqueIdToPointTo, AddRemove::Add);
}
update();
if (m_lifetimeTimer)
m_lifetimeTimer->stop();
if (lifetimeMsec > 1)
{
if (!m_lifetimeTimer)
{
m_lifetimeTimer = new QTimer(this);
m_lifetimeTimer->setSingleShot(true);
connect(m_lifetimeTimer.data(), &QTimer::timeout, this, &ObjectIndicatorImpl::remove); // lifetime expired
}
m_lifetimeTimer->setInterval(lifetimeMsec);
m_lifetimeTimer->start();
}
m_setSelected = setSelected;
if (m_setSelected)
setMapObjectSelected(m_setSelected);
TRACE_LOG(m_logger) << LOGFUNCTION << " END, newUniqueId = " << newUniqueId;
}
void ObjectIndicatorImpl::setPointToPointTo(const QPointF &targetGeo, int lifetimeMsec)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START, targetGeo = " << targetGeo
<< ", lifetimeMsec=" << lifetimeMsec;
connect(m_mapImpl, &MapImpl::extentChangedDelayed,
this, &ObjectIndicatorImpl::update, Qt::UniqueConnection);
clearCurrentSelection();
addRemoveCallback(m_uniqueIdToPointTo, AddRemove::Remove);
m_uniqueIdToPointTo = INVALID_MAP_ID;
m_targetGeo2D = targetGeo;
update();
if (m_lifetimeTimer)
m_lifetimeTimer->stop();
if (lifetimeMsec > 1)
{
if (!m_lifetimeTimer)
{
m_lifetimeTimer = new QTimer(this);
m_lifetimeTimer->setSingleShot(true);
connect(m_lifetimeTimer.data(), &QTimer::timeout, this, &ObjectIndicatorImpl::remove); // lifetime expired
}
m_lifetimeTimer->setInterval(lifetimeMsec);
m_lifetimeTimer->start();
}
}
void ObjectIndicatorImpl::clearCurrentSelection()
{
ObjectContainer &objCont = m_mapImpl->objectContainer();
const QList<ObjectContainer::Object*> &allObj = objCont.getAllObjects();
for (ObjectContainer::Object* mapObj : allObj)
{
if (!mapObj)
continue;
if (!mapObj->selected())
continue;
mapObj->setSelected(false);
mapObj->updateView();
}
}
bool ObjectIndicatorImpl::update()
{
if (!m_updateTimer)
return false;
m_updateTimer->start(); // start is restart
return true;
}
bool ObjectIndicatorImpl::updateImpl()
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " START"
<< ", m_uniqueIdToPointTo = " << m_uniqueIdToPointTo;
if (!m_qGraphicsView)
return false;
if (!m_qGraphicsScene)
return false;
if (!SituationMap::isUniqueMapIdValid(m_uniqueIdToPointTo) && m_targetGeo2D.isNull())
return false;
//
// Line:
//
Point3D targetGeo;
QColor color = m_defaultColor;
// center:
bool targetIsValid = false;
if (!m_targetGeo2D.isNull())
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " target: m_targetGeo2D= " << m_targetGeo2D;
targetGeo = Point3D::fromQPointF(m_targetGeo2D);
targetIsValid = true;
} else {
DEBUG_LOG(m_logger) << LOGFUNCTION << " target: m_uniqueIdToPointTo= " << m_uniqueIdToPointTo;
if (!SituationMap::isUniqueMapIdValid(m_uniqueIdToPointTo))
return false;
targetIsValid = centerOfTarget(targetGeo, color);
}
QRectF rect = m_qGraphicsScene->sceneRect();
DEBUG_LOG(m_logger) << LOGFUNCTION << " rect: " << rect;
QBrush brush(color, Qt::SolidPattern);
QPen pen(brush, m_lineWidth, Qt::DashLine);
QPointF targetSceneCoordinate;
if (targetIsValid)
{
if (m_mapImpl->getElevationMapManager())
{
const double ele = m_mapImpl->getElevationMapManager()->elevation(targetGeo.x(), targetGeo.y());
targetGeo.rz() += ele; // targetGeo should contain an absolute z-value
}
QPointF targetWindowCoord = m_mapImpl->geoCoordinateToViewPortWindowPoint3D(targetGeo);
targetSceneCoordinate = m_qGraphicsView->mapToScene(targetWindowCoord.toPoint());
if (targetSceneCoordinate.isNull())
{
INFO_LOG(m_logger) << LOGFUNCTION << " targetSceneCoordinate invisible!!!?";
targetSceneCoordinate = rect.center();
}
QLineF lineData(rect.center(), targetSceneCoordinate);
if (!m_qGraphicsLine)
m_qGraphicsLine = m_qGraphicsScene->addLine(lineData, pen);
m_qGraphicsLine->setLine(lineData);
m_qGraphicsLine->setPen(pen);
DEBUG_LOG(m_logger) << LOGFUNCTION
<< ", rect.center() " << rect.center()
<< ", bCenterOfTarget " << targetIsValid
<< ", targetGeo:" << targetGeo
<< ", targetSceneCoordinate " << targetSceneCoordinate;
}
else
{
delete m_qGraphicsLine;
m_qGraphicsLine = nullptr;
targetSceneCoordinate = rect.center();
}
//
// ArrowTip:
//
m_arrowTip = QPixmap::fromImage(renderArrowHeadSymbol(color, 30, 10));
if (!m_qGraphicsArrowTip)
{
m_qGraphicsArrowTip = m_qGraphicsScene->addPixmap(m_arrowTip);
m_qGraphicsArrowTip->setOffset(m_arrowTip.width() / -2.0, 0);
}
m_qGraphicsArrowTip->setPixmap(m_arrowTip);
m_qGraphicsArrowTip->setPos(targetSceneCoordinate);
const double lineAngle = MathUtils::getAngleDegreeNorth(targetSceneCoordinate, rect.center());
const double angle = 360.0 - (lineAngle);
DEBUG_LOG(m_logger) << LOGFUNCTION << ", lineAngle " << lineAngle
<< ", angle " << angle;
// Sets the clockwise rotation angle, in degrees, around the Z axis.
m_qGraphicsArrowTip->setRotation(angle);
//
// centerMarker:
//
rect = QRect(rect.center().x() - m_markerSize * 0.5, rect.center().y() - m_markerSize * 0.5,
m_markerSize, m_markerSize);
if (!m_qGraphicsCenterMarker)
m_qGraphicsCenterMarker = m_qGraphicsScene->addEllipse(rect, pen, brush);
m_qGraphicsCenterMarker->setRect(rect);
m_qGraphicsCenterMarker->setPen(QPen(color, Qt::DashLine));
m_qGraphicsCenterMarker->setBrush(brush);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
void ObjectIndicatorImpl::onMapDestroyed()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
remove();
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
AbstractMapObjectImpl *ObjectIndicatorImpl::getObject(const UniqueMapId &uniqueId)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START, uniqueId = " << uniqueId;
if (!SituationMap::isUniqueMapIdValid(uniqueId))
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " uniqueId invalid: " << uniqueId;
return nullptr;
}
if (!m_mapImpl->objectFactory().contains(uniqueId))
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " m_uniqueIdToPointTo not found: " << m_uniqueIdToPointTo;
return nullptr;
}
AbstractMapObjectImpl *impl = dynamic_cast<AbstractMapObjectImpl *>(m_mapImpl->objectFactory().idToMapObject(uniqueId));
TRACE_LOG(m_logger) << LOGFUNCTION << " END, uniqueId = " << uniqueId;
return impl;
}
bool ObjectIndicatorImpl::addRemoveCallback(const UniqueMapId &uniqueId, AddRemove addRemove)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START, uniqueId = " << uniqueId
<< " addRemove = " << (int)addRemove;
if (!SituationMap::isUniqueMapIdValid(uniqueId))
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " uniqueId invalid: " << uniqueId;
return false;
}
AbstractMapObjectImpl *impl = getObject(uniqueId);
if (!impl)
return false;
const QString &objToPointToDebugInfo = impl->debugInfo();
DEBUG_LOG(m_logger) << LOGFUNCTION << " uniqueId is valid, uniqueId=" << uniqueId
<< ", (objToPointToDebugInfo=" << objToPointToDebugInfo << ")";
if (addRemove == AddRemove::Add)
impl->addChangedCallback(this);
else
impl->removeChangedCallback(this);
TRACE_LOG(m_logger) << LOGFUNCTION << " END, uniqueId = " << uniqueId
<< ", addRemove = " << (int)addRemove;
return true;
}
void ObjectIndicatorImpl::remove()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START, m_uniqueIdToPointTo=" << m_uniqueIdToPointTo;
disconnect(this);
if (m_updateTimer)
m_updateTimer->stop();
addRemoveCallback(m_uniqueIdToPointTo, AddRemove::Remove);
// if we set the object selected, remove selection
if (m_setSelected)
setMapObjectSelected(false);
m_uniqueIdToPointTo = INVALID_MAP_ID;
m_targetGeo2D = QPointF();
delete m_qGraphicsCenterMarker;
delete m_qGraphicsLine;
delete m_qGraphicsArrowTip;
m_qGraphicsCenterMarker = nullptr;
m_qGraphicsLine = nullptr;
m_qGraphicsArrowTip = nullptr;
updateImpl();
TRACE_LOG(m_logger) << LOGFUNCTION << " END, m_uniqueIdToPointTo=" << m_uniqueIdToPointTo;
}
void ObjectIndicatorImpl::onOriginPositionChanged()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " update...";
update();
}
bool ObjectIndicatorImpl::centerOfTarget(Point3D &objCenterPoint, QColor &objColor)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
//
// point to desired obj:
//
RefPointer<AbstractMapObject> objToPointTo;
if (!SituationMap::isUniqueMapIdValid(m_uniqueIdToPointTo))
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " m_uniqueIdToPointTo invalid: " << m_uniqueIdToPointTo;
return false;
}
if (!m_mapImpl->objectFactory().contains(m_uniqueIdToPointTo))
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " m_uniqueIdToPointTo not found: " << m_uniqueIdToPointTo;
return false;
}
objToPointTo = m_mapImpl->objectFactory().get(m_uniqueIdToPointTo);
// retrive values from objToPointTo:
if (!objToPointTo.valid())
{
WARNING_LOG(m_logger) << LOGFUNCTION << " objToPointTo not found";
return false;
}
AbstractMapObjectImpl *impl = dynamic_cast<AbstractMapObjectImpl *>(objToPointTo.get());
if (!impl)
{
WARNING_LOG(m_logger) << LOGFUNCTION << " dynamic_cast failed";
return false;
}
// get target position:
BoundingBox bbox;
objToPointTo->boundingBox(bbox);
if (!bbox.isValid())
WARNING_LOG(m_logger) << LOGFUNCTION << " boundingBox not valid: bbox = " << bbox;
const QString &objToPointToDebugInfo = objToPointTo->debugInfo();
DEBUG_LOG(m_logger) << LOGFUNCTION
<< ", objToPointTo is valid, uniqueIdToPointTo = " << m_uniqueIdToPointTo
<< ", (objToPointToDebugInfo = " << objToPointToDebugInfo << ")"
<< ", bbox= " << bbox;
objCenterPoint = bbox.center();
// objColor:
objColor = impl->majorColor();
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
QImage ObjectIndicatorImpl::renderArrowHeadSymbol(const QColor &color, int length, int halfWidth)
{
int width = halfWidth * 2;
QImage image(width, length, QImage::Format_ARGB32);
image.fill(Qt::transparent);
QPainter painter(&image);
painter.setRenderHints(QPainter::Antialiasing);
QPen pen(color);
pen.setWidth(2);
painter.setPen(pen);
painter.setBrush(QBrush(color, Qt::BrushStyle::SolidPattern));
// 2 ||
// | |
// 1 | | 3
QPolygon poly;
poly.reserve(3);
poly.append(QPoint(0, length));
poly.append(QPoint(halfWidth, 0));
poly.append(QPoint(width, length));
painter.drawPolygon(poly);
painter.end();
// image.save(QLatin1String("/tmp/Arrow.png"));
return image;
}
bool ObjectIndicatorImpl::setMapObjectSelected(bool selected)
{
// 'clear' current selection:
clearCurrentSelection();
if (!selected)
return true; // already done by clearCurrentSelection :-)
if (!SituationMap::isUniqueMapIdValid(m_uniqueIdToPointTo))
return false;
RefPointer<AbstractMapObject> objToPointTo = m_mapImpl->objectFactory().get(m_uniqueIdToPointTo);
// retrive values from objToPointTo:
if (!objToPointTo.valid())
{
WARNING_LOG(m_logger) << LOGFUNCTION << " objToPointTo not found";
return false;
}
AbstractMapObjectImpl *impl = dynamic_cast<AbstractMapObjectImpl *>(objToPointTo.get());
if (!impl)
{
WARNING_LOG(m_logger) << LOGFUNCTION << " dynamic_cast failed";
return false;
}
if (impl->selected() == selected)
return true;
impl->setSelected(selected);
return impl->updateView();
}
} // namespace SituationMap