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

@@ -0,0 +1,202 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#include "explosion_single_central_to_map.h"
#include "pdm_handler.h"
#include <Map/bounding_box.h>
#include <LtsCoordTrans/lts_coord_trans.h>
#include <ParticipantManagement/Data/ppm_data_plugin.h>
namespace SituationMap
{
ExplosionSingleCentral2SituationMap::ExplosionSingleCentral2SituationMap(PdmHandler *pdmHandler, ObjectFactory &objFac, const QString &layername, const char *loggerName)
: BaseClass(objFac, layername, loggerName)
, m_pdmHandler(pdmHandler)
{
}
bool ExplosionSingleCentral2SituationMap::init(PluginProvider *pluginProvider)
{
if (!BaseClass::init(pluginProvider) ||
!pluginProvider->ppmDtc())
return false;
m_ppmDtc = pluginProvider->ppmDtc();
return true;
}
bool ExplosionSingleCentral2SituationMap::run()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (! m_aesDtc)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no dtc";
return false;
}
// attention: as orginizer this may not necessary:
// m_aesDtc->waitForHistoricalDataExplosionSingleCentral(1000);
// m_ppmDtc->waitForHistoricalDataParticipant(1000);
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::explosionSingleCentralChanged,
this, &ExplosionSingleCentral2SituationMap::handleChanged, Qt::UniqueConnection);
// get:
m_aesDtc->explosionSingleCentrals([this](const AreaEffectSimulation::ExplosionSingleCentral & data)
{
handleChanged(data, DataModification::eAdded);
});
// pay attention to addtitional aesItemView: AtExplosionSingleCentral
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::aesItemViewChanged,
this, &ExplosionSingleCentral2SituationMap::itemViewChangedESC, Qt::UniqueConnection);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return BaseClass::run();
}
void ExplosionSingleCentral2SituationMap::itemViewChangedESC(const AreaEffectSimulation::AesItemView &data, DataModification mod)
{
// TRACE_LOG(m_logger) << LOGFUNCTION << " itemViewChanged for aes item with id " << data.aesItemId();
if (mod != DataModification::eAdded && mod != DataModification::eModified)
return;
if (data.aesTypeId() != AreaEffectSimulation::AesType::AtExplosionSingleCentral)
return;
const int32_t simId = data.aesItemId(); // simId of area ('parent')
if (simId < 0)
return;
const auto uniqueMapId = this->simId2UniqueMapId(simId);
if (!isUniqueMapIdValid(uniqueMapId))
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " skip due to invalid map id";
return;
}
RefPointer<MAP_TYPE> mapObj = this->getMapObjectOfUniqueMapId(uniqueMapId);
if (!mapObj.valid())
{
WARNING_LOG(m_logger) << "Can not find map object for aes item with simId " << simId;
return;
}
AreaEffectSimulation::AesItemView itemView;
if (m_aesDtc->aesItemViewFromEntityId(simId, AreaEffectSimulation::AesType::AtExplosionSingleCentral, itemView))
{
updateDetonation(itemView, mapObj);
if (!mapObj->updateView())
ERROR_LOG(m_logger) << LOGFUNCTION << " aesItemId = " << data.aesItemId() << " updateView failed";
}
}
bool ExplosionSingleCentral2SituationMap::updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
// show just the ObjectAppearance::Technical
mapObj->setVisibility(ObjectAppearance::Tactical, false);
const int32_t simId = ddsData.id();
mapObj->setIdentifier(QString::fromStdString(ddsData.name()));
// Todo: Check What to insert if unset?
int partyId = -1;
if (ddsData.participantId().is_set())
{
const int pId = ddsData.participantId().get();
const ParticipantManagement::Participant &participant = m_ppmDtc->participant(pId);
if (participant.id() == pId)
partyId = participant.partyId();
}
else
{
if (ddsData.partyId().is_set())
partyId = ddsData.partyId().get();
}
if (partyId < 0 )
partyId = 0;
mapObj->setPartyId(partyId);
const bool changeToActive = (ddsData.effectStateId().underlying()==AreaEffectSimulation::AesEffectState_def::EsActivated) &&
(static_cast<int>(mapObj->aesState()) < static_cast<int>(AreaEffectSimulation::AesEffectState_def::EsActivated));
mapObj->setAesState(effectState2aesState(ddsData.effectStateId().underlying()));
AreaEffectSimulation::AesItemView itemView;
if (m_aesDtc->aesItemViewFromEntityId(simId, AreaEffectSimulation::AesType::AtExplosionSingleCentralTrajectory, itemView))
this->updateGeometry(itemView, mapObj);
else
{
ERROR_LOG(m_logger) << LOGFUNCTION
<< " no AesItemView (AtExplosionSingle) found"
<< ", simId = " << simId
<< ", provide fallBackGeometry";
// provide fallbackGeometry to avoid errorMsg like 'incorrect number of positions'
mapObj->setPositions({{0.0, 0.0, .0},
{0.0, 0.1, .0},
{0.1, 0.1, .0},
{0.1, 0.0, .0}});
// do not return here, perform stuff like updateVisibility and so on
}
// Impact required???
const Core::GeoPosition2D &impactPos2D = ddsData.impactPosition();
mapObj->setImpactOrigin(Point3D(impactPos2D.lon(), impactPos2D.lat(), 0.0));
// // SMArt?
// if (m_pdmHandler && m_pdmHandler->isSmart(ddsData.chargeTypeId()))
// mapObj->setImpactType(SingleFire::ImpactType::doubleImpact);
// else
// mapObj->setImpactType(SingleFire::ImpactType::normalImpact);
if (m_aesDtc->aesItemViewFromEntityId(simId, AreaEffectSimulation::AesType::AtExplosionSingleCentral, itemView))
updateDetonation(itemView, mapObj);
if (changeToActive)
mapObj->startDetonationAnimation();
updateVisibility(ddsData, mapObj);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
bool ExplosionSingleCentral2SituationMap::updateDetonation(const AreaEffectSimulation::AesItemView &itemView, RefPointer<Aes2SituationMap::MAP_TYPE> mapObj)
{
const int32_t simId = itemView.aesItemId(); // simId of area ('parent')
if (simId < 0)
return false;
if (itemView.form().size() != 2)
return false;
// Sphere
const Core::GeoPosition &form0 = itemView.form().front(); //lon/lat
const Core::GeoPosition &form1 = itemView.form().back(); //lon/lat
SingleFireCentral::DetonationData dd;
dd.m_origin = Point3D(form0.lon(), form0.lat(), form0.z());
const LtsCoordTrans::UtmCoordinate utm0 = LtsCoordTrans::UtmCoordinate::fromGeographic(form0.lon(), form0.lat());
const LtsCoordTrans::UtmCoordinate utm1 = LtsCoordTrans::UtmCoordinate::fromGeographic(form1.lon(), form1.lat());
// radius is given by the distance:
// dd.m_radius = LtsCoordTrans::distance(LtsCoordTrans::UtmCoordinate::fromGeographic(form0.lon(), form0.lat()),
// LtsCoordTrans::UtmCoordinate::fromGeographic(form1.lon(), form1.lat()));
dd.m_radius = (LtsUtils::QPoint3D(utm0.x, utm0.y, form0.z()) - LtsUtils::QPoint3D(utm1.x, utm1.y, form1.z())).length();
mapObj->setDetonation(dd);
return true;
}
}
@@ -0,0 +1,62 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "aes_to_situation_map_tmpl.h"
#include <Plugins/AreaEffectSimulation/aes_data_plugin_interface.h>
#include <MapObjects/single_fire_central.h>
#include <QObject>
namespace SituationMap
{
class PdmHandler;
class ExplosionSingleCentral2SituationMap;
template <>
struct Aes2SituationMapTraits<ExplosionSingleCentral2SituationMap>
{
using DDS_TYPE = AreaEffectSimulation::ExplosionSingleCentral;
using MAP_TYPE = SituationMap::SingleFireCentral;
static const AreaEffectSimulation::AesType_def::type aesType = AreaEffectSimulation::AesType_def::AtExplosionSingleCentralTrajectory;
};
class ExplosionSingleCentral2SituationMap final : public Aes2SituationMap<ExplosionSingleCentral2SituationMap>
{
Q_OBJECT
public:
using BaseClass = SituationMap::Aes2SituationMap<ExplosionSingleCentral2SituationMap>;
using BaseClass::BaseClass;
ExplosionSingleCentral2SituationMap(PdmHandler *pdmHandler,
ObjectFactory &objFac,
const QString &layername,
const char *loggerName);
bool init(PluginProvider *pluginProvider) override;
bool run() override;
bool iterateAesData(const std::function<bool(const AreaEffectSimulation::ExplosionSingleCentral &data)> &cb) const
{
return m_aesDtc->explosionSingleCentrals(cb);
}
protected:
void itemViewChangedESC(const AreaEffectSimulation::AesItemView &data, DataModification mod);
bool updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj) override;
bool updateDetonation(const AreaEffectSimulation::AesItemView &itemView,
RefPointer<MAP_TYPE> mapObj);
PdmHandler *m_pdmHandler = nullptr;
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc;
};
} // namespace
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,306 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
// Own
#include "unified_map_object_data.h"
#include "plugin_provider.h"
#include "map_object_type.h"
#include "resource_manager_mode.h"
#include <Map/situation_map_types.h>
#include <Common/situation_map_logging.h>
#include <Common/ref_pointer.h>
// Plugins
#include <Plugins/ProjectDataManagement/pdm_data_plugin_interface.h>
// Qt
#include <QObject>
#include <QPointer>
namespace SituationMap
{
// forward:
class AbstractMapObject;
class AirSupportImpact2SituationMap;
//class AlarmToMap;
class Building2SituationMap;
class BuildingHitlineInfo2SituationMap;
class BuildingOutline;
class GeoImage;
class BuildingContamination;
class BuildingOwnership;
class GuezIed2SituationMap;
class GuezNasat9Liner2SituationMap;
class HitlineInfo2SituationMap;
class Map;
class TrainingAreaToSituationMap;
class SpecialAreaToSituationMap;
class MountingPointToMap;
class SoundAreaToMap;
class MSEPointToMap;
class MSEBridgeToMap;
class MovementTrackManager;
class Participant;
class Participant2SituationMap;
class PdmHandler;
class Sim2SituationMapBase;
class ShootbackAreaToSituationMap;
class Polygon;
class EmergencyCallToMap;
class ChargeEffectToMap;
class SingleFire;
//------------------------------------------------------------------------------
class AdapterDds : public QObject
{
Q_OBJECT
public:
/*! \name Construction, Destruction */
//@{
explicit AdapterDds(QObject *parent = nullptr);
virtual ~AdapterDds();
//@}
/*! \name Initialization */
//@{
bool init(Map *map, PluginProvider *pluginProvider, QPointer<SituationMap::MovementTrackManager> &movementTrackMgr, bool resourceMode);
bool initRenderer3D_AesExtrusion();
bool initRenderer3D_AesCentral_Booby(const QString &layernameAesCentral, const QVector<int> &aesTypesForReRunIfPartyColorChanges);
// For boobyTraps
bool assignUniqueValueRendererAesCentral(const QString &layername);
// For Areas (AreaEffect)
bool assignUniqueValueRendererAesCentral3DExtrusion(const QString &layername);
bool run();
bool isRunning() const;
bool stop();
void clearObjects();
//@}
/*! \name ResourceManagerMode (PlanView|ComponentMonitor) ... */
//@{
ResourceManagerMode resourceManagerMode() const;
bool setResourceManagerMode(ResourceManagerMode rmm);
//@}
/*! \name EmergencyCalls ... */
//@{
bool showExpiredEmergencyCalls(bool bShowExpired);
//@}
/*! \name uniqueMapId... */
//@{
bool uniqueMapId2SimId(UniqueMapId uniqueMapIdIn, int32_t &simIdOut);
// unifiedMapObjectData
bool unifiedMapObjectData(UniqueMapId uniqueMapIdIn, UnifiedMapObjectData &umodOut) const;
//@}
/*! \name simId... */
//@{
// Participant:
UniqueMapId simId2UniqueMapIdParticipant(int32_t simId) const;
RefPointer<Participant> simId2Participant(int32_t simId);
QPointer<MovementTrackManager> movementTrackManager() const { return m_movementTrackManager; }
// Aes
UniqueMapId simId2UniqueMapIdAes(int32_t simId) const;
RefPointer<AbstractMapObject> simId2Aes(int32_t simId);
// Building
UniqueMapId simId2UniqueMapIdBuilding(int32_t simId) const;
RefPointer<BuildingOutline> simId2Building(int32_t simId);
// Bridge
UniqueMapId simId2UniqueMapIdBridge(int32_t simId) const;
RefPointer<BuildingOutline> simId2Bridge(int32_t simId);
// MountingPoint
UniqueMapId simId2UniqueMapIdMountingPoint(int32_t simId) const;
RefPointer<GeoImage> simId2MountingPoint(int32_t simId);
// GuezIEDs
UniqueMapId simId2UniqueMapIdGuezIed(int32_t simId) const;
RefPointer<Participant> simId2GuezIed(int32_t simId);
// Charge Effect
UniqueMapId simId2UniqueMapIdChargeEffect(int32_t simId) const;
RefPointer<SingleFire> simId2ChargeEffect(int32_t simId);
// TrainingAreas
UniqueMapId simId2UniqueMapIdTrainingArea(int32_t simId) const;
RefPointer<SituationMap::Polygon> simId2TrainingArea(int32_t simId);
// SpecialAreas
UniqueMapId simId2UniqueMapIdSpecialArea(int32_t simId) const;
RefPointer<SituationMap::Polygon> simId2SpecialArea(int32_t simId);
// ShootbackAreas
UniqueMapId simId2UniqueMapIdShootbackArea(int32_t simId) const;
RefPointer<SituationMap::Polygon> simId2ShootbackArea(int32_t simId);
// more general approach:
UniqueMapId simId2UniqueMapId(MapObjectType mot, int32_t simId) const;
QVector<UniqueMapId> simIds2UniqueMapIds(MapObjectType mot, QVector<int32_t> simIds) const;
RefPointer<AbstractMapObject> simId2MapObject(MapObjectType mot, int32_t simId);
//@}
/*! \name Object Selection */
//@{
Sim2SituationMapBase *situationMapBase(MapObjectType mot) const;
bool setMapObjectSelected(MapObjectType mot, const QVector<int> &entityIds, bool selection = true);
bool clearMapObjectSelection(MapObjectType mot = MapObjectType::MOT_Undefined);
//@}
/*! \name BuildingOwnership */
//@{
bool isBuildingOwnershipSupported() const;
bool isBuildingOwnershipVisible() const;
bool setBuildingOwnershipVisible(bool visible);
//@}
/*! \name BuildingContamination */
//@{
bool isBuildingContaminationSupported() const;
bool isBuildingContaminationVisible() const;
bool setBuildingContaminationVisible(bool visible);
//@}
/*! \name Participants */
//@{
bool enableFireEventFlashing(bool enable);
bool isFireEventFlashingEnabled() const;
//@}
/*! \name Nmea own Position!*/
bool setOwnPositionVisible(bool enable);
bool isOwnPositionVisible() const;
Q_SIGNALS:
void mapObjectChanged(UniqueMapId uniqueMapId); // to refresh MapObjectSelectionWidget for example
void mapObjectRemoved(UniqueMapId uniqueMapId); // to refresh MapObjectSelectionWidget for example
void participantPositionChanged(const int32_t participantId, const Point3D &newPos); // to update OC situation range for example
void resourceManagerModeChanged(ResourceManagerMode newMode);
public Q_SLOTS:
void restart() { stop(); run(); }
void restartIfRunning()
{
if (!this->isRunning())
return;
restart();
}
/*! \name SymbolDictionary */
//@{
void onSymbolDictionaryChanged();
//@}
/*! \name Click events */
//@{
bool onMapObjectClicked(const RefPointer<AbstractMapObject> &mapObject);
bool onMapObjectClicked(UniqueMapId uniqueMapId);
bool onMapObjectsClicked(const QVector<UniqueMapId> &uniqueMapIds);
//@}
/*! \name Changed events for ordering */
//@{
void onMapObjectChangedUpdateDrawOrder(UniqueMapId uniqueMapId);
void onMapObjectRemoved(UniqueMapId uniqueMapId);
//@}
private slots:
void onParticipantOwnPositionChanged(const Point3D &newPos, int64_t sampleTime);
private:
void startChangedDelayTimer();
void startOwnPositionOutdatedTimer();
QList<Sim2SituationMapBase *> listOfSim2Map() const;
QList<Sim2SituationMapBase *> listOfAes2Map() const;
private:
bool m_isShowOwnPosition{true};
bool m_isRunning{false};
QTimer *m_changedDelayTimer{nullptr};
QTimer *m_ownPositionOutdatedTimer{nullptr};
QPointer<Map> m_map;
PdmHandler *m_pdmHandler{nullptr};
PluginProvider *m_pluginProvider{nullptr};
// Participants:
QSharedPointer<Participant2SituationMap> m_particpants;
QMap<int32_t, long> m_participantId2uniqueMapId;
QPointer<SituationMap::MovementTrackManager> m_movementTrackManager;
QSharedPointer<HitlineInfo2SituationMap> m_hitlineInfo2SituationMap;
QSharedPointer<BuildingHitlineInfo2SituationMap> m_bldHitlineInfo2SituationMap;
// AES:
QMap<int, Sim2SituationMapBase *> m_aes2MapCont;
QMap<UniqueMapId, qint64> m_startTimeMap; // contains the effectStartTime of (aes) objects to order them by time
QSharedPointer<ChargeEffectToMap> m_chargeEffects;
// ALM:
QSharedPointer<EmergencyCallToMap> m_emergencyCalls;
// Asm
QSharedPointer<TrainingAreaToSituationMap> m_trainingAreas;
// CES: CentralEffectSimulation
QSharedPointer<BuildingOwnership> m_buildingOwnership;
QSharedPointer<BuildingContamination> m_buildingContamination;
// ISM:
QSharedPointer<MountingPointToMap> m_mountingPoints;
QSharedPointer<SoundAreaToMap> m_soundAreas;
QSharedPointer<Building2SituationMap> m_buildings;
QSharedPointer<MSEPointToMap> m_msePoints; // mses == MainStructureElement
QSharedPointer<MSEBridgeToMap> m_mseBridges; // mses == MainStructureElement
QSharedPointer<SpecialAreaToSituationMap> m_specialAreas;
// GIM
QSharedPointer<GuezIed2SituationMap> m_guezIeds;
// GNA
QSharedPointer<GuezNasat9Liner2SituationMap> m_guezNasat9Liner;
// TGT
QSharedPointer<ShootbackAreaToSituationMap> m_shootbackAreas;
LOGGER_T m_logger;
};
//------------------------------------------------------------------------------
} // namespace
@@ -0,0 +1,553 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
// #define USE_OBJECTAPPEARANCE_VECTOR // maybe ractivate later... (save code until then)
// Qwn
#include "sim_to_situation_map_tmpl.h"
#include <Plugins/FilterManagement/flt_data_plugin_interface.h>
#include <Plugins/FilterManagement/flt_aes_plugin_interface.h>
#include <PluginInterfaces/gui_plugin_interface.h>
#include <AreaEffectSimulation/aes_data_plugin_interface.h>
#include <AreaEffectSimulation/aes_info_gui_plugin_interface.h>
#include <FilterManagement/flt_data_plugin_aes_display_filter.h>
#include <Map/abstract_effect_simulation.h>
namespace SituationMap
{
//------------------------------------------------------------------------------
inline PositionCont form2PosCont(const std::vector<Core::GeoPosition2D> &form)
{
PositionCont ret;
ret.reserve(form.size());
for (const auto &pos : form)
ret.push_back({pos.lon(), pos.lat(), 0.0});
return ret;
}
inline PositionCont form2PosCont(const std::vector<Core::GeoPosition> &form)
{
PositionCont ret;
ret.reserve(form.size());
for (const auto &pos : form)
ret.push_back({pos.lon(), pos.lat(), pos.z()});
return ret;
}
inline PositionCont form2PosCont(const QPolygonF &form)
{
PositionCont ret;
ret.reserve(form.size());
for (const auto &pos : form)
ret.push_back({pos.x(), pos.y(), 0.0});
return ret;
}
//------------------------------------------------------------------------------
inline SituationMap::AesEffectState effectState2aesState(AreaEffectSimulation::AesEffectState effectState)
{
SituationMap::AesEffectState aesState = AesEffectState::Unknown;
switch (effectState.underlying()) // underlying() -> inner_enum
{
case AreaEffectSimulation::AesEffectState_def::EsUnknown:
case AreaEffectSimulation::AesEffectState_def::EsError:
case AreaEffectSimulation::AesEffectState_def::EsExpired:
case AreaEffectSimulation::AesEffectState_def::EsRemoved:
case AreaEffectSimulation::AesEffectState_def::EsPaused:
case AreaEffectSimulation::AesEffectState_def::EsReceived:
case AreaEffectSimulation::AesEffectState_def::EsCreated:
aesState = AesEffectState::Created;
break;
case AreaEffectSimulation::AesEffectState_def::EsFired:
case AreaEffectSimulation::AesEffectState_def::EsPrepared:
aesState = AesEffectState::Prepared;
break;
case AreaEffectSimulation::AesEffectState_def::EsActivated:
aesState = AesEffectState::Activated;
break;
}
return aesState;
}
template <typename SUPER>
struct Aes2SituationMapTraits;
template <typename SUPER>
class Aes2SituationMap : public Sim2SituationMap<typename Aes2SituationMapTraits<SUPER>::DDS_TYPE, typename Aes2SituationMapTraits<SUPER>::MAP_TYPE>
, protected FilterManagement::AesDisplayFilter::FilterChangedCallback
, protected DdsFilterHandling<typename Aes2SituationMapTraits<SUPER>::MAP_TYPE>
{
public:
using DDS_TYPE = typename Aes2SituationMapTraits<SUPER>::DDS_TYPE;
using MAP_TYPE = typename Aes2SituationMapTraits<SUPER>::MAP_TYPE;
using BaseClass = Sim2SituationMap<DDS_TYPE, MAP_TYPE>;
using FilterClass = DdsFilterHandling<MAP_TYPE>;
Aes2SituationMap(ObjectFactory &objFac,
const QString &layername,
const char *loggerName)
: BaseClass(objFac, layername, 0, loggerName)
, FilterClass(loggerName, this)
{}
Aes2SituationMap(ObjectFactory &objFac,
const QString &layername,
int drawOrder,
const char *loggerName)
: BaseClass(objFac, layername, drawOrder, loggerName)
, FilterClass(loggerName, this)
{}
~Aes2SituationMap()
{
if (m_displayFilter)
m_displayFilter->removeChangedCallback(this);
}
void setIsVisibleByExternalCallback(const std::function<bool(int32_t, bool&)> &isVisibleByExternalCallback)
{
m_isVisibleByExternalCallback = isVisibleByExternalCallback;
}
int32_t getSimId(const DDS_TYPE &ddsData) const override
{
return ddsData.id();
}
virtual bool init(PluginProvider *pluginProvider)
{
if (!pluginProvider ||
!pluginProvider->aesDtc())
return false;
m_pluginProvider = pluginProvider;
m_aesDtc = m_pluginProvider->aesDtc();
m_aesInfoIfc = m_pluginProvider->aesInfoIfc();
// FilterManagement
FilterClass::init(pluginProvider);
auto fltAesIfc = m_pluginProvider->fltAesIfc();
if (fltAesIfc)
{
m_displayFilter = fltAesIfc->aesFilterForOperator(m_pluginProvider->operatorId(),
m_pluginProvider->workspaceId());
if (m_displayFilter)
m_displayFilter->addChangedCallback(this);
}
m_pluginProvider->disconnect(this);
QObject::connect(m_pluginProvider, &PluginProvider::partitionTimeChanged,
this, &Aes2SituationMap::partitionTimeChanged);
QObject::connect(m_pluginProvider, &PluginProvider::workspaceIdChanged,
this, &Aes2SituationMap::onWorkspaceIdChanged);
#ifdef USE_OBJECTAPPEARANCE_VECTOR
// only show technical symbols by default
m_objectAppearanceVisibility += ObjectAppearance::Technical;
#endif // USE_OBJECTAPPEARANCE_VECTOR
return true;
}
bool run() override
{
QObject::connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::aesItemViewChanged,
this, &Aes2SituationMap::itemViewChanged, Qt::UniqueConnection);
return true;
}
void stop() override
{
QObject::disconnect(m_pluginProvider, &PluginProvider::partitionTimeChanged,
this, &Aes2SituationMap::partitionTimeChanged);
m_aesDtc->disconnect(this);
}
bool mapObjectsClicked(const QVector<UniqueMapId> &uniqueMapIds) override
{
auto sp = m_aesInfoIfc.lock();
if (!sp)
return false;
const QVector<int32_t> &simIds = this->uniqueMapIds2SimIds(uniqueMapIds);
if (simIds.isEmpty())
return true;
sp->showInfoWindow(simIds, Aes2SituationMapTraits<SUPER>::aesType);
return true;
}
// for startTime (of AesItems):
qint64 startTime(UniqueMapId uniqueMapId) const override
{
if (!m_aesDtc)
return -1;
int32_t simIdOut = -1;
if (!this->uniqueMapId2SimId(uniqueMapId, simIdOut))
return -1;
return effectStartTimeFromSimId(simIdOut);
}
bool unifiedMapObjectData(UniqueMapId uniqueMapId, UnifiedMapObjectData &umodOut) const override
{
if (!m_aesDtc)
return false;
int32_t simIdOut = -1;
if (!this->uniqueMapId2SimId(uniqueMapId, simIdOut))
return false;
umodOut = UnifiedMapObjectData();
umodOut.m_participantData.m_typeName = QObject::tr("Area Effect Simulation");
RefPointer<MAP_TYPE> mapObj = this->getMapObjectOfUniqueMapId(uniqueMapId);
if (mapObj.valid())
umodOut.m_image = mapObj->previewImage();
const SUPER *derived = static_cast<const SUPER*>(this);
const auto cb = [simIdOut, &umodOut](const DDS_TYPE &data) -> bool
{
if (data.id() == simIdOut)
{
if (data.partyId().is_set())
umodOut.m_partyId = data.partyId().get();
umodOut.m_description1 = QString::fromStdString(data.name());
return true; // break loop
}
return false;
};
return derived->iterateAesData(cb);
}
protected:
// DdsFilterHandling
void onWorkspaceIdChanged(const QString &newWorkspaceId) override
{
if (m_displayFilter)
m_displayFilter->removeChangedCallback(this);
m_displayFilter = nullptr;
auto fltAesIfc = m_pluginProvider->fltAesIfc();
if (!fltAesIfc)
return;
const auto opId = m_pluginProvider->operatorId();
const auto wsId = m_pluginProvider->workspaceId();
FilterClass::onWorkspaceIdChanged(newWorkspaceId);
m_displayFilter = fltAesIfc->aesFilterForOperator(opId, wsId);
if (m_displayFilter)
m_displayFilter->addChangedCallback(this);
}
qint64 effectStartTimeFromSimId(int simId) const
{
qint64 effectStart = -1;
const SUPER *derived = static_cast<const SUPER*>(this);
const auto cb = [simId, &effectStart](const DDS_TYPE &data) -> bool
{
if (data.id() == simId)
{
if (data.effectStart().is_set())
effectStart = data.effectStart().get();
return true;
}
return false;
};
derived->iterateAesData(cb);
return effectStart;
}
void visibilityFilterChanged(AreaEffectSimulation::AesType aesType)
{
if (Aes2SituationMapTraits<SUPER>::aesType != aesType)
return;
SUPER *derived = static_cast<SUPER*>(this);
const auto cb = [derived](const DDS_TYPE &data) -> bool
{
derived->updateVisibility(data);
return false;
};
derived->iterateAesData(cb);
}
bool isElapsed(const DDS_TYPE &ddsData) const override
{
const AreaEffectSimulation::AesEffectState &aesEffectState = ddsData.effectStateId();
if (ddsData.isDeleted())
return true;
if (aesEffectState == AreaEffectSimulation::AesEffectState_def::EsRemoved)
return true;
if (aesEffectState == AreaEffectSimulation::AesEffectState_def::EsExpired)
{
if (!ddsData.effectStart().is_set())
return true;
const auto effectEnd = ddsData.effectStart().get() + ddsData.effectDuration();
const auto afterGlow = m_displayFilter ? m_displayFilter->maxAfterglowDurationMSec() : 0;
return (m_pluginProvider->partitionTime() > effectEnd + afterGlow);
}
return false;
}
void partitionTimeChanged()
{
const int partitionTimeSec = m_pluginProvider->partitionTime() / 1000;
bool bCleanup = (partitionTimeSec % 10) == 0; // modulo
SUPER *derived = static_cast<SUPER*>(this);
const auto cb = [this, bCleanup](const DDS_TYPE &data) -> bool
{
// !!! return false -> do not stop looping over items !!!
if (data.isDeleted())
return false;
if (data.effectStateId() != AreaEffectSimulation::AesEffectState_def::EsExpired)
return false;
// consider isElapsed() here. Remove object to speed up the loop etc:
if (bCleanup)
{
if (!m_simId2UniqueMapId.contains(getSimId(data)))
return false;
if (isElapsed(data))
this->removeElement(data);
return false;
}
this->updateVisibility(data);
return false;
};
derived->iterateAesData(cb);
}
void itemViewChanged(const AreaEffectSimulation::AesItemView &data, DataModification mod)
{
// TRACE_LOG(m_logger) << LOGFUNCTION << " itemViewChanged for aes item with id " << data.aesItemId();
if (mod != DataModification::eAdded && mod != DataModification::eModified)
return;
if (data.aesTypeId() != Aes2SituationMapTraits<SUPER>::aesType)
return;
const auto uniqueMapId = this->simId2UniqueMapId(data.aesItemId());
if (!isUniqueMapIdValid(uniqueMapId))
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " skip due to invalid map id";
return;
}
RefPointer<MAP_TYPE> mapObj = this->getMapObjectOfUniqueMapId(uniqueMapId);
if (!mapObj.valid())
{
WARNING_LOG(m_logger) << "Can not find map object for aes item with id " << data.aesItemId();
return;
}
updateGeometry(data, mapObj);
}
public:
void updateVisibility()
{
onAesDisplayFilterChanged(Aes2SituationMapTraits<SUPER>::aesType);
}
protected:
void updateVisibility(const DDS_TYPE &data)
{
const auto uniqueMapId = this->simId2UniqueMapId(getSimId(data));
if (!isUniqueMapIdValid(uniqueMapId))
{
// DEBUG_LOG(m_logger) << LOGFUNCTION << " skip due to invalid map id/simId: " << data.id();
return;
}
if (isElapsed(data))
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " skip due to isElapsed map id/simId: " << data.id();
return;
}
RefPointer<MAP_TYPE> mapObj = this->getMapObjectOfUniqueMapId(uniqueMapId);
if (!mapObj.valid())
{
WARNING_LOG(m_logger) << "Can not find map object for aes item with id " << getSimId(data);
return;
}
updateVisibility(data, mapObj);
}
virtual bool updateVisibility(const DDS_TYPE &data, RefPointer<MAP_TYPE> mapObj)
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " simId = " << this->getSimId(data);
if (!mapObj)
return false;
bool isReferenced = false;
bool isVisibleByExternal = true;
if (m_isVisibleByExternalCallback)
{
isVisibleByExternal = false;
isReferenced = m_isVisibleByExternalCallback(this->getSimId(data), isVisibleByExternal);
DEBUG_LOG(m_logger) << " simId = " << this->getSimId(data)
<< " isReferenced = " << isReferenced
<< " isVisibleByExternal = " << isVisibleByExternal;
if (!isReferenced)
isVisibleByExternal = true;
}
bool bIsVisibleByFilter = true;
if (!isReferenced && m_displayFilter)
{
bIsVisibleByFilter = isVisibleByFilter(data);
}
#ifdef USE_OBJECTAPPEARANCE_VECTOR
// assign visi to relevant appearance
Q_FOREACH(const auto appearance, m_objectAppearanceVisibility)
{
const bool bOldVisibility = mapObj->visibility(appearance);
if (bOldVisibility != isVisibile)
{
mapObj->setVisibility(appearance, isVisibile);
changed = true;
mapObj->updateView();
DEBUG_LOG(m_logger) << "Set visibility for object " << data.id() << " to " << (isVisibile ? "visible" : "invisible");
}
}
#else
// setVisibility (complete object)
{
bool isVisibile = isVisibleByExternal && bIsVisibleByFilter;
const bool bOldVisibility = mapObj->visibility();
if (bOldVisibility != isVisibile)
{
mapObj->setVisibility(isVisibile);
mapObj->updateView();
DEBUG_LOG(m_logger) << "Set visibility for object " << data.id() << " to " << (isVisibile ? "visible" : "invisible");
this->emit_visibilityHasChangedSignal();
}
}
#endif // USE_OBJECTAPPEARANCE_VECTOR
return true;
}
virtual bool isVisibleByFilter(const DDS_TYPE &data) const
{
if (!m_displayFilter)
return true; // no filter -> visible
const auto es = data.effectStart().is_set() ? data.effectStart().get() : 0;
const auto partyId = data.partyId().is_set() ? data.partyId().get() : -1;
bool isVisibleByFilter = partyId > 0 ? FilterClass::m_currentSymbolSettings.symbolSettings.symbolPartyAppearance.value(partyId).isVisible : true;
if (isVisibleByFilter)
isVisibleByFilter = m_displayFilter->isVisible(Aes2SituationMapTraits<SUPER>::aesType,
data.effectStateId(),
data.chargeStruct().chargeTypeId(),
partyId,
data.isCentral(),
es,
data.effectDuration(),
m_pluginProvider->partitionTime());
return isVisibleByFilter;
}
protected:
virtual void onAesDisplayFilterChanged(AreaEffectSimulation::AesType aesType) override
{
if (Aes2SituationMapTraits<SUPER>::aesType != aesType.underlying())
return;
SUPER *derived = static_cast<SUPER*>(this);
const auto cb = [this](const DDS_TYPE &data) -> bool
{
// return false -> do not stop looping over items
if (data.isDeleted())
return false;
this->updateVisibility(data);
return false;
};
derived->iterateAesData(cb);
}
// default AES impl only checks symbol scale
bool symbolAppearanceSettingsChangesAreRelevant(const FilterManagement::SymbolAppearanceSettings::Settings &newSas) const override
{
if (FilterClass::m_currentSymbolSettings.symbolSettings.symbolPartyAppearance !=
newSas.symbolSettings.symbolPartyAppearance)
return true;
return (FilterClass::m_currentSymbolSettings.symbolSettings.symbolScale != newSas.symbolSettings.symbolScale);
}
void handleSymbolAppearanceSettings(RefPointer<MAP_TYPE> &mapObj) override
{
// [GUEZE-3258, GUEZE-3442] Performance, Filterupdate langsam
// // onAesDisplayFilterChanged(Aes2SituationMapTraits<SUPER>::aesType); // ExplosionCluster: onAesDisplayFilterChanged iteriert über alle!
mapObj->setScale(FilterClass::m_currentSymbolSettings.symbolSettings.symbolScale);
}
// [GUEZE-3258, GUEZE-3442] Performance, Filterupdate langsam
void symbolAppearanceSettingsChangedPostOperation() override
{
TRACE_LOG(m_logger) << LOGFUNCTION << " symbolAppearanceSettingsChangedPostOperation START";
// Note:
// 'updateVisibility()' == 'onAesDisplayFilterChanged(Aes2SituationMapTraits<SUPER>::aesType);'
updateVisibility();
}
public:
virtual bool updateGeometry(const AreaEffectSimulation::AesItemView &data,
RefPointer<MAP_TYPE> mapObj)
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " START" << " data.aesTypeId()=" << data.aesTypeId()
<< ", m_debugInfo " << mapObj->debugInfo();
mapObj->setPositions(form2PosCont(data.form()));
if (!mapObj->updateView())
ERROR_LOG(m_logger) << LOGFUNCTION << " aesItemId = " << data.aesItemId() << " updateView failed";
return true;
}
protected:
using BaseClass::m_simId2UniqueMapId;
using BaseClass::m_logger;
std::shared_ptr<AreaEffectSimulation::Interface::Dtc> m_aesDtc;
std::weak_ptr<AreaEffectSimulation::ForeignInfoGuiInterface> m_aesInfoIfc;
PluginProvider *m_pluginProvider = nullptr;
std::shared_ptr<FilterManagement::AesDisplayFilter> m_displayFilter;
std::function<bool(int32_t, bool&)> m_isVisibleByExternalCallback = nullptr;
#ifdef USE_OBJECTAPPEARANCE_VECTOR
QVector<ObjectAppearance> m_objectAppearanceVisibility;
#endif // USE_OBJECTAPPEARANCE_VECTOR
};
//------------------------------------------------------------------------------
} // namespace
@@ -0,0 +1,89 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#include "air_support_impact_to_map.h"
#include "pdm_handler.h"
#include <Map/bounding_box.h>
namespace SituationMap
{
AirSupportImpact2SituationMap::AirSupportImpact2SituationMap(PdmHandler *pdmHandler, ObjectFactory &objFac, const QString &layername, const char *loggerName)
: BaseClass(objFac, layername, loggerName)
, m_pdmHandler(pdmHandler)
{
}
bool AirSupportImpact2SituationMap::run()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (! m_aesDtc)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no dtc";
return false;
}
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::airSupportImpactChanged,
this, &AirSupportImpact2SituationMap::handleChanged, Qt::UniqueConnection);
// get:
m_aesDtc->airSupportImpacts([this](const AreaEffectSimulation::AirSupportImpact & data)
{
handleChanged(data, DataModification::eAdded);
});
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return BaseClass::run();
}
bool AirSupportImpact2SituationMap::updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
// show just the ObjectAppearance::Technical
mapObj->setVisibility(ObjectAppearance::Tactical, false);
const int32_t simId = ddsData.id();
mapObj->setIdentifier(QString::fromStdString(ddsData.name()));
// Todo: Check What to insert if unset?
if (ddsData.partyId().is_set())
mapObj->setPartyId(ddsData.partyId().get());
mapObj->setAesState(effectState2aesState(ddsData.effectStateId().underlying()));
AreaEffectSimulation::AesItemView itemView;
if (m_aesDtc->aesItemViewFromEntityId(simId, AreaEffectSimulation::AesType::AtAirSupportImpact, itemView))
this->updateGeometry(itemView, mapObj);
else
{
DEBUG_LOG(m_logger) << LOGFUNCTION
<< " no AesItemView (AtAirSupportImpact) found"
<< ", simId = " << simId
<< ", provide fallBackGeometry";
// provide fallbackGeometry to avoid errorMsg like 'incorrect number of positions'
mapObj->setPositions({{0.0, 0.0, .0},
{0.0, 0.1, .0},
{0.1, 0.1, .0},
{0.1, 0.0, .0}});
// do not return here, perform stuff like updateVisibility and so on
}
// Impact:
const Core::GeoPosition2D &impactPos2D = ddsData.impactPosition();
mapObj->setImpactOrigin(Point3D(impactPos2D.lon(), impactPos2D.lat(), 0.0));
updateVisibility(ddsData, mapObj);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
}
@@ -0,0 +1,56 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "aes_to_situation_map_tmpl.h"
#include <Plugins/AreaEffectSimulation/aes_data_plugin_interface.h>
#include <MapObjects/single_fire.h>
#include <QObject>
namespace SituationMap
{
class PdmHandler;
class AirSupportImpact2SituationMap;
template <>
struct Aes2SituationMapTraits<AirSupportImpact2SituationMap>
{
using DDS_TYPE = AreaEffectSimulation::AirSupportImpact;
using MAP_TYPE = SituationMap::SingleFire;
static const AreaEffectSimulation::AesType::type aesType = AreaEffectSimulation::AesType::AtAirSupportImpact;
};
class AirSupportImpact2SituationMap final : public Aes2SituationMap<AirSupportImpact2SituationMap>
{
Q_OBJECT
public:
using BaseClass = SituationMap::Aes2SituationMap<AirSupportImpact2SituationMap>;
using BaseClass::BaseClass;
AirSupportImpact2SituationMap(PdmHandler *pdmHandler,
ObjectFactory &objFac,
const QString &layername,
const char *loggerName);
bool run() override;
bool iterateAesData(const std::function<bool(const AreaEffectSimulation::AirSupportImpact &data)> &cb) const
{
return m_aesDtc->airSupportImpacts(cb);
}
protected:
bool updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj) override;
PdmHandler *m_pdmHandler = nullptr;
};
} // namespace
@@ -0,0 +1,185 @@
/**
* @RDE_HEADER@
* The AlarmToMap class handles the transfer from MainStructureElement-DDS-Data to a representation on the map
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, NLSE, 2018-06-26
*/
// Own
#include "alarm_to_map.h"
#include <Map/object_factory.h>
#include <PluginInterfaces/gui_plugin_interface.h>
// Qt
#include <QPainter>
#include <sstream>
using namespace SituationMap;
QImage renderEmergencyCallSymbol()
{
int size = 200;
QImage image(size, size, QImage::Format_ARGB32);
image.fill(Qt::transparent);
QPainter painter(&image);
painter.setRenderHint(QPainter::Antialiasing);
QPen pen(Qt::white);
pen.setWidth(10);
painter.setPen(pen);
painter.setBrush(QBrush(Qt::red));
painter.drawEllipse(QPointF(image.rect().center()),
image.rect().width() * 0.45,
image.rect().height() * 0.45);
painter.setPen(QPen(Qt::white));
QFont font = painter.font();
font.setBold(true);
font.setPixelSize(75);
painter.setFont(font);
QPointF pos(image.width() * 0.125,
image.height() * 0.625);
painter.drawText(pos, QLatin1String("SOS"));
return image;
}
bool AlarmToMap::init(PluginProvider *pluginProvider)
{
if (!pluginProvider)
return false;
m_pluginProvider = pluginProvider;
DEBUG_LOG(m_logger) << LOGFUNCTION << " exerciseId=" << m_pluginProvider->exerciseId();
m_almDtc = m_pluginProvider->almDtc();
// FilterManagement:
FilterClass::init(m_pluginProvider);
return true;
}
bool AlarmToMap::run()
{
DEBUG_LOG(m_logger) << "Starting to run";
this->stop();
if (m_almDtc)
{
connect(m_almDtc.get(), &AlarmManagement::Interface::Dtc::notificationChanged,
this, &AlarmToMap::handleChanged, Qt::UniqueConnection);
// get:
m_almDtc->notifications([this](const AlarmManagement::Notification & data)
{
handleChanged(data, DataModification::eAdded);
});
}
return true;
}
void AlarmToMap::stop()
{
DEBUG_LOG(m_logger) << LOGFUNCTION << "Stopping";
if (m_almDtc)
m_almDtc->disconnect(this);
}
/*
bool AlarmToMap::unifiedMapObjectData(UniqueMapId uniqueMapId, UnifiedMapObjectData &umodOut) const
{
if (!m_almDtc)
return false;
int32_t simIdOut = -1;
if (!this->uniqueMapId2SimId(uniqueMapId, simIdOut))
return false;
umodOut = UnifiedMapObjectData();
RefPointer<MAP_T> mapObj = this->getMapObjectOfUniqueMapId(uniqueMapId);
if (mapObj.valid())
umodOut.m_image = mapObj->previewImage();
const auto cb = [simIdOut, &umodOut](const AlarmManagement::Notification & data) -> bool
{
if (data.id() == simIdOut)
{
umodOut.m_description1 = QString::fromStdString(data.name());
umodOut.m_participantData.m_typeName = AlarmManagement::Notification::toString(data.structureElementTypeId());
return true; // break loop
}
return false;
};
// sonst kann sich der compiler nicht zwischen bool und void entscheiden... !?
std::function<bool(const AlarmManagement::Notification &data)> cb1 = cb;
return m_almDtc->notification(cb1);
}
*/
bool AlarmToMap::isElapsed(const Sim2SituationMap::DDS_T &data) const
{
// true -> hide
// false -> show
DEBUG_LOG(m_logger) << " isElapsed";
// if (data.isDeleted())
// return true;
if (data.eventType().underlying() != ProjectDataManagement::EventType_def::EmergencyCall)
return true;
return false;
}
int32_t AlarmToMap::getSimId(const Sim2SituationMap::DDS_T &ddsData) const
{
return ddsData.id();
}
bool AlarmToMap::updateElementImpl(const Sim2SituationMap::DDS_T &ddsData, RefPointer<Sim2SituationMap::MAP_T> mapObj)
{
TRACE_LOG(m_logger) << LOGFUNCTION
<< ", id " << ddsData.id();
mapObj->setPickable(false);
mapObj->setDrawOrder(-1);
// Identifier:
mapObj->setIdentifier(QStringLiteral("SOS_%1").arg(ddsData.equipmentNumber()));
TextStyle textStyle;
textStyle.setSize(20);
textStyle.setTextColor(Qt::red);
textStyle.setTextOutlineColor(Qt::white);
textStyle.setTextOutlineWidth(5);
mapObj->setTextStyle(textStyle);
// Position:
const Core::GeoPosition &geoPos = ddsData.position();
mapObj->setOrigin(Point3D(geoPos.lon(), geoPos.lat(), geoPos.z()));
// Appearance:
mapObj->setProxyImage(renderEmergencyCallSymbol(), QSize(50, 50));
emit alarmUpdated(mapObj->identifier(), Point3D(geoPos.lon(), geoPos.lat(), geoPos.z())); // equipmentNumber contains issi
return true;
}
@@ -0,0 +1,69 @@
/**
* @RDE_HEADER@
* The AlarmToMap class handles the transfer from MainStructureElement-DDS-Data to a representation on the map
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, NLSE, 2018-06-26
*/
#pragma once
#include "sim_to_situation_map_tmpl.h"
#include <Plugins/AlarmManagement/alm_data_plugin_interface.h>
#include <MapObjects/geo_image.h>
namespace SituationMap
{
// AlarmManagement::Notification: implemented for EmergencyCalls
class AlarmToMap final : public Sim2SituationMap<AlarmManagement::Notification, SituationMap::GeoImage>
, protected DdsFilterHandling<SituationMap::GeoImage>
{
Q_OBJECT
using BaseClass = SituationMap::Sim2SituationMap<AlarmManagement::Notification, SituationMap::GeoImage>;
using FilterClass = DdsFilterHandling<SituationMap::GeoImage>;
public:
AlarmToMap(ObjectFactory &objFac,
const QString &layername,
int drawOrder,
const char *loggerName)
: BaseClass(objFac, layername, drawOrder, loggerName)
, FilterClass(loggerName, this)
, m_pluginProvider(nullptr)
{}
bool init(PluginProvider *pluginProvider);
bool run() override;
void stop() override;
// bool unifiedMapObjectData(UniqueMapId uniqueMapId, UnifiedMapObjectData &umodOut) const override;
protected:
bool isElapsed(const Sim2SituationMap::DDS_T &data) const override;
int32_t getSimId(const Sim2SituationMap::DDS_T &ddsData) const override;
bool updateElementImpl(const DDS_T &ddsData, RefPointer<MAP_T> mapObj) override;
bool symbolAppearanceSettingsChangesAreRelevant(const FilterManagement::SymbolAppearanceSettings::Settings &newSas) const override
{
return (m_currentSymbolSettings.symbolSettings.symbolScale != newSas.symbolSettings.symbolScale);
}
void handleSymbolAppearanceSettings(RefPointer<MAP_T> &mapObj) override
{
mapObj->setScale(m_currentSymbolSettings.symbolSettings.symbolScale);
}
signals:
void alarmUpdated(const QString &name, const Point3D &geoPosition);
private: // attributes
PluginProvider *m_pluginProvider;
std::shared_ptr<AlarmManagement::Interface::Dtc> m_almDtc;
}; // class AlarmToMap
} // namespace SituationMap
@@ -0,0 +1,111 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#include "bccontamination_to_map.h"
#include <ProjectDataManagement/pdm_dtc.h>
namespace SituationMap
{
bool BCContamination2SituationMap::run()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (!m_aesDtc)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no dtc";
return false;
}
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::bCContaminationChanged,
this, &BCContamination2SituationMap::handleChanged, Qt::UniqueConnection);
// get:
m_aesDtc->bCContaminations([this](const AreaEffectSimulation::BCContamination &data)
{
handleChanged(data, DataModification::eAdded);
});
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return BaseClass::run();
}
bool BCContamination2SituationMap::updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
// show just the ObjectAppearance::Technical
mapObj->setVisibility(ObjectAppearance::Tactical, false);
mapObj->setIdentifier(QString::fromStdString(ddsData.name()));
// if partyId is not set (like B,C agent), use default color
if (ddsData.partyId().is_set())
mapObj->setPartyId(ddsData.partyId().get());
else
{
mapObj->setLineStyle(LineStyle(Qt::yellow, 2));
mapObj->setFillStyle(FillStyle(Qt::yellow, FillPattern::Null));
}
mapObj->setAesState(effectState2aesState(ddsData.effectStateId().underlying()));
const int32_t simId = ddsData.id();
AreaEffectSimulation::AesItemView itemView;
if (m_aesDtc->aesItemViewFromEntityId(simId, AreaEffectSimulation::AesType::AtBCContamination, itemView))
this->updateGeometry(itemView, mapObj);
else
{
DEBUG_LOG(m_logger) << LOGFUNCTION
<< " no AesItemView (AtBCContamination) found"
<< ", simId = " << simId
<< ", provide fallBackGeometry";
// provide fallbackGeometry to avoid errorMsg like 'incorrect number of positions'
mapObj->setPositions({{0.0, 0.0, .0},
{0.0, 0.1, .0},
{0.1, 0.1, .0},
{0.1, 0.0, .0}});
// do not return here, perform stuff like updateVisibility and so on
}
// 'Impact':
const Core::GeoPosition2D& impactPos2D = ddsData.impactPosition();
mapObj->setImpactOrigin(Point3D(impactPos2D.lon(), impactPos2D.lat(), 0.0));
// Extrusion:
//
// Required: RenderingMode::Dynamic ; SurfacePlacementMode::Relative
// Renderer: initRenderer3D_AesExtrusion ->
// assignUniqueValueRendererAesCentral3DExtrusion
// with ExtrusionMode::BaseHeight - means relative to ground
//
if (ddsData.partyId().is_set())
{
//int height = m_pluginProvider->pdmDtc()->height(ddsData.chargeTypeId());
// mapObj->setExtrusionColorName();
// use partyId as Fallback
//
// pdm return '0' if chargeTypeId does not exists:
int height = ddsData.upperOffset();
if (height > 0)
mapObj->setExtrusionHeight(height);
else
mapObj->setExtrusionHeight(); // default value to reset
}
updateVisibility(ddsData, mapObj);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
} // namespace SituationMap
@@ -0,0 +1,50 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "aes_to_situation_map_tmpl.h"
#include <Plugins/AreaEffectSimulation/aes_data_plugin_interface.h>
//#include <MapObjects/biological_agent.h>
#include <MapObjects/single_fire.h>
#include <QObject>
#include <memory>
namespace SituationMap
{
class BCContamination2SituationMap;
template <>
struct Aes2SituationMapTraits<BCContamination2SituationMap>
{
using DDS_TYPE = AreaEffectSimulation::BCContamination;
using MAP_TYPE = SituationMap::SingleFire;
static const AreaEffectSimulation::AesType_def::type aesType = AreaEffectSimulation::AesType_def::AtBCContamination;
};
class BCContamination2SituationMap final : public Aes2SituationMap<BCContamination2SituationMap>
{
Q_OBJECT
public:
using BaseClass = SituationMap::Aes2SituationMap<BCContamination2SituationMap>;
using BaseClass::BaseClass;
bool run() override;
bool iterateAesData(const std::function<bool(const AreaEffectSimulation::BCContamination &data)> &cb) const
{
return m_aesDtc->bCContaminations(cb);
}
protected:
bool updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj) override;
};
} // namespace
@@ -0,0 +1,367 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#include "booby_traps_to_map.h"
#include <Map/object_factory.h>
#include <Map/map.h>
namespace SituationMap
{
//------------------------------------------------------------------------------
bool BoobyTrap2SituationMap::run()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (!m_aesDtc)
return false;
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::boobyTrapChanged,
this, &BoobyTrap2SituationMap::handleChanged, Qt::UniqueConnection);
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::aesItemViewChanged,
this, &BoobyTrap2SituationMap::onAesItemViewChanged, Qt::UniqueConnection);
// get:
m_aesDtc->boobyTraps([this](const AreaEffectSimulation::BoobyTrap &data)
{
handleChanged(data, DataModification::eAdded);
});
if (m_objFac.map() && (m_objFac.map()->mode() == Mode::Mode_3D))
connect(m_pluginProvider, &PluginProvider::partitionTimeChanged,
this, &BoobyTrap2SituationMap::onPartitionTimeChanged, Qt::UniqueConnection);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return BaseClass::run();
}
void BoobyTrap2SituationMap::onAesItemViewChanged(const AreaEffectSimulation::AesItemView &data, DataModification modType)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START, " << " data.aesTypeId()=" << data.aesTypeId() << " modType=" << modType;
// there are many project/situation, where the following condition will never fullfilled.
// so check this BEFORE the id to save time :-)
if (data.aesTypeId() != AreaEffectSimulation::AesType::AtBoobyTrapSecondary)
return;
if (modType == DataModification::eRemoved)
return;
const int32_t simId = data.aesItemId(); // simId of area ('parent')
if (simId < 0)
return;
// real work:
updateSecondary(simId);
TRACE_LOG(m_logger) << LOGFUNCTION << " END" << " data.aesTypeId()=" << data.aesTypeId() << " modType=" << modType;
}
void BoobyTrap2SituationMap::onPartitionTimeChanged(qint64 newPartitionTime)
{
// TRACE_LOG(m_logger) << LOGFUNCTION << " START, newPartitionTime=" << newPartitionTime
// << ", exerciseId = " << m_pluginProvider->exerciseId()
// << ", workspaceId = " << m_pluginProvider->workspaceId()
// << ", this=" << this;
updateAllDetonationSpheres(newPartitionTime);
}
void BoobyTrap2SituationMap::updateAllDetonationSpheres(qint64 newPartitionTime)
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " START"
<< ", m_simId2UniqueMapId.size = " << m_simId2UniqueMapId.size();
// iterate using m_simId2UniqueMapId vs using m_ddsDataContainer
// m_simId2UniqueMapId contains existing (map) objects
// m_ddsDataContainer may contain outdated elements (expired).
// But expired items are relevant for listOverviews...
// so iterate using m_simId2UniqueMapId:
QMapIterator<int32_t, UniqueMapId> it(m_simId2UniqueMapId);
while (it.hasNext())
{
it.next();
const UniqueMapId uniqueMapId = it.value();
RefPointer<MAP_T> mapObj = m_objFac.get<MAP_T>(uniqueMapId);
if (!mapObj.valid())
continue;
const int simId = it.key();
const AreaEffectSimulation::BoobyTrap &boobyTrap = m_aesDtc->boobyTrap(simId);
if (boobyTrap.id() != simId)
continue;
if (updateDetonationSphere3D(mapObj, boobyTrap, newPartitionTime))
if (!mapObj->updateView())
WARNING_LOG(m_logger) << LOGFUNCTION << " simId = " << simId << " updateView failed";
} // while
DEBUG_LOG(m_logger) << LOGFUNCTION << " END";
}
bool BoobyTrap2SituationMap::updateDetonationSphere3D(RefPointer<Sim2SituationMap::MAP_T> mapObj, const AreaEffectSimulation::BoobyTrap &data, qint64 newPartitionTime)
{
const int32_t simId = data.id(); // simId of area ('parent')
if (!mapObj)
return false;
bool bUpdateRequired = false;
const bool bDesiredNewState = data.triggered() && ((newPartitionTime - data.sampleTime() < 5000)); // 5000 = 5 sec
TRACE_LOG(m_logger) << LOGFUNCTION << ", START" << " simId = " << simId
<< ", sampleTime " << data.sampleTime()
<< ", bDesiredNewState " << bDesiredNewState;
// The sphere begins being displayed at the impact time, object has EffectState::Active.
// Accordingly impactPosition can _not_ change anymore!!!
// So we do not have to update the origin of the SceneMarker
// We can simplify and recognized the changes: ADDING or REMOVING the marker
//#define RENDERER_APPROACH
#ifdef RENDERER_APPROACH
// 3DMarker has to be removed?
if (mapObj->has3DMarkerRenderer() && !bDesiredNewState)
{
DEBUG_LOG(m_logger) << LOGFUNCTION << ", START REMOVE " << " simId = " << simId;
mapObj->set3DMarkerRenderer(Point3D(), QVariantMap());
bUpdateRequired = true;
}
// 3DMarker has to be added?
else if (!mapObj->has3DMarkerRenderer() && bDesiredNewState)
{
DEBUG_LOG(m_logger) << LOGFUNCTION << ", START ADD " << " simId = " << simId;
const Core::GeoPosition2D &geoPos = data.impactPosition();
Point3D markerOrigin(geoPos.lon(), geoPos.lat(), 0); // ToDo: impactPosition -> 3D
QVariantMap attribMap;
QString attribValue;
const QColor &majorColor = mapObj->majorColor();
attribValue = QString(QStringLiteral("Impact_Color_%1")).arg(majorColor.name());
attribMap.insert(QStringLiteral("IMPACT_COLOR"), attribValue);
double radius = std::max(data.impactRadius(), 10.0); // at least 10 meter (fallback)
attribValue = QString(QStringLiteral("Impact_Radius_%1")).arg(radius);
attribMap.insert(QStringLiteral("IMPACT_RADIUS"), attribValue);
LayerFactory::UniqueValueDataAesCentral::TYPE type{LayerFactory::UniqueValueDataAesCentral::TYPE::SPHERE};
if (data.centralAngle().is_set())
type = LayerFactory::UniqueValueDataAesCentral::TYPE::CONE;
attribValue = QString(QStringLiteral("Impact_Type_%1")).arg(LayerFactory::toString(type));
attribMap.insert(QStringLiteral("IMPACT_TYPE"), attribValue);
// SceneProperties: HEADING, PITCH, ROLL
int heading = 0;
if (data.rotationAngle().is_set())
heading = static_cast<int>(data.rotationAngle().get());
attribMap.insert(QStringLiteral("HEADING"), ((heading+90)%360)); // data.rotationAngle()
attribMap.insert(QStringLiteral("PITCH"), 0);
attribMap.insert(QStringLiteral("ROLL"), 90);
// qCritical() << " ident " << mapObj->identifier() << ", " << attribMap;
mapObj->set3DMarkerRenderer(markerOrigin, attribMap);
bUpdateRequired = true;
}
#else // RENDERER_APPROACH
// SceneSymbol has to be removed?
if (mapObj->has3DMarkerSceneSymbol() && !bDesiredNewState)
{
FATAL_LOG(m_logger) << LOGFUNCTION << ", START REMOVE " << " simId = " << simId;
mapObj->set3DMarkerSceneSymbol(Point3D(), {});
bUpdateRequired = true;
}
// SceneSymbol has to be added?
else if (!mapObj->has3DMarkerSceneSymbol() && bDesiredNewState)
{
FATAL_LOG(m_logger) << LOGFUNCTION << ", START ADD " << " simId = " << simId;
const Core::GeoPosition2D &geoPos = data.impactPosition();
Point3D markerOrigin(geoPos.lon(), geoPos.lat(), 0); // ToDo: impactPosition -> 3D
VirtualMine::SceneSymbolData ssData;
const QColor &majorColor = mapObj->majorColor();
ssData.color = majorColor;
ssData.radius = std::max(data.impactRadius(), 10.0); // at least 10 meter (fallback)
// cone or sphere
ssData.cone = data.centralAngle().is_set();
int heading = 0;
if (data.rotationAngle().is_set())
heading = static_cast<int>(data.rotationAngle().get());
ssData.heading = (heading+90)%360;
ssData.pitch = 0.0;
ssData.roll = 90;
mapObj->set3DMarkerSceneSymbol(markerOrigin, ssData);
}
#endif // RENDERER_APPROACH
TRACE_LOG(m_logger) << LOGFUNCTION << ", END" << " simId = " << simId;
return bUpdateRequired;
}
bool BoobyTrap2SituationMap::updateSecondary(int32_t simId)
{
TRACE_LOG(m_logger) << LOGFUNCTION << ", START" << " simId = " << simId;
if (simId < 0)
return false;
// MapObj should exist:
RefPointer<MAP_T> mapObj = this->getMapObjectOfSimId(simId);
if (!mapObj.valid())
{
DEBUG_LOG(m_logger) << LOGFUNCTION
<< " getMapObjectOfSimId failed"
<< " simId = " << simId << " (maybe expired)";
return false;
}
//
// AesitemView: AtBoobyTrapSecondary
//
AreaEffectSimulation::AesItemView dataAesItemView;
AreaEffectSimulation::BoobyTrap trap;
if (m_aesDtc->aesItemViewFromEntityId(simId, AreaEffectSimulation::AesType::AtBoobyTrapSecondary, dataAesItemView))
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " simId = " << simId << " AesItemViewForSecondary found :-) ";
trap = m_aesDtc->boobyTrap(dataAesItemView.aesItemId());
} else {
ERROR_LOG(m_logger) << LOGFUNCTION << " simId = " << simId << " no AesItemViewForSecondary found. :-( ";
}
// simId == aesItemId
if ((dataAesItemView.aesItemId() == simId) &&
(trap.id() == simId) &&
trap.triggered())
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " simId = " << simId << " setSubsidiaryLine";
VirtualMine::OptionalData optData;
optData.closed = true;
mapObj->setSubsidiaryLine(0, // key
form2PosCont(dataAesItemView.form()), optData);
} else {
DEBUG_LOG(m_logger) << LOGFUNCTION << " simId = " << simId << " removeSubsidiaryLine";
mapObj->removeSubsidiaryLine(0);
}
if (!mapObj->updateView()) {
ERROR_LOG(m_logger) << LOGFUNCTION << " simId = " << simId << " updateView failed";
return false;
}
TRACE_LOG(m_logger) << LOGFUNCTION << ", END" << " simId = " << simId
<< " trap.triggered(" << trap.triggered();
return true;
}
bool BoobyTrap2SituationMap::updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
// show just the ObjectAppearance::Technical
mapObj->setVisibility(ObjectAppearance::Tactical, false);
mapObj->setIdentifier(QString::fromStdString(ddsData.name()));
// if partyId is not set (like B,C agent), use default color
if (ddsData.partyId().is_set())
mapObj->setPartyId(ddsData.partyId().get());
mapObj->setAesState(effectState2aesState(ddsData.effectStateId().underlying()));
const int32_t simId = ddsData.id();
AreaEffectSimulation::AesItemView itemView;
if (m_aesDtc->aesItemViewFromEntityId(simId, AreaEffectSimulation::AesType::AtBoobyTrap, itemView))
{
this->updateGeometry(itemView, mapObj);
if (m_objFac.map() && (m_objFac.map()->mode() == Mode::Mode_3D))
updateDetonationSphere3D(mapObj, ddsData, m_pluginProvider->partitionTime());
}
else
{
DEBUG_LOG(m_logger) << LOGFUNCTION
<< " no AesItemView (AtBoobyTrap) found"
<< ", simId = " << simId
<< ", provide fallBackGeometry";
// provide fallbackGeometry to avoid errorMsg like 'incorrect number of positions'
mapObj->setPositions({{0.0, 0.0, .0},
{0.0, 0.1, .0},
{0.1, 0.1, .0},
{0.1, 0.0, .0}});
// do not return here, perform stuff like updateVisibility and so on
}
// updateSecondary
updateSecondary(simId);
updateVisibility(ddsData, mapObj);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
bool BoobyTrap2SituationMap::isVisibleByFilter(const DDS_TYPE &data) const
{
if (!m_displayFilter)
return true; // no filter -> visible
const auto es = data.effectStart().is_set() ? data.effectStart().get() : 0;
const auto partyId = data.partyId().is_set() ? data.partyId().get() : -1;
bool isVisibleByFilter = partyId > 0 ? FilterClass::m_currentSymbolSettings.symbolSettings.symbolPartyAppearance.value(partyId).isVisible : true;
if (isVisibleByFilter)
isVisibleByFilter = m_displayFilter->isVisible(AreaEffectSimulation::AesType_def::AtMineArea,
data.effectStateId(),
data.chargeStruct().chargeTypeId(),
partyId,
data.isCentral(),
es,
data.effectDuration(),
m_pluginProvider->partitionTime());
return isVisibleByFilter;
}
void BoobyTrap2SituationMap::onAesDisplayFilterChanged(AreaEffectSimulation::AesType aesType)
{
if ((AreaEffectSimulation::AesType_def::AtBoobyTrap != aesType.underlying()) &&
(AreaEffectSimulation::AesType_def::AtMineArea != aesType.underlying()))
return;
const auto cb = [this](const DDS_TYPE &data) -> bool
{
// return false -> do not stop looping over items
if (data.isDeleted())
return false;
this->updateVisibility(data);
return false;
};
iterateAesData(cb);
}
}
@@ -0,0 +1,91 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "aes_to_situation_map_tmpl.h"
#include <Plugins/AreaEffectSimulation/aes_data_plugin_interface.h>
#include <MapObjects/virtual_mine.h>
#include <QObject>
namespace SituationMap
{
/*
Norbert Thoden, 03.08.2023
Es gibt verdeckten Ladungen (BoobyTraps) und PanzerAbwehrRichtmine/PzAbwRiMi (Off-Route-Mines)
Die verdeckten Ladungen Typ 1 und 2 werden durch BoobyTraps visualisiert.
VLAD_1 hat ein Kreissegement, VLAD_2 hat einen Vollkreis.
Die VLAD haben
- einen inneren 'triggerRadius' (Auslöseradius)
- einen aeusseren 'impactRadius' (Wirkradius)
Die Darstellung in 3D ist:
- VLAD_1 -> Kegel (CONE)
- VLAD_1 -> Kugel (SPHERE)
Dann gibt es noch:
Die Off-Route-Mines:
- PzAbwRiMi 1 für Deutschland
- PzAbwRiMi 2 für Russland (zusätzlicher Wirk-Kreis)
Diese werden durch einen rechteckigen Bereich dargestellt, sieht aber fast aus wie eine Linie.
KEIN Quader
(Der rechteckigen Bereich entspricht dann dem triggerRadius UND impactRadius!)
Für Russland wird ein zusätzlicher Wirk-Kreis am Ursprung dargestellt.
Wenn ein FAHRZEUG diese 'Linie' überquert, wird die Off-Route-Mines getriggert.
Der zusätzlicher Wirk-Kreis wird per AesItemView mit AtOffRouteMineSecondary gepublished.
*/
class BoobyTrap2SituationMap;
template <>
struct Aes2SituationMapTraits<BoobyTrap2SituationMap>
{
using DDS_TYPE = AreaEffectSimulation::BoobyTrap;
using MAP_TYPE = SituationMap::VirtualMine;
static const AreaEffectSimulation::AesType_def::type aesType = AreaEffectSimulation::AesType_def::AtBoobyTrap;
};
class BoobyTrap2SituationMap final : public Aes2SituationMap<BoobyTrap2SituationMap>
{
Q_OBJECT
public:
using BaseClass = SituationMap::Aes2SituationMap<BoobyTrap2SituationMap>;
using BaseClass::BaseClass;
bool run() override;
bool iterateAesData(const std::function<bool(const AreaEffectSimulation::BoobyTrap &data)> &cb) const
{
return m_aesDtc->boobyTraps(cb);
}
protected Q_SLOTS:
void onPartitionTimeChanged(qint64 newPartitionTime);
protected:
void updateAllDetonationSpheres(qint64 newPartitionTime);
protected Q_SLOTS:
void onAesItemViewChanged(const AreaEffectSimulation::AesItemView &data, DataModification modType);
protected:
bool updateDetonationSphere3D(RefPointer<MAP_T> mapObj, const AreaEffectSimulation::BoobyTrap &data, qint64 newPartitionTime);
bool updateSecondary(int32_t simId);
protected:
bool updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj) override;
bool isVisibleByFilter(const DDS_TYPE &data) const override;
void onAesDisplayFilterChanged(AreaEffectSimulation::AesType aesType) override;
};
} // namespace
@@ -0,0 +1,84 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#include "borderline_to_map.h"
#include <Map/object_factory.h>
namespace SituationMap
{
//------------------------------------------------------------------------------
bool Borderline2SituationMap::run()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (!m_aesDtc)
return false;
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::borderlineChanged,
this, &Borderline2SituationMap::handleChanged, Qt::UniqueConnection);
// get:
m_aesDtc->borderlines([this](const AreaEffectSimulation::Borderline &data)
{
handleChanged(data, DataModification::eAdded);
});
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
// NLDEVCTRL-922: RPL Nr 725: Ablauflinien Sicht-/Benutzbarkeit
// ERST das primäre DDS-Topic Borderline publizieren, DANN die
// zugehörige/sekundäre AesItemView.
// Somit kann beim primären DDS-Topic die Geometrie aus dem sekundären DDS-Topic NICHT ermittelt werden.
// 2019 wurde die Lösung implementiert, allerdings wurden die Borderlines vergessen. Habe dies nun nachgeholt:
// --> BaseClass::run()
return BaseClass::run();
}
bool Borderline2SituationMap::updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
// show just the ObjectAppearance::Technical
// mapObj->setVisibility(ObjectAppearance::Tactical, false);
LineStyle ls = mapObj->lineStyle();
ls.setLineWidth(2);
mapObj->setLineStyle(ls);
mapObj->setIdentifier(QString::fromStdString(ddsData.name()));
if (ddsData.partyId().is_set())
mapObj->setPartyId(ddsData.partyId().get());
const int32_t simId = ddsData.id();
AreaEffectSimulation::AesItemView itemView;
if (m_aesDtc->aesItemViewFromEntityId(simId, AreaEffectSimulation::AesType::AtBorderline, itemView))
this->updateGeometry(itemView, mapObj);
else
{
DEBUG_LOG(m_logger) << LOGFUNCTION
<< " no AesItemView (AtBorderline) found"
<< ", simId = " << simId
<< ", provide fallBackGeometry";
// provide fallbackGeometry to avoid errorMsg like 'incorrect number of positions'
mapObj->setPositions({{0.0, 0.0, .0},
{0.0, 0.1, .0},
{0.1, 0.1, .0},
{0.1, 0.0, .0}});
// do not return here, perform stuff like updateVisibility and so on
}
updateVisibility(ddsData, mapObj);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
}
@@ -0,0 +1,58 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "aes_to_situation_map_tmpl.h"
#include <Plugins/AreaEffectSimulation/aes_data_plugin_interface.h>
#include <MapObjects/polyline.h>
#include <QObject>
namespace SituationMap
{
//------------------------------------------------------------------------------
// class Borderline2SituationMap
//------------------------------------------------------------------------------
class Borderline2SituationMap;
template <>
struct Aes2SituationMapTraits<Borderline2SituationMap>
{
using DDS_TYPE = AreaEffectSimulation::Borderline;
using MAP_TYPE = SituationMap::Polyline;
static const AreaEffectSimulation::AesType_def::type aesType = AreaEffectSimulation::AesType_def::AtBorderline;
};
class Borderline2SituationMap final : public Aes2SituationMap<Borderline2SituationMap>
{
Q_OBJECT
public:
using BaseClass = SituationMap::Aes2SituationMap<Borderline2SituationMap>;
using BaseClass::BaseClass;
bool run() override;
//distinction between global and local borderlines
bool isElapsed(const DDS_TYPE &ddsData) const override
{
return (ddsData.operatorId() > 0 && m_pluginProvider->operatorId() != ddsData.operatorId());
}
bool iterateAesData(const std::function<bool(const AreaEffectSimulation::Borderline &data)> &cb) const
{
return m_aesDtc->borderlines(cb);
}
protected:
bool updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj) override;
};
} // namespace
@@ -0,0 +1,664 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
// Own
#include "building_contamination.h"
#include <Map/map.h>
#include <Map/object_factory.h>
#include <MapObjects/cube.h>
#include <LtsCoordTrans/lts_coord_trans.h>
#include <MathUtils/simple_helper.h>
#include <functional>
#define USE_BUFFER_APPROACH
#ifdef USE_BUFFER_APPROACH
# include <arcgis/PolygonBuilder.h>
# include <arcgis/GeometryEngine.h>
#endif // USE_BUFFER_APPROACH
namespace SituationMap
{
//------------------------------------------------------------------------------
class BuildingContamination::Private
{
public:
explicit Private() = default;
~Private() = default;
// buildingId, BuildingContamination
QMap<int32_t, Buildings::BuildingState> m_buildingStateData;
Map *m_map = nullptr;
// MapObjects
QMap<QPair<int, int>, UniqueMapId> m_bldgFlr2UniqueMapId;
bool m_visible = false;
int m_drawOrder = 0;
//------------------------------------------------------------------------------
static QPair<int, int> createKey(int buildingId, int floorId)
{
return {buildingId, floorId};
}
static int buildingIdOfKey(const QPair<int, int> &keyData)
{
return keyData.first;
}
RefPointer<Cube> getCreateCube(int buildingId, int floorId)
{
const QPair<int, int> &key = createKey(buildingId, floorId);
const UniqueMapId uniqueMapId = m_bldgFlr2UniqueMapId.value(key, INVALID_MAP_ID);
if (!SituationMap::isUniqueMapIdValid(uniqueMapId))
{
const QString &layernameForCubes = m_map->layerFactory().layernameForCubes();
const QString &key_debugInfo = QStringLiteral("bldg_%1-flr%2").arg(buildingId).arg(floorId);
RefPointer<Cube> cube =
m_map->objectFactory().create<Cube>(layernameForCubes, key_debugInfo);
if (cube.valid())
m_bldgFlr2UniqueMapId[key] = cube->uniqueMapId();
return cube;
}
return m_map->objectFactory().get<Cube>(uniqueMapId);
}
void removeCube(int buildingId = -1)
{
QMutableMapIterator<QPair<int, int>, UniqueMapId> mapIt(m_bldgFlr2UniqueMapId);
while (mapIt.hasNext())
{
mapIt.next();
const QPair<int, int> &key = mapIt.key();
int curBuildingId = buildingIdOfKey(key);
if ((buildingId < 0) ||
(buildingId == curBuildingId)
)
{
UniqueMapId uMapId = mapIt.value();
SituationMap::AbstractMapObject *mapObj = m_map->objectFactory().idToMapObject(uMapId);
if (mapObj)
mapObj->removeMySelf();
// Will remove that pair from map:
mapIt.remove();
}
} // while
}
bool updateVisibility(int buildingId = -1)
{
bool success = true;
QMutableMapIterator<QPair<int, int>, UniqueMapId> mapIt(m_bldgFlr2UniqueMapId);
while (mapIt.hasNext())
{
mapIt.next();
const QPair<int, int> &key = mapIt.key();
int curBuildingId = buildingIdOfKey(key);
if ((buildingId < 0) ||
(buildingId == curBuildingId)
)
{
UniqueMapId uMapId = mapIt.value();
SituationMap::AbstractMapObject *mapObj = m_map->objectFactory().idToMapObject(uMapId);
if (mapObj)
{
mapObj->setVisibility(m_visible);
if (!mapObj->updateView())
success = false;
}
}
} // while
return success;
}
};
//------------------------------------------------------------------------------
// class BuildingContamination
//------------------------------------------------------------------------------
BuildingContamination::BuildingContamination(int drawOrder, QObject *parent)
: BaseClass(parent)
, m_logger(getLogger("BuildingContamination"))
, d(new Private())
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
d->m_drawOrder = drawOrder;
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
BuildingContamination::~BuildingContamination()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
this->stop();
// this->removeAllObjects(); // will be done by dtor on Map
delete d;
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
bool BuildingContamination::init(Map *map, PluginProvider *pluginProvider)
{
d->m_map = map;
if (!d->m_map)
return false;
if (!pluginProvider ||
!pluginProvider->cesDtc() ||
!pluginProvider->ismDtc())
return false;
m_bldDtc = pluginProvider->bldDtc();
m_ismDtc = pluginProvider->ismDtc();
return true;
}
void BuildingContamination::removeAllObjects()
{
d->removeCube(); // will remove all stored MapObjects/Cubes
}
bool BuildingContamination::run()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (!d->m_map)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no m_map";
return false;
}
if (!m_bldDtc)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no m_bldDtc";
return false;
}
m_bldDtc->disconnect(this);
qRegisterMetaType<Buildings::BuildingState>("Buildings::BuildingState");
connect(m_bldDtc.get(), &Buildings::Interface::Dtc::buildingStateChanged,
this, &BuildingContamination::onBuildingStateChanged, Qt::QueuedConnection);
// get:
m_bldDtc->buildingStates([this](const Buildings::BuildingState & data)
{
onBuildingStateChanged(data, DataModification::eAdded);
});
// Trigger manually :
if (false)
{
std::function<void(int, int, int)> fTriggerBuilding = [this](int partyId, int buildingId, int floorId)
{
// V100.1: Renderingmode::Dynamic -> cube shows height
// V100.1: Renderingmode::Static -> cube is flat
// retrieve geometry:
const PositionCont &absPositionsGeo = retrieveBuildingGeometry(buildingId, floorId);
// retrieve height:
QMap<int, double> floorHeights = retrieveBuildingAbsHeight(buildingId);
// cubes:
RefPointer<Cube> cube = d->getCreateCube(buildingId, floorId);
if (!cube)
ERROR_LOG(m_logger) << LOGFUNCTION << " no cube created";
cube->setVisibility(d->m_visible);
cube->setDrawOrder(d->m_drawOrder);
cube->setPartyId(partyId); // means: set partyId of owner
cube->setPositions(absPositionsGeo);
const double height = floorHeights.value(floorId, 2.5 * floorId);
cube->setHeight(height);
bool success = cube->updateView();
INFO_LOG(m_logger) << LOGFUNCTION << " cube->updateView " << success;
};
// partyId, bldId, floorid
fTriggerBuilding(24, 5, 1);
fTriggerBuilding(-1, 5, 2);
fTriggerBuilding(89, 5, 3);
}
// : Trigger manually
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
void BuildingContamination::stop()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
m_bldDtc->disconnect(this);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
bool BuildingContamination::isVisible() const
{
return d->m_visible;
}
bool BuildingContamination::setVisible(bool visible)
{
d->m_visible = visible;
bool succ = d->updateVisibility();
return succ;
}
void BuildingContamination::onBuildingStateChanged(const Buildings::BuildingState &data, DataModification modType)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
const int buildingId = data.id();
switch (modType)
{
case DataModification::eAdded:
case DataModification::eModified:
// retrieve geometry from ISM and ownership and finally create cubes
updateBuilding(buildingId);
break;
case DataModification::eRemoved:
// reset ownership -> remove cubes:
d->removeCube(buildingId);
break;
} // switch
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
void BuildingContamination::onResetBuildingState()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
d->removeCube();
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
void BuildingContamination::updateBuilding(int buildingId)
{
DEBUG_LOG(m_logger) << "update Building " << buildingId;
// retrieve data for complete building:
const Buildings::BuildingState &bos = m_bldDtc->buildingState(buildingId);
// update own data:
d->m_buildingStateData[buildingId] = bos;
const auto contaminations = bos.contaminationStates();
DEBUG_LOG(m_logger) << "Statecount " << contaminations.size();
// accessable by floorId:
QSet<int> contaminatedFloors;
for (const Buildings::ContaminationState &contaminationState : contaminations)
{
//we might get multiple contaminations so first make a Set of rooms:
QSet<int> rooms;
for (const auto &room : contaminationState.rooms())
{
rooms.insert(room);
}
//now check for floors
DEBUG_LOG(m_logger) << "contaminated rooms " << rooms.size();
for (int room : rooms)
{
int floorIdContamination = findFloorIdByRoomId(room);
if ( floorIdContamination == -1)
continue;
contaminatedFloors.insert(floorIdContamination);
}
}
DEBUG_LOG(m_logger) << "contaminated floors " << contaminatedFloors.size();
// qCritical() << "floor2Party" << floor2Party;
// retrieve height of all floors:
QMap<int, double> floorHeights = retrieveBuildingAbsHeight(buildingId);
// create/update one Cube (MapObject) per floor:
QMapIterator<int, double> mapIt(floorHeights);
int floorCounter = 0;
while (mapIt.hasNext())
{
mapIt.next();
// a) floorId
const int floorId = mapIt.key();
// b) height
const double height = mapIt.value();
// c) contamination:
// set them to "false", if not existing:
const bool isContaminaed = contaminatedFloors.contains(floorId);
DEBUG_LOG(m_logger) << LOGFUNCTION
<< " floorId=" << floorId
<< " height=" << height
<< " partyId=" << isContaminaed;
// retrieve geometry:
const PositionCont &absPositionsGeo = retrieveBuildingGeometry(buildingId, ++floorCounter);
// cubes
RefPointer<Cube> cube = d->getCreateCube(buildingId, floorId);
cube->setVisibility(d->m_visible);
cube->setDrawOrder(d->m_drawOrder);
cube->setPartyId(-1);
if(isContaminaed)
{
cube->setPartyId(-2);
QColor col(Qt::yellow);
cube->setForceMajorColor(col.name());
}
cube->setPositions(absPositionsGeo);
cube->setHeight(height);
if (!cube->updateView())
ERROR_LOG(m_logger) << LOGFUNCTION << " cube->updateView() failed";
} // while
}
//void BuildingContamination::updateBuildingVisiblity(int buildingId)
//{
//}
int BuildingContamination::findFloorIdByRoomId(int roomId) noexcept(false)
{
// get the floor by getting the parent of the room
auto roomToFloorCache = m_roomToFloorCache.constFind(roomId); // try to find the floor in the cache first
if (roomToFloorCache != m_roomToFloorCache.constEnd())
{
//qWarning() << ":) cache hit for room" << roomId;
return roomToFloorCache.value();
}
//qWarning() << ":( cache miss for room" << roomId;
InfrastructureManagement::StructureElement roomSe;
if (!m_ismDtc->getStructureElementById(roomId, roomSe))
{
ERROR_LOG(m_logger) << "getStructureElementById roomId=" << roomId << " not found";
return -1;
}
const std::vector<int32_t> path = roomSe.path();
for (const int parentSeId : path)
{
InfrastructureManagement::StructureElement parentSe;
if (!getRoom(parentSeId, parentSe))
continue;
//qWarning() << "seId" << seId << "type" << structureElement2.structureElementTypeId().underlying();
if (parentSe.structureElementTypeId().underlying() != InfrastructureManagement::StructureElementType_def::Floor)
continue;
// there can only be one floor per room (duh), so we can break after that and finally know the se id for the floor the participant is in
m_roomToFloorCache.insert(roomId, parentSeId);
return parentSeId;
}
throw QStringLiteral("findFloorId: floor id for room %1 not found").arg(roomSe.id());
}
bool BuildingContamination::getRoom(int roomSeId, InfrastructureManagement::StructureElement &roomSe)
{
auto it = m_roomStructureElementCache.find(roomSeId);
if (it != m_roomStructureElementCache.end())
{
//qWarning() << "getRoom: cache hit!";
roomSe = *it;
return true;
}
if (m_ismDtc->getStructureElementById(roomSeId, roomSe))
{
//qWarning() << "getRoom: cache miss - adding to cache";
m_roomStructureElementCache.insert(roomSeId, roomSe);
return true;
}
return false; // not found :((((
}
PositionCont BuildingContamination::retrieveBuildingGeometry(int buildingId, int floorId) const
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
<< " buildingId=" << buildingId
<< " floorId=" << floorId;
if (!m_ismDtc)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no m_ismDtc";
return PositionCont();
}
//
// retrieve relative points of footprint:
//
QVector<QPointF> relPositions;
{
const InfrastructureManagement::MainFootprint &mainFootprint = m_ismDtc->mainFootprint(buildingId);
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
<< " mainFootprint.elements().size()=" << mainFootprint.elements().size();
relPositions.reserve(mainFootprint.elements().size());
// sorted per definition
for (const InfrastructureManagement::FootprintElement &element : mainFootprint.elements())
{
const auto &relPos = element.relPosition();
relPositions += QPointF(relPos.offsetX(), relPos.offsetY());
}
}
// DEBUG_LOG(m_logger) << "footprintOrg = " << relPositions;
//
// expand the polyline depending on the floor:
//
#ifndef USE_BUFFER_APPROACH
// calculate the mass/center point of the outline/polygon:
{
// assume that there will be not more than 100 floors:
const double distance = 0.5 + (100 - floorId) * 0.01;
const QPolygonF &massPoly = relPositions.toVector();
const QPointF &massCenterPoint = massPoly.boundingRect().center();
// increase distance to massCenterPoint (depending on the quadrant)
const double massCenterPointX = massCenterPoint.x();
const double massCenterPointY = massCenterPoint.y();
QMutableListIterator<QPointF> listIt(relPositions);
while (listIt.hasNext())
{
QPointF &relPosition = listIt.next();
// X
if (relPosition.x() < massCenterPointX)
relPosition.rx() -= distance;
else
relPosition.rx() += distance;
// Y
if (relPosition.y() < massCenterPointY)
relPosition.ry() -= distance;
else
relPosition.ry() += distance;
} // for
// DEBUG_LOG(m_logger) << "footprintBlown = " << relPositions;
}
#endif // USE_BUFFER_APPROACH
//
// translate to absolute
//
PositionCont absPositionsGeo;
const InfrastructureManagement::MainStructureElement &mse = m_ismDtc->mainStructureElement(buildingId);
const Core::GeoPosition &geoPosition = mse.geoPosition();
const QPointF &referencePointGeo = QPointF(geoPosition.lon(), geoPosition.lat());
const LtsCoordTrans::UtmCoordinate &referencePointUTM = LtsCoordTrans::UtmCoordinate::fromGeographic(referencePointGeo);
const double angleRad = mse.angle() * LtsCoordTrans::deg2rad();
// add relPos to referencePoint:
const QPointF center;
absPositionsGeo.reserve(relPositions.size());
for (const auto &relPosition : qAsConst(relPositions))
{
const QPointF &relPositionRotate = MathUtils::rotate(relPosition, center, angleRad); // rotate relPosition by angleRad around 0,0
const QPointF &pGeo = referencePointUTM.geographic(relPositionRotate); // add relPosition to referencePointUTM
absPositionsGeo.append(Point3D::fromQPointF(pGeo));
} // for
// DEBUG_LOG(m_logger) << "absPositionsGeo = " << absPositionsGeo;
#ifdef USE_BUFFER_APPROACH
{
//
// This works better for building for building with a shape like a 'H'...
//
// assume that there will be not more than 100 floors:
const double distance = (100 - floorId) * 0.01;
// create EsriGeometry:
Esri::ArcGISRuntime::PolygonBuilder polygonBuilder(Esri::ArcGISRuntime::SpatialReference::wgs84());
constexpr double rad2deg = LtsCoordTrans::rad2deg();
for (const Point3D &point : qAsConst(absPositionsGeo))
polygonBuilder.addPoint(Esri::ArcGISRuntime::Point(point.x() * rad2deg,
point.y() * rad2deg,
point.z()));
const Esri::ArcGISRuntime::Geometry &esriGeometry = polygonBuilder.toGeometry();
const Esri::ArcGISRuntime::Polygon &polyline =
Esri::ArcGISRuntime::GeometryEngine::bufferGeodetic(esriGeometry,
distance,
Esri::ArcGISRuntime::LinearUnitId::Meters,
0.1,
Esri::ArcGISRuntime::GeodeticCurveType::Geodesic);
if (polyline.parts().isEmpty())
return absPositionsGeo;
const Esri::ArcGISRuntime::ImmutablePart &immutablePart = polyline.parts().part(0);
const Esri::ArcGISRuntime::ImmutablePointCollection &pointCollection = immutablePart.points();
const int size = pointCollection.size();
INFO_LOG(m_logger) << " pointCollection.size = " << pointCollection.size()
<< " - buildingId = " << buildingId
<< ", mse.name = " << mse.name();
absPositionsGeo.clear();
absPositionsGeo.reserve(size);
for (const Esri::ArcGISRuntime::Point &esriP : pointCollection)
{
absPositionsGeo.append(Point3D(esriP.x() * LtsCoordTrans::deg2rad(),
esriP.y() * LtsCoordTrans::deg2rad(),
esriP.z()));
} // for;
}
#endif // USE_BUFFER_APPROACH
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return absPositionsGeo;
}
QMap<int, double> BuildingContamination::retrieveBuildingAbsHeight(int buildingId) const
{
QMap<int, double> floorHeights;
const InfrastructureManagement::MainStructureElement &mse = m_ismDtc->mainStructureElement(buildingId);
// move from dds to QVector:
for (const InfrastructureManagement::StructureElement &element : mse.elements())
{
if (element.structureElementTypeId() != InfrastructureManagement::StructureElementType::Floor)
continue;
const int floorId = element.id();
//
// Cubes are using the UniqueValueRenderer of layer 'BuildingContamination'.
// To reduce the dependency to the elevation source, choose
// ExtrusionMode::AbsoluteHeight @ UniqueValueRenderer
// Additionally, the top is flat (and not according base surface.)
//
// If UniqueValueRenderer uses: Esri::ArcGISRuntime::ExtrusionMode::AbsoluteHeight
// ExtrusionMode::AbsoluteHeight has a flat top.
double height = element.geoPosition().z();
// If UniqueValueRenderer uses: Esri::ArcGISRuntime::ExtrusionMode::BaseHeight
// This is the only extrusion mode that doesn't have a flat top.
// The extruded height, we need the relative,
// double height = element.relPosition().offsetZ();
floorHeights[floorId] = height;
}
// this is the height of the bottom, not the ceiling
// therefore we have take value of topwards neighboring floor:
{
QMutableMapIterator<int, double> mapIt(floorHeights);
while (mapIt.hasNext())
{
QMap<int, double>::iterator curFloor = mapIt.next();
if (mapIt.hasNext())
{
QMap<int, double>::iterator upperFloor = mapIt.peekNext(); // neighboring floor
curFloor.value() = upperFloor.value();
}
else
curFloor.value() += 2.0; // add default height of 2 [meter]
}
}
return floorHeights;
}
}
@@ -0,0 +1,91 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
// Own
#include "plugin_provider.h"
#include <Map/situation_map_types.h>
#include <Common/situation_map_logging.h>
#include <Plugins/Buildings/bld_data_plugin_interface.h>
#include <Plugins/InfrastructureManagement/ism_data_plugin_interface.h>
// Qt
#include <QObject>
#include <QMap>
namespace SituationMap
{
// forward:
class Map;
class BuildingContamination : public QObject
{
Q_OBJECT
using BaseClass = QObject;
public:
explicit BuildingContamination(int drawOrder, QObject *parent = nullptr);
~BuildingContamination();
bool init(Map *map, PluginProvider *pluginProvider);
void clearInterfaces();
void removeAllObjects();
void clearObjects() { removeAllObjects(); }
bool run();
void stop();
bool isVisible() const;
bool setVisible(bool visible);
Q_SIGNALS:
protected Q_SLOTS:
void onBuildingStateChanged(const Buildings::BuildingState &data, DataModification modType);
void onResetBuildingState();
protected:
void updateBuilding(int buildingId);
int findFloorIdByRoomId(int roomId);
bool getRoom(int roomSeId, InfrastructureManagement::StructureElement &roomSe);
PositionCont retrieveBuildingGeometry(int buildingId, int floorId) const;
QMap<int, double> retrieveBuildingAbsHeight(int buildingId) const;
private:
LOGGER_T m_logger; ///< Interface of the Logging-Facility
QMap<int /* room */, int /* floor */> m_roomToFloorCache;
QMap<int /* room */, InfrastructureManagement::StructureElement /* se */> m_roomStructureElementCache;
class Private;
/**
* The private d->pointer to not break BC when changing internals of this class
*/
Private *d = nullptr;
// DDS:
std::shared_ptr<Buildings::Interface::Dtc> m_bldDtc;
std::shared_ptr<InfrastructureManagement::Interface::Dtc> m_ismDtc;
};
} // namespace
@@ -0,0 +1,662 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
// Own
#include "building_ownership.h"
#include <Map/map.h>
#include <Map/object_factory.h>
#include <MapObjects/cube.h>
#include <LtsCoordTrans/lts_coord_trans.h>
#include <MathUtils/simple_helper.h>
#include <unordered_map>
#include <functional>
#define USE_BUFFER_APPROACH
#ifdef USE_BUFFER_APPROACH
# include <arcgis/PolygonBuilder.h>
# include <arcgis/GeometryEngine.h>
#endif // USE_BUFFER_APPROACH
namespace SituationMap
{
//------------------------------------------------------------------------------
// PositionCont BuildingOwnership::retrieveBuildingGeometry(int buildingId, int floorId) const
// QMap<int, double> BuildingOwnership::retrieveBuildingAbsHeight(int buildingId) const
//------------------------------------------------------------------------------
// class BuildingGeometryCache
//------------------------------------------------------------------------------
class BuildingGeometryCache
{
//------------------------------------------------------------------------------
// struct KEY_T
//------------------------------------------------------------------------------
struct KEY_T
{
KEY_T(int buildingId = -1, int floorId = -1)
: m_buildingId(buildingId), m_floorId(floorId)
{}
int m_buildingId{-1};
int m_floorId{-1};
bool operator<(const KEY_T &other) const
{
return m_buildingId < other.m_buildingId
|| ((m_buildingId == other.m_buildingId) && (m_floorId < other.m_floorId));
}
};
public:
BuildingGeometryCache() = default;
~BuildingGeometryCache() = default;
void init(BuildingOwnership *buildingOwnership)
{
m_buildingOwnership = buildingOwnership;
}
PositionCont retrieveBuildingGeometry(int buildingId, int floorId) const
{
const KEY_T key(buildingId, floorId);
loadGeometry(key);
return m_cacheGeometry[key];
};
QMap<int, double> retrieveBuildingAbsHeight(int buildingId) const
{
loadAbsHeight(buildingId);
return m_cacheAbsHeight[buildingId];
};
private:
void loadGeometry(const KEY_T &key) const
{
if (m_cacheGeometry.contains(key))
return;
m_cacheGeometry[key] = m_buildingOwnership->retrieveBuildingGeometryInternal(key.m_buildingId, key.m_floorId);
}
void loadAbsHeight(int buildingId) const
{
if (m_cacheAbsHeight.contains(buildingId))
return;
m_cacheAbsHeight[buildingId] = m_buildingOwnership->retrieveBuildingAbsHeightInternal(buildingId);
}
private:
BuildingOwnership *m_buildingOwnership{nullptr};
mutable QMap<KEY_T, PositionCont> m_cacheGeometry;
mutable QMap<int, QMap<int, double>> m_cacheAbsHeight; // key == buildingId
};
//------------------------------------------------------------------------------
class BuildingOwnership::Private
{
public:
explicit Private() = default;
~Private() = default;
// buildingId, BuildingOwnership
QMap<int32_t, CentralEffectSimulation::BuildingOwnership> m_ownershipData;
BuildingGeometryCache m_buildingGeometryCache;
Map *m_map = nullptr;
// MapObjects
QMap<QPair<int, int>, UniqueMapId> m_bldgFlr2UniqueMapId;
bool m_visible = false;
int m_drawOrder = 0;
//------------------------------------------------------------------------------
static QPair<int, int> createKey(int buildingId, int floorId)
{
return {buildingId, floorId};
}
static int buildingIdOfKey(const QPair<int, int> &keyData)
{
return keyData.first;
}
RefPointer<Cube> getCreateCube(int buildingId, int floorId)
{
const QPair<int, int> &key = createKey(buildingId, floorId);
const UniqueMapId uniqueMapId = m_bldgFlr2UniqueMapId.value(key, INVALID_MAP_ID);
if (!SituationMap::isUniqueMapIdValid(uniqueMapId))
{
const QString &layernameForCubes = m_map->layerFactory().layernameForCubes();
const QString &key_debugInfo = QStringLiteral("bldg_%1-flr%2").arg(buildingId).arg(floorId);
RefPointer<Cube> cube =
m_map->objectFactory().create<Cube>(layernameForCubes, key_debugInfo);
if (cube.valid())
m_bldgFlr2UniqueMapId[key] = cube->uniqueMapId();
return cube;
}
return m_map->objectFactory().get<Cube>(uniqueMapId);
}
void removeCube(int buildingId = -1)
{
QMutableMapIterator<QPair<int, int>, UniqueMapId> mapIt(m_bldgFlr2UniqueMapId);
while (mapIt.hasNext())
{
mapIt.next();
const QPair<int, int> &key = mapIt.key();
int curBuildingId = buildingIdOfKey(key);
if ((buildingId < 0) ||
(buildingId == curBuildingId)
)
{
UniqueMapId uMapId = mapIt.value();
SituationMap::AbstractMapObject *mapObj = m_map->objectFactory().idToMapObject(uMapId);
if (mapObj)
mapObj->removeMySelf();
// Will remove that pair from map:
mapIt.remove();
}
} // while
}
bool updateVisibility(int buildingId = -1)
{
bool success = true;
QMutableMapIterator<QPair<int, int>, UniqueMapId> mapIt(m_bldgFlr2UniqueMapId);
while (mapIt.hasNext())
{
mapIt.next();
const QPair<int, int> &key = mapIt.key();
int curBuildingId = buildingIdOfKey(key);
if ((buildingId < 0) ||
(buildingId == curBuildingId)
)
{
UniqueMapId uMapId = mapIt.value();
SituationMap::AbstractMapObject *mapObj = m_map->objectFactory().idToMapObject(uMapId);
if (mapObj)
{
mapObj->setVisibility(m_visible);
if (!mapObj->updateView())
success = false;
}
}
} // while
return success;
}
};
//------------------------------------------------------------------------------
// class BuildingOwnership
//------------------------------------------------------------------------------
BuildingOwnership::BuildingOwnership(int drawOrder, QObject *parent)
: BaseClass(parent)
, m_logger(getLogger("BuildingOwnership"))
, d(new Private())
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
d->m_drawOrder = drawOrder;
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
BuildingOwnership::~BuildingOwnership()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
this->stop();
// this->removeAllObjects(); // will be done by dtor on Map
delete d;
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
bool BuildingOwnership::init(Map *map, PluginProvider *pluginProvider)
{
d->m_map = map;
if (!d->m_map)
return false;
if (!pluginProvider ||
!pluginProvider->cesDtc() ||
!pluginProvider->ismDtc())
return false;
m_cesDtc = pluginProvider->cesDtc();
m_ismDtc = pluginProvider->ismDtc();
d->m_buildingGeometryCache.init(this);
return true;
}
void BuildingOwnership::removeAllObjects()
{
d->removeCube(); // will remove all stored MapObjects/Cubes
}
bool BuildingOwnership::run()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (!d->m_map)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no m_map";
return false;
}
if (!m_cesDtc)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no m_cesDtc";
return false;
}
m_cesDtc->disconnect(this);
qRegisterMetaType<CentralEffectSimulation::BuildingOwnership>("CentralEffectSimulation::BuildingOwnership");
connect(m_cesDtc.get(), &CentralEffectSimulation::Interface::Dtc::buildingOwnershipChanged,
this, &BuildingOwnership::onBuildingOwnershipChanged, Qt::QueuedConnection);
// get:
m_cesDtc->buildingOwnerships([this](const CentralEffectSimulation::BuildingOwnership & data)
{
onBuildingOwnershipChanged(data, DataModification::eAdded);
});
// Trigger manually :
if (false)
{
std::function<void(int, int, int)> fTriggerBuilding = [this](int partyId, int buildingId, int floorId)
{
// V100.1: Renderingmode::Dynamic -> cube shows height
// V100.1: Renderingmode::Static -> cube is flat
// retrieve geometry:
const PositionCont &absPositionsGeo = retrieveBuildingGeometry(buildingId, floorId);
// retrieve height:
QMap<int, double> floorHeights = retrieveBuildingAbsHeight(buildingId);
// cubes:
RefPointer<Cube> cube = d->getCreateCube(buildingId, floorId);
if (!cube)
ERROR_LOG(m_logger) << LOGFUNCTION << " no cube created";
cube->setVisibility(d->m_visible);
cube->setDrawOrder(d->m_drawOrder);
cube->setPartyId(partyId); // means: set partyId of owner
cube->setPositions(absPositionsGeo);
const double height = floorHeights.value(floorId, 2.5 * floorId);
cube->setHeight(height);
bool success = cube->updateView();
INFO_LOG(m_logger) << LOGFUNCTION << " cube->updateView " << success;
};
// partyId, bldId, floorid
fTriggerBuilding(24, 5, 1);
fTriggerBuilding(-1, 5, 2);
fTriggerBuilding(89, 5, 3);
}
// : Trigger manually
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
void BuildingOwnership::stop()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
m_cesDtc->disconnect(this);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
bool BuildingOwnership::isVisible() const
{
return d->m_visible;
}
bool BuildingOwnership::setVisible(bool visible)
{
d->m_visible = visible;
bool succ = d->updateVisibility();
return succ;
}
void BuildingOwnership::onBuildingOwnershipChanged(const CentralEffectSimulation::BuildingOwnership &data, DataModification modType)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
const int buildingId = data.buildingId();
switch (modType)
{
case DataModification::eAdded:
case DataModification::eModified:
// retrieve geometry from ISM and ownership and finally create cubes
updateBuilding(buildingId);
break;
case DataModification::eRemoved:
// reset ownership -> remove cubes:
d->removeCube(buildingId);
break;
} // switch
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
void BuildingOwnership::onResetBuildingOwnership()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
d->removeCube();
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
void BuildingOwnership::updateBuilding(int buildingId)
{
// retrieve data for complete building:
const CentralEffectSimulation::BuildingOwnership &bos = m_cesDtc->buildingOwnership(buildingId);
// update own data:
d->m_ownershipData[buildingId] = bos;
const auto &ownerships = bos.ownerships();
// accessable by floorId:
QMap<int, int> floor2Party;
for (const CentralEffectSimulation::Ownership &ownership : ownerships)
// BuildingOwnership uses a '0' to indicate an invalid partyId.... :-(
if (ownership.partyId() > 0)
floor2Party[ownership.floorId()] = ownership.partyId();
// qCritical() << "floor2Party" << floor2Party;
// retrieve height of all floors:
const QMap<int, double> &floorHeights = retrieveBuildingAbsHeight(buildingId);
// create/update one Cube (MapObject) per floor:
QMapIterator<int, double> mapIt(floorHeights);
int floorCounter = 0;
while (mapIt.hasNext())
{
mapIt.next();
// a) floorId
const int floorId = mapIt.key();
// b) height
const double height = mapIt.value();
// c) partyId:
// set them to "unknown", if not existing:
const int partyId = floor2Party.value(floorId, -1); // invalid partyId -> unknown -> white color
DEBUG_LOG(m_logger) << LOGFUNCTION
<< " floorId=" << floorId
<< " height=" << height
<< " partyId=" << partyId;
// retrieve geometry:
const PositionCont &absPositionsGeo = retrieveBuildingGeometry(buildingId, ++floorCounter);
// cubes
RefPointer<Cube> cube = d->getCreateCube(buildingId, floorId);
cube->setVisibility(d->m_visible);
cube->setDrawOrder(d->m_drawOrder);
cube->setPartyId(partyId); // means: set partyId of owner
cube->setPositions(absPositionsGeo);
cube->setHeight(height);
if (!cube->updateView())
ERROR_LOG(m_logger) << LOGFUNCTION << " cube->updateView() failed";
} // while
}
PositionCont BuildingOwnership::retrieveBuildingGeometry(int buildingId, int floorId) const
{
return d->m_buildingGeometryCache.retrieveBuildingGeometry(buildingId, floorId);
}
PositionCont BuildingOwnership::retrieveBuildingGeometryInternal(int buildingId, int floorId) const
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
<< " buildingId=" << buildingId
<< " floorId=" << floorId;
if (!m_ismDtc)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no m_ismDtc";
return PositionCont();
}
//
// retrieve relative points of footprint:
//
QVector<QPointF> relPositions;
{
const InfrastructureManagement::MainFootprint &mainFootprint = m_ismDtc->mainFootprint(buildingId);
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
<< " mainFootprint.elements().size()=" << mainFootprint.elements().size();
relPositions.reserve(mainFootprint.elements().size());
// sorted per definition
const auto &fpElements = mainFootprint.elements();
for (const InfrastructureManagement::FootprintElement &element : fpElements)
{
const auto &relPos = element.relPosition();
relPositions += QPointF(relPos.offsetX(), relPos.offsetY());
}
}
// DEBUG_LOG(m_logger) << "footprintOrg = " << relPositions;
//
// expand the polyline depending on the floor:
//
#ifndef USE_BUFFER_APPROACH
// calculate the mass/center point of the outline/polygon:
{
// assume that there will be not more than 100 floors:
const double distance = 0.5 + (100 - floorId) * 0.01;
const QPolygonF &massPoly = relPositions.toVector();
const QPointF &massCenterPoint = massPoly.boundingRect().center();
// increase distance to massCenterPoint (depending on the quadrant)
const double massCenterPointX = massCenterPoint.x();
const double massCenterPointY = massCenterPoint.y();
QMutableListIterator<QPointF> listIt(relPositions);
while (listIt.hasNext())
{
QPointF &relPosition = listIt.next();
// X
if (relPosition.x() < massCenterPointX)
relPosition.rx() -= distance;
else
relPosition.rx() += distance;
// Y
if (relPosition.y() < massCenterPointY)
relPosition.ry() -= distance;
else
relPosition.ry() += distance;
} // for
// DEBUG_LOG(m_logger) << "footprintBlown = " << relPositions;
}
#endif // USE_BUFFER_APPROACH
//
// translate to absolute
//
PositionCont absPositionsGeo;
const InfrastructureManagement::MainStructureElement &mse = m_ismDtc->mainStructureElement(buildingId);
const Core::GeoPosition &geoPosition = mse.geoPosition();
const QPointF &referencePointGeo = QPointF(geoPosition.lon(), geoPosition.lat());
const LtsCoordTrans::UtmCoordinate referencePointUTM = LtsCoordTrans::UtmCoordinate::fromGeographic(referencePointGeo);
const double angleRad = mse.angle() * LtsCoordTrans::deg2rad();
// add relPos to referencePoint:
const QPointF center;
absPositionsGeo.reserve(relPositions.size());
for (const auto &relPosition : qAsConst(relPositions))
{
const QPointF &relPositionRotate = MathUtils::rotate(relPosition, center, angleRad); // rotate relPosition by angleRad around 0,0
const QPointF &pGeo = referencePointUTM.geographic(relPositionRotate); // add relPosition to referencePointUTM
absPositionsGeo.append(Point3D::fromQPointF(pGeo));
} // for
// DEBUG_LOG(m_logger) << "absPositionsGeo = " << absPositionsGeo;
#ifdef USE_BUFFER_APPROACH
{
//
// This works better for building for building with a shape like a 'H'...
//
// assume that there will be not more than 100 floors:
const double distance = (100 - floorId) * 0.01;
// create EsriGeometry:
Esri::ArcGISRuntime::PolygonBuilder polygonBuilder(Esri::ArcGISRuntime::SpatialReference::wgs84());
constexpr double rad2deg = LtsCoordTrans::rad2deg();
for (const Point3D &point : qAsConst(absPositionsGeo))
polygonBuilder.addPoint(Esri::ArcGISRuntime::Point(point.x() * rad2deg,
point.y() * rad2deg,
point.z()));
const Esri::ArcGISRuntime::Geometry &esriGeometry = polygonBuilder.toGeometry();
const Esri::ArcGISRuntime::Polygon polyline =
Esri::ArcGISRuntime::GeometryEngine::bufferGeodetic(esriGeometry,
distance,
Esri::ArcGISRuntime::LinearUnitId::Meters,
0.1,
Esri::ArcGISRuntime::GeodeticCurveType::Geodesic);
if (polyline.parts().isEmpty())
return absPositionsGeo;
const Esri::ArcGISRuntime::ImmutablePart &immutablePart = polyline.parts().part(0);
const Esri::ArcGISRuntime::ImmutablePointCollection &pointCollection = immutablePart.points();
const int size = pointCollection.size();
// NOTICE_LOG(m_logger) << " pointCollection.size = " << pointCollection.size()
// << " - buildingId = " << buildingId
// << ", mse.name = " << mse.name();
absPositionsGeo.clear();
absPositionsGeo.reserve(size);
for (const Esri::ArcGISRuntime::Point &esriP : pointCollection)
{
absPositionsGeo.append(Point3D(esriP.x() * LtsCoordTrans::deg2rad(),
esriP.y() * LtsCoordTrans::deg2rad(),
esriP.z()));
} // for;
}
#endif // USE_BUFFER_APPROACH
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return absPositionsGeo;
}
QMap<int, double> BuildingOwnership::retrieveBuildingAbsHeight(int buildingId) const
{
return d->m_buildingGeometryCache.retrieveBuildingAbsHeight(buildingId);
}
QMap<int, double> BuildingOwnership::retrieveBuildingAbsHeightInternal(int buildingId) const
{
QMap<int, double> floorHeights;
const InfrastructureManagement::MainStructureElement &mse = m_ismDtc->mainStructureElement(buildingId);
// move from dds to QVector:
for (const InfrastructureManagement::StructureElement &element : mse.elements())
{
if (element.structureElementTypeId() != InfrastructureManagement::StructureElementType::Floor)
continue;
const int floorId = element.id();
//
// Cubes are using the UniqueValueRenderer of layer 'BuildingOwnership'.
// To reduce the dependency to the elevation source, choose
// ExtrusionMode::AbsoluteHeight @ UniqueValueRenderer
// Additionally, the top is flat (and not according base surface.)
//
// If UniqueValueRenderer uses: Esri::ArcGISRuntime::ExtrusionMode::AbsoluteHeight
// ExtrusionMode::AbsoluteHeight has a flat top.
double height = element.geoPosition().z();
// If UniqueValueRenderer uses: Esri::ArcGISRuntime::ExtrusionMode::BaseHeight
// This is the only extrusion mode that doesn't have a flat top.
// The extruded height, we need the relative,
// double height = element.relPosition().offsetZ();
floorHeights[floorId] = height;
}
// this is the height of the bottom, not the ceiling
// therefore we have take value of topwards neighboring floor:
{
QMutableMapIterator<int, double> mapIt(floorHeights);
while (mapIt.hasNext())
{
QMap<int, double>::iterator curFloor = mapIt.next();
if (mapIt.hasNext())
{
QMap<int, double>::iterator upperFloor = mapIt.peekNext(); // neighboring floor
curFloor.value() = upperFloor.value();
}
else
curFloor.value() += 2.0; // add default height of 2 [meter]
}
}
return floorHeights;
}
}
@@ -0,0 +1,90 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
// Own
#include "plugin_provider.h"
#include <Map/situation_map_types.h>
#include <Common/situation_map_logging.h>
#include <Plugins/CentralEffectSimulation/ces_data_plugin_interface.h>
#include <Plugins/InfrastructureManagement/ism_data_plugin_interface.h>
// Qt
#include <QObject>
#include <QMap>
namespace SituationMap
{
// forward:
class Map;
class BuildingOwnership : public QObject
{
Q_OBJECT
using BaseClass = QObject;
public:
explicit BuildingOwnership(int drawOrder, QObject *parent = nullptr);
~BuildingOwnership();
bool init(Map *map, PluginProvider *pluginProvider);
void clearInterfaces();
void removeAllObjects();
void clearObjects() { removeAllObjects(); }
bool run();
void stop();
bool isVisible() const;
bool setVisible(bool visible);
Q_SIGNALS:
protected Q_SLOTS:
void onBuildingOwnershipChanged(const CentralEffectSimulation::BuildingOwnership &data, DataModification modType);
void onResetBuildingOwnership();
protected:
friend class BuildingGeometryCache;
void updateBuilding(int buildingId);
PositionCont retrieveBuildingGeometry(int buildingId, int floorId) const;
PositionCont retrieveBuildingGeometryInternal(int buildingId, int floorId) const;
QMap<int, double> retrieveBuildingAbsHeight(int buildingId) const;
QMap<int, double> retrieveBuildingAbsHeightInternal(int buildingId) const;
private:
LOGGER_T m_logger; ///< Interface of the Logging-Facility
class Private;
/**
* The private d->pointer to not break BC when changing internals of this class
*/
Private *d = nullptr;
// DDS:
std::shared_ptr<CentralEffectSimulation::Interface::Dtc> m_cesDtc;
std::shared_ptr<InfrastructureManagement::Interface::Dtc> m_ismDtc;
};
} // namespace
@@ -0,0 +1,440 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
// Own
#include "buildinghitlineinfo_to_map.h"
#include "pdm_handler.h"
#include <Map/object_factory.h>
// Qt
#include <QTimer>
#include <QJsonObject>
#include <QJsonDocument>
namespace SituationMap
{
BuildingHitlineInfo2SituationMap::BuildingHitlineInfo2SituationMap(PdmHandler *pdmHandler,
Participant2SituationMap *participant2SituationMap,
ObjectFactory &objFac,
const QString &layername,
int drawOrder,
const char *loggerName)
: BaseClass(objFac, layername, drawOrder, loggerName)
, FilterClass(loggerName, this)
, m_pdmHandler(pdmHandler)
, m_participant2SituationMap(participant2SituationMap)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
BuildingHitlineInfo2SituationMap::~BuildingHitlineInfo2SituationMap()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
int32_t BuildingHitlineInfo2SituationMap::getSimId(const Sim2SituationMap::DDS_T &ddsData) const
{
return ddsData.id();
}
bool BuildingHitlineInfo2SituationMap::init(PluginProvider *pluginProvider)
{
if (!pluginProvider ||
!pluginProvider->bldDtc())
return false;
m_pluginProvider = pluginProvider;
m_bldDtc = pluginProvider->bldDtc();
m_bldBuildingInfoIfc = pluginProvider->bldInfoIfc();
m_ismDtc = pluginProvider->ismDtc();
if (!m_bldDtc)
return false;
if (!m_ismDtc)
return false;
// FilterManagement:
FilterClass::init(m_pluginProvider);
// PartitionTime
connect(m_pluginProvider, &PluginProvider::partitionTimeChanged,
this, &BuildingHitlineInfo2SituationMap::onPartitionTimeChanged);
// Get initial DDS data
// building to Height
m_exerciseId = m_pluginProvider->exerciseId();
m_buildingHeight.clear();
// try to fill m_buildingHeight BEFORE the buildingHitLineInfos are processed
m_ismDtc->waitForHistoricalDataMainStructureElement(5000);
connect(m_ismDtc.get(), &InfrastructureManagement::Interface::Dtc::mainStructureElementChanged,
this, &BuildingHitlineInfo2SituationMap::onMainStructureElementChanged);
m_ismDtc->mainStructureElements([this](const InfrastructureManagement::MainStructureElement & data)
{
onMainStructureElementChanged(data, DataModification::eAdded);
});
return true;
}
bool BuildingHitlineInfo2SituationMap::run()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (!m_bldDtc)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no dtc";
return false;
}
connect(m_bldDtc.get(), &Buildings::Interface::Dtc::buildingHitLineInfoChanged,
this, &BuildingHitlineInfo2SituationMap::onBuildingHitLineInfoChanged);
// get BuildingHitlines:
m_bldDtc->buildingHitLineInfos([this](const Sim2SituationMap::DDS_T & ddsData)
{
onBuildingHitLineInfoChanged(ddsData, DataModification::eAdded);
});
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
void BuildingHitlineInfo2SituationMap::stop()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (m_bldDtc)
m_bldDtc->disconnect(this);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
bool BuildingHitlineInfo2SituationMap::mapObjectsClicked(const QVector<UniqueMapId> &uniqueMapIds)
{
if (!m_bldBuildingInfoIfc)
return false;
const QVector<qint32> &hitLineIds = uniqueMapIds2SimIds(uniqueMapIds);
if (hitLineIds.isEmpty())
return true;
m_bldBuildingInfoIfc->showHitLineInfoWindow(hitLineIds); // HitlineIds != buildingIds
return true;
}
QString BuildingHitlineInfo2SituationMap::chargeTypeIdentifier(const int32_t originatorChargeTypeId) const
{
if (!m_pdmHandler)
return QStringLiteral("ctId_%1").arg(originatorChargeTypeId);
QString chargeTypeString = m_pdmHandler->trChargeTypeShortName(originatorChargeTypeId);
if (chargeTypeString.isEmpty())
return QStringLiteral("ctId_%1").arg(originatorChargeTypeId);
return chargeTypeString;
}
bool BuildingHitlineInfo2SituationMap::unifiedMapObjectData(UniqueMapId uniqueMapId, UnifiedMapObjectData &umodOut) const
{
if (!m_bldDtc)
return false;
int32_t simIdOut = -1;
if (!this->uniqueMapId2SimId(uniqueMapId, simIdOut))
return false;
umodOut = UnifiedMapObjectData();
RefPointer<MAP_T> mapObj = this->getMapObjectOfUniqueMapId(uniqueMapId);
if (mapObj.valid())
umodOut.m_image = mapObj->previewImage();
const auto cb = [this, simIdOut, &umodOut](const Sim2SituationMap::DDS_T & ddsData) -> bool
{
if (ddsData.id() == simIdOut)
{
umodOut.m_partyId = ddsData.originatorPartyId();
const int32_t originatorChargeTypeId = ddsData.chargeTypeId();
umodOut.m_description1 = chargeTypeIdentifier(originatorChargeTypeId);
return true; // break loop
}
return false;
};
// sonst kann sich der compiler nicht zwischen bool und void entscheiden... !?
std::function<bool(const Sim2SituationMap::DDS_T &ddsData)> cb1 = cb;
return m_bldDtc->buildingHitLineInfos(cb1);
}
bool BuildingHitlineInfo2SituationMap::onBuildingHitLineInfoChanged(const Sim2SituationMap::DDS_T &ddsData,
DataModification modType)
{
const bool bIsValid = !isElapsed(ddsData);
if (bIsValid)
updateDdsDataContainer(ddsData, modType); // helpfull for FilterManagement/onSymbolAppearanceSettingsChanged
return handleChanged(ddsData, modType);
}
void BuildingHitlineInfo2SituationMap::onMainStructureElementChanged(const InfrastructureManagement::MainStructureElement &mse, DataModification modType)
{
switch (modType)
{
case DataModification::eAdded:
case DataModification::eModified:
{
if (mse.modelId() != 0 && m_ismDtc->isElementAssignedToExercise(mse, m_exerciseId))
{
DEBUG_LOG(m_logger) << "m_buildingHeight.insert id=" << mse.id() << " z=" << mse.geoPosition().z();
m_buildingHeight.insert(mse.id(), mse.geoPosition().z());
}
break;
}
case DataModification::eRemoved:
m_buildingHeight.remove(mse.id());
break;
}
}
bool isValidPos(const Core::GeoPosition &pos)
{
if (qFuzzyIsNull(pos.lat()) && qFuzzyIsNull(pos.lon()))
return false;
return !std::isnan(pos.lat()) && !std::isnan(pos.lon());
}
bool BuildingHitlineInfo2SituationMap::isElapsed(const Sim2SituationMap::DDS_T &data) const
{
// true -> hide
// false -> show
DEBUG_LOG(m_logger) << " isElapsed";
// 2024-09: N.Thoden
// Some hitlines were starting at 0.0.
// After densify the line hat ~500000 vertices.
// Try to avoid them:
{
const Core::GeoPosition &startGeoPos = data.originatorPos();
if (!isValidPos(startGeoPos))
return true;
const Core::GeoPosition &endGeoPos = data.buildingPos();
if (!isValidPos(endGeoPos))
return true;
}
// GUEZE-2861 says we have to create LTD this way again
//#########################################################
// GUEZE-2550:
// No LTD is created this way...
// if (m_pdmHandler->isLTDChargeType(data.chargeTypeId()))
// return true;
//#########################################################
return false;
}
bool BuildingHitlineInfo2SituationMap::updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj)
{
const qint32 hitlineId = ddsData.id();
TRACE_LOG(m_logger) << LOGFUNCTION << " START" << " id=" << hitlineId;
// mapObj->setPickable(true); // default: pickable == true
mapObj->setVisibility(SituationMap::ObjectAppearance::Tactical, false);
mapObj->rLineStyle().setLineWidth(3); // will influence LineWith and ArrowSize
//Line Style
LineStyle ls = mapObj->lineStyle();
const SpecialChargeType sct = m_pdmHandler->isSpecialChargeType(ddsData.chargeTypeId());
switch (sct)
{
case SpecialChargeType::LRF:
ls.setLinePattern(LinePattern::Dot);
break;
case SpecialChargeType::LTD:
ls.setLinePattern(LinePattern::Solid);
break;
case SpecialChargeType::NoneSpecial:
default:
ls.setLinePattern(LinePattern::Dash);
} // switch
mapObj->setLineStyle(ls);
// PartyId:
mapObj->setPartyId(ddsData.originatorPartyId());
// Identifier
const int32_t originatorChargeTypeId = ddsData.chargeTypeId();
mapObj->setIdentifier(chargeTypeIdentifier(originatorChargeTypeId));
// setStartAndEndPoint
const Core::GeoPosition &startGeoPos = ddsData.originatorPos();
const Core::GeoPosition &endGeoPos = ddsData.buildingPos();
int bldgId = ddsData.buildingId(); // bldgId == mseId
double buildingHeight = m_buildingHeight.value(bldgId, 0); // default == 0;
mapObj->setStartAndEndPoint(Point3D(startGeoPos.lon(), startGeoPos.lat(), startGeoPos.z()),
Point3D(endGeoPos.lon(), endGeoPos.lat(), endGeoPos.z()-buildingHeight));
// FilterManagement:
handleSymbolAppearanceSettings(mapObj, ddsData);
TRACE_LOG(m_logger) << LOGFUNCTION << " END" << " id=" << hitlineId;
return true;
}
void BuildingHitlineInfo2SituationMap::onSymbolAppearanceSettingsChanged(FilterManagement::SymbolAppearanceSettings::Part part)
{
if ((part != FilterManagement::SymbolAppearanceSettings::Part::All) &&
(part != FilterManagement::SymbolAppearanceSettings::Part::Symbol))
return;
// Part::All || Part::Symbol
const bool relevant = symbolAppearanceSettingsChangesAreRelevant(m_symbolAppearanceSettings->settings());
m_currentSymbolSettings = m_symbolAppearanceSettings->settings();
if (!relevant)
return;
handleSymbolAppearanceSettings();
}
bool BuildingHitlineInfo2SituationMap::symbolAppearanceSettingsChangesAreRelevant(const FilterManagement::SymbolAppearanceSettings::Settings &newSas) const
{
return qFuzzyCompare(m_currentSymbolSettings.symbolSettings.symbolScale, newSas.symbolSettings.symbolScale) ||
(m_currentSymbolSettings.symbolSettings.symbolPartyAppearance != newSas.symbolSettings.symbolPartyAppearance) ||
(m_currentSymbolSettings.symbolSettings.hitLineDisplayLengthMSec != newSas.symbolSettings.hitLineDisplayLengthMSec) ||
(m_currentSymbolSettings.symbolSettings.lrfLineDisplayLengthMSec != newSas.symbolSettings.lrfLineDisplayLengthMSec) ||
(m_currentSymbolSettings.symbolSettings.ltdLineDisplayLengthMSec != newSas.symbolSettings.ltdLineDisplayLengthMSec);
}
void BuildingHitlineInfo2SituationMap::handleSymbolAppearanceSettings()
{
for (const Buildings::BuildingHitLineInfo &buildingHitline : qAsConst(m_ddsDataContainer))
{
const UniqueMapId uniqueMapId = m_simId2UniqueMapId.value(buildingHitline.id(), INVALID_MAP_ID);
if (uniqueMapId == INVALID_MAP_ID)
{
WARNING_LOG(m_logger) << LOGFUNCTION << "Found a buildingHitline which is in internal map but has no map object...: " << buildingHitline.id();
continue;
}
RefPointer<MAP_T> mapObj = m_objFac.get<MAP_T>(uniqueMapId);
if (!mapObj.valid())
continue;
handleSymbolAppearanceSettings(mapObj, buildingHitline);
if (!mapObj->updateView())
WARNING_LOG(m_logger) << LOGFUNCTION << " updateView failed,"
<< " mapObj = " << mapObj->debugInfo();
} // for
}
void BuildingHitlineInfo2SituationMap::handleSymbolAppearanceSettings(RefPointer<MAP_T> mapObj, const Sim2SituationMap::DDS_T &ddsData)
{
const FilterManagement::SymbolAppearanceSettings::Settings &filterSettings = m_symbolAppearanceSettings->settings();
mapObj->setScale(filterSettings.symbolSettings.symbolScale);
bool bUncertain = false;
const bool isVisi = isVisible(ddsData, &bUncertain);
if (bUncertain)
{
// N. Thoden, 25.09.2020
// Do NOT store mapObj at lambda! The lambda will be destroyed AFTER
// HitlineInfo2SituationMap and the ESRI map. So the RefPointer is still
// holding a MapObject. The destruction will fail due to non-existing ESRI map...
QTimer::singleShot(200, this, [this, ddsData]()
{
RefPointer<MAP_T> mapObj = getMapObjectOfSimId(ddsData.id());
if (!mapObj.valid())
return;
handleSymbolAppearanceSettings(mapObj, ddsData);
});
}
// add missing updateView()
if (mapObj->visibility() != isVisi)
{
mapObj->setVisibility(isVisi);
if (!mapObj->updateView())
WARNING_LOG(m_logger) << LOGFUNCTION << " updateView failed,"
<< " mapObj = " << mapObj->debugInfo();
}
}
bool BuildingHitlineInfo2SituationMap::isVisible(const Sim2SituationMap::DDS_T &ddsData, bool *bUncertain) const
{
return visibleBySymbolPartyAppearance(ddsData) &&
visibleByHitLineDisplayLength(m_pluginProvider->partitionTime(), ddsData) && // partitionTime() -> msec
visibleByParticipants(ddsData, bUncertain);
}
bool BuildingHitlineInfo2SituationMap::visibleBySymbolPartyAppearance(const Sim2SituationMap::DDS_T &ddsData) const
{
const FilterManagement::SymbolAppearanceSettings::Settings &filterSettings = m_symbolAppearanceSettings->settings();
const auto spa = filterSettings.symbolSettings.symbolPartyAppearance.value(ddsData.originatorPartyId());
return spa.isVisible;
}
bool BuildingHitlineInfo2SituationMap::visibleByParticipants(const Sim2SituationMap::DDS_T &ddsData, bool *bUncertain) const
{
// show hitline only if
// ddsData.originatorParticipantId() && ddsData.injuryParticipantId() are visible:
if (!m_participant2SituationMap)
return true;
bool bParticipantExists = true;
bool bRet = m_participant2SituationMap->isParticipantVisible(ddsData.originatorParticipantId(), &bParticipantExists);
if (!bParticipantExists && bUncertain)
*bUncertain = true;
return bRet;
}
bool BuildingHitlineInfo2SituationMap::visibleByHitLineDisplayLength(const qint64 newPartitionTime, const DDS_T &ddsData) const
{
qint64 displayLength = m_currentSymbolSettings.symbolSettings.hitLineDisplayLengthMSec;
const SpecialChargeType sct = m_pdmHandler->isSpecialChargeType(ddsData.chargeTypeId());
switch (sct)
{
case SpecialChargeType::LRF:
displayLength = m_currentSymbolSettings.symbolSettings.lrfLineDisplayLengthMSec;
break;
case SpecialChargeType::LTD:
displayLength = m_currentSymbolSettings.symbolSettings.ltdLineDisplayLengthMSec;
break;
case SpecialChargeType::NoneSpecial:
default:
break;
} // switch
// DEBUG_LOG(m_logger) << LOGFUNCTION
// << ", newPartitionTime = " << newPartitionTime
// << ", stateTime = " << ddsData.sampleTime()
// << ", age = " << (newPartitionTime - stateTime)
// << ", sct = " << sct
// << ", displayLength = " << displayLength;
if (displayLength < 0)
return true;
return (newPartitionTime - ddsData.sampleTime()) <= displayLength; // all msec
}
void BuildingHitlineInfo2SituationMap::onPartitionTimeChanged()
{
handleSymbolAppearanceSettings();
}
}
@@ -0,0 +1,102 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "sim_to_situation_map_tmpl.h"
#include "participant_to_map.h" // participantIsVisible
#include <Buildings/bld_dtc.h> // BuildingHitLineInfo
#include <MapObjects/hit_line.h>
#include <InfrastructureManagement/ism_dtc.h>
#include <Plugins/Buildings/bld_info_gui_plugin_interface.h>
#include <Plugins/FilterManagement/flt_data_plugin_interface.h>
#include <FilterManagement/flt_dtc.h>
#include <memory>
namespace SituationMap
{
// forward:
class PdmHandler;
class BuildingHitlineInfo2SituationMap final : public Sim2SituationMap<Buildings::BuildingHitLineInfo, SituationMap::HitLine>
, protected DdsFilterHandling<SituationMap::HitLine>
{
Q_OBJECT
using BaseClass = SituationMap::Sim2SituationMap<Buildings::BuildingHitLineInfo, SituationMap::HitLine>;
using FilterClass = DdsFilterHandling<SituationMap::HitLine>;
public:
BuildingHitlineInfo2SituationMap(PdmHandler *pdmHandler,
Participant2SituationMap *participant2SituationMap,
ObjectFactory &objFac,
const QString &layername,
int drawOrder,
const char *loggerName);
~BuildingHitlineInfo2SituationMap();
bool init(PluginProvider *pluginProvider);
bool run() override;
void stop() override;
bool mapObjectsClicked(const QVector<UniqueMapId> &uniqueMapIds) override;
bool unifiedMapObjectData(UniqueMapId uniqueMapId, UnifiedMapObjectData &umodOut) const override;
QString chargeTypeIdentifier(const int32_t originatorChargeTypeId) const;
protected Q_SLOTS:
bool onBuildingHitLineInfoChanged(const Sim2SituationMap::DDS_T &ddsData, DataModification modType = DataModification::eAdded);
void onMainStructureElementChanged(const InfrastructureManagement::MainStructureElement &mse, DataModification modType);
protected:
bool isElapsed(const Sim2SituationMap::DDS_T &data) const override;
bool isVisible(const Sim2SituationMap::DDS_T &ddsData, bool *bUncertain) const;
bool visibleBySymbolPartyAppearance(const Sim2SituationMap::DDS_T &ddsData) const;
bool visibleByParticipants(const Sim2SituationMap::DDS_T &ddsData, bool *bUncertain) const;
bool visibleByHitLineDisplayLength(const qint64 newPartitionTime, const Sim2SituationMap::DDS_T &ddsData) const;
void onPartitionTimeChanged();
int32_t getSimId(const Sim2SituationMap::DDS_T &ddsData) const override;
bool updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj) override;
void onSymbolAppearanceSettingsChanged(FilterManagement::SymbolAppearanceSettings::Part part) override;
bool symbolAppearanceSettingsChangesAreRelevant(const FilterManagement::SymbolAppearanceSettings::Settings &newSas) const override;
void handleSymbolAppearanceSettings(RefPointer<MAP_T> &mapObj) override
{
if (!mapObj.valid())
return;
const int simId = m_uniqueMapId2SimId.value(mapObj->uniqueMapId());
handleSymbolAppearanceSettings(mapObj, m_ddsDataContainer.value(simId));
}
void handleSymbolAppearanceSettings();
void handleSymbolAppearanceSettings(RefPointer<MAP_T> mapObj, const Sim2SituationMap::DDS_T &ddsData);
private:
PluginProvider *m_pluginProvider = nullptr;
std::shared_ptr<Buildings::Interface::Dtc> m_bldDtc;
std::shared_ptr<Buildings::ForeignInfoGuiInterface> m_bldBuildingInfoIfc;
std::shared_ptr<InfrastructureManagement::Interface::Dtc> m_ismDtc;
PdmHandler *m_pdmHandler = nullptr;
QPointer<Participant2SituationMap> m_participant2SituationMap;
int m_exerciseId{-1};
QHash < int32_t, double > m_buildingHeight; // Key = BuildingId, Value z-value from geoPosition of the building
};
} // namespace
@@ -0,0 +1,428 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
// Own
#include "buildings_to_map.h"
#include <Map/object_factory.h>
#include <LtsCoordTrans/lts_coord_trans.h>
#include <MathUtils/simple_helper.h>
#include <Common/PluginInterfaces/gui_plugin_interface.h> // for method "getForeignGuiInterface"
#include <Plugins/Buildings/bld_info_gui_plugin_interface.h> // for Buildings::ForeignInfoGuiInterface
#include <ProjectDataManagement/pdm_to_string.h>
#include <InfrastructureManagement/ism_resource_management_gui_plugin_interface.h>
// Qt
#include <QPolygonF>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonParseError>
namespace SituationMap
{
int32_t Building2SituationMap::getSimId(const Sim2SituationMap::DDS_T &ddsData) const
{
return ddsData.id();
}
bool Building2SituationMap::init(PluginProvider *pluginProvider, bool enableDamageVisualization)
{
if (!pluginProvider ||
!pluginProvider->ismDtc())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no pluginProvider";
return false;
}
m_enableDamageVisualization = enableDamageVisualization;
m_pluginProvider = pluginProvider;
m_ismDtc = pluginProvider->ismDtc();
// optional
m_ismGuiIfc = pluginProvider->ismGuiIfc();
m_bldDtc = pluginProvider->bldDtc();
m_bldInfoIfc = pluginProvider->bldInfoIfc();
// FilterManagement:
FilterClass::init(m_pluginProvider);
return true;
}
bool Building2SituationMap::run()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (!m_ismDtc)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no dtc";
return false;
}
m_mseIdWithoutValidFootprint.clear();
// mainStructureElement
connect(m_ismDtc.get(), &InfrastructureManagement::Interface::Dtc::mainFootprintChanged,
this, &Building2SituationMap::onMainFootprintChanged);
// mainStructureElement
connect(m_ismDtc.get(), &InfrastructureManagement::Interface::Dtc::mainStructureElementChanged,
this, &Building2SituationMap::onMainStructureElementChanged);
// get:
m_ismDtc->mainStructureElements([this](const InfrastructureManagement::MainStructureElement & data)
{
onMainStructureElementChanged(data, DataModification::eAdded);
});
if (m_bldDtc)
connect(m_bldDtc.get(), &Buildings::Interface::Dtc::buildingStateChanged,
this, &Building2SituationMap::onBuildingStateChanged);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
bool Building2SituationMap::isElapsed(const InfrastructureManagement::MainStructureElement &ddsData) const
{
if (BaseClass::isElapsed(ddsData))
return true;
// skip MeteoDataUnit, RadioStation because they don´t have a footprint
// avoid something like: mainFootprint with id=" << mseId << " is not sufficiant."
const InfrastructureManagement::StructureElementType::inner_enum set = ddsData.structureElementTypeId().underlying();
if ((set == InfrastructureManagement::StructureElementType_def::MeteoDataUnit) ||
(set == InfrastructureManagement::StructureElementType_def::RadioStation) ||
(set == InfrastructureManagement::StructureElementType_def::ApproachingPoint)
)
return true;
// // skip MeteoDataUnit, because they don´t have a footprint
// const auto &elements = ddsData.elements();
// if (elements.size() < 1)
// return false;
// const InfrastructureManagement::StructureElement &element = elements.at(0);
// const InfrastructureManagement::MountingPointType& mpt = element.mountingPointTypeId();
// if (mpt == InfrastructureManagement::MountingPointType_def::MeteoDataUnit)
// return true;
// return false;
const qint32 mseId = ddsData.id();
const InfrastructureManagement::MainFootprint &mainFootprint = m_ismDtc->mainFootprint(mseId);
if (mainFootprint.elements().size() < 3)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " mainFootprint with id=" << mseId << " is not sufficiant."
<< " mainFootprint.elements().size() = " << mainFootprint.elements().size();
if (!m_mseIdWithoutValidFootprint.contains(mseId))
{
INFO_LOG(m_logger) << LOGFUNCTION << " Save for future mainFootPrintChanged..."
<< " (m_mseIdWithoutValidFootprint.size()=" << m_mseIdWithoutValidFootprint.size();
m_mseIdWithoutValidFootprint.append(mseId);
}
return true;
}
return false;
}
bool Building2SituationMap::mapObjectsClicked(const QVector<UniqueMapId> &uniqueMapIds)
{
if (!m_bldInfoIfc)
return false;
const QVector<int32_t> &simIds = uniqueMapIds2SimIds(uniqueMapIds);
if (simIds.isEmpty())
return true;
// SWPÄ 2/22: buildingOutline are also visible.
// But do not open a bunch of bldgInfoWindows while selectByArea at MountingPointListDialog
// is optional so check in advance!
if (m_ismGuiIfc && m_ismGuiIfc->isInSelectionMode())
return true;
m_bldInfoIfc->showInfoWindow(simIds);
return true;
}
bool Building2SituationMap::unifiedMapObjectData(UniqueMapId uniqueMapId, UnifiedMapObjectData &umodOut) const
{
if (!m_ismDtc)
return false;
int32_t buildingId = -1;
if (!this->uniqueMapId2SimId(uniqueMapId, buildingId))
return false;
umodOut = UnifiedMapObjectData();
umodOut.m_participantData.m_typeName = tr("Building");
umodOut.m_buildingData.buildingId = buildingId;
RefPointer<MAP_T> mapObj = this->getMapObjectOfUniqueMapId(uniqueMapId);
if (mapObj.valid())
umodOut.m_image = mapObj->previewImage();
if (m_bldDtc)
{
const Buildings::BuildingState &bldgState = m_bldDtc->buildingState(buildingId);
if (bldgState.id() == buildingId)
{
umodOut.m_participantData.m_vulnerabilityState = bldgState.vulnerabilityState().underlying();
umodOut.m_participantData.m_vulnerabilityString = ProjectDataManagement::toString(bldgState.vulnerabilityState());
}
}
umodOut.m_description1 = m_ismDtc->getBuildingDisplayName(buildingId);
return true;
}
void Building2SituationMap::onMainStructureElementChanged(const InfrastructureManagement::MainStructureElement &data,
DataModification modType)
{
const bool isResourceMgr = m_pluginProvider->appId() == LtsAppDescriptor::App::ResourceManager;
bool assignedToExercise = isResourceMgr || (m_ismDtc->isElementAssignedToExercise(data, m_pluginProvider->exerciseId()));
if (modType == DataModification::eAdded && !assignedToExercise)
return;
if (modType == DataModification::eModified && !assignedToExercise)
{
/*
* Was mse assigned to this exercise but someone removed the assignment?
* If yes, remove mse from situation map by changing the request to "eRemoved".
* If no, simply ignore the assignment.
*/
const int32_t simId = getSimId(data);
if (m_simId2UniqueMapId.contains(simId))
modType = DataModification::eRemoved;
else
return;
}
handleChanged(data, modType);
}
void Building2SituationMap::onMainFootprintChanged(const InfrastructureManagement::MainFootprint &data, DataModification modType)
{
if (modType == DataModification::eRemoved)
return;
if (data.elements().size() < 3)
return;
const int32_t mseId = data.id(); // mfpId == mseId
if (m_mseIdWithoutValidFootprint.contains(mseId))
{
// try again:
const InfrastructureManagement::MainStructureElement &mseData = m_ismDtc->mainStructureElement(mseId);
if (mseData.id() == mseId)
{
m_mseIdWithoutValidFootprint.removeAll(mseId);
onMainStructureElementChanged(mseData, DataModification::eAdded);
}
}
}
void Building2SituationMap::onBuildingStateChanged(const Buildings::BuildingState &data, DataModification modType)
{
Q_UNUSED(modType);
if (!m_enableDamageVisualization)
return;
// if (modType == DataModification::eRemoved)
// return;
const int buildingId = data.id(); // simId;
auto it = m_simId2UniqueMapId.constFind(buildingId);
if (it == m_simId2UniqueMapId.constEnd())
return; // maybe not assigned to out exercise?
// retrieve mapObj
const UniqueMapId uniqueMapId = it.value();
RefPointer<Sim2SituationMap::MAP_T> mapObj = m_objFac.get<Sim2SituationMap::MAP_T>(uniqueMapId);
if (!mapObj)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " not found in objFac"
<< " simId/buildingId = " << buildingId
<< " uniqueMapId = " << uniqueMapId ;
return;
}
if (!updateBldgDamage(mapObj, buildingId))
{
ERROR_LOG(m_logger) << LOGFUNCTION << " updateBldgDamage failed, "
<< " simId/buildingId = " << buildingId
<< " uniqueMapId = " << uniqueMapId;
return;
}
if (!mapObj->updateView())
WARNING_LOG(m_logger) << LOGFUNCTION << " updateView failed,"
<< " mapObj = " << mapObj->debugInfo();
}
bool Building2SituationMap::updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
<< " id=" << ddsData.id()
<< " name=" << ddsData.name()
<< " geoPosition=" << ddsData.geoPosition()
<< " angle=" << ddsData.angle();
// typically, building are filled with gray. But the MapObjectIndicator is hard to see.
// so force a different color here:
mapObj->setForceMajorColor(Qt::black);
// show just the ObjectAppearance::Technical
mapObj->setVisibility(ObjectAppearance::Tactical, false);
const qint32 buildingId = getSimId(ddsData); // ddsData.id();
//
// retrieve absolut utm points of footprint (angle is already taken into account)
//
int zoneOut = -1;
bool isGroundLevel = false;
const QPolygonF &absUtmPositions2D = m_ismDtc->getUtmFootprintById(buildingId, zoneOut, isGroundLevel);
const Core::GeoPosition &geoPosition = ddsData.geoPosition();
const QPointF referencePointGeo(geoPosition.lon(), geoPosition.lat());
// utmPos -> geoPos
PositionCont absPositionsGeo;
absPositionsGeo.reserve(absUtmPositions2D.size());
for (const QPointF &absPosition : qAsConst(absUtmPositions2D))
{
const LtsCoordTrans::UtmCoordinate utmPos(zoneOut, absPosition.x(), absPosition.y());
const QPointF &pGeo = utmPos.geographic();
absPositionsGeo.append(Point3D::fromQPointF(pGeo));
} // for
DEBUG_LOG(m_logger) << "absPositionsGeo = " << absPositionsGeo;
mapObj->setPositions(absPositionsGeo);
// Identifier: Many buildings in a city lead to many (unreadable) identifiers -> filter flag is introduced
TextStyle ts = mapObj->textStyle();
ts.setHorizontalAlignment(HorizontalAlignment::Center);
mapObj->setTextStyle(ts);
// mapObj->setIdentifier(QString::fromStdString(ddsData.name()));
mapObj->setIdentifier(m_ismDtc->getBuildingDisplayName(ddsData));
if (m_enableDamageVisualization && m_bldDtc)
{
// set FillStyle according damage
updateBldgDamage(mapObj, buildingId);
}
// display referencePoint:
mapObj->setMarker(Point3D::fromQPointF(referencePointGeo));
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
bool Building2SituationMap::updateBldgDamage(RefPointer<MAP_T> mapObj, qint32 buildingId)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START, buildingId=" << buildingId;
if (!m_bldDtc)
return false;
if (!mapObj)
return false;
const Buildings::BuildingState &bldgState = m_bldDtc->buildingState(buildingId);
const bool bIsContaminated = !bldgState.contaminationStates().empty();
// LineStyle
LineStyle ls = mapObj->lineStyle();
if (bIsContaminated)
ls.setLineColor(Qt::yellow);
else
ls.setLineColor(Qt::black);
mapObj->setLineStyle(ls);
// FillStyle
FillStyle fs = mapObj->fillStyle();
fs.setFillPattern(FillPattern::Solid);
int damagePercent = bldgState.damagePercent();
// Not found -> assume no damage
// In case of replay destruction, do not return false
if (bldgState.id() != buildingId)
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " simId/buildingId = " << buildingId
<< " not found!! (mapObj = " << mapObj->debugInfo() << ")";
damagePercent = 0;
}
double opacity = 1.0;
if (damagePercent < 1)
opacity = 0.0;
else if (damagePercent < 20)
opacity = 0.2;
else if (damagePercent < 40)
opacity = 0.4;
else if (damagePercent < 60)
opacity = 0.6;
else if (damagePercent < 80)
opacity = 0.8;
QColor col = QColor(125, 125, 125, 125); // gray
if (opacity > 0.1)
{
col = Qt::red;
col.setAlphaF(opacity);
}
fs.setFillColor(col);
mapObj->setFillStyle(fs);
// refresh MapObjectSelectionWidget or similar:
emit mapObjectChanged(mapObj->uniqueMapId());
TRACE_LOG(m_logger) << LOGFUNCTION << " END, buildingId=" << buildingId
<< ", damagePercent=" << damagePercent
<< ", fillStyle=" << mapObj->fillStyle()
<< ", uniqueMapId=" << mapObj->uniqueMapId();
return true;
}
bool Building2SituationMap::symbolAppearanceSettingsChangesAreRelevant(const FilterManagement::SymbolAppearanceSettings::Settings &newSas) const
{
return (m_currentSymbolSettings.symbolSettings.symbolScale != newSas.symbolSettings.symbolScale) ||
(m_currentSymbolSettings.symbolSettings.showBuildingOutline != newSas.symbolSettings.showBuildingOutline) ||
(m_currentSymbolSettings.symbolSettings.showBuildingIdentifier != newSas.symbolSettings.showBuildingIdentifier);
}
void Building2SituationMap::handleSymbolAppearanceSettings(RefPointer<MAP_T> &mapObj)
{
mapObj->setScale(m_currentSymbolSettings.symbolSettings.symbolScale);
mapObj->setVisibility(m_currentSymbolSettings.symbolSettings.showBuildingOutline);
mapObj->setIdentifierVisible(m_currentSymbolSettings.symbolSettings.showBuildingIdentifier);
}
}
@@ -0,0 +1,88 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "sim_to_situation_map_tmpl.h"
#include <Plugins/InfrastructureManagement/ism_data_plugin_interface.h>
#include <Buildings/bld_dtc.h> // damage
#include <MapObjects/building_outline.h>
namespace Buildings
{
class ForeignInfoGuiInterface;
}
namespace SituationMap
{
class Building2SituationMap final : public Sim2SituationMap<InfrastructureManagement::MainStructureElement, SituationMap::BuildingOutline>
, protected DdsFilterHandling<SituationMap::BuildingOutline>
{
Q_OBJECT
using BaseClass = SituationMap::Sim2SituationMap<InfrastructureManagement::MainStructureElement, SituationMap::BuildingOutline>;
using FilterClass = DdsFilterHandling<SituationMap::BuildingOutline>;
public:
explicit Building2SituationMap(ObjectFactory &objFac,
const QString &layername,
int drawOrder,
const char *loggerName)
: BaseClass(objFac, layername, drawOrder, loggerName)
, FilterClass(loggerName, this)
{}
bool init(PluginProvider *pluginProvider, bool enableDamageVisualization);
bool run() override;
void stop() override
{
if (m_ismDtc)
m_ismDtc->disconnect(this);
if (m_bldDtc)
m_bldDtc->disconnect(this);
}
bool isElapsed(const InfrastructureManagement::MainStructureElement &ddsData) const override;
bool mapObjectsClicked(const QVector<UniqueMapId> &uniqueMapIds) override;
bool unifiedMapObjectData(UniqueMapId uniqueMapId, UnifiedMapObjectData &umodOut) const override;
protected Q_SLOTS:
void onMainStructureElementChanged(const InfrastructureManagement::MainStructureElement &data,
DataModification modType = DataModification::eAdded);
void onMainFootprintChanged(const InfrastructureManagement::MainFootprint &data,
DataModification modType = DataModification::eAdded);
void onBuildingStateChanged(const Buildings::BuildingState &data, DataModification modType);
protected:
int32_t getSimId(const Sim2SituationMap::DDS_T &ddsData) const override;
bool updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj) override;
bool updateBldgDamage(RefPointer<MAP_T> mapObj, qint32 buildingId);
bool symbolAppearanceSettingsChangesAreRelevant(const FilterManagement::SymbolAppearanceSettings::Settings &newSas) const override;
void handleSymbolAppearanceSettings(RefPointer<MAP_T> &mapObj) override;
private:
PluginProvider *m_pluginProvider = nullptr;
std::shared_ptr<InfrastructureManagement::Interface::Dtc> m_ismDtc;
std::shared_ptr<InfrastructureManagement::ForeignResourceManagementGuiInterface> m_ismGuiIfc;
std::shared_ptr<Buildings::Interface::Dtc> m_bldDtc;
std::shared_ptr<Buildings::ForeignInfoGuiInterface> m_bldInfoIfc;
bool m_enableDamageVisualization = false;
mutable QVector<int> m_mseIdWithoutValidFootprint;
};
} // namespace
@@ -0,0 +1,790 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#include "charge_effect_to_map.h"
#include "aes_to_situation_map_tmpl.h"
#include <AreaEffectSimulation/Utils/polygons.h>
#include <GuezIedManagement/gim_dtc.h>
#include <LtsCoordTrans/lts_coord_trans.h>
#include <Map/map.h>
#include <ParticipantManagement/Data/ppm_data_plugin.h>
#include <ProjectDataManagement/pdm_dtc.h>
#include <QTimer>
#define ADD_UNIQUE_MAP_ID_TO_NOTIFIY(uniqueMapId) addUniqueMapIdToNotifiy(uniqueMapId, __FILE__, __LINE__)
#ifdef LTS_DEBUG
// # define BENCHMARK
#endif // LTS_DEBUG
#ifdef BENCHMARK
#define BENCHMARK_SETUP_AND_START() \
QElapsedTimer elapsedTimer; \
elapsedTimer.start();
#define BENCHMARK_RUN
// # define BENCHMARK_UPDATE_ELEMENT
// # define BENCHMARK_ALL_TRAC
#define BENCHMARK_ALL_NOTIFIED
#else
#define BENCHMARK_SETUP_AND_START()
#endif
namespace SituationMap
{
static int s_effect3dMaxDisplayDuration = 5000; // show explosion / detonationSPHERE for 5 sec [LS-648]
ChargeEffectToMap::ChargeEffectToMap(ObjectFactory &objFac, const QString &layername, int drawOrder, const char *loggerName)
: BaseClass(objFac, layername, drawOrder, loggerName), FilterClass(loggerName, this), m_pluginProvider(nullptr), m_notifyTimer(new QTimer(this))
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
m_notifyTimer->setInterval(100);
m_notifyTimer->setSingleShot(true);
connect(m_notifyTimer, &QTimer::timeout, this, &ChargeEffectToMap::updateAllNotifiedItems);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
ChargeEffectToMap::~ChargeEffectToMap()
{
DEBUG_LOG(m_logger) << " [ChargeEffectToMap] Dtor called! ";
if (m_displayFilter)
m_displayFilter->removeChangedCallback(this);
}
bool ChargeEffectToMap::init(PluginProvider *pluginProvider)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (!pluginProvider)
return false;
m_pluginProvider = pluginProvider;
// FilterManagement:
FilterClass::init(m_pluginProvider);
auto fltAesIfc = pluginProvider->fltAesIfc();
if (fltAesIfc)
{
m_displayFilter = fltAesIfc->aesFilterForOperator(pluginProvider->operatorId(), pluginProvider->workspaceId());
if (m_displayFilter)
m_displayFilter->addChangedCallback(this);
}
onAesDisplayFilterChanged(AreaEffectSimulation::AesType_def::AtExplosionArea);
connect(m_pluginProvider, &PluginProvider::partitionTimeChanged, this, &ChargeEffectToMap::onPartitionTimeChanged, Qt::UniqueConnection);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
bool ChargeEffectToMap::run()
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " Starting to run";
this->stop();
if (!m_pluginProvider->aesDtc())
return false;
m_pluginProvider->aesDtc()->enableEffectCluster(); // aesItemFromId
m_pluginProvider->aesDtc()->enableChargeEffect();
m_pluginProvider->aesDtc()->enableTrajectoryTimeAware();
connect(m_pluginProvider->aesDtc().get(),
&AreaEffectSimulation::Interface::Dtc::chargeEffectChanged,
this,
&ChargeEffectToMap::onChargeEffectChanged,
Qt::UniqueConnection);
connect(m_pluginProvider->aesDtc().get(),
&AreaEffectSimulation::Interface::Dtc::trajectoryTimeAwareChanged,
this,
&ChargeEffectToMap::onTracjectoryChanged,
Qt::UniqueConnection);
m_pluginProvider->aesDtc()->chargeEffects([this](const AreaEffectSimulation::ChargeEffect &data) { handleChanged(data, DataModification::eAdded); });
m_pluginProvider->aesDtc()->trajectoryTimeAwares([this](const AreaEffectSimulation::TrajectoryTimeAware &data)
{ onTracjectoryChanged(data, DataModification::eAdded); });
onAesDisplayFilterChanged(AreaEffectSimulation::AesType_def::AtExplosionArea);
return true;
}
void ChargeEffectToMap::stop()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (m_pluginProvider->aesDtc())
m_pluginProvider->aesDtc()->disconnect(this);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
bool ChargeEffectToMap::mapObjectsClicked(const QVector<UniqueMapId> &uniqueMapIds)
{
if (!m_pluginProvider->aesInfoIfc())
return false;
const QVector<int32_t> &simIds = uniqueMapIds2SimIds(uniqueMapIds);
if (simIds.isEmpty())
return true;
for (int chargeEffectId : simIds)
m_pluginProvider->aesInfoIfc()->showChargeEffectInfoWindow(chargeEffectId); // TODO implement info windows
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
int ChargeEffectToMap::getPartyIdFromOriginator(const int originatorId, const int originatorType) const
{
int partyId = -1;
switch (originatorType)
{
case ProjectDataManagement::StateChangeOriginator::Participant:
{
const auto &participant = m_pluginProvider->ppmDtc()->participant(originatorId);
partyId = participant.partyId();
break;
}
case ProjectDataManagement::StateChangeOriginator::Party:
{
partyId = originatorId;
break;
}
case ProjectDataManagement::StateChangeOriginator::AreaEffectSimulation:
{
AreaEffectSimulation::AesItem aesItem;
if (m_pluginProvider->aesDtc()->aesItemFromId(originatorId, aesItem))
partyId = aesItem.partyId().get();
break;
}
case ProjectDataManagement::StateChangeOriginator::DusMine:
{
partyId = m_pluginProvider->aesDtc()->partyForDusMine(originatorId);
break;
}
case ProjectDataManagement::StateChangeOriginator::Unknown:
case ProjectDataManagement::StateChangeOriginator::ObserverController:
case ProjectDataManagement::StateChangeOriginator::Initialization:
case ProjectDataManagement::StateChangeOriginator::ExerciseControl:
{
partyId = 1; // 1 == OC
break;
}
case ProjectDataManagement::StateChangeOriginator::ImprovisedExplosiveDevice: // should not be possible atm
{
auto guezIedDtc = m_pluginProvider->gimDtc();
if (guezIedDtc)
{
const GuezIedManagement::Ied &gIed = guezIedDtc->iedForEquipmentNumber(originatorId);
if (gIed.id() > 0)
partyId = gIed.partyId();
}
break;
}
case ProjectDataManagement::StateChangeOriginator::WoundTreatmentDevice:
case ProjectDataManagement::StateChangeOriginator::MedicalTimeout:
case ProjectDataManagement::StateChangeOriginator::MaintainanceDevice:
case ProjectDataManagement::StateChangeOriginator::Sanitation:
default:
DEBUG_LOG(m_logger) << LOGFUNCTION << " originator state change for " << originatorType << " not (yet) implemented >>> "
<< ", originatorId = " << originatorId;
break;
}
return (partyId < 0) ? 0 : partyId;
}
bool ChargeEffectToMap::unifiedMapObjectData(UniqueMapId uniqueMapId, UnifiedMapObjectData &umodOut) const
{
if (!m_pluginProvider->aesDtc())
return false;
int simIdOut = -1;
if (!this->uniqueMapId2SimId(uniqueMapId, simIdOut))
return false;
umodOut = UnifiedMapObjectData();
RefPointer<MAP_T> mapObj = m_objFac.get<MAP_T>(uniqueMapId);
if (mapObj.valid())
umodOut.m_image = mapObj->previewImage();
const auto cb = [simIdOut, &umodOut](const AreaEffectSimulation::ChargeEffect &data) -> bool
{
if (data.id() == simIdOut)
{
QString desc = QStringLiteral("id: %1\time: %2");
umodOut.m_description1 = desc.arg(data.id()).arg(QDateTime::fromMSecsSinceEpoch(data.sampleTime()).toString());
return true; // break loop
}
return false;
};
std::function<bool(const AreaEffectSimulation::ChargeEffect &data)> cb1 = cb;
return m_pluginProvider->aesDtc()->chargeEffects(cb1);
}
void ChargeEffectToMap::onPartitionTimeChanged(qint64 newPartitionTime)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START, newPartitionTime=" << newPartitionTime << ", exerciseId = " << m_pluginProvider->exerciseId()
<< ", workspaceId = " << m_pluginProvider->workspaceId() << ", this=" << this;
updateAllTrajectories();
updateAllChargeEffects();
}
bool ChargeEffectToMap::updateElementImpl(const DDS_T &ddsData, RefPointer<MAP_T> mapObj)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START ";
// show just the ObjectAppearance::Technical
mapObj->setVisibility(ObjectAppearance::Tactical, false);
mapObj->setPickable(true);
mapObj->setIdentifier(QString::fromStdString(ddsData.name()));
const int partyId = getPartyIdFromOriginator(ddsData.originatorId(), ddsData.originatorTypeId().underlying());
mapObj->setPartyId(partyId);
// E01562-255_darstellung_nebel_wirkfelder
// See charge_effect_to_map.cpp and effect_cluster_to_map.cpp
// IsSmoke (Smoke == Nebel)
const bool bIsSmoke = m_pluginProvider->pdmDtc()->isSmoke(ddsData.chargeTypeId(), ddsData.igniterTypeId(), ddsData.igniterFunctionId());
if (bIsSmoke)
mapObj->forcePartyColor(Qt::darkYellow);
// Impact:
const Core::GeoPosition &impactGeoPos = ddsData.position();
const Point3D origin = LtsUtils::QPoint3D(impactGeoPos.lon(), impactGeoPos.lat(), impactGeoPos.z());
double impactRadius = m_pluginProvider->pdmDtc()->impactRadius(ddsData.chargeTypeId(), ddsData.igniterTypeId(), ddsData.igniterFunctionId()); // GUEZE-2634
if (impactRadius <= 5)
impactRadius = 5; // default value
const auto polygon = form2PosCont(AreaEffectSimulation::Polygons::circle(origin.toPointF(), impactRadius));
mapObj->setPositions(polygon);
const AreaEffectSimulation::AesEffectState effectState = ddsData.state().underlying();
mapObj->setAesState(effectState2aesState(effectState.underlying()));
// updateVisibility
updateVisibility(mapObj, ddsData);
TRACE_LOG(m_logger) << LOGFUNCTION << " END ";
return true;
}
bool ChargeEffectToMap::isElapsed(const DDS_T &data) const
{
// true -> hide
// false -> show
Q_UNUSED(data)
bool bIsElapsed = false; // TODO when should it be visible ?
return bIsElapsed;
}
int32_t ChargeEffectToMap::getSimId(const DDS_T &ddsData) const { return ddsData.id(); }
bool ChargeEffectToMap::removeElement(const int32_t simId) { return BaseClass::removeElement(simId); }
bool ChargeEffectToMap::iterateAesData(const std::function<bool(const AreaEffectSimulation::ChargeEffect &)> &cb) const
{
if (!m_pluginProvider)
return false;
return m_pluginProvider->aesDtc()->chargeEffects(cb);
}
void ChargeEffectToMap::onSymbolAppearanceSettingsChanged(FilterManagement::SymbolAppearanceSettings::Part part)
{
if ((part != FilterManagement::SymbolAppearanceSettings::Part::All) && (part != FilterManagement::SymbolAppearanceSettings::Part::Symbol))
return;
// Part::All || Part::Symbol
const bool relevant = symbolAppearanceSettingsChangesAreRelevant(m_symbolAppearanceSettings->settings());
m_currentSymbolSettings = m_symbolAppearanceSettings->settings();
if (!relevant)
return;
updateAllChargeEffects();
}
bool ChargeEffectToMap::symbolAppearanceSettingsChangesAreRelevant(const FilterManagement::SymbolAppearanceSettings::Settings &newSas) const
{
DEBUG_LOG(m_logger) << "[symbolAppearanceSettingsChangesAreRelevant] : currSas.symScale: " << m_currentSymbolSettings.symbolSettings.symbolScale
<< " newSas.symScale: " << newSas.symbolSettings.symbolScale;
return (m_currentSymbolSettings.symbolSettings.symbolScale != newSas.symbolSettings.symbolScale)
|| (m_currentSymbolSettings.symbolSettings.symbolPartyAppearance != newSas.symbolSettings.symbolPartyAppearance);
}
void ChargeEffectToMap::handleSymbolAppearanceSettings(RefPointer<MAP_T> &mapObj)
{
if (!mapObj.valid())
return;
mapObj->setScale(m_currentSymbolSettings.symbolSettings.symbolScale);
const int simId = m_uniqueMapId2SimId.value(mapObj->uniqueMapId());
const auto &data = m_pluginProvider->aesDtc()->chargeEffect(simId);
if (data.id() <= 0)
{
WARNING_LOG(m_logger) << "[handleSymbolAppearanceSettings] data id is invalid! mapObjUniqueId: " << mapObj->uniqueMapId();
return;
}
this->updateVisibility(mapObj, data);
}
void ChargeEffectToMap::updateAllChargeEffects()
{
const auto cb = [this](const Sim2SituationMap::DDS_T &data) -> bool
{
// return false -> do not stop looping over items
if (isElapsed(data))
return false;
const UniqueMapId uniqueMapId = this->m_simId2UniqueMapId.value(data.id(), INVALID_MAP_ID);
if (uniqueMapId == INVALID_MAP_ID)
{
WARNING_LOG(m_logger) << " [updateAllChargeEffects] !!! Found a ChargeEffect which is in internal map but has no map object...: data.id: " << data.id();
return false;
}
RefPointer<MAP_T> mapObj = m_objFac.get<MAP_T>(uniqueMapId);
if (!mapObj.valid())
{
WARNING_LOG(m_logger) << " [updateAllChargeEffects] !!! invalid map object...: data.id: " << data.id();
return false;
}
this->updateVisibility(mapObj, data);
return false;
};
iterateAesData(cb);
}
void ChargeEffectToMap::updateVisibility(RefPointer<MAP_T> &mapObj, const Sim2SituationMap::DDS_T &data)
{
if (!mapObj.valid())
return;
const FilterManagement::SymbolAppearanceSettings::Settings &filterSettings = m_symbolAppearanceSettings->settings();
const bool isVisi = isVisible(data);
INFO_LOG(m_logger) << " [updateVisibility]: >> data.id: " << data.id() << " is visible? " << isVisi;
if (isVisi) // if not visisible, the gtl and co are invisible due to their mainObject
{
updateGunToTargetLine_SimpleOnSurface(mapObj, data);
// [E01562-377_filter_trajectory] Especially in context of Snapshot, the Tracjectories have to be updated:
updateAllTrajectories();
updateImpacts2D3D(mapObj, data);
if (m_objFac.map() && (m_objFac.map()->mode() == Mode::Mode_3D))
updateDetonation3D(mapObj, data, isVisi); // DetonationSphere
}
mapObj->setScale(filterSettings.symbolSettings.symbolScale);
mapObj->setVisibility(isVisi);
ADD_UNIQUE_MAP_ID_TO_NOTIFIY(mapObj->uniqueMapId());
}
//
// updateGunToTargetLine_SimpleOnSurface using the MainDataTopic ChargeEffect
// Relevant if originator is a Particiant. Introduced for Moerser
//
void ChargeEffectToMap::updateGunToTargetLine_SimpleOnSurface(RefPointer<MAP_T> &mapObj, const DDS_T &data)
{
const Core::GeoPosition2D &impactPos2D = data.position();
const Point3D origin = LtsUtils::QPoint3D(impactPos2D.lon(), impactPos2D.lat(), .0);
// check if Originator is Participant
// handle Treffer linie | visibility
// GTL / Line:
// - ist für 2D und 3D
// - abhängig vom Filter 'showExplosionClusterGunToTargetLine'
// - sichtbar bis WF abgelaufen + Afterglow
bool bDisplayFilterShowGTL = true;
if (m_displayFilter)
bDisplayFilterShowGTL = m_displayFilter->showExplosionClusterGunToTargetLine();
if (bDisplayFilterShowGTL)
{
// check if Originator is Participant
Point3D originatorPos;
Point3D targetPos;
if (data.originatorTypeId() == ProjectDataManagement::StateChangeOriginator::Participant)
{
const auto &ppPos = m_pluginProvider->ppmDtc()->participantPosition(data.originatorId());
originatorPos = Point3D(ppPos.pos().lon(), ppPos.pos().lat(), ppPos.pos().z());
targetPos = origin;
}
mapObj->setGunToTargetLineSurface(originatorPos, targetPos);
}
else
{
mapObj->setGunToTargetLineSurface(Point3D(), Point3D());
}
}
bool ChargeEffectToMap::updateSingleTrajectory(const AreaEffectSimulation::TrajectoryTimeAware &traj, bool considerTime)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
// check for our type:
// [E01562-259] use originatorId, originatorTypeId (instead of aesItemId, aesTypeId)
if (traj.originatorTypeId() != ProjectDataManagement::StateChangeOriginator::ChargeEffect)
return false;
const int32_t simId = traj.originatorId(); // simId = chargeEffectId ('parent')
if (!m_simId2UniqueMapId.contains(simId))
return false;
// Filter:
bool bDisplayFilterShowTRJ = true;
if (m_displayFilter)
bDisplayFilterShowTRJ = m_displayFilter->showExplosionClusterTrajectory();
// startPoint reached?
const qint64 partitionTimeMsec = m_pluginProvider->partitionTime();
DEBUG_LOG(m_logger) << LOGFUNCTION << " START "
<< ", simId=" << simId << ", traj=" << traj << ", considerTime=" << considerTime
<< ", partitionTimeMsec - traj.trajectoryStartTime() = " << partitionTimeMsec - traj.trajectoryStartTime();
if (traj.trajectoryStartTime() > partitionTimeMsec)
return false;
// MapObj should exist:
RefPointer<MAP_T> mapObj = this->getMapObjectOfSimId(simId);
if (!mapObj.valid())
{
// is called from onPartitionTimeChanged via updateAllTracjectories()
// Maybe TrajectoryTimeAware is still published while ExplosionCLuster is already expired.
// Therefore just DEBUG_LOG
DEBUG_LOG(m_logger) << LOGFUNCTION << " getMapObjectOfSimId failed"
<< " simId=" << simId;
return false;
}
bool bHasChanged = false;
const bool moIsVisibleByFilter = true; // Todo!! isVisibleByFilter(m_ddsDataContainer.value(simId));
const int index = 0;
if (bDisplayFilterShowTRJ && moIsVisibleByFilter)
{
// maybe complete trajectory is already transfered?
// and expensive update can be skipped?
const std::vector<Core::GeoPositionRelativeTime> &geometry = traj.geometry();
const PositionCont &curPath = mapObj->trajectory(index);
if (geometry.size() > static_cast<size_t>(curPath.size()))
{
// transfer geometry:
PositionCont posCont;
posCont.reserve(geometry.size());
for (const Core::GeoPositionRelativeTime &posTime : qAsConst(geometry))
{
if (considerTime && ((traj.trajectoryStartTime() + posTime.relativeTime()) > partitionTimeMsec))
break;
posCont.append(Point3D(posTime.lon(), posTime.lat(), posTime.z()));
}
DEBUG_LOG(m_logger) << "update trajectory, simId=" << simId << ", index=" << index << ", posCont.size() " << posCont.size();
if (posCont.size() == 1)
posCont.clear();
bHasChanged = mapObj->setTrajectory(index, posCont); // empty posCont will remove according path :-)
}
}
else
{
bHasChanged = mapObj->setTrajectory(index, {}); // empty posCont will remove according path :-)
}
if (bHasChanged)
ADD_UNIQUE_MAP_ID_TO_NOTIFIY(mapObj->uniqueMapId());
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
void ChargeEffectToMap::updateAllTrajectories()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
BENCHMARK_SETUP_AND_START();
// is obj and trj visible?
// if not, we can skip:
#ifdef BENCHMARK_ALL_TRAC
FATAL_LOG(m_logger) << LOGFUNCTION << " trajectoryTimeAwares took " << elapsedTimer.elapsed() << " [ms]"
<< ", size " << m_uniqueMapIdsToUpdate.size() << ", size "
<< m_aesDtc->trajectoryTimeAwares().size()
#endif // BENCHMARK_ALL_TRAC
// avoid data copying:
auto cb
= [this](const AreaEffectSimulation::TrajectoryTimeAware &traj) { updateSingleTrajectory(traj); };
m_pluginProvider->aesDtc()->trajectoryTimeAwares(cb);
#ifdef BENCHMARK_ALL_TRAC
FATAL_LOG(m_logger) << LOGFUNCTION << " All took " << elapsedTimer.elapsed() << " [ms]"
<< ", size " << m_uniqueMapIdsToUpdate.size() << ", size "
<< m_aesDtc->trajectoryTimeAwares().size()
#endif // BENCHMARK_ALL_TRAC
// updateAllNotifiedItems();
TRACE_LOG(m_logger)
<< LOGFUNCTION << " END";
}
void ChargeEffectToMap::updateImpacts2D3D(RefPointer<MAP_T> &mapObj, const DDS_T &data)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
static QVector<AreaEffectSimulation::AesEffectState_def::type> relevantEffectStates
= {AreaEffectSimulation::AesEffectState_def::EsActivated, AreaEffectSimulation::AesEffectState_def::EsFired};
// assume the states are consistant to effectStart and duration
const bool bDisplayDueToEffectState = relevantEffectStates.contains(data.state().underlying());
if (bDisplayDueToEffectState)
{
// setImpacts, setImpactsAbsoluteHeight
const Core::GeoPosition &impactGeoPos = data.position();
const Point3D &origin = LtsUtils::QPoint3D(impactGeoPos.lon(), impactGeoPos.lat(), impactGeoPos.z());
const Core::ZReference zReference = data.zReference();
switch (zReference.underlying())
{
case Core::ZReference_def::ZrDrapedOnGround:
mapObj->setImpacts({origin}); // will be shown draped
break;
case Core::ZReference_def::ZrUndefined: // Todo: check
case Core::ZReference_def::ZrAbsolute: // Above ASL
mapObj->setImpactsAbsoluteHeight({origin}); // will be shown with SurfacePlacementMode::Absolute
break;
default:
ERROR_LOG(m_logger) << LOGFUNCTION << " ZReference not supported";
break;
} // switch
}
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
void ChargeEffectToMap::updateDetonation3D(RefPointer<MAP_T> &mapObj, const DDS_T &data, bool isChargeEffectVisible)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START ";
const int32_t simId = data.id(); // simId of ChargeEffect
const AreaEffectSimulation::AesEffectState effectState = data.state();
bool bHasChanged = false;
// Filter:
// a)
bool bDisplay = isChargeEffectVisible;
const qint64 partitionTimeMsec = m_pluginProvider->partitionTime();
// b)
if (bDisplay && m_displayFilter)
bDisplay = m_displayFilter->showExplosionClusterDetonationSphere();
// c)
// bDisplayDueToEffectState
// assume the states are consistant to effectStart and duration
static QVector<AreaEffectSimulation::AesEffectState_def::type> relevantEffectStates
= {AreaEffectSimulation::AesEffectState_def::EsActivated, AreaEffectSimulation::AesEffectState_def::EsFired, AreaEffectSimulation::AesEffectState_def::EsExpired};
bDisplay = bDisplay && relevantEffectStates.contains(effectState.underlying());
const qint64 age = partitionTimeMsec - data.effectStart() + data.effectDuration();
DEBUG_LOG(m_logger) << LOGFUNCTION << " START, simId=" << simId << ", bDisplay=" << bDisplay<<" effectState: "<<data.state()<<" age[msec]: "<<age;
if (bDisplay && age <= s_effect3dMaxDisplayDuration)
{
double impactRadius = m_pluginProvider->pdmDtc()->impactRadius(data.chargeTypeId(), data.igniterTypeId(), data.igniterFunctionId());
if (impactRadius <= 5)
impactRadius = 5; // defaultValue == 5m
const Core::GeoPosition &effectGeoPos = data.position();
const Point3D &origin = Point3D(effectGeoPos.lon(), effectGeoPos.lat(), effectGeoPos.z());
const Core::ZReference &zRef = data.zReference();
switch (zRef.underlying())
{
case Core::ZReference_def::ZrDrapedOnGround:
if (mapObj->setDetonationsDraped({origin}, std::round(impactRadius)))
bHasChanged = true;
break;
case Core::ZReference_def::ZrUndefined: // Todo: check
case Core::ZReference_def::ZrAbsolute: // Above ASL
if (mapObj->setDetonationsAbsolute({origin}, std::round(impactRadius)))
bHasChanged = true;
break;
default:
ERROR_LOG(m_logger) << LOGFUNCTION << " ZReference not supported";
} // switch
}
else
{
if (mapObj->setDetonationsDraped({}, 1))
bHasChanged = true;
if (mapObj->setDetonationsAbsolute({}, 1))
bHasChanged = true;
} // if (bDisplayFilterShowDetoSphere)
// updateView:
if (bHasChanged)
ADD_UNIQUE_MAP_ID_TO_NOTIFIY(mapObj->uniqueMapId());
TRACE_LOG(m_logger) << LOGFUNCTION << " END ";
}
bool ChargeEffectToMap::isVisible(const DDS_T &data) const
{
bool isVisible = visibleBySymbolPartyAppearance(data) && visibleByAesFilter(data);
return isVisible;
}
bool ChargeEffectToMap::visibleBySymbolPartyAppearance(const DDS_T &data) const
{
const FilterManagement::SymbolAppearanceSettings::Settings &filterSettings = m_symbolAppearanceSettings->settings();
const int partyId = getPartyIdFromOriginator(data.originatorId(), data.originatorTypeId().underlying());
const auto spa = filterSettings.symbolSettings.symbolPartyAppearance.value(partyId);
return spa.isVisible;
}
bool ChargeEffectToMap::visibleByAesFilter(const DDS_T &data) const
{
if (!m_displayFilter)
return true; // no filter -> visible
switch (data.state().underlying())
{
case AreaEffectSimulation::AesEffectState_def::EsError:
case AreaEffectSimulation::AesEffectState_def::EsUnknown:
case AreaEffectSimulation::AesEffectState_def::EsRemoved:
case AreaEffectSimulation::AesEffectState_def::EsReceived:
case AreaEffectSimulation::AesEffectState_def::EsFired:
DEBUG_LOG(m_logger) << "[visibleByAesFilter] set unvisible id: " << data.id() << ", state:" << data.state();
return false;
case AreaEffectSimulation::AesEffectState_def::EsCreated:
DEBUG_LOG(m_logger) << "[visibleByAesFilter][EsCreated] created visible: " << m_effectStateStruct.displayCreated;
return m_effectStateStruct.displayCreated;
case AreaEffectSimulation::AesEffectState_def::EsPrepared:
DEBUG_LOG(m_logger) << "[visibleByAesFilter][EsPrepared] prepared visible? " << m_effectStateStruct.displayPrepared;
return m_effectStateStruct.displayPrepared;
case AreaEffectSimulation::AesEffectState_def::EsActivated:
case AreaEffectSimulation::AesEffectState_def::EsPaused:
DEBUG_LOG(m_logger) << "[visibleByAesFilter] [active/paused] visible? " << m_effectStateStruct.displayActivated;
return m_effectStateStruct.displayActivated;
case AreaEffectSimulation::AesEffectState_def::EsExpired:
{
auto timeTriggered = data.sampleTime();
const AreaEffectSimulation::AesType t(AreaEffectSimulation::AesType::AtExplosionClusterSingleExplosions);
const auto afterGlow = m_effectStateStruct.expiredAfterglowDurationMSec;
DEBUG_LOG(m_logger) << "[visibleByAesFilter] [EsExpired] >>> partitionTime: " << m_pluginProvider->partitionTime() << " timeTriggered: " << timeTriggered
<< " afterGlow: " << afterGlow << " timeTriggered + afterGlow: " << timeTriggered + afterGlow;
return (m_pluginProvider->partitionTime() < timeTriggered + afterGlow);
}
} // switch
return true;
}
void ChargeEffectToMap::onAesDisplayFilterChanged(AreaEffectSimulation::AesType aesType)
{
DEBUG_LOG(m_logger) << "[ChargeEffectToMap] onAesDisplayFilterChanged aes Type: " << aesType;
if (!m_displayFilter
|| ((AreaEffectSimulation::AesType_def::AtExplosionCluster != aesType.underlying())
&& (AreaEffectSimulation::AesType_def::AtExplosionArea != aesType.underlying())))
return;
m_effectStateStruct = m_displayFilter->effectStateFilter(AreaEffectSimulation::AesType_def::AtExplosionArea);
// FilterManagement:
updateAllChargeEffects();
}
void ChargeEffectToMap::onChargeEffectChanged(const DDS_T &data, DataModification modType)
{
INFO_LOG(m_logger) << "[onChargeEffectChanged] >>> " << data.id() << " name: " << data.name() << " originId: " << data.originatorId()
<< " originTypeId: " << data.originatorTypeId().underlying() << " chargeTypeId: " << data.chargeTypeId() << " state: " << data.state();
this->handleChanged(data, modType);
}
bool ChargeEffectToMap::onTracjectoryChanged(const AreaEffectSimulation::TrajectoryTimeAware &data, DataModification modType)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START, modType=" << modType; // << ", traj=" << data;
Q_UNUSED(modType); // Todo: check
updateSingleTrajectory(data);
TRACE_LOG(m_logger) << LOGFUNCTION << " END, modType=" << modType; // << ", traj=" << data;
return true;
}
void ChargeEffectToMap::updateAllNotifiedItems()
{
BENCHMARK_SETUP_AND_START();
std::string localLoggerName = m_logger.getLoggerName() + ".update";
LOGGER_T logger = m_logger.getNGLLogger(localLoggerName);
INFO_LOG(logger) << LOGFUNCTION << " m_uniqueMapIdsToUpdate.size() = " << m_uniqueMapIdsToUpdate.size();
for (int uniqueMapId : qAsConst(m_uniqueMapIdsToUpdate))
{
// Still managed or removed in the meantime? (The case may occur at snapshot)
if (!m_uniqueMapId2SimId.contains(uniqueMapId))
continue;
RefPointer<MAP_T> mapObj = getMapObjectOfUniqueMapId(uniqueMapId);
if (!mapObj.valid())
continue;
if (!mapObj->updateView())
WARNING_LOG(m_logger) << LOGFUNCTION << " updateView failed for " << mapObj->debugInfo();
} // for
TRACE_LOG(m_logger) << LOGFUNCTION << " END, m_uniqueMapIdsToUpdate.size()=" << m_uniqueMapIdsToUpdate.size();
#ifdef BENCHMARK_ALL_NOTIFIED
FATAL_LOG(m_logger) << LOGFUNCTION << " took " << elapsedTimer.elapsed() << " [ms]"
<< ", size " << m_uniqueMapIdsToUpdate.size();
#endif // BENCHMARK_ALL_NOTIFIED
m_uniqueMapIdsToUpdate.clear();
}
void ChargeEffectToMap::addUniqueMapIdToNotifiy(int uniqueMapId, const char *file, int lineNo)
{
std::string localLoggerName = m_logger.getLoggerName() + ".update";
LOGGER_T logger = m_logger.getNGLLogger(localLoggerName);
if (logger.isDebugEnabled())
{
const int simId = m_uniqueMapId2SimId.value(uniqueMapId, -1);
DEBUG_LOG(logger) << "START ******* addUniqueMapIdToNotifiy: uniqueMapId = " << uniqueMapId << " (simId=" << simId << "), caller= " << file << ":" << lineNo;
}
if (uniqueMapId > 0)
m_uniqueMapIdsToUpdate.insert(uniqueMapId);
if (!m_notifyTimer->isActive())
m_notifyTimer->start();
}
} // namespace SituationMap
@@ -0,0 +1,99 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "sim_to_situation_map_tmpl.h"
#include <Plugins/AreaEffectSimulation/aes_data_plugin_interface.h>
#include <FilterManagement/flt_data_plugin_aes_display_filter.h>
#include <MapObjects/area_fire.h>
#include <QObject>
namespace SituationMap
{
class PdmHandler;
class ChargeEffectToMap final : public Sim2SituationMap<AreaEffectSimulation::ChargeEffect, SituationMap::AreaFire>
, protected FilterManagement::AesDisplayFilter::FilterChangedCallback
, protected DdsFilterHandling<SituationMap::AreaFire>
{
Q_OBJECT
using BaseClass = SituationMap::Sim2SituationMap<AreaEffectSimulation::ChargeEffect, SituationMap::AreaFire>;
using FilterClass = DdsFilterHandling<SituationMap::AreaFire>;
public:
explicit ChargeEffectToMap(ObjectFactory &objFac,
const QString &layername,
int drawOrder,
const char *loggerName);
~ChargeEffectToMap();
bool init(PluginProvider *pluginProvider);
bool run() override;
void stop() override;
bool mapObjectsClicked(const QVector<UniqueMapId> &uniqueMapIds) override;
int getPartyIdFromOriginator(const int originatorId, const int originatorType) const;
bool unifiedMapObjectData(UniqueMapId uniqueMapId, UnifiedMapObjectData &umodOut) const override;
protected:
bool updateElementImpl(const Sim2SituationMap::DDS_T &ddsData, RefPointer<MAP_T> mapObj) override;
bool isElapsed(const Sim2SituationMap::DDS_T &data) const override;
int32_t getSimId(const Sim2SituationMap::DDS_T &ddsData) const override;
bool removeElement(const int32_t simId) override;
bool iterateAesData(const std::function<bool (const AreaEffectSimulation::ChargeEffect &)> &cb) const;
void onSymbolAppearanceSettingsChanged(FilterManagement::SymbolAppearanceSettings::Part part) override;
bool symbolAppearanceSettingsChangesAreRelevant(const FilterManagement::SymbolAppearanceSettings::Settings &newSas) const override;
void handleSymbolAppearanceSettings(RefPointer<MAP_T> &mapObj) override;
void updateAllChargeEffects();
void updateVisibility(RefPointer<MAP_T> &mapObj, const DDS_T &data);
//!
//! \brief updateGunToTargetLine_SimpleOnSurface using the MainDataTopic ChargeEffect
//! Relevant if originator is a Particiant. Introduced for Moerser
//! \param mapObj
//! \param data
//!
void updateGunToTargetLine_SimpleOnSurface(RefPointer<MAP_T> &mapObj, const DDS_T &data);
bool updateSingleTrajectory(const AreaEffectSimulation::TrajectoryTimeAware &traj, bool considerTime = true);
void updateAllTrajectories();
void updateImpacts2D3D(RefPointer<MAP_T> &mapObj, const DDS_T &data);
void updateDetonation3D(RefPointer<MAP_T> &mapObj, const DDS_T &data, bool isChargeEffectVisible = true);
bool isVisible(const Sim2SituationMap::DDS_T &data) const;
bool visibleBySymbolPartyAppearance(const Sim2SituationMap::DDS_T &data) const;
bool visibleByAesFilter(const Sim2SituationMap::DDS_T &data) const;
protected Q_SLOTS:
void onAesDisplayFilterChanged(AreaEffectSimulation::AesType aesType) override;
void onChargeEffectChanged(const DDS_T &data, DataModification modType);
bool onTracjectoryChanged(const AreaEffectSimulation::TrajectoryTimeAware &data, DataModification modType);
void updateAllNotifiedItems();
void addUniqueMapIdToNotifiy(int uniqueMapId, const char *file, int lineNo);
void onPartitionTimeChanged(qint64 newPartitionTime);
protected: // attributes
PluginProvider *m_pluginProvider;
std::shared_ptr<FilterManagement::AesDisplayFilter> m_displayFilter;
FilterManagement::AesDisplayFilter::EffectStateStruct m_effectStateStruct;
QTimer *m_notifyTimer{nullptr};
QSet<int> m_uniqueMapIdsToUpdate;
};
} // namespace SituationMap
@@ -0,0 +1,79 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#include "danger_area_to_map.h"
#include <Map/object_factory.h>
namespace SituationMap
{
//------------------------------------------------------------------------------
bool DangerArea2SituationMap::run()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (!m_aesDtc)
return false;
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::dangerAreaChanged,
this, &DangerArea2SituationMap::handleChanged, Qt::UniqueConnection);
// get:
m_aesDtc->dangerAreas([this](const AreaEffectSimulation::DangerArea & data)
{
handleChanged(data, DataModification::eAdded);
});
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return BaseClass::run();
}
bool DangerArea2SituationMap::updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
// show just the ObjectAppearance::Technical
mapObj->setVisibility(ObjectAppearance::Tactical, false);
mapObj->setIdentifier(QString::fromStdString(ddsData.name()));
// [GUEZE-3110] Gefahrenbereiche sollen immer in Gelb dargestellt werden.
// if partyId is not set (like B,C agent), use default color
// if (ddsData.partyId().is_set())
// mapObj->setPartyId(ddsData.partyId().get());
mapObj->setAesState(effectState2aesState(ddsData.effectStateId().underlying()));
const int32_t simId = ddsData.id();
AreaEffectSimulation::AesItemView itemView;
if (m_aesDtc->aesItemViewFromEntityId(simId, AreaEffectSimulation::AesType::AtDangerArea, itemView))
this->updateGeometry(itemView, mapObj);
else
{
DEBUG_LOG(m_logger) << LOGFUNCTION
<< " no AesItemView (AtDangerArea) found"
<< ", simId = " << simId
<< ", provide fallBackGeometry";
// provide fallbackGeometry to avoid errorMsg like 'incorrect number of positions'
mapObj->setPositions({{0.0, 0.0, .0},
{0.0, 0.1, .0},
{0.1, 0.1, .0},
{0.1, 0.0, .0}});
// do not return here, perform stuff like updateVisibility and so on
}
updateVisibility(ddsData, mapObj);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
}
@@ -0,0 +1,47 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "aes_to_situation_map_tmpl.h"
#include <Plugins/AreaEffectSimulation/aes_data_plugin_interface.h>
#include <MapObjects/danger_area.h>
#include <QObject>
namespace SituationMap
{
class DangerArea2SituationMap;
template <>
struct Aes2SituationMapTraits<DangerArea2SituationMap>
{
using DDS_TYPE = AreaEffectSimulation::DangerArea;
using MAP_TYPE = SituationMap::DangerArea;
static const AreaEffectSimulation::AesType_def::type aesType = AreaEffectSimulation::AesType_def::AtDangerArea;
};
class DangerArea2SituationMap final : public Aes2SituationMap<DangerArea2SituationMap>
{
Q_OBJECT
public:
using BaseClass = SituationMap::Aes2SituationMap<DangerArea2SituationMap>;
using BaseClass::BaseClass;
bool run() override;
bool iterateAesData(const std::function<bool(const AreaEffectSimulation::DangerArea &data)> &cb) const
{
return m_aesDtc->dangerAreas(cb);
}
protected:
bool updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj) override;
};
} // namespace
@@ -0,0 +1,141 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#include "dus_single_mine_to_map.h"
#include <AreaEffectSimulation/Utils/polygons.h> // for mineAreaSegment
#include <AreaEffectSimulation/Utils/ddsdbconvert.h> // for mineAreaSegment
#include <LtsUtilsCore/dds_bitarray.h>
#include <SituationMap/Symbology/sidc_codec.h>
namespace SituationMap
{
//------------------------------------------------------------------------------
// class DusSingleMine2SituationMap -
// typical XY2SituationMap, supplied by DusMineStateProxy which is connected to DDS
//------------------------------------------------------------------------------
bool DusSingleMine2SituationMap::run()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::dusSingleMineChanged,
this, &DusSingleMine2SituationMap::handleChanged, Qt::UniqueConnection);
// get:
m_aesDtc->dusSingleMines([this](const AreaEffectSimulation::DusSingleMine & data)
{
handleChanged(data, DataModification::eAdded);
});
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return BaseClass::run();
}
bool DusSingleMine2SituationMap::mapObjectsClicked(const QVector<UniqueMapId> &uniqueMapIds)
{
auto sp = m_aesInfoIfc.lock();
if (!sp)
return false;
const QVector<int32_t> &simIds = this->uniqueMapIds2SimIds(uniqueMapIds);
if (simIds.isEmpty())
return true;
sp->showInfoWindow(simIds, Aes2SituationMapTraits<DusSingleMine2SituationMap>::aesType); // AreaEffectSimulation::AesType_def::AtDusSingleMine);
return true;
}
bool DusSingleMine2SituationMap::unifiedMapObjectData(UniqueMapId uniqueMapId, UnifiedMapObjectData &umodOut) const
{
umodOut = UnifiedMapObjectData();
int32_t simIdOut = -1;
if (!this->uniqueMapId2SimId(uniqueMapId, simIdOut))
return false;
RefPointer<MAP_T> mapObj = this->getMapObjectOfUniqueMapId(uniqueMapId);
if (mapObj.valid())
umodOut.m_symDataToRender = mapObj->symbolDataToRender();
const std::function<bool(const AreaEffectSimulation::DusSingleMine &data)> cb = [simIdOut, &umodOut](const AreaEffectSimulation::DusSingleMine & data) -> bool
{
if (data.id() == simIdOut)
{
// umodOut.m_description1 = QString::number(data.id());
umodOut.m_description2 = QString::number(data.mineId());
return true; // break loop
}
return false;
};
return m_aesDtc->dusSingleMines(cb);
}
bool DusSingleMine2SituationMap::updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
// show just the ObjectAppearance::Technical
mapObj->setVisibility(ObjectAppearance::Tactical, false);
// const int32_t simId = ddsData.id();
// SIDC:
SymbolData symData;
symData.sidc = AdvancedSymbology::SidcCodec::encodeComplete(mapObj->symbologyType(), "10011500002103000000"); // 10011500002103000000 - ANTITANK MINE
symData.color = Qt::yellow;
symData.size = 1.0;
mapObj->setSymbol(symData);
// // State (display as injury)
// SituationMap::Injury injury = SituationMap::Injury::NoInjury;
// if (ddsData.triggered())
// injury = SituationMap::Injury::TotalKill;
// mapObj->setInjury(injury, QColor(Qt::black));
// Position:
mapObj->setOrigin(Point3D(ddsData.position().lon(), ddsData.position().lat(), .0));
// // show id as string:
// mapObj->setTextModifier(Participant::TextModifier::T_UniqueDesignation, QString::number(simId));
// show mineId as string:
mapObj->setTextModifier(Participant::TextModifier::M_HigherFormation, QString::number(ddsData.mineId()));
updateVisibility(ddsData, mapObj);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
bool DusSingleMine2SituationMap::symbolAppearanceSettingsChangesAreRelevant(const FilterManagement::SymbolAppearanceSettings::Settings &newSas) const
{
return (m_currentSymbolSettings.symbolSettings.symbolScale != newSas.symbolSettings.symbolScale) ||
(m_currentSymbolSettings.symbolSettings.symbolTransparency != newSas.symbolSettings.symbolTransparency)
// || (m_currentSymbolSettings.symbolSettings.symbolPartyAppearance != newSas.symbolSettings.symbolPartyAppearance)
;
}
void DusSingleMine2SituationMap::handleSymbolAppearanceSettings(RefPointer<MAP_T> &mapObj)
{
// TextModifier? No Party -> no switch....
// mapObj->setTextModifierVisibility(Participant::TextModifier::T_UniqueDesignation, l.showDesignator);
// mapObj->setTextModifierVisibility(Participant::TextModifier::M_HigherFormation, l.showTacticalIdentifier);
mapObj->setUserSymbolOpacity(1.0f - m_currentSymbolSettings.symbolSettings.symbolTransparency);
mapObj->setScale(m_currentSymbolSettings.symbolSettings.symbolScale);
}
}
@@ -0,0 +1,62 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "aes_to_situation_map_tmpl.h"
#include <Plugins/AreaEffectSimulation/aes_data_plugin_interface.h>
#include <MapObjects/participant.h>
#include <QObject>
namespace SituationMap
{
//------------------------------------------------------------------------------
// class DusSingleMine2SituationMap -
// typical XY2SituationMap, supplied by DusMineStateProxy which is connected to DDS
//------------------------------------------------------------------------------
class DusSingleMine2SituationMap;
template <>
struct Aes2SituationMapTraits<DusSingleMine2SituationMap>
{
using DDS_TYPE = AreaEffectSimulation::DusSingleMine;
using MAP_TYPE = SituationMap::Participant;
static const AreaEffectSimulation::AesType_def::type aesType = AreaEffectSimulation::AesType_def::AtDusSingleMine;
};
class DusSingleMine2SituationMap final : public Aes2SituationMap<DusSingleMine2SituationMap>
{
Q_OBJECT
public:
using BaseClass = SituationMap::Aes2SituationMap<DusSingleMine2SituationMap>;
using BaseClass::BaseClass;
bool run() override;
bool iterateAesData(const std::function<bool(const DDS_TYPE &data)> &cb) const
{
return m_aesDtc->dusSingleMines(cb);
}
bool mapObjectsClicked(const QVector<UniqueMapId> &uniqueMapIds) override;
bool unifiedMapObjectData(UniqueMapId uniqueMapId, UnifiedMapObjectData &umodOut) const override;
protected:
bool updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj) override;
bool updateSingleMines(const int simId,
RefPointer<MAP_T> mapObj);
bool symbolAppearanceSettingsChangesAreRelevant(const FilterManagement::SymbolAppearanceSettings::Settings &newSas) const override;
void handleSymbolAppearanceSettings(RefPointer<MAP_T> &mapObj) override;
protected Q_SLOTS:
};
} // namespace
@@ -0,0 +1,598 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#include "effect_cluster_to_map.h"
#include "pdm_handler.h"
#include <LtsUtilsCore/dds_bitarray.h>
#include <LtsCoordTrans/lts_coord_trans.h>
#include <AreaEffectSimulation/Utils/polygons.h>
#include <ParticipantManagement/ppm_dtc.h>
#include <Map/map.h>
#define ADD_UNIQUE_MAP_ID_TO_NOTIFIY(uniqueMapId) addUniqueMapIdToNotifiy(uniqueMapId, __FILE__, __LINE__)
#ifdef LTS_DEBUG
//# define BENCHMARK
#endif // LTS_DEBUG
#ifdef BENCHMARK
# define BENCHMARK_SETUP_AND_START() QElapsedTimer elapsedTimer; elapsedTimer.start();
# define BENCHMARK_RUN
//# define BENCHMARK_UPDATE_ELEMENT
//# define BENCHMARK_ALL_TRAC
# define BENCHMARK_ALL_NOTIFIED
#else
# define BENCHMARK_SETUP_AND_START()
#endif
namespace SituationMap
{
EffectCluster2SituationMap::EffectCluster2SituationMap(PdmHandler *pdmHandler, ObjectFactory &objFac, const QString &layername, int drawOrder, const char *loggerName)
: BaseClass(objFac, layername, drawOrder, loggerName)
, m_notifyTimer(new QTimer(this))
, m_pdmHandler(pdmHandler)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
m_notifyTimer->setInterval(100);
m_notifyTimer->setSingleShot(true);
connect(m_notifyTimer, &QTimer::timeout,
this, &EffectCluster2SituationMap::updateAllNotifiedItems);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
EffectCluster2SituationMap::~EffectCluster2SituationMap()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
m_notifyTimer->stop();
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
bool EffectCluster2SituationMap::run()
{
// a delay to let the filter be set
QTimer::singleShot(1000, this, &EffectCluster2SituationMap::runDelayed);
return true;
}
bool EffectCluster2SituationMap::runDelayed()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (!m_aesDtc)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no dtc";
return false;
}
BENCHMARK_SETUP_AND_START();
// main topic:
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::effectClusterChanged,
this, &EffectCluster2SituationMap::onEffectClusterChanged, Qt::UniqueConnection);
// aesItemViewChanged:
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::aesItemViewChanged,
this, &EffectCluster2SituationMap::onAesItemViewChanged, Qt::UniqueConnection);
// get:
m_aesDtc->effectClusters([this](const AreaEffectSimulation::EffectCluster &data)
{
onEffectClusterChanged(data, DataModification::eAdded);
});
#ifdef BENCHMARK_RUN
FATAL_LOG(m_logger) << LOGFUNCTION << " EffectClusters took " << elapsedTimer.elapsed() << " [ms]"
<< ", size " << m_simId2UniqueMapId.size();
#endif // BENCHMARK_RUN
#ifdef BENCHMARK_RUN
FATAL_LOG(m_logger) << LOGFUNCTION << " trajectoryTimeAwares took " << elapsedTimer.elapsed() << " [ms]"
<< ", size " << m_simId2UniqueMapId.size();
#endif // BENCHMARK_RUN
#ifdef BENCHMARK_RUN
FATAL_LOG(m_logger) << LOGFUNCTION << " all took " << elapsedTimer.elapsed() << " [ms]"
<< ", size " << m_simId2UniqueMapId.size();
#endif // BENCHMARK_RUN
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return BaseClass::run();
}
void EffectCluster2SituationMap::stop()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
m_notifyTimer->stop();
if (m_aesDtc)
m_aesDtc->disconnect(this);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
bool EffectCluster2SituationMap::updateVisibility(const Aes2SituationMap::DDS_TYPE &ddsData, RefPointer<Aes2SituationMap::MAP_TYPE> mapObj)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START, simId=" << getSimId(ddsData);
if (!BaseClass::updateVisibility(ddsData, mapObj))
{
ERROR_LOG(m_logger) << LOGFUNCTION << " BaseClass::updateVisibility failed, simId=" << getSimId(ddsData);
return false;
}
const int32_t simId = ddsData.id();
const AreaEffectSimulation::AesEffectState effectState = ddsData.effectStateId().underlying();
bool bIsMode3D = false;
if (m_objFac.map() && (m_objFac.map()->mode() == Mode::Mode_3D))
bIsMode3D = true;
// optional component 1)
// GunToTargetLine:
// GUEZE-2271: Geplante Flugkurve Bei Auslösung ausgeblenden:
{
// [GUEZE-2271]
// GTL / Line:
// - ist für 2D und 3D
// - abhängig vom Filter 'showEffectClusterGunToTargetLine'
// - sichtbar bis WF abgelaufen + Afterglow
// GFK / Trajectory:
// - ist nur für 3D
// - abhängig vom Filter 'showEffectClusterGunToTargetLine'
// - sichtbar bis WF aktiv
// determine visibility:
bool bDisplayFilterShowGTL = true;
if (m_displayFilter)
bDisplayFilterShowGTL = m_displayFilter->showExplosionClusterGunToTargetLine();
const bool bDisplayFilterShowGFK = bDisplayFilterShowGTL && bIsMode3D /*&&
((effectState.underlying() != AreaEffectSimulation::AesEffectState_def::EsActivated) &&
(effectState.underlying() != AreaEffectSimulation::AesEffectState_def::EsExpired))*/; // Jira [LS-647] gefordert dauerhaft sichtbar
// retrieve form/geometry if required:
// if aesItemViewFromEntityId fails (item not found), the itemViewGunToTargetLine stays empty
AreaEffectSimulation::AesItemView itemViewGunToTargetLine;
const std::vector<Core::GeoPosition>& form = itemViewGunToTargetLine.form(); // ref will be updated, if org changes
if (bDisplayFilterShowGTL || bDisplayFilterShowGFK)
m_aesDtc->aesItemViewFromEntityId(simId, AreaEffectSimulation::AesType::AtEffectClusterGunToTargetLine, itemViewGunToTargetLine);
// evaluate
if (bDisplayFilterShowGTL && (form.size() >= 2))
mapObj->setGunToTargetLineSurface(Point3D(form.front().lon(), form.front().lat(), 0.0),
Point3D(form.back().lon() , form.back().lat() , 0.0));
else
mapObj->setGunToTargetLineSurface(Point3D(), Point3D());
// GFK:
if (bIsMode3D)
{
if (bDisplayFilterShowGFK)
{
// transfer 'preview' trajectory
PositionCont gunToTargetPath;
gunToTargetPath.reserve(static_cast<int>(form.size()));
for (const Core::GeoPosition& item : qAsConst(form))
gunToTargetPath.append(Point3D(item.lon(), item.lat(), item.z()));
mapObj->setGunToTargetTrajectory3D(gunToTargetPath);
} else {
mapObj->setGunToTargetTrajectory3D({});
}
} // if (bIsMode3D)
}
// optional component 2) MeanHitPoints / MHPs: display as scheduled impacts:
{
bool bDisplayFilterShowMHP = true;
if (m_displayFilter)
bDisplayFilterShowMHP = m_displayFilter->showExplosionClusterMeanHitPoint(); //same es ExC
PositionCont mhps;
mhps.reserve(static_cast<int>(ddsData.effectors().size()));
for (const auto &effector : qAsConst(ddsData.effectors()))
{
const Core::GeoPosition &mhpPos = effector.mhpPosition();
mhps.append(Point3D(mhpPos.lon(), mhpPos.lat(), mhpPos.z())); // lon, lat, z <=> x, y, z
}
if (bDisplayFilterShowMHP)
{
// E01562-255_darstellung_nebel_wirkfelder
// See charge_effect_to_map.cpp and effect_cluster_to_map.cpp
// IsSmoke (Smoke == Nebel)
QColor impactsColor;
const auto &chargeStruct = ddsData.chargeStruct();
const bool bIsSmoke = m_pluginProvider->pdmDtc()->isSmoke(chargeStruct.chargeTypeId(), chargeStruct.igniterTypeId(), chargeStruct.igniterFunctionId());
if (bIsSmoke)
impactsColor = Qt::darkYellow;
mapObj->setScheduledImpacts(mhps, impactsColor);
}
else
{
mapObj->setScheduledImpacts({});
}
}
ADD_UNIQUE_MAP_ID_TO_NOTIFIY(mapObj->uniqueMapId());
return true;
}
bool EffectCluster2SituationMap::updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
BENCHMARK_SETUP_AND_START();
const int32_t simId = ddsData.id();
// show just the ObjectAppearance::Technical
mapObj->setVisibility(ObjectAppearance::Tactical, false);
mapObj->setIdentifier(QString::fromStdString(ddsData.name()));
// Todo: Check what to insert if unset?
if (ddsData.partyId().is_set())
mapObj->setPartyId(ddsData.partyId().get());
const AreaEffectSimulation::AesEffectState effectState = ddsData.effectStateId().underlying();
mapObj->setAesState(effectState2aesState(effectState));
// has object an error? visualize by LinePattern
LineStyle ls = mapObj->lineStyle();
ls.setLinePattern(LinePattern::Solid);
mapObj->setLineStyle(ls);
#ifdef BENCHMARK_UPDATE_ELEMENT
FATAL_LOG(m_logger) << LOGFUNCTION << " part1 took " << elapsedTimer.elapsed() << " [ms]"
<< ", size " << m_simId2UniqueMapId.size();
#endif // BENCHMARK_UPDATE_ELEMENT
// 1st AesItemView for boundary:
AreaEffectSimulation::AesItemView itemView;
if (m_aesDtc->aesItemViewFromEntityId(simId, AreaEffectSimulation::AesType::AtEffectCluster, itemView))
this->updateGeometry(itemView, mapObj);
else
{
DEBUG_LOG(m_logger) << LOGFUNCTION
<< " no AesItemView (AtEffectCluster) found"
<< ", simId = " << simId
<< ", provide fallBackGeometry";
// provide fallbackGeometry to avoid errorMsg like 'incorrect number of positions'
mapObj->setPositions({{0.0, 0.0, .0},
{0.0, 0.1, .0},
{0.1, 0.1, .0},
{0.1, 0.0, .0}});
// do not return here, perform stuff like updateVisibility and so on
}
#ifdef BENCHMARK_UPDATE_ELEMENT
FATAL_LOG(m_logger) << LOGFUNCTION << " aesItemViewFromEntityId took " << elapsedTimer.elapsed() << " [ms]"
<< ", size " << m_simId2UniqueMapId.size();
#endif // BENCHMARK_UPDATE_ELEMENT
// updateNonLethalArea ist executed at updateGeometry()
// No Extrusion
#ifdef BENCHMARK_UPDATE_ELEMENT
FATAL_LOG(m_logger) << LOGFUNCTION << " updateAllTracjectories took " << elapsedTimer.elapsed() << " [ms]"
<< ", size " << m_simId2UniqueMapId.size();
#endif // BENCHMARK_UPDATE_ELEMENT
updateVisibility(ddsData, mapObj);
#ifdef BENCHMARK_UPDATE_ELEMENT
FATAL_LOG(m_logger) << LOGFUNCTION << " all took " << elapsedTimer.elapsed() << " [ms]"
<< ", size " << m_simId2UniqueMapId.size();
#endif // BENCHMARK_UPDATE_ELEMENT
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
bool EffectCluster2SituationMap::updateGeometry(const AreaEffectSimulation::AesItemView &aesItemView, RefPointer<AreaFire> mapObj)
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " START";
// GUEZE-2586 Anpassung Karte für letaler nonletaler Bereich
// update mainGraphicalObject as well as nonLethalArea:
const int simId = aesItemView.aesItemId();
auto it = m_ddsDataContainer.find(simId);
if (it != m_ddsDataContainer.end())
updateNonLethalArea(mapObj, *it, aesItemView);
return BaseClass::updateGeometry(aesItemView, mapObj);
}
bool EffectCluster2SituationMap::removeElement(const int32_t simId)
{
return BaseClass::removeElement(simId);
}
bool EffectCluster2SituationMap::onAesItemViewChanged(const AreaEffectSimulation::AesItemView &aesItemView, DataModification modType)
{
Q_UNUSED(modType);
// check modType:F
// // if (modType == DataModification::eRemoved)
// // return false;
const int simId = aesItemView.aesItemId();
TRACE_LOG(m_logger) << LOGFUNCTION << " START, simId=" << simId;
bool success = false;
if (aesItemView.aesTypeId() == AreaEffectSimulation::AesType::AtEffectClusterGunToTargetLine)
{
// MapObj should exist:
RefPointer<MAP_T> mapObj = this->getMapObjectOfSimId(simId);
if (mapObj.valid())
updateVisibility(m_ddsDataContainer.value(simId), mapObj);
}
TRACE_LOG(m_logger) << LOGFUNCTION << " END, success=" << success;
return success;
}
bool EffectCluster2SituationMap::updateGunToTargetLineAndTrajectory(const AreaEffectSimulation::AesItemView &itemView,
RefPointer<Sim2SituationMap::MAP_T> mapObj)
{
const std::vector<Core::GeoPosition>& formRef = itemView.form();
TRACE_LOG(m_logger) << LOGFUNCTION << " START, form.size = " << formRef.size();
if (formRef.size() >= 2)
{
mapObj->setGunToTargetLineSurface(Point3D(formRef.front().lon(), formRef.front().lat(), 0.0),
Point3D(formRef.back().lon() , formRef.back().lat() , 0.0));
} else {
// empty -> remove line
mapObj->setGunToTargetLineSurface(Point3D(), Point3D());
}
if (m_objFac.map() && (m_objFac.map()->mode() == Mode::Mode_3D))
{
// transfer 'preview' trajectory
PositionCont gunToTargetPath;
gunToTargetPath.reserve(static_cast<int>(formRef.size()));
for (const Core::GeoPosition& item : qAsConst(formRef))
gunToTargetPath.append(Point3D(item.lon(), item.lat(), item.z()));
mapObj->setGunToTargetTrajectory3D(gunToTargetPath);
}
ADD_UNIQUE_MAP_ID_TO_NOTIFIY(mapObj->uniqueMapId());
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
PositionCont circleE(const QPointF &center_geo, qreal radius, int steps= 72)
{
const LtsCoordTrans::UtmCoordinate &centerUtm = LtsCoordTrans::UtmCoordinate::fromGeographic(center_geo);
PositionCont poly;
if (steps < 6)
steps = 6;
poly.reserve(steps);
for (int i = 0; i < 360; i += (360 / steps))
{
double angle = double(i) * LtsCoordTrans::deg2rad();
const QPointF &pointGeo = centerUtm.geographic(QPointF(cos(angle) * radius, sin(angle) * radius));
poly.push_back(Point3D(pointGeo.x(), pointGeo.y(), 0.0));
}
return poly;
}
bool EffectCluster2SituationMap::updateNonLethalArea(RefPointer<Sim2SituationMap::MAP_T> mapObj,
const AreaEffectSimulation::EffectCluster &EffectCluster,
const AreaEffectSimulation::AesItemView &aesItemView)
{
if (!m_pdmHandler)
return false;
if (EffectCluster.id() != aesItemView.aesItemId())
return false;
// GUEZE-2586 Anpassung Karte für letaler nonletaler Bereich
// we need
// EffectCluster for chargeTypeId
// aesItemView for real geometry (EffectCluster.area().bottomLeft is not effected be distribution);
const int chargeTypeId = EffectCluster.chargeStruct().chargeTypeId();
const ProjectDataManagement::GearClass &gc = m_pdmHandler->gearClassFromChargeTypeId(chargeTypeId);
if (gc.underlying() == ProjectDataManagement::GearClass_def::AirSupport)
{
const QVector<ProjectDataManagement::CasEffect> &casEffectsVec = m_pdmHandler->casEffects(EffectCluster.chargeStruct());
// per definition, the vector is ordered
// the first item should be the lethal one. That could be ignored, it´s the circle of MainGraphicalObject.
// But if there are two, we check the second:
if (casEffectsVec.size() >= 2)
{
const ProjectDataManagement::CasEffect &ce = casEffectsVec[1];
// Maybe check severityType here?
const double impactRadius = ce.impactRadius();
const AreaEffectSimulation::Area &areaRef = EffectCluster.area();
// const Core::GeoPosition2D &blGeo = areaRef.cornerBottomLeft();
const Core::GeoPosition2D &blGeo = aesItemView.boundingBoxBottomLeft();
const QPointF &centerGeo = AreaEffectSimulation::Polygons::bottomLeft2CenterPoint(QPointF(blGeo.lon(), blGeo.lat()),
areaRef.width(), areaRef.height(), areaRef.rotation());
updateNonLethalArea(mapObj, centerGeo, impactRadius);
}
} else {
updateNonLethalArea(mapObj); // no center, no radius -> clear/remove
}
return true;
}
// GUEZE-2586 Anpassung Karte für letaler nonletaler Bereich
bool EffectCluster2SituationMap::updateNonLethalArea(RefPointer<Sim2SituationMap::MAP_T> mapObj, const QPointF &centerGeo, double radius)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START, radius = " << radius;
if (!mapObj)
return false;
if (radius <= 0)
{
mapObj->setNonLethalArea({});
} else {
const PositionCont &nonLethalAreaPolygon = circleE(centerGeo, radius);
mapObj->setNonLethalArea(nonLethalAreaPolygon);
}
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
void EffectCluster2SituationMap::updateAllNotifiedItems()
{
BENCHMARK_SETUP_AND_START();
std::string localLoggerName = m_logger.getLoggerName() + ".update";
LOGGER_T logger = m_logger.getNGLLogger(localLoggerName);
INFO_LOG(logger) << LOGFUNCTION << " m_uniqueMapIdsToUpdate.size() = " << m_uniqueMapIdsToUpdate.size();
for (int uniqueMapId : qAsConst(m_uniqueMapIdsToUpdate))
{
// Still managed or removed in the meantime? (The case may occur at snapshot)
if (!m_uniqueMapId2SimId.contains(uniqueMapId))
continue;
RefPointer<MAP_T> mapObj = getMapObjectOfUniqueMapId(uniqueMapId);
if (!mapObj.valid())
continue;
if (!mapObj->updateView())
WARNING_LOG(m_logger) << LOGFUNCTION << " updateView failed for "<< mapObj->debugInfo();
} // for
TRACE_LOG(m_logger) << LOGFUNCTION << " END, m_uniqueMapIdsToUpdate.size()=" << m_uniqueMapIdsToUpdate.size();
#ifdef BENCHMARK_ALL_NOTIFIED
FATAL_LOG(m_logger) << LOGFUNCTION << " took " << elapsedTimer.elapsed() << " [ms]" << ", size " << m_uniqueMapIdsToUpdate.size();
#endif // BENCHMARK_ALL_NOTIFIED
m_uniqueMapIdsToUpdate.clear();
}
void EffectCluster2SituationMap::addUniqueMapIdToNotifiy(int uniqueMapId, const char *file, int lineNo)
{
std::string localLoggerName = m_logger.getLoggerName() + ".update";
LOGGER_T logger = m_logger.getNGLLogger(localLoggerName);
if (logger.isDebugEnabled())
{
const int simId = m_uniqueMapId2SimId.value(uniqueMapId, -1);
DEBUG_LOG(logger) << "START ******* addUniqueMapIdToNotifiy: uniqueMapId = " << uniqueMapId << " (simId=" << simId << "), caller= " << file << ":" << lineNo;
}
if (uniqueMapId > 0)
m_uniqueMapIdsToUpdate.insert(uniqueMapId);
if (!m_notifyTimer->isActive())
m_notifyTimer->start();
}
AreaEffectSimulation::AesType EffectCluster2SituationMap::aesTypeFromGearClassChargeType(const DDS_TYPE &data)const
{
static QMap<int, AreaEffectSimulation::AesType> s_aesTypeMap;
if (s_aesTypeMap.contains(data.chargeStruct().chargeTypeId()))
return s_aesTypeMap[data.chargeStruct().chargeTypeId()];
const ProjectDataManagement::GearClass &gc = m_pdmHandler->gearClassFromChargeTypeId(data.chargeStruct().chargeTypeId());
switch (gc.underlying())
{
case ProjectDataManagement::GearClass::AirSupport:
s_aesTypeMap[data.chargeStruct().chargeTypeId()] = AreaEffectSimulation::AesType::AtAirSupportImpact;
break;
case ProjectDataManagement::GearClass::Artillery:
case ProjectDataManagement::GearClass::Mortar:
case ProjectDataManagement::GearClass::Rocket:
s_aesTypeMap[data.chargeStruct().chargeTypeId()] = AreaEffectSimulation::AesType::AtExplosionArea;
break;
default:
return AreaEffectSimulation::AesType::AtUnknown;
}
return s_aesTypeMap[data.chargeStruct().chargeTypeId()];
}
void EffectCluster2SituationMap::onAesDisplayFilterChanged(AreaEffectSimulation::AesType aesType)
{
TRACE_LOG(m_logger) << " onAesDisplayFilterChanged, aesType =" << aesType
<< ", this " << this;
if ((AreaEffectSimulation::AesType_def::AtEffectCluster != aesType.underlying()) &&
(AreaEffectSimulation::AesType_def::AtExplosionArea != aesType.underlying()) &&
(AreaEffectSimulation::AesType_def::AtAirSupportImpact != aesType.underlying()))
return;
const auto cb = [this](const DDS_TYPE &data) -> bool
{
// return false -> do not stop looping over items
if (isElapsed(data))
return false;
this->updateVisibility(data);
return false;
};
iterateAesData(cb);
}
bool EffectCluster2SituationMap::isVisibleByFilter(const Aes2SituationMap::DDS_TYPE &data) const
{
if (!m_displayFilter)
return true; // no filter -> visible
const auto es = data.effectStart().is_set() ? data.effectStart().get() : 0;
const auto partyId = data.partyId().is_set() ? data.partyId().get() : -1;
bool isVisibleByFilter = partyId > 0 ? FilterClass::m_currentSymbolSettings.symbolSettings.symbolPartyAppearance.value(partyId).isVisible : true;
if (isVisibleByFilter)
{
AreaEffectSimulation::AesType aestype = aesTypeFromGearClassChargeType(data);
if (aestype == AreaEffectSimulation::AesType::AtUnknown)
{
WARNING_LOG(m_logger) << " Only AES TYPE explosion Cluster, AirSupportImpact, Explosion area will be displayed";
aestype = AreaEffectSimulation::AesType::AtExplosionArea;
}
isVisibleByFilter = m_displayFilter->isVisible(aestype,//AreaEffectSimulation::AesType::AtExplosionArea,
data.effectStateId(),
data.chargeStruct().chargeTypeId(),
partyId,
data.isCentral(),
es,
data.effectDuration(),
m_pluginProvider->partitionTime());
}
return isVisibleByFilter;
}
bool EffectCluster2SituationMap::onEffectClusterChanged(const AreaEffectSimulation::EffectCluster &EffectCluster, DataModification modType)
{
updateDdsDataContainer(EffectCluster, modType);
return BaseClass::handleChanged(EffectCluster, modType);
}
}
@@ -0,0 +1,92 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "aes_to_situation_map_tmpl.h"
#include <Plugins/AreaEffectSimulation/aes_data_plugin_interface.h>
#include <MapObjects/area_fire.h>
#include <QSet>
#include <QTimer>
namespace SituationMap
{
class PdmHandler;
class EffectCluster2SituationMap;
template <>
struct Aes2SituationMapTraits<EffectCluster2SituationMap>
{
using DDS_TYPE = AreaEffectSimulation::EffectCluster;
using MAP_TYPE = SituationMap::AreaFire;
static const AreaEffectSimulation::AesType_def::type aesType = AreaEffectSimulation::AesType_def::AtEffectCluster;
};
class EffectCluster2SituationMap final : public Aes2SituationMap<EffectCluster2SituationMap>
{
Q_OBJECT
public:
using BaseClass = SituationMap::Aes2SituationMap<EffectCluster2SituationMap>;
using BaseClass::BaseClass;
explicit EffectCluster2SituationMap(PdmHandler *pdmHandler,
ObjectFactory &objFac,
const QString &layername,
int drawOrder,
const char *loggerName);
virtual ~EffectCluster2SituationMap();
bool run() override;
void stop() override;
bool iterateAesData(const std::function<bool(const AreaEffectSimulation::EffectCluster &data)> &cb) const
{
return m_aesDtc->effectClusters(cb);
}
using BaseClass::updateVisibility; // hidden overloaded virtual function
bool updateVisibility(const DDS_TYPE &ddsData, RefPointer<MAP_TYPE> mapObj) override;
protected:
bool updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj) override;
bool updateGeometry(const AreaEffectSimulation::AesItemView &aesItemView,
RefPointer<SituationMap::AreaFire> mapObj) override;
bool removeElement(const int32_t simId) override;
void onAesDisplayFilterChanged(AreaEffectSimulation::AesType aesType) override;
bool isVisibleByFilter(const DDS_TYPE &data) const override;
AreaEffectSimulation::AesType aesTypeFromGearClassChargeType(const Aes2SituationMap::DDS_TYPE &data) const;
protected Q_SLOTS:
bool runDelayed();
bool onEffectClusterChanged(const AreaEffectSimulation::EffectCluster &EffectCluster, DataModification modType);
bool onAesItemViewChanged(const AreaEffectSimulation::AesItemView &aesItemView, DataModification modType);
bool updateGunToTargetLineAndTrajectory(const AreaEffectSimulation::AesItemView &itemView, RefPointer<Sim2SituationMap::MAP_T> mapObj);
bool updateNonLethalArea(RefPointer<Sim2SituationMap::MAP_T> mapObj,
const AreaEffectSimulation::EffectCluster &EffectCluster,
const AreaEffectSimulation::AesItemView &aesItemView);
bool updateNonLethalArea(RefPointer<Sim2SituationMap::MAP_T> mapObj, const QPointF &centerGeo = QPointF(), double radius = 0);
void updateAllNotifiedItems();
void addUniqueMapIdToNotifiy(int uniqueMapId, const char *file, int lineNo);
protected:
QTimer *m_notifyTimer{nullptr};
QSet<int> m_uniqueMapIdsToUpdate;
PdmHandler *m_pdmHandler{nullptr};
};
} // namespace
@@ -0,0 +1,272 @@
/**
* @RDE_HEADER@
* The EmergencyCallToMap class handles the transfer from MainStructureElement-DDS-Data to a representation on the map
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, NLSE, 2018-06-26
*/
// Own
#include "emergency_call_to_map.h"
#include <Map/object_factory.h>
#include <Map/map.h>
#include <PluginInterfaces/gui_plugin_interface.h>
#include <Common/LtsAppDescriptor/lts_app_descriptor.h>
// Qt
#include <QDateTime>
#include <QPainter>
#include <QDebug>
#include <sstream>
using namespace SituationMap;
static QImage renderEmergencySymbol(bool bExpired)
{
int size = 200;
QImage image(size, size, QImage::Format_ARGB32);
image.fill(Qt::transparent);
QPainter painter(&image);
painter.setRenderHint(QPainter::Antialiasing);
QPen pen(Qt::white);
pen.setWidth(10);
painter.setPen(pen);
if (bExpired)
painter.setBrush(QBrush(Qt::gray));
else
painter.setBrush(QBrush(Qt::red));
painter.drawEllipse(QPointF(image.rect().center()),
image.rect().width() * 0.45,
image.rect().height() * 0.45);
painter.setPen(QPen(Qt::white));
QFont font = painter.font();
font.setBold(true);
font.setPixelSize(75);
painter.setFont(font);
QPointF pos(image.width() * 0.125,
image.height() * 0.625);
painter.drawText(pos, QLatin1String("SOS"));
return image;
}
bool EmergencyCallToMap::init(PluginProvider *pluginProvider)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (!pluginProvider)
return false;
m_pluginProvider = pluginProvider;
DEBUG_LOG(m_logger) << LOGFUNCTION << " exerciseId=" << m_pluginProvider->exerciseId();
m_almDtc = m_pluginProvider->almDtc();
m_almInfoIfc = m_pluginProvider->almInfoIfc();
// FilterManagement:
FilterClass::init(m_pluginProvider);
// GUEZE-2623: SOS-Symbole im Snapshot:
const bool bIsReplay = m_pluginProvider->isReplayPartition();
const bool bIsSnapshot = m_pluginProvider->appId() == LtsAppDescriptor::App::Snapshot;
if (bIsReplay && !bIsSnapshot)
{
// just Replay...
// switch off
bool success = false;
if (m_objFac.map())
success = m_objFac.map()->layerFactory().switchEmergencyCallLayerOff();
DEBUG_LOG(m_logger) << LOGFUNCTION << ", switchEmergencyCallLayerOff _OFF_ ; success = " << success;
}
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
bool EmergencyCallToMap::run()
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " Starting to run";
this->stop();
if (m_almDtc)
{
connect(m_almDtc.get(), &AlarmManagement::Interface::Dtc::almEmergencyCallChanged,
this, &EmergencyCallToMap::handleChanged, Qt::UniqueConnection);
// get:
m_almDtc->almEmergencyCalls([this](const AlarmManagement::AlmEmergencyCall & data)
{
handleChanged(data, DataModification::eAdded);
});
}
// switchEmergencyCallLayerOn/Off (GUEZE-1711)
// GUEZE-2933 // Filtervoreinstellungen werden nicht übernommen
// // forceEmergencyCallLayerVisibility();
return true;
}
void EmergencyCallToMap::stop()
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " Stopping";
if (m_almDtc)
m_almDtc->disconnect(this);
}
bool EmergencyCallToMap::mapObjectsClicked(const QVector<UniqueMapId> &uniqueMapIds)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (!m_almInfoIfc)
return false;
const QVector<int32_t> &simIds = uniqueMapIds2SimIds(uniqueMapIds);
if (simIds.isEmpty())
return true;
m_almInfoIfc->showEmergencyCallInfoWindows(simIds);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
bool EmergencyCallToMap::unifiedMapObjectData(UniqueMapId uniqueMapId, UnifiedMapObjectData &umodOut) const
{
if (!m_almDtc)
return false;
int32_t simIdOut = -1;
if (!this->uniqueMapId2SimId(uniqueMapId, simIdOut))
return false;
umodOut = UnifiedMapObjectData();
RefPointer<MAP_T> mapObj = this->getMapObjectOfUniqueMapId(uniqueMapId);
if (mapObj.valid())
umodOut.m_image = mapObj->previewImage();
const auto cb = [ simIdOut, &umodOut](const AlarmManagement::AlmEmergencyCall & data) -> bool
{
if (data.id() == simIdOut)
{
umodOut.m_equipmentNumber = data.issi();
QString desc = QStringLiteral("id: %1\ntime: %2");
umodOut.m_description1 = desc.arg(data.id()).arg(QDateTime::fromMSecsSinceEpoch(data.sampleTime()).toString());
return true; // break loop
}
return false;
};
std::function<bool(const AlarmManagement::AlmEmergencyCall &data)> cb1 = cb;
return m_almDtc->almEmergencyCalls(cb1);
}
void EmergencyCallToMap::showExpired(bool showExpired)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START, showExpired=" << showExpired;
bool change = m_showExpired != showExpired;
if (change)
{
m_showExpired = showExpired;
run();
}
TRACE_LOG(m_logger) << LOGFUNCTION << " END, showExpired=" << showExpired;
}
bool EmergencyCallToMap::isElapsed(const Sim2SituationMap::DDS_T &data) const
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
// true -> hide
// false -> show
bool bIsValid = m_showExpired || !data.expired();
DEBUG_LOG(m_logger) << LOGFUNCTION
<< ", id: "<< data.id()
<< ", issi: "<< data.issi()
<< ", data.expired: " << data.expired()
<< ", m_showExpired: " << m_showExpired
<< " -> bIsValid=" << bIsValid;
TRACE_LOG(m_logger) << LOGFUNCTION << " END, bIsValid=" << bIsValid;
return !bIsValid;
}
int32_t EmergencyCallToMap::getSimId(const Sim2SituationMap::DDS_T &ddsData) const
{
return ddsData.id();
}
bool EmergencyCallToMap::updateElementImpl(const Sim2SituationMap::DDS_T &ddsData, RefPointer<Sim2SituationMap::MAP_T> mapObj)
{
TRACE_LOG(m_logger) << LOGFUNCTION << ", id " << ddsData.id();
mapObj->setPickable(true);
mapObj->setDrawOrder(1);
// Identifier:
mapObj->setIdentifier(QStringLiteral("SOS_%1").arg(ddsData.issi())); // issi equipmentNumber
TextStyle textStyle;
textStyle.setSize(20);
if (ddsData.expired())
textStyle.setTextColor(Qt::gray);
else
textStyle.setTextColor(Qt::red);
textStyle.setTextOutlineColor(Qt::white);
textStyle.setTextOutlineWidth(5);
mapObj->setTextStyle(textStyle);
// Position:
const Core::GeoPosition2D &geoPos = ddsData.position();
mapObj->setOrigin(Point3D(geoPos.lon(), geoPos.lat(), 0.0)); // 2024-07: EmergencyCall-Layer: SurfacePlacement:Relative
// Appearance:
mapObj->setProxyImage(renderEmergencySymbol(ddsData.expired()), QSize(50, 50));
// for better visibility at 3D activate pin/needle
mapObj->setPinEnabled(true);
forceEmergencyCallLayerVisibility();
emit emergencyCallUpdated(mapObj->identifier(), Point3D(geoPos.lon(), geoPos.lat(), 0)); // equipmentNumber contains issi
return true;
}
void EmergencyCallToMap::forceEmergencyCallLayerVisibility()
{
if (!m_pluginProvider)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " EmergencyCallLayer: failed due to missing pluginProvider!!!";
return;
}
// GUEZE-2623: SOS-Symbole im Snapshot:
const bool bIsLive = !m_pluginProvider->isReplayPartition();
// const bool bIsSnapshot = m_pluginProvider->appId() == LtsAppDescriptor::App::Snapshot;
// if (bIsLive || bIsSnapshot)
if (bIsLive)
{
// switch on
bool success = false;
if (m_objFac.map())
success = m_objFac.map()->layerFactory().switchEmergencyCallLayerOn();
DEBUG_LOG(m_logger) << LOGFUNCTION << ", switchEmergencyCallLayerOn _ON_ ; success = " << success;
}
}
@@ -0,0 +1,79 @@
/**
* @RDE_HEADER@
* The EmergencyCallToMap class handles the transfer from MainStructureElement-DDS-Data to a representation on the map
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, NLSE, 2018-06-26
*/
#pragma once
#include "sim_to_situation_map_tmpl.h"
#include <Plugins/AlarmManagement/alm_data_plugin_interface.h>
#include <Plugins/AlarmManagement/alm_info_gui_plugin_interface.h>
#include <MapObjects/geo_image.h>
namespace SituationMap
{
// AlarmManagement::AlmEmergencyCall: implemented for EmergencyCalls
// GUEZE-1711, 1709...
class EmergencyCallToMap final : public Sim2SituationMap<AlarmManagement::AlmEmergencyCall, SituationMap::GeoImage>
, protected DdsFilterHandling<SituationMap::GeoImage>
{
Q_OBJECT
using BaseClass = SituationMap::Sim2SituationMap<AlarmManagement::AlmEmergencyCall, SituationMap::GeoImage>;
using FilterClass = DdsFilterHandling<SituationMap::GeoImage>;
public:
EmergencyCallToMap(ObjectFactory &objFac,
const QString &layername,
int drawOrder,
const char *loggerName)
: BaseClass(objFac, layername, drawOrder, loggerName)
, FilterClass(loggerName, this)
, m_pluginProvider(nullptr)
{}
bool init(PluginProvider *pluginProvider);
bool run() override;
void stop() override;
bool mapObjectsClicked(const QVector<UniqueMapId> &uniqueMapIds) override;
bool unifiedMapObjectData(UniqueMapId uniqueMapId, UnifiedMapObjectData &umodOut) const override;
void showExpired(bool showExpired);
// bool unifiedMapObjectData(UniqueMapId uniqueMapId, UnifiedMapObjectData &umodOut) const override;
protected:
bool isElapsed(const Sim2SituationMap::DDS_T &data) const override;
int32_t getSimId(const Sim2SituationMap::DDS_T &ddsData) const override;
bool updateElementImpl(const DDS_T &ddsData, RefPointer<MAP_T> mapObj) override;
bool symbolAppearanceSettingsChangesAreRelevant(const FilterManagement::SymbolAppearanceSettings::Settings &newSas) const override
{
return (m_currentSymbolSettings.symbolSettings.symbolScale != newSas.symbolSettings.symbolScale);
}
void handleSymbolAppearanceSettings(RefPointer<MAP_T> &mapObj) override
{
mapObj->setScale(m_currentSymbolSettings.symbolSettings.symbolScale);
}
void forceEmergencyCallLayerVisibility();
signals:
void emergencyCallUpdated(const QString &name, const SituationMap::Point3D &geoPosition);
private: // attributes
PluginProvider *m_pluginProvider;
bool m_showExpired{false}; // switched on temporary by a dialog
std::shared_ptr<AlarmManagement::Interface::Dtc> m_almDtc;
std::shared_ptr<AlarmManagement::ForeignInfoGuiInterface> m_almInfoIfc;
}; // class EmergencyCallToMap
} // namespace SituationMap
@@ -0,0 +1,185 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#include "explosion_area_to_map.h"
#include <LtsUtilsCore/dds_bitarray.h>
namespace SituationMap
{
bool ExplosionArea2SituationMap::run()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (!m_aesDtc)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no dtc";
return false;
}
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::explosionAreaChanged,
this, &ExplosionArea2SituationMap::handleChanged, Qt::UniqueConnection);
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::triggeredImpactsChanged,
this, &ExplosionArea2SituationMap::onTriggeredImpactsChanged, Qt::UniqueConnection);
// get:
m_aesDtc->explosionAreas([this](const AreaEffectSimulation::ExplosionArea &data)
{
handleChanged(data, DataModification::eAdded);
});
m_aesDtc->triggeredImpactss([this](const AreaEffectSimulation::TriggeredImpacts &data)
{
onTriggeredImpactsChanged(data, DataModification::eAdded);
});
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return BaseClass::run();
}
bool ExplosionArea2SituationMap::updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
const int32_t simId = ddsData.id();
// show just the ObjectAppearance::Technical
mapObj->setVisibility(ObjectAppearance::Tactical, false);
mapObj->setIdentifier(QString::fromStdString(ddsData.name()));
// Todo: Check what to insert if unset?
if (ddsData.partyId().is_set())
mapObj->setPartyId(ddsData.partyId().get());
const AreaEffectSimulation::AesEffectState effectState = ddsData.effectStateId().underlying();
mapObj->setAesState(effectState2aesState(effectState));
// 1st AesItemView for boundary:
AreaEffectSimulation::AesItemView itemView;
if (m_aesDtc->aesItemViewFromEntityId(simId, AreaEffectSimulation::AesType::AtExplosionArea, itemView))
this->updateGeometry(itemView, mapObj);
else
{
DEBUG_LOG(m_logger) << LOGFUNCTION
<< " no AesItemView (AtExplosionArea) found"
<< ", simId = " << simId
<< ", provide fallBackGeometry";
// provide fallbackGeometry to avoid errorMsg like 'incorrect number of positions'
mapObj->setPositions({{0.0, 0.0, .0},
{0.0, 0.1, .0},
{0.1, 0.1, .0},
{0.1, 0.0, .0}});
// do not return here, perform stuff like updateVisibility and so on
}
// Extrusion:
//
// Required: RenderingMode::Dynamic ; SurfacePlacementMode::Relative
// Renderer: initRenderer3D_AesExtrusion ->
// assignUniqueValueRendererAesCentral3DExtrusion
// with ExtrusionMode::BaseHeight - means relative to ground
//
// if (ddsData.partyId().is_set())
// {
// // mapObj->setExtrusionColorName();
// // use partyId as Fallback
// //
// mapObj->setExtrusionHeight(20);
// }
updateVisibility(ddsData, mapObj);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
bool ExplosionArea2SituationMap::onTriggeredImpactsChanged(const AreaEffectSimulation::TriggeredImpacts &data, DataModification modType)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
// check for our type:
if (data.aesTypeId() != AreaEffectSimulation::AesType::AtExplosionAreaSingleExplosions)
return false;
if (modType == DataModification::eRemoved)
{
// Either deleted or (maybe) Expired.
return false;
}
// 2nd AesItemView for impacts:
const int32_t simId = data.aesItemId(); // simId of area ('parent')
// MapObj should exist:
RefPointer<MAP_T> mapObj = this->getMapObjectOfSimId(simId);
if (!mapObj.valid())
{
INFO_LOG(m_logger) << LOGFUNCTION
<< " getMapObjectOfSimId failed"
<< " simId=" << simId;
return false;
}
// triggeredExplosions should only be emitted, if the area is activated
// so no additional check could be skipped:
// assume item is EsActivated now:
// analyze triggeredImpacts:
AreaEffectSimulation::AesItemView itemView;
if (m_aesDtc->aesItemViewFromEntityId(simId, AreaEffectSimulation::AesType::AtExplosionAreaSingleExplosions, itemView))
{
const PositionCont &posCont = form2PosCont(itemView.form());
const auto &bitField = data.bitfield();
// false == impact in past -> visible ; true == no impact :-)
int32_t impactCount = data.impactCount();
if (impactCount != posCont.size())
{
ERROR_LOG(m_logger) << LOGFUNCTION
<< " size mismatch"
<< " impactCount=" << impactCount
<< " posCont.size()=" << posCont.size() ;
mapObj->setImpacts(posCont);
}
else
{
PositionCont posContImpacts;
posContImpacts.reserve(posCont.size());
for (int i = 0; i < posCont.size(); ++i)
{
if (!LtsUtils::BitArray::testBit(bitField, i))
posContImpacts.append(posCont.at(i));
}
// DEBUG_LOG(m_logger) << LOGFUNCTION << " posContImpacts=" << posContImpacts.size();
mapObj->setImpacts(posContImpacts);
}
if (!mapObj->updateView())
{
ERROR_LOG(m_logger) << LOGFUNCTION
<< " updateView failed";
return false;
}
} else {
ERROR_LOG(m_logger) << LOGFUNCTION
<< " no AesItemView(AtExplosionAreaSingleExplosions) found"
<< " simId=" << simId;
return false;
}
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
}
@@ -0,0 +1,51 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "aes_to_situation_map_tmpl.h"
#include <Plugins/AreaEffectSimulation/aes_data_plugin_interface.h>
#include <MapObjects/area_fire.h>
#include <QObject>
namespace SituationMap
{
class ExplosionArea2SituationMap;
template <>
struct Aes2SituationMapTraits<ExplosionArea2SituationMap>
{
using DDS_TYPE = AreaEffectSimulation::ExplosionArea;
using MAP_TYPE = SituationMap::AreaFire;
static const AreaEffectSimulation::AesType_def::type aesType = AreaEffectSimulation::AesType_def::AtExplosionArea;
};
class ExplosionArea2SituationMap final : public Aes2SituationMap<ExplosionArea2SituationMap>
{
Q_OBJECT
public:
using BaseClass = SituationMap::Aes2SituationMap<ExplosionArea2SituationMap>;
using BaseClass::BaseClass;
bool run() override;
bool iterateAesData(const std::function<bool(const AreaEffectSimulation::ExplosionArea &data)> &cb) const
{
return m_aesDtc->explosionAreas(cb);
}
protected:
bool updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj) override;
protected Q_SLOTS:
bool onTriggeredImpactsChanged(const AreaEffectSimulation::TriggeredImpacts &data, DataModification modType);
};
} // namespace
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,103 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "aes_to_situation_map_tmpl.h"
#include <Plugins/AreaEffectSimulation/aes_data_plugin_interface.h>
#include <MapObjects/area_fire.h>
#include <QSet>
#include <QTimer>
namespace SituationMap
{
class PdmHandler;
class ExplosionCluster2SituationMap;
template <>
struct Aes2SituationMapTraits<ExplosionCluster2SituationMap>
{
using DDS_TYPE = AreaEffectSimulation::ExplosionCluster;
using MAP_TYPE = SituationMap::AreaFire;
static const AreaEffectSimulation::AesType_def::type aesType = AreaEffectSimulation::AesType_def::AtExplosionCluster;
};
class ExplosionCluster2SituationMap final : public Aes2SituationMap<ExplosionCluster2SituationMap>
{
Q_OBJECT
public:
using BaseClass = SituationMap::Aes2SituationMap<ExplosionCluster2SituationMap>;
using BaseClass::BaseClass;
explicit ExplosionCluster2SituationMap(PdmHandler *pdmHandler,
ObjectFactory &objFac,
const QString &layername,
int drawOrder,
const char *loggerName);
virtual ~ExplosionCluster2SituationMap();
bool run() override;
void stop() override;
bool iterateAesData(const std::function<bool(const AreaEffectSimulation::ExplosionCluster &data)> &cb) const
{
return m_aesDtc->explosionClusters(cb);
}
using BaseClass::updateVisibility; // hidden overloaded virtual function
bool updateVisibility(const DDS_TYPE &ddsData, RefPointer<MAP_TYPE> mapObj) override;
protected:
bool updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj) override;
bool updateGeometry(const AreaEffectSimulation::AesItemView &aesItemView,
RefPointer<SituationMap::AreaFire> mapObj) override;
bool removeElement(const int32_t simId) override;
void onAesDisplayFilterChanged(AreaEffectSimulation::AesType aesType) override;
bool isVisibleByFilter(const DDS_TYPE &data) const override;
AreaEffectSimulation::AesType aesTypeFromGearClassChargeType(const Aes2SituationMap::DDS_TYPE &data) const;
protected Q_SLOTS:
bool runDelayed();
bool onExplosionClusterChanged(const AreaEffectSimulation::ExplosionCluster &explosionCluster, DataModification modType);
bool onAesItemViewChanged(const AreaEffectSimulation::AesItemView &aesItemView, DataModification modType);
bool onEffectssChanged(const AreaEffectSimulation::Effects &effects, DataModification modType);
bool updateGunToTargetLineAndTrajectory(const AreaEffectSimulation::AesItemView &itemView, RefPointer<Sim2SituationMap::MAP_T> mapObj);
bool onTracjectoryChanged(const AreaEffectSimulation::TrajectoryTimeAware &data, DataModification modType);
bool updateNonLethalArea(RefPointer<Sim2SituationMap::MAP_T> mapObj,
const AreaEffectSimulation::ExplosionCluster &explosionCluster,
const AreaEffectSimulation::AesItemView &aesItemView);
bool updateNonLethalArea(RefPointer<Sim2SituationMap::MAP_T> mapObj, const QPointF &centerGeo = QPointF(), double radius = 0);
bool updateSingleTracjectory(const AreaEffectSimulation::TrajectoryTimeAware &traj, bool considerTime = true);
bool updateAllTracjectories(int simToRestrict = -1);
bool updateEffects3DSingleItem(const AreaEffectSimulation::Effects& effects);
bool updateEffects3DAllItems(int simToRestrict = -1);
void updateAllNotifiedItems();
void addUniqueMapIdToNotifiy(int uniqueMapId, const char *file, int lineNo);
void onPartitionTimeChanged(qint64 newPartitionTime);
protected:
QTimer *m_notifyTimer{nullptr};
QSet<int> m_uniqueMapIdsToUpdate;
PdmHandler *m_pdmHandler{nullptr};
};
} // namespace
@@ -0,0 +1,95 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#include "explosion_single_to_map.h"
#include "pdm_handler.h"
#include <Map/bounding_box.h>
namespace SituationMap
{
ExplosionSingle2SituationMap::ExplosionSingle2SituationMap(PdmHandler *pdmHandler, ObjectFactory &objFac, const QString &layername, const char *loggerName)
: BaseClass(objFac, layername, loggerName)
, m_pdmHandler(pdmHandler)
{
}
bool ExplosionSingle2SituationMap::run()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (! m_aesDtc)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no dtc";
return false;
}
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::explosionSingleChanged,
this, &ExplosionSingle2SituationMap::handleChanged, Qt::UniqueConnection);
// get:
m_aesDtc->explosionSingles([this](const AreaEffectSimulation::ExplosionSingle &data)
{
handleChanged(data, DataModification::eAdded);
});
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return BaseClass::run();
}
bool ExplosionSingle2SituationMap::updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
// show just the ObjectAppearance::Technical
mapObj->setVisibility(ObjectAppearance::Tactical, false);
const int32_t simId = ddsData.id();
mapObj->setIdentifier(QString::fromStdString(ddsData.name()));
// Todo: Check What to insert if unset?
if (ddsData.partyId().is_set())
mapObj->setPartyId(ddsData.partyId().get());
mapObj->setAesState(effectState2aesState(ddsData.effectStateId().underlying()));
AreaEffectSimulation::AesItemView itemView;
if (m_aesDtc->aesItemViewFromEntityId(simId, AreaEffectSimulation::AesType::AtExplosionSingle, itemView))
this->updateGeometry(itemView, mapObj);
else
{
DEBUG_LOG(m_logger) << LOGFUNCTION
<< " no AesItemView (AtExplosionSingle) found"
<< ", simId = " << simId
<< ", provide fallBackGeometry";
// provide fallbackGeometry to avoid errorMsg like 'incorrect number of positions'
mapObj->setPositions({{0.0, 0.0, .0},
{0.0, 0.1, .0},
{0.1, 0.1, .0},
{0.1, 0.0, .0}});
// do not return here, perform stuff like updateVisibility and so on
}
// Impact:
const Core::GeoPosition2D& impactPos2D = ddsData.impactPosition();
mapObj->setImpactOrigin(Point3D(impactPos2D.lon(), impactPos2D.lat(), 0.0));
// SMArt?
if (m_pdmHandler && m_pdmHandler->isSmart(ddsData.chargeStruct()))
mapObj->setImpactType(SingleFire::ImpactType::doubleImpact);
else
mapObj->setImpactType(SingleFire::ImpactType::normalImpact);
updateVisibility(ddsData, mapObj);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
}
@@ -0,0 +1,56 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "aes_to_situation_map_tmpl.h"
#include <Plugins/AreaEffectSimulation/aes_data_plugin_interface.h>
#include <MapObjects/single_fire.h>
#include <QObject>
namespace SituationMap
{
class PdmHandler;
class ExplosionSingle2SituationMap;
template <>
struct Aes2SituationMapTraits<ExplosionSingle2SituationMap>
{
using DDS_TYPE = AreaEffectSimulation::ExplosionSingle;
using MAP_TYPE = SituationMap::SingleFire;
static const AreaEffectSimulation::AesType_def::type aesType = AreaEffectSimulation::AesType_def::AtExplosionSingle;
};
class ExplosionSingle2SituationMap final : public Aes2SituationMap<ExplosionSingle2SituationMap>
{
Q_OBJECT
public:
using BaseClass = SituationMap::Aes2SituationMap<ExplosionSingle2SituationMap>;
using BaseClass::BaseClass;
ExplosionSingle2SituationMap(PdmHandler *pdmHandler,
ObjectFactory &objFac,
const QString &layername,
const char *loggerName);
bool run() override;
bool iterateAesData(const std::function<bool(const AreaEffectSimulation::ExplosionSingle &data)> &cb) const
{
return m_aesDtc->explosionSingles(cb);
}
protected:
bool updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj) override;
PdmHandler *m_pdmHandler = nullptr;
};
} // namespace
@@ -0,0 +1,100 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#include "functional_area_to_map.h"
#include <Map/object_factory.h>
#include <Map/bounding_box.h>
namespace SituationMap
{
//------------------------------------------------------------------------------
bool FunctionalArea2SituationMap::run()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (!m_aesDtc)
return false;
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::functionalAreaChanged,
this, &FunctionalArea2SituationMap::handleChanged, Qt::UniqueConnection);
// get:
m_aesDtc->functionalAreas([this](const AreaEffectSimulation::FunctionalArea &data)
{
handleChanged(data, DataModification::eAdded);
});
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return BaseClass::run();
}
bool FunctionalArea2SituationMap::updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
// show just the ObjectAppearance::Technical
mapObj->setVisibility(ObjectAppearance::Tactical, false);
mapObj->setIdentifier(QString::fromStdString(ddsData.name()));
// if partyId is not set (like B,C agent), use default color
if (ddsData.partyId().is_set())
mapObj->setPartyId(ddsData.partyId().get());
mapObj->setAesState(effectState2aesState(ddsData.effectStateId().underlying()));
const int32_t simId = ddsData.id();
AreaEffectSimulation::AesItemView itemView;
if (m_aesDtc->aesItemViewFromEntityId(simId, AreaEffectSimulation::AesType::AtFunctionalArea, itemView))
this->updateGeometry(itemView, mapObj);
else
{
DEBUG_LOG(m_logger) << LOGFUNCTION
<< " no AesItemView (AtFunctionalArea) found"
<< ", simId = " << simId
<< ", provide fallBackGeometry";
// provide fallbackGeometry to avoid errorMsg like 'incorrect number of positions'
mapObj->setPositions({{0.0, 0.0, .0},
{0.0, 0.1, .0},
{0.1, 0.1, .0},
{0.1, 0.0, .0}});
// do not return here, perform stuff like updateVisibility and so on
}
// PointSymbol:
if (ddsData.pointSymbol().is_set())
{
const QString pointSymbolSidc = QString::fromStdString(ddsData.pointSymbol().get());
DEBUG_LOG(m_logger) << LOGFUNCTION
<< " pointSymbolSidc ='" << pointSymbolSidc << "'"
<< " simId=" << simId ;
mapObj->setPointSymbolSidc(pointSymbolSidc);
SituationMap::BoundingBox bbox;
mapObj->boundingBox(bbox);
Point3D center;
if (bbox.isValid())
{
center = bbox.center();
DEBUG_LOG(m_logger) << LOGFUNCTION
<< " center ='" << center << "'"
<< " simId=" << simId ;
}
mapObj->setPointSymbolOrigin(center);
}
updateVisibility(ddsData, mapObj);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
}
@@ -0,0 +1,51 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
// Qwn
#include "aes_to_situation_map_tmpl.h"
#include <Plugins/AreaEffectSimulation/aes_data_plugin_interface.h>
#include <MapObjects/functional_area.h>
#include <QObject>
namespace SituationMap
{
class FunctionalArea2SituationMap;
template <>
struct Aes2SituationMapTraits<FunctionalArea2SituationMap>
{
using DDS_TYPE = AreaEffectSimulation::FunctionalArea;
using MAP_TYPE = SituationMap::FunctionalArea;
static const AreaEffectSimulation::AesType_def::type aesType = AreaEffectSimulation::AesType_def::AtFunctionalArea;
};
class FunctionalArea2SituationMap final : public Aes2SituationMap<FunctionalArea2SituationMap>
{
Q_OBJECT
public:
using BaseClass = SituationMap::Aes2SituationMap<FunctionalArea2SituationMap>;
using BaseClass::BaseClass;
bool run() override;
bool iterateAesData(const std::function<bool(const AreaEffectSimulation::FunctionalArea &data)> &cb) const
{
return m_aesDtc->functionalAreas(cb);
}
protected:
bool updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj) override;
};
} // namespace
@@ -0,0 +1,75 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#include "gas_pipe_to_map.h"
#include <LtsUtilsCore/dds_bitarray.h>
namespace SituationMap
{
bool GasPipe2SituationMap::run()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (!m_aesDtc)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no dtc";
return false;
}
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::gasPipeChanged,
this, &GasPipe2SituationMap::handleChanged, Qt::UniqueConnection);
// get:
m_aesDtc->gasPipes([this](const AreaEffectSimulation::GasPipe &data)
{
handleChanged(data, DataModification::eAdded);
});
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return BaseClass::run();
}
bool GasPipe2SituationMap::updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
const int32_t simId = ddsData.id();
// set identifier:
mapObj->setIdentifier(QString::fromStdString(ddsData.name()));
if (ddsData.partyId().is_set())
mapObj->setPartyId(ddsData.partyId().get());
// AesItemView for boundary:
AreaEffectSimulation::AesItemView itemView;
if (m_aesDtc->aesItemViewFromEntityId(simId, AreaEffectSimulation::AesType::AtGasPipe, itemView))
{
this->updateGeometry(itemView, mapObj);
} else {
DEBUG_LOG(m_logger) << LOGFUNCTION
<< " no AesItemView (AtGasPipe) found"
<< ", simId = " << simId
<< ", provide fallBackGeometry";
// provide fallbackGeometry to avoid errorMsg like 'incorrect number of positions'
mapObj->setPositions({{0.0, 0.0, .0},
{0.0, 0.1, .0},
{0.1, 0.1, .0},
{0.1, 0.0, .0}});
// do not return here, perform stuff like updateVisibility and so on
}
updateVisibility(ddsData, mapObj);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
}
@@ -0,0 +1,47 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "aes_to_situation_map_tmpl.h"
#include <Plugins/AreaEffectSimulation/aes_data_plugin_interface.h>
#include <MapObjects/polygon.h>
#include <QObject>
namespace SituationMap
{
class GasPipe2SituationMap;
template <>
struct Aes2SituationMapTraits<GasPipe2SituationMap>
{
using DDS_TYPE = AreaEffectSimulation::GasPipe;
using MAP_TYPE = SituationMap::Polygon;
static const AreaEffectSimulation::AesType_def::type aesType = AreaEffectSimulation::AesType_def::AtGasPipe;
};
class GasPipe2SituationMap final : public Aes2SituationMap<GasPipe2SituationMap>
{
Q_OBJECT
public:
using BaseClass = SituationMap::Aes2SituationMap<GasPipe2SituationMap>;
using BaseClass::BaseClass;
bool run() override;
bool iterateAesData(const std::function<bool(const AreaEffectSimulation::GasPipe &data)> &cb) const
{
return m_aesDtc->gasPipes(cb);
}
protected:
bool updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj) override;
};
} // namespace
@@ -0,0 +1,476 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
// Own
#include "guez_ied_to_map.h"
#include <Map/object_factory.h>
#include <LtsCoordTrans/lts_coord_trans.h>
#include <MathUtils/simple_helper.h>
#include <PluginInterfaces/gui_plugin_interface.h>
#include <Symbology/sidc_codec.h>
#include <Symbology/sidc_builder_base.h>
#include <FilterManagement/flt_aes_plugin_interface.h>
// Qt
namespace SituationMap
{
GuezIed2SituationMap::GuezIed2SituationMap(ObjectFactory &objFac, const QString &layername, int drawOrder, const char *loggerName)
: BaseClass(objFac, layername, drawOrder, loggerName)
, FilterClass(loggerName, this)
, m_pluginProvider(nullptr)
{
}
GuezIed2SituationMap::~GuezIed2SituationMap()
{
if (m_displayFilter)
m_displayFilter->removeChangedCallback(this);
}
int32_t GuezIed2SituationMap::getSimId(const Sim2SituationMap::DDS_T &ddsData) const
{
return ddsData.id();
}
bool GuezIed2SituationMap::init(PluginProvider *pluginProvider)
{
if (!pluginProvider)
return false;
m_pluginProvider = pluginProvider;
m_guezIedDtc = pluginProvider->gimDtc();
if (!m_guezIedDtc)
return false;
m_guezIedGuiIfc = pluginProvider->gimIfc();
// enable/waitForHistoricalData
m_guezIedDtc->enableIed(true);
m_guezIedDtc->enableIedPosition(true);
m_guezIedDtc->waitForHistoricalDataIed(1000);
m_guezIedDtc->waitForHistoricalDataIedPosition(1000);
// FilterManagement:
FilterClass::init(m_pluginProvider);
auto fltAesIfc = pluginProvider->fltAesIfc();
if (fltAesIfc)
{
m_displayFilter = fltAesIfc->aesFilterForOperator(pluginProvider->operatorId(), pluginProvider->workspaceId());
if (m_displayFilter)
m_displayFilter->addChangedCallback(this);
}
onAesDisplayFilterChanged(AreaEffectSimulation::AesType_def::AtMineAreaSingleMines);
connect(m_pluginProvider, &PluginProvider::partitionTimeChanged,
this, &GuezIed2SituationMap::partitionTimeChanged);
return true;
}
bool GuezIed2SituationMap::run()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (!m_guezIedDtc)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no dtc";
return false;
}
connect(m_guezIedDtc.get(), &GuezIedManagement::Interface::Dtc::iedChanged,
this, &GuezIed2SituationMap::onIedChanged);
connect(m_guezIedDtc.get(), &GuezIedManagement::Interface::Dtc::iedPositionChanged,
this, &GuezIed2SituationMap::onIedPositionChanged);
// get Ieds:
m_guezIedDtc->ieds([this](const GuezIedManagement::Ied & data)
{
onIedChanged(data, DataModification::eAdded);
});
// get positions
m_guezIedDtc->iedPositions([this](const GuezIedManagement::IedPosition & data)
{
onIedPositionChanged(data, DataModification::eAdded);
});
onAesDisplayFilterChanged(AreaEffectSimulation::AesType_def::AtMineAreaSingleMines);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
bool GuezIed2SituationMap::mapObjectsClicked(const QVector<UniqueMapId> &uniqueMapIds)
{
if (!m_guezIedGuiIfc)
return false;
const QVector<int32_t> &simIds = uniqueMapIds2SimIds(uniqueMapIds);
if (simIds.isEmpty())
return true;
m_guezIedGuiIfc->showInfoWindow(simIds);
return true;
}
bool GuezIed2SituationMap::unifiedMapObjectData(UniqueMapId uniqueMapId, UnifiedMapObjectData &umodOut) const
{
if (!m_guezIedDtc)
return false;
int32_t simIdOut = -1;
if (!this->uniqueMapId2SimId(uniqueMapId, simIdOut))
return false;
umodOut = UnifiedMapObjectData();
RefPointer<MAP_T> mapObj = this->getMapObjectOfUniqueMapId(uniqueMapId);
if (mapObj.valid())
umodOut.m_image = mapObj->previewImage();
const auto cb = [simIdOut, &umodOut](const GuezIedManagement::Ied & data) -> bool
{
if (data.id() == simIdOut)
{
umodOut.m_equipmentNumber = data.equipmentNumber();
umodOut.m_partyId = data.partyId();
umodOut.m_description1 = QString::fromStdString(data.name());
umodOut.m_description2 = QString::number(data.explosiveForce());
return true; // break loop
}
return false;
};
// sonst kann sich der compiler nicht zwischen bool und void entscheiden... !?
std::function<bool(const GuezIedManagement::Ied &data)> cb1 = cb;
return m_guezIedDtc->ieds(cb1);
}
void GuezIed2SituationMap::onIedChanged(const GuezIedManagement::Ied &data,
DataModification modType)
{
if (modType == DataModification::eRemoved)
return;
DEBUG_LOG(m_logger) << "onIedChanged: " << data;
updateDdsDataContainer(data, modType); // helpful for FilterManagement/onSymbolAppearanceSettingsChanged
handleChanged(data, modType);
}
void GuezIed2SituationMap::onIedPositionChanged(const GuezIedManagement::IedPosition &data, DataModification modType)
{
if (modType == DataModification::eRemoved)
return;
DEBUG_LOG(m_logger) << "onIedPositionChanged: " << data;
const int32_t simId = data.id();
const Core::GeoPosition &geoPos = data.position();
// Assume, that IED was already created:
auto it = m_simId2UniqueMapId.constFind(simId);
if (it == m_simId2UniqueMapId.constEnd())
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " GUEZ Ied not found simId = " << simId;
return;
}
const UniqueMapId uniqueMapId = it.value();
RefPointer<Sim2SituationMap::MAP_T> mapObj = m_objFac.get<Sim2SituationMap::MAP_T>(uniqueMapId);
if (mapObj)
{
// Position & Height:
mapObj->setOrigin(Point3D(geoPos.lon(), geoPos.lat(), geoPos.z()));
if (!mapObj->updateView())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " GUEZ Ied updateView failed"
<< " simId = " << simId
<< " uniqueMapId = " << uniqueMapId ;
return;
}
}
else
{
ERROR_LOG(m_logger) << LOGFUNCTION << " GUEZ Ied not found in objFac"
<< " simId = " << simId
<< " uniqueMapId = " << uniqueMapId ;
}
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return;
}
Injury guezIedStateToInjury(const GuezIedManagement::IedTacticalState &iedState)
{
switch (iedState.underlying())
{
case GuezIedManagement::IedTacticalState::Active:
return AdvancedSymbology::Injury::NoInjury; // ""
break;
default:
return AdvancedSymbology::Injury::TotalKill; // "/\"
}
}
void updateIedPyro(const GuezIedManagement::IedTacticalState &iedStateIn,
AdvancedSymbology::Injury &injuryInOut,
QString &symbolInOut)
{
// Note:
// Special: triggered Ied<Small|Big> has seperate SIDC:
// "M25D|CMPL|10014000001103000000"); // SIDC for IED (OHNE ZickZack)
// "M25D|CMPL|10014000001103010000"); // SIDC for IED (MIT ZickZack)
// ^
// | -> Therefore suppress Injury
// handled at guez_ied_to_map.cpp and gim_info_dialog.cpp
if (injuryInOut != AdvancedSymbology::Injury::TotalKill)
return;
switch (iedStateIn.underlying())
{
case GuezIedManagement::IedTacticalState::Unknown:
case GuezIedManagement::IedTacticalState::NotActive:
case GuezIedManagement::IedTacticalState::Active:
// empty
break;
case GuezIedManagement::IedTacticalState::TriggeredBySwitch:
case GuezIedManagement::IedTacticalState::TriggeredByRemote:
case GuezIedManagement::IedTacticalState::TriggeredByLightBarrier:
case GuezIedManagement::IedTacticalState::TriggeredByTautWire:
case GuezIedManagement::IedTacticalState::TriggeredByControlDevice:
{
// Sonderfall: type == Ied:
// sidc MIT ZickZack ersetzt 'sidc OHNE ZickZack && TotalKill'
const QString &bsc = AdvancedSymbology::SidcBuilderBase::concreteSidcToBaseSymbolCode(symbolInOut);
// QStringLiteral("AP6D|CMPL|10014000001103000000"); // SIDC for IED (OHNE ZickZack)
if ((bsc.compare(QStringLiteral("AP6D|BASE|40110300")) == 0 ||
bsc.compare(QStringLiteral("M25D|BASE|40110300")) == 0)
)
{
symbolInOut = QStringLiteral("AP6D|CMPL|10014000001103010000"); // SIDC for IED (MIT ZickZack)
injuryInOut = AdvancedSymbology::Injury::NoInjury;
}
}
break;
case GuezIedManagement::IedTacticalState::Defused:
// empty
return;
} //switch
}
bool GuezIed2SituationMap::updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
<< " id=" << ddsData.id()
<< " name=" << ddsData.name();
// const qint32 guezIedId = ddsData.id();
// SIDC:
// (role is not neccessary here, participant will take it from partyId via partyIdToColorFunctor)
SymbolData symData = mapObj->symbol();
symData.sidc = QString::fromStdString(ddsData.symbol());
// Identifier as(TextModifier)
mapObj->setTextModifier(Participant::TextModifier::T_UniqueDesignation, QString::fromStdString(ddsData.name()));
mapObj->setTextModifier(Participant::TextModifier::M_HigherFormation, QString::number(ddsData.explosiveForce()));
// PartyId:
mapObj->setPartyId(ddsData.partyId());
// Injury/TacticalState
// Special: triggered Ied<Small|Big> has seperate SIDC:
// "M25D|CMPL|10014000001103000000"); // SIDC for IED (OHNE ZickZack)
// "M25D|CMPL|10014000001103010000"); // SIDC for IED (MIT ZickZack)
// ^
// | -> Therefore suppress Injury
//
// Attention:
//
// following block is copied to Plugins/GuezIedManagement/Gui/InfoDialog/gim_info_dialog.cpp
//
AdvancedSymbology::Injury injury = guezIedStateToInjury(ddsData.tacticalState());
if ((ddsData.type() == GuezIedManagement::IedType_def::IedSmallPyro) ||
(ddsData.type() == GuezIedManagement::IedType_def::IedBigPyro))
{
updateIedPyro(ddsData.tacticalState(), injury, symData.sidc);
}
int32_t injuryPartyId = -1;
mapObj->setInjury(injury, injuryPartyId);
mapObj->setSymbol(symData);
// // if (symData.sidc.compare(QStringLiteral("M25D|CMPL|10014000001103010000")) == 0)
// const QString &bsc = AdvancedSymbology::SidcBuilderBase::concreteSidcToBaseSymbolCode(symData.sidc);
// if ((bsc.compare(QStringLiteral("AP6D|BASE|40110301")) == 0 ||
// bsc.compare(QStringLiteral("M25D|BASE|40110301")) == 0)
// )
// mapObj->setInjury(AdvancedSymbology::Injury::NoInjury, ddsData.partyId());
// else
// {
// int32_t injuryPartyId = -1;
// mapObj->setInjury(guezIedStateToInjury(ddsData.tacticalState()), injuryPartyId);
// }
// FilterManagement:
if (m_symbolAppearanceSettings) // ToDO: check m_currentSymbolSettings.isValid() ?
handleSymbolAppearanceSettings(mapObj, ddsData);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
void GuezIed2SituationMap::onAesDisplayFilterChanged(AreaEffectSimulation::AesType aesType)
{
DEBUG_LOG(m_logger) << "GuezIed2SituationMap";
if (!m_displayFilter || aesType != AreaEffectSimulation::AesType_def::AtMineAreaSingleMines)
return;
m_effectStateStruct = m_displayFilter->effectStateFilter(AreaEffectSimulation::AesType_def::AtMineAreaSingleMines);
// FilterManagement:
handleSymbolAppearanceSettings();
return;
}
void GuezIed2SituationMap::onSymbolAppearanceSettingsChanged(FilterManagement::SymbolAppearanceSettings::Part part)
{
if ((part != FilterManagement::SymbolAppearanceSettings::Part::All) &&
(part != FilterManagement::SymbolAppearanceSettings::Part::Symbol))
return;
// Part::All || Part::Symbol
const bool relevant = symbolAppearanceSettingsChangesAreRelevant(m_symbolAppearanceSettings->settings());
m_currentSymbolSettings = m_symbolAppearanceSettings->settings();
if (!relevant)
return;
handleSymbolAppearanceSettings();
}
bool GuezIed2SituationMap::symbolAppearanceSettingsChangesAreRelevant(const FilterManagement::SymbolAppearanceSettings::Settings &newSas) const
{
return (m_currentSymbolSettings.symbolSettings.symbolScale != newSas.symbolSettings.symbolScale) ||
(m_currentSymbolSettings.symbolSettings.symbolTransparency != newSas.symbolSettings.symbolTransparency) ||
(m_currentSymbolSettings.symbolSettings.symbolPartyAppearance != newSas.symbolSettings.symbolPartyAppearance);
}
void GuezIed2SituationMap::handleSymbolAppearanceSettings()
{
for (const GuezIedManagement::Ied &ied : qAsConst(m_ddsDataContainer))
{
const UniqueMapId uniqueMapId = m_simId2UniqueMapId.value(ied.id(), INVALID_MAP_ID);
if (uniqueMapId == INVALID_MAP_ID)
{
WARNING_LOG(m_logger) << LOGFUNCTION << "Found a ied which is in internal map but has no map object...: " << ied.id();
continue;
}
RefPointer<MAP_T> mapObj = m_objFac.get<MAP_T>(uniqueMapId);
if (!mapObj.valid())
continue;
handleSymbolAppearanceSettings(mapObj, ied);
if (!mapObj->updateView())
WARNING_LOG(m_logger) << LOGFUNCTION << " updateView failed,"
<< " mapObj = " << mapObj->debugInfo();
} // foreach
}
void GuezIed2SituationMap::handleSymbolAppearanceSettings(RefPointer<MAP_T> &mapObj, const Sim2SituationMap::DDS_T &ddsData)
{
const FilterManagement::SymbolAppearanceSettings::Settings &filterSettings = m_symbolAppearanceSettings->settings();
mapObj->setScale(filterSettings.symbolSettings.symbolScale);
mapObj->setUserSymbolOpacity(1.0f - filterSettings.symbolSettings.symbolTransparency);
const auto spa = filterSettings.symbolSettings.symbolPartyAppearance.value(ddsData.partyId());
mapObj->setTextModifierVisibility(Participant::TextModifier::T_UniqueDesignation, spa.showDesignator);
mapObj->setTextModifierVisibility(Participant::TextModifier::M_HigherFormation, spa.showTacticalIdentifier);
const bool isVisi = isVisible(ddsData);
mapObj->setVisibility(isVisi);
}
bool GuezIed2SituationMap::isVisible(const Sim2SituationMap::DDS_T &ddsData) const
{
bool isVisi = visibleBySymbolPartyAppearance(ddsData) &&
visibleByAesFilter(ddsData);
// DEBUG_LOG(m_logger) << LOGFUNCTION << " new Ied" << ddsData.id() << " isisVisi " << isVisi;
return isVisi;
}
bool GuezIed2SituationMap::visibleBySymbolPartyAppearance(const Sim2SituationMap::DDS_T &ddsData) const
{
const FilterManagement::SymbolAppearanceSettings::Settings &filterSettings = m_symbolAppearanceSettings->settings();
const auto spa = filterSettings.symbolSettings.symbolPartyAppearance.value(ddsData.partyId());
return spa.isVisible;
}
bool GuezIed2SituationMap::visibleByAesFilter(const Sim2SituationMap::DDS_T &ddsData) const
{
if (!m_displayFilter)
return true;
switch (ddsData.tacticalState().underlying())
{
// typical states: NotActive -> Active -> Triggered
// relevant Filter Flags:
// state NotActive -> effectStateStruct.displayPrepared
// state Active -> effectStateStruct.displayActivated
// state TriggeredBY... -> effectStateStruct.expiredAfterglowDurationMSec (slider)
case GuezIedManagement::IedTacticalState_def::NotActive:
return m_effectStateStruct.displayPrepared;
case GuezIedManagement::IedTacticalState_def::Active:
return m_effectStateStruct.displayActivated;
case GuezIedManagement::IedTacticalState_def::Unknown:
return false;
case GuezIedManagement::IedTacticalState_def::Defused:
case GuezIedManagement::IedTacticalState_def::TriggeredByControlDevice:
case GuezIedManagement::IedTacticalState_def::TriggeredByLightBarrier:
case GuezIedManagement::IedTacticalState_def::TriggeredByRemote:
case GuezIedManagement::IedTacticalState_def::TriggeredBySwitch:
case GuezIedManagement::IedTacticalState_def::TriggeredByTautWire:
auto timeTriggered = ddsData.sampleTime();
const AreaEffectSimulation::AesType t(AreaEffectSimulation::AesType::AtMineAreaSingleMines);
const auto afterGlow = m_effectStateStruct.expiredAfterglowDurationMSec; // Check!!!
DEBUG_LOG(m_logger) << LOGFUNCTION
<< " partitionTime=" << m_pluginProvider->partitionTime()
<< " timeTriggered" << timeTriggered
<< " afterGlow" << afterGlow
<< " timeTriggered + afterGlow=" << timeTriggered + afterGlow;
return (m_pluginProvider->partitionTime() < timeTriggered + afterGlow);
} // switch
return true;
}
void GuezIed2SituationMap::partitionTimeChanged()
{
handleSymbolAppearanceSettings();
}
}
@@ -0,0 +1,101 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "sim_to_situation_map_tmpl.h"
#include <GuezIedManagement/gim_data_plugin_interface.h>
#include <GuezIedManagement/gim_info_gui_plugin_interface.h>
#include <FilterManagement/flt_data_plugin_aes_display_filter.h>
#include <AreaEffectSimulation/aes_enums.hpp>
#include <MapObjects/participant.h>
namespace Buildings
{
class ForeignInfoGuiInterface;
}
namespace SituationMap
{
class GuezIed2SituationMap final : public Sim2SituationMap<GuezIedManagement::Ied, SituationMap::Participant>
, protected FilterManagement::AesDisplayFilter::FilterChangedCallback
, protected DdsFilterHandling<SituationMap::Participant>
{
Q_OBJECT
using BaseClass = SituationMap::Sim2SituationMap<GuezIedManagement::Ied, SituationMap::Participant>;
using FilterClass = DdsFilterHandling<SituationMap::Participant>;
public:
GuezIed2SituationMap(ObjectFactory &objFac,
const QString &layername,
int drawOrder,
const char *loggerName);
~GuezIed2SituationMap();
bool init(PluginProvider *pluginProvider);
bool run() override;
void stop() override
{
if (m_guezIedDtc)
m_guezIedDtc->disconnect(this);
if (m_pluginProvider)
disconnect(m_pluginProvider, &PluginProvider::partitionTimeChanged,
this, &GuezIed2SituationMap::partitionTimeChanged);
}
bool mapObjectsClicked(const QVector<UniqueMapId> &uniqueMapIds) override;
bool unifiedMapObjectData(UniqueMapId uniqueMapId, UnifiedMapObjectData &umodOut) const override;
protected Q_SLOTS:
void onIedChanged(const GuezIedManagement::Ied &data, DataModification modType = DataModification::eAdded);
void onIedPositionChanged(const GuezIedManagement::IedPosition &data, DataModification modType = DataModification::eAdded);
void onAesDisplayFilterChanged(AreaEffectSimulation::AesType aesType) override;
protected:
void partitionTimeChanged();
int32_t getSimId(const Sim2SituationMap::DDS_T &ddsData) const override;
bool updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj) override;
void onSymbolAppearanceSettingsChanged(FilterManagement::SymbolAppearanceSettings::Part part) override;
bool symbolAppearanceSettingsChangesAreRelevant(const FilterManagement::SymbolAppearanceSettings::Settings &newSas) const override;
void handleSymbolAppearanceSettings(RefPointer<MAP_T> &mapObj) override
{
if (!mapObj.valid())
return;
const int simId = m_uniqueMapId2SimId.value(mapObj->uniqueMapId());
handleSymbolAppearanceSettings(mapObj, m_ddsDataContainer.value(simId));
}
void handleSymbolAppearanceSettings();
void handleSymbolAppearanceSettings(RefPointer<MAP_T> &mapObj, const Sim2SituationMap::DDS_T &ddsData);
// void handleSymbolAppearanceSettings(RefPointer<MAP_T> &mapObj) override;
bool isVisible(const Sim2SituationMap::DDS_T &ddsData) const;
bool visibleBySymbolPartyAppearance(const Sim2SituationMap::DDS_T &ddsData) const;
bool visibleByAesFilter(const Sim2SituationMap::DDS_T &ddsData) const;
private:
std::shared_ptr<GuezIedManagement::Interface::Dtc> m_guezIedDtc;
std::shared_ptr<GuezIedManagement::ForeignGuiInterface> m_guezIedGuiIfc;
PluginProvider *m_pluginProvider;
std::shared_ptr<FilterManagement::AesDisplayFilter> m_displayFilter;
FilterManagement::AesDisplayFilter::EffectStateStruct m_effectStateStruct;
};
} // namespace
@@ -0,0 +1,355 @@
/**
* @RDE_HEADER@
* Guez Nasat NineLiner 9Liner
* $Id$
* $HeadURL$
* $Author$
*/
// Own
#include "guez_nasat_9liner.h"
#include <Map/object_factory.h>
#include <LtsCoordTrans/lts_coord_trans.h>
#include <MathUtils/simple_helper.h>
#include <Common/PluginInterfaces/gui_plugin_interface.h> // for method "getForeignGuiInterface"
// Qt
#include <QPolygonF>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonParseError>
#include <QTimer>
namespace SituationMap
{
int32_t GuezNasat9Liner2SituationMap::getSimId(const Sim2SituationMap::DDS_T &ddsData) const
{
return ddsData.id();
}
GuezNasat9Liner2SituationMap::GuezNasat9Liner2SituationMap(ObjectFactory &objFac, const QString &layername, int drawOrder, const char *loggerName)
: BaseClass(objFac, layername, drawOrder, loggerName)
, FilterClass(loggerName, this)
, m_pluginProvider(nullptr)
, m_notifyTimer(new QTimer(this))
{
m_notifyTimer->setInterval(500);
m_notifyTimer->setSingleShot(true);
connect(m_notifyTimer, &QTimer::timeout,
this, &GuezNasat9Liner2SituationMap::updateAllItems);
}
GuezNasat9Liner2SituationMap::~GuezNasat9Liner2SituationMap()
{
m_notifyTimer->stop();
}
bool GuezNasat9Liner2SituationMap::init(PluginProvider *pluginProvider)
{
if (!pluginProvider)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no pluginProvider";
return false;
}
m_pluginProvider = pluginProvider;
m_gnaDtc = pluginProvider->gnaDtc();
if (!m_gnaDtc)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no m_gnaDtc";
return false;
}
m_gnaDtc->enableNasat9Liner();
// m_gnaDtc->waitForHistoricalDataNasat9Liner(); // blocks ???
m_ppmDtc = pluginProvider->ppmDtc();
if (!m_ppmDtc)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no m_ppmDtc";
return false;
}
// FilterManagement:
FilterClass::init(m_pluginProvider);
// PartitionTime
connect(m_pluginProvider, &PluginProvider::partitionTimeChanged,
this, &GuezNasat9Liner2SituationMap::onPartitionTimeChanged);
return true;
}
bool GuezNasat9Liner2SituationMap::run()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (!m_gnaDtc)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no dtc";
return false;
}
// PPM
{
connect(m_ppmDtc.get(), &ParticipantManagement::Interface::Dtc::participantChanged,
this, &GuezNasat9Liner2SituationMap::onParticipantChanged, Qt::UniqueConnection);
// get:
m_ppmDtc->participants([this](const ParticipantManagement::Participant &data)
{
onParticipantChanged(data, DataModification::eAdded);
});
}
// GNA
{
connect(m_gnaDtc.get(), &GuezNasat::Interface::Dtc::nasat9LinerChanged,
this, &GuezNasat9Liner2SituationMap::handleChanged, Qt::UniqueConnection);
// get:
m_gnaDtc->nasat9Liners([this](const GuezNasat::Nasat9Liner & data)
{
handleChanged(data, DataModification::eAdded);
});
}
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
bool GuezNasat9Liner2SituationMap::isElapsed(const GuezNasat::Nasat9Liner &ddsData) const
{
// true -> hide
// false -> show
DEBUG_LOG(m_logger) << LOGFUNCTION << " check ddsData=" << ddsData;
if (BaseClass::isElapsed(ddsData))
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " check ddsData=" << ddsData << " HIDE";
return true;
}
// GUEZE-1676: Nineliner sollen zeitlich wie Trefferlinien angezeigt werden
// replace checkbox by slider, so 'isCurrent' is outdated:
DEBUG_LOG(m_logger) << LOGFUNCTION << " check ddsData=" << ddsData << " SHOW";
return false;
}
bool GuezNasat9Liner2SituationMap::mapObjectsClicked(const QVector<UniqueMapId> &uniqueMapIds)
{
// if(!m_bldInfoIfc)
// return false;
const QVector<int32_t> &simIds = uniqueMapIds2SimIds(uniqueMapIds);
if (simIds.isEmpty())
return true;
// m_bldInfoIfc->showInfoWindow(simIds);
return true;
}
bool GuezNasat9Liner2SituationMap::unifiedMapObjectData(UniqueMapId uniqueMapId, UnifiedMapObjectData &umodOut) const
{
if (!m_gnaDtc)
return false;
int32_t simIdOut = -1;
if (!this->uniqueMapId2SimId(uniqueMapId, simIdOut))
return false;
umodOut = UnifiedMapObjectData();
RefPointer<MAP_T> mapObj = this->getMapObjectOfUniqueMapId(uniqueMapId);
if (mapObj.valid())
umodOut.m_image = mapObj->previewImage();
umodOut.m_description1 = QString::fromStdString(m_gnaDtc->nasat9Liner(simIdOut).name());
return true;
}
void GuezNasat9Liner2SituationMap::onParticipantChanged(const ParticipantManagement::Participant &data, DataModification modType)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
<< " pId=" << data.id()
<< " parytIdOld=" << m_participantToPartyId.value(data.id(), -1)
<< " parytId=" << data.partyId()
<< ", m_participantToPartyId.size()=" << m_participantToPartyId.size();
const int simId = data.id();
switch (modType)
{
case DataModification::eAdded:
case DataModification::eModified:
m_participantToPartyId[simId] = data.partyId();
break;
case DataModification::eRemoved:
m_ddsDataContainer.remove(simId);
break;
}
// what can change?
// - participant moves from one party to another
//
// schedule slot updateAllItems
m_notifyTimer->start();
TRACE_LOG(m_logger) << LOGFUNCTION << " END, m_participantToPartyId.size()=" << m_participantToPartyId.size();
}
bool GuezNasat9Liner2SituationMap::handleChanged(const Sim2SituationMap::DDS_T &ddsData, DataModification modType)
{
m_notifyTimer->start();
updateDdsDataContainer(ddsData, modType); // helpfull for FilterManagement/onSymbolAppearanceSettingsChanged
return BaseClass::handleChanged(ddsData, modType);
}
bool GuezNasat9Liner2SituationMap::updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
<< " id=" << ddsData.id()
<< " name=" << ddsData.name()
<< " isCurrent=" << ddsData.isCurrent()
<< " initialPoint=" << ddsData.initialPoint()
<< " targetPosition=" << ddsData.targetPosition()
<< " participantId=" << ddsData.participantId()
<< " m_participantToPartyId.size()=" << m_participantToPartyId.size()
<< " partyId.size()=" << m_participantToPartyId.value(ddsData.participantId(), -1);
mapObj->setPickable(false);
// show just the ObjectAppearance::Technical
mapObj->setVisibility(ObjectAppearance::Tactical, false);
// PartyId, if not available yet it will be updated later
// (via onParticipantChanged and m_notifyTimer)
mapObj->setPartyId(m_participantToPartyId.value(ddsData.participantId(), -1));
TextStyle ts = mapObj->textStyle();
ts.setHorizontalAlignment(HorizontalAlignment::Center);
mapObj->setTextStyle(ts);
MAP_T::NineLinerData data;
data.initialPoint = Point3D(ddsData.initialPoint().lon(), ddsData.initialPoint().lat(), .0);
data.targetPosition = Point3D(ddsData.targetPosition().lon(), ddsData.targetPosition().lat(), .0);
data.fah = ddsData.finalAttackHeading();
data.fahLow = ddsData.finalAttackHeadingLow();
data.fahHigh = ddsData.finalAttackHeadingHigh();
data.friendliesBearing = ddsData.friendliesBearing();
data.friendliesDistance = ddsData.friendliesDistance();
mapObj->setNineLinerData(data);
mapObj->setIdentifier(QString::fromStdString(ddsData.name()));
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
bool GuezNasat9Liner2SituationMap::symbolAppearanceSettingsChangesAreRelevant(const FilterManagement::SymbolAppearanceSettings::Settings &newSas) const
{
return (m_currentSymbolSettings.symbolSettings.symbolScale != newSas.symbolSettings.symbolScale) ||
(m_currentSymbolSettings.symbolSettings.nasatNineLinerDisplayLengthMSec != newSas.symbolSettings.nasatNineLinerDisplayLengthMSec);
}
void GuezNasat9Liner2SituationMap::handleSymbolAppearanceSettings()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START" << " m_ddsDataContainer.size()=" << m_ddsDataContainer.size();
for (const GuezNasat::Nasat9Liner &nineLiner : qAsConst(m_ddsDataContainer))
{
RefPointer<MAP_T> mapObj = getMapObjectOfSimId(nineLiner.id());
if (!mapObj.valid())
continue;
handleSymbolAppearanceSettings(mapObj, nineLiner);
} // for
TRACE_LOG(m_logger) << LOGFUNCTION << " END" << " m_ddsDataContainer.size()=" << m_ddsDataContainer.size();
}
void GuezNasat9Liner2SituationMap::handleSymbolAppearanceSettings(RefPointer<MAP_T> &mapObj)
{
if (!mapObj.valid())
return;
const int simId = m_uniqueMapId2SimId.value(mapObj->uniqueMapId());
handleSymbolAppearanceSettings(mapObj, m_ddsDataContainer.value(simId));
// Since svc GNA updates sample_time for outdated nineLiner(isCurrent==false),
// (see handler_nasat_nine_liner.cpp) following workaround is obsolete:
// bool bIsRealCurrent = true;
// int32_t simIdOut = -1;
// if (uniqueMapId2SimId(mapObj->uniqueMapId(), simIdOut))
// {
// const DDS_T ddsData = m_ddsDataContainer[simIdOut];
// qint64 youngestSampleTime = getYoungestSampleTimeOfCurrentForParticipant(ddsData.participantId());
// if (youngestSampleTime == ddsData.sampleTime())
// {
// DEBUG_LOG(m_logger) << LOGFUNCTION << " IS YOUNGEST ITEM " << simIdOut;
// bIsRealCurrent = true;
// } else {
// DEBUG_LOG(m_logger) << LOGFUNCTION << " IS NOT YOUNGEST ITEM " << simIdOut;
// bIsRealCurrent = false;
// }
// }
}
void GuezNasat9Liner2SituationMap::handleSymbolAppearanceSettings(RefPointer<Sim2SituationMap::MAP_T> mapObj, const Sim2SituationMap::DDS_T &ddsData)
{
mapObj->setScale(m_currentSymbolSettings.symbolSettings.symbolScale);
const bool isVisi = visibleByDisplayLength(m_pluginProvider->partitionTime(), ddsData.sampleTime());
if (mapObj->visibility() != isVisi)
{
mapObj->setVisibility(isVisi);
if (!mapObj->updateView())
WARNING_LOG(m_logger) << LOGFUNCTION << " updateView failed,"
<< " mapObj = " << mapObj->debugInfo();
}
}
bool GuezNasat9Liner2SituationMap::visibleByDisplayLength(const qint64 newPartitionTime, const qint64 stateTime) const
{
DEBUG_LOG(m_logger) << LOGFUNCTION
<< " newPartitionTime = " << newPartitionTime
<< " stateTime = " << stateTime
<< " age = " << (newPartitionTime - stateTime)
<< " nasatNineLinerDisplayLengthMSec = " << m_currentSymbolSettings.symbolSettings.nasatNineLinerDisplayLengthMSec;
if (m_currentSymbolSettings.symbolSettings.nasatNineLinerDisplayLengthMSec < 0)
return true;
return (newPartitionTime - stateTime) <= m_currentSymbolSettings.symbolSettings.nasatNineLinerDisplayLengthMSec; // all msec
}
void GuezNasat9Liner2SituationMap::onPartitionTimeChanged()
{
handleSymbolAppearanceSettings();
}
void GuezNasat9Liner2SituationMap::updateAllItems()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START, m_ddsDataContainer.size()=" << m_ddsDataContainer.size();
for (const DDS_T &ddsData : qAsConst(m_ddsDataContainer))
{
RefPointer<MAP_T> mapObj = getMapObjectOfSimId(ddsData.id());
if (!mapObj.valid())
continue;
updateElementImpl(ddsData, mapObj);
handleSymbolAppearanceSettings(mapObj);
if (!mapObj->updateView())
WARNING_LOG(m_logger) << LOGFUNCTION << " updateView failed for "<< mapObj->debugInfo();
} // for
TRACE_LOG(m_logger) << LOGFUNCTION << " END, m_ddsDataContainer.size()=" << m_ddsDataContainer.size();
}
}
@@ -0,0 +1,91 @@
/**
* @RDE_HEADER@
* Guez Nasat NineLiner 9Liner
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "sim_to_situation_map_tmpl.h"
#include <Plugins/GuezNasat/gna_data_plugin_interface.h>
#include <Plugins/ParticipantManagement/ppm_data_plugin_interface.h>
#include <MapObjects/polyline.h>
#include <MapObjects/nine_liner.h>
class QTimer;
namespace Buildings
{
class ForeignInfoGuiInterface;
}
namespace SituationMap
{
class GuezNasat9Liner2SituationMap final : public Sim2SituationMap<GuezNasat::Nasat9Liner, SituationMap::NineLiner>
, protected DdsFilterHandling<SituationMap::NineLiner>
{
Q_OBJECT
using BaseClass = SituationMap::Sim2SituationMap<GuezNasat::Nasat9Liner, SituationMap::NineLiner>;
using FilterClass = DdsFilterHandling<SituationMap::NineLiner>;
public:
explicit GuezNasat9Liner2SituationMap(ObjectFactory &objFac,
const QString &layername,
int drawOrder,
const char *loggerName);
~GuezNasat9Liner2SituationMap();
bool init(PluginProvider *pluginProvider);
bool run() override;
void stop() override
{
// m_participantWithMaybeMissingPartyId.clear();
if (m_gnaDtc)
m_gnaDtc->disconnect(this);
if (m_ppmDtc)
m_ppmDtc->disconnect(this);
}
bool isElapsed(const GuezNasat::Nasat9Liner &ddsData) const override;
bool mapObjectsClicked(const QVector<UniqueMapId> &uniqueMapIds) override;
bool unifiedMapObjectData(UniqueMapId uniqueMapId, UnifiedMapObjectData &umodOut) const override;
protected Q_SLOTS:
void onParticipantChanged(const ParticipantManagement::Participant &data, DataModification modType);
void updateAllItems();
protected:
int32_t getSimId(const Sim2SituationMap::DDS_T &ddsData) const override;
bool handleChanged(const DDS_T &ddsData, DataModification modType);
bool updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj) override;
bool symbolAppearanceSettingsChangesAreRelevant(const FilterManagement::SymbolAppearanceSettings::Settings &newSas) const override;
void handleSymbolAppearanceSettings();
void handleSymbolAppearanceSettings(RefPointer<MAP_T> &mapObj) override;
void handleSymbolAppearanceSettings(RefPointer<MAP_T> mapObj, const Sim2SituationMap::DDS_T &ddsData);
bool visibleByDisplayLength(const qint64 newPartitionTime, const qint64 stateTime) const;
void onPartitionTimeChanged();
private:
PluginProvider *m_pluginProvider{nullptr};
std::shared_ptr<GuezNasat::Interface::Dtc> m_gnaDtc; // guez NASAT
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc; // to get the partyId
QHash<int, int> m_participantToPartyId;
QTimer *m_notifyTimer{nullptr};
QMap<int, qint64> m_lastSampleTimePerParticipant; // participantId, sampleTime
};
} // namespace
@@ -0,0 +1,546 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
// Own
#include "hitlineinfo_to_map.h"
#include "pdm_handler.h"
#include <Map/object_factory.h>
#include <Map/map.h>
#include <LtsCoordTrans/lts_coord_trans.h>
#include <LtsUtilsCore/outdated_position.h>
#include <MathUtils/simple_helper.h>
#include <PluginInterfaces/gui_plugin_interface.h>
#include <Plugins/ParticipantManagement/ppm_data_plugin_interface.h>
// Qt
#include <QDateTime>
#include <QTimer>
namespace SituationMap
{
HitlineInfo2SituationMap::HitlineInfo2SituationMap(PdmHandler *pdmHandler,
Participant2SituationMap *participant2SituationMap,
ObjectFactory &objFac,
const QString &layername,
int drawOrder,
const char *loggerName)
: BaseClass(objFac, layername, drawOrder, loggerName)
, FilterClass(loggerName, this)
, m_pdmHandler(pdmHandler)
, m_participant2SituationMap(participant2SituationMap)
, m_pBuildingHitlineCleanupTimer(new QTimer(this))
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
m_pBuildingHitlineCleanupTimer->setInterval(1000 * 60 * 5); // every 5 min should be enough
connect(m_pBuildingHitlineCleanupTimer, &QTimer::timeout, this, &HitlineInfo2SituationMap::onCleanupBuildingHitlines);
m_pBuildingHitlineCleanupTimer->start();
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
HitlineInfo2SituationMap::~HitlineInfo2SituationMap()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
int32_t HitlineInfo2SituationMap::getSimId(const Sim2SituationMap::DDS_T &ddsData) const
{
return ddsData.id();
}
bool HitlineInfo2SituationMap::init(PluginProvider *pluginProvider)
{
if (!pluginProvider ||
!pluginProvider->ppmDtc())
return false;
m_pluginProvider = pluginProvider;
m_ppmDtc = pluginProvider->ppmDtc();
if (!m_ppmDtc)
return false;
auto bldDtc = m_pluginProvider->bldDtc();
if (bldDtc)
{
connect(bldDtc.get(), &Buildings::Interface::Dtc::buildingHitLineInfoChanged,
this, &HitlineInfo2SituationMap::onBuildingHitlineInfoChanged);
bldDtc->buildingHitLineInfos([this](const Buildings::BuildingHitLineInfo & data)
{
onBuildingHitlineInfoChanged(data, DataModification::eAdded);
});
}
// FilterManagement:
FilterClass::init(m_pluginProvider);
// PartitionTime
connect(m_pluginProvider, &PluginProvider::partitionTimeChanged,
this, &HitlineInfo2SituationMap::onPartitionTimeChanged);
return true;
}
bool HitlineInfo2SituationMap::run()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (!m_ppmDtc)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no dtc";
return false;
}
connect(m_ppmDtc.get(), &ParticipantManagement::Interface::Dtc::hitLineInfoChanged,
this, &HitlineInfo2SituationMap::onHitLineInfoChanged);
// get Hitlines:
m_ppmDtc->hitLineInfos([this](const Sim2SituationMap::DDS_T & ddsData)
{
onHitLineInfoChanged(ddsData, DataModification::eAdded);
});
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
void HitlineInfo2SituationMap::stop()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (m_ppmDtc)
m_ppmDtc->disconnect(this);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
bool HitlineInfo2SituationMap::isElapsed(const ParticipantManagement::HitLineInfo &ddsData) const
{
// true -> hide
// false -> show
// GUEZE-2861 says we have to create LTD this way again
//#########################################################
// GUEZE-2550:
// No LTD is created this way...
// if (m_pdmHandler->isLTDChargeType(ddsData.chargeTypeId()))
// return true;
//#########################################################
// [GUEZE-495]: 3D Lagedarstellung Trefferlinien
// Data of real life: HitLineInfo contains (0,0,0)
// Therefore the HitLine was densified to ~600000 vertices!!!
// The slowed down the OpApp dramatically!!
// Fix: ignore Hitlines with this -> elapsed
const Core::GeoPosition &startGeoPos = ddsData.originatorPos();
const Core::GeoPosition &endGeoPos = ddsData.injuryPos();
{
Point3D dummy(startGeoPos.lon(), startGeoPos.lat(), startGeoPos.z());
if (dummy.isNull())
return true;
}
{
Point3D dummy(endGeoPos.lon(), endGeoPos.lat(), endGeoPos.z());
if (dummy.isNull())
return true;
}
// GUEZE-495: RPL Nr 769: 3D Lagedarstellung Trefferlinien
// [DoD]: Es werden in der 3D-Ansicht keinerlei Trefferlinien oder deren
// Bestandteile angezeigt, bei denen der Start- und/oder Endpunkt unterhalb
// der Erdoberfläche liegt. In der 2D-Ansicht werden weiterhin alle
// Trefferlinien (ober- sowie unterirdisch) angezeigt.
if (m_objFac.map() && (m_objFac.map()->mode() == Mode::Mode_3D))
{
if (startGeoPos.z() < 0)
return true;
if (endGeoPos.z() < 0)
return true;
}
return false;
}
bool HitlineInfo2SituationMap::mapObjectsClicked(const QVector<UniqueMapId> &uniqueMapIds)
{
auto ppmParticipantInfoIfc = m_pluginProvider->ppmParticipantInfoIfc();
if (!ppmParticipantInfoIfc)
return false;
const QVector<qint32> &simIds = uniqueMapIds2SimIds(uniqueMapIds);
if (simIds.isEmpty())
return true;
ppmParticipantInfoIfc->showHitLineInfoWindow(simIds);
return true;
}
QString HitlineInfo2SituationMap::chargeTypeIdentifier(const int32_t originatorChargeTypeId) const
{
if (!m_pdmHandler)
return QStringLiteral("ctId_%1").arg(originatorChargeTypeId);
QString chargeTypeString = m_pdmHandler->trChargeTypeShortName(originatorChargeTypeId);
if (chargeTypeString.isEmpty())
return QStringLiteral("ctId_%1").arg(originatorChargeTypeId);
return chargeTypeString;
}
bool HitlineInfo2SituationMap::unifiedMapObjectData(UniqueMapId uniqueMapId, UnifiedMapObjectData &umodOut) const
{
if (!m_ppmDtc)
return false;
int32_t simIdOut = -1;
if (!this->uniqueMapId2SimId(uniqueMapId, simIdOut))
return false;
umodOut = UnifiedMapObjectData();
RefPointer<MAP_T> mapObj = this->getMapObjectOfUniqueMapId(uniqueMapId);
if (mapObj.valid())
umodOut.m_image = mapObj->previewImage();
const auto cb = [this, simIdOut, &umodOut](const Sim2SituationMap::DDS_T & ddsData) -> bool
{
if (ddsData.id() == simIdOut)
{
umodOut.m_partyId = ddsData.originatorPartyId();
const int32_t originatorChargeTypeId = ddsData.chargeTypeId();
umodOut.m_description1 = chargeTypeIdentifier(originatorChargeTypeId);
return true; // break loop
}
return false;
};
// sonst kann sich der compiler nicht zwischen bool und void entscheiden... !?
std::function<bool(const Sim2SituationMap::DDS_T &ddsData)> cb1 = cb;
return m_ppmDtc->hitLineInfos(cb1);
}
bool HitlineInfo2SituationMap::onHitLineInfoChanged(const Sim2SituationMap::DDS_T &ddsData,
DataModification modType)
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " START"
<< ", ddsData.id()=" << ddsData.id()
<< ", ddsData.injuryBuildingId()=" << ddsData.injuryBuildingId()
<< ", modType=" << modType
<< ", m_buildingHits.size()=" << m_buildingHits.size();
// avoid construction if invisible due to BldgHitline?
if (((modType==DataModification::eAdded) || (modType==DataModification::eModified)) &&
(!visibleByBldgHitlines(ddsData))
)
{
DEBUG_LOG(m_logger) << "Not showing participant hitline " << ddsData <<
" since there is already a hitline on the building";
return true;
}
updateDdsDataContainer(ddsData, modType); // helpfull for FilterManagement/onSymbolAppearanceSettingsChanged
return handleChanged(ddsData, modType);
}
// same as in building viewer (BuildingViewerDdsController)
void HitlineInfo2SituationMap::onBuildingHitlineInfoChanged(const Buildings::BuildingHitLineInfo &data, DataModification modType)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
<< ", data.id()=" << data.id()
<< ", data.originatorParticipantId()=" << data.originatorParticipantId()
<< ", data.buildingId()=" << data.buildingId()
<< ", modType=" << modType
<< ", m_buildingHits.size()=" << m_buildingHits.size();
if (modType != DataModification::eAdded && modType != DataModification::eModified)
return;
BuildingHit bh;
bh.sampleTime = data.sampleTime();
bh.originatorParticipantId = data.originatorParticipantId();
bh.chargeTypeId = data.chargeTypeId();
m_buildingHits[data.buildingId()].push_back(bh);
TRACE_LOG(m_logger) << LOGFUNCTION << " END"
<< ", data.id()=" << data.id()
<< ", data.originatorParticipantId()=" << data.originatorParticipantId()
<< ", data.buildingId()=" << data.buildingId()
<< ", modType=" << modType
<< ", m_buildingHits.size()=" << m_buildingHits.size();
}
void HitlineInfo2SituationMap::onCleanupBuildingHitlines()
{
const qint64 tNow = QDateTime::currentMSecsSinceEpoch();
const auto isOutdated = [tNow](const BuildingHit &bh)
{
return LtsUtils::isPositionTimeOutdated(tNow, bh.sampleTime);
};
for (auto &hitLines : m_buildingHits)
hitLines.erase(std::remove_if(hitLines.begin(), hitLines.end(), isOutdated), hitLines.end());
}
bool HitlineInfo2SituationMap::createElement(const DDS_T &ddsData)
{
const int32_t simId = getSimId(ddsData);
if (!m_simId2UniqueMapId.contains(simId))
{
INFO_LOG(m_logger) << LOGFUNCTION << " new Hitline !!!!" << " simId = " << simId;
const SpecialChargeType specialChargeTypeId = m_pdmHandler->isSpecialChargeType(ddsData.chargeTypeId());
if (PdmHandler::isChargeTypeLtdOrLrf(specialChargeTypeId))
m_participant2SituationMap->onParticipantFakeGearEventChanged(ddsData.originatorParticipantId(), ddsData.sampleTime(), specialChargeTypeId);
// Note:
// do not remove the FakeEvent from m_participant2SituationMap
// if there are two fake events: 1st at 10sec, 2nd at 20sec.
// the removeElement of the first must not remove the originatorParticipantId
// at m_participant2SituationMap
// Norbert Thoden, 2023-06-22
}
return BaseClass::createElement(ddsData);
}
bool HitlineInfo2SituationMap::updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj)
{
const qint32 hitlineId = ddsData.id();
TRACE_LOG(m_logger) << LOGFUNCTION << " START" << " id=" << hitlineId;
// mapObj->setPickable(true); // default: pickable == true
mapObj->setVisibility(SituationMap::ObjectAppearance::Tactical, false);
mapObj->rLineStyle().setLineWidth(3); // will influence LineWith and ArrowSize
// Line Style
LineStyle ls = mapObj->lineStyle();
const SpecialChargeType sct = m_pdmHandler->isSpecialChargeType(ddsData.chargeTypeId());
switch (sct)
{
case SpecialChargeType::LRF:
ls.setLinePattern(LinePattern::Dot);
break;
case SpecialChargeType::LTD:
ls.setLinePattern(LinePattern::Solid);
break;
case SpecialChargeType::NoneSpecial:
default:
ls.setLinePattern(LinePattern::Dash);
} // switch
mapObj->setLineStyle(ls);
// PartyId:
mapObj->setPartyId(ddsData.originatorPartyId());
// Identifier
const int32_t originatorChargeTypeId = ddsData.chargeTypeId();
mapObj->setIdentifier(chargeTypeIdentifier(originatorChargeTypeId));
// setStartAndEndPoint
const Core::GeoPosition &startGeoPos = ddsData.originatorPos();
const Core::GeoPosition &endGeoPos = ddsData.injuryPos();
mapObj->setStartAndEndPoint(Point3D(startGeoPos.lon(), startGeoPos.lat(), startGeoPos.z()),
Point3D(endGeoPos.lon(), endGeoPos.lat(), endGeoPos.z()));
// FilterManagement:
handleSymbolAppearanceSettings(mapObj, ddsData);
TRACE_LOG(m_logger) << LOGFUNCTION << " END" << " id=" << hitlineId;
return true;
}
void HitlineInfo2SituationMap::onSymbolAppearanceSettingsChanged(FilterManagement::SymbolAppearanceSettings::Part part)
{
if ((part != FilterManagement::SymbolAppearanceSettings::Part::All) &&
(part != FilterManagement::SymbolAppearanceSettings::Part::Symbol))
return;
// Part::All || Part::Symbol
const bool relevant = symbolAppearanceSettingsChangesAreRelevant(m_symbolAppearanceSettings->settings());
m_currentSymbolSettings = m_symbolAppearanceSettings->settings();
if (!relevant)
return;
handleSymbolAppearanceSettings();
}
bool HitlineInfo2SituationMap::symbolAppearanceSettingsChangesAreRelevant(const FilterManagement::SymbolAppearanceSettings::Settings &newSas) const
{
return qFuzzyCompare(m_currentSymbolSettings.symbolSettings.symbolScale, newSas.symbolSettings.symbolScale) ||
(m_currentSymbolSettings.symbolSettings.symbolPartyAppearance != newSas.symbolSettings.symbolPartyAppearance) ||
(m_currentSymbolSettings.symbolSettings.hitLineDisplayLengthMSec != newSas.symbolSettings.hitLineDisplayLengthMSec||
(m_currentSymbolSettings.symbolSettings.lrfLineDisplayLengthMSec != newSas.symbolSettings.lrfLineDisplayLengthMSec)||
(m_currentSymbolSettings.symbolSettings.ltdLineDisplayLengthMSec != newSas.symbolSettings.ltdLineDisplayLengthMSec));
}
void HitlineInfo2SituationMap::handleSymbolAppearanceSettings()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START" << " m_ddsDataContainer.size()=" << m_ddsDataContainer.size();
for (const ParticipantManagement::HitLineInfo &hitline : qAsConst(m_ddsDataContainer))
{
RefPointer<MAP_T> mapObj = getMapObjectOfSimId(hitline.id());
if (!mapObj.valid())
continue;
handleSymbolAppearanceSettings(mapObj, hitline);
} // for
TRACE_LOG(m_logger) << LOGFUNCTION << " END" << " m_ddsDataContainer.size()=" << m_ddsDataContainer.size();
}
void HitlineInfo2SituationMap::handleSymbolAppearanceSettings(RefPointer<MAP_T> mapObj, const Sim2SituationMap::DDS_T &ddsData)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START" << " ddsData.id()=" << ddsData.id()
<< ", mapObj = " << mapObj->debugInfo();
const FilterManagement::SymbolAppearanceSettings::Settings &filterSettings = m_symbolAppearanceSettings->settings();
mapObj->setScale(filterSettings.symbolSettings.symbolScale);
bool bUncertain = false;
const bool isVisi = isVisible(ddsData, &bUncertain);
if (bUncertain)
{
// N. Thoden, 25.09.2020
// Do NOT store mapObj at lambda! The lambda will be destroyed AFTER
// HitlineInfo2SituationMap and the ESRI map. So the RefPointer is still
// holding a MapObject. The destruction will fail due to non-existing ESRI map...
QTimer::singleShot(200, this, [this, ddsData]()
{
RefPointer<MAP_T> mapObj = getMapObjectOfSimId(ddsData.id());
if (!mapObj.valid())
return;
handleSymbolAppearanceSettings(mapObj, ddsData);
});
}
if (mapObj->visibility() != isVisi)
{
mapObj->setVisibility(isVisi);
if (!mapObj->updateView())
WARNING_LOG(m_logger) << LOGFUNCTION << " updateView failed,"
<< " mapObj = " << mapObj->debugInfo();
}
TRACE_LOG(m_logger) << LOGFUNCTION << " END" << " ddsData.id()=" << ddsData.id()
<< ", mapObj = " << mapObj->debugInfo();
}
bool HitlineInfo2SituationMap::isVisible(const Sim2SituationMap::DDS_T &ddsData, bool *bUncertain) const
{
return
visibleByBldgHitlines(ddsData) &&
visibleBySymbolPartyAppearance(ddsData) &&
visibleByHitLineDisplayLength(m_pluginProvider->partitionTime(), ddsData) && // partitionTime() -> msec
visibleByParticipants(ddsData, bUncertain);
}
bool HitlineInfo2SituationMap::visibleBySymbolPartyAppearance(const Sim2SituationMap::DDS_T &ddsData) const
{
const FilterManagement::SymbolAppearanceSettings::Settings &filterSettings = m_symbolAppearanceSettings->settings();
const auto spa = filterSettings.symbolSettings.symbolPartyAppearance.value(ddsData.originatorPartyId());
return spa.isVisible;
}
bool HitlineInfo2SituationMap::visibleByParticipants(const Sim2SituationMap::DDS_T &ddsData, bool *bUncertain) const
{
// show hitline only if
// ddsData.originatorParticipantId() && ddsData.injuryParticipantId() are visible:
if (!m_participant2SituationMap)
return true;
bool bParticipant1Exists = true;
bool bParticipant2Exists = true;
bool visi =
m_participant2SituationMap->isParticipantVisible(ddsData.originatorParticipantId(), &bParticipant1Exists) &&
m_participant2SituationMap->isParticipantVisible(ddsData.injuryParticipantId(), &bParticipant2Exists);
if ((!bParticipant1Exists || !bParticipant2Exists) && bUncertain)
*bUncertain = true;
return visi;
}
bool HitlineInfo2SituationMap::visibleByBldgHitlines(const Sim2SituationMap::DDS_T &ddsData) const
{
auto itBuildingHit = m_buildingHits.constFind(ddsData.injuryBuildingId());
if (itBuildingHit != m_buildingHits.constEnd())
{
const QVector<BuildingHit> &bHits = itBuildingHit.value();
// get displayLength according chargeTypeId:
qint64 displayLength = m_currentSymbolSettings.symbolSettings.hitLineDisplayLengthMSec;
const SpecialChargeType sct = m_pdmHandler->isSpecialChargeType(ddsData.chargeTypeId());
switch (sct)
{
case SpecialChargeType::LRF:
displayLength = m_currentSymbolSettings.symbolSettings.lrfLineDisplayLengthMSec;
break;
case SpecialChargeType::LTD:
displayLength = m_currentSymbolSettings.symbolSettings.ltdLineDisplayLengthMSec;
break;
case SpecialChargeType::NoneSpecial:
default:
// empty
break;
} // switch
// player is in a building which got hit in the last few minutes
for (const BuildingHit &bh : bHits)
{
if (bh.chargeTypeId == ddsData.chargeTypeId() &&
bh.originatorParticipantId == ddsData.originatorParticipantId() &&
ddsData.sampleTime() - displayLength < bh.sampleTime)
{
DEBUG_LOG(m_logger) << "Not showing participant hitline " << ddsData << " since there is already a hitline on the building";
return false;
}
}
}
return true;
}
bool HitlineInfo2SituationMap::visibleByHitLineDisplayLength(const qint64 newPartitionTime, const Sim2SituationMap::DDS_T &ddsData) const
{
const qint64 stateTime = ddsData.sampleTime();
qint64 displayLength = m_currentSymbolSettings.symbolSettings.hitLineDisplayLengthMSec;
const SpecialChargeType sct = m_pdmHandler->isSpecialChargeType(ddsData.chargeTypeId());
switch (sct)
{
case SpecialChargeType::LRF:
displayLength = m_currentSymbolSettings.symbolSettings.lrfLineDisplayLengthMSec;
break;
case SpecialChargeType::LTD:
displayLength = m_currentSymbolSettings.symbolSettings.ltdLineDisplayLengthMSec;
break;
case SpecialChargeType::NoneSpecial:
default:
// empty
break;
} // switch
DEBUG_LOG(m_logger) << LOGFUNCTION
<< " newPartitionTime = " << newPartitionTime
<< " stateTime = " << stateTime
<< " age = " << (newPartitionTime - stateTime)
<< " SpecialChargeType = " << sct
<< " displayLengthMSec = " << displayLength;
if (displayLength <= 0)
return false;
return (newPartitionTime - stateTime) <= displayLength;
}
void HitlineInfo2SituationMap::onPartitionTimeChanged()
{
handleSymbolAppearanceSettings();
}
}
@@ -0,0 +1,110 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "sim_to_situation_map_tmpl.h"
#include "participant_to_map.h" // participantIsVisible
#include <MapObjects/hit_line.h>
#include <Buildings/bld_dtc.h>
#include <FilterManagement/flt_dtc.h>
#include <ParticipantManagement/ppm_dtc.h>
#include <ParticipantManagement/ppm_participant_info_gui_plugin_interface.h>
#include <memory>
namespace SituationMap
{
// forward:
class PdmHandler;
class HitlineInfo2SituationMap final : public Sim2SituationMap<ParticipantManagement::HitLineInfo, SituationMap::HitLine>
, protected DdsFilterHandling<SituationMap::HitLine>
{
Q_OBJECT
using BaseClass = SituationMap::Sim2SituationMap<ParticipantManagement::HitLineInfo, SituationMap::HitLine>;
using FilterClass = DdsFilterHandling<SituationMap::HitLine>;
public:
HitlineInfo2SituationMap(PdmHandler *pdmHandler,
Participant2SituationMap *participant2SituationMap,
ObjectFactory &objFac,
const QString &layername,
int drawOrder,
const char *loggerName);
~HitlineInfo2SituationMap();
bool init(PluginProvider *pluginProvider);
bool run() override;
void stop() override;
bool isElapsed(const ParticipantManagement::HitLineInfo &ddsData) const override;
bool mapObjectsClicked(const QVector<UniqueMapId> &uniqueMapIds) override;
bool unifiedMapObjectData(UniqueMapId uniqueMapId, UnifiedMapObjectData &umodOut) const override;
QString chargeTypeIdentifier(const int32_t originatorChargeTypeId) const;
protected Q_SLOTS:
bool onHitLineInfoChanged(const Sim2SituationMap::DDS_T &ddsData, DataModification modType = DataModification::eAdded);
void onBuildingHitlineInfoChanged(const Buildings::BuildingHitLineInfo &data, DataModification modType);
void onCleanupBuildingHitlines();
protected:
bool isVisible(const Sim2SituationMap::DDS_T &ddsData, bool *bUncertain) const;
bool visibleBySymbolPartyAppearance(const Sim2SituationMap::DDS_T &ddsData) const;
bool visibleByParticipants(const Sim2SituationMap::DDS_T &ddsData, bool *bUncertain) const;
bool visibleByBldgHitlines(const Sim2SituationMap::DDS_T &ddsData) const;
bool visibleByHitLineDisplayLength(const qint64 newPartitionTime, const DDS_T &ddsData) const;
void onPartitionTimeChanged();
bool createElement(const DDS_T &ddsData) override;
int32_t getSimId(const Sim2SituationMap::DDS_T &ddsData) const override;
bool updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj) override;
void onSymbolAppearanceSettingsChanged(FilterManagement::SymbolAppearanceSettings::Part part) override;
bool symbolAppearanceSettingsChangesAreRelevant(const FilterManagement::SymbolAppearanceSettings::Settings &newSas) const override;
void handleSymbolAppearanceSettings(RefPointer<MAP_T> &mapObj) override
{
if (!mapObj.valid())
return;
const int simId = m_uniqueMapId2SimId.value(mapObj->uniqueMapId());
handleSymbolAppearanceSettings(mapObj, m_ddsDataContainer.value(simId));
}
void handleSymbolAppearanceSettings();
void handleSymbolAppearanceSettings(RefPointer<MAP_T> mapObj, const Sim2SituationMap::DDS_T &ddsData);
private:
PluginProvider *m_pluginProvider = nullptr;
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc;
PdmHandler *m_pdmHandler = nullptr;
QPointer<Participant2SituationMap> m_participant2SituationMap;
struct BuildingHit
{
int64_t sampleTime = 0;
int originatorParticipantId = 0;
int chargeTypeId = 0;
};
QHash<int, QVector<BuildingHit>> m_buildingHits;
QTimer *m_pBuildingHitlineCleanupTimer = nullptr;
};
} // namespace
@@ -0,0 +1,27 @@
/**
* @RDE_HEADER@
* Decleration of enum MapObjectType
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
namespace SituationMap
{
enum class MapObjectType {
MOT_Undefined,
MOT_Participant,
MOT_Aes,
MOT_Building,
MOT_Bridge,
MOT_MountingPoint,
MOT_GuezIed,
MOT_TrainingArea,
MOT_SpecialArea,
MOT_ShootbackArea
};
} // namespace
@@ -0,0 +1,445 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#include "mine_area_null_to_map.h"
#include <AreaEffectSimulation/Utils/polygons.h> // for mineAreaSegment
#include <AreaEffectSimulation/Utils/ddsdbconvert.h> // for mineAreaSegment
#include <ProjectDataManagement/pdm_dtc.h>
#include <LtsUtilsCore/dds_bitarray.h>
#include <SituationMap/Symbology/sidc_codec.h>
namespace SituationMap
{
DusMineStateProxy::DusMineStateProxy(QObject *parent)
: BaseClass(parent)
, m_lastDusMineState()
, m_lastItemView()
, m_logger(getLogger("DusMineStateProxy"))
{
}
bool DusMineStateProxy::init(PluginProvider *pluginProvider)
{
if (!pluginProvider)
return false;
m_aesDtc = pluginProvider->aesDtc();
return m_aesDtc != nullptr;
}
bool DusMineStateProxy::run()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (!m_aesDtc)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no dtc";
return false;
}
// connecting to relevant topics
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::dusMineStateChanged,
this, static_cast<bool (DusMineStateProxy::*)(const AreaEffectSimulation::DusMineState&, DataModification)>(&DusMineStateProxy::handleChanged), Qt::UniqueConnection);
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::aesItemViewChanged,
this, static_cast<bool (DusMineStateProxy::*)(const AreaEffectSimulation::AesItemView&, DataModification)>(&DusMineStateProxy::handleChanged), Qt::UniqueConnection);
const std::function<bool(const AreaEffectSimulation::DusMineState &)> cbDusMineState = [this] (const AreaEffectSimulation::DusMineState &data) -> bool
{ return handleChanged(data, DataModification::eAdded); };
m_aesDtc->dusMineStates(cbDusMineState);
const std::function<bool(const AreaEffectSimulation::AesItemView &)> cbAesItemView = [this] (const AreaEffectSimulation::AesItemView &data) -> bool
{ return handleChanged(data, DataModification::eAdded); };
m_aesDtc->aesItemViews(cbAesItemView);
return true;
}
void DusMineStateProxy::stop()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
this->disconnect();
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
bool DusMineStateProxy::dusMineStateAndPositionDatas(const std::function<void (const DusMineStateAndPositionData &)> &cb)
{
if (m_map.isEmpty())
return false;
for (auto it = m_map.constBegin(); it != m_map.constEnd(); ++it)
cb(it.value());
return true;
}
bool DusMineStateProxy::dusMineStateAndPositionDatas(const std::function<bool (const DusMineStateAndPositionData &)> &cb)
{
if (m_map.isEmpty())
return false;
for (auto it = m_map.constBegin(); it != m_map.constEnd(); ++it)
if (cb(it.value()))
return true;
return false;
}
bool DusMineStateProxy::handleChanged(const AreaEffectSimulation::DusMineState &ddsData, DataModification modType)
{
Q_UNUSED(modType);
// only id 0 is valid for Null Area
if (ddsData.id() != 0)
return false;
TRACE_LOG(m_logger) << LOGFUNCTION << " START, ddsData.id()=" << ddsData.id()
<< " ddsData.mines().size() = " << ddsData.mines().size();
if (modType == DataModification::eRemoved)
m_lastDusMineState = AreaEffectSimulation::DusMineState();
else
m_lastDusMineState = ddsData;
return publishNewMap();
}
bool DusMineStateProxy::handleChanged(const AreaEffectSimulation::AesItemView &ddsData, DataModification modType)
{
Q_UNUSED(modType);
// only AtMineAreaSingleMines = 15
if (ddsData.id() != AreaEffectSimulation::AesType::AtMineAreaSingleMines)
return false;
TRACE_LOG(m_logger) << LOGFUNCTION << " START, ddsData.id()=" << ddsData.id()
<< " ddsData.form().size() = " << ddsData.form().size();
if (modType == DataModification::eRemoved)
m_lastItemView = AreaEffectSimulation::AesItemView();
else
m_lastItemView = ddsData;
return publishNewMap();
}
bool DusMineStateProxy::publishNewMap()
{
if (m_lastItemView.setId() != m_lastDusMineState.setId()) // got matching ItemView? 'synchronizing'
return false;
const QMap<int32_t, DusMineStateAndPositionData> &mapContVeryNew = getFromDds();
QMapIterator<int32_t, DusMineStateAndPositionData> mapItRetrieved(mapContVeryNew);
// iterate over all just retrieved:
while (mapItRetrieved.hasNext())
{
mapItRetrieved.next();
if (m_map.contains(mapItRetrieved.key()))
emit dusMineStateChanged(mapItRetrieved.value(), DataModification::eModified);
else
emit dusMineStateChanged(mapItRetrieved.value(), DataModification::eAdded);
} // while
// are some entries removed?
QMapIterator<int32_t, DusMineStateAndPositionData> mapItRemoved(m_map);
// iterate over all just retrieved:
while (mapItRemoved.hasNext())
{
mapItRemoved.next();
if (! mapContVeryNew.contains(mapItRemoved.key())) // -> removed
emit dusMineStateChanged(mapItRemoved.value(), DataModification::eRemoved);
} // while
// update own container:
m_map = mapContVeryNew;
DEBUG_LOG(m_logger) << "Publishing new dus-mine map to situationMap adapter";
return true;
}
const QMap<int32_t, DusMineStateAndPositionData> DusMineStateProxy::getFromDds()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START, ddsData.id()=" << m_lastDusMineState.id()
<< " ddsData.mines().size() = " << m_lastDusMineState.mines().size();
QMap<int32_t, DusMineStateAndPositionData> mapCont;
const auto size = m_lastDusMineState.mines().size();
const auto &mines = m_lastDusMineState.mines();
if (m_logger.isDebugEnabled())
{
int idx = 0;
for (const AreaEffectSimulation::DusMine &mine : mines)
{
DEBUG_LOG(m_logger) << LOGFUNCTION
<< " idx=" << idx++
<< ", eqId=" << mine.eqId()
<< ", chargeTypeId=" << mine.chargeTypeId();
}
}
// ItemView
if (size != m_lastItemView.form().size())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " ddsData.id()=" << m_lastDusMineState.id()
<< " size does not match"
<< " ddsData.mines().size() = " << mines.size()
<< " itemView.form().size() = " << m_lastItemView.form().size();
return mapCont;
}
DEBUG_LOG(m_logger) << LOGFUNCTION << " ddsData.id()=" << m_lastDusMineState.id()
<< " size ::"
<< " ddsData.mines().size() = " << mines.size()
<< " itemView.form().size() = " << m_lastItemView.form().size();
for (size_t i = 0; i < size; ++i)
{
const AreaEffectSimulation::DusMine &dusMine = mines[i];
const Core::GeoPosition2D &pos = m_lastItemView.form().at(i);
DusMineStateAndPositionData dmsDdsData(dusMine.eqId(),
{dusMine.chargeTypeId(),0,0},
dusMine.triggered(),
pos
);
DEBUG_LOG(m_logger) << LOGFUNCTION << " i=" << i << ", id/eqId=" << dusMine.eqId() << ", pos=" << pos;
mapCont.insert(dusMine.eqId(), dmsDdsData);
} // for
return mapCont;
}
bool DusMineStateProxy::getItemView(AreaEffectSimulation::AesItemView &itemView)
{
// AtMineAreaSingleMines = 15
int aesType = static_cast<int>(AreaEffectSimulation::AesType::inner_enum::AtMineAreaSingleMines); // 15
const AreaEffectSimulation::AesItemView &localItemView = m_aesDtc->aesItemView(aesType);
if (localItemView.id() != aesType)
return false;
itemView = localItemView;
return true;
}
//------------------------------------------------------------------------------
// class MineAreaNull2SituationMap -
// typical XY2SituationMap, supplied by DusMineStateProxy which is connected to DDS
//------------------------------------------------------------------------------
bool MineAreaNull2SituationMap::init(PluginProvider *pluginProvider)
{
if (!BaseClass::init(pluginProvider))
return false;
if (!m_dusMineStateProxy)
{
m_dusMineStateProxy = new DusMineStateProxy(this);
if (!m_dusMineStateProxy->init(pluginProvider))
ERROR_LOG(m_logger) << LOGFUNCTION << " init failed for DusMineStateProxy";
}
return true;
}
bool MineAreaNull2SituationMap::run()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (!m_dusMineStateProxy)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no DusMineStateProxy";
return false;
}
m_dusMineStateProxy->run();
connect(m_dusMineStateProxy, &DusMineStateProxy::dusMineStateChanged,
this, &MineAreaNull2SituationMap::handleChanged, Qt::UniqueConnection);
// get:
m_dusMineStateProxy->dusMineStateAndPositionDatas([this](const DusMineStateAndPositionData & data)
{
handleChanged(data, DataModification::eAdded);
});
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
void MineAreaNull2SituationMap::stop()
{
if (m_dusMineStateProxy)
m_dusMineStateProxy->stop();
}
bool MineAreaNull2SituationMap::mapObjectsClicked(const QVector<UniqueMapId> &uniqueMapIds)
{
auto sp = m_aesInfoIfc.lock();
if (!sp)
return false;
const QVector<int32_t> &simIds = this->uniqueMapIds2SimIds(uniqueMapIds);
if (simIds.isEmpty())
return true;
sp->showInfoWindow(simIds, AreaEffectSimulation::AesType_def::AtMineAreaSingleMines);
return true;
}
bool MineAreaNull2SituationMap::unifiedMapObjectData(UniqueMapId uniqueMapId, UnifiedMapObjectData &umodOut) const
{
if (!m_dusMineStateProxy)
return false;
int32_t simIdOut = -1;
if (!this->uniqueMapId2SimId(uniqueMapId, simIdOut))
return false;
umodOut = UnifiedMapObjectData();
RefPointer<MAP_T> mapObj = this->getMapObjectOfUniqueMapId(uniqueMapId);
if (mapObj.valid())
umodOut.m_symDataToRender = mapObj->symbolDataToRender();
const auto cb = [simIdOut, &umodOut](const DusMineStateAndPositionData &data) -> bool
{
if (data.id() == simIdOut)
{
umodOut.m_description1 = QString::number(data.id()); // == eqId
umodOut.m_description2 = data.triggered() ? tr("disarmed") : tr("armed");
return true; // break loop
}
return false;
};
// sonst kann sich der compiler nicht zwischen bool und void entscheiden... !?
std::function<bool(const DusMineStateAndPositionData &data)> cb1 = cb;
return m_dusMineStateProxy->dusMineStateAndPositionDatas(cb1);
}
bool MineAreaNull2SituationMap::updateVisibility(const Aes2SituationMap::DDS_TYPE &ddsData, RefPointer<Aes2SituationMap::MAP_TYPE> mapObj)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START, simId=" << getSimId(ddsData);
if (!BaseClass::updateVisibility(ddsData, mapObj))
{
ERROR_LOG(m_logger) << LOGFUNCTION << " BaseClass::updateVisibility failed, simId=" << getSimId(ddsData);
return false;
}
AreaEffectSimulation::AesItemView itemView;
bool bUpdateView = false;
if (m_displayFilter )
{
mapObj->setVisibility(m_displayFilter->showNotTriggeredCDMine()
&& this->isVisibleByFilter(ddsData));
bUpdateView = true;
}
if (bUpdateView && !mapObj->updateView())
ERROR_LOG(m_logger)<< LOGFUNCTION << " simId = " << getSimId(ddsData) << " XXXX updateView failed";
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
void MineAreaNull2SituationMap::onAesDisplayFilterChanged(AreaEffectSimulation::AesType aesType)
{
// GUEZ: Ausgelöste DUS-Minen werden *grundsätzlich* bis zum Reaktivieren angezeigt (Jan 2021)
// For AHTC is has to be verified
if (AreaEffectSimulation::AesType_def::AtMineArea != aesType.underlying())
return;
const auto cb = [this](const DDS_TYPE &data) -> bool
{
// return false -> do not stop looping over items
if (data.isDeleted())
return false;
this->updateVisibility(data);
return false;
};
iterateAesData(cb);
}
bool MineAreaNull2SituationMap::updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
// show just the ObjectAppearance::Technical
mapObj->setVisibility(ObjectAppearance::Tactical, false);
const int32_t simId_eqId = ddsData.id(); // eqId
// SIDC:
SymbolData symData;
symData.sidc = AdvancedSymbology::SidcCodec::encodeComplete( mapObj->symbologyType(), "10011500002101000000" ); // 10011500002101000000 - LAND MINE
symData.color = Qt::yellow;
symData.size = 1.0;
mapObj->setSymbol(symData);
// State (display as injury)
SituationMap::Injury injury = SituationMap::Injury::NoInjury;
if (ddsData.triggered())
injury = SituationMap::Injury::TotalKill;
mapObj->setInjury(injury, QColor(Qt::black));
// don't show active DUS mines on map - don't know if they are still there
// where they were triggered the last time
//const bool isDusMine = m_pluginProvider->pdmDtc()->isDus(ddsData.chargeTypeId());
//mapObj->setVisibility(isDusMine ? ddsData.triggered() : true);
mapObj->setVisibility(true);
// Position:
mapObj->setOrigin(Point3D(ddsData.position().lon(), ddsData.position().lat(), .0));
// show eqId as string:
mapObj->setTextModifier(Participant::TextModifier::M_HigherFormation, QString::number(simId_eqId));
updateVisibility(ddsData, mapObj);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
bool MineAreaNull2SituationMap::symbolAppearanceSettingsChangesAreRelevant(const FilterManagement::SymbolAppearanceSettings::Settings &newSas) const
{
return (m_currentSymbolSettings.symbolSettings.symbolScale != newSas.symbolSettings.symbolScale) ||
(m_currentSymbolSettings.symbolSettings.symbolTransparency != newSas.symbolSettings.symbolTransparency)
// || (m_currentSymbolSettings.symbolSettings.symbolPartyAppearance != newSas.symbolSettings.symbolPartyAppearance)
;
}
void MineAreaNull2SituationMap::handleSymbolAppearanceSettings(RefPointer<MAP_T> &mapObj)
{
// TextModifier? No Party -> no switch....
// mapObj->setTextModifierVisibility(Participant::TextModifier::T_UniqueDesignation, l.showDesignator);
// mapObj->setTextModifierVisibility(Participant::TextModifier::M_HigherFormation, l.showTacticalIdentifier);
mapObj->setUserSymbolOpacity(1.0f - m_currentSymbolSettings.symbolSettings.symbolTransparency);
mapObj->setScale(m_currentSymbolSettings.symbolSettings.symbolScale);
}
}
@@ -0,0 +1,224 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "aes_to_situation_map_tmpl.h"
#include <Plugins/AreaEffectSimulation/aes_data_plugin_interface.h>
#include <MapObjects/participant.h>
#include <QObject>
namespace SituationMap
{
//------------------------------------------------------------------------------
// class AesItemProxy
// to support/imitate typical ddsData structure
//------------------------------------------------------------------------------
class AesItemProxy
{
public:
//----------------------------------------------------------------------------
class EffectStart final // replica
{
public:
static bool is_set() { return false; }
static qint64 get() { return 0; }
};
//----------------------------------------------------------------------------
class PartyId final // replica
{
public:
static bool is_set() { return false; }
static qint64 get() { return -1; }
};
//----------------------------------------------------------------------------
explicit AesItemProxy(int32_t id = 0,
const AreaEffectSimulation::ChargeStruct &chargeStruct = {-1,0,0},
const Core::GeoPosition2D &form = Core::GeoPosition2D())
: m_id_param(id),
m_chargeStruct(chargeStruct),
m_form_param(form)
{}
virtual ~AesItemProxy() = default;
int32_t id() const { return m_id_param; }
void setId(const int32_t &value) { m_id_param = value; }
static std::string name() { return std::string(); }
static bool isDeleted() { return false; }
static EffectStart effectStart() { return {}; }
static PartyId partyId() { return {}; }
static bool isCentral() { return false;}
static AreaEffectSimulation::AesEffectState effectStateId() { return AreaEffectSimulation::AesEffectState_def::EsCreated;}
AreaEffectSimulation::ChargeStruct chargeStruct() const { return m_chargeStruct; }
int chargeTypeId() const { return m_chargeStruct.chargeTypeId(); }
static qint64 effectDuration() { return -1; }
Core::GeoPosition2D position() const { return m_form_param; }
private:
int32_t m_id_param;
AreaEffectSimulation::ChargeStruct m_chargeStruct;
Core::GeoPosition2D m_form_param;
};
//------------------------------------------------------------------------------
// class DusMineStateAndPositionData
//------------------------------------------------------------------------------
class DusMineStateAndPositionData : public AesItemProxy
{
public:
using BaseClass = AesItemProxy;
//----------------------------------------------------------------------------
explicit DusMineStateAndPositionData(int32_t id = 0,
const AreaEffectSimulation::ChargeStruct &chargeStruct = {-1,0,0},
bool triggered = false,
const Core::GeoPosition2D &form = Core::GeoPosition2D()
)
: BaseClass(id, chargeStruct, form),
m_triggered(triggered)
{}
virtual ~DusMineStateAndPositionData() = default;
bool triggered() const { return m_triggered; }
void setTriggered(bool onOff) { m_triggered = onOff; }
private:
bool m_triggered;
};
//------------------------------------------------------------------------------
// class DusMineStateProxy
//------------------------------------------------------------------------------
class MineAreaNull2SituationMap; // forward
class DusMineStateProxy final : public QObject
{
Q_OBJECT
public:
using BaseClass = QObject;
explicit DusMineStateProxy(QObject *parent = nullptr);
~DusMineStateProxy() = default;
bool init(PluginProvider *pluginProvider);
bool run();
void stop();
virtual bool dusMineStateAndPositionDatas(const std::function<void(const DusMineStateAndPositionData &data)> &cb);
virtual bool dusMineStateAndPositionDatas(const std::function<bool(const DusMineStateAndPositionData &data)> &cb);
Q_SIGNALS:
void dusMineStateChanged(const DusMineStateAndPositionData &dusMineStateAndPositionData, DataModification modType);
protected:
bool handleChanged(const AreaEffectSimulation::DusMineState &ddsData, DataModification modType);
bool handleChanged(const AreaEffectSimulation::AesItemView &ddsData, DataModification modType);
bool publishNewMap();
const QMap<int32_t, DusMineStateAndPositionData> getFromDds();
// bool getTriggeredImpacts(AreaEffectSimulation::TriggeredImpacts &triggeredImpacts);
bool getItemView(AreaEffectSimulation::AesItemView &itemView);
std::shared_ptr<AreaEffectSimulation::Interface::Dtc> m_aesDtc;
AreaEffectSimulation::DusMineState m_lastDusMineState;
AreaEffectSimulation::AesItemView m_lastItemView;
QMap<int32_t, DusMineStateAndPositionData> m_map;
QSharedPointer<MineAreaNull2SituationMap> m_mineAreaNull2SituationMap;
LOGGER_T m_logger; ///< Interface of the Logging-Facility
};
//------------------------------------------------------------------------------
// class MineAreaNull2SituationMap -
// typical XY2SituationMap, supplied by DusMineStateProxy which is connected to DDS
//------------------------------------------------------------------------------
class MineAreaNull2SituationMap;
template <>
struct Aes2SituationMapTraits<MineAreaNull2SituationMap>
{
using DDS_TYPE = DusMineStateAndPositionData;
using MAP_TYPE = SituationMap::Participant;
static const AreaEffectSimulation::AesType_def::type aesType = AreaEffectSimulation::AesType_def::AtMineArea; // not AtDusSingleMine
};
class MineAreaNull2SituationMap final : public Aes2SituationMap<MineAreaNull2SituationMap>
{
Q_OBJECT
public:
using BaseClass = SituationMap::Aes2SituationMap<MineAreaNull2SituationMap>;
using BaseClass::BaseClass;
bool init(PluginProvider *pluginProvider) override;
bool run() override;
void stop() override;
bool iterateAesData(const std::function<bool(const DDS_TYPE &data)> &cb) const
{
// [GUEZE-3258, GUEZE-3442] Performance, Filterupdate langsam
// nullptr check is important now:
if (!m_dusMineStateProxy)
return false;
return m_dusMineStateProxy->dusMineStateAndPositionDatas(cb);
}
bool mapObjectsClicked(const QVector<UniqueMapId> &uniqueMapIds) override;
bool unifiedMapObjectData(UniqueMapId uniqueMapId, UnifiedMapObjectData &umodOut) const override;
using BaseClass::updateVisibility; // hidden overloaded virtual function
bool updateVisibility(const DDS_TYPE &ddsData, RefPointer<MAP_TYPE> mapObj) override;
// bool updateVisibility(const DDS_TYPE &data, RefPointer<MAP_TYPE> mapObj) override;
protected:
void onAesDisplayFilterChanged(AreaEffectSimulation::AesType aesType) override;
bool updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj) override;
bool updateSingleMines(const int simId,
RefPointer<MAP_T> mapObj);
bool symbolAppearanceSettingsChangesAreRelevant(const FilterManagement::SymbolAppearanceSettings::Settings &newSas) const override;
void handleSymbolAppearanceSettings(RefPointer<MAP_T> &mapObj) override;
protected Q_SLOTS:
private:
DusMineStateProxy *m_dusMineStateProxy = nullptr;
};
} // namespace
@@ -0,0 +1,482 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#include "mine_area_to_map.h"
#include <AreaEffectSimulation/Utils/polygons.h> // for mineAreaSegment
#include <AreaEffectSimulation/Utils/ddsdbconvert.h> // for mineAreaSegment
#include <ProjectDataManagement/pdm_dtc.h>
#include <LtsUtilsCore/dds_bitarray.h>
/*
relevant topics and relationship:
MineArea
(id, name, effect{Start,Duration}, boundingBox, Segments@Key==>=0==>FillPattern}
1st AesItemView/boundary - aesItemId==id && aesTypeId==AtMineArea (aesItemViewFromEntityId)
(form->SingleSegments@Key=-1==>NoFill)
2nd AesItemView/mines - aesItemId==id && aesTypeId==AtMineAreaSingleMines (onTriggeredImpactsChanged)
(form->ImpactsPositions)
TriggeredImpacts - aesItemId==id && aesTypeId==AtMineAreaSingleMines
(bitfield,impactCount)
required 2nd AesItemView/mines
---
Semantics:
MineArea & 1st AesItemView -> mainGeometry, singleSements
TriggeredImpacts & 2nd AesItemView -> Impacts(De)Activated
// Main Szenario:
Sze 1: MineArea arrived but no according 1st AesItemView/boundary
2nd AesItemView/mines and TriggeredImpacts arrives
1st AesItemView/boundary arrives
setPositionsMine evaluates according visibility: yes, via onMapExtentChanged
*/
namespace SituationMap
{
bool MineArea2SituationMap::run()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (!m_aesDtc)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no dtc";
return false;
}
m_triggeredImpacts.clear();
m_aesItemViewForImpacts.clear();
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::mineAreaChanged,
this, &MineArea2SituationMap::handleChanged, Qt::UniqueConnection);
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::triggeredImpactsChanged,
this, &MineArea2SituationMap::onTriggeredImpactsChanged, Qt::UniqueConnection);
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::aesItemViewChanged,
this, &MineArea2SituationMap::onAesItemViewChanged, Qt::UniqueConnection);
// get:
m_aesDtc->mineAreas([this](const AreaEffectSimulation::MineArea &data)
{
handleChanged(data, DataModification::eAdded);
});
m_aesDtc->triggeredImpactss([this](const AreaEffectSimulation::TriggeredImpacts &data)
{
onTriggeredImpactsChanged(data, DataModification::eAdded);
});
m_aesDtc->aesItemViews([this](const AreaEffectSimulation::AesItemView &data)
{
onAesItemViewChanged(data, DataModification::eAdded);
});
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return BaseClass::run();
}
bool MineArea2SituationMap::updateVisibility(const DDS_TYPE &data, RefPointer<MAP_TYPE> mapObj)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START, simId=" << getSimId(data);
// FATAL_LOG(m_logger) << LOGFUNCTION << " START, simId=" << getSimId(data);
// FATAL_LOG(m_logger) << LOGFUNCTION << " START, mapObj.get()=" << mapObj.get();
// FATAL_LOG(m_logger) << LOGFUNCTION << " START, mapObj->visibility()=" << mapObj->visibility();
// FATAL_LOG(m_logger) << LOGFUNCTION << " START, m_displayFilter.get()=" << m_displayFilter.get();
if (!BaseClass::updateVisibility(data, mapObj))
{
ERROR_LOG(m_logger) << LOGFUNCTION << " BaseClass::updateVisibility failed, simId=" << getSimId(data);
return false;
}
// only show details if main object is also visible
// NLDEVCTRL-445: Projektion Filter und Kartenausschnitt : avoid coredump (no m_displayFilter)
bool bDisplayFilterShowDetails = true;
if (m_displayFilter)
bDisplayFilterShowDetails = m_displayFilter->showDetails(AreaEffectSimulation::AesType_def::AtMineArea);
const bool bShowDetails = mapObj->visibility() && bDisplayFilterShowDetails;
bool bUpdateView = false;
if (bShowDetails != mapObj->mineVisibility(MineField::MineState::Activated))
{
mapObj->setMineVisibility(MineField::MineState::Activated, bShowDetails);
bUpdateView = true;
}
if (bShowDetails != mapObj->mineVisibility(MineField::MineState::DeActivated))
{
mapObj->setMineVisibility(MineField::MineState::DeActivated, bShowDetails);
bUpdateView = true;
}
if (bUpdateView)
if (!mapObj->updateView())
ERROR_LOG(m_logger) << LOGFUNCTION << " simId = " << getSimId(data) << " XXXX updateView failed";
return true;
}
bool MineArea2SituationMap::updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
// show just the ObjectAppearance::Technical
mapObj->setVisibility(ObjectAppearance::Tactical, false);
const int32_t simId = ddsData.id();
mapObj->setIdentifier(QString::fromStdString(ddsData.name()));
// if partyId is not set (like B,C agent), use default color
if (ddsData.partyId().is_set())
mapObj->setPartyId(ddsData.partyId().get());
mapObj->setAesState(effectState2aesState(ddsData.effectStateId().underlying()));
// 1st AesItemView for boundary:
{
AreaEffectSimulation::AesItemView itemView;
if (m_aesDtc->aesItemViewFromEntityId(simId, AreaEffectSimulation::AesType::AtMineArea, itemView))
{
this->updateGeometry(itemView, mapObj);
} else {
DEBUG_LOG(m_logger) << LOGFUNCTION
<< " no AesItemView (AtMineArea) found"
<< ", simId = " << simId
<< ", provide fallBackGeometry";
// provide fallbackGeometry to avoid errorMsg like 'incorrect number of positions'
mapObj->setPositions({{0.0, 0.0, .0},
{0.0, 0.1, .0},
{0.1, 0.1, .0},
{0.1, 0.0, .0}});
// do not return here, perform stuff like updateVisibility and so on
}
const QVector<AreaEffectSimulation::Database::AesMineAreaSegment> segments(AreaEffectSimulation::DdsDbConvert::mineAreaSegments(ddsData));
const QVector<QPolygonF> singleSegments(AreaEffectSimulation::Polygons::mineAreaSingleSegments(segments, ddsData.width(), ddsData.isCenterLine()));
QList<int> keysInUse = mapObj->keysInUse();
int segmentIdx = -1;
PositionCont posCont;
for(const QPolygonF &singleSegment : singleSegments)
{
++segmentIdx;
posCont.clear();
posCont.reserve(singleSegment.size());
// GUEZE-2254: 3D Wirksim -PzAbwVMi 3D
// In 3D wurde die Linie nicht visualisiert.
// Ein Rechteck mit war unendlich schmal, dadurch soll es quasi als
// Linienzug dargestellt werden, war in 3D aber nicht sichtbar.
// Ursache: Der Linienzug hatte identische Koordinaten.
// Das mag das SDK nicht so gerne.
// Leider ist dies so in Polygons::mineArea2Segment programmiert - schade
// Jan, 2024, Norbert Thoden
// Nachtrag:
// Machmal reicht es wohl doch nicht, den Linienzug von A, B, B, C zu
// reduzieren auf A, B, C
// Daher wird in mineArea2Segment nun eine Mindestbreite von 0.1m vorgenommen.
// Point3D preDescessor;
// for (auto item : singleSegment)
// {
// const Point3D candidate(item.x(), item.y(), .0);
// // check if different:
// if (candidate != preDescessor)
// {
// posCont.append(candidate);
// preDescessor = candidate;
// qCritical() << " simId = " << simId
// << ", segmentIdx = " << segmentIdx
// << ", APPEND";
// } else {
// qCritical() << " simId = " << simId
// << ", segmentIdx = " << segmentIdx
// << ", SKIP";
// }
// }
// : GUEZE-2254
for (auto item : singleSegment)
posCont.append(Point3D(item.x(), item.y(), .0));
mapObj->setSegment(segmentIdx, posCont);
keysInUse.removeAll(segmentIdx);
}
for (auto item : qAsConst(keysInUse))
if (item >= 0) // segments have key >= 0 ; -1 is used for boundary
mapObj->removeSegment(item);
}
// 2nd AesItemView for mines (if already available)
auto itTi = m_triggeredImpacts.constFind(simId);
if (itTi != m_triggeredImpacts.cend())
onTriggeredImpactsChanged(itTi.value(), DataModification::eAdded);
updateVisibility(ddsData, mapObj);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
bool MineArea2SituationMap::updateGeometry(const AreaEffectSimulation::AesItemView &data,
RefPointer<SituationMap::MineField> mapObj)
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " START";
const PositionCont &posCont = form2PosCont(data.form());
// single segments
// - maybe use AesItemView and
// - 1st segment is P0, P1, Pn, Pn-1
// - 2nd segment is P2, P3, Pn-2, Pn-3 ...
// - use QPolygonF AreaEffectSimulation::mineAreaSegment(const DatabaseInterface::AesMineArea &area, const DatabaseInterface::AesMineAreaSegment &segment)
mapObj->setSegment(-1, posCont); // neg key -> no fill
mapObj->setPositions(posCont); // for TacticalAppearance
DEBUG_LOG(m_logger) << LOGFUNCTION << " END, posCont.size() = " << posCont.size();
return true;
}
void MineArea2SituationMap::onTriggeredImpactsChanged(const AreaEffectSimulation::TriggeredImpacts &data, DataModification modType)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
const int32_t simId = data.aesItemId(); // simId of area ('parent')
if (simId < 0)
return;
// check for our type:
if (data.aesTypeId() != AreaEffectSimulation::AesType::AtMineAreaSingleMines)
return;
// ignore mine area 0 (dus mines without minefield)
if (simId == 0)
return;
if (modType == DataModification::eRemoved)
{
m_triggeredImpacts.remove(simId);
return;
}
// update own container:
m_triggeredImpacts[simId] = data;
DEBUG_LOG(m_logger) << LOGFUNCTION << " simId = " << simId
<< " m_triggeredImpacts updated";
// try to update mines:
updateMines(simId);
TRACE_LOG(m_logger) << LOGFUNCTION << " END"
<< " simId = " << simId;
}
void MineArea2SituationMap::onAesItemViewChanged(const AreaEffectSimulation::AesItemView &data, DataModification modType)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START" << " data.aesTypeId()=" << data.aesTypeId() << " modType=" << modType;
const int32_t simId = data.aesItemId(); // simId of area ('parent')
if (simId < 0)
return;
// fix update MF <-> update 1st AesItemView :
{
if (data.aesTypeId() == AreaEffectSimulation::AesType::AtMineArea)
{
// MapObj should exist:
RefPointer<MAP_T> mapObj = this->getMapObjectOfSimId(simId);
if (!mapObj.valid())
{
INFO_LOG(m_logger) << LOGFUNCTION
<< " getMapObjectOfSimId failed"
<< ", simId = " << simId
<< ", modType=" << modType;
return;
}
updateGeometry(data, mapObj);
}
}
// : fix update MF <-> update 1st AesItemView
if (data.aesTypeId() != AreaEffectSimulation::AesType::AtMineAreaSingleMines)
return;
if (modType == DataModification::eRemoved)
{
m_aesItemViewForImpacts.remove(simId);
return;
}
// update own container:
// (2nd AesItemView for impacts)
m_aesItemViewForImpacts[simId] = data;
DEBUG_LOG(m_logger) << LOGFUNCTION << " simId = " << simId
<< " m_aesItemViewForImpacts updated";
// try to update mines:
updateMines(simId);
TRACE_LOG(m_logger) << LOGFUNCTION << " END"
<< " simId = " << simId;
}
bool MineArea2SituationMap::completeMissingData(int32_t simId,
AreaEffectSimulation::TriggeredImpacts &dataTriggeredImpacts,
AreaEffectSimulation::AesItemView &dataAesItemView) const
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
<< " simId = " << simId;
if (simId < 0)
return false;
// idea: get both data from own container and check if the match.
// if so, continue procreesing...
//
// AesitemView:
//
auto itAIV = m_aesItemViewForImpacts.find(simId);
if (itAIV == m_aesItemViewForImpacts.constEnd())
{
INFO_LOG(m_logger) << LOGFUNCTION << " simId = " << simId
<< " no AesItemViewForImpacts found.";
return false;
}
dataAesItemView = itAIV.value();
//
// TriggeredImpacts
//
auto itTI = m_triggeredImpacts.find(simId);
if (itTI == m_triggeredImpacts.constEnd())
{
INFO_LOG(m_logger) << LOGFUNCTION << " simId = " << simId
<< " no TriggeredImpacts found.";
return false;
}
dataTriggeredImpacts = itTI.value();
// do the match?
const int32_t impactCount = dataTriggeredImpacts.impactCount();
const int32_t formSize = dataAesItemView.form().size();
if (impactCount != formSize)
{
WARNING_LOG(m_logger) << LOGFUNCTION
<< " simId = " << simId
<< " size mismatch"
<< " impactCount=" << impactCount
<< " formSize.size()=" << formSize;
return false;
}
// data is available and the match -> return true
TRACE_LOG(m_logger) << LOGFUNCTION << " END"
<< " simId = " << simId;
return true;
}
bool MineArea2SituationMap::updateMines(const int32_t simId)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
<< " simId = " << simId;
if (simId < 0)
return false;
// MapObj should exist:
RefPointer<MAP_T> mapObj = this->getMapObjectOfSimId(simId);
if (!mapObj.valid())
{
DEBUG_LOG(m_logger) << LOGFUNCTION
<< " getMapObjectOfSimId failed"
<< " simId = " << simId << " (maybe expired)";
return false;
}
AreaEffectSimulation::TriggeredImpacts dataTriggeredImpacts;
AreaEffectSimulation::AesItemView dataAesItemView;
bool bothTopicsMatch = completeMissingData(simId, dataTriggeredImpacts, dataAesItemView); // dataAesItemView should be filled now
const PositionCont &posCont = form2PosCont(dataAesItemView.form());
// don't show active DUS mines on map - don't know if they are still there
// where they were triggered the last time
//const bool isDusMine = m_pluginProvider->pdmDtc()->isDus(dataAesItemView.chargeTypeId());
if (bothTopicsMatch)
{
PositionCont posContActivated; // still aimed
PositionCont posContDeActivated; // already triggered
posContActivated.reserve(posCont.size());
posContDeActivated.reserve(posCont.size());
const auto &bitField = dataTriggeredImpacts.bitfield();
// false == impact in past -> filled -> deActivated;
// true == no impact yet -> no fill -> activated
for (int i = 0; i < posCont.size(); ++i)
{
const Point3D &point = posCont.at(i);
if (LtsUtils::BitArray::testBit(bitField, i))
posContActivated.append(point);
else
posContDeActivated.append(point);
}
mapObj->setPositionsMine(MineField::MineState::Activated, posContActivated);
//mapObj->setPositionsMine(MineField::MineState::Activated, isDusMine ? PositionCont() : posContActivated);
mapObj->setPositionsMine(MineField::MineState::DeActivated, posContDeActivated);
DEBUG_LOG(m_logger) << LOGFUNCTION << " simId = " << simId << " size match -> posContActivated " << posContActivated.size();
DEBUG_LOG(m_logger) << LOGFUNCTION << " simId = " << simId << " size match -> posContDeActivated " << posContDeActivated.size();
}
else
{
// on initial, there is no TriggeredImpacts published. In that case interpret all positions as active:
INFO_LOG(m_logger) << LOGFUNCTION << " simId = " << simId
<< " bothTopicsMatch = " << bothTopicsMatch
<< " on initial, there is no TriggeredImpacts published. In that case interpret all positions as active..";
mapObj->setPositionsMine(MineField::MineState::Activated, posCont);
//mapObj->setPositionsMine(MineField::MineState::Activated, isDusMine ? PositionCont() : posCont);
mapObj->setPositionsMine(MineField::MineState::DeActivated, PositionCont());
DEBUG_LOG(m_logger) << LOGFUNCTION << " simId = " << simId << " size mismatch -> all active";
}
if (!mapObj->updateView())
{
ERROR_LOG(m_logger) << LOGFUNCTION
<< " simId = " << simId
<< " updateView failed";
return false;
}
TRACE_LOG(m_logger) << LOGFUNCTION << " END"
<< " simId = " << simId;
return true;
}
}
@@ -0,0 +1,67 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "aes_to_situation_map_tmpl.h"
#include <Plugins/AreaEffectSimulation/aes_data_plugin_interface.h>
#include <MapObjects/mine_field.h>
#include <QObject>
namespace SituationMap
{
class MineArea2SituationMap;
template <>
struct Aes2SituationMapTraits<MineArea2SituationMap>
{
using DDS_TYPE = AreaEffectSimulation::MineArea;
using MAP_TYPE = SituationMap::MineField;
static const AreaEffectSimulation::AesType_def::type aesType = AreaEffectSimulation::AesType_def::AtMineArea;
};
class MineArea2SituationMap final : public Aes2SituationMap<MineArea2SituationMap>
{
Q_OBJECT
public:
using BaseClass = SituationMap::Aes2SituationMap<MineArea2SituationMap>;
using BaseClass::BaseClass;
bool run() override;
bool iterateAesData(const std::function<bool(const AreaEffectSimulation::MineArea &data)> &cb) const
{
return m_aesDtc->mineAreas(cb);
}
bool updateVisibility(const DDS_TYPE &data, RefPointer<MAP_TYPE> mapObj) override;
protected:
bool updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj) override;
bool updateGeometry(const AreaEffectSimulation::AesItemView &data,
RefPointer<SituationMap::MineField> mapObj) override;
bool updateSingleMines(const int simId,
RefPointer<MAP_T> mapObj);
protected Q_SLOTS:
void onTriggeredImpactsChanged(const AreaEffectSimulation::TriggeredImpacts &data, DataModification modType);
void onAesItemViewChanged(const AreaEffectSimulation::AesItemView &data, DataModification modType);
protected:
bool completeMissingData(int32_t simId,
AreaEffectSimulation::TriggeredImpacts &dataTriggeredImpacts,
AreaEffectSimulation::AesItemView &dataAesItemView) const;
bool updateMines(const int32_t simId);
private:
QMap<int32_t, AreaEffectSimulation::TriggeredImpacts> m_triggeredImpacts;
// simId
QMap<int32_t, AreaEffectSimulation::AesItemView> m_aesItemViewForImpacts;
// simId
};
} // namespace
@@ -0,0 +1,81 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#include "mine_corridor_to_map.h"
#include <AreaEffectSimulation/Utils/polygons.h> // for mineAreaSegment
#include <AreaEffectSimulation/Utils/ddsdbconvert.h> // for ...Segment
#include <LtsUtilsCore/dds_bitarray.h>
namespace SituationMap
{
bool MineCorridor2SituationMap::run()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (!m_aesDtc)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no dtc";
return false;
}
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::mineCorridorChanged,
this, &MineCorridor2SituationMap::handleChanged, Qt::UniqueConnection);
// get:
m_aesDtc->mineCorridors([this](const AreaEffectSimulation::MineCorridor &data)
{
handleChanged(data, DataModification::eAdded);
});
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return BaseClass::run();
}
bool MineCorridor2SituationMap::updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
const int32_t simId = ddsData.id();
// adjust appearance:
QColor color(Qt::gray);
color.setAlpha(175);
mapObj->rLineStyle().setLineColor(color);
mapObj->rFillStyle().setFillColor(color);
// set identifier:
mapObj->setIdentifier(QString::fromStdString(ddsData.name()));
// AesItemView for boundary:
AreaEffectSimulation::AesItemView itemView;
if (m_aesDtc->aesItemViewFromEntityId(simId, AreaEffectSimulation::AesType::AtMineCorridor, itemView))
{
this->updateGeometry(itemView, mapObj);
} else {
DEBUG_LOG(m_logger) << LOGFUNCTION
<< " no AesItemView (AtMineCorridor) found"
<< ", simId = " << simId
<< ", provide fallBackGeometry";
// provide fallbackGeometry to avoid errorMsg like 'incorrect number of positions'
mapObj->setPositions({{0.0, 0.0, .0},
{0.0, 0.1, .0},
{0.1, 0.1, .0},
{0.1, 0.0, .0}});
// do not return here, perform stuff like updateVisibility and so on
}
updateVisibility(ddsData, mapObj);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
}
@@ -0,0 +1,47 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "aes_to_situation_map_tmpl.h"
#include <Plugins/AreaEffectSimulation/aes_data_plugin_interface.h>
#include <MapObjects/polygon.h>
#include <QObject>
namespace SituationMap
{
class MineCorridor2SituationMap;
template <>
struct Aes2SituationMapTraits<MineCorridor2SituationMap>
{
using DDS_TYPE = AreaEffectSimulation::MineCorridor;
using MAP_TYPE = SituationMap::Polygon;
static const AreaEffectSimulation::AesType_def::type aesType = AreaEffectSimulation::AesType_def::AtMineCorridor;
};
class MineCorridor2SituationMap final : public Aes2SituationMap<MineCorridor2SituationMap>
{
Q_OBJECT
public:
using BaseClass = SituationMap::Aes2SituationMap<MineCorridor2SituationMap>;
using BaseClass::BaseClass;
bool run() override;
bool iterateAesData(const std::function<bool(const AreaEffectSimulation::MineCorridor &data)> &cb) const
{
return m_aesDtc->mineCorridors(cb);
}
protected:
bool updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj) override;
};
} // namespace
@@ -0,0 +1,911 @@
/**
* @RDE_HEADER@
* The MountingPointToMap class handles the transfer from MountingPoint-DDS-Data to a representation on the map of the data
* $Id$
* $HeadURL$
* $Author$
* Created by Hannes Baeuerle, SLSE, 2017-01-17
*/
// Own
#include "mounting_point_to_map.h"
#include <Map/map.h>
#include <Map/object_factory.h>
#include <Map/layer_factory.h>
#include <PluginInterfaces/gui_plugin_interface.h>
#include <InfrastructureManagement/ism_translation.h>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonParseError>
#include <QJsonArray>
#include <QGuiApplication>
#include <sstream>
// Which object should be visible?
// Just
// 1) Normal User
// 1a) excercise login (SitMap) (userId == 17 ; exerciseId == 42 ; resourceMode == off)
// -> MountingPoints of associated bldgs (m_bldgsInExcersise) ???
// is Elapsed: (MountingPointType::OutdoorCamera || MountingPointType::AnnouncementUnit) && data.hasAssociatedAsset()==true
// 1b) normal login, switch to ResourceMgr (exerciseId == 0 ; resourceMode == on)
// -> MountingPoints of all bldgs ???
// is Elapsed: (MountingPointType::OutdoorCamera || MountingPointType::AnnouncementUnit)
// 2) Organisator (minor priority)
// 2a) organisator login (userId == 98|99 ; exerciseId == 0 ; resourceMode == off)
// -> MountingPoints of all bldgs ???
// 2b) organisator login (userId == 98|99 ; exerciseId == 0 ; resourceMode == on)
// -> MountingPoints of all bldgs ???
namespace SituationMap
{
QString toString(ResourceManagerMode rmm)
{
switch (rmm) {
case ResourceManagerMode::Undefined:
return QStringLiteral("RMM_Undefined");
break;
case ResourceManagerMode::RMM_PlanActivityView:
return QStringLiteral("RMM_PlanActivityView");
break;
case ResourceManagerMode::RMM_PlanDefinitionView:
return QStringLiteral("RMM_PlanDefinitionView");
break;
case ResourceManagerMode::RMM_ComponentMonitor:
return QStringLiteral("RMM_ComponentMonitor");
break;
}
return QStringLiteral("RMM_UNKNOWN");
}
bool MountingPointToMap::init(PluginProvider *pluginProvider, bool resourceMode)
{
if (!pluginProvider ||
!pluginProvider->ismDtc() ||
!pluginProvider->ismDataIfc())
return false;
m_resourceMode = resourceMode; // hack
m_pluginProvider = pluginProvider;
INFO_LOG(m_logger) << LOGFUNCTION << " m_resourceMode=" << m_resourceMode
<< " exerciseId=" << m_pluginProvider->exerciseId();
// FilterManagement:
FilterClass::init(m_pluginProvider);
m_ismDtc = m_pluginProvider->ismDtc();
m_ismDataIfc = m_pluginProvider->ismDataIfc();
m_ismGuiIfc = m_pluginProvider->ismGuiIfc();
m_cmoDtc = m_pluginProvider->cmoDtc();
InfrastructureManagement::MountingPoint::init(); // load all icons before using them later
m_handleAllMountingPointsTimer = new QTimer(this);
m_handleAllMountingPointsTimer->setInterval(1500);
m_handleAllMountingPointsTimer->setSingleShot(true);
connect(m_handleAllMountingPointsTimer, &QTimer::timeout,
this, &MountingPointToMap::onHandleAllMountingPoints);
#ifdef SUPPORT_SELECTION_APPROACH
m_selectionFilterTimer = new QTimer(this);
m_selectionFilterTimer->setInterval(2000);
connect(m_selectionFilterTimer, &QTimer::timeout,
this, &MountingPointToMap::onHandleSelectionFilterTimeout);
#endif // SUPPORT_SELECTION_APPROACH
if (m_cmoDtc)
{
m_cmoDtc->enableComponentStatus(true);
m_cmoDtc->waitForHistoricalDataComponentStatus(1000);
// further operation regarding ComponentStatus are delayed -> run()
// benefits: - fast startup
// - onHandleAllMountingPoints can use m_cmoDtc which should be update-to-date then
}
INFO_LOG(m_logger) << LOGFUNCTION << " m_resourceMode=" << m_resourceMode
<< " exerciseId=" << m_pluginProvider->exerciseId()
<< " DONE";
return true;
}
bool MountingPointToMap::initRenderer()
{
INFO_LOG(m_logger) << LOGFUNCTION << " START"
<< ", to rmm = " << toString(m_resourceManagerMode)
<< ", m_uniqueValueRendererAssigned=" << m_uniqueValueRendererAssigned;
// excute just once:
if (m_uniqueValueRendererAssigned)
return true;
QElapsedTimer elapsedTimer;
if (m_logger.isInfoEnabled())
elapsedTimer.start();
m_uniqueValueRendererAssigned = initRendererInternal();
if (m_logger.isInfoEnabled())
INFO_LOG(m_logger) << LOGFUNCTION << " END, initRendererXY to rmm = " << toString(m_resourceManagerMode) << " took " << elapsedTimer.elapsed() << " [ms]";
return m_uniqueValueRendererAssigned;
}
bool MountingPointToMap::initRendererInternal()
{
// Die PlanAktivitätsSicht zeigt nur die Anbringungspunkte des aktuellen Plans
// (bei leerem Plan also keine, es ist keine Statusänderung durch den Nutzer möglich)
//
// grün: keine Aktivität erforderlich
// blau: Aktivität erforderlich: MONTIEREN
// rot: Aktivität erforderlich: DE-MONTIEREN
// In der (alten) PlanDefinitionsSicht werden alle Anbringungspunkte (ca. 25000)
// angezeigt.
//
// Die FarbCodierung ist:
// grau: Dem Plan nicht zugeordnet (Idle)
// blau: Dem Plan zugeordnet + Zielstatus „montiert“ (Equipped)
// rot: Dem Plan zugeordnet + Zielstatus „darf nicht montiert sein“ (Empty)
INFO_LOG(m_logger) << LOGFUNCTION << " START, rmm=" << toString(m_resourceManagerMode);
const QString &layername = m_layername;
QVector<SituationMap::LayerFactory::UniqueValueData> uvCont;
SituationMap::LayerFactory::UniqueValueData uvd;
// loop over ImageTable
QMap<InfrastructureManagement::MountingPointType_def::type, InfrastructureManagement::MountingPoint::MpNameImageData> &imageCont =
InfrastructureManagement::MountingPoint::getImageTable();
// Norbert Thoden, 13.20.2022: (CTCAP15)
// static ImageTable contains images in good quality (100*100px)
// on map we want small images 25*25px)
// -> .scaled(QSize(25,25), Qt::KeepAspectRatio, Qt::SmoothTransformation);
// there are just a few scale operations (~12*6=72).
// tranfer 72 images (25,25), no scale -> 4ms
// tranfer 72 images (100,100) scaled(QSize(25,25), Qt::KeepAspectRatio, Qt::SmoothTransformation) -> 6ms
// not relevant :-)
uvCont.reserve(imageCont.size() * 5);
for (const InfrastructureManagement::MountingPoint::MpNameImageData &mnid : qAsConst(imageCont) )
{
{
const InfrastructureManagement::MountingPoint::NameImagePair &nipRef = mnid.nipBlue;
uvd.label = nipRef.m_name;
uvd.img = nipRef.m_img.scaled(QSize(25,25), Qt::KeepAspectRatio, Qt::SmoothTransformation);
uvd.value = nipRef.m_name;
uvCont.append(uvd);
}
{
const InfrastructureManagement::MountingPoint::NameImagePair &nipRef = mnid.nipGray;
uvd.label = nipRef.m_name;
uvd.img = nipRef.m_img.scaled(QSize(25,25), Qt::KeepAspectRatio, Qt::SmoothTransformation);
uvd.value = nipRef.m_name;
uvCont.append(uvd);
}
{
const InfrastructureManagement::MountingPoint::NameImagePair &nipRef = mnid.nipGreen;
uvd.label = nipRef.m_name;
uvd.img = nipRef.m_img.scaled(QSize(25,25), Qt::KeepAspectRatio, Qt::SmoothTransformation);
uvd.value = nipRef.m_name;
uvCont.append(uvd);
}
{
const InfrastructureManagement::MountingPoint::NameImagePair &nipRef = mnid.nipRed;
uvd.label = nipRef.m_name;
uvd.img = nipRef.m_img.scaled(QSize(25,25), Qt::KeepAspectRatio, Qt::SmoothTransformation);
uvd.value = nipRef.m_name;
uvCont.append(uvd);
}
{
const InfrastructureManagement::MountingPoint::NameImagePair &nipRef = mnid.nipOrange;
uvd.label = nipRef.m_name;
uvd.img = nipRef.m_img.scaled(QSize(25,25), Qt::KeepAspectRatio, Qt::SmoothTransformation);
uvd.value = nipRef.m_name;
uvCont.append(uvd);
}
} // for
bool success = m_objFac.map()->layerFactory().assignUniqueValueRenderer(layername,
QStringLiteral("MountingPointFieldName"),
uvCont);
if (!success)
ERROR_LOG(m_logger) << LOGFUNCTION << " assignUniqueValueRenderer ... on layer= " << layername << " failed";
INFO_LOG(m_logger) << LOGFUNCTION << " END, rmm=" << toString(m_resourceManagerMode);
return success;
}
ResourceManagerMode MountingPointToMap::resourceManagerMode() const
{
return m_resourceManagerMode;
}
bool MountingPointToMap::setResourceManagerMode(ResourceManagerMode rmm)
{
INFO_LOG(m_logger) << LOGFUNCTION << " START"
<< ", current rmm = " << toString(m_resourceManagerMode) << " - desired rmm = " << toString(rmm);
QElapsedTimer elapsedTimer;
if (m_logger.isInfoEnabled())
elapsedTimer.start();
if (rmm == ResourceManagerMode::Undefined)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " ERROR, ResourceManagerMode::Undefined required "
<< ", stay at current rmm = " << toString(m_resourceManagerMode);
return false;
}
bool change = m_resourceManagerMode != rmm;
m_resourceManagerMode = rmm;
if (change)
{
run();
}
if (change && m_logger.isInfoEnabled())
INFO_LOG(m_logger) << LOGFUNCTION << " END, switching to current rmm = " << toString(m_resourceManagerMode) << " took " << elapsedTimer.elapsed() << " [ms]";
INFO_LOG(m_logger) << LOGFUNCTION << " END" << ", desired rmm = " << toString(rmm);
return true;
}
bool MountingPointToMap::run()
{
DEBUG_LOG(m_logger) << " Starting to run";
this->stop();
if (!m_ismDataIfc)
{
ERROR_LOG(m_logger) << LOGFUNCTION << "Could not run. ForeignDataInterface not set.";
return false;
}
// m_ismDataIfc has buildingsInCurrentExercise
connect(m_ismDataIfc.get(), &InfrastructureManagement::ForeignDataInterface::buildingsInCurrentExerciseChanged,
this, &MountingPointToMap::onBuildingsInCurrentExerciseChanged, Qt::UniqueConnection);
connect(m_ismDataIfc.get(), &InfrastructureManagement::ForeignDataInterface::mountingPointChanged,
this, &MountingPointToMap::onMountingPointChanged, Qt::UniqueConnection);
// execute initRenderer here instead of init()
// if TA is not already present, the LayerFactory ist not prepared for initRenderer().
// So delay initRenderer() to run()
initRenderer(); // according m_resourceManagerMode
// get:
onHandleAllMountingPoints(); // could be timeconsuming
#ifdef SUPPORT_SELECTION_APPROACH
setVisibility();
m_selectionFilterTimer->start();
#endif // SUPPORT_SELECTION_APPROACH
if (m_cmoDtc)
{
// svcComponentenMonitor (Proxy) publishes topics in ex_0:
// // get not required here:
// m_cmoDtc->componentStatuss([this](const ComponentMonitor::ComponentStatus &data)
// {
// onComponentStatusChanged(data, DataModification::eAdded);
// });
connect(m_cmoDtc.get(), &ComponentMonitor::Interface::Dtc::componentStatusChanged,
this, &MountingPointToMap::onComponentStatusChanged, Qt::UniqueConnection);
}
return true;
}
void MountingPointToMap::onHandleAllMountingPoints()
{
INFO_LOG(m_logger) << LOGFUNCTION << " START"
<< ", m_pluginProvider->exerciseId() = " << m_pluginProvider->exerciseId()
<< ", m_resourceMode = " << m_resourceMode;
if (m_pluginProvider->exerciseId() != 0 || m_resourceMode)
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " mountingPoints().size() = " << m_ismDataIfc->mountingPoints().size();
m_ismDataIfc->mountingPoints([this](const InfrastructureManagement::MountingPoint& data)
{
onMountingPointChanged(data, DataModification::eAdded);
});
}
INFO_LOG(m_logger) << LOGFUNCTION << " END";
}
void MountingPointToMap::stop()
{
DEBUG_LOG(m_logger) << LOGFUNCTION << "Stopping...";
if (m_handleAllMountingPointsTimer)
m_handleAllMountingPointsTimer->stop();
#ifdef SUPPORT_SELECTION_APPROACH
if (m_selectionFilterTimer)
m_selectionFilterTimer->stop();
#endif // SUPPORT_SELECTION_APPROACH
if (m_ismDtc)
m_ismDtc->disconnect(this);
if (m_ismDataIfc)
m_ismDataIfc->disconnect(this);
if (m_cmoDtc)
m_cmoDtc->disconnect(this);
m_mountingPoints.clear();
DEBUG_LOG(m_logger) << LOGFUNCTION << "Stopping...done";
}
// Useful for assignment of MountingPoints at resourceApp of ISM
bool MountingPointToMap::mapObjectsClicked(const QVector<UniqueMapId> &uniqueMapIds)
{
// Useful for assignment of MountingPoints at resourceApp of ISM
if (!m_ismGuiIfc)
return false;
const QVector<int32_t> &simIds = uniqueMapIds2SimIds(uniqueMapIds);
if (simIds.isEmpty())
return true;
if (m_ismGuiIfc->isInSelectionMode())
m_ismGuiIfc->addToSelection(simIds);
else
m_ismGuiIfc->showMountingPointInfoWindows(simIds);
return true;
}
bool MountingPointToMap::unifiedMapObjectData(UniqueMapId uniqueMapId, UnifiedMapObjectData &umodOut) const
{
if (!m_ismDataIfc)
return false;
int32_t simIdOut = -1;
if (!this->uniqueMapId2SimId(uniqueMapId, simIdOut))
return false;
umodOut = UnifiedMapObjectData();
// RefPointer<MAP_T> mapObj = this->getMapObjectOfUniqueMapId(uniqueMapId);
// if (mapObj.valid())
// umodOut.m_image = mapObj->previewImage();
const auto cb = [this, simIdOut, &umodOut](const InfrastructureManagement::MountingPoint &data) -> bool
{
if (data.id() == simIdOut)
{
umodOut.m_description1 = data.name();
umodOut.m_participantData.m_typeName = InfrastructureManagement::toString(data.type());
// This image should be identical to the one of the uniqueValueRenderer:
QString attribValueUnused;
bool suc = false;
switch (m_resourceManagerMode) {
case ResourceManagerMode::RMM_PlanActivityView:
suc = InfrastructureManagement::MountingPoint::getImageAttributePlanActivity(data, umodOut.m_image, attribValueUnused);
if (!suc)
WARNING_LOG(m_logger) << LOGFUNCTION
<< "getImageAttributePlanActivity failed m_resourceMode=" << m_resourceMode
<< " m_resourceManagerMode=" << toString(m_resourceManagerMode);
break;
case ResourceManagerMode::RMM_PlanDefinitionView:
suc = InfrastructureManagement::MountingPoint::getImageAttributePlanDefinition(data, umodOut.m_image, attribValueUnused);
if (!suc)
WARNING_LOG(m_logger) << LOGFUNCTION
<< "getImageAttributePlanDefinition failed m_resourceMode=" << m_resourceMode
<< " m_resourceManagerMode=" << toString(m_resourceManagerMode);
break;
case ResourceManagerMode::RMM_ComponentMonitor:
{
InfrastructureManagement::MountingPoint::MpColor col = InfrastructureManagement::MountingPoint::MpColor::GRAY;
suc = InfrastructureManagement::MountingPoint::getImageAttribute(data, col, umodOut.m_image, attribValueUnused);
if (!suc)
{
WARNING_LOG(m_logger) << LOGFUNCTION
<< "getImageAttribute failed m_resourceMode=" << m_resourceMode
<< " m_resourceManagerMode=" << toString(m_resourceManagerMode);
}
}
break;
default:
// empty
break;
} // switch
return true; // break loop
}
return false;
};
// sonst kann sich der compiler nicht zwischen bool und void entscheiden... !?
std::function<bool(const InfrastructureManagement::MountingPoint &data)> cb1 = cb;
return m_ismDataIfc->mountingPoints(cb1);
}
bool MountingPointToMap::onMountingPointChanged(const InfrastructureManagement::MountingPoint &data, DataModification modType)
{
DEBUG_LOG(m_logger) << " m_resourceMode=" << m_resourceMode
<< " onMountingPointChanged"
<< " id=" << data.id()
<< " name=" << data.name()
<< " buildingId=" << data.buildingId()
<< " associatedAssetId=" << data.associatedAssetId()
<< " hasAssociatedAsset=" << data.hasAssociatedAsset()
<< " MountingPointType=" << data.type()
<< " aimState=" << data.aimState()
<< " exerciseId=" << m_pluginProvider->exerciseId();
if (m_pluginProvider->exerciseId() == 0 && !m_resourceMode)
return true;
if (!isElapsed(data)) // add just 'valid' data
{
m_mountingPoints.insert(data.id(), data);
// m_assAssetHostnameToMountingPointId
const std::string &hostname = mountingPointHostname(data);
if (!hostname.empty())
{
m_associatedAssetHostnameToMountingPointId[hostname] = data.id();
DEBUG_LOG(m_logger) << " m_resourceMode=" << m_resourceMode
<< " INSERT hostname '" << hostname << "'"
<< " id " << data.id();
}
}
return handleChanged(data, modType);
}
bool MountingPointToMap::isElapsed(const Sim2SituationMap::DDS_T &data) const
{
// true -> hide
// false -> show
DEBUG_LOG(m_logger) << " isElapsed"
<< ", m_resourceManagerMode=" << (int)m_resourceManagerMode;
if (BaseClass::isElapsed(data))
return true;
const InfrastructureManagement::MountingPointType mpType = data.type();
// SWPÄ 2/22 - Hannes: BuildingNetworkSwitch werden komplett ignoriert:
if (mpType.underlying() == InfrastructureManagement::MountingPointType::BuildingNetworkSwitch)
return true;
// show all types (except BuildingControlUnit) because of resourceMode (ResourceApp)
if (m_resourceMode)
{
// original RMM_PlanView:
switch (m_resourceManagerMode) {
case ResourceManagerMode::RMM_PlanActivityView:
// keine BuildingControlUnit ; nur Equipped&Empty anzeigen
return ( (mpType.underlying() == InfrastructureManagement::MountingPointType_def::BuildingControlUnit) ||
(data.aimState().underlying() == InfrastructureManagement::MountingPointState_def::Idle)
);
break;
case ResourceManagerMode::RMM_PlanDefinitionView:
// empty (quasi alle anzeigen)
return (mpType.underlying() == InfrastructureManagement::MountingPointType_def::BuildingControlUnit);
break;
case ResourceManagerMode::RMM_ComponentMonitor:
// Afo 116.1
return
! (data.hasAssociatedAsset() &&
(
(mpType.underlying() == InfrastructureManagement::MountingPointType_def::OutdoorIPS) ||
(mpType.underlying() == InfrastructureManagement::MountingPointType_def::IndoorIPS) ||
(mpType.underlying() == InfrastructureManagement::MountingPointType_def::OutdoorCamera) ||
(mpType.underlying() == InfrastructureManagement::MountingPointType_def::IndoorCamera) ||
(mpType.underlying() == InfrastructureManagement::MountingPointType_def::OutdoorCamera) ||
(mpType.underlying() == InfrastructureManagement::MountingPointType_def::EffectGenerationControlUnit) ||
(mpType.underlying() == InfrastructureManagement::MountingPointType_def::BuildingSensorModule)
)
);
break;
default:
break;
}
} // if (m_resourceMode)
const int bldgId = data.buildingId();
if (!m_ismDataIfc->isBuildingsInCurrentExercise(bldgId))
{
DEBUG_LOG(m_logger) << "isElapsed: buildingId=" << bldgId;
return true; // true -> hide
}
// ok, we are NOT in resourceMode:
// show only MountingPointType::OutdoorCamera, which are assigned (data.hasAssociatedAsset()):
// and AnnoucementUnits
// (to enable InfoWindow)
if ((mpType.underlying() == InfrastructureManagement::MountingPointType::OutdoorCamera) ||
(mpType.underlying() == InfrastructureManagement::MountingPointType::AnnouncementUnit))
return data.hasAssociatedAsset() == false;
return true;
}
int32_t MountingPointToMap::getSimId(const Sim2SituationMap::DDS_T &ddsData) const
{
return ddsData.id();
}
bool MountingPointToMap::updateElementImpl(const Sim2SituationMap::DDS_T &ddsData, RefPointer<Sim2SituationMap::MAP_T> mapObj)
{
DEBUG_LOG(m_logger) << LOGFUNCTION
<< " m_resourceMode=" << m_resourceMode
<< " m_resourceManagerMode=" << (int)m_resourceManagerMode
<< " id " << ddsData.id()
<< " type " << ddsData.type()
<< " name = " << ddsData.name()
<< " has associatedAssetId = " << ddsData.associatedAssetId()
<< " aimState = " << ddsData.aimState()
<< ", goeCoord = " << ddsData.geoPosition();
// mapObj->setIdentifier(ddsData.name()); // do not show the name as identifier for mountingPoints
const Core::GeoPosition &geoPos = ddsData.geoPosition();
mapObj->setOrigin(Point3D(geoPos.lon(), geoPos.lat(), geoPos.z()));
// retrieve attribute value:
QString attribValue;
QImage imgUnused;
switch (m_resourceManagerMode) {
case ResourceManagerMode::RMM_PlanActivityView:
{
bool suc = InfrastructureManagement::MountingPoint::getImageAttributePlanActivity(ddsData, imgUnused, attribValue);
if (!suc)
{
WARNING_LOG(m_logger) << LOGFUNCTION
<< "getImageAttributePlanActivity failed m_resourceMode=" << m_resourceMode
<< " m_resourceManagerMode=" << (int)m_resourceManagerMode;
}
}
break;
case ResourceManagerMode::RMM_PlanDefinitionView:
{
bool suc = InfrastructureManagement::MountingPoint::getImageAttributePlanDefinition(ddsData, imgUnused, attribValue);
if (!suc)
{
WARNING_LOG(m_logger) << LOGFUNCTION
<< "getImageAttributePlanDefinition failed m_resourceMode=" << m_resourceMode
<< " m_resourceManagerMode=" << (int)m_resourceManagerMode;
}
}
break;
case ResourceManagerMode::RMM_ComponentMonitor:
{
InfrastructureManagement::MountingPoint::MpColor col = InfrastructureManagement::MountingPoint::MpColor::GRAY;
const InfrastructureManagement::MountingPointType mpType = ddsData.type();
if ( (mpType.underlying() == InfrastructureManagement::MountingPointType_def::OutdoorIPS) ||
(mpType.underlying() == InfrastructureManagement::MountingPointType_def::IndoorIPS) )
{
col = InfrastructureManagement::MountingPoint::MpColor::GRAY;
} else {
const std::string &hostname = mountingPointHostname(ddsData);
if (!hostname.empty())
{
ComponentMonitor::ComponentState stateOut;
if (componentStateOfHostname(hostname, stateOut))
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " componentStateOfHostname: '" << hostname << "' -> " << stateOut;
switch (stateOut.underlying()) {
case ComponentMonitor::ComponentState_def::Undefined:
if (QGuiApplication::keyboardModifiers().testFlag(Qt::ControlModifier))
col = InfrastructureManagement::MountingPoint::MpColor::ORANGE;
else
col = InfrastructureManagement::MountingPoint::MpColor::RED;
break;
case ComponentMonitor::ComponentState_def::Reachable:
col = InfrastructureManagement::MountingPoint::MpColor::GREEN;
break;
case ComponentMonitor::ComponentState_def::Unreachable:
col = InfrastructureManagement::MountingPoint::MpColor::RED;
break;
default:
// empty
break;
}
} else {
DEBUG_LOG(m_logger) << LOGFUNCTION
<< " componentStateOfHostname: host '" << hostname << "' not found. Maybe topic removed ";
// stay at default color...
}
}
} // if
bool suc = InfrastructureManagement::MountingPoint::getImageAttribute(ddsData, col, imgUnused, attribValue);
if (!suc)
{
WARNING_LOG(m_logger) << LOGFUNCTION
<< ", getImageAttribute failed m_resourceMode=" << m_resourceMode
<< ", m_resourceManagerMode=" << (int)m_resourceManagerMode;
}
}
break;
default:
// empty
break;
} // switch
// attribValue = QStringLiteral("announcement_RED");
// // attrib.insert(QStringLiteral("MountingPointFieldName"), QString(QStringLiteral("announcement_With"))); // presets_disabled_Without, ips, reference_module, presets
QVariantMap attribMap;
attribMap.insert(QStringLiteral("MountingPointFieldName"), attribValue);
INFO_LOG(m_logger) << LOGFUNCTION
<< " id " << ddsData.id()
<< " type " << ddsData.type()
<< " name = " << ddsData.name()
<< " attribValue = >>>" << attribValue << "<<<";
mapObj->setAttributes(attribMap);
return true; // mapObj->updateView() is done by template
}
#ifdef BLDCOMPONENT_FILTER_APPROACH
void MountingPointToMap::handleBuildingComponentSettings(RefPointer<Sim2SituationMap::MAP_T> &mapObj)
{
if (!mapObj.valid())
return;
const UniqueMapId uniqueMapId = mapObj->uniqueMapId();
int32_t simIdOut = -1;
if (!this->uniqueMapId2SimId(uniqueMapId, simIdOut))
return;
const InfrastructureManagement::MountingPoint &ddsDataMP = m_mountingPoints[simIdOut];
Q_ASSERT(ddsDataMP.id() == simIdOut);
handleBuildingComponentSettingsMP(mapObj, ddsDataMP);
}
void MountingPointToMap::handleBuildingComponentSettingsMP(RefPointer<Sim2SituationMap::MAP_T> &mapObj,
const InfrastructureManagement::MountingPoint &mountingPoint)
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " m_resourceMode=" << m_resourceMode
<< ", debugInfo='" << mapObj->debugInfo();
if (!mapObj.valid())
return;
const InfrastructureManagement::MountingPointType_def::type type = mountingPoint.type().underlying();
bool newVisi = showMountingPointType(type);
if (newVisi)
{
// GUEZE-1478:
// Wenn im Dialog "Gebäude/Komponenten" alle Etagenfilter deaktiviert sind,
// werden alle Anbringungspunkte auf der Karte dargestellt.
// Erwartet wäre, dass kein Anbringungspunkt dargestellt wird (r58287)
const QSet<int> hiddenFloorIdsRef = m_currentBuildingComponentSettings.buildingSettings.hiddenFloorIds;
newVisi = !hiddenFloorIdsRef.contains(mountingPoint.floor());
}
bool oldVisibility = mapObj->visibility();
if (oldVisibility != newVisi)
{
mapObj->setVisibility(newVisi);
if (!mapObj->updateView())
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << mapObj->debugInfo() << "'" << " updateView failed";
}
}
bool MountingPointToMap::showMountingPointType(InfrastructureManagement::MountingPointType_def::type mpType) const
{
const FilterManagement::BuildingComponentSettings::BldCmpSettings::ComponentSettings &cs =
m_currentBuildingComponentSettings.componentSettings;
switch (mpType) {
case InfrastructureManagement::MountingPointType_def::AnnouncementUnit:
#ifdef GUEZ_MODE
return false;
#else
return cs.showAnnouncementUnit;
#endif
break;
case InfrastructureManagement::MountingPointType_def::BuildingControlUnit:
return cs.showBuildingControlUnit;
break;
case InfrastructureManagement::MountingPointType_def::BuildingNetworkSwitch:
#ifdef GUEZ_MODE
return false;
#else
return cs.showBuildingNetworkSwitch;
#endif
break;
case InfrastructureManagement::MountingPointType_def::BuildingSensorModule:
return cs.showBuildingSensorModule;
break;
case InfrastructureManagement::MountingPointType_def::EffectGenerationControlUnit:
return cs.showEffectGenerationControlUnit;
break;
case InfrastructureManagement::MountingPointType_def::IndoorCamera:
return cs.showIndoorCamera;
break;
case InfrastructureManagement::MountingPointType_def::IndoorIPS:
return cs.showIndoorIPS;
break;
case InfrastructureManagement::MountingPointType_def::MeteoDataUnit:
return cs.showMeteoDataUnit;
break;
case InfrastructureManagement::MountingPointType_def::OutdoorCamera:
return cs.showOutdoorCamera;
break;
case InfrastructureManagement::MountingPointType_def::OutdoorControlUnit:
#ifdef GUEZ_MODE
return false;
#else
return cs.showOutdoorControlUnit;
#endif
break;
case InfrastructureManagement::MountingPointType_def::OutdoorIPS:
return cs.showOutdoorIPS;
break;
case InfrastructureManagement::MountingPointType_def::VirtualIPS:
return cs.showVirtualIPS;
break;
case InfrastructureManagement::MountingPointType_def::Unknown:
WARNING_LOG(m_logger) << LOGFUNCTION << " visibility of MountingPointType_def::Unknown - unwanted, most likelky an error...";
#ifdef LTS_DEBUG
Q_ASSERT(false);
#endif
return true;
break;
default:
break;
}
return true;
}
#endif // BLDCOMPONENT_FILTER_APPROACH
#ifdef SUPPORT_SELECTION_APPROACH
void MountingPointToMap::onHandleSelectionFilterTimeout()
{
if (!m_ismGuiIfc)
return;
m_ismGuiIfc->getCurrentFilters(m_selectionFilter.m_floorIds, m_selectionFilter.m_mountingPointTypes);
setVisibility();
}
#endif // SUPPORT_SELECTION_APPROACH
std::string MountingPointToMap::mountingPointHostname(const InfrastructureManagement::MountingPoint &mountingPoint)
{
// m_assAssetHostnameToMountingPointId
if (!mountingPoint.hasAssociatedAsset())
return {};
const int assAssetId = mountingPoint.associatedAssetId();
const InfrastructureManagement::InstrumentationAsset &iAsset = m_ismDtc->instrumentationAsset(assAssetId);
if (iAsset.id() == assAssetId)
{
const std::string &hostname = iAsset.hostname();
if (!hostname.empty())
return hostname;
}
return {};
}
bool MountingPointToMap::componentStateOfHostname(const std::string &hostname, ComponentMonitor::ComponentState &stateOut)
{
stateOut = ComponentMonitor::ComponentState(ComponentMonitor::ComponentState_def::Undefined);
if (!m_cmoDtc)
return false;
const auto cb = [hostname, &stateOut](const ComponentMonitor::ComponentStatus &ddsData) -> bool
{
if (ddsData.hostname().compare(hostname) == 0)
{
stateOut = ddsData.state();
return true; // true -> break loop
}
return false;
};
// sonst kann sich der compiler nicht zwischen bool und void entscheiden... !?
std::function<bool(const ComponentMonitor::ComponentStatus &data)> cb1 = cb;
return m_cmoDtc->componentStatuss(cb1);
}
void MountingPointToMap::onBuildingsInCurrentExerciseChanged()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
<< ", m_resourceManagerMode = " << toString(m_resourceManagerMode);
// if bldg is moved from one exercise to another, MountingPoint gets it data updated and therefore mountingPointChanged is emitted.
// but to be safe:
m_handleAllMountingPointsTimer->start();
}
bool MountingPointToMap::onComponentStatusChanged(const ComponentMonitor::ComponentStatus &data, DataModification modType)
{
if (m_resourceManagerMode != ResourceManagerMode::RMM_ComponentMonitor)
return false;
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
<< ", data =" << data
<< ", modType = " << modType
<< ", m_resourceManagerMode = " << toString(m_resourceManagerMode);
// name is empty, use hostname :-)
// like [[id: 18, name: , isDeleted: 0, isUsed: 0]hostname: UBEOCE0002, state: ComponentState::Undefined ]
//
// Do we have a MP with an associated asset which also has a hostname?
//
const std::string &hostname = data.hostname();
if (hostname.empty())
return false;
DEBUG_LOG(m_logger) << LOGFUNCTION << " START"
<< ", data =" << data
<< ", modType = " << modType
<< ", m_resourceManagerMode = " << toString(m_resourceManagerMode);
const auto it = m_associatedAssetHostnameToMountingPointId.find(hostname);
if (it == m_associatedAssetHostnameToMountingPointId.end())
return false;
const int mountingPointId = *it;
// Part 1:
const InfrastructureManagement::MountingPoint &mountingPoint = m_mountingPoints[mountingPointId];
// Part 2:
const UniqueMapId uniqueMapId = m_simId2UniqueMapId.value(mountingPointId, INVALID_MAP_ID);
if (!isUniqueMapIdValid(uniqueMapId))
{
WARNING_LOG(m_logger) << LOGFUNCTION << "Found a mountingPoint which is in internal map but has no map object...: " << mountingPointId;
return false;
}
RefPointer<MAP_T> mapObj = m_objFac.get<MAP_T>(uniqueMapId);
if (!mapObj.valid())
return false;
// updateElementImpl will look for ComponentState (ComponentState::Reachable....)
updateElementImpl(mountingPoint, mapObj);
if (!mapObj->updateView())
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << mapObj->debugInfo() << "'" << " updateView failed";
return true;
}
} // namespace SituationMap
@@ -0,0 +1,126 @@
/**
* @RDE_HEADER@
* The MountingPointToMap class handles the transfer from MountingPoint-DDS-Data to a representation on the map of the data
* $Id$
* $HeadURL$
* $Author$
* Created by Hannes Baeuerle, SLSE, 2017-01-17
*/
#pragma once
// Select one approach
//#define SUPPORT_SELECTION_APPROACH
#define BLDCOMPONENT_FILTER_APPROACH
#include "sim_to_situation_map_tmpl.h"
#include "resource_manager_mode.h"
#include <Plugins/InfrastructureManagement/ism_data_plugin_interface.h>
#include <Plugins/InfrastructureManagement/ism_resource_management_gui_plugin_interface.h>
#include <Plugins/ComponentMonitor/cmo_data_plugin_interface.h>
#include <Plugins/InfrastructureManagement/Shared/ism_mounting_point.h>
#include <MapObjects/geo_image.h>
#include <MapObjects/map_object_attributes.h>
#include <QTimer>
namespace SituationMap
{
class MountingPointToMap final : public Sim2SituationMap<InfrastructureManagement::MountingPoint, SituationMap::MapObjectAttributes>
, protected DdsFilterHandling<SituationMap::MapObjectAttributes>
{
Q_OBJECT
using BaseClass = SituationMap::Sim2SituationMap<InfrastructureManagement::MountingPoint, SituationMap::MapObjectAttributes>;
using FilterClass = DdsFilterHandling<SituationMap::MapObjectAttributes>;
public:
MountingPointToMap(ObjectFactory &objFac,
const QString &layername,
int drawOrder,
const char *loggerName)
: BaseClass(objFac, layername, drawOrder, loggerName)
, FilterClass(loggerName, this)
{}
bool init(PluginProvider *pluginProvider, bool resourceMode);
bool initRenderer();
bool initRendererInternal();
// bool initRendererPlanDefinitionView();
// bool initRendererComponentView();
ResourceManagerMode resourceManagerMode() const;
bool setResourceManagerMode(ResourceManagerMode rmm);
bool run() override;
void stop() override;
bool mapObjectsClicked(const QVector<UniqueMapId> &uniqueMapIds) override; // Useful for assignment of MountingPoints at resourceApp of ISM
bool unifiedMapObjectData(UniqueMapId uniqueMapId, UnifiedMapObjectData &umodOut) const override;
protected Q_SLOTS:
void onHandleAllMountingPoints();
#ifdef SUPPORT_SELECTION_APPROACH
void onHandleSelectionFilterTimeout();
#endif // SUPPORT_SELECTION_APPROACH
bool onMountingPointChanged(const InfrastructureManagement::MountingPoint &data, DataModification modType);
void onBuildingsInCurrentExerciseChanged();
bool onComponentStatusChanged(const ComponentMonitor::ComponentStatus &data, DataModification modType);
protected:
bool isElapsed(const Sim2SituationMap::DDS_T &data) const override;
int32_t getSimId(const Sim2SituationMap::DDS_T &ddsData) const override;
bool updateElementImpl(const DDS_T &ddsData, RefPointer<MAP_T> mapObj) override;
void handleSymbolAppearanceSettings(RefPointer<MAP_T> &mapObj) override
{
Q_UNUSED(mapObj);
}
#ifdef BLDCOMPONENT_FILTER_APPROACH
bool buildingComponentSettingsChangesAreRelevant(const FilterManagement::BuildingComponentSettings::BldCmpSettings&) const override
{
return true;
}
void handleBuildingComponentSettings(RefPointer<MAP_T> &mapObj) override;
void handleBuildingComponentSettingsMP(RefPointer<MAP_T> &mapObj,
const InfrastructureManagement::MountingPoint &mountingPoint);
bool showMountingPointType(InfrastructureManagement::MountingPointType_def::type mpType) const;
#endif // BLDCOMPONENT_FILTER_APPROACH
private:
std::string mountingPointHostname(const InfrastructureManagement::MountingPoint &mountingPoint);
bool componentStateOfHostname(const std::string &hostname, ComponentMonitor::ComponentState &stateOut);
private: // attributes
PluginProvider *m_pluginProvider{nullptr};
std::shared_ptr<InfrastructureManagement::Interface::Dtc> m_ismDtc;
std::shared_ptr<InfrastructureManagement::ForeignDataInterface> m_ismDataIfc;
std::shared_ptr<InfrastructureManagement::ForeignResourceManagementGuiInterface> m_ismGuiIfc;
std::shared_ptr<ComponentMonitor::Interface::Dtc> m_cmoDtc; // CMO ComponentMonitor
bool m_uniqueValueRendererAssigned{false};
bool m_resourceMode{false};
ResourceManagerMode m_resourceManagerMode{ResourceManagerMode::RMM_PlanActivityView};
QTimer *m_handleAllMountingPointsTimer{nullptr};
QMap<int, InfrastructureManagement::MountingPoint> m_mountingPoints; // key=id, value=
QMap<std::string, int> m_associatedAssetHostnameToMountingPointId; // key=AssociatedAssetHostname, value=MountingPointId
#ifdef SUPPORT_SELECTION_APPROACH
struct SelectionFilter
{
QVector<int> m_floorIds;
QVector<InfrastructureManagement::MountingPointType> m_mountingPointTypes;
} m_selectionFilter;
QTimer *m_selectionFilterTimer{nullptr};
#endif // SUPPORT_SELECTION_APPROACH
}; // class MountingPointToMap
} // namespace SituationMap
@@ -0,0 +1,359 @@
/**
* @RDE_HEADER@
* The MSEBridge class handles the transfer from MainStructureElement-DDS-Data to a representation on the map
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, NLSE, 2021-06-24
*/
// Own
#include "mse_bridge_to_map.h"
#include <Map/object_factory.h>
#include <LtsCoordTrans/lts_coord_trans.h>
#include <MathUtils/simple_helper.h>
#include <PluginInterfaces/gui_plugin_interface.h> // for method "getForeignGuiInterface"
#include <Plugins/Buildings/bld_info_gui_plugin_interface.h> // for Buildings::ForeignInfoGuiInterface
#include <InfrastructureManagement/ism_translation.h>
#include <SituationMap/Symbology/sidc_codec.h>
#include <Common/resource_path.h>
// Qt
#include <QUrl>
#include <QDir>
namespace SituationMap
{
int32_t MSEBridgeToMap::getSimId(const Sim2SituationMap::DDS_T &ddsData) const
{
return ddsData.id();
}
bool MSEBridgeToMap::init(PluginProvider *pluginProvider)
{
if (!pluginProvider ||
!pluginProvider->ismDtc())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no pluginProvider";
return false;
}
m_pluginProvider = pluginProvider;
m_ismDtc = pluginProvider->ismDtc();
m_bldInfoIfc = pluginProvider->bldInfoIfc();
// FilterManagement:
FilterClass::init(m_pluginProvider);
return true;
}
bool MSEBridgeToMap::run()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (!m_ismDtc)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no dtc";
return false;
}
m_mseIdWithoutValidFootprint.clear();
// mainFootprint
connect(m_ismDtc.get(), &InfrastructureManagement::Interface::Dtc::mainFootprintChanged,
this, &MSEBridgeToMap::onMainFootprintChanged);
// mainStructureElement
connect(m_ismDtc.get(), &InfrastructureManagement::Interface::Dtc::mainStructureElementChanged,
this, &MSEBridgeToMap::onMainStructureElementChanged);
// get:
m_ismDtc->mainStructureElements([this](const InfrastructureManagement::MainStructureElement & data)
{
onMainStructureElementChanged(data, DataModification::eAdded);
});
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
bool MSEBridgeToMap::isElapsed(const InfrastructureManagement::MainStructureElement &ddsData) const
{
if (BaseClass::isElapsed(ddsData))
return true;
if (ddsData.structureElementTypeId() != InfrastructureManagement::StructureElementType::Bridge)
return true;
const qint32 mseId = ddsData.id();
const InfrastructureManagement::MainFootprint &mainFootprint = m_ismDtc->mainFootprint(mseId);
if (mainFootprint.elements().size() < 4)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " mainFootprint with id=" << mseId << " is not sufficiant."
<< " mainFootprint.elements().size() = " << mainFootprint.elements().size();
if (!m_mseIdWithoutValidFootprint.contains(mseId))
{
INFO_LOG(m_logger) << LOGFUNCTION << " Save for future mainFootPrintChanged..."
<< " (m_mseIdWithoutValidFootprint.size()=" << m_mseIdWithoutValidFootprint.size();
m_mseIdWithoutValidFootprint.append(mseId);
}
return true;
}
return false;
}
bool MSEBridgeToMap::mapObjectsClicked(const QVector<UniqueMapId> &uniqueMapIds)
{
if (!m_bldInfoIfc)
return false;
const QVector<int32_t> &simIds = uniqueMapIds2SimIds(uniqueMapIds);
if (simIds.isEmpty())
return true;
m_bldInfoIfc->showBridgeInfoWindow(simIds);
return true;
}
bool MSEBridgeToMap::unifiedMapObjectData(UniqueMapId uniqueMapId, UnifiedMapObjectData &umodOut) const
{
if (!m_ismDtc)
return false;
int32_t simIdOut = -1;
if (!this->uniqueMapId2SimId(uniqueMapId, simIdOut))
return false;
umodOut = UnifiedMapObjectData();
RefPointer<MAP_T> mapObj = this->getMapObjectOfUniqueMapId(uniqueMapId);
if (mapObj.valid())
umodOut.m_image = mapObj->previewImage();
const auto cb = [this, simIdOut, &umodOut](const InfrastructureManagement::MainStructureElement & data) -> bool
{
if (data.id() == simIdOut)
{
umodOut.m_description1 = m_ismDtc->getBuildingDisplayName(data);
umodOut.m_participantData.m_typeName = InfrastructureManagement::toString(data.structureElementTypeId());
return true; // break loop
}
return false;
};
// sonst kann sich der compiler nicht zwischen bool und void entscheiden... !?
std::function<bool(const InfrastructureManagement::MainStructureElement &data)> cb1 = cb;
return m_ismDtc->mainStructureElements(cb1);
}
void MSEBridgeToMap::onMainStructureElementChanged(const InfrastructureManagement::MainStructureElement &data,
DataModification modType)
{
// const bool assignedToExercise = m_ismDtc->isElementAssignedToExercise(data, m_pluginProvider->exerciseId());
// if (modType == DataModification::eAdded && !assignedToExercise)
// return;
// if (modType == DataModification::eModified && !assignedToExercise)
// {
// /*
// * Was mse assigned to this exercise but someone removed the assignment?
// * If yes, remove mse from situation map by changing the request to "eRemoved".
// * If no, simply ignore the assignment.
// */
// const int32_t simId = getSimId(data);
// if (m_simId2UniqueMapId.contains(simId))
// modType = DataModification::eRemoved;
// else
// return;
// }
handleChanged(data, modType);
}
void MSEBridgeToMap::onMainFootprintChanged(const InfrastructureManagement::MainFootprint &data, DataModification modType)
{
if (modType == DataModification::eRemoved)
return;
if (data.elements().size() < 4)
return;
const int32_t mseId = data.id(); // mfpId == mseId
if (m_mseIdWithoutValidFootprint.contains(mseId))
{
// try again:
const InfrastructureManagement::MainStructureElement &mseData= m_ismDtc->mainStructureElement(mseId);
if (mseData.id() == mseId)
{
m_mseIdWithoutValidFootprint.removeAll(mseId);
onMainStructureElementChanged(mseData, DataModification::eAdded);
}
}
}
bool MSEBridgeToMap::updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
<< " id=" << ddsData.id()
<< " name=" << ddsData.name()
<< " geoPosition=" << ddsData.geoPosition()
<< " angle=" << ddsData.angle();
// show just the ObjectAppearance::Technical
mapObj->setVisibility(ObjectAppearance::Tactical, false);
// Identifier
mapObj->setIdentifier(m_ismDtc->getBuildingDisplayName(ddsData));
// Bridge symbol does not work, obstacle yes - don´t know the difference (line vs. area???)
// SymbolData symData; /*= mapObj->symbol();*/
// // symData.sidc = AdvancedSymbology::SidcCodec::encodeComplete(mapObj->symbologyType(), "10011500001301000000"); // 10011500001301000000 - Bridge
// symData.sidc = AdvancedSymbology::SidcCodec::encodeComplete(AdvancedSymbology::SymbologyType::APP6D, "10012500002714000000"); // 10012500002714000000 - Protection _Areas_: Bridge
// symData.color = Qt::yellow;
// symData.size = 1.0;
// mapObj->setSymbol(symData);
const qint32 bridgeId = getSimId(ddsData); // ddsData.id();
//
// retrieve relative points of footprint:
//
QList<QPointF> relPositions2D;
{
const InfrastructureManagement::MainFootprint &mainFootprint = m_ismDtc->mainFootprint(bridgeId);
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
<< " id=" << ddsData.id()
<< " name=" << ddsData.name()
<< " mainFootprint.elements().size()=" << mainFootprint.elements().size();
relPositions2D.reserve(mainFootprint.elements().size());
// sorted per definition
for (const InfrastructureManagement::FootprintElement &element : mainFootprint.elements())
{
const auto &relPos = element.relPosition();
relPositions2D += QPointF(relPos.offsetX(), relPos.offsetY());
}
}
DEBUG_LOG(m_logger) << "footprint = " << relPositions2D;
//
// translate to absolute
//
PositionCont absPositionsGeo;
const Core::GeoPosition &geoPosition = ddsData.geoPosition();
const double angleRad = ddsData.angle() * LtsCoordTrans::deg2rad();
const QPointF referencePointGeo(geoPosition.lon(), geoPosition.lat());
const LtsCoordTrans::UtmCoordinate referencePointUTM = LtsCoordTrans::UtmCoordinate::fromGeographic(referencePointGeo);
// add relPos to referencePoint:
const QPointF center;
absPositionsGeo.reserve(relPositions2D.size());
for (const auto &relPosition : qAsConst(relPositions2D))
{
const QPointF relPositionRotate = MathUtils::rotate(relPosition, center, angleRad); // rotate relPosition by angleRad around 0,0
const QPointF pGeo = referencePointUTM.geographic(relPositionRotate); // add relPosition to referencePointUTM
absPositionsGeo.append(Point3D::fromQPointF(pGeo));
} // for
DEBUG_LOG(m_logger) << "absPositionsGeo = " << absPositionsGeo;
mapObj->setPositions(absPositionsGeo);
// display referencePoint:
mapObj->setMarker(Point3D::fromQPointF(referencePointGeo));
// [GUEZE-691]
// Model, QColor, LinePattern, FillStyle with color
//
// QUrl(QStringLiteral("/shd/CTC/TOOLS/ArcGIS/Runtime/Data/3D/3dexport/JetAnim/jet anim.fbx")); // fbx -> works
// QUrl(QStringLiteral("/shd/CTC/TOOLS/ArcGIS/Runtime/Data/3D/bradley_low_3ds/bradle.3ds")); // 3ds -> works
// QUrl(QStringLiteral("/shd/CTC/TOOLS/ArcGIS/Runtime/Data/3D/Sketchup2017/Bruecke_001_ohnePfeiler.3ds"));
// -> /usr/share/arcgis/resources/3Dmodels
static QString resourcePath = SituationMap::getResourcePath() + QDir::separator() + QStringLiteral("3Dmodels") + QDir::separator();
BuildingOutline::ModelSceneSymbolData mssd;
// mssd.url = QUrl(resourcePath + QString(QStringLiteral("bridge_intact.3ds"))); // modelled vertical
mssd.url = QUrl(resourcePath + QString(QStringLiteral("SPD/buildings/Bruecke_20m/Bruecke_20m.dae"))); // modelled horizontal
mssd.scale = 1.0;
QColor color = Qt::darkGray;
LinePattern linePattern = LinePattern::Dash;
FillPattern fillPattern = FillPattern::Solid;
// DDS topic 'ISM::BridgeChangedStatus' is for recording purpose
// Here it´s sufficiant to use m_ismDtc->getBridgeStatus
switch(m_ismDtc->getBridgeStatus(ddsData.id()).underlying())
{
case InfrastructureManagement::BridgeStatus::Broken:
{
// use a) bridge_broken.3ds or b) bridge_intact but with scale==0.25
QFileInfo fi(resourcePath + QString(QStringLiteral("SPD/buildings/Bruecke_20m/Bruecke_20m_defekt.dae")));
if (fi.exists())
mssd.url = QUrl(fi.absoluteFilePath());
else
mssd.scale = 0.25;
// LinePattern maybe helpful for 3D (where the fillpattern is not visible depending on SurfacePlaecementMode)
linePattern = LinePattern::Dot;
fillPattern = FillPattern::DiagonalCross;
}
break;
case InfrastructureManagement::BridgeStatus::Intact:
mssd.scale = 1.2; // to cover the outline (which angle differs)
color.setAlphaF(0.5);
break;
default:
color = Qt::yellow;
break;
}
// Identifier: Many buildings in a city lead to many (unreadable) identifiers -> filter flag is introduced
TextStyle ts = mapObj->textStyle();
ts.setHorizontalAlignment(HorizontalAlignment::Center);
// ts.setTextColor(color); // black is default and sufficiant
LineStyle ls = mapObj->lineStyle();
ls.setLinePattern(linePattern);
FillStyle fs = mapObj->fillStyle();
fs.setFillColor(color);
fs.setFillPattern(fillPattern);
mapObj->setTextStyle(ts);
mapObj->setLineStyle(ls);
mapObj->setFillStyle(fs);
mssd.heading = (ddsData.angle()*-1)+90; // heading: degree, clockwise, 0 is north/12
mapObj->setModelSceneSymbolData(mssd);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
bool MSEBridgeToMap::symbolAppearanceSettingsChangesAreRelevant(const FilterManagement::SymbolAppearanceSettings::Settings &newSas) const
{
return (m_currentSymbolSettings.symbolSettings.symbolScale != newSas.symbolSettings.symbolScale) ||
(m_currentSymbolSettings.symbolSettings.showBuildingIdentifier != newSas.symbolSettings.showBuildingIdentifier);
}
void MSEBridgeToMap::handleSymbolAppearanceSettings(RefPointer<MAP_T> &mapObj)
{
mapObj->setScale(m_currentSymbolSettings.symbolSettings.symbolScale);
mapObj->setIdentifierVisible(m_currentSymbolSettings.symbolSettings.showBuildingIdentifier);
}
}
@@ -0,0 +1,78 @@
/**
* @RDE_HEADER@
* The MSEBridge class handles the transfer from MainStructureElement-DDS-Data to a representation on the map
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, NLSE, 2021-06-24
*/
#pragma once
#include "sim_to_situation_map_tmpl.h"
#include <Plugins/InfrastructureManagement/ism_data_plugin_interface.h>
#include <Buildings/bld_dtc.h> // damage
#include <MapObjects/building_outline.h>
namespace Buildings
{
class ForeignInfoGuiInterface;
}
namespace SituationMap
{
class MSEBridgeToMap final : public Sim2SituationMap<InfrastructureManagement::MainStructureElement, SituationMap::BuildingOutline>
, protected DdsFilterHandling<SituationMap::BuildingOutline>
{
Q_OBJECT
using BaseClass = SituationMap::Sim2SituationMap<InfrastructureManagement::MainStructureElement, SituationMap::BuildingOutline>;
using FilterClass = DdsFilterHandling<SituationMap::BuildingOutline>;
public:
explicit MSEBridgeToMap(ObjectFactory &objFac,
const QString &layername,
int drawOrder,
const char *loggerName)
: BaseClass(objFac, layername, drawOrder, loggerName)
, FilterClass(loggerName, this)
{}
bool init(PluginProvider *pluginProvider);
bool run() override;
void stop() override
{
if (m_ismDtc)
m_ismDtc->disconnect(this);
}
bool isElapsed(const InfrastructureManagement::MainStructureElement &ddsData) const override;
bool mapObjectsClicked(const QVector<UniqueMapId> &uniqueMapIds) override;
bool unifiedMapObjectData(UniqueMapId uniqueMapId, UnifiedMapObjectData &umodOut) const override;
protected Q_SLOTS:
void onMainStructureElementChanged(const InfrastructureManagement::MainStructureElement &data,
DataModification modType = DataModification::eAdded);
void onMainFootprintChanged(const InfrastructureManagement::MainFootprint &data,
DataModification modType = DataModification::eAdded);
protected:
int32_t getSimId(const Sim2SituationMap::DDS_T &ddsData) const override;
bool updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj) override;
bool symbolAppearanceSettingsChangesAreRelevant(const FilterManagement::SymbolAppearanceSettings::Settings &newSas) const override;
void handleSymbolAppearanceSettings(RefPointer<MAP_T> &mapObj) override;
private:
PluginProvider *m_pluginProvider = nullptr;
std::shared_ptr<InfrastructureManagement::Interface::Dtc> m_ismDtc;
std::shared_ptr<Buildings::ForeignInfoGuiInterface> m_bldInfoIfc;
mutable QVector<int> m_mseIdWithoutValidFootprint;
};
} // namespace
@@ -0,0 +1,221 @@
/**
* @RDE_HEADER@
* The MSEPointToMap class handles the transfer from MainStructureElement-DDS-Data to a representation on the map
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, NLSE, 2018-06-26
*/
// Own
#include "mse_point_to_map.h"
#include <Map/object_factory.h>
#include <PluginInterfaces/gui_plugin_interface.h>
#include <InfrastructureManagement/ism_translation.h>
#include <Plugins/Buildings/bld_info_gui_plugin_interface.h> // for Buildings::ForeignInfoGuiInterface
// Qt
#include <QPainter>
#include <sstream>
using namespace SituationMap;
QImage renderApproachingPoint(const QColor &color)
{
int size = 100;
QImage image(size, size, QImage::Format_ARGB32);
image.fill(Qt::transparent);
QPainter painter(&image);
painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
// 'marking':
painter.setPen(QPen(Qt::NoPen)); // rect with no outter line
painter.setBrush(QBrush(color, Qt::Dense5Pattern)); // fillPattern (Dense4Pattern .. Dense6Pattern)
painter.drawRect(image.rect());
// prepare remaining:
QPen pen(color);
pen.setWidth(5);
painter.setPen(pen);
const int sizeHalf = size / 2.0;
QPointF center(sizeHalf, sizeHalf);
// circle
painter.setBrush(color);
painter.drawEllipse(center, sizeHalf * 0.1, sizeHalf * 0.1);
// lines
QLine newLine(sizeHalf, 0, sizeHalf, sizeHalf * 0.6);
painter.drawLine(newLine);
QTransform trans;
trans.translate(sizeHalf, sizeHalf);
trans.rotate(90);
trans.translate(-sizeHalf, -sizeHalf);
newLine = trans.map(newLine);
painter.drawLine(newLine);
newLine = trans.map(newLine);
painter.drawLine(newLine);
newLine = trans.map(newLine);
painter.drawLine(newLine);
painter.end();
return image;
}
bool MSEPointToMap::init(PluginProvider *pluginProvider)
{
if (!pluginProvider ||
!pluginProvider->ismDtc() ||
!pluginProvider->ismDataIfc())
return false;
m_pluginProvider = pluginProvider;
DEBUG_LOG(m_logger) << LOGFUNCTION << " exerciseId=" << m_pluginProvider->exerciseId();
m_ismDtc = m_pluginProvider->ismDtc();
m_bldInfoIfc = pluginProvider->bldInfoIfc();
// InfrastructureManagement::MountingPoint::init(); // load all icons before using them later
// FilterManagement:
FilterClass::init(m_pluginProvider);
return true;
}
bool MSEPointToMap::run()
{
DEBUG_LOG(m_logger) << "Starting to run";
this->stop();
// Main Structure Element to get dependence on the exercise
connect(m_ismDtc.get(), &InfrastructureManagement::Interface::Dtc::mainStructureElementChanged,
this, &MSEPointToMap::handleChanged, Qt::UniqueConnection);
// get:
m_ismDtc->mainStructureElements([this](const InfrastructureManagement::MainStructureElement & data)
{
handleChanged(data, DataModification::eAdded);
});
return true;
}
void MSEPointToMap::stop()
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " Stopping";
if (m_ismDtc)
m_ismDtc->disconnect(this);
}
bool MSEPointToMap::unifiedMapObjectData(UniqueMapId uniqueMapId, UnifiedMapObjectData &umodOut) const
{
if (!m_ismDtc)
return false;
int32_t simIdOut = -1;
if (!this->uniqueMapId2SimId(uniqueMapId, simIdOut))
return false;
umodOut = UnifiedMapObjectData();
RefPointer<MAP_T> mapObj = this->getMapObjectOfUniqueMapId(uniqueMapId);
if (mapObj.valid())
umodOut.m_image = mapObj->previewImage();
const auto cb = [simIdOut, &umodOut](const InfrastructureManagement::MainStructureElement & data) -> bool
{
if (data.id() == simIdOut)
{
umodOut.m_description1 = QString::fromStdString(data.name());
umodOut.m_participantData.m_typeName = InfrastructureManagement::toString(data.structureElementTypeId());
return true; // break loop
}
return false;
};
// sonst kann sich der compiler nicht zwischen bool und void entscheiden... !?
std::function<bool(const InfrastructureManagement::MainStructureElement &data)> cb1 = cb;
return m_ismDtc->mainStructureElements(cb1);
}
bool MSEPointToMap::isElapsed(const Sim2SituationMap::DDS_T &data) const
{
// true -> hide
// false -> show
DEBUG_LOG(m_logger) << " isElapsed";
if (BaseClass::isElapsed(data))
return true;
if (data.isDeleted())
return true;
if (data.structureElementTypeId() != InfrastructureManagement::StructureElementType::ApproachingPoint)
return true;
return false;
}
int32_t MSEPointToMap::getSimId(const Sim2SituationMap::DDS_T &ddsData) const
{
return ddsData.id();
}
bool MSEPointToMap::updateElementImpl(const Sim2SituationMap::DDS_T &ddsData, RefPointer<Sim2SituationMap::MAP_T> mapObj)
{
TRACE_LOG(m_logger) << LOGFUNCTION
<< ", id " << ddsData.id()
<< ", name = " << ddsData.name();
// Identifier:
mapObj->setIdentifier(QString::fromStdString(ddsData.name()));
TextStyle textStyle;
textStyle.setSize(10);
if (ddsData.structureElementTypeId() == InfrastructureManagement::StructureElementType::ApproachingPoint)
{
textStyle.setTextColor(Qt::yellow);
mapObj->setProxyImage(renderApproachingPoint(Qt::yellow), QSize(50, 50));
}
mapObj->setTextStyle(textStyle);
// Position:
const Core::GeoPosition &geoPos = ddsData.geoPosition();
mapObj->setOrigin(Point3D(geoPos.lon(), geoPos.lat(), geoPos.z()));
return true;
}
bool MSEPointToMap::mapObjectsClicked(const QVector<UniqueMapId> &uniqueMapIds)
{
if (!m_bldInfoIfc)
return false;
const QVector<int32_t> &simIds = uniqueMapIds2SimIds(uniqueMapIds);
if (simIds.isEmpty())
return true;
return true;
}
@@ -0,0 +1,69 @@
/**
* @RDE_HEADER@
* The MSEPointToMap class handles the transfer from MainStructureElement-DDS-Data to a representation on the map
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, NLSE, 2018-06-26
*/
#pragma once
#include "sim_to_situation_map_tmpl.h"
#include <Plugins/InfrastructureManagement/ism_data_plugin_interface.h>
#include <MapObjects/geo_image.h>
namespace SituationMap
{
// MSE == MainStructureElement
class MSEPointToMap final : public Sim2SituationMap<InfrastructureManagement::MainStructureElement, SituationMap::GeoImage>
, protected DdsFilterHandling<SituationMap::GeoImage>
{
Q_OBJECT
using BaseClass = SituationMap::Sim2SituationMap<InfrastructureManagement::MainStructureElement, SituationMap::GeoImage>;
using FilterClass = DdsFilterHandling<SituationMap::GeoImage>;
public:
MSEPointToMap(ObjectFactory &objFac,
const QString &layername,
int drawOrder,
const char *loggerName)
: BaseClass(objFac, layername, drawOrder, loggerName)
, FilterClass(loggerName, this)
, m_pluginProvider(nullptr)
{}
bool init(PluginProvider *pluginProvider);
bool run() override;
void stop() override;
bool mapObjectsClicked(const QVector<UniqueMapId> &uniqueMapIds) override;
bool unifiedMapObjectData(UniqueMapId uniqueMapId, UnifiedMapObjectData &umodOut) const override;
protected:
bool isElapsed(const Sim2SituationMap::DDS_T &data) const override;
int32_t getSimId(const Sim2SituationMap::DDS_T &ddsData) const override;
bool updateElementImpl(const DDS_T &ddsData, RefPointer<MAP_T> mapObj) override;
bool symbolAppearanceSettingsChangesAreRelevant(const FilterManagement::SymbolAppearanceSettings::Settings &newSas) const override
{
return (m_currentSymbolSettings.symbolSettings.symbolScale != newSas.symbolSettings.symbolScale);
}
void handleSymbolAppearanceSettings(RefPointer<MAP_T> &mapObj) override
{
mapObj->setScale(m_currentSymbolSettings.symbolSettings.symbolScale);
}
private:
private: // attributes
PluginProvider *m_pluginProvider;
std::shared_ptr<InfrastructureManagement::Interface::Dtc> m_ismDtc;
std::shared_ptr<Buildings::ForeignInfoGuiInterface> m_bldInfoIfc;
}; // class MSEPointToMap
} // namespace SituationMap
@@ -0,0 +1,180 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#include "ncontamination_to_map.h"
#include <Map/map.h>
#include <Map/object_factory.h>
namespace SituationMap
{
//------------------------------------------------------------------------------
bool NContamination2SituationMap::run()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (!m_aesDtc)
return false;
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::nContaminationChanged,
this, &NContamination2SituationMap::handleChanged, Qt::UniqueConnection);
// get:
m_aesDtc->nContaminations([this](const AreaEffectSimulation::NContamination &data)
{
handleChanged(data, DataModification::eAdded);
});
if (m_objFac.map() && (m_objFac.map()->mode() == Mode::Mode_3D))
connect(m_pluginProvider, &PluginProvider::partitionTimeChanged,
this, &NContamination2SituationMap::onPartitionTimeChanged, Qt::UniqueConnection);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return BaseClass::run();
}
void NContamination2SituationMap::onPartitionTimeChanged(qint64 newPartitionTime)
{
// TRACE_LOG(m_logger) << LOGFUNCTION << " START, newPartitionTime=" << newPartitionTime
// << ", exerciseId = " << m_pluginProvider->exerciseId()
// << ", workspaceId = " << m_pluginProvider->workspaceId()
// << ", this=" << this;
updateAllSpheres3D(newPartitionTime);
}
void NContamination2SituationMap::updateAllSpheres3D(qint64 newPartitionTime)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
<< ", m_simId2UniqueMapId.size = " << m_simId2UniqueMapId.size();
// iterate using m_simId2UniqueMapId vs using m_ddsDataContainer
// m_simId2UniqueMapId contains existing (map) objects
// m_ddsDataContainer may contain outdated elements (expired).
// But expired items are relevant for listOverviews...
// so iterate using m_simId2UniqueMapId:
QMapIterator<int32_t, UniqueMapId> it(m_simId2UniqueMapId);
while (it.hasNext())
{
it.next();
const UniqueMapId uniqueMapId = it.value();
RefPointer<MAP_T> mapObj = m_objFac.get<MAP_T>(uniqueMapId);
if (!mapObj.valid())
continue;
const int simId = it.key();
const AreaEffectSimulation::NContamination &nCont = m_aesDtc->nContamination(simId);
if (nCont.id() != simId)
continue;
if (updateSphere3D(mapObj, nCont, newPartitionTime))
if (!mapObj->updateView())
WARNING_LOG(m_logger) << LOGFUNCTION << " simId = " << simId << " updateView failed";
} // while
DEBUG_LOG(m_logger) << LOGFUNCTION << " END";
}
bool NContamination2SituationMap::updateSphere3D(RefPointer<Sim2SituationMap::MAP_T> mapObj, const AreaEffectSimulation::NContamination &data, qint64 newPartitionTime)
{
const int32_t simId = data.id(); // simId of area ('parent')
if (!mapObj)
return false;
bool bUpdateRequired = false;
const bool bDesiredNewState = (data.effectStateId().underlying() == AreaEffectSimulation::AesEffectState_def::EsActivated) && // Assume, that NContamination will not expire within that 5 seconds...
((newPartitionTime - data.sampleTime() < 5000)); // 5000 = 5 sec
TRACE_LOG(m_logger) << LOGFUNCTION << ", START" << " simId = " << simId
<< ", sampleTime " << data.sampleTime()
<< ", bDesiredNewState " << bDesiredNewState;
// The sphere begins being displayed at the impact time, object has EffectState::Active.
// Accordingly impactPosition can _not_ change anymore!!!
// So we do not have to update the origin of the SceneMarker
// We can simplify and recognized the changes: ADDING or REMOVING the marker
// MSS has to be removed?
if (mapObj->hasDetonation() && !bDesiredNewState)
{
DEBUG_LOG(m_logger) << LOGFUNCTION << ", START REMOVE " << " simId = " << simId;
mapObj->resetDetonation();
bUpdateRequired = true;
}
// MSS has to be added?
else if (!mapObj->hasDetonation() && bDesiredNewState)
{
DEBUG_LOG(m_logger) << LOGFUNCTION << ", START ADD " << " simId = " << simId;
const Core::GeoPosition2D &geoPos = data.impactPosition();
Point3D markerOrigin(geoPos.lon(), geoPos.lat(), 0); // ToDo: impactPosition -> 3D
mapObj->setDetonation(markerOrigin, data.impactRadius());
bUpdateRequired = true;
}
TRACE_LOG(m_logger) << LOGFUNCTION << ", END" << " simId = " << simId;
return bUpdateRequired;
}
bool NContamination2SituationMap::updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
// show just the ObjectAppearance::Technical
mapObj->setVisibility(ObjectAppearance::Tactical, false);
mapObj->setIdentifier(QString::fromStdString(ddsData.name()));
// if partyId is not set (like B,C agent), use default color
if (ddsData.partyId().is_set())
mapObj->setPartyId(ddsData.partyId().get());
mapObj->setAesState(effectState2aesState(ddsData.effectStateId().underlying()));
if (m_objFac.map() && (m_objFac.map()->mode() == Mode::Mode_3D))
updateSphere3D(mapObj, ddsData, m_pluginProvider->partitionTime());
const int32_t simId = ddsData.id();
AreaEffectSimulation::AesItemView itemView;
if (m_aesDtc->aesItemViewFromEntityId(simId, AreaEffectSimulation::AesType::AtNContamination, itemView))
this->updateGeometry(itemView, mapObj);
else
{
DEBUG_LOG(m_logger) << LOGFUNCTION
<< " no AesItemView (AtNContamination) found"
<< ", simId = " << simId
<< ", provide fallBackGeometry";
// provide fallbackGeometry to avoid errorMsg like 'incorrect number of positions'
mapObj->setPositions({{0.0, 0.0, .0},
{0.0, 0.1, .0},
{0.1, 0.1, .0},
{0.1, 0.0, .0}});
// do not return here, perform stuff like updateVisibility and so on
}
// 'Impact':
const Core::GeoPosition2D& impactPos2D = ddsData.impactPosition();
mapObj->setImpactOrigin(Point3D(impactPos2D.lon(), impactPos2D.lat(), 0.0));
updateVisibility(ddsData, mapObj);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
}
@@ -0,0 +1,52 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "aes_to_situation_map_tmpl.h"
#include <Plugins/AreaEffectSimulation/aes_data_plugin_interface.h>
#include <MapObjects/nuclear_agent.h>
#include <QObject>
namespace SituationMap
{
class NContamination2SituationMap;
template <>
struct Aes2SituationMapTraits<NContamination2SituationMap>
{
using DDS_TYPE = AreaEffectSimulation::NContamination;
using MAP_TYPE = SituationMap::NuclearAgent;
static const AreaEffectSimulation::AesType_def::type aesType = AreaEffectSimulation::AesType_def::AtNContamination;
};
class NContamination2SituationMap final : public Aes2SituationMap<NContamination2SituationMap>
{
Q_OBJECT
public:
using BaseClass = SituationMap::Aes2SituationMap<NContamination2SituationMap>;
using BaseClass::BaseClass;
bool run() override;
bool iterateAesData(const std::function<bool(const AreaEffectSimulation::NContamination &data)> &cb) const
{
return m_aesDtc->nContaminations(cb);
}
protected Q_SLOTS:
void onPartitionTimeChanged(qint64 newPartitionTime);
protected:
void updateAllSpheres3D(qint64 newPartitionTime);
bool updateSphere3D(RefPointer<MAP_T> mapObj, const AreaEffectSimulation::NContamination &data, qint64 newPartitionTime);
protected:
bool updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj) override;
};
} // namespace
@@ -0,0 +1,376 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#include "off_route_to_map.h"
#include <Map/map.h>
#include <Map/object_factory.h>
#include <Map/layer_factory.h>
namespace SituationMap
{
static int s_offRouteMine2 = 254;
//------------------------------------------------------------------------------
bool OffRoute2SituationMap::run()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (!m_aesDtc)
return false;
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::offRouteMineChanged,
this, &OffRoute2SituationMap::handleChanged, Qt::UniqueConnection);
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::aesItemViewChanged,
this, &OffRoute2SituationMap::onAesItemViewChanged, Qt::UniqueConnection);
// get:
m_aesDtc->offRouteMines([this](const AreaEffectSimulation::OffRouteMine &data)
{
handleChanged(data, DataModification::eAdded);
});
if (m_objFac.map() && (m_objFac.map()->mode() == Mode::Mode_3D))
connect(m_pluginProvider, &PluginProvider::partitionTimeChanged,
this, &OffRoute2SituationMap::onPartitionTimeChanged, Qt::UniqueConnection);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return BaseClass::run();
}
void OffRoute2SituationMap::onPartitionTimeChanged(qint64 newPartitionTime)
{
// TRACE_LOG(m_logger) << LOGFUNCTION << " START, newPartitionTime=" << newPartitionTime
// << ", exerciseId = " << m_pluginProvider->exerciseId()
// << ", workspaceId = " << m_pluginProvider->workspaceId()
// << ", this=" << this;
updateAllDetonationSpheres(newPartitionTime);
}
void OffRoute2SituationMap::onAesItemViewChanged(const AreaEffectSimulation::AesItemView &data, DataModification modType)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START, " << " data.aesTypeId()=" << data.aesTypeId() << " modType=" << modType;
// there are many project/situation, where the following condition will never fullfilled.
// so check this BEFORE the id to save time :-)
if (data.aesTypeId() != AreaEffectSimulation::AesType::AtOffRouteMineSecondary)
return;
const int32_t simId = data.aesItemId(); // simId of area ('parent')
if (simId < 0)
return;
// real work:
updateSecondary(simId);
TRACE_LOG(m_logger) << LOGFUNCTION << " END" << " data.aesTypeId()=" << data.aesTypeId() << " modType=" << modType;
}
void OffRoute2SituationMap::updateAllDetonationSpheres(qint64 newPartitionTime)
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " START"
<< ", m_simId2UniqueMapId.size = " << m_simId2UniqueMapId.size();
// iterate using m_simId2UniqueMapId vs using m_ddsDataContainer
// m_simId2UniqueMapId contains existing (map) objects
// m_ddsDataContainer may contain outdated elements (expired).
// But expired items are relevant for listOverviews...
// so iterate using m_simId2UniqueMapId:
QMapIterator<int32_t, UniqueMapId> it(m_simId2UniqueMapId);
while (it.hasNext())
{
it.next();
const UniqueMapId uniqueMapId = it.value();
RefPointer<MAP_T> mapObj = m_objFac.get<MAP_T>(uniqueMapId);
if (!mapObj.valid())
continue;
const int simId = it.key();
const AreaEffectSimulation::OffRouteMine &offRouteMine = m_aesDtc->offRouteMine(simId);
if (offRouteMine.id() != simId)
continue;
if (updateDetonationSphere3D(mapObj, offRouteMine, newPartitionTime))
if (!mapObj->updateView())
WARNING_LOG(m_logger) << LOGFUNCTION << " simId = " << simId << " updateView failed";
} // while
DEBUG_LOG(m_logger) << LOGFUNCTION << " END";
}
bool OffRoute2SituationMap::updateDetonationSphere3D(RefPointer<Sim2SituationMap::MAP_T> mapObj, const AreaEffectSimulation::OffRouteMine &trap, qint64 newPartitionTime)
{
const int32_t simId = trap.id(); // simId of area ('parent')
if (!mapObj)
return false;
bool bUpdateRequired = false;
const bool bDesiredNewState = trap.triggered() && ((newPartitionTime - trap.sampleTime() < 5000)); // 5000 = 5 sec
TRACE_LOG(m_logger) << LOGFUNCTION << ", START" << " simId = " << simId
<< ", sampleTime " << trap.sampleTime()
<< ", bDesiredNewState " << bDesiredNewState;
// The sphere begins being displayed at the impact time, object has EffectState::Active.
// Accordingly impactPosition can _not_ change anymore!!!
// So we do not have to update the origin of the SceneMarker
// We can simplify and recognized the changes: ADDING or REMOVING the marker
//#define RENDERER_APPROACH
#ifdef RENDERER_APPROACH
// 3DMarker has to be removed?
if (mapObj->has3DMarkerRenderer() && !bDesiredNewState)
{
INFO_LOG(m_logger) << LOGFUNCTION << ", START REMOVE " << " simId = " << simId;
mapObj->set3DMarkerRenderer(Point3D(), QVariantMap());
bUpdateRequired = true;
}
// 3DMarker has to be added?
else if (!mapObj->has3DMarkerRenderer() && bDesiredNewState)
{
INFO_LOG(m_logger) << LOGFUNCTION << ", START ADD " << " simId = " << simId;
const Core::GeoPosition2D &geoPos = trap.area().cornerBottomLeft(); // should be impactPosition
Point3D markerOrigin(geoPos.lon(), geoPos.lat(), 0); // ToDo: impactPosition -> 3D
QVariantMap attribMap;
QString attribValue;
const QColor &majorColor = mapObj->majorColor();
attribValue = QString(QStringLiteral("Impact_Color_%1")).arg(majorColor.name());
attribMap.insert(QStringLiteral("IMPACT_COLOR"), attribValue);
// compare AdapterDds::assignUniqueValueRendererAesCentral:
// double radius = std::max( (trap.impactRadius().is_set() ? trap.impactRadius().get() : 1) , 1.0); // at least 1 meter
// // (------------------------------------------------------------)
// see GUEZE-3307: Immer 10m;
const double radius = 10;
attribValue = QString(QStringLiteral("Impact_Radius_%1")).arg(radius);
attribMap.insert(QStringLiteral("IMPACT_RADIUS"), attribValue);
LayerFactory::UniqueValueDataAesCentral::TYPE type{LayerFactory::UniqueValueDataAesCentral::TYPE::SPHERE};
// BoobyTrap _may_ be an CONE, OffRouteMine is _always_ a sphere
// if (trap.centralAngle().is_set())
// type = LayerFactory::UniqueValueDataAesCentral::TYPE::CONE;
attribValue = QString(QStringLiteral("Impact_Type_%1")).arg(LayerFactory::toString(type));
attribMap.insert(QStringLiteral("IMPACT_TYPE"), attribValue);
// SceneProperties: HEADING, PITCH, ROLL
// int heading = 0;
// if (trap.rotationAngle().is_set())
// heading = static_cast<int>(trap.rotationAngle().get());
//attribMap.insert(QStringLiteral("HEADING"), ((heading+90)%360)); // data.rotationAngle()
attribMap.insert(QStringLiteral("HEADING"), 0); // data.rotationAngle()
attribMap.insert(QStringLiteral("PITCH") , 0);
attribMap.insert(QStringLiteral("ROLL") , 90);
// qCritical() << " ident " << mapObj->identifier() << ", " << attribMap;
mapObj->set3DMarkerRenderer(markerOrigin, attribMap);
bUpdateRequired = true;
}
#else // RENDERER_APPROACH
// SceneSymbol has to be removed?
if (mapObj->has3DMarkerSceneSymbol() && !bDesiredNewState)
{
FATAL_LOG(m_logger) << LOGFUNCTION << ", START REMOVE " << " simId = " << simId;
mapObj->set3DMarkerSceneSymbol(Point3D(), {});
bUpdateRequired = true;
}
else if (!mapObj->has3DMarkerSceneSymbol() && bDesiredNewState)
{
FATAL_LOG(m_logger) << LOGFUNCTION << ", START ADD " << " simId = " << simId;
const Core::GeoPosition2D &geoPos = trap.area().cornerBottomLeft(); // should be impactPosition
Point3D markerOrigin(geoPos.lon(), geoPos.lat(), 0); // ToDo: impactPosition -> 3D
VirtualMine::SceneSymbolData ssData;
const QColor &majorColor = mapObj->majorColor();
ssData.color = majorColor;
ssData.radius = std::max( (trap.impactRadius().is_set() ? trap.impactRadius().get() : 1) , 1.0); // at least 1 meter
// BoobyTrap _may_ be an CONE, OffRouteMine is _always_ a sphere
// if (trap.centralAngle().is_set())
// type = LayerFactory::UniqueValueDataAesCentral::TYPE::CONE;
ssData.cone = false;
// int heading = 0;
// if (trap.rotationAngle().is_set())
// heading = static_cast<int>(data.rotationAngle().get());
// ssData.heading = (heading+90)%360;
// ssData.pitch = 0.0;
// ssData.roll = 90;
mapObj->set3DMarkerSceneSymbol(markerOrigin, ssData);
}
#endif // RENDERER_APPROACH
TRACE_LOG(m_logger) << LOGFUNCTION << ", END" << " simId = " << simId;
return bUpdateRequired;
}
bool OffRoute2SituationMap::updateSecondary(int32_t simId, bool bUpdateJust3DPart)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START" << " simId = " << simId
<< ", bUpdateJust3DPart" << bUpdateJust3DPart;
if (simId < 0)
return false;
// MapObj should exist:
RefPointer<MAP_T> mapObj = this->getMapObjectOfSimId(simId);
if (!mapObj.valid())
{
DEBUG_LOG(m_logger) << LOGFUNCTION
<< " getMapObjectOfSimId failed"
<< " simId = " << simId << " (maybe expired)";
return false;
}
//
// AesitemView: AtOffRouteMineSecondary
//
const AreaEffectSimulation::OffRouteMine &trap = m_aesDtc->offRouteMine(simId);
if (trap.chargeStruct().chargeTypeId() == s_offRouteMine2) // s_offRouteMine2 = 254 == Typ2 / Russland ->_mit_ zusaetzlichen Wirkkreis:
{
AreaEffectSimulation::AesItemView dataAesItemView;
if (m_aesDtc->aesItemViewFromEntityId(simId, AreaEffectSimulation::AesType::AtOffRouteMineSecondary, dataAesItemView))
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " simId = " << simId << " AesItemViewForSecondary found :-) ";
} else {
WARNING_LOG(m_logger) << LOGFUNCTION << " simId = " << simId << " no AesItemViewForSecondary found. :-( ";
}
// simId == aesItemId
if ((dataAesItemView.aesItemId() == simId) &&
(trap.id() == simId) &&
trap.triggered())
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " simId = " << simId << " setSubsidiaryLine";
VirtualMine::OptionalData optData;
optData.closed = true;
mapObj->setSubsidiaryLine(0, // key
form2PosCont(dataAesItemView.form()), optData);
} else {
DEBUG_LOG(m_logger) << LOGFUNCTION << " simId = " << simId << " removeSubsidiaryLine";
mapObj->removeSubsidiaryLine(0);
}
if (!mapObj->updateView()){
ERROR_LOG(m_logger) << LOGFUNCTION << " simId = " << simId << " updateView failed";
return false;
}
}
TRACE_LOG(m_logger) << LOGFUNCTION << ", END" << " simId = " << simId
<< " trap.triggered(" << trap.triggered();
return true;
}
bool OffRoute2SituationMap::updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
// show just the ObjectAppearance::Technical
mapObj->setVisibility(ObjectAppearance::Tactical, false);
mapObj->setIdentifier(QString::fromStdString(ddsData.name()));
// if partyId is not set (like B,C agent), use default color
if (ddsData.partyId().is_set())
mapObj->setPartyId(ddsData.partyId().get());
mapObj->setAesState(effectState2aesState(ddsData.effectStateId().underlying()));
const int32_t simId = ddsData.id();
AreaEffectSimulation::AesItemView itemView;
if (m_aesDtc->aesItemViewFromEntityId(simId, AreaEffectSimulation::AesType::AtOffRouteMine, itemView))
{
this->updateGeometry(itemView, mapObj);
if (m_objFac.map() && (m_objFac.map()->mode() == Mode::Mode_3D))
updateDetonationSphere3D(mapObj, ddsData, m_pluginProvider->partitionTime());
}
else
{
DEBUG_LOG(m_logger) << LOGFUNCTION
<< " no AesItemView (AtOffRouteMine) found"
<< ", simId = " << simId
<< ", provide fallBackGeometry";
// provide fallbackGeometry to avoid errorMsg like 'incorrect number of positions'
mapObj->setPositions({{0.0, 0.0, .0},
{0.0, 0.1, .0},
{0.1, 0.1, .0},
{0.1, 0.0, .0}});
// do not return here, perform stuff like updateVisibility and so on
}
// updateSecondary
updateSecondary(simId);
updateVisibility(ddsData, mapObj);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
bool OffRoute2SituationMap::isVisibleByFilter(const Aes2SituationMap::DDS_TYPE &data) const
{
if (!m_displayFilter)
return true; // no filter -> visible
const auto es = data.effectStart().is_set() ? data.effectStart().get() : 0;
const auto partyId = data.partyId().is_set() ? data.partyId().get() : -1;
bool isVisibleByFilter = partyId > 0 ? FilterClass::m_currentSymbolSettings.symbolSettings.symbolPartyAppearance.value(partyId).isVisible : true;
if (isVisibleByFilter)
isVisibleByFilter = m_displayFilter->isVisible(AreaEffectSimulation::AesType_def::AtMineArea,
data.effectStateId(),
data.chargeStruct().chargeTypeId(),
partyId,
data.isCentral(),
es,
data.effectDuration(),
m_pluginProvider->partitionTime());
return isVisibleByFilter;
}
void OffRoute2SituationMap::onAesDisplayFilterChanged(AreaEffectSimulation::AesType aesType)
{
if ((AreaEffectSimulation::AesType_def::AtOffRouteMine != aesType.underlying()) &&
(AreaEffectSimulation::AesType_def::AtMineArea != aesType.underlying()))
return;
const auto cb = [this](const DDS_TYPE &data) -> bool
{
// return false -> do not stop looping over items
if (data.isDeleted())
return false;
this->updateVisibility(data);
return false;
};
iterateAesData(cb);
}
}
@@ -0,0 +1,72 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "aes_to_situation_map_tmpl.h"
#include <Plugins/AreaEffectSimulation/aes_data_plugin_interface.h>
#include <MapObjects/virtual_mine.h>
#include <QObject>
#define OFFROUTEMINE_HAS_SECONDARY_VIEW
namespace SituationMap
{
//
//
//
//
// Siehe auch booby_traps_to_map.h
//
//
//
//
class OffRoute2SituationMap;
template <>
struct Aes2SituationMapTraits<OffRoute2SituationMap>
{
using DDS_TYPE = AreaEffectSimulation::OffRouteMine;
using MAP_TYPE = SituationMap::VirtualMine;
static const AreaEffectSimulation::AesType_def::type aesType = AreaEffectSimulation::AesType_def::AtOffRouteMine;
};
class OffRoute2SituationMap final : public Aes2SituationMap<OffRoute2SituationMap>
{
Q_OBJECT
public:
using BaseClass = SituationMap::Aes2SituationMap<OffRoute2SituationMap>;
using BaseClass::BaseClass;
bool run() override;
bool iterateAesData(const std::function<bool(const AreaEffectSimulation::OffRouteMine &data)> &cb) const
{
return m_aesDtc->offRouteMines(cb);
}
protected Q_SLOTS:
void onPartitionTimeChanged(qint64 newPartitionTime);
protected:
void updateAllDetonationSpheres(qint64 newPartitionTime);
protected Q_SLOTS:
void onAesItemViewChanged(const AreaEffectSimulation::AesItemView &data, DataModification modType);
protected:
bool updateDetonationSphere3D(RefPointer<MAP_T> mapObj, const AreaEffectSimulation::OffRouteMine &trap, qint64 newPartitionTime);
bool updateSecondary(int32_t simId, bool bUpdateJust3DPart = false);
protected:
bool updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj) override;
bool isVisibleByFilter(const DDS_TYPE &data) const override;
void onAesDisplayFilterChanged(AreaEffectSimulation::AesType aesType) override;
};
} // namespace
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,233 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
// Qwn
#include "sim_to_situation_map_tmpl.h"
#include "pdm_handler.h"
#include <Utils/movement_track_manager.h>
#include <Plugins/FilterManagement/flt_data_plugin_interface.h>
#include <Plugins/AreaEffectSimulation/aes_data_plugin_interface.h>
#include <Plugins/ParticipantManagement/ppm_data_plugin_interface.h>
#include <Plugins/ParticipantManagement/ppm_participant_info_gui_plugin_interface.h>
#include <Plugins/OcSituationClient/osc_participant_info_gui_plugin_interface.h>
#include <Plugins/GuezIedManagement/gim_data_plugin_interface.h>
#include <MapObjects/participant.h>
#include <QPointer>
namespace SituationMap
{
struct HitlineInfo // For info dialog
{
qint32 participantId = -1;
ParticipantManagement::ParticipantPosition participantPosition;
ParticipantManagement::StateInformation participantState; // contains originatorId
ParticipantManagement::ParticipantPosition originatorPosition;
qint32 injuryPartyId = -1;
};
class LayerFactory;
class PdmHandler;
//------------------------------------------------------------------------------
class Participant2SituationMap final : public Sim2SituationMap<ParticipantManagement::Participant, SituationMap::Participant>
, protected DdsFilterHandling<SituationMap::Participant>
{
Q_OBJECT
using BaseClass = SituationMap::Sim2SituationMap<ParticipantManagement::Participant, SituationMap::Participant>;
using FilterClass = DdsFilterHandling<SituationMap::Participant>;
struct InternalPosition final : public ParticipantManagement::UnitPosition
{
Core::PositionReportingSource reportingSource;
bool isUnit = true;
bool bShowCenter = false;
bool bIsMountedOn = false;
bool bHasMountedParticipants = false;
inline const Core::GeoPosition &position() const OMG_NOEXCEPT
{
return (isUnit && bShowCenter) ? positionCenter() : positionLeader();
}
inline rti::core::int64 sampleTime() const OMG_NOEXCEPT
{
return (isUnit && bShowCenter) ? sampleTimeCenter() : sampleTimeLeader();
}
InternalPosition() = default;
explicit InternalPosition(const ParticipantManagement::UnitPosition &unitPos_param, bool bCenter)
: ParticipantManagement::UnitPosition(unitPos_param)
, bShowCenter(bCenter)
{}
};
public:
Participant2SituationMap(PdmHandler *pdmHandler,
ObjectFactory &objFac,
const QString &layername,
const char *loggerName);
~Participant2SituationMap();
// ppmParticipantInfoIfc and ocParticipantInfoIfc are optional
bool init(LayerFactory *layerFactory,
PluginProvider *pluginProvider);
bool run() override;
void stop() override;
bool mapObjectsClicked(const QVector<UniqueMapId> &uniqueMapIds) override;
bool unifiedMapObjectData(UniqueMapId uniqueMapId, UnifiedMapObjectData &umodOut) const override;
void setMovementTrackManager(const QPointer<MovementTrackManager> &mtMgr) { m_movementTrackManager = mtMgr; }
bool enableFireEventFlashing(bool enable);
bool isFireEventFlashingEnabled() const;
// for hitlineInfo:
bool isParticipantVisible(const int32_t participantId, bool *bParticipantExists) const;
Q_SIGNALS:
void hitlineOccured(const HitlineInfo &hitlineInfo); // to create Hitline (and its info dialog)
void participantPositionChanged(const int32_t participantId, const Point3D &newPos);
void participantOwnPositionChanged(const Point3D &newPos, int64_t sampleTime); // For filtering out the own position of tablet via Nmea
public Q_SLOTS:
void onParticipantFakeGearEventChanged(int participantId, qint64 sampleTime, SpecialChargeType specialChargeType);
protected Q_SLOTS:
void onPartitionTimeChanged(qint64 newPartitionTime);
void onFireEventFlashTimer();
void onTypesChanged(const ParticipantManagement::Type &data,
DataModification modType);
void onParticipantChanged(const ParticipantManagement::Participant &data,
DataModification modType);
void onPositionChanged(const ParticipantManagement::ParticipantPosition &data,
DataModification modType);
void onUnitPositionChanged(const ParticipantManagement::UnitPosition &data,
DataModification modType);
void updateParticipantPosition(int participantId, bool bHandleSymbolAppearanceSettingsParticipant = true);
void updateParticipantPosition(const InternalPosition &pos, bool bHandleSymbolAppearanceSettingsParticipant = true);
// void updateParticipantPosition(RefPointer<Sim2SituationMap::MAP_T> mapObj, int participantId);
void onDynamicParticipantDataChanged(const ParticipantManagement::DynamicParticipantData &data,
DataModification modType);
void onBiteChanged(const ParticipantManagement::Bite &data,
DataModification modType);
void onParticipantGearEventChanged(const ParticipantManagement::ParticipantGearEvent &data, DataModification modType);
void onAesItemViewChanged(const AreaEffectSimulation::AesItemView &data, DataModification modType);
void onDusMineStateChanged(const AreaEffectSimulation::DusMineState &data, DataModification modType);
void onMovementTrackActivityChanged(int trackId, bool active);
void onMovementTrackRemoved(int trackId);
void addToUpdateNotify(const RefPointer<MAP_T> &mapObj);
void notifyMapAboutModifedObjects();
protected:
void updateHierarchyLevels();
int participantHierachyLevel(const ParticipantManagement::Participant &data) const;
QString layernameWithHierachy(qint32 hierachyLevel) const;
QString layernameWithHierachy(const Sim2SituationMap::DDS_T &ddsData) const override;
bool isElapsed(const ParticipantManagement::Participant &data) const override;
void checkForUnknownOriginatorsParticipant(int possibleOriginatorParticipantId);
void checkForUnknownOriginatorsAes(int possibleOriginatorEffectSimId);
bool updateDynamicParticipantData(RefPointer<Sim2SituationMap::MAP_T> mapObj, const ParticipantManagement::DynamicParticipantData &data);
int32_t getSimId(const Sim2SituationMap::DDS_T &ddsData) const override;
bool updateElementImpl(const ParticipantManagement::Participant &ddsData,
RefPointer<Participant> mapObj) override;
bool removeElement(const int32_t simId) override;
void updateGearEvents(bool doUpdateView = false); // to let the participant flash
void updateGearEventInternal(bool doUpdateView,
qint64 curPartitionTimeMSec,
qint64 fireEventFlashingDurationMSec,
const QSet<int> &particpantIdsWithGearEvents);
bool symbolAppearanceSettingsChangesAreRelevant(const FilterManagement::SymbolAppearanceSettings::Settings & /*newSas*/) const override
{
return true;
}
void handleSymbolAppearanceSettings(RefPointer<MAP_T> &mapObj) override;
void onSymbolAppearanceSettingsChanged(FilterManagement::SymbolAppearanceSettings::Part part) override;
bool hasBitError(const ParticipantManagement::DynamicParticipantData &dpd) const;
bool isOutOfDate(const InternalPosition &pos) const;
bool isSimulatedPosition(const InternalPosition &pos) const;
void handleSymbolAppearanceSettingsParticipant(int participantId);
void handleSymbolAppearanceSettingsParticipant(RefPointer<MAP_T> &mapObj,
const ParticipantManagement::Participant &participant);
void handleSymbolAppearanceSettingsParticipant(RefPointer<MAP_T> &mapObj,
const ParticipantManagement::Participant &participant,
const InternalPosition &pPos,
const ParticipantManagement::DynamicParticipantData &dpd);
private:
LayerFactory *m_layerFactory = nullptr;
PluginProvider *m_pluginProvider = nullptr;
QTimer *m_notifiyTimer = nullptr;
std::shared_ptr<AreaEffectSimulation::Interface::Dtc> m_aesDtc;
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc;
std::shared_ptr<ParticipantManagement::ForeignParticipantInfoGuiInterface> m_ppmParticipantInfoIfc;
std::shared_ptr<OcSituationClient::ForeignParticipantInfoGuiInterface> m_ocParticipantInfoIfc;
// some lookupTables:
QHash<qint32, ParticipantManagement::Type> m_types;
QHash<int, ParticipantManagement::Participant> m_participants;
QHash<int, InternalPosition> m_participantPositions;
QHash<int, ParticipantManagement::DynamicParticipantData> m_participantDynamicData;
QHash<int, qint64> m_participantGearEvents; // for fireEventFlashing, <participantId, sampleTime>
QHash<int, qint64> m_lrfParticipantFakeGearEvents; // for fireEventFlashing, <participantId, sampleTime> / caused by Hitline(LRF, LTD)
QHash<int, qint64> m_ltdParticipantFakeGearEvents; // for fireEventFlashing, <participantId, sampleTime> / caused by Hitline(LRF, LTD)
QHash<int, bool> m_participantsWithProperties; // participantId, isArtillery(feuereinheit)
QVector<QPair<int, int>> m_unknownOriginatorsParticipant; // <originatorParticipantId, participantId>
QVector<QPair<int, int>> m_unknownOriginatorsAes; // <originatorEffectSimulationId, participantId>
QSet<int> m_participantWithMaybeMissingPartyId; // <participantId> originatorType==DusMine
QHash<int, int> m_aesItemView2PartyId; // <EffectSimulationId, PartyId>
QVector<RefPointer<MAP_T>> m_objectsToUpdate;
QSet<int> m_hasBiteError;
PdmHandler *m_pdmHandler;
bool m_bShowCenterPositions = false;
QTimer *m_fireEventFlashTimer = nullptr;
int m_fireEventFlashTriState = 0;
bool m_fireEventFlashEnable = true;
QPointer<SituationMap::MovementTrackManager> m_movementTrackManager;
};
} // namespace
@@ -0,0 +1,205 @@
/**
* Handling of PDM-Data so we dont call the DTC more than once
* $Id$
* $HeadURL$
* $Author$
* Created by Philipp Dassow, SLST, 2017-09-25
*/
#include "pdm_handler.h"
#include <ProjectDataManagement/pdm_dtc.h>
#include <QJsonDocument>
#include <QJsonObject>
namespace SituationMap
{
QString toString(SpecialChargeType value)
{
switch (value)
{
case SpecialChargeType::NoneSpecial:
return QStringLiteral("SpecialChargeType:NoneSpecial");
case SpecialChargeType::LRF:
return QStringLiteral("SpecialChargeType:LRF");
case SpecialChargeType::LTD:
return QStringLiteral("SpecialChargeType:LTD");
} // switch
Q_ASSERT(false);
return QStringLiteral("SpecialChargeTypeERROR");
}
PdmHandler::PdmHandler(const std::shared_ptr<ProjectDataManagement::Interface::Dtc> &dtcPdm)
: m_dtcPdm(dtcPdm)
, m_logger(getLogger("PdmHandler"))
{}
void PdmHandler::initializePdm()
{
if (m_dtcPdm == nullptr)
return;
if (m_bPdmInitialized)
return;
m_bPdmInitialized = true;
connect(m_dtcPdm.get(), &ProjectDataManagement::Interface::Dtc::chargeTypeChanged,
this, &PdmHandler::onChargeTypeChanged);
connect(m_dtcPdm.get(), &ProjectDataManagement::Interface::Dtc::gearTypeChargeTypeChanged,
this, &PdmHandler::onGearTypeChargeTypeChanged);
m_chargeTypes = m_dtcPdm->chargeTypes();
m_gearTypeChargeTypes = m_dtcPdm->gearTypeChargeTypes();
}
void PdmHandler::onChargeTypeChanged(const ProjectDataManagement::ChargeType &data, DataModification mod)
{
switch (mod)
{
case DataModification::eAdded:
case DataModification::eModified:
m_chargeTypes[data.id()] = data;
break;
case DataModification::eRemoved:
break;
}
}
void PdmHandler::onGearTypeChargeTypeChanged(const ProjectDataManagement::GearTypeChargeType &data, DataModification mod)
{
switch (mod)
{
case DataModification::eAdded:
case DataModification::eModified:
m_gearTypeChargeTypes[data.id()] = data;
break;
case DataModification::eRemoved:
break;
}
}
ProjectDataManagement::ChargeType PdmHandler::chargeTypeFromId(int chargeTypeId)
{
if (chargeTypeId <= 0)
return ProjectDataManagement::ChargeType();
initializePdm();
auto it = m_chargeTypes.constFind(chargeTypeId);
if (it == m_chargeTypes.cend())
{
WARNING_LOG(m_logger) << "Could not find charge type with id " << chargeTypeId;
return ProjectDataManagement::ChargeType();
}
return it.value();
}
int PdmHandler::maxRangeFromGearTypeIdAndChargeTypeId(int gearTypeId, int chargeTypeId)
{
if (gearTypeId < 0)
return -1;
if (chargeTypeId < 0)
return -1;
initializePdm();
// [NLDEVCTRL-926]: honor gearTypeId also
for (const auto &entry : qAsConst(m_gearTypeChargeTypes))
if ((entry.gearTypeId() == gearTypeId) &&
(entry.chargeTypeId() == chargeTypeId))
return entry.maxRange();
// [NLDEVCTRL-926]: Not found? Try with gearTypeId == 1000; // suggested by Malte Diers, Aug 2021
for (const auto &entry : qAsConst(m_gearTypeChargeTypes))
if ((entry.gearTypeId() == 1000) &&
(entry.chargeTypeId() == chargeTypeId))
return entry.maxRange();
return -1;
}
double PdmHandler::impactRadius(const AreaEffectSimulation::ChargeStruct &chargeStruct, double defaultValue)
{
if (chargeStruct.chargeTypeId() < 0)
return defaultValue;
initializePdm();
if (!m_dtcPdm)
return defaultValue;
return m_dtcPdm->impactRadius(chargeStruct.chargeTypeId(), chargeStruct.igniterTypeId(), chargeStruct.igniterFunctionId());
}
bool PdmHandler::isSmart(const AreaEffectSimulation::ChargeStruct &chargeStruct)
{
if (chargeStruct.chargeTypeId() < 0)
return false;
initializePdm();
if (!m_dtcPdm)
return false;
return m_dtcPdm->isSmart(chargeStruct.chargeTypeId(), chargeStruct.igniterTypeId(), chargeStruct.igniterFunctionId());
}
QString PdmHandler::trChargeTypeShortName(int chargeTypeId)
{
if (!m_dtcPdm)
return QString();
return m_dtcPdm->trChargeTypeShortName(chargeTypeId);
}
bool PdmHandler::isLRFChargeType(int chargeTypeId)
{
return isSpecialChargeType(chargeTypeId) == SpecialChargeType::LRF;
}
bool PdmHandler::isLTDChargeType(int chargeTypeId)
{
return isSpecialChargeType(chargeTypeId) == SpecialChargeType::LTD;
}
bool PdmHandler::isChargeTypeLtdOrLrf(SpecialChargeType sct)
{
return ((sct == SpecialChargeType::LRF) || (sct == SpecialChargeType::LTD));
}
ProjectDataManagement::GearClass PdmHandler::gearClassFromChargeTypeId(int chargeTypeId)
{
if (!m_dtcPdm)
return ProjectDataManagement::GearClass_def::Unknown;
return m_dtcPdm->gearClassFromChargeTypeId(chargeTypeId);
}
QVector<ProjectDataManagement::CasEffect> PdmHandler::casEffects(const AreaEffectSimulation::ChargeStruct &chargeStruct)
{
if (!m_dtcPdm)
return {};
return m_dtcPdm->casEffects(chargeStruct.chargeTypeId(), chargeStruct.igniterTypeId(), chargeStruct.igniterFunctionId());
}
bool PdmHandler::isChargeTypeLtdOrLrf(int chargeTypeId)
{
const SpecialChargeType specialChargeTypeId = isSpecialChargeType(chargeTypeId);
return isChargeTypeLtdOrLrf(specialChargeTypeId);
}
SpecialChargeType PdmHandler::isSpecialChargeType(int chargeTypeId)
{
// NOTE: igniterType/IgniterFunciton = 0 as long as does not contain values
ProjectDataManagement::ChargeTypeProperty ret = m_dtcPdm->getChargeTypeSpecialProperty(chargeTypeId, 0,0);
if (ret == ProjectDataManagement::ChargeTypeProperty::LRF)
return SpecialChargeType::LRF;
if (ret == ProjectDataManagement::ChargeTypeProperty::LTD)
return SpecialChargeType::LTD;
return SpecialChargeType::NoneSpecial;
}
} // namespace SituationMap
@@ -0,0 +1,87 @@
/**
* Handling of PDM-Data so we dont call the DTC more than once
* $Id$
* $HeadURL$
* $Author$
* Created by Philipp Dassow, SLST, 2017-09-25
*/
#pragma once
#include <Common/situation_map_logging.h>
#include <QMap>
#include <QObject>
#include <memory> // std::shared_pt
#include <LtsUtilsCore/data_modification_enum.h>
#include <ProjectDataManagement/pdm_dtc.h> // safe_enum GearClass
#include <AreaEffectSimulation/aes_dtc.h>
//namespace ProjectDataManagement
//{
//class ChargeType;
//class GearTypeChargeType;
//namespace Interface
//{
//// forward
//class Dtc;
//}
//}
namespace SituationMap
{
enum class SpecialChargeType
{
NoneSpecial,
LRF, // LaserRangeFinder / Laser-Entfernungsmesser
LTD // LaserTargetDesignator / Zielmarkierung
};
QString toString(SpecialChargeType value);
static inline std::ostream &operator<< (std::ostream &stream,
const SpecialChargeType value)
{
stream << "SpecialChargeType " << toString(value);
return stream;
}
class PdmHandler : public QObject
{
Q_OBJECT
public:
explicit PdmHandler(const std::shared_ptr<ProjectDataManagement::Interface::Dtc> &dtcPdm);
ProjectDataManagement::ChargeType chargeTypeFromId(int chargeTypeId);
int maxRangeFromGearTypeIdAndChargeTypeId(int gearTypeId, int chargeTypeId);
double impactRadius(const AreaEffectSimulation::ChargeStruct &chargeStruct, double defaultValue = 10.0);
bool isSmart(const AreaEffectSimulation::ChargeStruct &chargeStruct);
QString trChargeTypeShortName(int chargeTypeId);
SpecialChargeType isSpecialChargeType(int chargeTypeId);
bool isLRFChargeType(int chargeTypeId);
bool isLTDChargeType(int chargeTypeId);
bool isChargeTypeLtdOrLrf(int chargeTypeId);
static bool isChargeTypeLtdOrLrf(SpecialChargeType sct);
ProjectDataManagement::GearClass gearClassFromChargeTypeId(int chargeTypeId);
QVector<ProjectDataManagement::CasEffect> casEffects(const AreaEffectSimulation::ChargeStruct &chargeStruct);
private:
void initializePdm();
void onChargeTypeChanged(const ProjectDataManagement::ChargeType &data, DataModification mod);
void onGearTypeChargeTypeChanged(const ProjectDataManagement::GearTypeChargeType &data, DataModification mod);
private:
std::shared_ptr<ProjectDataManagement::Interface::Dtc> m_dtcPdm;
QMap<int, ProjectDataManagement::ChargeType> m_chargeTypes;
QMap<int, ProjectDataManagement::GearTypeChargeType> m_gearTypeChargeTypes;
bool m_bPdmInitialized{false};
LOGGER_T m_logger;
};
}
@@ -0,0 +1,239 @@
/**
* @RDE_HEADER@
* Interface to provide access to Plugins
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <memory>
#include <QObject>
#include <SituationMap/sitmapdds_export.h>
namespace LtsAppDescriptor
{
enum class App;
}
namespace AlarmManagement
{
class ForeignInfoGuiInterface;
namespace Interface
{
class Dtc;
class Ftc;
}
}
namespace AssetManagement
{
namespace Interface
{
class Dtc;
class Ftc;
}
}
namespace AreaEffectSimulation
{
class ForeignInfoGuiInterface;
namespace Interface
{
class Dtc;
}
}
namespace Buildings
{
namespace Interface
{
class Dtc;
class Ftc;
}
class ForeignInfoGuiInterface;
}
namespace CentralEffectSimulation
{
namespace Interface
{
class Dtc;
}
}
namespace ExerciseManagement
{
namespace Interface
{
class Dtc;
class Ftc;
}
}
namespace FilterManagement
{
class ForeignFltParticipantGuiInterface;
class ForeignAesGuiInterface;
class ForeignFltBuildingComponentGuiInterface;
namespace Interface
{
class Dtc;
class Ftc;
}
}
namespace GuezIedManagement
{
class ForeignGuiInterface;
namespace Interface
{
class Dtc;
}
}
namespace GuezNasat
{
class ForeignGuiInterface;
namespace Interface
{
class Dtc;
}
}
namespace InfrastructureManagement
{
class ForeignDataInterface;
class ForeignResourceManagementGuiInterface;
namespace Interface
{
class Dtc;
}
}
namespace OperatorManagement
{
namespace Interface
{
class Dtc;
class Ftc;
}
}
namespace ParticipantManagement
{
class ForeignParticipantInfoGuiInterface;
namespace Interface
{
class Dtc;
class Ftc;
}
}
namespace SituationReplay
{
namespace Interface
{
class Dtc;
}
}
namespace ProjectDataManagement
{
namespace Interface
{
class Dtc;
}
}
namespace OcSituationClient
{
class ForeignParticipantInfoGuiInterface;
}
namespace ServiceMonitor
{
class ForeignGuiInterface;
}
namespace TargetManagement
{
namespace Interface
{
class Dtc;
}
}
namespace ComponentMonitor
{
namespace Interface
{
class Dtc;
}
}
namespace SituationMap
{
class SITMAPDDS_EXPORT PluginProvider : public QObject
{
Q_OBJECT
public:
using QObject::QObject;
virtual QString toString() const = 0;
virtual int exerciseId() const = 0;
virtual bool isSessionValid() const = 0;
virtual qint64 partitionTime() const = 0;
virtual int partitionId() const = 0;
virtual int operatorId() const = 0;
virtual LtsAppDescriptor::App appId() const = 0;
virtual bool isVisibleParty(int partyId) const = 0;
virtual QString workspaceId() const = 0;
virtual bool isReplayPartition() const = 0;
virtual std::shared_ptr<AreaEffectSimulation::Interface::Dtc> aesDtc() const = 0;
virtual std::shared_ptr<AreaEffectSimulation::ForeignInfoGuiInterface> aesInfoIfc() const = 0;
virtual std::shared_ptr<AlarmManagement::Interface::Dtc> almDtc() const = 0;
virtual std::shared_ptr<AlarmManagement::Interface::Ftc> almFtc() const = 0;
virtual std::shared_ptr<AlarmManagement::ForeignInfoGuiInterface> almInfoIfc() const = 0;
virtual std::shared_ptr<AssetManagement::Interface::Dtc> asmDtc() const = 0;
virtual std::shared_ptr<AssetManagement::Interface::Ftc> asmFtc() const = 0;
virtual std::shared_ptr<Buildings::Interface::Dtc> bldDtc() const = 0;
virtual std::shared_ptr<Buildings::Interface::Ftc> bldFtc() const = 0;
virtual std::shared_ptr<Buildings::ForeignInfoGuiInterface> bldInfoIfc() const = 0;
virtual std::shared_ptr<CentralEffectSimulation::Interface::Dtc> cesDtc() const = 0;
virtual std::shared_ptr<ExerciseManagement::Interface::Dtc> exmDtc() const = 0;
virtual std::shared_ptr<ExerciseManagement::Interface::Ftc> exmFtc() const = 0;
virtual std::shared_ptr<FilterManagement::Interface::Dtc> fltDtc() const = 0;
virtual std::shared_ptr<FilterManagement::Interface::Ftc> fltFtc() const = 0;
virtual std::shared_ptr<FilterManagement::ForeignFltParticipantGuiInterface> fltParticipantIfc() const = 0;
virtual std::shared_ptr<FilterManagement::ForeignAesGuiInterface> fltAesIfc() const = 0;
virtual std::shared_ptr<FilterManagement::ForeignFltBuildingComponentGuiInterface> fltBuildingComponentIfc() const = 0;
virtual std::shared_ptr<GuezIedManagement::Interface::Dtc> gimDtc() const = 0;
virtual std::shared_ptr<GuezIedManagement::ForeignGuiInterface> gimIfc() const = 0;
virtual std::shared_ptr<GuezNasat::Interface::Dtc> gnaDtc() const = 0;
virtual std::shared_ptr<GuezNasat::ForeignGuiInterface> gnaIfc() const = 0;
virtual std::shared_ptr<InfrastructureManagement::Interface::Dtc> ismDtc() const = 0;
virtual std::shared_ptr<InfrastructureManagement::ForeignDataInterface> ismDataIfc() const = 0;
virtual std::shared_ptr<InfrastructureManagement::ForeignResourceManagementGuiInterface> ismGuiIfc() const = 0;
virtual std::shared_ptr<OperatorManagement::Interface::Dtc> opmDtc() const = 0;
virtual std::shared_ptr<OperatorManagement::Interface::Ftc> opmFtc() const = 0;
virtual std::shared_ptr<ParticipantManagement::Interface::Dtc> ppmDtc() const = 0;
virtual std::shared_ptr<SituationReplay::Interface::Dtc> srpDtc() const = 0;
virtual std::shared_ptr<ParticipantManagement::Interface::Ftc> ppmFtc() const = 0;
virtual std::shared_ptr<ParticipantManagement::ForeignParticipantInfoGuiInterface> ppmParticipantInfoIfc() const = 0;
virtual std::shared_ptr<ProjectDataManagement::Interface::Dtc> pdmDtc() const = 0;
virtual std::shared_ptr<OcSituationClient::ForeignParticipantInfoGuiInterface> ocParticipantInfoIfc() const = 0;
virtual std::shared_ptr<ServiceMonitor::ForeignGuiInterface> smoServiceMonitorIfc() const = 0;
virtual std::shared_ptr<TargetManagement::Interface::Dtc> tgtDtc() const = 0;
virtual std::shared_ptr<ComponentMonitor::Interface::Dtc> cmoDtc() const = 0;
signals:
void partitionTimeChanged(qint64 partitionTime);
void workspaceIdChanged(const QString &newWorkspaceId);
};
} // namespace SituationMap
@@ -0,0 +1,81 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#include "recon_area_to_map.h"
namespace SituationMap
{
bool ReconArea2SituationMap::run()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (!m_aesDtc)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no dtc";
return false;
}
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::reconAreaChanged,
this, &ReconArea2SituationMap::handleChanged, Qt::UniqueConnection);
// get:
m_aesDtc->reconAreas([this](const AreaEffectSimulation::ReconArea &data)
{
handleChanged(data, DataModification::eAdded);
});
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return BaseClass::run();
}
bool ReconArea2SituationMap::updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
// show just the ObjectAppearance::Technical
mapObj->setVisibility(ObjectAppearance::Tactical, false);
mapObj->setIdentifier(QString::fromStdString(ddsData.name()));
// if partyId is not set (like B,C agent), use default color
if (ddsData.partyId().is_set())
mapObj->setPartyId(ddsData.partyId().get());
else
{
mapObj->rLineStyle().setLineColor(Qt::black);
mapObj->rFillStyle().setFillColor(Qt::black);
}
mapObj->setAesState(effectState2aesState(ddsData.effectStateId().underlying()));
const int32_t simId = ddsData.id();
AreaEffectSimulation::AesItemView itemView;
if (m_aesDtc->aesItemViewFromEntityId(simId, Aes2SituationMapTraits<ReconArea2SituationMap>::aesType, itemView))
this->updateGeometry(itemView, mapObj);
else
{
DEBUG_LOG(m_logger) << LOGFUNCTION
<< " no AesItemView (AtReconArea) found"
<< ", simId = " << simId
<< ", provide fallBackGeometry";
// provide fallbackGeometry to avoid errorMsg like 'incorrect number of positions'
mapObj->setPositions({{0.0, 0.0, .0},
{0.0, 0.1, .0},
{0.1, 0.1, .0},
{0.1, 0.0, .0}});
// do not return here, perform stuff like updateVisibility and so on
}
updateVisibility(ddsData, mapObj);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
} // namespace SituationMap
@@ -0,0 +1,49 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "aes_to_situation_map_tmpl.h"
#include <Plugins/AreaEffectSimulation/aes_data_plugin_interface.h>
#include <MapObjects/biological_agent.h>
#include <QObject>
#include <memory>
namespace SituationMap
{
class ReconArea2SituationMap;
template <>
struct Aes2SituationMapTraits<ReconArea2SituationMap>
{
using DDS_TYPE = AreaEffectSimulation::ReconArea;
using MAP_TYPE = SituationMap::BiologicalAgent;
static const AreaEffectSimulation::AesType_def::type aesType = AreaEffectSimulation::AesType_def::AtReconArea;
};
class ReconArea2SituationMap final : public Aes2SituationMap<ReconArea2SituationMap>
{
Q_OBJECT
public:
using BaseClass = SituationMap::Aes2SituationMap<ReconArea2SituationMap>;
using BaseClass::BaseClass;
bool run() override;
bool iterateAesData(const std::function<bool(const AreaEffectSimulation::ReconArea &data)> &cb) const
{
return m_aesDtc->reconAreas(cb);
}
protected:
bool updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj) override;
};
} // namespace
@@ -0,0 +1,25 @@
/**
* @RDE_HEADER@
* Decleration of enum ResourceManagerMode
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <QString>
namespace SituationMap
{
// GUEZE-1491
enum class ResourceManagerMode
{
Undefined,
RMM_PlanActivityView, ///! PlanAktivitaetsSicht (Ansicht 1)
RMM_PlanDefinitionView, ///! PlanDefinitionsSicht (Ansicht 2, nur bei aufgeschaltetem Dialog "Anbringungspunkte")
RMM_ComponentMonitor ///! Reachability via CheckMk (Nagios)
};
} // namespace
@@ -0,0 +1,107 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#include "shootback_area_to_map.h"
#include <LtsUtilsCore/dds_bitarray.h>
#include <LtsCoordTrans/lts_coord_trans.h>
namespace SituationMap
{
bool ShootbackAreaToSituationMap::init(PluginProvider *pluginProvider)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (!pluginProvider ||
!pluginProvider->asmDtc())
return false;
m_pluginProvider = pluginProvider;
DEBUG_LOG(m_logger) << LOGFUNCTION << " exerciseId=" << m_pluginProvider->exerciseId();
m_tgtDtc = m_pluginProvider->tgtDtc();
// FilterManagement:
FilterClass::init(m_pluginProvider);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
bool ShootbackAreaToSituationMap::run()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (!m_tgtDtc)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no dtc";
return false;
}
this->stop();
connect(m_tgtDtc.get(), &TargetManagement::Interface::Dtc::shootbackAreaChanged,
this, &ShootbackAreaToSituationMap::handleChanged, Qt::UniqueConnection);
// get:
m_tgtDtc->shootbackAreas([this](const TargetManagement::ShootbackArea & data)
{
handleChanged(data, DataModification::eAdded);
});
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
void ShootbackAreaToSituationMap::stop()
{
DEBUG_LOG(m_logger) << LOGFUNCTION << "Stopping";
if (m_tgtDtc)
m_tgtDtc->disconnect(this);
}
int32_t ShootbackAreaToSituationMap::getSimId(const Sim2SituationMap::DDS_T &ddsData) const
{
return ddsData.id();
}
bool ShootbackAreaToSituationMap::updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
// const int32_t simId = ddsData.id();
// Style
mapObj->setLineStyle(LineStyle(Qt::black, 2, LinePattern::Solid));
// mapObj->setFillStyle(FillStyle(FillPattern::BackwardDiagonal));
// set identifier:
mapObj->setIdentifier(QString::fromStdString(ddsData.name()));
const Core::GeoPosition2D &center = ddsData.position();
const LtsCoordTrans::UtmCoordinate referencePointUTM = LtsCoordTrans::UtmCoordinate::fromGeographic(center.lon(), center.lat());
const QPointF size(ddsData.width() / 2.0, ddsData.height() / 2.0);
PositionCont posCont;
posCont.reserve(4);
posCont.push_back(Point3D::fromQPointF(referencePointUTM.geographic(size.x() * -1, size.y() * -1)));
posCont.push_back(Point3D::fromQPointF(referencePointUTM.geographic(size.x() * -1, size.y() * +1)));
posCont.push_back(Point3D::fromQPointF(referencePointUTM.geographic(size.x() * +1, size.y() * +1)));
posCont.push_back(Point3D::fromQPointF(referencePointUTM.geographic(size.x() * +1, size.y() * -1)));
mapObj->setPositions(posCont);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
}
@@ -0,0 +1,61 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "sim_to_situation_map_tmpl.h"
#include <Plugins/TargetManagement/tgt_data_plugin_interface.h>
#include <MapObjects/polygon.h>
#include <QObject>
namespace SituationMap
{
class ShootbackAreaToSituationMap final : public Sim2SituationMap<TargetManagement::ShootbackArea, SituationMap::Polygon>
, protected DdsFilterHandling<SituationMap::Polygon>
{
Q_OBJECT
using BaseClass = SituationMap::Sim2SituationMap<TargetManagement::ShootbackArea, SituationMap::Polygon>;
using FilterClass = DdsFilterHandling<SituationMap::Polygon>;
public:
ShootbackAreaToSituationMap(ObjectFactory &objFac,
const QString &layername,
int drawOrder,
const char *loggerName)
: BaseClass(objFac, layername, drawOrder, loggerName)
, FilterClass(loggerName, this)
, m_pluginProvider(nullptr)
{}
bool init(PluginProvider *pluginProvider);
bool run() override;
void stop() override;
protected:
int32_t getSimId(const Sim2SituationMap::DDS_T &ddsData) const override;
bool updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj) override;
bool symbolAppearanceSettingsChangesAreRelevant(const FilterManagement::SymbolAppearanceSettings::Settings &newSas) const override
{
return (m_currentSymbolSettings.symbolSettings.symbolScale != newSas.symbolSettings.symbolScale);
}
void handleSymbolAppearanceSettings(RefPointer<MAP_T> &mapObj) override
{
mapObj->setScale(m_currentSymbolSettings.symbolSettings.symbolScale);
}
private: // attributes
PluginProvider *m_pluginProvider;
std::shared_ptr<TargetManagement::Interface::Dtc> m_tgtDtc;
};
} // namespace
@@ -0,0 +1,685 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
// Own
#include "unified_map_object_data.h"
#include "plugin_provider.h"
#include <Map/object_factory.h>
#include <Common/situation_map_logging.h>
// Lts
#include <LtsUtilsCore/data_modification_enum.h>
#include <LtsAppDescriptor/lts_app_descriptor.h>
// Flt
#include <FilterManagement/flt_data_plugin_interface.h>
#include <FilterManagement/flt_participant_plugin_interface.h>
#include <FilterManagement/flt_symbol_appearance_settings.h>
#include <FilterManagement/flt_building_cmpnt_plugin_interface.h>
#include <FilterManagement/flt_building_cmpnt_settings.h>
// Qt
#include <QObject>
#include <QMap>
#include <QVector>
const char SimIdProperty[] = "SimId";
namespace SituationMap
{
//------------------------------------------------------------------------------
// Sim2SituationMapBase
//------------------------------------------------------------------------------
class Sim2SituationMapBase : public QObject
{
Q_OBJECT
using BaseClass = QObject;
public:
Sim2SituationMapBase(ObjectFactory &objFac,
const QString &layername,
int drawOrder,
const char *loggerName)
: BaseClass()
, m_objFac(objFac)
, m_assignDrawOrder(true)
, m_drawOrder(drawOrder)
, m_layername(layername)
, m_loggerName(QString::fromLatin1(loggerName))
, m_logger(getLogger(loggerName))
{}
virtual ~Sim2SituationMapBase() = default;
bool assignDrawOrder() const
{
return m_assignDrawOrder;
}
void setAssignDrawOrder(bool assignDrawOrder)
{
m_assignDrawOrder = assignDrawOrder;
}
virtual bool run() = 0;
virtual void stop() = 0;
virtual void clearObjects() = 0;
// Useful for assignment of MountingPoints at resourceApp of ISM
virtual bool mapObjectsClicked(const QVector<UniqueMapId> &uniqueMapIds)
{
Q_UNUSED(uniqueMapIds);
// empty
return false;
}
//
virtual bool unifiedMapObjectData(UniqueMapId /*uniqueMapId*/, UnifiedMapObjectData &/*umodOut*/) const
{
return false;
}
// for lookup :
long mapObjectCount() const
{
return m_simId2UniqueMapId.size();
}
UniqueMapId simId2UniqueMapId(int32_t simId) const
{
const UniqueMapId uniqueMapId = m_simId2UniqueMapId.value(simId, SituationMap::INVALID_MAP_ID);
return uniqueMapId;
}
bool uniqueMapId2SimId(UniqueMapId uniqueMapId, int32_t &simId) const
{
if (!SituationMap::isUniqueMapIdValid(uniqueMapId))
return false;
simId = m_uniqueMapId2SimId.value(uniqueMapId, -1);
return (simId != -1);
}
const QVector<int32_t> uniqueMapIds2SimIds(const QVector<UniqueMapId> &uniqueMapIds) const
{
QVector<int32_t> simIds;
simIds.reserve(uniqueMapIds.size());
int32_t simId_entityId = -1;
for(const UniqueMapId uniqueMapId : qAsConst(uniqueMapIds))
{
if (this->uniqueMapId2SimId(uniqueMapId, simId_entityId))
simIds.append(simId_entityId);
}
return simIds;
}
// : for lookup
// for startTime (of AesItems):
// for chronological ordering
virtual qint64 startTime(UniqueMapId uniqueMapId) const
{
Q_UNUSED(uniqueMapId);
return -1;
}
const QString &layername() const
{
return m_layername;
}
template <typename MAP_T>
void iterateObjects(const std::function<void( RefPointer<MAP_T> &mapObj)> &f)
{
for (const UniqueMapId &uniqueMapId : qAsConst(m_simId2UniqueMapId))
{
RefPointer<MAP_T> mapObj = m_objFac.get<MAP_T>(uniqueMapId);
if (!mapObj.valid())
continue;
f(mapObj);
}
}
virtual void reRenderObjects()
{
for (const UniqueMapId &uniqueMapId : qAsConst(m_simId2UniqueMapId))
{
RefPointer<AbstractMapObject> mapObj = m_objFac.get(uniqueMapId);
if (!mapObj.valid())
continue;
mapObj->reRenderSymbol();
mapObj->updateView();
if (!mapObj->updateView())
ERROR_LOG(m_logger) << LOGFUNCTION << " updateElement failed, "
<< " uniqueMapId = " << uniqueMapId
<< " debugInfo='" << mapObj->debugInfo() << "'";
}
}
void emit_visibilityHasChangedSignal()
{
emit visibilityHasChangedSignal();
}
virtual void symbolAppearanceSettingsChangedPostOperation()
{
// empty
}
Q_SIGNALS:
// void mapObjectCreated(UniqueMapId uniqueMapId); // to refresh MapObjectSelectionWidget for example
void mapObjectChanged(UniqueMapId uniqueMapId); // to refresh MapObjectSelectionWidget for example
void mapObjectRemoved(UniqueMapId uniqueMapId); // to refresh MapObjectSelectionWidget for example
void visibilityHasChangedSignal(); // emitted at 'aes_to_situation_map.tmpl (updateVisibility)
protected:
ObjectFactory &m_objFac;
bool m_assignDrawOrder;
int m_drawOrder;
const QString m_layername;
// simId , UniqueMapId
QMap<int32_t, UniqueMapId> m_simId2UniqueMapId;
QMap<UniqueMapId, int32_t> m_uniqueMapId2SimId;
QString m_loggerName;
LOGGER_T m_logger; ///< Interface to the Logging-Facility
};
//------------------------------------------------------------------------------
// Sim2SituationMap
//------------------------------------------------------------------------------
template <typename DDS_TYPE, typename MAP_TYPE>
class Sim2SituationMap : public Sim2SituationMapBase
{
public:
using DDS_T = DDS_TYPE;
using MAP_T = MAP_TYPE;
Sim2SituationMap(ObjectFactory &objFac,
const QString &layername,
const char *loggerName)
: Sim2SituationMapBase(objFac, layername, 0, loggerName)
{}
Sim2SituationMap(ObjectFactory &objFac,
const QString &layername,
int drawOrder,
const char *loggerName)
: Sim2SituationMapBase(objFac, layername, drawOrder, loggerName)
{}
~Sim2SituationMap()
{
}
// SimObject:
virtual int32_t getSimId(const DDS_TYPE &ddsData) const = 0;
virtual bool isElapsed(const DDS_TYPE &ddsData) const
{
Q_UNUSED(ddsData)
return false;
}
// MapObject:
RefPointer<MAP_T> getMapObjectOfUniqueMapId(const UniqueMapId uniqueMapId) const
{
if (!isUniqueMapIdValid(uniqueMapId))
return {};
return m_objFac.get<MAP_T>(uniqueMapId);
}
RefPointer<MAP_T> getMapObjectOfSimId(const int32_t simId) const
{
const UniqueMapId uniqueMapId = m_simId2UniqueMapId.value(simId, INVALID_MAP_ID);
return getMapObjectOfUniqueMapId(uniqueMapId);
}
protected:
void addProperties(RefPointer<MAP_T> mapObj, int32_t simId)
{
if (mapObj)
mapObj->setProperty(SimIdProperty, simId);
}
virtual QString layernameWithHierachy(const DDS_T &ddsData) const
{
Q_UNUSED(ddsData); // typically there is no need to add ddsData to layername (in contrast to participants)
return m_layername;
}
virtual bool createElement(const DDS_T &ddsData)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
<< " simId = " << getSimId(ddsData);
const int32_t simId = getSimId(ddsData);
// to avoid duplicates:
if (m_simId2UniqueMapId.contains(simId))
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " mapObject already exists"
<< " simId = " << simId;
return true;
}
const QString &debugInfo = QStringLiteral("%1_%2").arg(m_loggerName).arg(simId);
const QString &layername = this->layernameWithHierachy(ddsData);
RefPointer<MAP_T> mapObj = m_objFac.create<MAP_T>(layername, debugInfo);
if (!mapObj)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " creation failed"
<< " simId = " << simId;
return false;
}
if (m_assignDrawOrder)
mapObj->setDrawOrder(m_drawOrder);
addProperties(mapObj, simId);
const UniqueMapId uniqueMapId = mapObj->uniqueMapId();
if (!isUniqueMapIdValid(uniqueMapId))
{
ERROR_LOG(m_logger) << LOGFUNCTION << " uniqueMapId invalid"
<< " simId = " << simId;
return false;
}
m_simId2UniqueMapId[simId] = uniqueMapId;
m_uniqueMapId2SimId[uniqueMapId] = simId;
DEBUG_LOG(m_logger) << LOGFUNCTION << " END";
return true;
} // createElement
virtual bool updateElementImpl(const DDS_T &ddsData, RefPointer<MAP_T> mapObj) = 0;
bool updateElement(const DDS_T &ddsData)
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " START"
<< " simId = " << getSimId(ddsData);
const int32_t simId = getSimId(ddsData);
// Assume, that element was already created:
const UniqueMapId uniqueMapId = m_simId2UniqueMapId.value(simId, INVALID_MAP_ID);
if (!isUniqueMapIdValid(uniqueMapId))
{
ERROR_LOG(m_logger) << LOGFUNCTION << " not found" << " simId = " << simId;
return false;
}
RefPointer<MAP_T> mapObj = m_objFac.get<MAP_T>(uniqueMapId);
if (!mapObj)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " not found in objFac"
<< " simId = " << simId
<< " uniqueMapId = " << uniqueMapId;
return false;
}
bool success = updateElementImpl(ddsData, mapObj);
if (!success)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " updateElementImpl failed, "
<< " simId = " << getSimId(ddsData);
return false;
}
// FilterManagement:
handleSymbolAppearanceSettings(mapObj);
handleBuildingComponentSettings(mapObj);
if (!mapObj->updateView())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " updateElement failed, "
<< " simId = " << getSimId(ddsData);
return false;
}
// refresh MapObjectSelectionWidget or similar:
emit mapObjectChanged(uniqueMapId);
DEBUG_LOG(m_logger) << LOGFUNCTION << " END";
return true;
} // updateElement
bool removeElement(const DDS_T &ddsData)
{
const int32_t simId = getSimId(ddsData);
DEBUG_LOG(m_logger) << LOGFUNCTION << " START" << " simId = " << simId;
return removeElement(simId);
} // removeElement
virtual bool removeElement(const int32_t simId)
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " START" << " simId = " << simId;
// Assume, that participant was already created:
const UniqueMapId uniqueMapId = m_simId2UniqueMapId.value(simId, INVALID_MAP_ID);
if (!isUniqueMapIdValid(uniqueMapId))
{
TRACE_LOG(m_logger) << LOGFUNCTION << " not found"
<< ", simId = " << simId;
return false;
}
RefPointer<MAP_T> mapObj = m_objFac.get<MAP_T>(uniqueMapId);
if (mapObj)
{
mapObj->removeMySelf();
m_simId2UniqueMapId.remove(simId);
m_uniqueMapId2SimId.remove(uniqueMapId);
}
else
{
ERROR_LOG(m_logger) << LOGFUNCTION << " not found in objFac"
<< " simId = " << simId
<< " uniqueMapId = " << uniqueMapId;
}
DEBUG_LOG(m_logger) << LOGFUNCTION << " END";
// refresh MapObjectSelectionWidget or similar:
emit mapObjectRemoved(uniqueMapId);
return true;
} // removeElement
// still needed here, otherwise we can't update the settings during updateElement
virtual void handleSymbolAppearanceSettings(RefPointer<MAP_T> &mapObj) = 0;
virtual void handleBuildingComponentSettings(RefPointer<MAP_T> &/*mapObj*/)
{
//empty
}
public:
void clearObjects() override
{
const QList<int32_t> &simIds = m_simId2UniqueMapId.keys();
for(int32_t simId : simIds)
this->removeElement(simId);
}
protected:
bool handleChanged(const DDS_T &ddsData, DataModification modType)
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " START"
<< " modType = " << modType
<< " simId = " << getSimId(ddsData);
const bool bIsElapsed = isElapsed(ddsData);
if (bIsElapsed && (modType == DataModification::eAdded)) // an elapsed item is added - e.g. mounting_point_to_map
modType = DataModification::eRemoved; // process as removed
if (bIsElapsed && modType == DataModification::eModified)
modType = DataModification::eRemoved; // process as removed
bool success = false;
switch (modType)
{
// in case we missed eAdded or it was removed before (snapshot mode - time can jump forwards and backwards)
case DataModification::eAdded:
case DataModification::eModified:
success = this->createElement(ddsData) && this->updateElement(ddsData);
break;
case DataModification::eRemoved:
success = this->removeElement(ddsData);
break;
} // switch
DEBUG_LOG(m_logger) << LOGFUNCTION << " END";
return success;
} // handleChanged
// DdsDataContainer :
// optional offer, useful for improving onSymbolAppearanceSettingsChanged (Participant, HitlineInfo..)
QHash<int, DDS_T> m_ddsDataContainer;
void updateDdsDataContainer(const DDS_T &data, DataModification modType)
{
int simId = getSimId(data);
switch (modType)
{
case DataModification::eAdded:
case DataModification::eModified:
m_ddsDataContainer[simId] = data;
break;
case DataModification::eRemoved:
m_ddsDataContainer.remove(simId);
break;
}
}
// : DdsDataContainer
};
template <typename MAP_T>
class DdsFilterHandling :
protected FilterManagement::SymbolAppearanceSettings::SettingsChangedCallback,
protected FilterManagement::BuildingComponentSettings::SettingsChangedCallback
{
public:
DdsFilterHandling(const char *loggerName, Sim2SituationMapBase *smBase)
: m_smBase(smBase)
, my_logger(getLogger(loggerName))
{}
virtual ~DdsFilterHandling()
{
removeSymbolAppearanceCallback();
removeBuildingComponentCallback();
}
protected:
void init(PluginProvider *pluginProvider)
{
m_pluginProvider = pluginProvider;
onWorkspaceIdChanged(m_pluginProvider->workspaceId());
QObject::connect(pluginProvider, &PluginProvider::workspaceIdChanged, m_smBase,
[this](const QString &newWorkspaceId) { onWorkspaceIdChanged(newWorkspaceId); });
}
virtual void onWorkspaceIdChanged(const QString &newWorkspaceId)
{
DEBUG_LOG(my_logger) << LOGFUNCTION << ": onWorkspaceIdChanged: " << newWorkspaceId
<< ", m_pluginProvider->toString: " << m_pluginProvider->toString();
removeSymbolAppearanceCallback();
removeBuildingComponentCallback();
const auto fltParticipantIfc = m_pluginProvider->fltParticipantIfc();
if (fltParticipantIfc)
{
m_symbolAppearanceSettings = fltParticipantIfc->symbolAppearanceForOperator(m_pluginProvider->operatorId(),
m_pluginProvider->workspaceId());
if (m_symbolAppearanceSettings)
m_symbolAppearanceSettings->addChangedCallback(this);
else
{
ERROR_LOG(my_logger) << LOGFUNCTION << " addChangedCallback SymAppearance failed";
#ifdef LTS_DEBUG
Q_ASSERT(false);
#endif // LTS_DEBUG
}
onSymbolAppearanceSettingsChanged(FilterManagement::SymbolAppearanceSettings::Part::All);
}
else
ERROR_LOG(my_logger) << LOGFUNCTION << " no FilterManagement flm";
if (m_symbolAppearanceSettings && !m_symbolAppearanceSettings->isChangedCallbackRegistered(this))
for (int i=0; i<20;++i)
ERROR_LOG(my_logger) << LOGFUNCTION << " isChangedCallbackRegistered SymApp failure!!!";
const auto buildingComponentIfc = m_pluginProvider->fltBuildingComponentIfc();
if (buildingComponentIfc)
{
m_buildingComponentSettings = buildingComponentIfc->buildingComponentSettingsForOperator(m_pluginProvider->operatorId(),
m_pluginProvider->workspaceId());
if (m_buildingComponentSettings)
m_buildingComponentSettings->addChangedCallback(this);
else
{
ERROR_LOG(my_logger) << LOGFUNCTION << " addChangedCallback BldgCmpnt failed";
#ifdef LTS_DEBUG
Q_ASSERT(false);
#endif // LTS_DEBUG
}
onBuildingComponentSettingsChanged();
}
else if (m_pluginProvider->appId() == LtsAppDescriptor::App::ResourceManager)
ERROR_LOG(my_logger) << LOGFUNCTION << " no FilterManagement flm (fltBuildingComponentIfc)";
if (m_buildingComponentSettings && !m_buildingComponentSettings->isChangedCallbackRegistered(this))
for (int i=0; i<20;++i)
ERROR_LOG(my_logger) << LOGFUNCTION << " isChangedCallbackRegistered BldgCmpnt failure!!!";
}
private:
void removeSymbolAppearanceCallback()
{
if (m_symbolAppearanceSettings)
m_symbolAppearanceSettings->removeChangedCallback(this);
m_symbolAppearanceSettings = nullptr;
}
void removeBuildingComponentCallback()
{
if (m_buildingComponentSettings)
m_buildingComponentSettings->removeChangedCallback(this);
m_buildingComponentSettings = nullptr;
}
protected:
virtual bool symbolAppearanceSettingsChangesAreRelevant(const FilterManagement::SymbolAppearanceSettings::Settings & /*newSas*/) const
{
return true;
}
virtual bool buildingComponentSettingsChangesAreRelevant(const FilterManagement::BuildingComponentSettings::BldCmpSettings& /*newBcs*/) const
{
return false; // most adapter could ignore it.
}
// callback from SymbolAppearanceSettings::SettingsChangedCallback
void onSymbolAppearanceSettingsChanged(FilterManagement::SymbolAppearanceSettings::Part part) override
{
Q_UNUSED(part);
QElapsedTimer elapsedTimer;
if (my_logger.isInfoEnabled())
elapsedTimer.start();
// First, check for relevance...
const bool relevant = symbolAppearanceSettingsChangesAreRelevant(m_symbolAppearanceSettings->settings());
// ... then, update m_current...
m_currentSymbolSettings = m_symbolAppearanceSettings->settings();
if (!relevant)
return;
// assign to all elements:
auto cb = [this](RefPointer<MAP_T> &mapObj)
{
handleSymbolAppearanceSettings(mapObj);
if (!mapObj->updateView())
WARNING_LOG(my_logger) << LOGFUNCTION << " updateView failed,"
<< " mapObj = " << mapObj->debugInfo();
};
m_smBase->iterateObjects<MAP_T>(cb);
// [GUEZE-3258, GUEZE-3442] Performance, Filterupdate langsam
// The party checkboxes are relevant for the visibility.
// But the visibility is determined by processing the ddsData which is not available here.
// so introduce symbolAppearanceSettingsChangedPostOperation
m_smBase->symbolAppearanceSettingsChangedPostOperation(); // something like: party visibility has changed...
if (my_logger.isInfoEnabled())
{
// code: typeid(*m_smBase) / typeid(*m_smBase).name
// resulting clang warning : "expression with side effects will be evaluated despite being used as an operand to 'typeid'"
// so try this:
std::string className;
if (m_smBase)
{
auto &tempRef = *m_smBase;
className = typeid(tempRef).name();
}
INFO_LOG(my_logger) << className << " with PostOperation took " << elapsedTimer.elapsed() << " [ms]"
<< ", mapObjectCount " << m_smBase->mapObjectCount();
}
}
// callback from SymbolAppearanceSettings::SettingsChangedCallback
void onBuildingComponentSettingsChanged() override
{
// First, check for relevance...
const bool relevant = buildingComponentSettingsChangesAreRelevant(m_buildingComponentSettings->bldCmpSettings());
// ... then, update m_current...
m_currentBuildingComponentSettings = m_buildingComponentSettings->bldCmpSettings();
if (!relevant)
return;
// assign to all elements:
auto cb = [this](RefPointer<MAP_T> &mapObj)
{
handleBuildingComponentSettings(mapObj);
if (!mapObj->updateView())
WARNING_LOG(my_logger) << LOGFUNCTION << " updateView failed,"
<< " mapObj = " << mapObj->debugInfo();
};
m_smBase->iterateObjects<MAP_T>(cb);
}
virtual void handleSymbolAppearanceSettings(RefPointer<MAP_T> &mapObj) = 0;
virtual void handleBuildingComponentSettings(RefPointer<MAP_T> &)
{
// default implementation is empty :-)
// most derived classes could ignore this.
// adapter 'building_to_map' should overload it.
}
protected:
std::shared_ptr<FilterManagement::SymbolAppearanceSettings> m_symbolAppearanceSettings;
FilterManagement::SymbolAppearanceSettings::Settings m_currentSymbolSettings;
std::shared_ptr<FilterManagement::BuildingComponentSettings> m_buildingComponentSettings;
FilterManagement::BuildingComponentSettings::BldCmpSettings m_currentBuildingComponentSettings;
private:
PluginProvider *m_pluginProvider{nullptr};
Sim2SituationMapBase *m_smBase{nullptr};
NGL::INGLLogger &my_logger;
// : FilterManagement
};
} // namespace
@@ -0,0 +1,361 @@
/**
* @RDE_HEADER@
* The SoundAreaToMap class handles the transfer from MountingPoint-DDS-Data to a representation on the map of the data
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, LNE, 2020-08-01
*/
// Own
#include "sound_area_to_map.h"
#include <Map/object_factory.h>
#include <PluginInterfaces/gui_plugin_interface.h>
#include <InfrastructureManagement/ism_translation.h>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonParseError>
#include <QJsonArray>
#include <sstream>
using namespace SituationMap;
//------------------------------------------------------------------------------
inline PositionCont form2PosCont2D(const std::vector<Core::GeoPosition2D> &form)
{
PositionCont ret;
ret.reserve(form.size());
for (const auto &pos : form)
ret.push_back({pos.lon(), pos.lat(), 0.0});
return ret;
}
bool SoundAreaToMap::init(PluginProvider *pluginProvider, bool resourceMode)
{
if (!pluginProvider ||
!pluginProvider->ismDtc() ||
!pluginProvider->ismDataIfc())
return false;
m_resourceMode = resourceMode; // hack
m_pluginProvider = pluginProvider;
DEBUG_LOG(m_logger) << LOGFUNCTION << " m_resourceMode=" << m_resourceMode
<< " exerciseId=" << m_pluginProvider->exerciseId();
m_ismDtc = m_pluginProvider->ismDtc();
m_ismDataIfc = m_pluginProvider->ismDataIfc();
m_ismGuiIfc = m_pluginProvider->ismGuiIfc();
InfrastructureManagement::MountingPoint::init(); // load all icons before using them later
return true;
}
bool SoundAreaToMap::run()
{
this->stop();
if (!m_ismDtc)
{
ERROR_LOG(m_logger) << LOGFUNCTION << "Could not run. Dtc not set.";
return false;
}
// // Main Structure Element to get dependence on the exercise
// connect(m_ismDtc.get(), &InfrastructureManagement::Interface::Dtc::mainStructureElementChanged,
// this, &SoundAreaToMap::onMainStructureElementChanged, Qt::UniqueConnection);
// // get:
// m_ismDtc->mainStructureElements([this](const InfrastructureManagement::MainStructureElement &data)
// {
// onMainStructureElementChanged(data, DataModification::eAdded);
// });
connect(m_ismDtc.get(), &InfrastructureManagement::Interface::Dtc::effectAreaChanged,
this, &SoundAreaToMap::onEffectAreaChanged, Qt::UniqueConnection);
// get:
if (m_pluginProvider->exerciseId() != 0 || m_resourceMode)
{
m_ismDtc->effectAreas([this](const InfrastructureManagement::EffectArea& data)
{
onEffectAreaChanged(data, DataModification::eAdded);
});
}
return true;
}
void SoundAreaToMap::stop()
{
DEBUG_LOG(m_logger) << LOGFUNCTION << "Stopping";
if (m_ismDtc)
m_ismDtc->disconnect(this);
m_bldgsInExcersise.clear();
m_mountingPoints.clear();
}
bool SoundAreaToMap::mapObjectsClicked(const QVector<UniqueMapId> &uniqueMapIds)
{
// call SoundAreaInfoWindow, if exists
return true;
if (!m_ismGuiIfc)
return false;
const QVector<int32_t> &simIds = uniqueMapIds2SimIds(uniqueMapIds);
if (simIds.isEmpty())
return true;
// if (m_ismGuiIfc->isInSelectionMode())
// m_ismGuiIfc->addToSelection(simIds); // issue with adding resources (chosen twice -> 1st: add, 2nd: remove)
// else
// m_ismGuiIfc->showMountingPointInfoWindows(simIds);
return true;
}
bool SoundAreaToMap::unifiedMapObjectData(UniqueMapId uniqueMapId, UnifiedMapObjectData &umodOut) const
{
if (!m_ismDtc)
return false;
int32_t simIdOut = -1;
if (!this->uniqueMapId2SimId(uniqueMapId, simIdOut))
return false;
umodOut = UnifiedMapObjectData();
RefPointer<MAP_T> mapObj = this->getMapObjectOfUniqueMapId(uniqueMapId);
if (mapObj.valid())
umodOut.m_image = mapObj->previewImage();
const auto cb = [simIdOut, &umodOut](const InfrastructureManagement::EffectArea &data) -> bool
{
if (data.id() == simIdOut)
{
umodOut.m_description1 = QString::fromStdString(data.name());
umodOut.m_description2 = tr("Sound Area") + QString(QStringLiteral(" (%1)")).arg(data.id());
return true; // break loop
}
return false;
};
// sonst kann sich der compiler nicht zwischen bool und void entscheiden... !?
std::function<bool(const InfrastructureManagement::EffectArea &data)> cb1 = cb;
return m_ismDtc->effectAreas(cb1);
}
bool SoundAreaToMap::onEffectAreaChanged(const InfrastructureManagement::EffectArea &data, DataModification modType)
{
DEBUG_LOG(m_logger) << " onEffectAreaChanged"
<< " id=" << data.id()
<< " name='" << data.name() << "'"
<< " areaEgcuId=" << data.areaEgcuId()
<< " ata.geometry().size()=" << data.geometry().size()
<< " exerciseId=" << m_pluginProvider->exerciseId();
// if (m_pluginProvider->exerciseId() == 0 && !m_resourceMode)
// return true;
// if (!isElapsed(data)) // add just 'valid' data
// m_mountingPoints.insert(data.id(), data);
return handleChanged(data, modType);
}
bool SoundAreaToMap::isElapsed(const Sim2SituationMap::DDS_T &data) const
{
// true -> hide
// false -> show
DEBUG_LOG(m_logger) << " isElapsed?";
if (BaseClass::isElapsed(data))
return true;
if (data.geometry().size() < 3)
return true;
return false;
}
int32_t SoundAreaToMap::getSimId(const Sim2SituationMap::DDS_T &ddsData) const
{
return ddsData.id();
}
SituationMap::PositionCont soundGeometryToPositions(const QJsonDocument &jdoc)
{
QJsonObject jObj = jdoc.object();
if (jObj.isEmpty())
return {};
const QJsonArray &jArray = jObj[QLatin1String("soundGeometry")].toArray();
if (jArray.isEmpty())
return {};
SituationMap::PositionCont posCont;
posCont.reserve(jArray.size());
for (const auto &val : qAsConst(jArray))
{
const QJsonObject &objTemp = val.toObject();
posCont.append(Point3D::fromQPointF({objTemp[QLatin1String("lon")].toDouble(), // lon=x
objTemp[QLatin1String("lat")].toDouble()} // lat=y
));
} // for
return posCont;
}
InfrastructureManagement::MountingPoint SoundAreaToMap::mountingPointWithAssociatedId(int associatedId)
{
if (!m_ismDataIfc)
return InfrastructureManagement::MountingPoint();
InfrastructureManagement::MountingPoint mp;
const auto cb = [&mp, associatedId](const InfrastructureManagement::MountingPoint &data) -> bool
{
if (data.associatedAssetId() == associatedId)
{
mp = data;
return true; // break loop
}
return false;
};
// sonst kann sich der compiler nicht zwischen bool und void entscheiden... !?
std::function<bool(const InfrastructureManagement::MountingPoint &data)> cb1 = cb;
m_ismDataIfc->mountingPoints(cb1);
return mp;
}
bool SoundAreaToMap::updateElementImpl(const Sim2SituationMap::DDS_T &ddsData, RefPointer<Sim2SituationMap::MAP_T> mapObj)
{
DEBUG_LOG(m_logger) << LOGFUNCTION
<< " id " << ddsData.id()
<< ", name = " << ddsData.name();
mapObj->setIdentifier(QString::fromStdString(ddsData.name())); // do not show the name as identifier for SoundAreas
mapObj->setPickable(true); // default: pickable == true
//
// Area
//
QColor col(Qt::red);
mapObj->setLineStyle(LineStyle(col, 1, LinePattern::DashDotDot));
mapObj->setFillStyle(FillStyle(col, FillPattern::BackwardDiagonal));
const SituationMap::PositionCont &posCont = form2PosCont2D(ddsData.geometry());
mapObj->setPositions(posCont);
//
// EGCU
//
const InfrastructureManagement::MountingPoint &associatedMountingPoint = mountingPointWithAssociatedId(ddsData.areaEgcuId());
DEBUG_LOG(m_logger) << LOGFUNCTION
<< " id " << ddsData.id()
<< ", name = " << ddsData.name()
<< " MP: buildingId" << associatedMountingPoint.buildingId()
<< " MP: geoPosition" << associatedMountingPoint.geoPosition();
if (associatedMountingPoint.id() > 0)
{
mapObj->setMarkerData(MarkerData(associatedMountingPoint.toImage(), QSize(25,25)));
const Core::GeoPosition &geoPos = associatedMountingPoint.geoPosition();
mapObj->setMarkerOrigin(Point3D(geoPos.lon(), geoPos.lat(), geoPos.z()));
} else {
mapObj->setMarkerData(MarkerData());
mapObj->setMarkerOrigin(Point3D());
}
return true; // mapObj->updateView() is done by template
}
//void SoundAreaToMap::setVisibility()
//{
// return;
// // Set vilibility
// DEBUG_LOG(m_logger) << "Set Vivibility"
// << ", m_mountingPoints.size=" << m_mountingPoints.size();
// // loop over all mounting points to show/hide
// for (const InfrastructureManagement::MountingPoint &mountingPoint : qAsConst(m_mountingPoints))
// {
// const int32_t mountingPointId = mountingPoint.id();
// bool isVisible = m_bldgsInExcersise.contains (mountingPoint.buildingId());
// DEBUG_LOG(m_logger) << "mountingPoint buildingId=" << mountingPoint.buildingId()
// << " mountingPointId=" << mountingPointId
// << " Visible=" << isVisible;
// const UniqueMapId uniqueMapId = m_simId2UniqueMapId.value(mountingPointId, INVALID_MAP_ID);
// if (!isUniqueMapIdValid(uniqueMapId))
// {
// WARNING_LOG(m_logger) << LOGFUNCTION << "Found a mountingPoint which is in internal map but has no map object...: " << mountingPointId;
// continue;
// }
// RefPointer<MAP_T> mapObj = m_objFac.get<MAP_T>(uniqueMapId);
// if (!mapObj.valid())
// continue;
// DEBUG_LOG(m_logger) << "mapObj->setVisibility:" << isVisible;
// mapObj->setVisibility(isVisible);
// if (!mapObj->updateView())
// ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << mapObj->debugInfo() << "'" << " updateView failed";
// }
//}
bool SoundAreaToMap::onMainStructureElementChanged(const InfrastructureManagement::MainStructureElement &data,
DataModification modType)
{
TRACE_LOG(m_logger) << LOGFUNCTION << "SoundAreaToMap::onMainStructureElementChanged data.id=" << data.id();
DEBUG_LOG(m_logger) << LOGFUNCTION << " vorher " << m_bldgsInExcersise.values();
m_bldgsInExcersise.remove(data.id());
if (modType == DataModification::eAdded || modType == DataModification::eModified)
{
QJsonParseError parseError;
QJsonDocument doc = QJsonDocument::fromJson(QByteArray::fromStdString(data.properties()), &parseError);
if (parseError.error != QJsonParseError::NoError)
{
INFO_LOG(m_logger) << "Could not parse JSON props of building with ID "
<< data.id()
<< ". Reason: "
<< parseError.errorString()
<< "; JSON: "
<< doc.toJson(QJsonDocument::Compact);
return true;
}
const int32_t actualExerciseId = m_pluginProvider->exerciseId();
const QJsonArray &arr = doc.object().value(QLatin1String("available_in_exercise")).toArray();
for (const QJsonValue &value : qAsConst(arr))
{
if (!value.isDouble())
continue;
const int tmp = value.toInt();
DEBUG_LOG(m_logger) << "actualExerciseId=" << actualExerciseId
<< " available_in_exercise=" << tmp;
if (tmp == actualExerciseId)
{
DEBUG_LOG(m_logger) << "m_bldgsInExcersise.append:" << data.id();
m_bldgsInExcersise.insert(data.id());
}
}
}
DEBUG_LOG(m_logger) << LOGFUNCTION << " nachher " << m_bldgsInExcersise.values();
// setVisibility();
return true;
}
@@ -0,0 +1,73 @@
/**
* @RDE_HEADER@
* The SoundAreaToMap class handles the transfer from MountingPoint-DDS-Data to a representation on the map of the data
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, LNE, 2020-08-01
*/
#pragma once
#include "sim_to_situation_map_tmpl.h"
#include <Plugins/InfrastructureManagement/ism_data_plugin_interface.h>
#include <Plugins/InfrastructureManagement/ism_resource_management_gui_plugin_interface.h>
#include <Plugins/InfrastructureManagement/Shared/ism_mounting_point.h>
#include <MapObjects/sound_area.h>
namespace SituationMap
{
class SoundAreaToMap final : public Sim2SituationMap<InfrastructureManagement::EffectArea, SituationMap::SoundArea>
{
Q_OBJECT
using BaseClass = SituationMap::Sim2SituationMap<InfrastructureManagement::EffectArea, SituationMap::SoundArea>;
public:
SoundAreaToMap(ObjectFactory &objFac,
const QString &layername,
int drawOrder,
const char *loggerName)
: BaseClass(objFac, layername, drawOrder, loggerName)
{}
bool init(PluginProvider *pluginProvider, bool resourceMode);
bool run() override;
void stop() override;
bool mapObjectsClicked(const QVector<UniqueMapId> &uniqueMapIds) override; // Useful for assignment of MountingPoints at resourceApp of ISM
bool unifiedMapObjectData(UniqueMapId uniqueMapId, UnifiedMapObjectData &umodOut) const override;
protected Q_SLOTS:
bool onEffectAreaChanged(const InfrastructureManagement::EffectArea &data, DataModification modType);
bool onMainStructureElementChanged(const InfrastructureManagement::MainStructureElement &data,
DataModification modType = DataModification::eAdded);
protected:
bool isElapsed(const Sim2SituationMap::DDS_T &data) const override;
int32_t getSimId(const Sim2SituationMap::DDS_T &ddsData) const override;
bool updateElementImpl(const DDS_T &ddsData, RefPointer<MAP_T> mapObj) override;
void handleSymbolAppearanceSettings(RefPointer<MAP_T> &mapObj) override
{
Q_UNUSED(mapObj);
}
private:
InfrastructureManagement::MountingPoint mountingPointWithAssociatedId(int associatedId);
// void setVisibility();
private: // attributes
PluginProvider *m_pluginProvider{nullptr};
std::shared_ptr<InfrastructureManagement::Interface::Dtc> m_ismDtc;
std::shared_ptr<InfrastructureManagement::ForeignDataInterface> m_ismDataIfc;
std::shared_ptr<InfrastructureManagement::ForeignResourceManagementGuiInterface> m_ismGuiIfc;
bool m_resourceMode{false};
QSet<int> m_bldgsInExcersise; // All Buildings from this Exercise
QMap<int, InfrastructureManagement::MountingPoint> m_mountingPoints; // key=id, value=
}; // class SoundAreaToMap
} // namespace SituationMap
@@ -0,0 +1,113 @@
/**
* @RDE_HEADER@
* The SpecialAreaToSituationMap class handles the transfer from SpecialArea-DDS-Data to a representation on the map
* $Id$
* $HeadURL$
* $Author$
*/
#include "special_areas_to_map.h"
#include <LtsUtilsCore/dds_bitarray.h>
#include <LtsCoordTrans/lts_coord_trans.h>
#include <Plugins/ExerciseManagement/exm_data_plugin_interface.h>
namespace SituationMap
{
bool SpecialAreaToSituationMap::init(PluginProvider *pluginProvider)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (!pluginProvider ||
!pluginProvider->ismDtc())
return false;
m_pluginProvider = pluginProvider;
DEBUG_LOG(m_logger) << LOGFUNCTION << " exerciseId=" << m_pluginProvider->exerciseId();
m_ismDtc = m_pluginProvider->ismDtc();
// FilterManagement:
FilterClass::init(m_pluginProvider);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
bool SpecialAreaToSituationMap::run()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (!m_ismDtc)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no dtc";
return false;
}
this->stop();
connect(m_ismDtc.get(), &InfrastructureManagement::Interface::Dtc::specialAreaChanged,
this, &SpecialAreaToSituationMap::handleChanged, Qt::UniqueConnection);
// get:
m_ismDtc->specialAreas([this](const InfrastructureManagement::SpecialArea & data)
{
handleChanged(data, DataModification::eAdded);
});
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
void SpecialAreaToSituationMap::stop()
{
DEBUG_LOG(m_logger) << LOGFUNCTION << "Stopping";
if (m_ismDtc)
m_ismDtc->disconnect(this);
}
bool SpecialAreaToSituationMap::isElapsed(const Sim2SituationMap::DDS_T &data) const
{
Q_UNUSED(data)
// true -> hide
// false -> show
return false;
}
int32_t SpecialAreaToSituationMap::getSimId(const Sim2SituationMap::DDS_T &ddsData) const
{
return ddsData.id();
}
bool SpecialAreaToSituationMap::updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
// const int32_t simId = ddsData.id();
mapObj->setPickable(false); // otherwise MOSW will be opened, InfoWindows is incomplete...
// Style
mapObj->setLineStyle(LineStyle(Qt::green, 3, LinePattern::DashDot));
mapObj->setFillStyle(FillStyle(FillPattern::Null));
// set identifier:
mapObj->setIdentifier(QString::fromStdString(ddsData.name()));
const std::vector<Core::GeoPosition2D> &polygon = ddsData.polygon();
PositionCont posCont;
posCont.reserve(polygon.size());
for (const auto &p : qAsConst(polygon))
posCont.push_back(Point3D(p.lon(), p.lat(), .0));
mapObj->setPositions(posCont);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
}
@@ -0,0 +1,64 @@
/**
* @RDE_HEADER@
* The SpecialAreaToSituationMap class handles the transfer from SpecialArea-DDS-Data to a representation on the map
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "sim_to_situation_map_tmpl.h"
#include <Plugins/InfrastructureManagement/ism_data_plugin_interface.h>
#include <MapObjects/polygon.h>
#include <QObject>
namespace SituationMap
{
class SpecialAreaToSituationMap final : public Sim2SituationMap<InfrastructureManagement::SpecialArea, SituationMap::Polygon>
, protected DdsFilterHandling<SituationMap::Polygon>
{
Q_OBJECT
using BaseClass = SituationMap::Sim2SituationMap<InfrastructureManagement::SpecialArea, SituationMap::Polygon>;
using FilterClass = DdsFilterHandling<SituationMap::Polygon>;
public:
SpecialAreaToSituationMap(ObjectFactory &objFac,
const QString &layername,
int drawOrder,
const char *loggerName)
: BaseClass(objFac, layername, drawOrder, loggerName)
, FilterClass(loggerName, this)
, m_pluginProvider(nullptr)
{}
bool init(PluginProvider *pluginProvider);
bool run() override;
void stop() override;
protected:
bool isElapsed(const Sim2SituationMap::DDS_T &data) const override;
int32_t getSimId(const Sim2SituationMap::DDS_T &ddsData) const override;
bool updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj) override;
bool symbolAppearanceSettingsChangesAreRelevant(const FilterManagement::SymbolAppearanceSettings::Settings &newSas) const override
{
return (m_currentSymbolSettings.symbolSettings.symbolScale != newSas.symbolSettings.symbolScale) ||
(m_currentSymbolSettings.symbolSettings.showSpecialAreas != newSas.symbolSettings.showSpecialAreas);
}
void handleSymbolAppearanceSettings(RefPointer<MAP_T> &mapObj) override
{
mapObj->setScale(m_currentSymbolSettings.symbolSettings.symbolScale);
mapObj->setVisibility(m_currentSymbolSettings.symbolSettings.showSpecialAreas);
}
private: // attributes
PluginProvider *m_pluginProvider;
std::shared_ptr<InfrastructureManagement::Interface::Dtc> m_ismDtc;
};
} // namespace
@@ -0,0 +1,81 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#include "technical_area_to_map.h"
#include <LtsUtilsCore/dds_bitarray.h>
namespace SituationMap
{
bool TechnicalArea2SituationMap::run()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (!m_aesDtc)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no dtc";
return false;
}
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::technicalAreaChanged,
this, &TechnicalArea2SituationMap::handleChanged, Qt::UniqueConnection);
// get:
m_aesDtc->technicalAreas([this](const AreaEffectSimulation::TechnicalArea & data)
{
handleChanged(data, DataModification::eAdded);
});
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return BaseClass::run();
}
bool TechnicalArea2SituationMap::updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
const int32_t simId = ddsData.id();
mapObj->setPickable(false); // otherwise MOSW will be opened, InfoWindows is incomplete...
// Style
mapObj->setLineStyle(LineStyle(Qt::black, 2, LinePattern::DashDotDot));
// mapObj->setFillStyle(FillStyle(FillPattern::Null));
// set identifier:
mapObj->setIdentifier(QString::fromStdString(ddsData.name()));
// if (ddsData.partyId().is_set())
// mapObj->setPartyId(ddsData.partyId().get());
// AesItemView for boundary:
AreaEffectSimulation::AesItemView itemView;
if (m_aesDtc->aesItemViewFromEntityId(simId, AreaEffectSimulation::AesType::AtTechnicalArea, itemView))
this->updateGeometry(itemView, mapObj);
else
{
DEBUG_LOG(m_logger) << LOGFUNCTION
<< " no AesItemView (AtTechnicalArea) found"
<< ", simId = " << simId
<< ", provide fallBackGeometry";
// provide fallbackGeometry to avoid errorMsg like 'incorrect number of positions'
mapObj->setPositions({{0.0, 0.0, .0},
{0.0, 0.1, .0},
{0.1, 0.1, .0},
{0.1, 0.0, .0}});
// do not return here, perform stuff like updateVisibility and so on
}
updateVisibility(ddsData, mapObj);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
}
@@ -0,0 +1,47 @@
/**
* @RDE_HEADER@
* The TrainingAreaToSituationMap class handles the transfer from TechnicalArea-DDS-Data to a representation on the map
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "aes_to_situation_map_tmpl.h"
#include <Plugins/AreaEffectSimulation/aes_data_plugin_interface.h>
#include <MapObjects/polygon.h>
#include <QObject>
namespace SituationMap
{
class TechnicalArea2SituationMap;
template <>
struct Aes2SituationMapTraits<TechnicalArea2SituationMap>
{
using DDS_TYPE = AreaEffectSimulation::TechnicalArea;
using MAP_TYPE = SituationMap::Polygon;
static const AreaEffectSimulation::AesType_def::type aesType = AreaEffectSimulation::AesType_def::AtTechnicalArea;
};
class TechnicalArea2SituationMap final : public Aes2SituationMap<TechnicalArea2SituationMap>
{
Q_OBJECT
public:
using BaseClass = SituationMap::Aes2SituationMap<TechnicalArea2SituationMap>;
using BaseClass::BaseClass;
bool run() override;
bool iterateAesData(const std::function<bool(const AreaEffectSimulation::TechnicalArea &data)> &cb) const
{
return m_aesDtc->technicalAreas(cb);
}
protected:
bool updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj) override;
};
} // namespace
@@ -0,0 +1,126 @@
/**
* @RDE_HEADER@
* The TrainingAreaToSituationMap class handles the transfer from TechnicalArea-DDS-Data to a representation on the map
* $Id$
* $HeadURL$
* $Author$
*/
#include "training_area_to_map.h"
#include <LtsUtilsCore/dds_bitarray.h>
#include <LtsCoordTrans/lts_coord_trans.h>
#include <Plugins/ExerciseManagement/exm_data_plugin_interface.h>
namespace SituationMap
{
bool TrainingAreaToSituationMap::init(PluginProvider *pluginProvider)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (!pluginProvider ||
!pluginProvider->asmDtc())
return false;
m_pluginProvider = pluginProvider;
DEBUG_LOG(m_logger) << LOGFUNCTION << " exerciseId=" << m_pluginProvider->exerciseId();
if (m_pluginProvider->exmDtc())
{
const int curExerciseId = m_pluginProvider->exerciseId();
m_trainingAreaIdOfCurrentExercise = m_pluginProvider->exmDtc()->exercise(curExerciseId).trainingAreaId();
}
m_asmDtc = m_pluginProvider->asmDtc();
// FilterManagement:
FilterClass::init(m_pluginProvider);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
bool TrainingAreaToSituationMap::run()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (!m_asmDtc)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no dtc";
return false;
}
this->stop();
connect(m_asmDtc.get(), &AssetManagement::Interface::Dtc::trainingAreaChanged,
this, &TrainingAreaToSituationMap::handleChanged, Qt::UniqueConnection);
// get:
m_asmDtc->trainingAreas([this](const AssetManagement::TrainingArea & data)
{
handleChanged(data, DataModification::eAdded);
});
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
void TrainingAreaToSituationMap::stop()
{
DEBUG_LOG(m_logger) << LOGFUNCTION << "Stopping";
if (m_asmDtc)
m_asmDtc->disconnect(this);
}
bool TrainingAreaToSituationMap::isElapsed(const Sim2SituationMap::DDS_T &data) const
{
// true -> hide
// false -> show
if (m_trainingAreaIdOfCurrentExercise <= 0)
return false; // show all
return (m_trainingAreaIdOfCurrentExercise != data.id());
}
int32_t TrainingAreaToSituationMap::getSimId(const Sim2SituationMap::DDS_T &ddsData) const
{
return ddsData.id();
}
bool TrainingAreaToSituationMap::updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
// const int32_t simId = ddsData.id();
mapObj->setPickable(false); // otherwise MOSW will be opened, InfoWindows is incomplete...
// Style
mapObj->setLineStyle(LineStyle(Qt::black, 2, LinePattern::Dot));
mapObj->setFillStyle(FillStyle(FillPattern::Null));
// set identifier:
mapObj->setIdentifier(QString::fromStdString(ddsData.name()));
const Core::GeoPosition2D &bottomLeft = ddsData.bottomLeft();
const LtsCoordTrans::UtmCoordinate referencePointUTM = LtsCoordTrans::UtmCoordinate::fromGeographic(bottomLeft.lon(), bottomLeft.lat());
const QPointF size(ddsData.width(), ddsData.height());
PositionCont posCont;
posCont.reserve(4);
posCont.push_back(Point3D(bottomLeft.lon(), bottomLeft.lat(), .0));
posCont.push_back(Point3D::fromQPointF(referencePointUTM.geographic(0 , size.y())));
posCont.push_back(Point3D::fromQPointF(referencePointUTM.geographic(size.x(), size.y())));
posCont.push_back(Point3D::fromQPointF(referencePointUTM.geographic(size.x(), 0)));
mapObj->setPositions(posCont);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
}
@@ -0,0 +1,65 @@
/**
* @RDE_HEADER@
* Interface
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "sim_to_situation_map_tmpl.h"
#include <Plugins/AssetManagement/asm_data_plugin_interface.h>
#include <MapObjects/polygon.h>
#include <QObject>
namespace SituationMap
{
class TrainingAreaToSituationMap final : public Sim2SituationMap<AssetManagement::TrainingArea, SituationMap::Polygon>
, protected DdsFilterHandling<SituationMap::Polygon>
{
Q_OBJECT
using BaseClass = SituationMap::Sim2SituationMap<AssetManagement::TrainingArea, SituationMap::Polygon>;
using FilterClass = DdsFilterHandling<SituationMap::Polygon>;
public:
TrainingAreaToSituationMap(ObjectFactory &objFac,
const QString &layername,
int drawOrder,
const char *loggerName)
: BaseClass(objFac, layername, drawOrder, loggerName)
, FilterClass(loggerName, this)
, m_pluginProvider(nullptr)
{}
bool init(PluginProvider *pluginProvider);
bool run() override;
void stop() override;
protected:
bool isElapsed(const Sim2SituationMap::DDS_T &data) const override;
int32_t getSimId(const Sim2SituationMap::DDS_T &ddsData) const override;
bool updateElementImpl(const Sim2SituationMap::DDS_T &ddsData,
RefPointer<MAP_T> mapObj) override;
bool symbolAppearanceSettingsChangesAreRelevant(const FilterManagement::SymbolAppearanceSettings::Settings &newSas) const override
{
return (m_currentSymbolSettings.symbolSettings.symbolScale != newSas.symbolSettings.symbolScale) ||
(m_currentSymbolSettings.symbolSettings.showTrainingAreaBorder != newSas.symbolSettings.showTrainingAreaBorder);
}
void handleSymbolAppearanceSettings(RefPointer<MAP_T> &mapObj) override
{
mapObj->setScale(m_currentSymbolSettings.symbolSettings.symbolScale);
mapObj->setVisibility(m_currentSymbolSettings.symbolSettings.showTrainingAreaBorder);
}
private: // attributes
PluginProvider *m_pluginProvider;
int m_trainingAreaIdOfCurrentExercise = -1;
std::shared_ptr<AssetManagement::Interface::Dtc> m_asmDtc;
};
} // namespace
@@ -0,0 +1,58 @@
/**
* @RDE_HEADER@
* UnifiedMapObjectData
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
// Qwn
#include <Map/situation_map_types.h>
// Qt
#include <QString>
namespace SituationMap
{
//------------------------------------------------------------------------------
// UnifiedMapObjectData
//------------------------------------------------------------------------------
struct UnifiedMapObjectData
{
// basic data:
int m_equipmentNumber{-1};
int m_partyId{-1};
struct participantData
{
int m_participantId{-1};
int m_typeId{-1};
int m_vulnerabilityState{-1};
QString m_vulnerabilityString;
QString m_typeName;
};
participantData m_participantData;
struct buildingData
{
int buildingId{-1};
};
buildingData m_buildingData;
QString m_description1;
QString m_description2;
// sidc (-> icon/image):
SymbolDataToRender m_symDataToRender;
QImage m_image;
};
} // namespace
@@ -0,0 +1,249 @@
#
# $Id$
# $HeadURL$
# $Author$
# Created by Mike Wille, SLSE, 2016-06-10
#
IF(BUILD_RPM)
IF(UNIX)
OPTION(BUILD_USE_MAP_CACHE "Use MapCache (GUEZ_ONLY) via _pname" ON)
ELSE()
OPTION(BUILD_USE_MAP_CACHE "Use MapCache (GUEZ_ONLY) via _pname" OFF)
ENDIF()
ELSE()
# !BUILD_RPM entspricht LTS_DEBUG
OPTION(BUILD_USE_MAP_CACHE "Use MapCache (GUEZ_ONLY) via LTS_debug)" ON)
ENDIF()
MESSAGE(STATUS "Enable MapCache: ${BUILD_USE_MAP_CACHE})")
IF (BUILD_USE_MAP_CACHE)
add_definitions(-DUSE_MAP_CACHE)
ENDIF()
SET(sitmap_dds_SRCS
situation_map_init.cpp
situation_map_init.h
situation_map_init_p.h
MapObjectSelection/map_object_model.cpp
MapObjectSelection/map_object_model.h
MapObjectSelection/map_object_selection_widget.cpp
MapObjectSelection/map_object_selection_widget.h
MapObjectSelection/map_object_custom_view.cpp
MapObjectSelection/map_object_custom_view.h
AdapterDds/adapter_dds.cpp
AdapterDds/adapter_dds.h
AdapterDds/map_object_type.h
AdapterDds/aes_to_situation_map_tmpl.h
AdapterDds/air_support_impact_to_map.cpp
AdapterDds/air_support_impact_to_map.h
AdapterDds/emergency_call_to_map.cpp
AdapterDds/emergency_call_to_map.h
AdapterDds/bccontamination_to_map.cpp
AdapterDds/bccontamination_to_map.h
AdapterDds/borderline_to_map.cpp
AdapterDds/borderline_to_map.h
AdapterDds/buildings_to_map.cpp
AdapterDds/buildings_to_map.h
AdapterDds/buildinghitlineinfo_to_map.cpp
AdapterDds/buildinghitlineinfo_to_map.h
AdapterDds/building_contamination.cpp
AdapterDds/building_contamination.h
AdapterDds/building_ownership.cpp
AdapterDds/building_ownership.h
AdapterDds/booby_traps_to_map.cpp
AdapterDds/booby_traps_to_map.h
AdapterDds/special_areas_to_map.cpp
AdapterDds/special_areas_to_map.h
AdapterDds/danger_area_to_map.cpp
AdapterDds/danger_area_to_map.h
AdapterDds/dus_single_mine_to_map.cpp
AdapterDds/dus_single_mine_to_map.h
AdapterDds/explosion_area_to_map.cpp
AdapterDds/explosion_area_to_map.h
AdapterDds/explosion_cluster_to_map.cpp
AdapterDds/explosion_cluster_to_map.h
AdapterDds/effect_cluster_to_map.cpp
AdapterDds/effect_cluster_to_map.h
AdapterDds/explosion_single_to_map.cpp
AdapterDds/explosion_single_to_map.h
# AdapterDds/explosion_single_central_to_map.cpp
# AdapterDds/explosion_single_central_to_map.h
AdapterDds/functional_area_to_map.cpp
AdapterDds/functional_area_to_map.h
AdapterDds/gas_pipe_to_map.cpp
AdapterDds/gas_pipe_to_map.h
AdapterDds/guez_ied_to_map.cpp
AdapterDds/guez_ied_to_map.h
AdapterDds/guez_nasat_9liner.cpp
AdapterDds/guez_nasat_9liner.h
AdapterDds/hitlineinfo_to_map.cpp
AdapterDds/hitlineinfo_to_map.h
AdapterDds/mine_area_null_to_map.cpp
AdapterDds/mine_area_null_to_map.h
AdapterDds/mine_area_to_map.cpp
AdapterDds/mine_area_to_map.h
AdapterDds/mine_corridor_to_map.cpp
AdapterDds/mine_corridor_to_map.h
AdapterDds/mounting_point_to_map.cpp
AdapterDds/mounting_point_to_map.h
AdapterDds/sound_area_to_map.cpp
AdapterDds/sound_area_to_map.h
AdapterDds/mse_point_to_map.cpp
AdapterDds/mse_point_to_map.h
AdapterDds/mse_bridge_to_map.cpp
AdapterDds/mse_bridge_to_map.h
AdapterDds/ncontamination_to_map.cpp
AdapterDds/ncontamination_to_map.h
AdapterDds/off_route_to_map.cpp
AdapterDds/off_route_to_map.h
AdapterDds/participant_to_map.cpp
AdapterDds/participant_to_map.h
AdapterDds/pdm_handler.cpp
AdapterDds/pdm_handler.h
AdapterDds/shootback_area_to_map.cpp
AdapterDds/shootback_area_to_map.h
AdapterDds/recon_area_to_map.cpp
AdapterDds/recon_area_to_map.h
AdapterDds/technical_area_to_map.cpp
AdapterDds/technical_area_to_map.h
AdapterDds/training_area_to_map.cpp
AdapterDds/training_area_to_map.h
AdapterDds/plugin_provider.h
AdapterDds/sim_to_situation_map_tmpl.h
AdapterDds/unified_map_object_data.h
AdapterDds/charge_effect_to_map.cpp
AdapterDds/charge_effect_to_map.h
)
NGL_WRAP_UI(sitmap_dds_SRCS
MapObjectSelection/map_object_selection_dialog.ui
MapObjectSelection/map_object_custom_view.ui
)
NGL_ADD_LIBRARY2(WS SitmapDds SHARED ${sitmap_dds_SRCS})
NGL_TARGET_INCLUDE_DIRECTORIES(SitmapDds
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../
)
NGL_TARGET_LINK_LIBRARIES(SitmapDds
PUBLIC
Qt5::Core
situationMap
LtsUtilsGuiDds # RequestHelper
PRIVATE
svcMapDummy
situationMapFunctionDialog # remove me here plz
LtsCoordTrans
LtsDataView
LtsSessionData
situationMapObjects
LtsUtilsSettings
#needed through AdapterDds sources
AlmDataPluginInterface
AsmDataPluginInterface
BldDataPluginInterface
ExmDataPluginInterface
FltDataPluginInterface
IsmDataPluginInterface
GnaDataPluginInterface
CmoDataPluginInterface
SmoCheckButtonHandler
TgtDataPluginInterface
IsmShared
svcAesClient
svcCesClient
svcGimClient
svcPpmClient
svcSrpClient
)
#
# SitmapGuiPlugin
#
SET(sitmap_edit_gui_SRCS
sitmap_gui_plugin.cpp
sitmap_gui_plugin.h
sitmap_register_app_handler.cpp
sitmap_register_app_handler.h
sitmap_widget_control.cpp
sitmap_widget_control.h
sitmap_layer_control.cpp
sitmap_layer_control.h
ConfigureUrl/sitmap_configure_url_model.cpp
ConfigureUrl/sitmap_configure_url_model.h
ConfigureUrl/sitmap_configure_url_widget.cpp
ConfigureUrl/sitmap_configure_url_widget.h
ConfigureUrl/sitmap_configure_urls.cpp
ConfigureUrl/sitmap_configure_urls.h
layers_model.cpp
layers_model.h
terrain_profile_handler.cpp
terrain_profile_handler.h
viewshed_dialog.h
plugin_provider_lts_session.h
plugin_provider_lts_session.cpp
TopicEditor/topic_editor.h
TopicEditor/topic_editor.cpp
)
NGL_WRAP_UI(sitmap_edit_gui_SRCS
ConfigureUrl/sitmap_configure_url_widget.ui
ConfigureUrl/sitmap_configure_single_url.ui
ConfigureUrl/sitmap_configure_urls.ui
sitmap_widget_control.ui
sitmap_layer_control.ui
TopicEditor/topic_editor.ui
)
NGL_ADD_LIBRARY2(WS SitmapGuiPlugin MODULE ${sitmap_edit_gui_SRCS})
NGL_TARGET_LINK_LIBRARIES(SitmapGuiPlugin
SitmapDds
svcMapDummy
situationMapCommon
situationMap
situationMapObjects
NGLLogger
LtsPrinting
LtsSession
SituationMapGuiPluginInterface
Qt5::Widgets
LtsWidgets
LtsCoordTrans
LtsAppDescriptor
LtsAppManager
LtsUtilsSettings
TopicEditorBase
FltFilterChange
LtsNotification
# only to create a menu entry - should be done by the bdv gui plugin...
BdvViewerGuiPluginInterface
AesDataPluginInterface
AlmDataPluginInterface
AsmDataPluginInterface
BldDataPluginInterface
CesDataPluginInterface
FltDataPluginInterface
GimDataPluginInterface
GnaDataPluginInterface
IsmDataPluginInterface
OpmDataPluginInterface
PpmDataPluginInterface
TgtDataPluginInterface
CmoDataPluginInterface
)
@@ -0,0 +1,92 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Configure_Single_Url</class>
<widget class="QWidget" name="Configure_Single_Url">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1099</width>
<height>134</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true">Layer Control</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Url:</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Name:</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QLabel" name="label_3">
<property name="toolTip">
<string>Min. zoom in limit</string>
</property>
<property name="text">
<string>Min Scale:</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QLineEdit" name="le_minScale">
<property name="text">
<string notr="true">-1</string>
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QLabel" name="label_4">
<property name="toolTip">
<string>Max. zoom in limit</string>
</property>
<property name="text">
<string>Max Scale:</string>
</property>
</widget>
</item>
<item row="2" column="4">
<widget class="QLineEdit" name="le_maxScale">
<property name="text">
<string notr="true">-1</string>
</property>
</widget>
</item>
<item row="3" column="1">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>17</width>
<height>13</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="2" colspan="3">
<widget class="QLineEdit" name="le_name"/>
</item>
<item row="0" column="2" colspan="3">
<widget class="QLineEdit" name="le_url"/>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,106 @@
/**
* @RDE_HEADER@
* SituationMap - ConfigureMapUrlsDialog
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, SLSE, 2018-09-19
*/
#include "sitmap_configure_url_model.h"
//ASM
#include <AssetManagement/asm_data_plugin_interface.h>
// Qt
namespace SituationMap
{
ConfigureMapUrlModel::ConfigureMapUrlModel(QObject *parent)
: BaseClass( {tr("Name"), tr("Url"), tr("Map Type"), tr("Min Scale"), tr("Max Scale")}, parent)
{
}
ConfigureMapUrlModel::~ConfigureMapUrlModel()
{
}
void ConfigureMapUrlModel::addData(const DATA_T &entry)
{
for (const auto &r : qAsConst(m_vecData))
{
if (r == entry)
return;
}
beginInsertRows(QModelIndex(), m_vecData.size(), m_vecData.size());
m_vecData += entry;
endInsertRows();
}
QModelIndex ConfigureMapUrlModel::moveRow(const QModelIndex &sourceIndex, int destinationRow)
{
if (destinationRow >= m_vecData.size() || destinationRow < 0)
return sourceIndex;
std::swap(m_vecData[destinationRow], m_vecData[sourceIndex.row()]);
// only works as expected when destinationRow is +/-1 from sourceRow
QModelIndex idx = index(destinationRow, 0);
emit dataChanged(index(sourceIndex.row(), 0), index(sourceIndex.row(), columnCount(QModelIndex()) - 1));
emit dataChanged(idx, index(destinationRow, columnCount(QModelIndex()) - 1));
return idx;
}
QVector<ConfigureMapUrlModel::DATA_T> ConfigureMapUrlModel::allData() const
{
return m_vecData;
}
QVariant ConfigureMapUrlModel::data(const QModelIndex &index, int role) const
{
if ((role != Qt::DisplayRole &&
role != Qt::EditRole &&
role != Qt::UserRole) || !index.isValid() || index.row() >= m_vecData.size())
return QVariant();
const DATA_T &md = m_vecData.at(index.row());
switch (index.column())
{
case Columns::Url:
return QString::fromStdString(md.url());
case Columns::Name:
return QString::fromStdString(md.name());
case Columns::MapType:
{
switch (md.mapTypeId().underlying())
{
case AssetManagement::MapType_def::Aerial:
return tr("Aerial");
case AssetManagement::MapType_def::Topographic:
return tr("Topographic");
case AssetManagement::MapType_def::Unknown:
case AssetManagement::MapType_def::Feature:
case AssetManagement::MapType_def::Elevation:
case AssetManagement::MapType_def::SceneObjects:
break;
//empty
}
return tr("Unknown");
}
case Columns::MinScale:
return md.minScale();
case Columns::MaxScale:
return md.maxScale();
}
return QVariant();
}
} //namespace SituationMap
@@ -0,0 +1,56 @@
/**
* @RDE_HEADER@
* SituationMap - ConfigureMapUrlsDialog
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, SLSE, 2018-09-19
*/
#pragma once
#include <LtsWidgets/lts_abstract_table_model.h>
//Qt
namespace AssetManagement
{
class MapDescription;
}
namespace SituationMap
{
// --------------------------------------------------------
// ConfigureMapUrlModel
// --------------------------------------------------------
class ConfigureMapUrlModel : public LtsWidgets::LtsAbstractTableModel<AssetManagement::MapDescription>
{
Q_OBJECT
using BaseClass = LtsWidgets::LtsAbstractTableModel<AssetManagement::MapDescription>;
using DATA_T = AssetManagement::MapDescription;
public:
enum Columns
{
Name,
Url,
MapType,
MinScale,
MaxScale,
};
explicit ConfigureMapUrlModel(QObject *parent = nullptr);
~ConfigureMapUrlModel();
QVariant data(const QModelIndex &index, int role) const override;
void addData(const DATA_T &entry);
QModelIndex moveRow(const QModelIndex &sourceIndex, int destinationRow);
QVector<ConfigureMapUrlModel::DATA_T> allData() const;
};
}// namespace SituationMap
@@ -0,0 +1,232 @@
/**
* @RDE_HEADER@
* SituationMap - ConfigureMapUrlsWidgetDialog
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, SLSE, 2018-09-19
*/
#include "sitmap_configure_url_widget.h"
#include "ui_sitmap_configure_url_widget.h"
#include "ui_sitmap_configure_single_url.h"
#include "sitmap_configure_url_model.h"
//ASM
#include <AssetManagement/asm_data_plugin_interface.h>
constexpr int MIN_SCALE = -1;
constexpr int MAX_SCALE = 9999999;
namespace SituationMap
{
//------------------------------------------------------------------------------
ConfigureSingleMapUrl::ConfigureSingleMapUrl(QWidget *parent)
: BaseClass(parent/*, LtsWidgets::ButtonCombination::OkApplyCancel*/)
, m_ui(new Ui::Configure_Single_Url)
, m_buttonBox(new LtsWidgets::LtsDialogButtonBox(this))
{
setAttribute(Qt::WA_DeleteOnClose);
m_ui->setupUi(this);
layout()->addWidget(m_buttonBox);
connect(m_buttonBox->getButton(LtsWidgets::DialogButton::Ok), &QPushButton::clicked, this, &ConfigureSingleMapUrl::onOk);
connect(m_buttonBox->getButton(LtsWidgets::DialogButton::Close), &QPushButton::clicked, this, &ConfigureSingleMapUrl::onClose);
m_ui->le_url->setPlaceholderText(QStringLiteral("http://HOSTNAME/arcgis/rest/services/XXXX/MapServer"));
m_ui->le_name->setPlaceholderText(tr("Displayname"));
// minScale to limit zoom out
m_ui->le_minScale->setPlaceholderText(tr("limit zoom out, '-1' for invalid, '0' for infinite"));
m_ui->le_minScale->setValidator(new QIntValidator(MIN_SCALE, MAX_SCALE, this));
m_ui->le_minScale->setToolTip(m_ui->le_minScale->placeholderText());
// maxScale to limit zoom in
m_ui->le_maxScale->setPlaceholderText(tr("limit zoom in, '-1' for invalid"));
m_ui->le_maxScale->setValidator(new QIntValidator(MIN_SCALE, MAX_SCALE, this));
m_ui->le_maxScale->setToolTip(m_ui->le_maxScale->placeholderText());
}
ConfigureSingleMapUrl::~ConfigureSingleMapUrl()
{
}
void ConfigureSingleMapUrl::setPlaceholderTextForFile()
{
m_ui->le_url->setPlaceholderText(QStringLiteral("file:filename.ext"));
}
void ConfigureSingleMapUrl::setData(const ConfigureSingleMapUrl::DATA_T &data)
{
m_ui->le_url->setText(QString::fromStdString(data.url()));
m_ui->le_name->setText(QString::fromStdString(data.name()));
m_ui->le_minScale->setText(QString::number(data.minScale()));
m_ui->le_maxScale->setText(QString::number(data.maxScale()));
}
ConfigureSingleMapUrl::DATA_T ConfigureSingleMapUrl::data()
{
ConfigureSingleMapUrl::DATA_T data;
data.url(m_ui->le_url->text().trimmed().toStdString());
data.name(m_ui->le_name->text().trimmed().toStdString());
data.minScale(m_ui->le_minScale->text().toDouble());
data.maxScale(m_ui->le_maxScale->text().toDouble());
return data;
}
void ConfigureSingleMapUrl::onOk()
{
emit signalApply();
this->close();
}
void ConfigureSingleMapUrl::onClose()
{
this->close();
}
//------------------------------------------------------------------------------
ConfigureMapUrlsWidget::ConfigureMapUrlsWidget(QWidget *parent)
: QWidget(parent)
, m_ui(new Ui::Configure_Urls_Widget)
, m_logger(getLogger("ConfigureMapUrlsWidget"))
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
m_ui->setupUi(this);
connect(m_ui->pbUp, &QPushButton::clicked, this, &ConfigureMapUrlsWidget::onUpClicked);
connect(m_ui->pbDown, &QPushButton::clicked, this, &ConfigureMapUrlsWidget::onDownClicked);
connect(m_ui->pbAdd, &QPushButton::clicked, this, &ConfigureMapUrlsWidget::onAddClicked);
connect(m_ui->pbModify, &QPushButton::clicked, this, &ConfigureMapUrlsWidget::onModfiyClicked);
connect(m_ui->pbRemove, &QPushButton::clicked, this, &ConfigureMapUrlsWidget::onRemoveClicked);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
ConfigureMapUrlsWidget::~ConfigureMapUrlsWidget()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
delete m_ui;
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
void ConfigureMapUrlsWidget::setModel(ConfigureMapUrlModel *model)
{
if (!m_ui->tvLayer || !model)
return;
m_ui->tvLayer->setModel(model);
m_ui->tvLayer->hideColumn(ConfigureMapUrlModel::Columns::MapType);
m_configureMapUrlModel = model;
}
ConfigureMapUrlModel *ConfigureMapUrlsWidget::model() const
{
return m_configureMapUrlModel;
}
QTableView *ConfigureMapUrlsWidget::tableView()
{
return m_ui->tvLayer;
}
void ConfigureMapUrlsWidget::onUpClicked()
{
if (!m_configureMapUrlModel)
return;
int currentRow = m_ui->tvLayer->currentIndex().row();
if (currentRow - 1 < 0)
return;
QModelIndex idx = m_configureMapUrlModel->moveRow(m_ui->tvLayer->currentIndex(), currentRow - 1);
m_ui->tvLayer->setCurrentIndex(idx);
emit hasChanges();
}
void ConfigureMapUrlsWidget::onDownClicked()
{
if (!m_configureMapUrlModel)
return;
int currentRow = m_ui->tvLayer->currentIndex().row();
QModelIndex idx = m_configureMapUrlModel->moveRow(m_ui->tvLayer->currentIndex(), currentRow + 1);
m_ui->tvLayer->setCurrentIndex(idx);
emit hasChanges();
}
void ConfigureMapUrlsWidget::onAddClicked()
{
delete m_currentConfigureSingleUrl;
m_currentConfigureSingleUrl = new ConfigureSingleMapUrl(this);
m_currentConfigureSingleUrl->setWindowTitle(tr("Add Url"));
if (m_placeholderTextFile)
m_currentConfigureSingleUrl->setPlaceholderTextForFile();
connect(m_currentConfigureSingleUrl.data(), &ConfigureSingleMapUrl::signalApply,
this, &ConfigureMapUrlsWidget::addSingleUrl);
m_currentConfigureSingleUrl->show();
}
void ConfigureMapUrlsWidget::addSingleUrl()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (!m_configureMapUrlModel)
return;
const ConfigureSingleMapUrl::DATA_T &data = m_currentConfigureSingleUrl->data();
m_configureMapUrlModel->addData(data);
emit hasChanges();
}
void ConfigureMapUrlsWidget::onModfiyClicked()
{
delete m_currentConfigureSingleUrl;
m_currentConfigureSingleUrl = new ConfigureSingleMapUrl(this);
m_currentConfigureSingleUrl->setWindowTitle(tr("Modify Url"));
if (m_placeholderTextFile)
m_currentConfigureSingleUrl->setPlaceholderTextForFile();
connect(m_currentConfigureSingleUrl.data(), &ConfigureSingleMapUrl::signalApply,
this, &ConfigureMapUrlsWidget::modifySingleUrl);
int currentRow = m_ui->tvLayer->currentIndex().row();
m_currentConfigureSingleUrl->setData(m_configureMapUrlModel->getRowData(currentRow));
m_currentConfigureSingleUrl->show();
}
void ConfigureMapUrlsWidget::modifySingleUrl()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (!m_configureMapUrlModel)
return;
int currentRow = m_ui->tvLayer->currentIndex().row();
const ConfigureSingleMapUrl::DATA_T &data = m_currentConfigureSingleUrl->data();
m_configureMapUrlModel->setRowData(currentRow, data);
emit hasChanges();
}
void ConfigureMapUrlsWidget::onRemoveClicked()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
int currentRow = m_ui->tvLayer->currentIndex().row();
m_configureMapUrlModel->removeRow(currentRow);
emit hasChanges();
}
} //namespace SituationMap
@@ -0,0 +1,117 @@
/**
* @RDE_HEADER@
* SituationMap - ConfigureMapUrlsDialog
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, SLSE, 2018-09-19
*/
#pragma once
//Map
#include <Common/situation_map_logging.h>
//Lts
#include <LtsWidgets/lts_dialog.h>
//Qt
#include <QTableView>
class QToolButton;
namespace Ui
{
class Configure_Urls_Widget;
class Configure_Single_Url;
}
namespace AssetManagement
{
class MapDescription;
}
namespace SituationMap
{
class ConfigureMapUrlModel;
// --------------------------------------------------------
// ConfigureSingleMapUrl
// --------------------------------------------------------
class ConfigureSingleMapUrl final : public LtsWidgets::LtsFramelessDialog
{
Q_OBJECT
public:
using BaseClass = LtsWidgets::LtsFramelessDialog;
using DATA_T = AssetManagement::MapDescription;
explicit ConfigureSingleMapUrl(QWidget *parent = nullptr);
~ConfigureSingleMapUrl();
void setPlaceholderTextForFile();
void setData(const DATA_T &data);
DATA_T data();
Q_SIGNALS:
void signalApply();
protected Q_SLOTS:
void onOk();
void onClose();
private:
Ui::Configure_Single_Url *m_ui;
LtsWidgets::LtsDialogButtonBox *m_buttonBox;
};
// --------------------------------------------------------
// ConfigureMapUrlsWidget
// --------------------------------------------------------
class ConfigureMapUrlsWidget : public QWidget
{
Q_OBJECT
public:
explicit ConfigureMapUrlsWidget(QWidget *parent = nullptr);
~ConfigureMapUrlsWidget();
void setPlaceholderTextForFile() { m_placeholderTextFile = true; }
void setModel(ConfigureMapUrlModel *model);
ConfigureMapUrlModel *model() const;
QTableView *tableView();
Q_SIGNALS:
void hasChanges();
protected Q_SLOTS:
void onUpClicked();
void onDownClicked();
void onAddClicked();
void onModfiyClicked();
void onRemoveClicked();
void addSingleUrl();
void modifySingleUrl();
private:
// void retranslate() override;
QPointer<ConfigureSingleMapUrl> m_currentConfigureSingleUrl;
Ui::Configure_Urls_Widget *m_ui;
ConfigureMapUrlModel *m_configureMapUrlModel = nullptr;
bool m_placeholderTextFile = false;
LOGGER_T m_logger;
};
}// namespace SituationMap
@@ -0,0 +1,133 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Configure_Urls_Widget</class>
<widget class="QWidget" name="Configure_Urls_Widget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>811</width>
<height>441</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true">Layer Control</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QTableView" name="tvLayer">
<property name="minimumSize">
<size>
<width>500</width>
<height>200</height>
</size>
</property>
<property name="editTriggers">
<set>QAbstractItemView::AnyKeyPressed|QAbstractItemView::CurrentChanged|QAbstractItemView::EditKeyPressed|QAbstractItemView::SelectedClicked</set>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
</widget>
</item>
<item row="0" column="1">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="pbUp">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../../../../Z/src/nglwidgets/nglresources.qrc">
<normaloff>:/icons/png/camera_arrow_up.png</normaloff>:/icons/png/camera_arrow_up.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pbDown">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../../../../Z/src/nglwidgets/nglresources.qrc">
<normaloff>:/icons/png/camera_arrow_down.png</normaloff>:/icons/png/camera_arrow_down.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pbAdd">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../../../../Z/src/nglwidgets/nglresources.qrc">
<normaloff>:/icons/png/add.png</normaloff>:/icons/png/add.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pbModify">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../../../../Z/src/nglwidgets/nglresources.qrc">
<normaloff>:/icons/png/edith_graphic_eass.png</normaloff>:/icons/png/edith_graphic_eass.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pbRemove">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../../../../Z/src/nglwidgets/nglresources.qrc">
<normaloff>:/icons/png/remove.png</normaloff>:/icons/png/remove.png</iconset>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
<resources>
<include location="../../../../../Z/src/nglwidgets/nglresources.qrc"/>
</resources>
<connections/>
</ui>
@@ -0,0 +1,383 @@
/**
* @RDE_HEADER@
* SituationMap - ConfigureMapUrlsDialog
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, SLSE, 2018-09-19
*/
#include "sitmap_configure_urls.h"
#include "ui_sitmap_configure_urls.h"
#include "sitmap_configure_url_model.h"
#include "sitmap_configure_url_widget.h"
#include <Map/map_initializer.h> // MapSettingJson
#include "AdapterDds/plugin_provider.h"
#include <LtsUtils/LtsUtilsCore/dds_vector.h>
namespace SituationMap
{
ConfigureMapUrls::ConfigureMapUrls(QWidget *parent)
: LtsDialog(parent, LtsWidgets::ButtonCombination::OkApplyCancel)
, m_pluginProvider(nullptr)
, m_requestHelper(new LtsUtils::RequestHelper(this))
, m_ui(new Ui::Configure_Urls)
, m_logger(getLogger("ConfigureMapUrls"))
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
m_ui->setupUi(this);
ConfigureMapUrlsWidget *w;
// clear, we use our own widgets:
m_ui->tabWidget->removeTab(0);
w = new ConfigureMapUrlsWidget();
w->setModel(new ConfigureMapUrlModel(this));
m_ui->tabWidget->addTab(w, tr("Map"));
connect(w, &ConfigureMapUrlsWidget::hasChanges, this, &ConfigureMapUrls::slotChangesMade);
w = new ConfigureMapUrlsWidget();
w->setModel(new ConfigureMapUrlModel(this));
m_ui->tabWidget->addTab(w, tr("Scene"));
connect(w, &ConfigureMapUrlsWidget::hasChanges, this, &ConfigureMapUrls::slotChangesMade);
w = new ConfigureMapUrlsWidget();
w->setModel(new ConfigureMapUrlModel(this));
w->setPlaceholderTextForFile();
m_ui->tabWidget->addTab(w, tr("Elevation"));
connect(w, &ConfigureMapUrlsWidget::hasChanges, this, &ConfigureMapUrls::slotChangesMade);
w = new ConfigureMapUrlsWidget();
w->setModel(new ConfigureMapUrlModel(this));
w->setPlaceholderTextForFile();
m_ui->tabWidget->addTab(w, tr("SceneObject"));
connect(w, &ConfigureMapUrlsWidget::hasChanges, this, &ConfigureMapUrls::slotChangesMade);
//NLDEVCTRL-1727
setOnlineHelpFilename(QStringLiteral("Configuration_of_Modells_SLPKs")); // former: Situation-Configure_Map_Urls
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
ConfigureMapUrls::~ConfigureMapUrls()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
delete m_ui;
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
bool ConfigureMapUrls::init(PluginProvider *pluginProvider)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
m_pluginProvider = pluginProvider;
if (!m_pluginProvider)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no pluginProvider";
return false;
}
bool bRet = true;
m_asmDtc = m_pluginProvider->asmDtc();
if (!m_asmDtc)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " Can not retrieve AssetManagement::DTC";
bRet = false;
}
m_asmFtc = m_pluginProvider->asmFtc();
if (!m_asmFtc)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " Can not retrieve AssetManagement::FTC";
bRet = false;
}
connect(m_ui->cbTrainingArea, &LtsWidgets::LtsComboBox::currentTextChanged,
this, &ConfigureMapUrls::onSelectedTrainingAreaChanged);
m_ui->tabWidget->setCurrentIndex(0);
fillTrainingAreaCbx();
syncTaToGui();
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return bRet;
}
void ConfigureMapUrls::fillTrainingAreaCbx()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (!m_asmDtc)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no dtc";
return;
}
{
QSignalBlocker blocker(m_ui->cbTrainingArea);
// training areas
int curIdxTa = m_ui->cbTrainingArea->currentIndex();
m_ui->cbTrainingArea->clear();
auto cb = [this](const AssetManagement::TrainingArea & ta)
{
m_ui->cbTrainingArea->addItem(QString::fromStdString(ta.name()), QVariant(ta.id()));
};
m_asmDtc->trainingAreas(cb);
m_ui->cbTrainingArea->model()->sort(0);
if (curIdxTa >= 0)
m_ui->cbTrainingArea->setCurrentIndex(curIdxTa);
}
if (m_ui->cbTrainingArea->model()->rowCount() > 0)
{
const int newTrainingAreaId = m_ui->cbTrainingArea->currentData().toInt();
if (!retrieveTaOfService(newTrainingAreaId))
{
ERROR_LOG(m_logger) << LOGFUNCTION << " retrieveTrainingAreaOfService failed";
return;
}
}
// resetChanges();
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
void ConfigureMapUrls::onSelectedTrainingAreaChanged(const QString & /*dummy*/)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
const int newTrainingAreaId = m_ui->cbTrainingArea->currentData().toInt();
if (m_trainingArea.id() == newTrainingAreaId)
return;
if (hasUnsavedChanges())
{
switch (LtsWidgets::LtsMessageDialog::askApplyDiscardCancel(this))
{
case LtsWidgets::Button::Apply:
apply();
if (!retrieveTaOfService(newTrainingAreaId))
{
ERROR_LOG(m_logger) << LOGFUNCTION << " retrieveTrainingAreaOfService failed";
return;
}
break;
case LtsWidgets::Button::Cancel:
INFO_LOG(m_logger) << LOGFUNCTION << " set back to m_trainingArea.id() = " << m_trainingArea.id();
m_ui->cbTrainingArea->setCurrentIndex(m_ui->cbTrainingArea->findData(QVariant(m_trainingArea.id()), Qt::UserRole));
break;
case LtsWidgets::Button::Discard:
if (!retrieveTaOfService(newTrainingAreaId))
{
ERROR_LOG(m_logger) << LOGFUNCTION << " retrieveTrainingAreaOfService failed";
return;
}
break;
default:
ERROR_LOG(m_logger) << LOGFUNCTION << " got unexpected!!!";
break;
}
}
else
{
if (!retrieveTaOfService(newTrainingAreaId))
{
ERROR_LOG(m_logger) << LOGFUNCTION << " retrieveTrainingAreaOfService failed";
return;
}
}
syncTaToGui();
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
bool ConfigureMapUrls::retrieveTaOfService(int trainingAreaId)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START, trainingAreaId=" << trainingAreaId;
if (!m_asmDtc)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no dtc";
return false;
}
// clear gui:
m_trainingArea = AssetManagement::TrainingArea();
syncTaToGui();
AssetManagement::TrainingArea ta = m_asmDtc->trainingArea(trainingAreaId);
if (ta.id() != trainingAreaId)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " switch to m_trainingArea failed (taId=" << trainingAreaId << ")";
return false;
}
m_trainingArea = ta;
INFO_LOG(m_logger) << LOGFUNCTION << " switch to m_trainingArea " << m_trainingArea.id()
<< ", ta" << ta;
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
static inline std::vector<AssetManagement::MapDescription> vecToVec(const QVector<AssetManagement::MapDescription> &vec)
{
return LtsUtils::convert<std::vector<AssetManagement::MapDescription>>(vec);
}
static inline QVector<AssetManagement::MapDescription> vecToVec(const std::vector<AssetManagement::MapDescription> &vec)
{
return LtsUtils::convert<QVector<AssetManagement::MapDescription>>(vec);
}
void basicConfig(ConfigureMapUrlsWidget *tv, bool showTypeMinMax = true)
{
if (!tv)
return;
tv->tableView()->resizeColumnsToContents();
tv->tableView()->setColumnWidth(1, 100);
tv->tableView()->setColumnWidth(2, 100);
tv->tableView()->setColumnWidth(3, 100);
tv->tableView()->setColumnWidth(4, 100);
if (!showTypeMinMax)
{
tv->tableView()->hideColumn(ConfigureMapUrlModel::Columns::MapType);
tv->tableView()->hideColumn(ConfigureMapUrlModel::Columns::MinScale);
tv->tableView()->hideColumn(ConfigureMapUrlModel::Columns::MaxScale);
}
}
void ConfigureMapUrls::syncTaToGui()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
ConfigureMapUrlsWidget *w;
w = static_cast<ConfigureMapUrlsWidget *>(m_ui->tabWidget->widget(0));
if (w && w->model())
{
w->model()->setData(vecToVec(m_trainingArea.map2D()));
TRACE_LOG(m_logger) << LOGFUNCTION << " model->rowCount()" << w->model()->rowCount();
}
basicConfig(w);
if (w && w->model())
connect(w->model(), &ConfigureMapUrlModel::dataChanged, this, []()
{
qCritical() << " Changed!!!";
});
w = static_cast<ConfigureMapUrlsWidget *>(m_ui->tabWidget->widget(1));
if (w && w->model())
{
w->model()->setData(vecToVec(m_trainingArea.scene3D()));
TRACE_LOG(m_logger) << LOGFUNCTION << " model->rowCount()" << w->model()->rowCount();
}
basicConfig(w);
w = static_cast<ConfigureMapUrlsWidget *>(m_ui->tabWidget->widget(2));
if (w && w->model())
w->model()->setData(vecToVec(m_trainingArea.elevation()));
basicConfig(w, false);
w = static_cast<ConfigureMapUrlsWidget *>(m_ui->tabWidget->widget(3));
if (w && w->model())
w->model()->setData(vecToVec(m_trainingArea.sceneObjects()));
basicConfig(w, false);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
void ConfigureMapUrls::syncGuiToTa()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
ConfigureMapUrlsWidget *w;
w = static_cast<ConfigureMapUrlsWidget *>(m_ui->tabWidget->widget(0));
if (w && w->model())
m_trainingArea.map2D(vecToVec(w->model()->allData()));
w = static_cast<ConfigureMapUrlsWidget *>(m_ui->tabWidget->widget(1));
if (w && w->model())
m_trainingArea.scene3D(vecToVec(w->model()->allData()));
w = static_cast<ConfigureMapUrlsWidget *>(m_ui->tabWidget->widget(2));
if (w && w->model())
m_trainingArea.elevation(vecToVec(w->model()->allData()));
w = static_cast<ConfigureMapUrlsWidget *>(m_ui->tabWidget->widget(3));
if (w && w->model())
m_trainingArea.sceneObjects(vecToVec(w->model()->allData()));
// The model does not know it`s mapDescriptionTypeId.
// So set them here:
for (auto &item : m_trainingArea.map2D())
item.mapDescriptionTypeId(AssetManagement::MapDescriptionType_def::Map2D);
for (auto &item : m_trainingArea.scene3D())
item.mapDescriptionTypeId(AssetManagement::MapDescriptionType_def::Scene3D);
for (auto &item : m_trainingArea.elevation())
item.mapDescriptionTypeId(AssetManagement::MapDescriptionType_def::Elevation);
for (auto &item : m_trainingArea.sceneObjects())
item.mapDescriptionTypeId(AssetManagement::MapDescriptionType_def::SceneObj);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
void ConfigureMapUrls::retranslate()
{
translate(m_ui, tr("Configure Map Urls"));
// reBuildUi();
}
bool ConfigureMapUrls::apply()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (!m_asmFtc)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " Can not retrieve AssetManagement::FTC";
return false;
}
this->syncGuiToTa();
bool success = m_requestHelper->startSingleRequest([this]()
{
return m_asmFtc->trainingAreaModifyRequest(m_trainingArea, this);
});
TRACE_LOG(m_logger) << LOGFUNCTION << " END, scucess=" << success;
return success;
}
void ConfigureMapUrls::onTrainingAreaModifyReply(const Core::FunctionReplyObject &reply)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (reply.error())
{
ERROR_LOG(m_logger) << LOGFUNCTION << "Got onTrainingAreaModifyReply error: " << reply();
return;
}
INFO_LOG(m_logger) << LOGFUNCTION << " Got onTrainingAreaModifyReply with id " << reply.id();
m_requestHelper->requestReply(reply);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
} //namespace SituationMap
@@ -0,0 +1,85 @@
/**
* @RDE_HEADER@
* SituationMap - ConfigureMapUrlsDialog
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, SLSE, 2018-09-19
*/
#pragma once
//Map
#include <Common/situation_map_logging.h>
//ASM
#include <AssetManagement/asm_data_plugin_interface.h>
//Lts
#include <LtsWidgets/lts_dialog.h>
//DDS
#include <LtsUtilsGuiDds/request_helper.h>
//Qt
namespace Ui
{
class Configure_Urls;
}
namespace SituationMap
{
class PluginProvider;
// --------------------------------------------------------
// ConfigureMapUrlsDialog
// --------------------------------------------------------
class ConfigureMapUrls : public LtsWidgets::LtsDialog
, protected AssetManagement::Interface::Ftc::TrainingAreaModifyReplyHandler
{
Q_OBJECT
public:
explicit ConfigureMapUrls(QWidget *parent = nullptr);
~ConfigureMapUrls();
bool init(PluginProvider *pluginProvider);
protected:
void fillTrainingAreaCbx();
bool retrieveTaOfService(int trainingAreaId);
void syncTaToGui();
void syncGuiToTa();
void onTrainingAreaModifyReply(const Core::FunctionReplyObject &reply) override;
protected Q_SLOTS:
void onSelectedTrainingAreaChanged(const QString &dummy = QString());
private:
void retranslate() override;
bool apply() override final;
protected:
private:
SituationMap::PluginProvider *m_pluginProvider;
std::shared_ptr<AssetManagement::Interface::Dtc> m_asmDtc;
std::shared_ptr<AssetManagement::Interface::Ftc> m_asmFtc;
LtsUtils::RequestHelper *m_requestHelper;
AssetManagement::TrainingArea m_trainingArea;
Ui::Configure_Urls *m_ui;
LOGGER_T m_logger;
};
}// namespace SituationMap
@@ -0,0 +1,75 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Configure_Urls</class>
<widget class="QWidget" name="Configure_Urls">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>667</width>
<height>368</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true"/>
</property>
<layout class="QGridLayout" name="gridLayout_7">
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="lblTrainingArea">
<property name="text">
<string>Training Area:</string>
</property>
</widget>
</item>
<item>
<widget class="LtsWidgets::LtsComboBox" name="cbTrainingArea">
<property name="const" stdset="0">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="map">
<attribute name="title">
<string>Map</string>
</attribute>
</widget>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LtsWidgets::LtsComboBox</class>
<extends>QComboBox</extends>
<header>LtsWidgets/lts_combo_box.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,73 @@
/**
* @RDE_HEADER@
* CustomView for MapObjects
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, SLSE, 2017-04-11
*/
// Own
#include "map_object_custom_view.h"
#include "ui_map_object_custom_view.h"
#include "map_object_model.h"
#include <LtsSession/lts_session_data.h>
// Ot
#include <QDataWidgetMapper>
namespace SituationMap
{
MapObjectCustomView::MapObjectCustomView(QWidget *parent)
: BaseClass(parent)
, m_ui(new Ui::MapObjectCustomView)
, m_mapper(new QDataWidgetMapper(this))
{
m_ui->setupUi(this);
if (LtsSessionData::LtsSessionData::getInstance()->isTablet())
{
constexpr auto scaleFactor = 1.4;
resize(size() * scaleFactor);
m_ui->lbIcon->setMinimumSize(m_ui->lbIcon->minimumSize() * scaleFactor);
m_ui->lbIcon->setMaximumSize(m_ui->lbIcon->maximumSize() * scaleFactor);
}
}
MapObjectCustomView::~MapObjectCustomView()
{
delete m_ui;
}
bool MapObjectCustomView::init(const QModelIndex &idx)
{
if (!idx.isValid())
return false;
if (idx.model() != m_mapper->model())
{
// create mapping;
m_mapper->setModel(const_cast<QAbstractItemModel *>(idx.model()));
m_mapper->addMapping(m_ui->lbDescription, MapObjectModel::Columns::SINGLE_DESCRIPTION, "text");
m_mapper->addMapping(m_ui->lbIcon, MapObjectModel::Columns::PICTURE, "pixmap");
}
setRow(idx.row());
return true;
}
void MapObjectCustomView::setRow(int row)
{
m_mapper->setCurrentIndex(row);
// assume for now, that the relation between row and uniqueMapId will not change:
QAbstractItemModel *modelPtr = m_mapper->model();
if (modelPtr)
m_uniqueMapId = modelPtr->data(modelPtr->index(row, MapObjectModel::Columns::UNIQUE_MAP_ID)).toInt();
else
m_uniqueMapId = -1;
}
} // namespace SituationMap
@@ -0,0 +1,46 @@
/**
* @RDE_HEADER@
* CustomView for MapObjects
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, SLSE, 2017-04-11
*/
#pragma once
// Own
#include <Map/situation_map_types.h>
#include <Viewer/LtsDataView/abstract_display_widget.h>
class QDataWidgetMapper;
namespace Ui
{
class MapObjectCustomView;
}
namespace SituationMap
{
class MapObjectCustomView final : public LtsDataView::AbstractDisplayWidget
{
Q_OBJECT
using BaseClass = AbstractDisplayWidget;
public:
explicit MapObjectCustomView(QWidget *parent = nullptr);
~MapObjectCustomView();
bool init(const QModelIndex &idx) override;
private:
void setRow(int row);
private:
Ui::MapObjectCustomView *m_ui;
QDataWidgetMapper *m_mapper = nullptr;
UniqueMapId m_uniqueMapId = INVALID_MAP_ID;
};
} // SituationMap
@@ -0,0 +1,83 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MapObjectCustomView</class>
<widget class="QWidget" name="MapObjectCustomView">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>63</width>
<height>88</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string notr="true"/>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>4</number>
</property>
<property name="leftMargin">
<number>6</number>
</property>
<property name="topMargin">
<number>6</number>
</property>
<property name="rightMargin">
<number>6</number>
</property>
<property name="bottomMargin">
<number>6</number>
</property>
<item>
<widget class="QLabel" name="lbIcon">
<property name="minimumSize">
<size>
<width>50</width>
<height>50</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>50</width>
<height>50</height>
</size>
</property>
<property name="text">
<string notr="true"/>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lbDescription">
<property name="text">
<string notr="true">&lt;Desc&gt;</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,545 @@
/**
* @RDE_HEADER@
* HMI Plugin for ExerciseManangement - Exercise Overview Dialog Model
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2016-02-29
*/
// Own
#include "map_object_model.h"
#include <Symbology/sidc_codec.h>
#include <SituationMap/Map/party_id_to_color_functor.h>
#include <LtsWidgets/lts_column_filter_proxy_model.h>
// Qt
#include <QString>
#include <QBuffer>
#include <QPainter>
#include <QGuiApplication>
namespace SituationMap
{
static constexpr int ICON_RESOLUTION_CUSTOM = 128;
static constexpr int ICON_RESOLUTION_TABLE = 32;
void updateMapObjectDataToEnsureGoodQuality(MapObjectData *mod)
{
mod->m_symDataToRender.sizeL = ICON_RESOLUTION_CUSTOM;
}
MapObjectData::~MapObjectData()
{
delete m_symbolResultWatcher;
}
void MapObjectData::onResultReady()
{
if (!m_symbolResultWatcher)
return;
QSharedPointer<AdvancedSymbology::SymbolResult> symResult = m_symbolResultWatcher->symbolResult();
if (!symResult)
return; // should NEVER happen! (Which object should have triggered the signal???)
setImage(symResult->symbolImage().image());
emit dataChanged(m_uniqueMapId);
m_symbolResultWatcher->deleteLater();
m_symbolResultWatcher = nullptr;
}
void MapObjectData::requestImage(AdvancedSymbology::SymbolDictionary *dict)
{
if (!m_symbolResultWatcher)
{
m_symbolResultWatcher = new AdvancedSymbology::SymbolResultWatcher;
connect(m_symbolResultWatcher, &AdvancedSymbology::SymbolResultWatcher::resultReady,
this, &MapObjectData::onResultReady);
}
updateMapObjectDataToEnsureGoodQuality(this);
m_symbolResultWatcher->setSymbolResult(dict->findImage(m_symDataToRender));
}
void MapObjectData::setImage(const QImage &img)
{
if (img.isNull())
{
m_pixIcon = QPixmap();
m_pixPicture = QPixmap();
return;
}
const auto dpr = qApp->devicePixelRatio(); // only works when all screens have the same dpr, otherwise
// the widget (= screen) must be known
m_pixIcon = QPixmap::fromImage(img.scaled(QSize(ICON_RESOLUTION_TABLE, ICON_RESOLUTION_TABLE) * dpr,
Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation));
m_pixPicture = QPixmap::fromImage(img.scaled(QSize(ICON_RESOLUTION_CUSTOM, ICON_RESOLUTION_CUSTOM) * dpr,
Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation));
m_pixIcon.setDevicePixelRatio(dpr);
m_pixPicture.setDevicePixelRatio(dpr);
}
//---------------------------------
// MapObjectModel
//---------------------------------
MapObjectModel::MapObjectModel(QObject *parent)
: LtsWidgets::LtsAbstractTableModel<QSharedPointer<MapObjectData>>(
{
tr("UniqueMapid"),
tr("Sidc"),
tr("Description"),
tr("Icon"),
tr("ParticipantId"),
tr("Equipment number"),
tr("Party"),
tr("TypeId"),
tr("Type"),
tr("VulnerabilityStateId"),
tr("VulnerabilityState"),
tr("Designator"),
tr("Tact. Identifier"),
tr("Picture")
},
parent)
, m_logger(getLogger("MapObjectModel"))
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
MapObjectModel::~MapObjectModel()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
void MapObjectModel::initModel(Map *map)
{
m_map = map;
m_dictionary = &(m_map->symbolDictionary());
// Assume that the dialog (and therefore this underlying model) is created
// AFTER all user-defined data is udes to update SymbolDictionary.
// So we can simply use the changedDELAYED:
connect(m_dictionary, &AdvancedSymbology::SymbolDictionary::changedDelayed, this, &MapObjectModel::requestCivilIcons, Qt::UniqueConnection);
connect(this, &MapObjectModel::rowsInserted, this, &MapObjectModel::updateUsedPartyIds);
connect(this, &MapObjectModel::rowsRemoved, this, &MapObjectModel::updateUsedPartyIds);
connect(this, &MapObjectModel::modelReset, this, &MapObjectModel::updateUsedPartyIds);
}
bool MapObjectModel::contains(UniqueMapId uniqueMapId) const
{
return findRowForUniqueMapId(uniqueMapId) >= 0;
}
void MapObjectModel::remove(UniqueMapId uniqueMapId)
{
const int row = findRowForUniqueMapId(uniqueMapId);
removeRow(row);
}
void MapObjectModel::setMapObjectData(const QVector<QSharedPointer<MapObjectData>> &mapObjectDataVec)
{
setData(mapObjectDataVec);
for (const QSharedPointer<MapObjectData> &mapObjectData : mapObjectDataVec)
if (mapObjectData)
{
updateMapObjectDataToEnsureGoodQuality(mapObjectData.data());
connect(mapObjectData.data(), &MapObjectData::dataChanged,
this, &MapObjectModel::onDataChanged, Qt::UniqueConnection);
}
}
bool MapObjectModel::addMapObjectData(const QSharedPointer<MapObjectData> &mapObjectData)
{
const int row = findRowForUniqueMapId(mapObjectData->m_uniqueMapId);
if (row >= 0)
return false;
updateMapObjectDataToEnsureGoodQuality(mapObjectData.data());
// APPEND
if (!insertRow(mapObjectData))
return false;
connect(mapObjectData.data(), &MapObjectData::dataChanged,
this, &MapObjectModel::onDataChanged, Qt::UniqueConnection);
return true;
}
QImage markImage(const QPixmap &orgPixmap)
{
QImage newImage(orgPixmap.size(), QImage::Format_ARGB32);
static QColor fillColor = QColor(211, 211, 211, 120);
newImage.fill(fillColor);
QPainter painter(&newImage);
painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
painter.drawPixmap(orgPixmap.rect(), orgPixmap);
painter.end();
return newImage;
}
bool MapObjectModel::updateMapObjectData(const QSharedPointer<MapObjectData> &mapObjectData)
{
const int row = findRowForUniqueMapId(mapObjectData->m_uniqueMapId);
if (row < 0)
return false;
// UPDATE
if (!mapObjectData->m_symDataToRender.sidc.isEmpty()) // if sidc is provided
{
updateMapObjectDataToEnsureGoodQuality(mapObjectData.data());
const auto &oldRowData = m_vecData.at(row);
if (oldRowData->m_symDataToRender == mapObjectData->m_symDataToRender)
return true; // image will not change -> return;
// 1) 'mark' old image and reuse it:
mapObjectData->setImage(markImage(oldRowData->m_pixPicture));
// 2) icons are 'reused', but start update
requestIcon(mapObjectData);
}
connect(mapObjectData.data(), &MapObjectData::dataChanged,
this, &MapObjectModel::onDataChanged, Qt::UniqueConnection);
return setRowData(row, mapObjectData);
}
void MapObjectModel::requestCivilIcons()
{
for (const DATA_T &moData : qAsConst(m_vecData))
{
if (!moData)
continue;
const QString &sidc = moData->m_symDataToRender.sidc;
if (!AdvancedSymbology::SidcCodec::isEncoded(sidc))
continue;
if (!AdvancedSymbology::SidcCodec::isCivil(sidc))
continue;
requestIcon(moData);
} // for
}
QVariant MapObjectModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (role == LtsWidgets::LtsColumnFilterProxyModel::ComboboxFilterRole &&
orientation == Qt::Horizontal)
{
if (section == PARTY)
{
LtsWidgets::ComboboxFilterContent cfc;
cfc.data.reserve(m_usedPartyIds.size());
LtsWidgets::ComboboxFilterData cfd;
for (const int partyId : m_usedPartyIds)
{
const PartyIdToColorFunctor::PartyData party = m_map->partyIdToColorFunctor().partyId(partyId);// m_parties.value(partyId);
cfd.data = partyId;
cfd.text = party.m_name;
cfd.icon = party.m_icon;
cfc.data.push_back(cfd);
}
cfc.sortItems = false;
return cfc.toVariant();
}
if (section == TYPE_NAME)
{
LtsWidgets::ComboboxFilterContent cfc;
cfc.data.reserve(m_usedTypeName.size());
LtsWidgets::ComboboxFilterData cfd;
for (const QString &typeName : m_usedTypeName)
{
cfd.data = typeName;
cfd.text = typeName;
cfc.data.push_back(cfd);
}
cfc.sortItems = true;
return cfc.toVariant();
}
if (section == VULNERABILITY_STATE)
{
LtsWidgets::ComboboxFilterContent cfc;
cfc.data.reserve(m_usedVulnerabilities.size());
LtsWidgets::ComboboxFilterData cfd;
for (auto it = m_usedVulnerabilities.begin(); it != m_usedVulnerabilities.end(); ++it)
{
cfd.data = it.key();
cfd.text = it.value();
cfc.data.push_back(cfd);
}
cfc.sortItems = false;
return cfc.toVariant();
}
}
return BaseClass::headerData(section, orientation, role);
}
QVariant MapObjectModel::data(const QModelIndex &index, int role) const
{
if (!indexIsValid(index))
return QVariant();
if (role != Qt::DisplayRole &&
role != Qt::ToolTipRole &&
role != Qt::EditRole && // required by QDataWidgetMapper of MapObjectCustomView
role != Qt::DecorationRole &&
role != LtsWidgets::LtsColumnFilterProxyModel::ComboboxFilterRole)
return QVariant();
const DATA_T &moData = m_vecData.at(index.row());
if (role == Qt::ToolTipRole)
{
switch (index.column())
{
case PARTY:
return QStringLiteral("%1 (%2)").arg(moData->m_partyName).arg(moData->m_partyId);
case UNIQUE_MAP_ID: // CustomView -> ToolTipRole and column==UNIQUE_MAP_ID (0)
case ICON: // TableView -> ToolTipRole and column==ICON
{
QString tooltip(QStringLiteral("<html>"));
const QPixmap &img = moData->m_pixPicture;
if (!img.isNull())
{
// without a temporary file:
QByteArray data;
QBuffer buffer(&data);
img.save(&buffer, "PNG", 100);
tooltip.append(QStringLiteral("<center><img src='data:image/png;base64,%1'></center>").arg(QString::fromLatin1(data.toBase64())));
}
if (!moData->m_typeName.isEmpty())
{
const QString &hdr = this->headerData(MapObjectModel::Columns::TYPE_NAME , Qt::Horizontal, Qt::DisplayRole).toString();
tooltip.append(QStringLiteral("<p>%1: %2</p>").arg(hdr, moData->m_typeName));
}
if (!moData->m_typeName.isEmpty())
{
const QString &hdr = this->headerData(MapObjectModel::Columns::VULNERABILITY_STATE, Qt::Horizontal, Qt::DisplayRole).toString();
tooltip.append(QStringLiteral("<p>%1: %2</p>").arg(hdr, moData->m_vulnerabilityString));
}
if (!moData->m_description1.isEmpty())
{
const QString &hdr = this->headerData(MapObjectModel::Columns::DESCRIPTION1, Qt::Horizontal, Qt::DisplayRole).toString();
tooltip.append(QStringLiteral("<p>%1: %2</p>").arg(hdr, moData->m_description1));
}
if (!moData->m_description2.isEmpty())
{
const QString &hdr = this->headerData(MapObjectModel::Columns::DESCRIPTION2, Qt::Horizontal, Qt::DisplayRole).toString();
tooltip.append(QStringLiteral("<p>%1: %2</p>").arg(hdr, moData->m_description2));
}
#ifdef LTS_DEBUG
tooltip.append(QStringLiteral("<p>participantId: %2</p>").arg(moData->m_participantId));
tooltip.append(QStringLiteral("<p>row: %2</p>").arg(index.row()));
tooltip.append(QStringLiteral("<p>uniqueMapId: %2</p>").arg(moData->m_uniqueMapId));
tooltip.append(QStringLiteral("<p>typeId: %2</p>").arg(moData->m_typeId));
tooltip.append(QStringLiteral("<p>vulnerabilityStateId: %2</p>").arg(moData->m_vulnerabilityState));
#endif // LTS_DEBUG
tooltip.append(QStringLiteral("</html>"));
return tooltip;
}
} // switch
} // if ((role == Qt::ToolTipRole))
if ((role == Qt::DisplayRole) || (role == Qt::EditRole) || (role != LtsWidgets::LtsColumnFilterProxyModel::ComboboxFilterRole))
{
const UniqueMapId &uniqueMapId = moData->m_uniqueMapId;
switch (index.column())
{
case UNIQUE_MAP_ID:
return uniqueMapId;
case SIDC:
return moData->m_symDataToRender.sidc;
case SINGLE_DESCRIPTION:
if (moData->m_equipmentNumber >= 0)
return moData->m_equipmentNumber;
else
return moData->m_description1;
case ICON:
{
// provided or already cached?
if (moData->m_pixIcon.isNull())
{
moData->setImage(AdvancedSymbology::SymbolDictionary::temporaryImage());
requestIcon(moData);
}
if (moData->m_pixIcon.isNull())
return QVariant();
return moData->m_pixIcon;
}
case PARTICIPANT_ID:
return moData->m_participantId <= 0 ? QVariant() : QVariant(moData->m_participantId);
case EQUIPMENT_NUMBER:
return moData->m_equipmentNumber <= 0 ? QVariant() : QVariant(moData->m_equipmentNumber);
case PARTY:
return moData->m_partyName;
case TYPE_ID:
return moData->m_typeId <= 0 ? QVariant() : QVariant(moData->m_typeId);
case TYPE_NAME:
return moData->m_typeName;
case VULNERABILITY_STATE:
return moData->m_vulnerabilityString;
case VULNERABILITY_STATE_ID:
return moData->m_vulnerabilityState <= 0 ? QVariant() : QVariant(moData->m_vulnerabilityState);
case DESCRIPTION1:
return moData->m_description1;
case DESCRIPTION2:
return moData->m_description2;
case PICTURE:
{
// provided or already cached?
if (moData->m_pixPicture.isNull())
{
moData->setImage(AdvancedSymbology::SymbolDictionary::temporaryImage());
requestIcon(moData);
}
if (moData->m_pixPicture.isNull())
return QVariant();
return moData->m_pixPicture;
} // case PICTURE
} // switch
}
if (role == LtsWidgets::LtsColumnFilterProxyModel::ComboboxFilterRole)
{
if (index.column() == PARTY)
return moData->m_partyId;
if (index.column() == TYPE_NAME)
return moData->m_typeName;
if (index.column() == VULNERABILITY_STATE)
return moData->m_vulnerabilityState;
}
return QVariant();
}
UniqueMapId MapObjectModel::uniqueMapIdOfIndex(const QModelIndex &index) const
{
if (!indexIsValid(index))
return SituationMap::INVALID_MAP_ID;
const DATA_T &moData = m_vecData.at(index.row());
if (!moData)
return SituationMap::INVALID_MAP_ID;
return moData->m_uniqueMapId;
}
void MapObjectModel::onDataChanged(UniqueMapId uniqueMapId)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START, uniqueMapId=" << uniqueMapId;
// resultWatcher has generated a new image -> update view:
int row = findRowForUniqueMapId(uniqueMapId);
emit dataChanged(index(row, 0), index(row, LtsAbstractTableModel::columnCount(QModelIndex()) - 1));
}
int MapObjectModel::findRowForUniqueMapId(UniqueMapId uniqueMapId) const
{
for (int i = 0; i < m_vecData.size(); ++i)
{
if (m_vecData.at(i)->m_uniqueMapId == uniqueMapId)
return i;
}
return -1;
}
void MapObjectModel::requestIcon(const MapObjectModel::DATA_T &data) const
{
// start rendering using SymbolResultWatcher:
data->requestImage(m_dictionary);
}
void MapObjectModel::updateUsedPartyIds()
{
m_usedPartyIds.clear();
m_usedTypeName.clear();
m_usedVulnerabilities.clear();
for (const QSharedPointer<MapObjectData> &item : qAsConst(m_vecData))
{
if (!item)
continue;
m_usedPartyIds[item->m_partyId] = item->m_partyId;
m_usedTypeName.insert(item->m_typeName);
m_usedVulnerabilities.insert(item->m_vulnerabilityState,
item->m_vulnerabilityState < 0 ? QStringLiteral("-") : item->m_vulnerabilityString);
}
}
// --------------------------------------------------------
// MapObjectProxyModel
// --------------------------------------------------------
void MapObjectProxyModel::setSourceModel(QAbstractItemModel *sourceModel)
{
m_sourceModel = qobject_cast<MapObjectModel*>(sourceModel);
BaseClass::setSourceModel(sourceModel);
}
bool MapObjectProxyModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
{
if (!m_sourceModel ||
source_left.column() != source_right.column() ||
source_left.row() < 0 || source_left.row() >= m_sourceModel->m_vecData.size() ||
source_right.row() < 0 || source_right.row() >= m_sourceModel->m_vecData.size()
)
return BaseClass::lessThan(source_left, source_right);
const QSharedPointer<MapObjectData> &left = m_sourceModel->m_vecData.at(source_left.row());
const QSharedPointer<MapObjectData>&right = m_sourceModel->m_vecData.at(source_right.row());
switch (source_left.column())
{
case MapObjectModel::Columns::UNIQUE_MAP_ID:
return left->m_uniqueMapId < right->m_uniqueMapId;
case MapObjectModel::Columns::SIDC:
return left->m_symDataToRender.sidc < right->m_symDataToRender.sidc;
case MapObjectModel::Columns::SINGLE_DESCRIPTION:
if (left->m_equipmentNumber && right->m_equipmentNumber)
return left->m_equipmentNumber < right->m_equipmentNumber;
if (left->m_equipmentNumber)
return true;
if (right->m_equipmentNumber)
return true;
return left->m_description1 < left->m_description1;
case MapObjectModel::Columns::PARTICIPANT_ID:
return left->m_participantId < right->m_participantId;
case MapObjectModel::Columns::EQUIPMENT_NUMBER:
return left->m_equipmentNumber < right->m_equipmentNumber;
case MapObjectModel::Columns::PARTY:
return left->m_partyId < right->m_partyId;
case MapObjectModel::Columns::TYPE_ID:
return left->m_typeId < right->m_typeId;
case MapObjectModel::Columns::TYPE_NAME:
return left->m_typeName < right->m_typeName;
case MapObjectModel::Columns::DESCRIPTION1:
return left->m_description1 < right->m_description1;
case MapObjectModel::Columns::DESCRIPTION2:
return left->m_description2 < right->m_description2;
}
return BaseClass::lessThan(source_left, source_right);
}
} // namespace SituationMap
Loaded 100 of 16245 files, more files were not shown because too many files have changed in this diff. Show more