Initial commit
This commit is contained in:
commit
b7d90b9afe
16245 files changed
+3396666
No files matched your search
Executable
+202
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
Executable
+62
@@ -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
|
||||
+2022
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
|
||||
+553
@@ -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
|
||||
+89
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+56
@@ -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
|
||||
+185
@@ -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
|
||||
+111
@@ -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
|
||||
+50
@@ -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
|
||||
+367
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
+91
@@ -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
|
||||
+84
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+58
@@ -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
|
||||
+664
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
+91
@@ -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
|
||||
+662
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
+90
@@ -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
|
||||
Executable
+440
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
+102
@@ -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
|
||||
+428
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
+88
@@ -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
|
||||
+790
@@ -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
|
||||
+99
@@ -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
|
||||
+79
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+47
@@ -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
|
||||
+141
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+62
@@ -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
|
||||
+598
@@ -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 ¢er_geo, qreal radius, int steps= 72)
|
||||
{
|
||||
const LtsCoordTrans::UtmCoordinate ¢erUtm = 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 ¢erGeo = 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 ¢erGeo, 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);
|
||||
}
|
||||
|
||||
}
|
||||
+92
@@ -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 ¢erGeo = 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
|
||||
+272
@@ -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;
|
||||
}
|
||||
}
|
||||
+79
@@ -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
|
||||
+185
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+51
@@ -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
|
||||
+1018
File diff suppressed because it is too large.
Load diff
+103
@@ -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 ¢erGeo = 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
|
||||
+95
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+56
@@ -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
|
||||
+100
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+51
@@ -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
|
||||
+75
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+47
@@ -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
|
||||
+476
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
+101
@@ -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
|
||||
+355
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+91
@@ -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
|
||||
+546
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
+110
@@ -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
|
||||
+27
@@ -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
|
||||
+445
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+224
@@ -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
|
||||
+482
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+67
@@ -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
|
||||
+81
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+47
@@ -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
|
||||
+911
@@ -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
|
||||
+126
@@ -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
|
||||
+359
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+78
@@ -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
|
||||
+221
@@ -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;
|
||||
}
|
||||
+69
@@ -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
|
||||
+180
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+52
@@ -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
|
||||
+376
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
+72
@@ -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
|
||||
+1892
File diff suppressed because it is too large.
Load diff
+233
@@ -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
|
||||
+205
@@ -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;
|
||||
};
|
||||
}
|
||||
+239
@@ -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
|
||||
+81
@@ -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
|
||||
+49
@@ -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
|
||||
+25
@@ -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
|
||||
+107
@@ -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 ¢er = 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;
|
||||
}
|
||||
|
||||
}
|
||||
+61
@@ -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
|
||||
+685
@@ -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
|
||||
+361
@@ -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;
|
||||
}
|
||||
+73
@@ -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
|
||||
+113
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+64
@@ -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
|
||||
+81
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+47
@@ -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
|
||||
+126
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+65
@@ -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
|
||||
+58
@@ -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
|
||||
Reference in new issue
Block a user