1420 lines
43 KiB
C++
Executable File
1420 lines
43 KiB
C++
Executable File
/**
|
||
* @RDE_HEADER@
|
||
* SituationMap - SituationMapInit
|
||
* $Id$
|
||
* $HeadURL$
|
||
* $Author$
|
||
* Created by Christian Ehrlicher, SLSE, 2016-02-29
|
||
*/
|
||
|
||
#include "situation_map_init.h"
|
||
#include "situation_map_init_p.h"
|
||
|
||
#include <QCoreApplication>
|
||
#include <QMenu>
|
||
#include <QFile>
|
||
#include <QDir>
|
||
#include <QJsonParseError>
|
||
|
||
#include <ngltools/ngltools_filesystem.h>
|
||
|
||
#include <Map/map_notifier.h>
|
||
#include <Map/grid.h>
|
||
#include <Map/object_factory.h>
|
||
#include <Map/layer_factory.h>
|
||
#include <Map/layer_parameter.h>
|
||
#include <Map/measurement.h>
|
||
#include <Map/viewshed.h>
|
||
#include <Map/bounding_box.h>
|
||
#include <Map/object_indicator.h>
|
||
#include <Map/measurement.h>
|
||
#include <Map/situation_map_utils.h>
|
||
#include <Utils/movement_track_manager.h>
|
||
|
||
#include <Symbology/symbol_dictionary.h>
|
||
#include <Symbology/symbol_data_to_render_role.h>
|
||
#include <ParticipantManagement/ppm_translation.h>
|
||
|
||
// OPM
|
||
#include <Plugins/OperatorManagement/opm_data_plugin_interface.h>
|
||
#include <Plugins/OperatorManagement/Data/opm_data_plugin.h>
|
||
#include <Plugins/ExerciseManagement/exm_data_plugin_interface.h>
|
||
#include <Services/OperatorManagement/opm.hpp>
|
||
#include <Plugins//AssetManagement/asm_data_plugin_interface.h>
|
||
#include <LtsUtilsSettings/settings.h>
|
||
|
||
// Contextmenue / Rights
|
||
#include <LtsSession/lts_session.h>
|
||
#include <LtsSession/lts_session_data.h>
|
||
#include <Services/SituationMap/map_operator_rights.h>
|
||
|
||
#include <LtsWidgets/lts_global_wait_dialog.h>
|
||
|
||
#include <functional>
|
||
|
||
#ifdef LTS_DEBUG
|
||
#define USE_FUNCTIONDIALOG
|
||
#endif
|
||
|
||
#ifdef USE_FUNCTIONDIALOG
|
||
|
||
// ndds/log/log_makeheader.h:21 ... -> create RTI bug !
|
||
#undef Public
|
||
#include <FunctionDialog/function_dialog.h>
|
||
|
||
#endif // USE_FUNCTIONDIALOG
|
||
|
||
namespace SituationMap
|
||
{
|
||
const char MapCacheState[] = "MapCacheState";
|
||
|
||
// CMake option at Lts/Plugins/SituationMapPlugin/Gui/SituationMap/CMakeLists.txt
|
||
#ifdef USE_MAP_CACHE
|
||
|
||
# pragma message("USE_MAP_CACHE is enabled")
|
||
|
||
class MapCache;
|
||
static MapCache *s_mapCache = nullptr;
|
||
|
||
// GUEZE-791 - RPL Nr 791: Arbeitsspeicherleck
|
||
|
||
/*!
|
||
* \brief The MapCache class reduces the number of loading processes
|
||
* We are caching here to avoid numerous construction and destruction of the map (3D/scene).
|
||
* At least at linux the scene with it´s ArcGISSceneLayerCache tends to alloc a
|
||
* hugh amount of data. Additionally allocation is influenced by the viewpoint
|
||
* choosen by the operator. And with other allocations (dds data, BGViewer or
|
||
* similar) at the same time the heap memory gets fragemented.
|
||
* So we try to reduce the number of loading processes.
|
||
* This should work with ONE TrainingArea.
|
||
* If we have more TA`s, the number of cached instances may increase...
|
||
*/
|
||
class MapCache
|
||
{
|
||
public:
|
||
static MapCache *getInstance()
|
||
{
|
||
if (!s_mapCache)
|
||
{
|
||
s_mapCache = new MapCache;
|
||
// qAddPostRoutine(&MapCache::cleanup); // since many of that objects/MapImpl are using log4cxx at dtor (which in turn leads to coredumps), we pass that to the os
|
||
}
|
||
return s_mapCache;
|
||
}
|
||
|
||
struct Item
|
||
{
|
||
QPointer<Map> m_mapWidget;
|
||
bool isItemFree() { return !m_mapWidget || m_mapWidget->property(MapCacheState).isNull(); }
|
||
};
|
||
|
||
Item& getFreeItemRef(const QString &itemName)
|
||
{
|
||
//Qt: If the map contains no item with key key, the function inserts a default-constructed value into the map with key key, and returns a reference to it.
|
||
QVector<Item> &vec = m_mapWidgetCache[itemName];
|
||
|
||
// search free item:
|
||
QMutableVectorIterator<Item> it(vec);
|
||
while (it.hasNext())
|
||
{
|
||
Item& itemRef = it.next();
|
||
if (itemRef.isItemFree())
|
||
return itemRef;
|
||
}
|
||
|
||
// Not found -> create:
|
||
vec.append(Item());
|
||
return vec.last();
|
||
}
|
||
|
||
static void cleanup()
|
||
{
|
||
delete s_mapCache;
|
||
}
|
||
|
||
~MapCache()
|
||
{
|
||
for (const auto &vec : qAsConst(m_mapWidgetCache))
|
||
{
|
||
for (const auto &item : vec)
|
||
{
|
||
std::cerr << " m_mapWidgetCache: delete " << item.m_mapWidget << std::endl;
|
||
delete item.m_mapWidget; // delete nullptr is ok
|
||
}
|
||
}
|
||
}
|
||
|
||
void dump()
|
||
{
|
||
std::cerr << " m_mapWidgetCache CacheSize = " << m_mapWidgetCache.size() << std::endl;
|
||
|
||
for (const auto &vec : qAsConst(m_mapWidgetCache))
|
||
{
|
||
std::cerr << " m_mapWidgetCache VectorSize: " << vec.size() << std::endl;
|
||
for (const auto &item : vec)
|
||
{
|
||
QString isVisiStr(QStringLiteral("unknown"));
|
||
if (item.m_mapWidget)
|
||
isVisiStr = item.m_mapWidget->isVisible() ? QStringLiteral("visible") : QStringLiteral("hidden");
|
||
|
||
QString updatesEnabledStr(QStringLiteral("unknown"));
|
||
if (item.m_mapWidget)
|
||
updatesEnabledStr = item.m_mapWidget->updatesEnabled() ? QStringLiteral("updatesEnabled") : QStringLiteral("updates_Not_Enabled");
|
||
|
||
std::cerr << " m_mapWidgetCache ITEM ="
|
||
<< " m_mapWidget=" << item.m_mapWidget
|
||
<< ", property (MapCacheState) ='" << (item.m_mapWidget ? item.m_mapWidget->property(MapCacheState).toString().toStdString() : "-") << "'"
|
||
<< ", mode=" << (item.m_mapWidget ? toString(item.m_mapWidget->mode()).toStdString().c_str() : "-") << "'"
|
||
<< ", parent()=" << (item.m_mapWidget ? item.m_mapWidget->parent() : nullptr) << "'"
|
||
<< ", isVisiStr=" << isVisiStr
|
||
<< ", updatesEnabledStr=" << updatesEnabledStr
|
||
<< std::endl;
|
||
} // for
|
||
} // for
|
||
}
|
||
|
||
private:
|
||
// map-name, ....
|
||
QMap<QString, QVector<Item>> m_mapWidgetCache;
|
||
}; // class ArcGISSceneLayerCache
|
||
|
||
#else
|
||
# pragma message("USE_MAP_CACHE is disabled")
|
||
#endif // USE_MAP_CACHE
|
||
|
||
|
||
|
||
SituationMapInit::SituationMapInit(QObject *parent)
|
||
: QObject(parent)
|
||
, m_logger(SituationMap::getLogger("SituationMapInit"))
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||
}
|
||
|
||
SituationMapInit::~SituationMapInit()
|
||
{
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION << " START";
|
||
|
||
if (m_pluginProvider == nullptr)
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " !m_pluginProvider";
|
||
m_adapterDds.clear();
|
||
return;
|
||
}
|
||
|
||
if (!m_pluginProvider->isSessionValid())
|
||
{
|
||
INFO_LOG(m_logger) << LOGFUNCTION << " no session anymore: return";
|
||
m_adapterDds.clear();
|
||
return;
|
||
}
|
||
|
||
|
||
if (m_adapterDds)
|
||
{
|
||
m_adapterDds->stop();
|
||
m_adapterDds.clear();
|
||
}
|
||
|
||
// remove some widgets (in context of toggle between 2D and 3D)
|
||
|
||
// SituationMap:
|
||
|
||
#ifdef USE_MAP_CACHE
|
||
|
||
if (m_situationMap)
|
||
{
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION << " MapCache: DELETE ...., isNull = " << m_situationMap->property(MapCacheState).isNull();
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION << " MapCache: DELETE ...., property = '" << (m_situationMap ? m_situationMap->property(MapCacheState).toString().toStdString() : "-") << "'";
|
||
|
||
if (m_situationMap->property(MapCacheState).isNull())
|
||
{
|
||
// no property -> 2D -> delete
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION << " MapCache: DELETE YES";
|
||
delete m_situationMap;
|
||
m_situationMap.clear();
|
||
} else {
|
||
// has property: interrupt parent-child-relationship
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION << " MapCache: DELETE NO, setParent->null";
|
||
m_situationMap->setParent(nullptr, true); // parent, beginDestroyFini
|
||
m_situationMap->setProperty(MapCacheState, QVariant()); // invalid QVariant -> property will be removed -> item is free for reUsing :-)
|
||
}
|
||
}
|
||
|
||
#else
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION << " DELETE situationMap: YES";
|
||
delete m_situationMap;
|
||
m_situationMap.clear();
|
||
#endif // USE_MAP_CACHE
|
||
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
ThatPartyIdToColorFunctor::ThatPartyIdToColorFunctor(const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc)
|
||
: BaseClass()
|
||
, m_ppmDtc(ppmDtc)
|
||
, m_logger(SituationMap::getLogger("ThatPartyIdToColorFunctor"))
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||
|
||
m_ppmDtc->waitForHistoricalDataParty(1000);
|
||
|
||
connect(m_ppmDtc.get(), &ParticipantManagement::Interface::Dtc::partyChanged,
|
||
this, &ThatPartyIdToColorFunctor::onPartyChanged);
|
||
|
||
m_ppmDtc->partys([this](const ParticipantManagement::Party & data)
|
||
{
|
||
onPartyChanged(data);
|
||
});
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||
}
|
||
|
||
void ThatPartyIdToColorFunctor::onPartyChanged(const ParticipantManagement::Party &data, DataModification modType)
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
|
||
<< ", modType= " << modType
|
||
<< " partyId=" << data.id()
|
||
<< " partyName='" << data.name() << "'"
|
||
<< " data.role().inner_enum=" << data.role();
|
||
|
||
const int partyId = data.id();
|
||
if (modType == DataModification::eRemoved
|
||
&& m_doRemovePartyFlag) // <--- pay attention (speed up replay)
|
||
removeParty(partyId);
|
||
else
|
||
{
|
||
const AdvancedSymbology::Role role = AdvancedSymbology::roleToRole<>(data.role());
|
||
const PartyData pData(ParticipantManagement::trPartyName(data.name()),
|
||
role,
|
||
QColor::fromRgb(QRgb(data.color())),
|
||
QColor::fromRgb(QRgb(data.fadingColor())));
|
||
|
||
setParty(partyId, pData);
|
||
}
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
bool SituationMapInit::initPluginProvider(SituationMap::PluginProvider *pluginProvider)
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START " << " session=" << pluginProvider;
|
||
|
||
m_pluginProvider = pluginProvider;
|
||
|
||
if (!m_pluginProvider)
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " no plugin provider!";
|
||
return false;
|
||
}
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START " << " session=" << pluginProvider;
|
||
return true;
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
bool SituationMapInit::initAdapter(QPointer<MovementTrackManager> &movementTrackMgr, bool resourceMode)
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||
|
||
if (!m_pluginProvider)
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " no plugin provider!";
|
||
return false;
|
||
}
|
||
|
||
// create AdapterDds
|
||
m_adapterDds = QSharedPointer<SituationMap::AdapterDds>(new SituationMap::AdapterDds);
|
||
|
||
// signal-signal
|
||
connect(m_adapterDds.data(), &AdapterDds::resourceManagerModeChanged,
|
||
this, &SituationMapInit::resourceManagerModeChanged);
|
||
|
||
if (m_situationMap == nullptr)
|
||
return false;
|
||
|
||
// init AdapterDds
|
||
if (!m_adapterDds->init(m_situationMap, m_pluginProvider, movementTrackMgr, resourceMode)) // re-think: resourceMode
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " m_adapterDds->init failed";
|
||
return false;
|
||
}
|
||
|
||
// create ThatPartyIdToColorFunctor (m_ppmDtc should be available now)
|
||
QSharedPointer<ThatPartyIdToColorFunctor> partyIdToColorFunctor =
|
||
QSharedPointer<ThatPartyIdToColorFunctor>(new ThatPartyIdToColorFunctor(m_pluginProvider->ppmDtc()));
|
||
m_situationMap->setPartyIdToColorFunctor(partyIdToColorFunctor);
|
||
|
||
// in context replay, skip removing of parties.
|
||
// the topic is removed and added -> no real modification:
|
||
// if (m_pluginProvider->isReplayPartition())
|
||
// partyIdToColorFunctor->setDoRemovePartyFlag(false);
|
||
|
||
// [NLDEVCTRL-1364] Ausfallkreuz TLN-Symbol - war teilweise schwarz.
|
||
// Daher nun auch in LiveLage kein eRemoved bearbeiten und Party 'behalten'.
|
||
partyIdToColorFunctor->setDoRemovePartyFlag(false);
|
||
|
||
connect(m_pluginProvider, &PluginProvider::partitionTimeChanged, this, [this](qint64 partitionTime)
|
||
{
|
||
if (m_situationMap)
|
||
m_situationMap->setPartitionTime(partitionTime);
|
||
});
|
||
|
||
// not neccessary, done in MapImpl::onAllPartysChanged / MapImpl::onPartyChanged :
|
||
// connect(partyIdToColorFunctor.data(), &ThatPartyIdToColorFunctor::partyChanged,
|
||
// m_adapterDds.data(), &SituationMap::AdapterDds::restartIfRunning);
|
||
// : not neccessary, done in MapImpl::onAllPartysChanged / MapImpl::onPartyChanged
|
||
|
||
connect(m_adapterDds.data(), &AdapterDds::participantPositionChanged,
|
||
this, &SituationMapInit::participantPositionChanged);
|
||
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||
return true;
|
||
}
|
||
|
||
void SituationMapInit::startDisplay()
|
||
{
|
||
if (!m_adapterDds)
|
||
return;
|
||
if (!m_situationMap)
|
||
return;
|
||
|
||
// run AdapterDds
|
||
QPointer<SituationMap::MapNotifier> mapNotifier = m_situationMap->createMapNotifier();
|
||
if (mapNotifier)
|
||
{
|
||
connect(mapNotifier.data(), &SituationMap::MapNotifier::mapReadyAndSymbolDictionaryLoaded, this, [this]()
|
||
{
|
||
// #define TRY_WORKAROUND_FOR_CRASH_ON_STARTUP
|
||
#ifdef TRY_WORKAROUND_FOR_CRASH_ON_STARTUP
|
||
QTimer::singleShot(500, std::bind(&SituationMap::AdapterDds::run, m_adapterDds));
|
||
#else
|
||
if (m_adapterDds) // might already be destroyed again (e.g. when closing the app before all was loaded)
|
||
m_adapterDds->run();
|
||
#endif // TRY_WORKAROUND_FOR_CRASH_ON_STARTUP
|
||
}, Qt::QueuedConnection);
|
||
|
||
mapNotifier->run();
|
||
}
|
||
}
|
||
|
||
void SituationMapInit::stopDisplay()
|
||
{
|
||
if (!m_adapterDds)
|
||
return;
|
||
m_adapterDds->stop();
|
||
}
|
||
|
||
bool SituationMapInit::clearObjects()
|
||
{
|
||
if (!m_adapterDds)
|
||
return false;
|
||
m_adapterDds->clearObjects();
|
||
|
||
if (!m_situationMap)
|
||
return false;
|
||
|
||
const int remainingObjectsCount = m_situationMap->objectFactory().count();
|
||
|
||
if (remainingObjectsCount != 0)
|
||
{
|
||
// maybe there are mapObjects of overlays...
|
||
WARNING_LOG(m_logger) << LOGFUNCTION << " remainingObjectsCount should be '0', is: " << remainingObjectsCount;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
SituationMap::Map *SituationMapInit::getWidget()
|
||
{
|
||
return m_situationMap;
|
||
}
|
||
|
||
SituationMap::AdapterDds *SituationMapInit::adapterDds()
|
||
{
|
||
return m_adapterDds.data();
|
||
}
|
||
|
||
bool SituationMapInit::enableMovementTrack(int participantId, bool enable)
|
||
{
|
||
if (!m_adapterDds)
|
||
return false;
|
||
|
||
auto ptr = m_adapterDds->simId2Participant(participantId);
|
||
if (!ptr)
|
||
return false;
|
||
|
||
QPointer<SituationMap::MovementTrackManager> movementTrackManager = m_adapterDds->movementTrackManager();
|
||
if (movementTrackManager)
|
||
{
|
||
const int trackId = participantId;
|
||
if (enable)
|
||
movementTrackManager->activateTrack(trackId); // Maybe another is deactivated/removed?
|
||
else
|
||
movementTrackManager->deactivateTrack(trackId);
|
||
}
|
||
|
||
// ptr->setMovementTrackEnabled(enable);
|
||
// if (!ptr->updateView())
|
||
// ERROR_LOG (m_logger) << "Couldn't update view after setting setMovementTrackEnabled(" << enable << ") for SimId: " << participantId;
|
||
|
||
return true;
|
||
}
|
||
|
||
bool SituationMapInit::isMovementTrackEnabled(int participantId) const
|
||
{
|
||
if (!m_adapterDds)
|
||
return false;
|
||
auto ptr = m_adapterDds->simId2Participant(participantId);
|
||
if (!ptr)
|
||
return false;
|
||
return ptr->isMovementTrackEnabled();
|
||
}
|
||
|
||
bool SituationMapInit::enableGearRanges(int participantId, bool enable)
|
||
{
|
||
if (!m_adapterDds)
|
||
return false;
|
||
auto ptr = m_adapterDds->simId2Participant(participantId);
|
||
if (!ptr)
|
||
return false;
|
||
ptr->setRangesVisibility(enable);
|
||
if (!ptr->updateView())
|
||
ERROR_LOG(m_logger) << "Couldn't updateview after setting setRangesVisibility(" << enable << ") for SimId: " << participantId;
|
||
|
||
return true;
|
||
}
|
||
|
||
bool SituationMapInit::isGearRangesEnabled(int participantId) const
|
||
{
|
||
if (!m_adapterDds)
|
||
return false;
|
||
auto ptr = m_adapterDds->simId2Participant(participantId);
|
||
if (!ptr)
|
||
return false;
|
||
return ptr->isRangesVisible();
|
||
}
|
||
|
||
QPointF SituationMapInit::centerPoint() const
|
||
{
|
||
return m_situationMap ? m_situationMap->centerPoint() : QPointF();
|
||
}
|
||
|
||
void SituationMapInit::setCenterPoint(const QPointF ¢er, double scale, float durationSeconds)
|
||
{
|
||
if (m_situationMap)
|
||
m_situationMap->setCenterPoint(center, scale, durationSeconds);
|
||
}
|
||
|
||
bool SituationMapInit::centerMapToParticipant(int participantId)
|
||
{
|
||
if (!m_situationMap || !m_adapterDds)
|
||
return false;
|
||
auto ptr = m_adapterDds->simId2Participant(participantId);
|
||
if (!ptr)
|
||
return false;
|
||
m_situationMap->setCenterPoint(ptr->origin().toPointF());
|
||
return true;
|
||
}
|
||
|
||
bool SituationMapInit::centerMapToAesObject(int entityId)
|
||
{
|
||
if (!m_situationMap || !m_adapterDds)
|
||
return false;
|
||
|
||
auto ptr = m_adapterDds->simId2Aes(entityId);
|
||
if (!ptr)
|
||
return false;
|
||
|
||
SituationMap::BoundingBox bbox;
|
||
ptr->boundingBox(bbox);
|
||
|
||
if (!bbox.isValid())
|
||
{
|
||
WARNING_LOG(m_logger) << LOGFUNCTION
|
||
<< " boundingBox not valid: bbox=" << bbox;
|
||
return false;
|
||
}
|
||
|
||
m_situationMap->setCenterPoint(bbox.center().toPointF());
|
||
return true;
|
||
}
|
||
|
||
|
||
bool SituationMapInit::centerMapToBuildingObject(int entityId)
|
||
{
|
||
if (!m_situationMap || !m_adapterDds)
|
||
return false;
|
||
auto ptr = m_adapterDds->simId2Building(entityId);
|
||
if (!ptr)
|
||
return false;
|
||
|
||
SituationMap::BoundingBox bbox;
|
||
ptr->boundingBox(bbox);
|
||
|
||
if (!bbox.isValid())
|
||
{
|
||
WARNING_LOG(m_logger) << LOGFUNCTION
|
||
<< " boundingBox not valid: bbox=" << bbox;
|
||
return false;
|
||
}
|
||
m_situationMap->setCenterPoint(bbox.center().toPointF());
|
||
return true;
|
||
}
|
||
|
||
bool SituationMapInit::centerMapToGuezIedObject(int entityId)
|
||
{
|
||
if (!m_situationMap || !m_adapterDds)
|
||
return false;
|
||
auto ptr = m_adapterDds->simId2GuezIed(entityId);
|
||
if (!ptr)
|
||
return false;
|
||
m_situationMap->setCenterPoint(ptr->origin().toPointF());
|
||
return true;
|
||
}
|
||
|
||
bool SituationMapInit::centerMapToChargeEffectObject(int entityId)
|
||
{
|
||
if (!m_situationMap || !m_adapterDds)
|
||
return false;
|
||
auto ptr = m_adapterDds->simId2ChargeEffect(entityId);
|
||
if (!ptr)
|
||
return false;
|
||
|
||
m_situationMap->setCenterPoint(ptr->origin().toPointF());
|
||
return true;
|
||
}
|
||
|
||
bool SituationMapInit::centerMapToMapObject(MapObjectType mot, int entityId)
|
||
{
|
||
if (!m_adapterDds || !m_situationMap)
|
||
return false;
|
||
|
||
auto ptr = m_adapterDds->simId2MapObject(mot, entityId);
|
||
if (!ptr)
|
||
return false;
|
||
|
||
SituationMap::BoundingBox bbox;
|
||
ptr->boundingBox(bbox);
|
||
|
||
if (!bbox.isValid())
|
||
{
|
||
WARNING_LOG(m_logger) << LOGFUNCTION
|
||
<< " boundingBox not valid: bbox=" << bbox;
|
||
return false;
|
||
}
|
||
|
||
// should work for
|
||
// - PointSymbols/Particpant (ExtentType::Pixel) as well as
|
||
// - MultiPointSymbols/Areas (ExtentType::Sim)
|
||
m_situationMap->setCenterPoint(bbox.center().toPointF());
|
||
|
||
return true;
|
||
}
|
||
|
||
bool SituationMapInit::zoomMapTo(const QVector<QPair<MapObjectType, int> > &entities, int paddingInDIPS)
|
||
{
|
||
if (!m_adapterDds || !m_situationMap)
|
||
return false;
|
||
|
||
PositionCont posCont;
|
||
|
||
for (const QPair<MapObjectType, int> &entity : qAsConst(entities))
|
||
{
|
||
RefPointer<AbstractMapObject> mapObj = m_adapterDds->simId2MapObject(entity.first, entity.second);
|
||
if (!mapObj)
|
||
continue;
|
||
|
||
RefPointer<AbstractSinglePointMapObject> single(mapObj); // dynacast
|
||
if (single)
|
||
posCont.push_back(single->origin());
|
||
else
|
||
{
|
||
RefPointer<Participant> participant(mapObj); // dynacast
|
||
if (participant)
|
||
posCont.push_back(participant->origin());
|
||
else
|
||
{
|
||
RefPointer<AbstractMultiPointMapObject> multi(mapObj); // dynacast
|
||
if (multi)
|
||
posCont += multi->positions();
|
||
}
|
||
}
|
||
} // for
|
||
|
||
if (!posCont.isEmpty())
|
||
{
|
||
QVector<QPointF> coords;
|
||
coords.reserve(posCont.size());
|
||
for (const Point3D p : qAsConst(posCont))
|
||
coords.push_back(p.toPointF());
|
||
m_situationMap->zoomToArea(coords, paddingInDIPS);
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
//QSharedPointer<AdvancedSymbology::SymbolResult> SituationMapInit::findPreviewImage(const QString &objectType, int entityId)
|
||
//{
|
||
// return QSharedPointer<AdvancedSymbology::SymbolResult>(new AdvancedSymbology::SymbolResult());
|
||
//}
|
||
|
||
bool SituationMapInit::objectIndicatorToParticipant(int participantId, bool setSelected, int lifetimeMsec)
|
||
{
|
||
if (!m_adapterDds || !m_situationMap)
|
||
return false;
|
||
auto ptr = m_adapterDds->simId2Participant(participantId);
|
||
if (!ptr)
|
||
return false;
|
||
m_situationMap->objectIndicator().setMapObjectToPointTo(ptr->uniqueMapId(), setSelected, lifetimeMsec);
|
||
return true;
|
||
}
|
||
|
||
bool SituationMapInit::objectIndicatorToAesObject(int entityId)
|
||
{
|
||
if (!m_adapterDds || !m_situationMap)
|
||
return false;
|
||
auto ptr = m_adapterDds->simId2Aes(entityId);
|
||
if (!ptr)
|
||
return false;
|
||
m_situationMap->objectIndicator().setMapObjectToPointTo(ptr->uniqueMapId());
|
||
return true;
|
||
}
|
||
|
||
bool SituationMapInit::objectIndicatorToBuildingObject(int entityId)
|
||
{
|
||
if (!m_adapterDds || !m_situationMap)
|
||
return false;
|
||
auto ptr = m_adapterDds->simId2Building(entityId);
|
||
if (!ptr)
|
||
return false;
|
||
m_situationMap->objectIndicator().setMapObjectToPointTo(ptr->uniqueMapId());
|
||
return true;
|
||
}
|
||
|
||
bool SituationMapInit::objectIndicatorToGuezIedObject(int entityId)
|
||
{
|
||
if (!m_adapterDds || !m_situationMap)
|
||
return false;
|
||
auto ptr = m_adapterDds->simId2GuezIed(entityId);
|
||
if (!ptr)
|
||
return false;
|
||
m_situationMap->objectIndicator().setMapObjectToPointTo(ptr->uniqueMapId());
|
||
return true;
|
||
}
|
||
|
||
bool SituationMapInit::objectIndicatorToMapObject(MapObjectType mot, int entityId, bool setSelected, int lifetimeMsec)
|
||
{
|
||
if (!m_adapterDds || !m_situationMap)
|
||
return false;
|
||
|
||
const UniqueMapId uniqueMapId = m_adapterDds->simId2UniqueMapId(mot, entityId);
|
||
if (!isUniqueMapIdValid(uniqueMapId))
|
||
return false;
|
||
|
||
m_situationMap->objectIndicator().setMapObjectToPointTo(uniqueMapId, setSelected, lifetimeMsec);
|
||
return true;
|
||
}
|
||
|
||
bool SituationMapInit::objectIndicatorToPoint(const QPointF &targetGeo, int lifetimeMsec)
|
||
{
|
||
if (!m_adapterDds || !m_situationMap)
|
||
return false;
|
||
m_situationMap->objectIndicator().setPointToPointTo(targetGeo, lifetimeMsec);
|
||
return true;
|
||
}
|
||
|
||
bool SituationMapInit::removeObjectIndicator()
|
||
{
|
||
if (!m_situationMap)
|
||
return false;
|
||
|
||
m_situationMap->objectIndicator().remove();
|
||
return true;
|
||
}
|
||
|
||
bool SituationMapInit::setMapObjectSelected(MapObjectType mot, const QVector<int> &entityIds, bool selection)
|
||
{
|
||
if (!m_adapterDds)
|
||
return false;
|
||
|
||
m_adapterDds->setMapObjectSelected(mot, entityIds, selection);
|
||
return true;
|
||
}
|
||
|
||
bool SituationMapInit::clearMapObjectSelection(MapObjectType mot)
|
||
{
|
||
if (!m_adapterDds)
|
||
return false;
|
||
m_adapterDds->clearMapObjectSelection(mot);
|
||
return true;
|
||
}
|
||
|
||
bool SituationMapInit::skipMapObjectSelectionDialog() const
|
||
{
|
||
return m_skipMapObjectSelectionDialog;
|
||
}
|
||
|
||
void SituationMapInit::setSkipMapObjectSelectionDialog(bool asList)
|
||
{
|
||
m_skipMapObjectSelectionDialog = asList;
|
||
}
|
||
|
||
void SituationMapInit::startMeasureLength()
|
||
{
|
||
if (!m_situationMap)
|
||
return ;
|
||
m_situationMap->measurement().measureLength();
|
||
}
|
||
void SituationMapInit::clearMeasureLength()
|
||
{
|
||
if (!m_situationMap)
|
||
return ;
|
||
m_situationMap->measurement().clear();
|
||
}
|
||
|
||
void SituationMapInit::startViewshed()
|
||
{
|
||
if (!m_situationMap)
|
||
return ;
|
||
|
||
m_viewshedId = -1;
|
||
QObject::disconnect(m_viewshedFinishedConnection);
|
||
m_viewshedFinishedConnection = connect(&m_situationMap->viewshed(), &Viewshed::viewshedFinished,
|
||
this, &SituationMapInit::onViewshedFinished);
|
||
|
||
m_situationMap->viewshed().create(); // no para -> start rubberband
|
||
}
|
||
|
||
void SituationMapInit::startViewshed(double alpha, double innerRadius, double observerHeight, double targetHeight, double beamAngle)
|
||
{
|
||
if (!m_situationMap)
|
||
return ;
|
||
|
||
m_viewshedId = -1;
|
||
QObject::disconnect(m_viewshedFinishedConnection);
|
||
m_viewshedFinishedConnection = connect(&m_situationMap->viewshed(), &Viewshed::viewshedFinished,
|
||
this, &SituationMapInit::onViewshedFinished);
|
||
|
||
m_situationMap->viewshed().create(alpha, innerRadius, observerHeight, targetHeight, beamAngle); // not enough para -> start rubberband
|
||
}
|
||
|
||
void SituationMapInit::onViewshedFinished(long viewshedId)
|
||
{
|
||
m_viewshedId = viewshedId;
|
||
QObject::disconnect(m_viewshedFinishedConnection); // disconnect even if viewshedId is invalid
|
||
}
|
||
|
||
void SituationMapInit::modifyViewshed(double alpha, double innerRadius, double observerHeight, double targetHeight, double beamAngle)
|
||
{
|
||
if (m_situationMap)
|
||
{
|
||
if (m_viewshedId >= 0)
|
||
m_situationMap->viewshed().modify(m_viewshedId, alpha, innerRadius, observerHeight, targetHeight, beamAngle);
|
||
else
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION << " m_viewshedId invalid (" << m_viewshedId << ")";
|
||
}
|
||
}
|
||
|
||
void SituationMapInit::clearViewshed()
|
||
{
|
||
if (m_situationMap)
|
||
m_situationMap->viewshed().remove(); // no para -> remove all
|
||
m_viewshedId = -1;
|
||
}
|
||
|
||
bool SituationMapInit::showExpiredEmergencyCalls(bool showExpired)
|
||
{
|
||
if (!m_adapterDds)
|
||
return false;
|
||
return m_adapterDds->showExpiredEmergencyCalls(showExpired);
|
||
}
|
||
|
||
|
||
bool SituationMapInit::setOwnPositionVisible(bool enable)
|
||
{
|
||
return m_adapterDds ? m_adapterDds->setOwnPositionVisible(enable) : false;
|
||
}
|
||
|
||
bool SituationMapInit::isOwnPositionVisble() const
|
||
{
|
||
return m_adapterDds ? m_adapterDds->isOwnPositionVisible() : false;
|
||
}
|
||
|
||
bool SituationMapInit::isBuildingOwnershipSupported() const
|
||
{
|
||
return m_adapterDds ? m_adapterDds->isBuildingOwnershipSupported() : false;
|
||
}
|
||
bool SituationMapInit::isBuildingOwnershipVisible() const
|
||
{
|
||
return m_adapterDds ? m_adapterDds->isBuildingOwnershipVisible() : false;
|
||
}
|
||
bool SituationMapInit::setBuildingOwnershipVisible(bool visible)
|
||
{
|
||
return m_adapterDds ? m_adapterDds->setBuildingOwnershipVisible(visible) : false;
|
||
}
|
||
|
||
bool SituationMapInit::isBuildingContaminationSupported() const
|
||
{
|
||
return m_adapterDds ? m_adapterDds->isBuildingContaminationSupported() : false;
|
||
}
|
||
bool SituationMapInit::isBuildingContaminationVisible() const
|
||
{
|
||
return m_adapterDds ? m_adapterDds->isBuildingContaminationVisible() : false;
|
||
}
|
||
bool SituationMapInit::setBuildingContaminationVisible(bool visible)
|
||
{
|
||
return m_adapterDds ? m_adapterDds->setBuildingContaminationVisible(visible) : false;
|
||
}
|
||
|
||
bool SituationMapInit::enableFireEventFlashing(bool enable)
|
||
{
|
||
return m_adapterDds ? m_adapterDds->enableFireEventFlashing(enable) : false;
|
||
}
|
||
|
||
bool SituationMapInit::isFireEventFlashingEnabled() const
|
||
{
|
||
return m_adapterDds ? m_adapterDds->isFireEventFlashingEnabled() : false;
|
||
}
|
||
|
||
|
||
void SituationMapInit::setPlaybackTimeString(const QString &timeString)
|
||
{
|
||
if (m_situationMap == nullptr)
|
||
return;
|
||
m_situationMap->setTimeString(timeString);
|
||
m_situationMap->showTimeString(true);
|
||
}
|
||
|
||
SituationMap::RB::RubberbandFactory &SituationMapInit::rubberbandFactory()
|
||
{
|
||
if (m_situationMap != nullptr)
|
||
return m_situationMap->rubberbandFactory();
|
||
|
||
// TODO: fallback for very bad cases! workaround:
|
||
SituationMap::Map *temp = SituationMap::Map::create();
|
||
return temp->rubberbandFactory();
|
||
}
|
||
|
||
ResourceManagerMode SituationMapInit::resourceManagerMode() const
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||
if (!m_adapterDds)
|
||
return ResourceManagerMode::Undefined;
|
||
|
||
ResourceManagerMode rmm = m_adapterDds->resourceManagerMode();
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||
return rmm;
|
||
}
|
||
bool SituationMapInit::setResourceManagerMode(ResourceManagerMode rmm)
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||
if (!m_adapterDds)
|
||
return false;
|
||
|
||
bool success = m_adapterDds->setResourceManagerMode(rmm);
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||
return success;
|
||
}
|
||
|
||
RefPointer<Participant> SituationMapInit::simId2Participant(int32_t simId)
|
||
{
|
||
if (!m_adapterDds)
|
||
return RefPointer<Participant>();
|
||
return m_adapterDds->simId2Participant(simId);
|
||
}
|
||
|
||
QVector<UniqueMapId> SituationMapInit::simIds2UniqueMapIds(MapObjectType mot, const QVector<int32_t> &simIds) const
|
||
{
|
||
if (!m_adapterDds)
|
||
return {};
|
||
return m_adapterDds->simIds2UniqueMapIds(mot, simIds);
|
||
}
|
||
|
||
static QVector<BaseUrl> convertMapDecription2BaseUrlVec(const std::vector<AssetManagement::MapDescription>& vecIn)
|
||
{
|
||
QVector<BaseUrl> vecOut;
|
||
vecOut.reserve(vecIn.size());
|
||
|
||
for (const AssetManagement::MapDescription &mapDescription : vecIn)
|
||
{
|
||
BaseUrl baseUrl(QString::fromStdString(mapDescription.url()),
|
||
mapDescription.minScale(), mapDescription.maxScale());
|
||
|
||
baseUrl.setName(QString::fromStdString(mapDescription.name()));
|
||
baseUrl.setDescription(QString::fromStdString(mapDescription.description()));
|
||
|
||
switch (mapDescription.mapTypeId().underlying()) {
|
||
case AssetManagement::MapType_def::Aerial:
|
||
baseUrl.setBasemapType(BasemapType::Aerial);
|
||
break;
|
||
case AssetManagement::MapType_def::Topographic:
|
||
baseUrl.setBasemapType(BasemapType::Topographic);
|
||
break;
|
||
case AssetManagement::MapType_def::Elevation:
|
||
case AssetManagement::MapType_def::Feature:
|
||
case AssetManagement::MapType_def::SceneObjects:
|
||
case AssetManagement::MapType_def::Unknown:
|
||
break;
|
||
} // switch
|
||
vecOut.append(baseUrl);
|
||
} // for
|
||
|
||
return vecOut;
|
||
}
|
||
|
||
bool SituationMapInit::trainingAreaExists() const
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||
|
||
if (!m_pluginProvider->exmDtc() || !m_pluginProvider->asmDtc())
|
||
return false;
|
||
|
||
const int exerciseId = m_pluginProvider->exerciseId();
|
||
if (exerciseId <= 0)
|
||
return false;
|
||
|
||
const int trainingAreaId = m_pluginProvider->exmDtc()->exercise(exerciseId).trainingAreaId();
|
||
if (trainingAreaId <= 0)
|
||
return false;
|
||
|
||
const AssetManagement::TrainingArea &ta = m_pluginProvider->asmDtc()->trainingArea(trainingAreaId);
|
||
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, trainingAreaExists = " << (ta.id() == trainingAreaId);
|
||
return (ta.id() == trainingAreaId);
|
||
}
|
||
|
||
MapSettingsJson SituationMapInit::getMapSettingsFromService() const
|
||
{
|
||
MapSettingsJson msj;
|
||
|
||
if (!m_pluginProvider->exmDtc() || !m_pluginProvider->asmDtc())
|
||
return msj;
|
||
|
||
const int exerciseId = m_pluginProvider->exerciseId();
|
||
const int trainingAreaId = m_pluginProvider->exmDtc()->exercise(exerciseId).trainingAreaId();
|
||
|
||
AssetManagement::TrainingArea ta = m_pluginProvider->asmDtc()->trainingArea(trainingAreaId);
|
||
|
||
if (ta.id() != trainingAreaId)
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " TrainingArea does not exists (yet)";
|
||
return msj;
|
||
}
|
||
|
||
msj.setMapUrls (convertMapDecription2BaseUrlVec(ta.map2D()));
|
||
msj.setSceneUrls (convertMapDecription2BaseUrlVec(ta.scene3D()));
|
||
msj.setSceneObjectUrls(convertMapDecription2BaseUrlVec(ta.sceneObjects()));
|
||
msj.setElevationUrls (convertMapDecription2BaseUrlVec(ta.elevation()));
|
||
|
||
return msj;
|
||
}
|
||
|
||
//SLOTS
|
||
|
||
bool SituationMapInit::initMap(bool enableSelection, SituationMap::Mode mapMode, const SituationMap::Viewpoint2D &viewPoint)
|
||
{
|
||
INFO_LOG(m_logger) << LOGFUNCTION << " START, enableSelection=" << enableSelection
|
||
<< ", mapMode=" << mapMode;
|
||
|
||
#ifdef USE_MAP_CACHE
|
||
|
||
bool reUsing = false;
|
||
|
||
if (mapMode == Mode::Mode_3D)
|
||
{
|
||
// GUEZE-791 - RPL Nr 791: Arbeitsspeicherleck:
|
||
MapCache::Item& mapCacheItemRef = MapCache::getInstance()->getFreeItemRef(QStringLiteral("3dMapWidget"));
|
||
|
||
if (m_logger.isInfoEnabled())
|
||
MapCache::getInstance()->dump();
|
||
|
||
const bool reUse = mapCacheItemRef.m_mapWidget;
|
||
|
||
if (reUse)
|
||
{
|
||
m_situationMap = mapCacheItemRef.m_mapWidget;
|
||
m_situationMap->setProperty(MapCacheState, QVariant(QStringLiteral("3D/reUsed/taken")));
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION << " MapCache: ReUse Mode_3D"
|
||
<< " (updatesEnabled()=" << m_situationMap->updatesEnabled() << ")";
|
||
reUsing = true;
|
||
} else {
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION << " MapCache: CREATE Mode_3D";
|
||
m_situationMap = SituationMap::Map::create();
|
||
mapCacheItemRef.m_mapWidget = m_situationMap;
|
||
mapCacheItemRef.m_mapWidget->setProperty(MapCacheState, QVariant(QStringLiteral("3D/created")));
|
||
}
|
||
|
||
} // if (mapMode == Mode::Mode_3D)
|
||
else
|
||
{
|
||
m_situationMap = SituationMap::Map::create();
|
||
// no property at 2D: m_situationMap->setProperty(MapCacheState, QVariant(QStringLiteral("2D/created")));
|
||
}
|
||
|
||
if (m_logger.isInfoEnabled())
|
||
MapCache::getInstance()->dump();
|
||
|
||
#else
|
||
m_situationMap = SituationMap::Map::create();
|
||
#endif // USE_MAP_CACHE
|
||
|
||
if (enableSelection)
|
||
{
|
||
connect(m_situationMap.data(), &SituationMap::Map::mapObjectsClicked, this, &SituationMapInit::onMapObjectsClicked);
|
||
connect(m_situationMap.data(), &SituationMap::Map::mapObjectsPickedByArea, this, &SituationMapInit::onMapObjectClickedByArea);
|
||
|
||
connect(m_situationMap.data(), &SituationMap::Map::mapReadyAndSymbolDictionaryLoaded, this, [this]()
|
||
{
|
||
// just for 2D (mode is valid later)
|
||
if (m_situationMap->mode() == SituationMap::Mode::Mode_2D)
|
||
{
|
||
connect(m_situationMap.data()
|
||
, &SituationMap::Map::contextMenuClicked
|
||
, this
|
||
, &SituationMapInit::onContextMenuRequested); // siehe auch sit_map.cpp Zeile 421 ff
|
||
}
|
||
});
|
||
} // if (enableSelection)
|
||
|
||
// handle Destruction of MapWidget
|
||
// any partitionTimeChanged signals will cause problems:
|
||
connect(m_situationMap.data(), &SituationMap::Map::beginDestroy, this, &SituationMapInit::onMapbeginDestroy);
|
||
|
||
if (m_situationMap == nullptr)
|
||
{
|
||
FATAL_LOG(m_logger) << LOGFUNCTION << " map not available!";
|
||
return false;
|
||
}
|
||
|
||
#ifdef USE_MAP_CACHE
|
||
if (reUsing)
|
||
return true;
|
||
#endif // USE_MAP_CACHE
|
||
|
||
|
||
INFO_LOG(m_logger) << LOGFUNCTION << " ***** initMap:"
|
||
<< ", mapMode=" << mapMode
|
||
<< ", m_pluginProvider->toString=" << m_pluginProvider->toString()
|
||
<< ", exerciseId()= " << m_pluginProvider->exerciseId();
|
||
|
||
m_situationMap->setReplay(m_pluginProvider->isReplayPartition());
|
||
|
||
bool success = false;
|
||
if ( (m_pluginProvider->appId() == LtsAppDescriptor::App::OC) ||
|
||
(m_pluginProvider->appId() == LtsAppDescriptor::App::SituationTablet) ||
|
||
(m_pluginProvider->exerciseId() == 0) // e.g. in case of App::ResourceManager
|
||
)
|
||
{
|
||
// OC -> offline -> use local map urls (iniFile):
|
||
success = initMapPart2(mapMode, viewPoint);
|
||
} else {
|
||
// !OC -> online -> give map descriptions at asm_training_area a chance:
|
||
|
||
|
||
const bool bTrainingAreaExists = this->trainingAreaExists();
|
||
|
||
INFO_LOG(m_logger) << LOGFUNCTION << " bTrainingAreaExists=" << bTrainingAreaExists
|
||
<< ", m_pluginProvider->toString " << m_pluginProvider->toString();
|
||
|
||
bool bIsOfTypeOrganizer =
|
||
(m_pluginProvider->operatorId() == 99) || // 99 == Organisator
|
||
(m_pluginProvider->operatorId() == 98); // 98 == Organizer
|
||
|
||
if (bTrainingAreaExists || bIsOfTypeOrganizer) // 99 == Organisator
|
||
{
|
||
const MapSettingsJson &mapSettingsFromService = getMapSettingsFromService();
|
||
success = initMapPart2(mapMode, viewPoint, &mapSettingsFromService);
|
||
return success;
|
||
}
|
||
|
||
// if trainingAreaExists does not exists:
|
||
// like race condition publishing data at newly created replay environment and creating snapshotApp (this code)
|
||
|
||
LtsWidgets::LtsGlobalWaitDialog::getInstance()->wait(); // really visible???
|
||
LtsWidgets::LtsGlobalWaitDialog::getInstance()->setCustomText(tr("Situation Map is starting..."));
|
||
|
||
QTimer *waitForTa = new QTimer(this);
|
||
waitForTa->setInterval(250);
|
||
waitForTa->setProperty("tries", 0); // HACK
|
||
connect(waitForTa, &QTimer::timeout,
|
||
this, [this, waitForTa, mapMode, viewPoint]()
|
||
{
|
||
int tries = waitForTa->property("tries").toInt();
|
||
|
||
INFO_LOG(m_logger) << LOGFUNCTION << " waiting for trainingAreaExists " << trainingAreaExists() << ", tries = " << tries;
|
||
|
||
if (this->trainingAreaExists())
|
||
{
|
||
LtsWidgets::LtsGlobalWaitDialog::getInstance()->done();
|
||
waitForTa->stop();
|
||
|
||
const MapSettingsJson &mapSettingsFromService = getMapSettingsFromService();
|
||
if (!initMapPart2(mapMode, viewPoint, &mapSettingsFromService))
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " initMapPart2 failed";
|
||
}
|
||
|
||
if (tries > 30)
|
||
{
|
||
LtsWidgets::LtsGlobalWaitDialog::getInstance()->done();
|
||
waitForTa->stop();
|
||
|
||
// giving up: use values of ini file:
|
||
NOTICE_LOG(m_logger) << LOGFUNCTION << " waiting for trainingAreaExists " << trainingAreaExists() << ", tries = " << tries
|
||
<< " giving up";
|
||
|
||
if (!initMapPart2(mapMode, viewPoint))
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " initMapPart2 failed";
|
||
return;
|
||
}
|
||
waitForTa->setProperty("tries", ++tries);
|
||
});
|
||
|
||
waitForTa->start();
|
||
|
||
return true;
|
||
}
|
||
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, success=" << success;
|
||
return success;
|
||
}
|
||
|
||
bool SituationMapInit::initMapPart2(SituationMap::Mode mapMode,
|
||
const SituationMap::Viewpoint2D &viewPoint,
|
||
const MapSettingsJson* mapSettingJson)
|
||
{
|
||
INFO_LOG(m_logger) << LOGFUNCTION << " mapSettingJson=" << mapSettingJson;
|
||
|
||
bool success = true;
|
||
|
||
const QString initFilePath = NGL::findFile(NGL::FileType::ConfigFile, QStringLiteral("situation_map_defaults.ini"));
|
||
if (!QFile::exists(initFilePath))
|
||
{
|
||
FATAL_LOG(m_logger) << LOGFUNCTION << " MapIniFile location failed, used path: '" << initFilePath << "'";
|
||
assert(false);
|
||
return false;
|
||
}
|
||
else
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION << " ***** MapIniFile found: " << initFilePath;
|
||
|
||
// ownership goes to m_situationMap
|
||
SituationMap::MapSettings *mapSettings =
|
||
new SituationMap::MapSettings(initFilePath, m_situationMap);
|
||
ThatMapInitializer *mapInitializer =
|
||
new ThatMapInitializer(*m_situationMap, *mapSettings, QLatin1String("SituationMapInterface"), m_situationMap);
|
||
|
||
if (mapSettingJson)
|
||
mapInitializer->setMapSettingsJson(*mapSettingJson);
|
||
|
||
mapInitializer->setViewPoint(viewPoint); // viewPoint is allowed to be null :-)
|
||
|
||
if (mapInitializer->hasErrors())
|
||
{
|
||
FATAL_LOG(m_logger) << LOGFUNCTION << " MapInitializer-filename='" << mapInitializer->filename()
|
||
<< "'' has following errors: "
|
||
<< " exists = " << mapInitializer->exists()
|
||
<< " accessError = " << mapInitializer->accessError()
|
||
<< " formatError = " << mapInitializer->formatError();
|
||
success = false;
|
||
}
|
||
else
|
||
success = mapInitializer->initMap(mapMode);
|
||
|
||
|
||
#ifdef USE_FUNCTIONDIALOG
|
||
// add FunctionDialog if needed:
|
||
if (m_situationMap)
|
||
SituationMap::FunctionDialog::addButtonToMap(m_situationMap);
|
||
#endif // USE_FUNCTIONDIALOG
|
||
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, success=" << success;
|
||
return success;
|
||
}
|
||
|
||
void SituationMapInit::myMapWidgetDialogIsAboutToBeClosed()
|
||
{
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION << " START";
|
||
|
||
// cleanup MapObjects and ESRI-Objects:
|
||
if (m_adapterDds)
|
||
{
|
||
m_adapterDds->stop();
|
||
m_adapterDds->clearObjects();
|
||
m_adapterDds.clear();
|
||
}
|
||
|
||
// If the user performs a logout, the MainDialog/LtsDialog/MyMapWidgetDialog
|
||
// (and children) is going to be destroyed.
|
||
//
|
||
if (m_situationMap && !m_situationMap->property(MapCacheState).isNull())
|
||
{
|
||
// m_situationMap has property (means 3D), so it should stay at the cache.
|
||
// But prevent destruction by interrupting parent-child-relationship
|
||
// and destroy some children like functionDialog, LayerControlDialog etc.
|
||
INFO_LOG(m_logger) << LOGFUNCTION << " MapCache: prevent destruction";
|
||
m_situationMap->setParent(nullptr, true); // parent, beginDestroyFini
|
||
// do not remove property !! //m_situationMap->setProperty(MapCacheState, QVariant());
|
||
}
|
||
}
|
||
|
||
QPointer<SituationMap::MovementTrackManager> SituationMapInit::movementTrackManager() const
|
||
{
|
||
if (!m_adapterDds)
|
||
return {};
|
||
return m_adapterDds->movementTrackManager();
|
||
}
|
||
|
||
|
||
bool SituationMapInit::updateAll()
|
||
{
|
||
if (m_situationMap == nullptr)
|
||
return false;
|
||
|
||
if (!m_situationMap->isReady())
|
||
{
|
||
INFO_LOG(m_logger) << LOGFUNCTION << " Map Not ready Yet: Skip ";
|
||
return false;
|
||
}
|
||
// m_situationMap->rubberbandFactory();
|
||
|
||
return true;
|
||
}
|
||
|
||
void SituationMapInit::onMapbeginDestroy()
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||
if (m_adapterDds)
|
||
{
|
||
m_adapterDds->stop();
|
||
m_adapterDds.clear();
|
||
}
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||
}
|
||
|
||
void SituationMapInit::onMapObjectsClicked(const SituationMap::Map::RefPointerMapObjectList &mapObjList,
|
||
const QPointF &viewportPosition)
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " ViewPort X: " << viewportPosition.x() << " Y: " << viewportPosition.y();
|
||
onMapObjectClickedByArea(mapObjList);
|
||
}
|
||
|
||
void SituationMapInit::onMapObjectClickedByArea(const SituationMap::Map::RefPointerMapObjectList &mapObjList)
|
||
{
|
||
//
|
||
// In Case of assignment of MountingPoints at resourceApp of ISM :
|
||
//
|
||
if (m_skipMapObjectSelectionDialog)
|
||
{
|
||
QVector<SituationMap::UniqueMapId> uniqueMapIdVec;
|
||
uniqueMapIdVec.reserve(mapObjList.size());
|
||
for (const auto &mapObject : mapObjList)
|
||
uniqueMapIdVec.append(mapObject->uniqueMapId());
|
||
m_adapterDds->onMapObjectsClicked(uniqueMapIdVec);
|
||
return;
|
||
}
|
||
// : In Case of assignment of MountingPoints at resourceApp of ISM
|
||
|
||
|
||
//
|
||
// typical :
|
||
//
|
||
|
||
// size = 0 || 1 || > 1
|
||
// 0 -> nothing, stays as before
|
||
// 1 -> open InfoDialog direct
|
||
// >1 -> create, update content of mapObjectSelection
|
||
|
||
if (mapObjList.isEmpty())
|
||
return;
|
||
|
||
if (mapObjList.size() == 1)
|
||
{
|
||
//
|
||
// open InfoDialog for a single object immediately:
|
||
//
|
||
const auto &mapObj = mapObjList.front();
|
||
{
|
||
if (!m_adapterDds->onMapObjectClicked(mapObj))
|
||
WARNING_LOG(m_logger) << LOGFUNCTION << " Click on a map object but found no handler for it ... "
|
||
<< " mapObj: debugInfo='" << mapObj->debugInfo() << "'"
|
||
<< " uniqueMapId=" << mapObj->uniqueMapId();
|
||
}
|
||
return;
|
||
}
|
||
|
||
emit mapObjectsClicked(mapObjList);
|
||
}
|
||
|
||
void SituationMapInit::onProcessMapObjectClicked(const QVector<SituationMap::UniqueMapId> &uniqueMapIds)
|
||
{
|
||
if (!m_adapterDds)
|
||
return;
|
||
if (!m_adapterDds->onMapObjectsClicked(uniqueMapIds))
|
||
WARNING_LOG(m_logger) << LOGFUNCTION << " onMapObjectsClicked failed ... ";
|
||
}
|
||
|
||
void SituationMapInit::onContextMenuRequested(const SituationMap::Map::RefPointerMapObjectList &mapObjList,
|
||
const QPointF &viewportPosition)
|
||
{
|
||
Q_UNUSED(mapObjList);
|
||
|
||
if (!m_situationMap)
|
||
return;
|
||
|
||
QMenu *contextMenu = new QMenu(); // WA_DeleteOnClose -> no parent required
|
||
contextMenu->setAttribute(Qt::WA_DeleteOnClose);
|
||
|
||
{ // 1
|
||
QAction *act = contextMenu->addAction(tr("Area Selection"));
|
||
connect(act, &QAction::triggered, this, [this]()
|
||
{
|
||
if (m_situationMap)
|
||
m_situationMap->pickMapObjectsArea();
|
||
});
|
||
}
|
||
|
||
{ // 2
|
||
QAction *act = contextMenu->addAction(tr("Area Scale"));
|
||
connect(act, &QAction::triggered, this, [this]()
|
||
{
|
||
if (m_situationMap)
|
||
m_situationMap->scaleByArea();
|
||
});
|
||
}
|
||
|
||
|
||
if (LtsSessionData::LtsSessionData::getInstance()->hasOperatorRight(OperatorRights::SituationMap::SituationMapMeasureDistance))
|
||
{
|
||
{ // 3
|
||
QAction *act = contextMenu->addAction(tr("Start Measure Length"));
|
||
connect(act, &QAction::triggered, this, [this]()
|
||
{
|
||
if (m_situationMap)
|
||
m_situationMap->measurement().measureLength();
|
||
});
|
||
}
|
||
{ // 4
|
||
QAction *act = contextMenu->addAction(tr("Clear Measure Length"));
|
||
connect(act, &QAction::triggered, this, [this]()
|
||
{
|
||
if (m_situationMap)
|
||
m_situationMap->measurement().clear();
|
||
});
|
||
}
|
||
}
|
||
|
||
// 5
|
||
QAction *saveAsImageAction = contextMenu->addAction(tr("Save as image"));
|
||
connect(saveAsImageAction, &QAction::triggered,
|
||
this, &SituationMapInit::saveAsImageRequested);
|
||
|
||
// QAction *terrainProfileStart = contextMenu.addAction(tr("Start Terrain Profile"));
|
||
// QAction *terrainProfileClear = contextMenu.addAction(tr("Terrain Profile"));
|
||
|
||
contextMenu->popup(m_situationMap->mapToGlobal(viewportPosition.toPoint()));
|
||
}
|
||
|
||
} // namespace SituationMap
|