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