Files
qt5-legatus-legacy/Lts/Plugins/SituationMapPlugin/Gui/SituationMap/AdapterDds/buildings_to_map.cpp
T
2026-08-13 18:33:10 +02:00

429 lines
14 KiB
C++
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* @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);
}
}