576 lines
18 KiB
C++
Executable File
576 lines
18 KiB
C++
Executable File
/**
|
|
* @RDE_HEADER@
|
|
* IndicationContainer
|
|
* $Id$
|
|
* $HeadURL$
|
|
* $Author$
|
|
*/
|
|
|
|
// Own
|
|
#include "indication_container.h"
|
|
#include <MapImpl/coordinate_translation.h>
|
|
#include <GraphicalObjects/graphical_object_picture_marker.h>
|
|
#include <MapImpl/coordinate_translation_thread.h>
|
|
|
|
|
|
// ESRI
|
|
#include <arcgis/GeoView.h>
|
|
#include <arcgis/PictureMarkerSymbol.h>
|
|
|
|
// Qt
|
|
#include <QElapsedTimer>
|
|
|
|
|
|
namespace SituationMap
|
|
{
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// class IndicationData
|
|
//-----------------------------------------------------------------------------
|
|
class IndicationData
|
|
{
|
|
public:
|
|
const QImage &image() const { return m_image;}
|
|
void setImage(const QImage &image) { if (m_image != image) m_changed = true; m_image = image; }
|
|
|
|
MarkerSymbolType markerSymbolType() const { return m_markerSymbolType; }
|
|
void setMarkerSymbolType(const MarkerSymbolType &markerSymbolType) { if (m_markerSymbolType != markerSymbolType) m_changed = true; m_markerSymbolType = markerSymbolType; }
|
|
|
|
const QColor &markerColor() const { return m_markerColor; }
|
|
void setMarkerColor(const QColor &markerColor) { if (m_markerColor != markerColor) m_changed = true; m_markerColor = markerColor; }
|
|
|
|
int markerSize() const { return m_markerSize; }
|
|
void setMarkerSize(int markerSize) { if (m_markerSize != markerSize) m_changed = true; m_markerSize = markerSize; }
|
|
|
|
bool markerSelected() const { return m_markerSelected; }
|
|
void setMarkerSelected(bool markerSelected) { if (m_markerSelected != markerSelected) m_changed = true; m_markerSelected = markerSelected; }
|
|
|
|
bool markerPickable() const { return m_markerPickable; }
|
|
void setMarkerPickable(bool markerPickable) { if (m_markerPickable != markerPickable) m_changed = true; m_markerPickable = markerPickable; }
|
|
|
|
PositionsTranslated &positionsTrans() { return m_positions; }
|
|
void setPositions(const PositionCont &positions) { if (m_positions.positions() != positions) m_changed = true; m_positions.setPositions(positions); }
|
|
|
|
bool markerVisible() const { return m_markerVisible; }
|
|
void setMarkerVisible(bool markerVisible) { if (m_markerVisible != markerVisible) m_changed = true; m_markerVisible = markerVisible; }
|
|
|
|
|
|
|
|
bool changed() const { return m_changed; }
|
|
void resetChanged() { m_changed = false; }
|
|
|
|
IndicationData()
|
|
{}
|
|
|
|
~IndicationData()
|
|
{
|
|
m_pictureMarker.clear();
|
|
}
|
|
|
|
public:
|
|
QSharedPointer<CoordTranslationThread> m_coordTranslationThread;
|
|
QSharedPointer<GraphicalObjectPictureMarker> m_pictureMarker;
|
|
|
|
private:
|
|
QImage m_image;
|
|
|
|
PositionsTranslated m_positions;
|
|
MarkerSymbolType m_markerSymbolType = MarkerSymbolType::Undefined;
|
|
int m_markerSize = 20;
|
|
QColor m_markerColor = Qt::black;
|
|
bool m_markerVisible = true;
|
|
bool m_markerSelected = false;
|
|
bool m_markerPickable = true;
|
|
bool m_changed = true;
|
|
};
|
|
|
|
|
|
class IndicationContainer::Private
|
|
{
|
|
public:
|
|
Private() = default;
|
|
~Private() = default;
|
|
|
|
// ESRI data:
|
|
Esri::ArcGISRuntime::GeoView *m_geoView = nullptr;
|
|
Esri::ArcGISRuntime::GraphicsOverlay *m_graphicsLayer = nullptr;
|
|
|
|
|
|
// Own data:
|
|
CoordTranslationFunctor *m_coordTransFunctor = nullptr;
|
|
QString m_debugInfo; // will be appended by consecutive number
|
|
UniqueMapId m_uniqueMapId;
|
|
|
|
SimpleValue<int> m_drawOrder = 0;
|
|
|
|
private:
|
|
// TODO: use sorted vector - only max. 10 elements in there, so qhash/qmap is overkill
|
|
QHash<int, QSharedPointer<IndicationData>> m_map;
|
|
|
|
public:
|
|
QSharedPointer<IndicationData> getIndicationData(int key)
|
|
{
|
|
auto it = m_map.find(key);
|
|
if (it != m_map.end())
|
|
return it.value();
|
|
auto ret = QSharedPointer<IndicationData>(new IndicationData());
|
|
m_map[key] = ret;
|
|
return ret;
|
|
}
|
|
|
|
void remove(int key) // attention, will remove the provides image/marker...
|
|
{
|
|
auto it = m_map.find(key);
|
|
if (it == m_map.end())
|
|
return;
|
|
const QSharedPointer<IndicationData> &indicationData = it.value();
|
|
if (indicationData && indicationData->m_coordTranslationThread)
|
|
indicationData->m_coordTranslationThread->wait();
|
|
m_map.erase(it);
|
|
}
|
|
void clear() { m_map.clear(); }
|
|
int size() const { return m_map.size(); }
|
|
QList<int> keys() const { return m_map.keys(); }
|
|
bool contains(int key) const { return m_map.contains(key); }
|
|
const QHash<int, QSharedPointer<IndicationData>> &container() const { return m_map; }
|
|
|
|
}; // class IndicationContainer::Private
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// class IndicationContainer
|
|
//-----------------------------------------------------------------------------
|
|
IndicationContainer::IndicationContainer(const Esri::ArcGISRuntime::GeoView *geoView,
|
|
Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer,
|
|
CoordTranslationFunctor *coordTransFunctor,
|
|
const UniqueMapId &uniqueMapId)
|
|
: QObject()
|
|
, m_logger(getLogger("IndicationContainer"))
|
|
, d(new Private)
|
|
{
|
|
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
|
d->m_geoView = const_cast<Esri::ArcGISRuntime::GeoView *>(geoView);
|
|
d->m_graphicsLayer = graphicsLayer;
|
|
d->m_coordTransFunctor = coordTransFunctor;
|
|
d->m_uniqueMapId = uniqueMapId;
|
|
|
|
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
|
}
|
|
|
|
IndicationContainer::~IndicationContainer()
|
|
{
|
|
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
|
|
|
// Thread::wait():
|
|
for (const QSharedPointer<IndicationData> &id : d->container())
|
|
{
|
|
if (id && id->m_coordTranslationThread)
|
|
{
|
|
id->m_coordTranslationThread->quit();
|
|
id->m_coordTranslationThread->wait();
|
|
}
|
|
} // for
|
|
|
|
|
|
d->clear();
|
|
delete d;
|
|
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
|
}
|
|
|
|
QString IndicationContainer::debugInfo() const
|
|
{
|
|
return d->m_debugInfo;
|
|
}
|
|
void IndicationContainer::setDebugInfo(const QString &debugInfo)
|
|
{
|
|
d->m_debugInfo = debugInfo;
|
|
}
|
|
|
|
|
|
PositionCont IndicationContainer::positions(int idx) const
|
|
{
|
|
return d->getIndicationData(idx)->positionsTrans().positions();
|
|
}
|
|
void IndicationContainer::setPositions(int idx, const PositionCont &positions)
|
|
{
|
|
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
|
|
<< ", debugInfo='" << d->m_debugInfo << "'"
|
|
<< ", m_uniqueMapId = " << d->m_uniqueMapId
|
|
<< ", idx=" << idx
|
|
<< ", positions.size=" << positions.size();
|
|
|
|
d->getIndicationData(idx)->setPositions(positions);
|
|
|
|
// // d->remove(idx); // attention: remove will implicit rmove the provided image...
|
|
|
|
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
|
}
|
|
|
|
void IndicationContainer::setMarker(int idx, MarkerSymbolType mst, int size, const QColor &color)
|
|
{
|
|
d->getIndicationData(idx)->setMarkerSymbolType(mst);
|
|
d->getIndicationData(idx)->setMarkerSize(size);
|
|
d->getIndicationData(idx)->setMarkerColor(color);
|
|
}
|
|
|
|
void IndicationContainer::setMarker(int idx, int size)
|
|
{
|
|
d->getIndicationData(idx)->setMarkerSize(size);
|
|
}
|
|
|
|
void IndicationContainer::setMarker(int idx, const QColor &color)
|
|
{
|
|
d->getIndicationData(idx)->setMarkerColor(color);
|
|
}
|
|
|
|
|
|
const QImage &IndicationContainer::image(int idx) const
|
|
{
|
|
return d->getIndicationData(idx)->image();
|
|
}
|
|
void IndicationContainer::setImage(int idx, const QImage &image)
|
|
{
|
|
auto id = d->getIndicationData(idx);
|
|
|
|
if (id->image() == image)
|
|
return;
|
|
id->setImage(image);
|
|
}
|
|
|
|
void IndicationContainer::clear(int idx)
|
|
{
|
|
d->remove(idx);
|
|
}
|
|
|
|
void IndicationContainer::clearAll()
|
|
{
|
|
d->clear();
|
|
}
|
|
|
|
int IndicationContainer::drawOrder() const
|
|
{
|
|
return d->m_drawOrder.value();
|
|
}
|
|
void IndicationContainer::setDrawOrder(int drawOrder)
|
|
{
|
|
d->m_drawOrder = drawOrder;
|
|
}
|
|
|
|
bool IndicationContainer::visible(int idx) const
|
|
{
|
|
return d->getIndicationData(idx)->markerVisible();
|
|
}
|
|
void IndicationContainer::setVisible(int idx, bool visible)
|
|
{
|
|
d->getIndicationData(idx)->setMarkerVisible(visible);
|
|
}
|
|
|
|
bool IndicationContainer::selected(int idx) const
|
|
{
|
|
return d->getIndicationData(idx)->markerSelected();
|
|
}
|
|
void IndicationContainer::setSelected(int idx, bool selected)
|
|
{
|
|
d->getIndicationData(idx)->setMarkerSelected(selected);
|
|
}
|
|
|
|
bool IndicationContainer::pickable(int idx) const
|
|
{
|
|
return d->getIndicationData(idx)->markerPickable();
|
|
}
|
|
|
|
void IndicationContainer::setPickable(int idx, bool pickable)
|
|
{
|
|
d->getIndicationData(idx)->setMarkerPickable(pickable);
|
|
}
|
|
|
|
|
|
|
|
int IndicationContainer::getIndicationCount() const
|
|
{
|
|
return d->size();
|
|
}
|
|
|
|
QList<int> IndicationContainer::getIndicationIndexList() const
|
|
{
|
|
return d->keys();
|
|
}
|
|
|
|
|
|
bool IndicationContainer::updateView()
|
|
{
|
|
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
|
|
<< ", debugInfo='" << d->m_debugInfo << "'"
|
|
<< ", m_uniqueMapId = " << d->m_uniqueMapId
|
|
<< " , d->m_map.size()=" << d->size();
|
|
bool success = true;
|
|
|
|
|
|
// int outterSize = d->m_map.size();
|
|
|
|
for (auto it = d->container().begin(); it != d->container().end(); ++it)
|
|
{
|
|
const QSharedPointer<IndicationData> &indicationData = it.value();
|
|
// per single dimension:
|
|
|
|
// nothing changed?
|
|
if ((!indicationData->changed()) && (!d->m_drawOrder.changed()))
|
|
{
|
|
DEBUG_LOG(m_logger) << LOGFUNCTION << " no change -> continue... "
|
|
<< ", debugInfo='" << d->m_debugInfo << "'";
|
|
continue;
|
|
}
|
|
|
|
// set
|
|
indicationData->positionsTrans().setCoordTransFunctor(d->m_coordTransFunctor);
|
|
|
|
int idx = it.key();
|
|
|
|
#define SYNC
|
|
#ifdef SYNC
|
|
bool updated = updateIndicationContainer(idx);
|
|
success = success && updated;
|
|
|
|
#else
|
|
|
|
// skip thread and do call sync if:
|
|
if (indicationData->positionsTrans().isTranslated()
|
|
|| ! indicationData->markerVisible()
|
|
)
|
|
{
|
|
// call sync:
|
|
updateIndicationContainer(idx); // update of invisible marker is cheap :-)
|
|
}
|
|
else
|
|
{
|
|
|
|
// ok, thread is requested:
|
|
|
|
// another thread prepared/running or finished/deleted?
|
|
if (indicationData->m_coordTranslationThread.isNull())
|
|
{
|
|
// move time consuming work to worker thread:
|
|
// apply Deleter to SharedPointer (to avoid simple 'delete')
|
|
indicationData->m_coordTranslationThread =
|
|
QSharedPointer<CoordTranslationThread> (new CoordTranslationThread(d->m_debugInfo), &QObject::deleteLater);
|
|
|
|
indicationData->m_coordTranslationThread->setUserData(idx);
|
|
indicationData->m_coordTranslationThread->setPositions(& (indicationData->positionsTrans()));
|
|
|
|
// QObject::connect(indicationData.m_coordTranslationThread.data(), &CoordTranslationThread::finished, indicationData.m_coordTranslationThread.data(), &QObject::deleteLater);
|
|
QObject::connect(indicationData->m_coordTranslationThread.data(), &CoordTranslationThread::finished, this, &IndicationContainer::onThreadFinished);
|
|
QObject::connect(indicationData->m_coordTranslationThread.data(), &CoordTranslationThread::resultReady, this, &IndicationContainer::onResultReady);
|
|
|
|
qWarning() << " start workerThread, idx=" << idx;
|
|
indicationData->m_coordTranslationThread->start();
|
|
|
|
}
|
|
else
|
|
{
|
|
FATAL_LOG(m_logger) << LOGFUNCTION
|
|
<< " new Translation via Thread requested, but still exists...";
|
|
}
|
|
|
|
}
|
|
#endif // SYNC
|
|
|
|
indicationData->resetChanged();
|
|
|
|
} // while
|
|
d->m_drawOrder.reset();
|
|
|
|
TRACE_LOG(m_logger) << LOGFUNCTION << " END"
|
|
<< " debugInfo='" << d->m_debugInfo << "'"
|
|
<< " success=" << success;
|
|
return success;
|
|
}
|
|
|
|
bool IndicationContainer::onResultReady(const QVariant &userData)
|
|
{
|
|
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
|
|
<< " debugInfo='" << d->m_debugInfo << "'"
|
|
<< "threadId: " << QThread::currentThreadId();
|
|
|
|
bool success = false;
|
|
|
|
bool bOk = false;
|
|
int idx = userData.toInt(&bOk);
|
|
if (bOk)
|
|
{
|
|
if (d->contains(idx))
|
|
{
|
|
QSharedPointer<IndicationData> indicationData = d->getIndicationData(idx);
|
|
if (! indicationData->positionsTrans().isTranslated())
|
|
{
|
|
ERROR_LOG(m_logger) << LOGFUNCTION << " NOT TRANSLATED, should not happen!!!"
|
|
<< " debugInfo='" << d->m_debugInfo << "'"
|
|
<< " idx=" << idx;
|
|
}
|
|
}
|
|
|
|
success = updateIndicationContainer(idx);
|
|
|
|
}
|
|
else
|
|
ERROR_LOG(m_logger) << LOGFUNCTION << " QVariant toInt failed!!!";
|
|
|
|
TRACE_LOG(m_logger) << LOGFUNCTION << " END"
|
|
<< " debugInfo='" << d->m_debugInfo << "'"
|
|
<< " success = " << success;
|
|
return success;
|
|
}
|
|
|
|
void IndicationContainer::onThreadFinished(const QVariant &userData)
|
|
{
|
|
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
|
|
<< " debugInfo='" << d->m_debugInfo << "'";
|
|
bool bOk = false;
|
|
int idx = userData.toInt(&bOk);
|
|
if (bOk)
|
|
{
|
|
if (d->contains(idx))
|
|
d->getIndicationData(idx)->m_coordTranslationThread.clear(); // will call the Deleter which is 'deleteLater'
|
|
}
|
|
else
|
|
qWarning() << "resultReady: QVariant toInt failed!!!";
|
|
|
|
TRACE_LOG(m_logger) << LOGFUNCTION << " END"
|
|
<< " debugInfo='" << d->m_debugInfo << "'";
|
|
}
|
|
|
|
|
|
bool IndicationContainer::updateIndicationContainer(int idx)
|
|
{
|
|
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
|
|
<< " debugInfo='" << d->m_debugInfo << "'"
|
|
<< " idx=" << idx;
|
|
|
|
QElapsedTimer timer;
|
|
|
|
if (m_logger.isInfoEnabled())
|
|
timer.start();
|
|
|
|
if (! d->contains(idx))
|
|
{
|
|
ERROR_LOG(m_logger) << LOGFUNCTION << " idx does not exist: idx=" << idx;
|
|
return false;
|
|
}
|
|
|
|
bool successPM = true;
|
|
QSharedPointer<IndicationData> indicationData = d->getIndicationData(idx);
|
|
|
|
// do we have positions or is PositionCont empty?
|
|
const PositionsTranslated &posTransRef = indicationData->positionsTrans();
|
|
int numberOfPositions = posTransRef.size();
|
|
if (posTransRef.isEmpty())
|
|
{
|
|
QSharedPointer<GraphicalObjectPictureMarker> &picMarker = indicationData->m_pictureMarker;
|
|
picMarker.clear();
|
|
}
|
|
else
|
|
{
|
|
successPM = updateIndicationContainerPictureMarker(idx);
|
|
}
|
|
|
|
bool success = successPM;
|
|
|
|
INFO_LOG(m_logger) << LOGFUNCTION << " END"
|
|
<< " debugInfo='" << d->m_debugInfo << "'"
|
|
<< " success=" << success
|
|
<< " successPM=" << successPM
|
|
<< " numberOfPositions = " << numberOfPositions
|
|
<< " took[ms] " << timer.elapsed();
|
|
|
|
TRACE_LOG(m_logger) << LOGFUNCTION << " END"
|
|
<< " debugInfo='" << d->m_debugInfo << "'"
|
|
<< " numberOfPositions = " << numberOfPositions
|
|
<< " successPM=" << successPM
|
|
<< " success=" << success;
|
|
return success;
|
|
}
|
|
|
|
bool IndicationContainer::updateIndicationContainerPictureMarker(int idx)
|
|
{
|
|
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
|
|
<< " debugInfo='" << d->m_debugInfo << "'"
|
|
<< " idx=" << idx;
|
|
QElapsedTimer timer;
|
|
|
|
if (m_logger.isInfoEnabled())
|
|
timer.start();
|
|
|
|
bool success = true;
|
|
int numberOfPositions = -1;
|
|
|
|
QSharedPointer<IndicationData> indicationData = d->getIndicationData(idx);
|
|
|
|
QSharedPointer<GraphicalObjectPictureMarker> &picMarker = indicationData->m_pictureMarker;
|
|
|
|
const MarkerSymbolType &mst = indicationData->markerSymbolType();
|
|
const bool bPicMarkerNeeded = (mst != MarkerSymbolType::Undefined) || !indicationData->image().isNull();
|
|
|
|
if (bPicMarkerNeeded)
|
|
{
|
|
if (picMarker.isNull())
|
|
{
|
|
QString debugInfo = QStringLiteral("%1#Indication_idx(%2)_PM").arg(d->m_debugInfo).arg(idx);
|
|
DEBUG_LOG(m_logger) << LOGFUNCTION << " create new Object: " << debugInfo;
|
|
picMarker = QSharedPointer<GraphicalObjectPictureMarker>
|
|
(new GraphicalObjectPictureMarker(d->m_geoView,
|
|
d->m_graphicsLayer,
|
|
debugInfo,
|
|
d->m_uniqueMapId));
|
|
}
|
|
|
|
// set parameter:
|
|
|
|
// [GUEZE-496] RPL Nr 770: 3D Lagedarstellung Einfrieren der SW Appl.
|
|
// GraphicalObjectPictureMarker supports multipoint geometry now
|
|
|
|
// do we have an mst or image?
|
|
if (mst != MarkerSymbolType::Undefined)
|
|
{
|
|
// Marker:
|
|
picMarker->setMarkerSymbol(mst,
|
|
indicationData->markerSize(),
|
|
indicationData->markerColor());
|
|
}
|
|
else
|
|
{
|
|
// Image:
|
|
picMarker->setImage(indicationData->image());
|
|
}
|
|
|
|
bool visible = indicationData->markerVisible();
|
|
picMarker->setDrawOrder(d->m_drawOrder.value());
|
|
picMarker->setVisibility(visible);
|
|
picMarker->setSelected(indicationData->markerSelected());
|
|
picMarker->setPickable(indicationData->markerPickable());
|
|
|
|
// Geometry/Positions
|
|
const PositionCont &positionsTrans = indicationData->positionsTrans().positionsTranslated();
|
|
picMarker->setPositions(positionsTrans);
|
|
numberOfPositions = positionsTrans.size();
|
|
|
|
success = picMarker->updateView();
|
|
} else {
|
|
picMarker.clear();
|
|
}
|
|
|
|
INFO_LOG(m_logger) << LOGFUNCTION << " END"
|
|
<< " debugInfo='" << d->m_debugInfo << "'"
|
|
<< " success=" << success
|
|
<< " numberOfPositions = " << numberOfPositions
|
|
<< " took[ms] " << timer.elapsed();
|
|
|
|
TRACE_LOG(m_logger) << LOGFUNCTION << " END"
|
|
<< " debugInfo='" << d->m_debugInfo << "'"
|
|
<< " numberOfPositions = " << numberOfPositions
|
|
<< " success=" << success;
|
|
return success;
|
|
}
|
|
|
|
} // namespace SituationMap
|