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

645 lines
20 KiB
C++
Executable File

/**
* @RDE_HEADER@
* Interface of AbstractMapObject
* $Id$
* $HeadURL$
* $Author$
*/
// Own
#include "overlay_handler_impl.h"
#include <Map/map.h>
#include <Map/layer_factory.h>
#include <Map/layer_parameter.h>
#include <Map/pixel_based_textbox_handler.h>
#include <Map/situation_map_utils.h>
#include <GeometryModel/geometry_model_factory.h>
#include <GeometryModel/geometry_pixelTextBox.h>
#include "geometry_model_renderer_esri.h"
#include <QFile>
//----------------------------------------------------------------------------
namespace SituationMap
{
OverlayHandler *OverlayHandler::create(Map *map)
{
return new OverlayHandlerImpl(map);
}
static const QLatin1String s_verlayLayerPrefix = QLatin1String("OverlayLayer_");
class OverlayData
{
public:
~OverlayData()
{
// graceful cleanup, destroy associated MapObject (adequate signal will be emitted)
if (m_geoModel)
m_geoModel->clearModel();
m_geoModelRenderer.clear();
m_geoModel.clear();
// : graceful cleanup
}
int m_key = -1;
QString m_logicalLayerName;
QString m_technicalLayerName; // just for debugging purpose
QSharedPointer<GeometryModel> m_geoModel;
QSharedPointer<GeometryModelRenderer> m_geoModelRenderer;
bool init(Map *map)
{
if (m_logicalLayerName.isEmpty())
return false;
m_geoModel = QSharedPointer<GeometryModel>(SituationMap::GeometryModelFactory::singleton()->create());
m_geoModelRenderer =
QSharedPointer<GeometryModelRenderer>(map->createGeometryModelRenderer(m_logicalLayerName, m_geoModel.data()));
m_geoModelRenderer->setNodesPickable(false); // we just want to display the overlay, no picking
return !m_geoModelRenderer.isNull();
}
QString toString() const
{
QString str;
str.append(QStringLiteral("m_key=%1").arg(m_key));
str.append(QStringLiteral(" m_logicalLayerName='%1'").arg(m_logicalLayerName));
str.append(QStringLiteral(" m_technicalLayerName='%1'").arg(m_technicalLayerName));
return str;
}
};
//-----------------------------------------------------------------------------
class OverlayHandlerImpl::Private
{
public:
Private() = default;
~Private() = default;
// ESRI data:
// Own data:
Map *m_map = nullptr;
private:
QMap<int, QSharedPointer<OverlayData>> m_overlayCont;
public:
QSharedPointer<OverlayData> &getOverlayData(int key)
{
if (m_overlayCont[key].isNull())
m_overlayCont[key] = QSharedPointer<OverlayData>(new OverlayData());
return m_overlayCont[key];
}
int remove(int key) { return m_overlayCont.remove(key); }
void clear() { m_overlayCont.clear(); }
int size() { return m_overlayCont.size(); }
QList<int> keys() { return m_overlayCont.keys(); }
bool contains(int key) { return m_overlayCont.contains(key); }
QMutableMapIterator<int, QSharedPointer<OverlayData>> mutableIterator()
{
return QMutableMapIterator<int, QSharedPointer<OverlayData>> (m_overlayCont);
}
}; // class OverlayHandlerImpl::Private
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
OverlayHandlerImpl::OverlayHandlerImpl(Map *map)
: BaseClass()
, m_logger(getLogger("OverlayHandlerImpl"))
, d(new Private)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
d->m_map = map;
if (! d->m_map)
ERROR_LOG(m_logger) << LOGFUNCTION << " error no Map ";
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
OverlayHandlerImpl::~OverlayHandlerImpl()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
delete d;
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
QString OverlayHandlerImpl::toString() const
{
QString str(QLatin1String("OverlayHandlerImpl"));
str.append(QStringLiteral(" m_overlayCont.size=%1").arg(d->size()));
return str;
}
bool OverlayHandlerImpl::setOverlay(int key, const QString &name, const QByteArray &overlayContent, bool isSnapshot)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START" << " key=" << key
<< " name='" << name << "'"
<< " overlayContent.size()='" << overlayContent.size()
<< " isSnapshot=" << isSnapshot;
if (! d->m_map)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " error, no Map " << " key=" << key;
return false;
}
const bool contains = d->contains(key);
// data:
QSharedPointer<OverlayData> overlayData;
// create or update?
if (contains)
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " Current11 SnaphotOverlay" << d->m_map->layerFactory().layerParameter(QStringLiteral("SnaphotOverlay"));
overlayData = d->getOverlayData(key);
// already created, but update displayname:
if (! d->m_map->layerFactory().addOverlayLayer(overlayData->m_logicalLayerName, name, isSnapshot))
{
ERROR_LOG(m_logger) << LOGFUNCTION << " error on addOverlayLayer" << " key=" << key;
TRACE_LOG(m_logger) << LOGFUNCTION << " END" << " key=" << key;
return false;
}
}
else
{
DEBUG_LOG(m_logger) << " CurrentAA SnaphotOverlay" << d->m_map->layerFactory().layerParameter(QStringLiteral("SnaphotOverlay"));
overlayData = QSharedPointer<OverlayData>(new OverlayData());
// case 'create' -> create layer:
overlayData->m_key = key;
if (isSnapshot)
overlayData->m_logicalLayerName = d->m_map->layerFactory().snapshotOverlayLayername();
else
overlayData->m_logicalLayerName = QString(s_verlayLayerPrefix) + QString::number(key);
if (! d->m_map->layerFactory().addOverlayLayer(overlayData->m_logicalLayerName, name, isSnapshot))
{
ERROR_LOG(m_logger) << LOGFUNCTION << " error on addOverlayLayer" << " key=" << key;
TRACE_LOG(m_logger) << LOGFUNCTION << " END" << " key=" << key;
return false;
}
// LayerFactory will make sure the technical layer is created.
DEBUG_LOG(m_logger) << LOGFUNCTION << " key=" << key << " overlayData init...";
if (! overlayData->init(d->m_map))
{
ERROR_LOG(m_logger) << LOGFUNCTION << " error on init" << " key=" << key;
d->m_map->layerFactory().removeOverlayLayer(overlayData->m_logicalLayerName);
TRACE_LOG(m_logger) << LOGFUNCTION << " END" << " key=" << key;
return false;
}
} // if (contains)
bool success = false;
if (overlayContent.isEmpty())
{
// in case of restoring the OperatorMapSettings / toggle 2D<->3D)
// prepare layer WITHOUNT content
DEBUG_LOG(m_logger) << LOGFUNCTION << " END, overlayContent is empty, so just be prepared"
<< ", key=" << key
<< ", isSnapshot=" << isSnapshot;
success = true;
} else {
if (overlayData->m_geoModel && overlayData->m_geoModelRenderer)
{
if (!overlayData->m_geoModel->fromByteArray(overlayContent))
{
// overlayContent string is not a valid geoModel -> abort
ERROR_LOG(m_logger) << LOGFUNCTION << " error on fromString," << " key=" << key;
if (!d->m_map->layerFactory().removeOverlayLayer(overlayData->m_logicalLayerName))
{
ERROR_LOG(m_logger) << LOGFUNCTION << " removeOverlayLayer failed," << " key=" << key;
}
TRACE_LOG(m_logger) << LOGFUNCTION << " END" << " key=" << key;
return false;
}
// overlayData->m_geoModel->cleanModel(true); has been done in GeometryModel::fromString
DEBUG_LOG(m_logger) << LOGFUNCTION << " key=" << key << " render...";
if (overlayData->m_geoModelRenderer->render())
{
success = true;
}
else
{
ERROR_LOG(m_logger) << LOGFUNCTION << " error on render" << " key=" << key;
}
}
} // if (overlayContent.isEmpty())
if (success)
{
// add temporary data to internal map:
if (!contains)
d->getOverlayData(key) = overlayData;
//INFO_LOG(m_logger) << LOGFUNCTION << " olData=" << d->getOverlayData(key).data()->toString();
}
else
{
INFO_LOG(m_logger) << LOGFUNCTION << " removeOverlayLayer" << " key=" << key
<< ", m_logicalLayerName " << overlayData->m_logicalLayerName;
d->m_map->layerFactory().removeOverlayLayer(overlayData->m_logicalLayerName);
}
//
const QString &strRef =
overlayData->m_geoModel->getModelAttribute(SituationMap::GeometryModel::Attribute::MetaPixelBasedTextBoxes).toString();
const QVector<SituationMap::PixelTextBoxData> &ptbdCont =
SituationMap::PixelTextBoxData::pixelTextBoxContainerFromJsonStr(strRef);
PixelBasedTextBoxHandler &pixelBasedTextBoxHandler = d->m_map->pixelBasedTextBoxHandler();
// cleanup:
const int parentId = key; // key == fileId
pixelBasedTextBoxHandler.removeAllTextBoxesOfParent(parentId);
for (const SituationMap::PixelTextBoxData &ptbd : qAsConst(ptbdCont))
{
// create WITHIN loop, since it will be modified by createUpdateTextBox:
PBTB_ID pbtbId;
pbtbId.m_parentId = parentId;
QTextEdit *newTextEdit = pixelBasedTextBoxHandler.createTextBox(pbtbId, ptbd, false);
if (newTextEdit)
DEBUG_LOG(m_logger) << LOGFUNCTION << " new TextBox created: newTextEdit = " << newTextEdit
<< ", pbtbId=" << pbtbId
<< ", ptbd=" << ptbd;
else
ERROR_LOG(m_logger) << LOGFUNCTION << " createUpdateTextBox failed"
<< ", pbtbId=" << pbtbId
<< ", ptbd=" << ptbd;
} // for
TRACE_LOG(m_logger) << LOGFUNCTION << " END" << " key=" << key
<< ", size=" << d->size();
return success;
}
QByteArray OverlayHandlerImpl::content(int key) const
{
if (!d->contains(key))
{
ERROR_LOG(m_logger) << LOGFUNCTION << " key=" << key << " unknown";
return QByteArray();
}
QSharedPointer<OverlayData> overlayData = d->getOverlayData(key);
return overlayData->m_geoModel->toByteArray();
}
bool OverlayHandlerImpl::reorderOverlays(const QVector<int> &orderOfIds)
{
QStringList layerOrder = d->m_map->layerFactory().layernames();
// Change the logical layer names in layerOrder list at all positions where a logical layer name has been map to an id ...
int idIndex = 0;
for (QStringList::iterator iter = layerOrder.begin(); layerOrder.end() != iter; ++iter)
{
QVector<int>::const_iterator orderIter = orderOfIds.cbegin();
// looking for the current logicalLayername in list of orderOfIds
while (orderOfIds.cend() != orderIter)
{
if (*iter == d->getOverlayData(*orderIter)->m_logicalLayerName)
{
// layer exists in orderOfIds lets change the order
*iter = d->getOverlayData(orderOfIds[idIndex])->m_logicalLayerName; // set new layername for this position
++idIndex;
break; // logical layer name is existing only once and we have changed the order hat this position, so we can leaf the while loop here
}
++orderIter;
}
}
// ready now give the new layer order to layer factory
if (!d->m_map->layerFactory().orderLayerTo(layerOrder))
{
ERROR_LOG(m_logger) << LOGFUNCTION << " orderLayerTo failed.";
return false;
}
return true;
} // void OverlayHandlerImpl::reorderOverlays( const QVector<int> & orderOfIds )
double OverlayHandlerImpl::minScale(int key) const
{
if (! d->contains(key))
{
ERROR_LOG(m_logger) << LOGFUNCTION << " key=" << key << " unknown";
return -1.0;
}
QSharedPointer<OverlayData> overlayData = d->getOverlayData(key);
const QString &logicalLayername = overlayData->m_logicalLayerName;
LayerParameter lp = d->m_map->layerFactory().layerParameter(logicalLayername);
return lp.minScale;
}
bool OverlayHandlerImpl::setMinScale(int key, double minScale)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START" << " key=" << key << " minScale=" << minScale;
if (! d->contains(key))
{
ERROR_LOG(m_logger) << LOGFUNCTION << " key=" << key << " unknown";
return false;
}
QSharedPointer<OverlayData> overlayData = d->getOverlayData(key);
const QString &logicalLayername = overlayData->m_logicalLayerName;
// get LayerParameter, update data and set:
LayerParameter lp = d->m_map->layerFactory().layerParameter(logicalLayername);
lp.minScale = minScale;
if (! d->m_map->layerFactory().setLayerParameter(logicalLayername, lp))
{
ERROR_LOG(m_logger) << LOGFUNCTION << " error updating LayerParameter, key=" << key;
return false;
}
TRACE_LOG(m_logger) << LOGFUNCTION << " END" << " key=" << key << " minScale=" << minScale;
return true;
}
double OverlayHandlerImpl::maxScale(int key) const
{
if (! d->contains(key))
{
ERROR_LOG(m_logger) << LOGFUNCTION << " key=" << key << " unknown";
return -1.0;
}
QSharedPointer<OverlayData> overlayData = d->getOverlayData(key);
const QString &logicalLayername = overlayData->m_logicalLayerName;
LayerParameter lp = d->m_map->layerFactory().layerParameter(logicalLayername);
return lp.maxScale;
}
bool OverlayHandlerImpl::setMaxScale(int key, double maxScale)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START" << " key=" << key << " maxScale=" << maxScale;
if (! d->contains(key))
{
ERROR_LOG(m_logger) << LOGFUNCTION << " key=" << key << " unknown";
return false;
}
QSharedPointer<OverlayData> overlayData = d->getOverlayData(key);
const QString &logicalLayername = overlayData->m_logicalLayerName;
// get LayerParameter, update data and set:
LayerParameter lp = d->m_map->layerFactory().layerParameter(logicalLayername);
lp.maxScale = maxScale;
if (! d->m_map->layerFactory().setLayerParameter(logicalLayername, lp))
{
ERROR_LOG(m_logger) << LOGFUNCTION << " error updating LayerParameter, key=" << key;
return false;
}
TRACE_LOG(m_logger) << LOGFUNCTION << " END" << " key=" << key << " maxScale=" << maxScale;
return true;
}
double OverlayHandlerImpl::opacity(int key) const
{
if (! d->contains(key))
{
ERROR_LOG(m_logger) << LOGFUNCTION << " key=" << key << " unknown";
return 0.0;
}
QSharedPointer<OverlayData> overlayData = d->getOverlayData(key);
const QString &logicalLayername = overlayData->m_logicalLayerName;
// get LayerParameter, update data and set:
LayerParameter lp = d->m_map->layerFactory().layerParameter(logicalLayername);
return double(lp.opacity) / 100.0;
}
bool OverlayHandlerImpl::setOpacity(int key, double opacity)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START" << " key=" << key << " opacity=" << opacity;
if (! d->contains(key))
{
ERROR_LOG(m_logger) << LOGFUNCTION << " key=" << key << " unknown";
return false;
}
opacity = (opacity < 0.0) ? 0.0 : ((opacity > 1.0) ? 1.0 : opacity);
QSharedPointer<OverlayData> overlayData = d->getOverlayData(key);
const QString &logicalLayername = overlayData->m_logicalLayerName;
// get LayerParameter, update data and set:
LayerParameter lp = d->m_map->layerFactory().layerParameter(logicalLayername);
lp.opacity = int(opacity * 100);
if (! d->m_map->layerFactory().setLayerParameter(logicalLayername, lp))
{
ERROR_LOG(m_logger) << LOGFUNCTION << " error on setLayerParameter" << " key=" << key;
return false;
}
TRACE_LOG(m_logger) << LOGFUNCTION << " END" << " key=" << key << " opacity=" << opacity;
return true;
}
bool OverlayHandlerImpl::setOverlayVisibility(int key, bool visibility)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
<< " key=" << key
<< " visibility=" << visibility;
// Lookup:
QSharedPointer<OverlayData> overlayData = d->getOverlayData(key);
const QString &logicalLayername = overlayData->m_logicalLayerName;
INFO_LOG(m_logger) << LOGFUNCTION << " visibility of layer='" << logicalLayername << "'"
<< " key=" << key
<< " -> " << visibility;
if (logicalLayername.isEmpty())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " layername is empty, key=" << key << " unknown";
return false;
}
// Technical/Esri:
// get LayerParameter, update data and set:
LayerParameter lp = d->m_map->layerFactory().layerParameter(logicalLayername);
lp.visible = visibility;
if (! d->m_map->layerFactory().setLayerParameter(logicalLayername, lp))
{
ERROR_LOG(m_logger) << LOGFUNCTION << " error on setLayerParameter" << " key=" << key;
return false;
}
TRACE_LOG(m_logger) << LOGFUNCTION << " END"
<< " key=" << key
<< " visibility=" << visibility;
return true;
}
bool OverlayHandlerImpl::overlayVisibility(int key) const
{
QSharedPointer<OverlayData> overlayData = d->getOverlayData(key);
const QString &logicalLayername = overlayData->m_logicalLayerName;
if (logicalLayername.isEmpty())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " layername is empty, key=" << key << " unknown";
return false;
}
LayerParameter lp = d->m_map->layerFactory().layerParameter(logicalLayername);
return lp.visible;
} // bool OverlayHandlerImpl::overlayVisibility(const int &key)
bool OverlayHandlerImpl::removeOverlay(int key)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
<< " key=" << key;
if (! d->m_map)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " error no Map " << " key=" << key;
return false;
}
if (! d->contains(key))
{
ERROR_LOG(m_logger) << LOGFUNCTION << " key=" << key << " unknown";
return false;
}
// Lookup:
QSharedPointer<OverlayData> overlayData = d->getOverlayData(key);
QString logicalLayername = overlayData->m_logicalLayerName; // create a copy here
DEBUG_LOG(m_logger) << LOGFUNCTION << " remove layer='" << logicalLayername << "'"
<< " key=" << key;
if (logicalLayername.isEmpty())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " layername is empty, key=" << key;
return false;
}
// Own data management:
//
// FIRST:
//
// Remove own MapObject BEFORE the layer
d->remove(key);
overlayData.clear(); // to decrease QSharedPointer <----- important
//
// SECOND:
//
// Technical/Esri:
if (!d->m_map->layerFactory().removeOverlayLayer(logicalLayername))
{
WARNING_LOG(m_logger) << LOGFUNCTION << " remove layer='" << logicalLayername << "'"
<< " key=" << key;
return false;
}
//
// Pixel-based TextBoxes:
//
PixelBasedTextBoxHandler &pixelBasedTextBoxHandler = d->m_map->pixelBasedTextBoxHandler();
const int parentId = key; // key == fileId
pixelBasedTextBoxHandler.removeAllTextBoxesOfParent(parentId);
TRACE_LOG(m_logger) << LOGFUNCTION << " END"
<< " key=" << key;
return true;
}
int OverlayHandlerImpl::removeAllOverlays()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START, current size = " << d->size();
int removed = 0;
const QList<int> &currentKeys = d->keys();
for (int key : currentKeys)
{
if (removeOverlay(key))
++removed;
}
TRACE_LOG(m_logger) << LOGFUNCTION << " END"
<< " removed = " << removed
<< " size now = " << d->size();
return removed;
}
int OverlayHandlerImpl::overlayCount() const
{
return d->size();
}
QList<int> OverlayHandlerImpl::overlays() const
{
return d->keys();
}
bool OverlayHandlerImpl::containsOverlay(int key) const
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return d->contains(key);
}
//-----------------------------------------------------------------------------
// output operator:
//-----------------------------------------------------------------------------
std::ostream &operator<< (std::ostream &stream,
const OverlayHandlerImpl &value)
{
stream << value.toString();
return stream;
}
} // namespace SituationMap