441 lines
15 KiB
C++
Executable File
441 lines
15 KiB
C++
Executable File
/**
|
|
* @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();
|
|
}
|
|
|
|
}
|