/** * @RDE_HEADER@ * Interface * $Id$ * $HeadURL$ * $Author$ */ // Own #include "buildings_to_map.h" #include #include #include #include // for method "getForeignGuiInterface" #include // for Buildings::ForeignInfoGuiInterface #include #include // Qt #include #include #include #include #include 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 &uniqueMapIds) { if (!m_bldInfoIfc) return false; const QVector &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 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 mapObj = m_objFac.get(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 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 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 &mapObj) { mapObj->setScale(m_currentSymbolSettings.symbolSettings.symbolScale); mapObj->setVisibility(m_currentSymbolSettings.symbolSettings.showBuildingOutline); mapObj->setIdentifierVisible(m_currentSymbolSettings.symbolSettings.showBuildingIdentifier); } }