/** * @RDE_HEADER@ * Gui Plugin for SituationMap * $Id$ * $HeadURL$ * $Author$ * Created by Patric Karwat, SLSE, 2016-02-29 */ #include "sitmap_gui_plugin.h" #include "situation_map_init.h" #include "sitmap_widget_control.h" #include "ConfigureUrl/sitmap_configure_urls.h" #include "AdapterDds/adapter_dds.h" #include "TopicEditor/topic_editor.h" #include #include #include #include #include // findChild #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // LocalServer // #define USE_LOCAL_SERVER #ifdef USE_LOCAL_SERVER # include static QString viewshedSvcName() { return QStringLiteral("Viewshed"); } #endif // USE_LOCAL_SERVER #include "terrain_profile_handler.h" #include "plugin_provider_lts_session.h" #include "MapObjectSelection/map_object_selection_widget.h" #include "viewshed_dialog.h" #include // make sure, that both enums have identical values assigned and a static_cast works fine: static_assert((int)SituationMap::MapMode::Undefined == (int)SituationMap::Mode::Undefined, "Mode/MapMode mismatch"); static_assert((int)SituationMap::MapMode::MapMode_2D == (int)SituationMap::Mode::Mode_2D, "Mode/MapMode mismatch"); static_assert((int)SituationMap::MapMode::MapMode_3D == (int)SituationMap::Mode::Mode_3D, "Mode/MapMode mismatch"); static_assert((int)SituationMap::MapLinePattern::Dash == (int)SituationMap::LinePattern::Dash, "MapLinePattern/LinePattern mismatch"); static_assert((int)SituationMap::MapLinePattern::DashDot == (int)SituationMap::LinePattern::DashDot, "MapLinePattern/LinePattern mismatch"); static_assert((int)SituationMap::MapLinePattern::DashDotDot == (int)SituationMap::LinePattern::DashDotDot, "MapLinePattern/LinePattern mismatch"); static_assert((int)SituationMap::MapLinePattern::Dot == (int)SituationMap::LinePattern::Dot, "MapLinePattern/LinePattern mismatch"); static_assert((int)SituationMap::MapLinePattern::Null == (int)SituationMap::LinePattern::Null, "MapLinePattern/LinePattern mismatch"); static_assert((int)SituationMap::MapLinePattern::Solid == (int)SituationMap::LinePattern::Solid, "MapLinePattern/LinePattern mismatch"); static_assert((int)SituationMap::MapFillPattern::BackwardDiagonal == (int)SituationMap::MapFillPattern::BackwardDiagonal, "MapFillPattern/FillPattern mismatch"); static_assert((int)SituationMap::MapFillPattern::Cross == (int)SituationMap::MapFillPattern::Cross, "MapFillPattern/FillPattern mismatch"); static_assert((int)SituationMap::MapFillPattern::DiagonalCross == (int)SituationMap::MapFillPattern::DiagonalCross, "MapFillPattern/FillPattern mismatch"); static_assert((int)SituationMap::MapFillPattern::ForwardDiagonal == (int)SituationMap::MapFillPattern::ForwardDiagonal, "MapFillPattern/FillPattern mismatch"); static_assert((int)SituationMap::MapFillPattern::Horizontal == (int)SituationMap::MapFillPattern::Horizontal, "MapFillPattern/FillPattern mismatch"); static_assert((int)SituationMap::MapFillPattern::Null == (int)SituationMap::MapFillPattern::Null, "MapFillPattern/FillPattern mismatch"); static_assert((int)SituationMap::MapFillPattern::Solid == (int)SituationMap::MapFillPattern::Solid, "MapFillPattern/FillPattern mismatch"); static_assert((int)SituationMap::MapFillPattern::Vertical == (int)SituationMap::MapFillPattern::Vertical, "MapFillPattern/FillPattern mismatch"); namespace SituationMap { #define LOG_ERROR_SIT ERROR_LOG(m_logger) << LOGFUNCTION << " no situationMapInit" #define CHECK_SMI_RETVAL if (!(m_situationMapInit)) { LOG_ERROR_SIT; return {}; } #define CHECK_SMI if (!(m_situationMapInit)) { LOG_ERROR_SIT; return; } //------------------------------------------------------------------------------ // MyMapWidgetDialog //------------------------------------------------------------------------------ MyMapWidgetDialog::MyMapWidgetDialog(QWidget *parent, LtsWidgets::ButtonCombination buttonCombination) : BaseClass(parent, buttonCombination, false /* unclosable */) { QHBoxLayout *box = new QHBoxLayout(); box->setObjectName(QStringLiteral("boxAroundSituationMapWidget")); box->setMargin(0); // seemless integration into BaseLayout this->setLayout(box); } MyMapWidgetDialog::~MyMapWidgetDialog() { // qCritical() << "MapCache: ~MyMapWidgetDialog::aboutToClose , widget=" << this->layout()->widget(); emit aboutToCloseSignal(); } void MyMapWidgetDialog::addWidget(QWidget *w) { if (!this->layout()) return; if (!w) return; // QLabel *l = new QLabel(QStringLiteral("DummyLabel")); // this->layout()->addWidget(l); this->layout()->addWidget(w); } void MyMapWidgetDialog::aboutToClose() { // qCritical() << "MapCache: MyMapWidgetDialog::aboutToClose , " << this->layout()->widget(); emit aboutToCloseSignal(); } void MyMapWidgetDialog::retranslate() { // lupdate doesn't like translate(tr("foo")) ... const QString txt(tr("Situation Map")); translate(txt); } //------------------------------------------------------------------------------ // GuiPlugin //------------------------------------------------------------------------------ std::shared_ptr GuiPlugin::createGuiInterface(LtsSession::LtsSession *session) { return std::make_shared(session); } //------------------------------------------------------------------------------ // InterfaceImpl //------------------------------------------------------------------------------ InterfaceImpl::InterfaceImpl(LtsSession::LtsSession *session) : GuiPluginBase::Interface(session, getLogger("Plugins.Gui.SitMap")) , m_ltsDialogSitMapWidget(nullptr) , m_registerAppHandler(*(new RegisterAppHandler)) // ref to prevent someone to delete the handler themselves , m_objToInform(nullptr) { } //------------------------------------------------------------------------------ InterfaceImpl::~InterfaceImpl() { m_registerAppHandler.finalize(); clearInterfaces(); } //------------------------------------------------------------------------------ TopicEditorBase::TopicEditor *InterfaceImpl::createTopicEditor(const TopicEditorBase::TopicData &data) { SituationMapTopicEditor *topicEditor = new SituationMapTopicEditor(); topicEditor->setTopicData(data); return topicEditor; } //------------------------------------------------------------------------------ LtsWidgets::LtsDialog *InterfaceImpl::createMapDialog(QWidget *parent) { m_situationMap.clear(); // use always 2D mode return onShowSituationMapDialog(parent); } // LtsWidgets::LtsDialog * InterfaceImpl::createMapDialog(QWidget *parent) //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ QVector InterfaceImpl::getActions() { QVector ret; { if (LtsAppDescriptor::App::PlanEditor != m_session->app()) { LtsWidgets::PluginData data; data.menuGroup = tr("Situation Map"); data.menuText = tr("Show Situation Map"); data.identifier = QStringLiteral("SituationMap"); if (getFlags().testFlag(LtsAppDescriptor::PluginInfo::Flag::MAIN)) { data.layoutArea = LtsWidgets::LayoutArea::eMainTab; data.createInstant = LtsWidgets::CreateInstantType::CreateInstantAndDiscardAction; data.closable = false; } data.exercisePart = LtsWidgets::ExercisePart::eExecution; data.createWidgetFunc = [this](QWidget * parent) { return onShowSituationMapDialog(parent); }; ret.append(data); } } // //now the menu entries // if (LtsAppDescriptor::App::PlanEditor != m_session->app()) { LtsWidgets::PluginData data; data.menuGroup = tr("Situation Map"); data.menuText = tr("Map Widgets"); data.identifier = QStringLiteral("SituationMap-MapWidget"); data.menuIcon = QIcon(QStringLiteral("icon:map_settings.svg")); data.directFunc = nullptr; data.exercisePart = LtsWidgets::ExercisePart::eSpecial; data.createWidgetFunc = [this](QWidget * parent) { return onShowMapWidgetControlDialog(parent); }; ret.append(data); } { LtsWidgets::PluginData data; data.menuGroup = tr("Situation Map"); // Layer Control data.menuText = tr("Layer Control"); data.identifier = QStringLiteral("SituationMap-LayerControlNew"); data.menuIcon = QIcon(QStringLiteral("icon:layer.svg")); data.exercisePart = LtsWidgets::ExercisePart::eSpecial; data.createWidgetFunc = [this](QWidget * parent) { return onShowLayerControlDialog(parent); }; ret.append(data); } // GUEZE-1624: not in ResourceManagerApp: // const bool bSuppress = (m_session->app() == LtsAppDescriptor::App::OC) || (m_session->app() == LtsAppDescriptor::App::ResourceManager); if (LtsAppDescriptor::App::PlanEditor != m_session->app() && m_session->app() != LtsAppDescriptor::App::OC && m_session->app() != LtsAppDescriptor::App::ResourceManager ) { LtsWidgets::PluginData data; data.menuGroup = tr("Situation Map"); // Participant Aggregation data.menuText = tr("Participant Aggregation"); data.identifier = QStringLiteral("SituationMap-ParticipantAggregation"); data.menuIcon = QIcon(QStringLiteral("icon:operator_group.svg")); data.exercisePart = LtsWidgets::ExercisePart::eSpecial; data.createWidgetFunc = [this](QWidget * parent) -> LtsWidgets::LtsDialog* { return new SituationMap::ParticipantAggregationDialog(m_situationMap, parent); }; ret.append(data); } { LtsWidgets::PluginData data; data.menuGroup = tr("Situation Map"); // Rocket data.menuText = tr("Rocket"); data.identifier = QStringLiteral("SituationMap-Rocket"); data.menuIcon = QIcon(QStringLiteral("icon:rocket.svg")); data.createWidgetFunc = nullptr; data.exercisePart = LtsWidgets::ExercisePart::eSpecial; data.directFunc = [this](const LtsWidgets::PluginData &) { if (m_situationMap != nullptr) m_situationMap->startRocket(); }; ret.append(data); } // Measurement { LtsWidgets::PluginData data; data.menuGroup = tr("Situation Map"); data.menuText = tr("Start Measure Length"); data.identifier = QStringLiteral("SituationMap-MeasureLength"); data.menuIcon = QIcon(QStringLiteral("icon:create_distance_measure.svg")); data.operatorRight = OperatorRights::SituationMap::SituationMapMeasureDistance; data.exercisePart = LtsWidgets::ExercisePart::eSpecial; data.createWidgetFunc = nullptr; data.directFunc = [this](const LtsWidgets::PluginData &) { this->startMeasureLength(); }; ret.append(data); } { LtsWidgets::PluginData data; data.menuGroup = tr("Situation Map"); data.menuText = tr("Clear Measure Length"); data.identifier = QStringLiteral("SituationMap-clearMeasurement"); data.menuIcon = QIcon(QStringLiteral("icon:create_distance_measure_remove.svg")); data.operatorRight = OperatorRights::SituationMap::SituationMapMeasureDistance; data.exercisePart = LtsWidgets::ExercisePart::eSpecial; data.createWidgetFunc = nullptr; data.directFunc = [this](const LtsWidgets::PluginData &) { this->clearMeasureLength(); }; ret.append(data); } // TerrainProfile if (LtsAppDescriptor::App::PlanEditor != m_session->app()) { LtsWidgets::PluginData data; data.menuGroup = tr("Situation Map"); data.menuText = tr("Start Terrain Profile"); data.identifier = QStringLiteral("SituationMap-TerrainProfile"); data.menuIcon = QIcon(QStringLiteral("icon:create_terrain_profile.svg")); data.operatorRight = OperatorRights::SituationMap::SituationMapTerrainProfile; data.exercisePart = LtsWidgets::ExercisePart::eSpecial; data.createWidgetFunc = nullptr; data.directFunc = [this](const LtsWidgets::PluginData &) { this->startTerrainProfile(); }; ret.append(data); } { LtsWidgets::PluginData data; data.menuGroup = tr("Situation Map"); data.menuText = tr("Clear Terrain Profile"); data.identifier = QStringLiteral("SituationMap-clearTerrainProfile"); data.menuIcon = QIcon(QStringLiteral("icon:create_terrain_profile_remove.svg")); data.operatorRight = OperatorRights::SituationMap::SituationMapTerrainProfile; data.exercisePart = LtsWidgets::ExercisePart::eSpecial; data.createWidgetFunc = nullptr; data.directFunc = [this](const LtsWidgets::PluginData &) { this->clearTerrainProfile(); }; ret.append(data); } // Viewshed if (LtsAppDescriptor::App::PlanEditor != m_session->app()) { LtsWidgets::PluginData data; data.menuGroup = tr("Situation Map"); data.menuText = tr("Start Viewshed"); data.identifier = QStringLiteral("SituationMap-Viewshed"); data.menuIcon = QIcon(QStringLiteral("icon:configure_line_of_sight.svg")); data.operatorRight = OperatorRights::SituationMap::SituationMapViewshed; data.exercisePart = LtsWidgets::ExercisePart::eSpecial; data.createWidgetFunc = nullptr; data.directFunc = [this](const LtsWidgets::PluginData &) { this->buildViewshedDialog(); }; ret.append(data); } { LtsWidgets::PluginData data; data.menuGroup = tr("Situation Map"); data.menuText = tr("Clear Viewshed"); data.identifier = QStringLiteral("SituationMap-clearViewshed"); data.menuIcon = QIcon(QStringLiteral("icon:configure_line_of_sight_remove.svg")); data.operatorRight = OperatorRights::SituationMap::SituationMapViewshed; data.exercisePart = LtsWidgets::ExercisePart::eSpecial; data.directFunc = [this](const LtsWidgets::PluginData &) { this->clearViewshed(); }; ret.append(data); } if (LtsAppDescriptor::App::PlanEditor != m_session->app()) { // Show Building Ownership const bool showBuildingOwnershp = LtsUtils::ProjectSettings::isFunctionEnabled(QStringLiteral("Buildings"), QStringLiteral("Ownership")); if ( showBuildingOwnershp) { LtsWidgets::PluginData data; data.menuGroup = tr("Situation Map"); // BuildingOwnership data.menuText = tr("Show Building Ownership"); data.identifier = QStringLiteral("SituationMap-ShowBuildingOwnership"); data.menuIcon = QIcon(QStringLiteral("icon:building_ownership.svg")); data.createWidgetFunc = nullptr; data.exercisePart = LtsWidgets::ExercisePart::eSpecial; data.directFunc = [this](const LtsWidgets::PluginData &) { if (!m_situationMapInit) return; bool curVisi = m_situationMapInit->isBuildingOwnershipVisible(); bool success = m_situationMapInit->setBuildingOwnershipVisible(!curVisi); if (!success) WARNING_LOG(m_logger) << LOGFUNCTION << "setBuildingOwnershipVisible failed"; if (menueBtnBuildingOwnership) menueBtnBuildingOwnership->setChecked(m_situationMapInit->isBuildingOwnershipVisible()); }; ret.append(data); } // Show Building Ownership const bool showBuildingContamination = LtsUtils::ProjectSettings::isFunctionEnabled(QStringLiteral("Buildings"), QStringLiteral("Contamination")); if (showBuildingContamination) { LtsWidgets::PluginData data; data.menuGroup = tr("Situation Map"); // BuildingOwnership data.menuText = tr("Show Building Contamination"); data.identifier = QStringLiteral("SituationMap-ShowBuildingContamination"); data.menuIcon = QIcon(QStringLiteral("icon:building_contamination.svg")); data.createWidgetFunc = nullptr; data.exercisePart = LtsWidgets::ExercisePart::eSpecial; data.directFunc = [this](const LtsWidgets::PluginData &) { if (!m_situationMapInit) return; bool curVisi = m_situationMapInit->isBuildingContaminationVisible(); bool success = m_situationMapInit->setBuildingContaminationVisible(!curVisi); if (!success) WARNING_LOG(m_logger) << LOGFUNCTION << "setBuildingContaminationVisible failed"; if (menueBtnBuildingContamination) menueBtnBuildingContamination->setChecked(m_situationMapInit->isBuildingContaminationVisible()); }; ret.append(data); } // Show 3D Buildings { LtsWidgets::PluginData data; data.menuGroup = tr("Situation Map"); // BuildingOwnership data.menuText = tr("Show 3D Buildings"); data.identifier = QStringLiteral("SituationMap-3D_Buildings"); data.menuIcon = QIcon(QStringLiteral("icon:load.svg")); data.createWidgetFunc = nullptr; data.exercisePart = LtsWidgets::ExercisePart::eSpecial; data.directFunc = [this](const LtsWidgets::PluginData &) { if (!m_situationMapInit) return; LayerFactory &layerFac = m_situationMapInit->getWidget()->layerFactory(); bool curVisi = layerFac.isSceneObjectLayerVisible(); layerFac.setSceneObjectLayerVisible(!curVisi); if (menueBtn3dBuildingsVisible) menueBtn3dBuildingsVisible->setChecked(layerFac.isSceneObjectLayerVisible()); }; ret.append(data); } } // Configure Map Urls if (m_pluginProvider->operatorId() == 99 && LtsAppDescriptor::App::OC != m_session->app()) // 99 == Organisator { LtsWidgets::PluginData data; data.menuGroup = tr("Situation Map"); data.menuText = tr("Configure Map Urls"); data.identifier = QStringLiteral("SituationMap-ConfigureMapUrls"); data.menuIcon = QIcon(QStringLiteral("icon:configure_map_urls.svg")); data.createWidgetFunc = nullptr; data.exercisePart = LtsWidgets::ExercisePart::eSpecial; data.createWidgetFunc = [this](QWidget * parent) { return onShowConfigureUrlsDialog(parent); }; ret.append(data); } if (LtsAppDescriptor::App::OC != m_session->app()) { // Print { LtsWidgets::PluginData data; data.menuGroup = tr("Situation Map"); data.menuText = tr("Print"); data.identifier = QStringLiteral("SituationMap-Print"); data.menuIcon = QIcon(QStringLiteral("icon:print.svg")); data.createWidgetFunc = nullptr; data.exercisePart = LtsWidgets::ExercisePart::eSpecial; data.directFunc = [this](const LtsWidgets::PluginData &) { this->doPrint(); }; ret.append(data); } } // // other menuGroup // { if (strcmp(PROJECTBUILD, "commaster") == 0) { LtsWidgets::PluginData data; data.menuGroup = menuGroup(); data.createInstant = LtsWidgets::CreateInstantType::CreateInstantAndDiscardAction; data.directFunc = [this](const LtsWidgets::PluginData &) { LtsNotification::LtsNotification *noti = m_session->createNotification(QStringLiteral("OwnPosition")); noti->setToolTip(tr("Show own position")); noti->setIcon(QIcon(QStringLiteral("icon:/position.svg"))); noti->setAction([this](){ if(m_situationMapInit->isOwnPositionVisble()) m_situationMapInit->setOwnPositionVisible(false); else m_situationMapInit->setOwnPositionVisible(true); }); }; ret.append(data); } } // Building Viewer if (LtsAppManager::LtsAppManager::getInstance()->hasApp(LtsAppDescriptor::App::BuildingViewer) && (m_session->app() != LtsAppDescriptor::App::ResourceManager) // GUEZE-1624: not in ResourceManagerApp: ) { LtsWidgets::PluginData data; data.menuGroup = tr("Apps"); data.menuText = tr("Building Viewer"); data.identifier = QStringLiteral("ShowBuildingViewer"); data.menuIcon = QIcon(QStringLiteral("icon:3d_viewer.svg")); data.createWidgetFunc = nullptr; data.directFunc = [this](const LtsWidgets::PluginData &) { std::shared_ptr bdvGuiIfc; m_session->getForeignGuiInterface(bdvGuiIfc); if (bdvGuiIfc) bdvGuiIfc->showBuildingViewer(m_session); }; ret.append(data); } return ret; } QString InterfaceImpl::menuGroup() const { return tr("Situation Map"); } bool InterfaceImpl::fetchInterfaces() { connect(m_session, &LtsSession::LtsSession::sessionAboutToBeDestroyed, this, &InterfaceImpl::onSessionAboutToBeDestroyed, Qt::UniqueConnection); // qWarning() << "sitmap appid" << static_cast(m_session->app()); // mandatory if (!m_session->getForeignGuiInterface(m_asbGuiIfc)) { DEBUG_LOG(m_logger) << LOGFUNCTION << " getForeignGuiInterface for ForeignGuiFlmSymbolsProxyInterface failed."; return false; } // PluginProvider if (!m_pluginProvider) m_pluginProvider = new SituationMap::PluginProviderLtsSession(m_session); if (!m_pluginProvider->init(m_logger)) return false; std::shared_ptr fltDtc = m_pluginProvider->fltDtc(); if (!fltDtc) { ERROR_LOG(m_logger) << LOGFUNCTION << " no fltDtc"; return false; } fltDtc->enableTriggerFilterData(); connect(fltDtc.get(), &FilterManagement::Interface::Dtc::triggerFilterDataChanged, this, &InterfaceImpl::onTriggerFilterDataChanged, Qt::UniqueConnection); // ASM m_asmDtc = m_pluginProvider->asmDtc(); if (m_asmDtc) { connect(m_asmDtc.get(), &AssetManagement::Interface::Dtc::trainingAreaChanged, this, &InterfaceImpl::onTrainingAreaChanged, Qt::UniqueConnection); // get: m_asmDtc->trainingAreas([this](const AssetManagement::TrainingArea &data) { onTrainingAreaChanged(data, DataModification::eAdded); }); } else { WARNING_LOG(m_logger) << LOGFUNCTION << " no m_asmDtc"; } // optional: // PlanOverlaysPlugin::ForeignGuiInterface // MarkerManagement::ForeignGuiInterface return true; } template void deleteLaterClear(QPointer &ptr) { if (!ptr) return; ptr->deleteLater(); ptr = nullptr; } template void deleteClear(QPointer &ptr) { delete ptr; ptr = nullptr; } void InterfaceImpl::onSessionAboutToBeDestroyed() { // DeRegister app per screenId at Opm: m_registerAppHandler.deRegisterApp(this); } void InterfaceImpl::clearInterfaces() { deleteClear(m_situationMapInit); deleteClear(m_terrainProfileHandler); deleteClear(m_pluginProvider); deleteLaterClear(m_dialogMapObjectSelection); deleteLaterClear(m_ltsDialogSitMapWidget); deleteLaterClear(m_mapWidgetControl); deleteLaterClear(m_mapLayerControl); deleteLaterClear(m_configureMapUrls); m_asbGuiIfc = nullptr; } bool InterfaceImpl::clearObjects() { if (!m_situationMapInit) return false; return m_situationMapInit->clearObjects(); } void InterfaceImpl::onChangeModeRequested() { DEBUG_LOG(m_logger) << LOGFUNCTION << " START"; if (!this->isMapReady()) return; // // old instance // // if available: save current oms (to restore them in toggled mode (2D <-> 3D) if (m_situationMap) { m_operatorMapSettings2achieve = m_situationMap->operatorMapSettings(); // toggle: m_operatorMapSettings2achieve.mode = SituationMap::toggleMode(m_operatorMapSettings2achieve.mode); } // DeRegister app per screenId at Opm: m_registerAppHandler.deRegisterApp(this); reCreateSituationMapInitAndAddToLayoutAndReInit(); { static const QLatin1String LayerNameEmergencyCall("EmergencyCall"); LayerParameter lp; if (m_operatorMapSettings2achieve.getLayerParameter(LayerNameEmergencyCall, lp)) { if (!lp.visible) { // desired state is off DEBUG_LOG(m_logger) << LOGFUNCTION << " EmergencyCall Timer ..."; // Timer with lambda : // most of the times, 1 sec should be enough: QTimer::singleShot(1000, this, [this] () { // check state now again: const OperatorMapSettings &oms = m_situationMap->operatorMapSettings(); LayerParameter lpCurrent; if (oms.getLayerParameter(LayerNameEmergencyCall, lpCurrent)) { if (lpCurrent.visible) // current is different to desired state { m_situationMap->layerFactory().switchEmergencyCallLayerOff(); DEBUG_LOG(m_logger) << LOGFUNCTION << " EmergencyCall Timer ... Done"; } } }); // : Timer with lambda } } } } void InterfaceImpl::reCreateSituationMapInitAndAddToLayoutAndReInit() { DEBUG_LOG(m_logger) << LOGFUNCTION << " START"; if (m_situationMapInit) { m_situationMapInit->stopDisplay(); m_situationMapInit->clearObjects(); // cleanup/reset MapObjectSelection (will destroy MapObjectPointer for example) if (m_dialogMapObjectSelection) m_dialogMapObjectSelection->reset(); } reCreateSituationMapInitAndAddToLayout(); // reInit some Widgets/Controls: if (m_mapWidgetControl && m_situationMap) m_mapWidgetControl->init(m_situationMap.data(), m_session); if (m_mapLayerControl) m_mapLayerControl->deleteLater(); // until ui can be REbuild... m_mapLayerControl = nullptr; TRACE_LOG(m_logger) << LOGFUNCTION << " END"; } LtsWidgets::LtsDialog *InterfaceImpl::onShowSituationMapDialog(QWidget *parent) { TRACE_LOG(m_logger) << LOGFUNCTION << " START"; m_waitForInitialOperatorMapSettings = new QTimer(this); m_waitForInitialOperatorMapSettings->setSingleShot(true); m_waitForInitialOperatorMapSettings->setInterval(5000); connect(m_waitForInitialOperatorMapSettings.data(), &QTimer::timeout, this, &InterfaceImpl::onInitialOperatorMapSettingsTimeout); m_escOrderAreaPosition.uniqueMapId = INVALID_MAP_ID; m_escOrderStartPosition.uniqueMapId = INVALID_MAP_ID; // MovementTrackManager: m_movementTrackManager = QPointer(new SituationMap::MovementTrackManager(this)); if (!m_ltsDialogSitMapWidget) m_ltsDialogSitMapWidget = new MyMapWidgetDialog(parent, LtsWidgets::ButtonCombination::SeamlessDialog); // create SituationMapInit: reCreateSituationMapInitAndAddToLayout(); TRACE_LOG(m_logger) << LOGFUNCTION << " END"; return m_ltsDialogSitMapWidget; } TopicReplay::Interface *InterfaceImpl::createInterface(TopicEditorBase::TopicType) { return new TopicReplayInterface; } QWidget *InterfaceImpl::reCreateSituationMapInit() { TRACE_LOG(m_logger) << LOGFUNCTION << " START"; // [GUEZE-862] // Maybe the sitMap has to switch between 2D to 3D. // In that case // - the AdapterDds@SituationMapPlugin and it´s // - the FilterManagement::SymbolAppearanceSettingsImpl // will be destroyed and recreated. // During SnapshotDialog::showSnapshotInternal filterData is taken from Snapshotdata, // written to the SymbolAppearanceSettingsImpl, but overwritten by _reCreating_ // SymbolAppearanceSettings and AesDisplayFilter (see m_symbolAppearanceMap @ FilterManagement/Gui/Aes/flt_aes_plugin.h) // To prevent destruction, add a shared_ptr to stack: std::shared_ptr fltParticipantIfc = m_pluginProvider->fltParticipantIfc(); std::shared_ptr fltAesIfc = m_pluginProvider->fltAesIfc(); std::shared_ptr preventDestruction1; std::shared_ptr preventDestruction2; if (m_session->isReplayPartition() && fltParticipantIfc && fltAesIfc) { INFO_LOG(m_logger) << LOGFUNCTION << " FILTER: PREVENT DESTRUCTION "; const int operatorId = LtsSessionData::LtsSessionData::getInstance()->getOperatorId(); const QString &wsId_context = m_session->workspaceId(); // aka context preventDestruction1 = fltParticipantIfc->symbolAppearanceForOperator(operatorId, wsId_context); preventDestruction2 = fltAesIfc->aesFilterForOperator(operatorId, wsId_context); } else { INFO_LOG(m_logger) << LOGFUNCTION << " SKIP FILTER: PREVENT DESTRUCTION "; } // save current ResourceManagerMode savedRMM = ResourceManagerMode::RMM_PlanActivityView; if (m_situationMapInit) savedRMM = m_situationMapInit->resourceManagerMode(); // prepare underlying widget: (containing SitMapCore, Adapter, MapWidgetControl, LayerControl etc.) delete m_situationMapInit; // ToDo: deleteLater??? delete m_terrainProfileHandler; m_uniqueMapIdOfPreviewObject.clear(); // ensure proper conditions bool enableSelection = m_session->app() == LtsAppDescriptor::App::OC || m_session->app() == LtsAppDescriptor::App::SituationTablet || m_session->app() == LtsAppDescriptor::App::ResourceManager || m_session->app() == LtsAppDescriptor::App::Scripts || m_session->app() == LtsAppDescriptor::App::Situation || m_session->app() == LtsAppDescriptor::App::Snapshot || m_session->app() == LtsAppDescriptor::App::SystemMonitor || m_session->app() == LtsAppDescriptor::App::Timeline; m_situationMapInit = new SituationMapInit(this); connect(m_situationMapInit.data(), &SituationMapInit::mapObjectsClicked, this, &InterfaceImpl::onMapObjectsClicked); connect(m_situationMapInit.data(), &SituationMapInit::saveAsImageRequested, this, &InterfaceImpl::onSaveAsImageRequested); if (!m_situationMapInit->initPluginProvider(m_pluginProvider)) { FATAL_LOG(m_logger) << LOGFUNCTION << " initMap failed, return empty dummy widget"; QWidget *noMapWidget = new QWidget(); // maybe add text 'no map' on widget? return noMapWidget; } // // initialize map: if (m_operatorMapSettings2achieve.mode == Mode::Undefined) m_operatorMapSettings2achieve.mode = Mode::Mode_2D; // set to Mode_2D to start within 3D // // m_situationMapInit->setReplay(m_session->isReplayPartition()); move to SituationMapInit::initMap() if (!m_situationMapInit->initMap(enableSelection, m_operatorMapSettings2achieve.mode, m_operatorMapSettings2achieve.viewpoint)) { FATAL_LOG(m_logger) << LOGFUNCTION << " initMap failed, return empty dummy widget"; QWidget *noMapWidget = new QWidget(); // maybe add text 'no map' on widget? return noMapWidget; } // store widgetPtr seperately (to simplify access) m_situationMap = m_situationMapInit->getWidget(); { QString name = QStringLiteral("objectName_app='%1'").arg(LtsSession::LtsSession::appToString(m_session->app())) + QStringLiteral("_exerciseId=%1").arg(m_session->exerciseId()) + QStringLiteral("_sessionName='%1'").arg(m_session->name()) + QStringLiteral("_pid=%1").arg(QCoreApplication::applicationPid()); m_situationMap->setObjectName(name); } m_situationMap->setTrainingsAreaExtent(m_trainingsAreaExtent); m_terrainProfileHandler = new TerrainProfileHandler(menuGroup()); m_terrainProfileHandler->init(m_session, m_situationMap); // trigger pre-loading symbols from Filemanagement : // (symbologyType is now available) if (m_asbGuiIfc) { m_asbGuiIfc->createFlmSymbolProxy(42); AdvancedSymbology::SymbologyType symType = AdvancedSymbology::SymbolDictionary::defaultSymbologyType(); if (m_situationMap) symType = m_situationMap->symbologyType(); m_asbGuiIfc->connectFlmSymbolProxy(42, symType); } // : trigger pre-loading symbols from Filemanagement #ifdef USE_LOCAL_SERVER // LocalServer -> viewshedUrl { SituationMap::LocalServer *localServer = SituationMap::LocalServer::instance(); LocalServiceData lsd; if (localServer->localGeoprocessingServiceData(viewshedSvcName(), lsd)) { // entry found if (lsd.isEmpty()) ERROR_LOG(m_logger) << LOGFUNCTION << " LocalServiceData empty, no viewshedUrl"; m_situationMap->viewshed().setViewshedUrl(lsd.svcUrl().toString()); } else { connect(localServer, &LocalServer::localGeoprocessingServiceStarted, this, [this](const QString & serviceName, const LocalServiceData & localSvcData) { if (serviceName.compare(viewshedSvcName()) == 0) m_situationMap->viewshed().setViewshedUrl(localSvcData.svcUrl().toString()); }); } } #endif // USE_LOCAL_SERVER // some operations has to be performed if: a) Map isReady and b) SymbolDictionary is loaded: // restore oms (and its overlays) if available { QPointer mapNotifier = m_situationMap->createMapNotifier(); if (mapNotifier) { connect(mapNotifier.data(), &MapNotifier::mapReadyAndSymbolDictionaryLoaded, this, [this /*, omsSaved*/]() { INFO_LOG(m_logger) << LOGFUNCTION << " currentTimeMsec: " << m_session->partitionTime(); if (m_operatorMapSettings2achieve.isEmpty()) WARNING_LOG(m_logger) << LOGFUNCTION << " oms empty!?"; else if (!restoreOperatorMapSettingsOverlays(m_operatorMapSettings2achieve)) ERROR_LOG(m_logger) << LOGFUNCTION << " restoreOperatorMapSettings failed"; if (isAutoSetExerciseTimeString()) showExerciseTimeString(true); }); if (m_session->app() == LtsAppDescriptor::App::OC) connect(mapNotifier.data(), &MapNotifier::mapReadyAndSymbolDictionaryLoaded, this, [this]() { INFO_LOG(m_logger) << LOGFUNCTION << " currentTimeMsec: " << m_session->partitionTime(); QTimer::singleShot(1000, this, &InterfaceImpl::restoreOcSituationRange); // we have to wait for the dds-adapter to create the participants }); mapNotifier->run(); } } // if (!omsSaved.isEmpty()) bool resourceMode = m_session->app() == LtsAppDescriptor::App::ResourceManager; LtsUtils::ProjectSettings *ps = LtsUtils::ProjectSettings::getInstance(); bool showAssets = ps->value(QStringLiteral("SituationMap"), QStringLiteral("enableAssetsInResourceMode"), true).toBool(); if (resourceMode && !showAssets) resourceMode = false; // init interfaces if (!m_situationMapInit->initAdapter(m_movementTrackManager, resourceMode)) { ERROR_LOG(m_logger) << LOGFUNCTION << " m_situationMapInit->init failed"; return nullptr; } bool enableFireEventFlashing = (m_session->app() != LtsAppDescriptor::App::Snapshot); if (!m_situationMapInit->enableFireEventFlashing(enableFireEventFlashing)) WARNING_LOG(m_logger) << LOGFUNCTION << " enableFireEventFlashing failed"; if (!m_situationMapInit->setResourceManagerMode(savedRMM)) WARNING_LOG(m_logger) << LOGFUNCTION << " setResourceManagerMode failed"; // Register app per screenId at Opm : if (m_pluginProvider) { m_registerAppHandler.setOpm(m_pluginProvider->opmDtc(), m_pluginProvider->opmFtc()); m_registerAppHandler.registerApp(this, m_session); } else ERROR_LOG(m_logger) << LOGFUNCTION << " no opmDtc/opmFtc, register of active app will not work"; // : Register app per screenId at Opm m_situationMapInit->startDisplay(); // perform asap: QTimer::singleShot(0, this, &InterfaceImpl::enableDisable); TRACE_LOG(m_logger) << LOGFUNCTION << " END"; return m_situationMap.data(); } void InterfaceImpl::doFindChild() { const LtsWidgets::LtsBaseLayoutWidget *baseLayout = m_session->baseLayout(); if (!baseLayout) { ERROR_LOG(m_logger) << LOGFUNCTION << " no baseLayout found"; return; } menueBtnMapWidgets = baseLayout->findChild(QStringLiteral("SituationMap-MapWidget")); // menueBtnLayerControl = baseLayout->findChild(QStringLiteral("LayerControl")); menueBtnParticipantAggregation = baseLayout->findChild(QStringLiteral("SituationMap-ParticipantAggregation")); menueBtnRocket = baseLayout->findChild(QStringLiteral("SituationMap-Rocket")); menueBtnStartMeasurement = baseLayout->findChild(QStringLiteral("SituationMap-MeasureLength")); menueBtnClearMeasurement = baseLayout->findChild(QStringLiteral("SituationMap-clearMeasurement")); menueBtnStartTerrainProfile = baseLayout->findChild(QStringLiteral("SituationMap-TerrainProfile")); menueBtnClearTerrainProfile = baseLayout->findChild(QStringLiteral("SituationMap-clearTerrainProfile")); menueBtnStartViewshed = baseLayout->findChild(QStringLiteral("SituationMap-Viewshed")); menueBtnClearViewshed = baseLayout->findChild(QStringLiteral("SituationMap-clearViewshed")); menueBtnBuildingOwnership = baseLayout->findChild(QStringLiteral("SituationMap-ShowBuildingOwnership")); menueBtnBuildingContamination = baseLayout->findChild(QStringLiteral("SituationMap-ShowBuildingContamination")); menueBtn3dBuildingsVisible = baseLayout->findChild(QStringLiteral("SituationMap-3D_Buildings")); menueBtnConfigureMapUrls = baseLayout->findChild(QStringLiteral("SituationMap-ConfigureMapUrls")); } void InterfaceImpl::enableDisable() { DEBUG_LOG(m_logger) << LOGFUNCTION << " getAppName()= " << LtsSession::LtsSession::appToString(appId()); DEBUG_LOG(m_logger) << LOGFUNCTION << " m_session->partitionType()= " << m_session->partitionType(); if (!m_situationMap) return; DEBUG_LOG(m_logger) << LOGFUNCTION << " m_situationMap->mode()= " << m_situationMap->mode() << " this->isMapReady()= " << this->isMapReady(); doFindChild(); if (menueBtnParticipantAggregation) menueBtnParticipantAggregation->setEnabled(this->isMapReady()); bool visible = m_situationMap->mode() == Mode::Mode_2D; if (menueBtnRocket) menueBtnRocket->setEnabled(this->isMapReady()); if (menueBtnStartMeasurement) { menueBtnStartMeasurement->setEnabled(this->isMapReady()); menueBtnStartMeasurement->setVisible(visible); } if (menueBtnClearMeasurement) { menueBtnClearMeasurement->setEnabled(this->isMapReady()); menueBtnClearMeasurement->setVisible(visible); } if (menueBtnStartTerrainProfile) { menueBtnStartTerrainProfile->setEnabled(this->isMapReady()); menueBtnStartTerrainProfile->setVisible(visible); } if (menueBtnClearTerrainProfile) { menueBtnClearTerrainProfile->setEnabled(this->isMapReady()); menueBtnClearTerrainProfile->setVisible(visible); } // enable = (m_situationMap->mode() == Mode::Mode_2D); // menueBtnShowBuildingViewer->setEnabled(enable); { visible = (m_situationMap->mode() == Mode::Mode_3D) && (LtsAppDescriptor::App::PlanEditor != m_session->app()); if (menueBtnBuildingOwnership) { menueBtnBuildingOwnership->setEnabled(m_situationMap->isReady()); menueBtnBuildingOwnership->setVisible(visible); if (m_situationMapInit) menueBtnBuildingOwnership->setChecked(m_situationMapInit->isBuildingOwnershipVisible()); menueBtn3dBuildingsVisible->setEnabled(m_situationMap->isReady()); menueBtn3dBuildingsVisible->setVisible(visible); if (m_situationMapInit) { bool curVisi = m_situationMapInit->getWidget()->layerFactory().isSceneObjectLayerVisible(); menueBtn3dBuildingsVisible->setChecked(curVisi); } } if (menueBtnBuildingContamination) { menueBtnBuildingContamination->setEnabled(m_situationMap->isReady()); menueBtnBuildingContamination->setVisible(visible); if (m_situationMapInit) menueBtnBuildingContamination->setChecked(m_situationMapInit->isBuildingContaminationVisible()); } } #ifdef USE_LOCAL_SERVER // Viewshed { if (m_situationMap->mode() == Mode::Mode_2D) { // if (menueBtnStartViewshed) // menueBtnStartViewshed->setVisible(false); // if (menueBtnClearViewshed) // menueBtnClearViewshed->setVisible(false); if (menueBtnStartViewshed) { bool viewshedSvcStarted = LocalServer::instance()->isLocalGeoprocessingServiceStarted(viewshedSvcName()); if (m_situationMap->isReady() && viewshedSvcStarted) menueBtnStartViewshed->setEnabled(true); else { menueBtnStartViewshed->setEnabled(false); SituationMap::LocalServer *localServer = SituationMap::LocalServer::instance(); connect(localServer, &LocalServer::localGeoprocessingServiceStarted, this, [this](const QString & serviceName, const LocalServiceData & localSvcData) { Q_UNUSED(localSvcData); if (menueBtnStartViewshed && m_situationMap && (serviceName.compare(viewshedSvcName()) == 0)) menueBtnStartViewshed->setEnabled(m_situationMap->isReady()); }); } } } else if (m_situationMap->mode() == Mode::Mode_3D) { if (menueBtnStartViewshed) { menueBtnStartViewshed->setVisible(true); menueBtnStartViewshed->setEnabled(m_situationMap->isReady()); } if (menueBtnClearViewshed) { menueBtnClearViewshed->setVisible(true); menueBtnClearViewshed->setEnabled(m_situationMap->isReady()); } } } // Viewshed #else if (menueBtnStartViewshed) menueBtnStartViewshed->setEnabled(m_situationMap->isReady()); if (menueBtnClearViewshed) menueBtnClearViewshed->setEnabled(m_situationMap->isReady()); #endif // USE_LOCAL_SERVER // handle isReady == false: if (!isMapReady()) connect(m_situationMap.data(), &Map::mapReadyAndSymbolDictionaryLoaded, this, &InterfaceImpl::enableDisable, Qt::UniqueConnection); } void InterfaceImpl::onInitialOperatorMapSettingsTimeout() { TRACE_LOG(m_logger) << LOGFUNCTION << " START"; m_waitForInitialOperatorMapSettings.clear(); reCreateSituationMapInitAndAddToLayout(); TRACE_LOG(m_logger) << LOGFUNCTION << " END"; } void InterfaceImpl::reCreateSituationMapInitAndAddToLayout() // TODO: error handling? { TRACE_LOG(m_logger) << LOGFUNCTION << " START"; if (!m_ltsDialogSitMapWidget) { ERROR_LOG(m_logger) << LOGFUNCTION << " no m_ltsDialog"; return; } // case of Situation or OC -> wait for OperatorMapSettings (and implicit a valid workspaceId) if ((m_session->app() != LtsAppDescriptor::App::Situation) && (m_session->app() != LtsAppDescriptor::App::OC) && (m_session->app() != LtsAppDescriptor::App::SituationTablet)) { m_waitForInitialOperatorMapSettings.clear(); // -> direct, no wait ... } // in replay context, waiting on 'old' oms doesn´t makes sense. Valid data can´t be expected. if (m_session->partitionType() == IDL::PartitionType::Replay) // Btn 'Situation Playback || App 'Situation Playback' -> SRM::InterfaceImpl::startReplayAppInternal() m_waitForInitialOperatorMapSettings.clear(); // -> direct, no wait ... // wait for initialOperatorMapSettings? (should be delivered by OPM) if (m_waitForInitialOperatorMapSettings) { m_waitForInitialOperatorMapSettings->start(); return; } reCreateSituationMapInit(); if (!m_situationMap) return; //#define USE_QDIALOG #ifdef USE_QDIALOG QHBoxLayout *layout = new QHBoxLayout(); layout->addWidget(m_situationMap); QDialog *dlg = new QDialog(); dlg->setLayout(layout); dlg->show(); #else // save vp BEFORE addWidget: const Viewpoint2D &vp = m_situationMap->viewpoint2D(); // wrap into LtsDialog: m_ltsDialogSitMapWidget->addWidget(m_situationMap); m_situationMap->show(); // GUEZE-1597: 3D Karte - Schwarzer Bildschirm // Skript: // ---------------------------------- // | Playback (Daten) | // ---------------------------------^ca. 60Sec // ---------------------------------- // | Lage (Darstellung | // ---------------------------------- // ---------- ---------- // | Flt2D | | Flt3D | // ---------- ---------- // Fehlerhaftes Szenario (5-50% Eintrittswahrscheinlichkeit) // Starten, in Flt3D pausieren, Kartenausschnitt der Lage markant verschieben // Vor oder während Flt2D restarten (ohne Stop) // (3DMapWidget wird mit verschobenen Kartenausschnitt im MapCache zwischengespeichert) // Wenn die Steuerung Flt3D erreicht, wird auf 3D 'umgeschaltet' (aus dem Cache geholt) // Und dabei wird der Kartenausschnitt zwar wiederhergestellt, es ist aber NICHT sichtbar - grr... // Als Fix: forceUpdate() -> size@Widget um 1px vergrößern und dann verkleinern, // nachdem das ESRIWidget per addWidget in seine VaterWidget 'm_ltsDialogSitMapWidget' eingefügt wurde: // forceUpdate after 'addWidget' forceUpdate(); // seems to be necessary for 3D, but it´s easier to tdo in any cases :-) connect(m_ltsDialogSitMapWidget.data(), &MyMapWidgetDialog::aboutToCloseSignal, m_situationMapInit.data(), &SituationMapInit::myMapWidgetDialogIsAboutToBeClosed); // thatLayout->addWidget(m_situationMap); // REGG-4944 - Beim Wechsel von 3D auf 2D-Lagedarstellung wird der // Kartenausschnitt und Kartenmittelpunkt nicht beibehalten. // 2D (mapView) and 3D differ: // 2D (mapView) : resize the widget -> scale does not change // 3D (sceneView) : resize the widget -> scale changes (bug?) // so, for 3D we have to set the viewpoint again: if ((m_situationMap->mode() == Mode::Mode_3D) && (m_operatorMapSettings2achieve.camera.isNull())) QTimer::singleShot(1000, this, [this, vp]() { Viewpoint2D vpFinal = m_operatorMapSettings2achieve.viewpoint.isNull() ? vp : m_operatorMapSettings2achieve.viewpoint; m_situationMap->setViewpoint2D(vpFinal); }); #endif TRACE_LOG(m_logger) << LOGFUNCTION << " END"; } QPointer InterfaceImpl::map() const { return m_situationMap; } void InterfaceImpl::setMapUpdatesEnabled(bool bEnabled) { INFO_LOG(m_logger) << LOGFUNCTION << " XXX setMapUpdatesEnabled, START, bEnabled= " << bEnabled; // GUEZE-791 - RPL Nr 791: Arbeitsspeicherleck // Scenario: // move a 3D scene in cache using script (show Snap3D, show snap2D (3dScene is at cache and UpdatesDISABLED)) // open EssentialsView/Hilfsansicht and switch to 3D -> map/scene is black / UpdatesDISABLED -> :-( // Solution: use m_ltsDialogSitMapWidget instead of m_situationMap if (m_ltsDialogSitMapWidget) { INFO_LOG(m_logger) << LOGFUNCTION << " XXX setMapUpdatesEnabled, switch from " << m_ltsDialogSitMapWidget->updatesEnabled() << " to " << bEnabled; m_ltsDialogSitMapWidget->setUpdatesEnabled(bEnabled); } INFO_LOG(m_logger) << LOGFUNCTION << " XXX setMapUpdatesEnabled, END, bEnabled= " << bEnabled; } bool InterfaceImpl::isMapReady() const { TRACE_LOG(m_logger) << LOGFUNCTION << " START, m_situationMap" << m_situationMap; if (!m_situationMap) return false; const bool ret = m_situationMap->isReady() && m_situationMap->isSymbolDictionaryLoaded(); TRACE_LOG(m_logger) << LOGFUNCTION << " END, " << " m_situationMap->isReady()=" << m_situationMap->isReady() << " m_situationMap->isSymbolDictionaryLoaded()=" << m_situationMap->isSymbolDictionaryLoaded() << ", ret = " << ret; return ret; } bool InterfaceImpl::setMapReadyCallback(QObject *context, const std::function &mapReadyCallback) { if (m_situationMap.isNull()) { ERROR_LOG(m_logger) << LOGFUNCTION << " no situationMap"; return false; } QPointer mapNotifier = m_situationMap->createMapNotifier(); if (mapNotifier) { connect(mapNotifier.data(), &SituationMap::MapNotifier::mapReadyAndSymbolDictionaryLoaded, context, mapReadyCallback); mapNotifier->run(); } return true; } MapMode InterfaceImpl::mapMode() const { if (!m_situationMap) return MapMode::Undefined; return static_cast(m_situationMap->mode()); // static_assert make sure that they are identical } bool InterfaceImpl::reInitToSystemDefault() { // do NOT consider operator-specific presets (OperatorMapSettings) m_waitForInitialOperatorMapSettings.clear(); m_operatorMapSettings2achieve.mode = Mode::Undefined; reCreateSituationMapInitAndAddToLayoutAndReInit(); return true; } bool InterfaceImpl::forceUpdate() { if (!m_situationMap) return false; const QSize &sizeOrg = m_situationMap.data()->size(); QSize tempSize = sizeOrg; tempSize.rheight() += 1; // resize for a moment to force update (context: Screen of ScriptEditor) m_situationMap.data()->resize(tempSize); m_situationMap.data()->update(); m_situationMap.data()->resize(sizeOrg); m_situationMap.data()->update(); return true; } ResourceManagerMode InterfaceImpl::resourceManagerMode() const { if (!(m_situationMapInit)) { LOG_ERROR_SIT; return ResourceManagerMode::Undefined; } return m_situationMapInit->resourceManagerMode(); } bool InterfaceImpl::setResourceManagerMode(ResourceManagerMode rmm) { if (!(m_situationMapInit)) { LOG_ERROR_SIT; return false; } return m_situationMapInit->setResourceManagerMode(rmm); } bool InterfaceImpl::setResourceManagerModeChangedCallback(QObject *context, const std::function &cb) { if (m_situationMap.isNull()) { ERROR_LOG(m_logger) << LOGFUNCTION << " no situationMap"; return false; } connect(m_situationMapInit.data(), &SituationMap::SituationMapInit::resourceManagerModeChanged, context, cb); return true; } void InterfaceImpl::executePayload(LtsWidgets::LtsBackgroundWidget *) { // preLoad dictionary to reduce startup time: //AdvancedSymbology::SymbolDictionary &dict = // AdvancedSymbology::SymbolDictionary::dictionary(AdvancedSymbology::SymbologyType::MIL2525D); //dict.load(); // dict.load() is async and can be called multiple times #ifdef USE_LOCAL_SERVER // LocalServer static bool startLocalServer = true; if (startLocalServer) // just once { startLocalServer = false; // We have to make sure that the the licence string is applied first: if (!Map::applyLicense()) { FATAL_LOG(m_logger) << LOGFUNCTION << " Map::applyLicense failed"; FATAL_LOG(m_logger) << LOGFUNCTION << " Map::applyLicense failed"; FATAL_LOG(m_logger) << LOGFUNCTION << " Map::applyLicense failed"; FATAL_LOG(m_logger) << LOGFUNCTION << " Map::applyLicense failed"; } SituationMap::LocalServer *localServer = SituationMap::LocalServer::instance(); // The final LocalServer-Url may look like: // http://127.0.0.1:50000/PkbQjC/arcgis/rest // The final serviceUrl may look like: // http://127.0.0.1:50000/PkbQjC/arcgis/rest/services/LegatusBremen201803151510.gpk/GPServer QString packagePath = QLatin1String("/usr/share/arcgis/resources/gpk/LegatusBremen201803151510.gpk"); QString serviceSubLocation = QLatin1String("Viewshed2Feature"); // packagePath = QLatin1String("/usr/share/arcgis/resources/gpk/LegatusViewshed.gpk"); // serviceSubLocation = QLatin1String("Viewshed"); // packagePath = QLatin1String("/shd/CTC/TOOLS/arcgis/EsriJebuLegatusViewshed2PolySync.gpk"); // serviceSubLocation = QLatin1String("Viewshed"); localServer->setLocalGeoprocessingService(viewshedSvcName(), packagePath, serviceSubLocation, true); localServer->startLocalGeoprocessingService(viewshedSvcName()); // starts LocalServer (and pending GPSsvc, which are none yet.) localServer->start(); } #endif // USE_LOCAL_SERVER // ToDo: check this: QTimer::singleShot(0, m_session, &LtsSession::LtsSession::slotExecuteNextPayload); } LtsWidgets::LtsDialog *InterfaceImpl::onShowMapWidgetControlDialog(QWidget *parent) { TRACE_LOG(m_logger) << LOGFUNCTION << " START"; if (!m_mapWidgetControl) { m_mapWidgetControl = new MapWidgetControl(menuGroup(), parent); connect(m_mapWidgetControl.data(), &MapWidgetControl::changeModeRequested, this, &InterfaceImpl::onChangeModeRequested, Qt::QueuedConnection); } m_mapWidgetControl->enableBtn2D3D(LtsAppDescriptor::App::PlanEditor != m_session->app()); if (m_situationMap) m_mapWidgetControl->init(m_situationMap.data(), m_session); m_mapWidgetControl->show(); TRACE_LOG(m_logger) << LOGFUNCTION << " END"; return m_mapWidgetControl; } LtsWidgets::LtsDialog *InterfaceImpl::onShowLayerControlDialog(QWidget *parent) { TRACE_LOG(m_logger) << LOGFUNCTION << " START"; if (!m_mapLayerControl) m_mapLayerControl = new LayerControlDialog(parent); if (m_situationMap) m_mapLayerControl->init(m_session, m_situationMap.data()); TRACE_LOG(m_logger) << LOGFUNCTION << " END"; return m_mapLayerControl; } LtsWidgets::LtsDialog *InterfaceImpl::onShowConfigureUrlsDialog(QWidget *parent) { TRACE_LOG(m_logger) << LOGFUNCTION << " START"; if (!m_pluginProvider) return nullptr; if (!m_configureMapUrls) m_configureMapUrls = new ConfigureMapUrls(parent); if (m_configureMapUrls) m_configureMapUrls->init(m_pluginProvider); TRACE_LOG(m_logger) << LOGFUNCTION << " END"; return m_configureMapUrls; } // // ForeignGuiInterface // void InterfaceImpl::enableMovementTrack(int participantId, bool enable) { CHECK_SMI; m_situationMapInit->enableMovementTrack(participantId, enable); } bool InterfaceImpl::isMovementTrackEnabled(int participantId) { CHECK_SMI_RETVAL; return m_situationMapInit->isMovementTrackEnabled(participantId); } bool InterfaceImpl::setMovementTrackCallback(QObject *context, const std::function &activeSimIds)> &movementTrackCallback) { if (m_situationMapInit.isNull()) { ERROR_LOG(m_logger) << LOGFUNCTION << " no m_situationMapInit"; return false; } QPointer movementTrackManager = m_situationMapInit->movementTrackManager(); if (!movementTrackManager) { ERROR_LOG(m_logger) << LOGFUNCTION << " no movementTrackManager"; return false; } connect(movementTrackManager.data(), &SituationMap::MovementTrackManager::activeSimIdsChanged, context, movementTrackCallback); return true; } void InterfaceImpl::enableGearRanges(int participantId, bool enable) { CHECK_SMI; m_situationMapInit->enableGearRanges(participantId, enable); } bool InterfaceImpl::isGearRangesEnabled(int participantId) { CHECK_SMI_RETVAL; return m_situationMapInit->isGearRangesEnabled(participantId); } bool InterfaceImpl::enableFireEventFlashing(bool enable) { CHECK_SMI_RETVAL; return m_situationMapInit->enableFireEventFlashing(enable); } bool InterfaceImpl::isFireEventFlashingEnabled() const { CHECK_SMI_RETVAL; return m_situationMapInit->isFireEventFlashingEnabled(); } QPointF InterfaceImpl::centerPoint() const { CHECK_SMI_RETVAL; return m_situationMapInit->centerPoint(); } void InterfaceImpl::setCenterPoint(const QPointF ¢er, double scale, float durationSeconds) { CHECK_SMI; m_situationMapInit->setCenterPoint(center, scale, durationSeconds); } void InterfaceImpl::centerMapToParticipant(int participantId) { CHECK_SMI; m_situationMapInit->centerMapToParticipant(participantId); } void InterfaceImpl::centerMapToAesObject(int entityId) { CHECK_SMI; m_situationMapInit->centerMapToAesObject(entityId); } void InterfaceImpl::centerMapToBuildingObject(int entityId) { CHECK_SMI; m_situationMapInit->centerMapToBuildingObject(entityId); } void InterfaceImpl::centerMapToGuezIedObject(int entityId) { CHECK_SMI; m_situationMapInit->centerMapToGuezIedObject(entityId); } void InterfaceImpl::centerMapToChargeEffectObject(int entityId) { CHECK_SMI; m_situationMapInit->centerMapToChargeEffectObject(entityId); } void InterfaceImpl::centerMapToMapObject(MapObjectType mot, int entityId) { CHECK_SMI; m_situationMapInit->centerMapToMapObject(mot, entityId); } void InterfaceImpl::zoomMapTo(const QVector > &entities, int paddingInDIPS) { CHECK_SMI; m_situationMapInit->zoomMapTo(entities, paddingInDIPS); } bool InterfaceImpl::objectIndicatorToParticipant(int participantId, bool setSelected, int lifetimeMsec) { CHECK_SMI_RETVAL; return m_situationMapInit->objectIndicatorToParticipant(participantId, setSelected, lifetimeMsec); } bool InterfaceImpl::objectIndicatorToAesObject(int entityId) { CHECK_SMI_RETVAL; return m_situationMapInit->objectIndicatorToAesObject(entityId); } bool InterfaceImpl::objectIndicatorToBuildingObject(int entityId) { CHECK_SMI_RETVAL; return m_situationMapInit->objectIndicatorToBuildingObject(entityId); } bool InterfaceImpl::objectIndicatorToGuezIedObject(int entityId) { CHECK_SMI_RETVAL; return m_situationMapInit->objectIndicatorToGuezIedObject(entityId); } bool InterfaceImpl::objectIndicatorToMapObject(MapObjectType mot, int entityId, bool setSelected, int lifetimeMsec) { CHECK_SMI_RETVAL; return m_situationMapInit->objectIndicatorToMapObject(mot, entityId, setSelected, lifetimeMsec); } bool InterfaceImpl::objectIndicatorToPoint(const QPointF &targetGeo, int lifetimeMsec) { CHECK_SMI_RETVAL; return m_situationMapInit->objectIndicatorToPoint(targetGeo, lifetimeMsec); } bool InterfaceImpl::removeObjectIndicator() { CHECK_SMI_RETVAL; return m_situationMapInit->removeObjectIndicator(); } bool InterfaceImpl::openMapObjectSelection(MapObjectType mot, const QVector &entityIds) { CHECK_SMI_RETVAL; const QVector &uniqueMapIdVec = m_situationMapInit->simIds2UniqueMapIds(mot, entityIds); if (uniqueMapIdVec.isEmpty()) return false; onMapObjectsClickedByIds(uniqueMapIdVec); return true; } bool InterfaceImpl::openMapObjectSelection(const QVector &mapObjectTypeEntityIdPairs) { CHECK_SMI_RETVAL; QVector uniqueMapIdVec; const bool resourceMode = m_session->app() == LtsAppDescriptor::App::ResourceManager; for (const MapObjectTypeEntityId &mapObjectTypeEntityId : mapObjectTypeEntityIdPairs) { // in App::ResourceManager: MSEBridgeToMap is not instanciated // 'instead' the bridges are displayed by Building2SituationMap // so handle bridges as buildings: if (resourceMode && (mapObjectTypeEntityId.mot == MapObjectType::MOT_Bridge) ) uniqueMapIdVec += m_situationMapInit->simIds2UniqueMapIds(MapObjectType::MOT_Building, mapObjectTypeEntityId.entityIds); else uniqueMapIdVec += m_situationMapInit->simIds2UniqueMapIds(mapObjectTypeEntityId.mot, mapObjectTypeEntityId.entityIds); } // for if (uniqueMapIdVec.isEmpty()) return false; onMapObjectsClickedByIds(uniqueMapIdVec); return true; } bool InterfaceImpl::setMapObjectSelected(MapObjectType mot, const QVector &entityIds, bool selection) { CHECK_SMI_RETVAL; return m_situationMapInit->setMapObjectSelected(mot, entityIds, selection); } bool InterfaceImpl::clearMapObjectSelection(MapObjectType mot) { CHECK_SMI_RETVAL; return m_situationMapInit->clearMapObjectSelection(mot); } bool InterfaceImpl::getCoordinate(QObject *objectToInform, const char *replySlot, const char *errorSlot) { if (!checkSlots(objectToInform, SIGNAL(coordinate(QPointF)), replySlot, errorSlot)) return false; switch (this->mapMode()) { case SituationMap::MapMode::MapMode_2D: { SituationMap::RB::RubberbandPointFeature *rubberband = nullptr; rubberband = createRubberband(objectToInform); if (!rubberband) return false; QObject::connect(rubberband, &SituationMap::RB::Rubberband::apply, this, [this, rubberband]() { const QVector data = rubberband->coordinateVector(); m_replySlot.invoke(m_objToInform, Qt::QueuedConnection, Q_ARG(QPointF, data.at(0))); }); if(m_errorSlot.isValid()) QObject::connect(rubberband, &SituationMap::RB::Rubberband::abort, this, [this]() { m_errorSlot.invoke(m_objToInform, Qt::QueuedConnection, Q_ARG(QString, QLatin1String("rubberband Abborted"))); }); } break; case SituationMap::MapMode::MapMode_3D: { cancelActiveRubberbands(); RB::RubberbandPointFeature3D *rb = m_situationMap->rubberbandFactory().create3D(objectToInform); if (!rb || !rb->rubberbandIsAlive()) { // analog zu: void InterfaceImpl::onError(SituationMap::RB::Rubberband *rb, const QString &errMsg) { if (rb) rb->deleteMySelf(); if (m_errorSlot.isValid()) m_replySlot.invoke(m_objToInform, Qt::QueuedConnection, Q_ARG(QString, QStringLiteral("Creating rubberband failed"))); } return false; } rb->setAutoDelete(true); QObject::connect(rb, &SituationMap::RB::Rubberband::apply, this, [this, rb]() { const QVector data = rb->coordinateVector(); m_replySlot.invoke(m_objToInform, Qt::QueuedConnection, Q_ARG(QPointF, data.at(0))); }); } break; case SituationMap::MapMode::Undefined: ERROR_LOG(m_logger) << LOGFUNCTION << " ModeMode == Undefined "; return false; break; } // switch return true; } bool InterfaceImpl::getCorridor(QObject *objectToInform, const char *replySlot, const char *errorSlot, double widthMin, double widthMax, double maxSegmentLength, int maxSegmentCount, bool centerLine, const QVector &points, double width ) { // verify mapReady if (!m_situationMap || !m_situationMap->isReady()) { ERROR_LOG(m_logger) << LOGFUNCTION << " Failure - map is not ready yet!!!"; return false; } // verify Mode: if (m_situationMap && m_situationMap->mode() == Mode::Mode_3D) { ERROR_LOG(m_logger) << LOGFUNCTION << " requested Rubberband is not allowd in this mode."; return false; } if (!checkSlots(objectToInform, SIGNAL(corridorData(double,QVector,QPolygonF)), replySlot, errorSlot)) return false; SituationMap::RB::RubberbandCorridor *rubberband = createRubberband(objectToInform); if (!rubberband) return false; if (centerLine) //default ist Border rubberband->setInputCenterline(); rubberband->minimumCorridorWidth(widthMin); rubberband->maximumCorridorWidth(widthMax); rubberband->maximumSegmentLength(maxSegmentLength); rubberband->maximumPointCount(maxSegmentCount + 1); rubberband->setCoordinateVectorWidth(points, width); adjustMapAccordingRubberband(rubberband->coordinateVector(RB::CoordinateSystem::Geo)); QObject::connect(rubberband, &SituationMap::RB::Rubberband::apply, this, [this, rubberband]() { QPolygonF bufferPolygon; if (!rubberband->bufferPolygon(bufferPolygon)) ERROR_LOG(m_logger) << LOGFUNCTION << " rubberband->bufferPolygon() failed"; m_replySlot.invoke(m_objToInform, Qt::DirectConnection, Q_ARG(double, rubberband->corridorWidth()), Q_ARG(QVector, rubberband->coordinateVector()), Q_ARG(QPolygonF, bufferPolygon) ); }); if(m_errorSlot.isValid()) QObject::connect(rubberband, &SituationMap::RB::Rubberband::abort, this, [this]() { m_errorSlot.invoke(m_objToInform, Qt::QueuedConnection, Q_ARG(QString, QLatin1String("rubberband Abborted"))); }); return true; } QVector InterfaceImpl::getParallelTranslation(const QVector &line, double distance, bool &angleFault) { angleFault = false; // verify mapReady if (!m_situationMap || !m_situationMap->isReady()) { ERROR_LOG(m_logger) << LOGFUNCTION << " Failure - map is not ready yet!!!"; return QVector(); } if (line.size() < 2) { ERROR_LOG(m_logger) << LOGFUNCTION << " Failure - line has less than 2 coordinates!!!"; return QVector(); } SituationMap::CoordTranslationFunctor *mapCtFunctor = m_situationMap->coordTranslationFunctor(); if (nullptr == mapCtFunctor) { ERROR_LOG(m_logger) << LOGFUNCTION << " Failure - coordinate translation to map coordinates is not defined!!!"; return QVector(); } const QVector ¶llelLine = SituationMap::MathUtils::GeometryEngine::parallelTranslation(mapCtFunctor, line, distance/*, angleFault*/); if (parallelLine.isEmpty()) { ERROR_LOG(m_logger) << LOGFUNCTION << " Failure - calculation of parallel line failed! May be invalid input line!"; return QVector(); } return parallelLine; } // QVector InterfaceImpl::getParallelTranslation(const QVector &line, double width, bool &angleFault) bool InterfaceImpl::getCircle(QObject *objectToInform, const char *replySlot, const char *errorSlot, double radiusMin, double radiusMax, const QPointF &pos, double initialRadius) { TRACE_LOG(m_logger) << LOGFUNCTION << " START"; // verify mapReady if (!m_situationMap || !m_situationMap->isReady()) { ERROR_LOG(m_logger) << LOGFUNCTION << " Failure - map is not ready yet!!!"; return false; } // verify Mode: if (m_situationMap && m_situationMap->mode() == Mode::Mode_3D) { ERROR_LOG(m_logger) << LOGFUNCTION << " requested Rubberband is not allowd in this mode."; return false; } if (!checkSlots(objectToInform, SIGNAL(circleData(QPointF,double)), replySlot, errorSlot)) return false; SituationMap::RB::RubberbandEllipse *rubberband = createRubberband(objectToInform); if (!rubberband) return false; if (!pos.isNull()) { rubberband->buildFromRectangleParamter(pos, initialRadius * 2, initialRadius * 2, QPointF(1, 0)); adjustMapAccordingRubberband(rubberband->coordinateVector(RB::CoordinateSystem::Geo)); } rubberband->constrainQuadratic(true); rubberband->constrainOrthogonal(true); rubberband->minWidth(radiusMin * 2); // Should be 2*radiusMin rubberband->maxWidth(radiusMax * 2); // Should be 2*radiusMax QObject::connect(rubberband, &SituationMap::RB::Rubberband::apply, this, [this, rubberband]() { const QVector data = rubberband->rectangleVerticies(); const LtsCoordTrans::UtmCoordinate p0(LtsCoordTrans::UtmCoordinate::fromGeographic(data.at(0))); const LtsCoordTrans::UtmCoordinate p1(LtsCoordTrans::UtmCoordinate::fromGeographic(data.at(2), p0.zone)); const double radius = fabs((p0.x - p1.x) / 2); m_replySlot.invoke(m_objToInform, Qt::QueuedConnection, Q_ARG(QPointF, rubberband->centerPoint()), Q_ARG(double, radius)); }); if(m_errorSlot.isValid()) QObject::connect(rubberband, &SituationMap::RB::Rubberband::abort, this, [this]() { m_errorSlot.invoke(m_objToInform, Qt::QueuedConnection, Q_ARG(QString, QLatin1String("rubberband Abborted"))); }); return true; } void inline getSectorStartEnd(double angle, double rotation, double &aStartRad, double &aEndRad) { double rotationMath = SituationMap::MathUtils::getAngleDegree2Math(rotation); // angle sectorStart { double val = rotationMath - angle / 2.; aStartRad = val > 0 ? val : val + 360; // return the positive angle of the value aStartRad = (aStartRad > 360. ? std::fmod(aStartRad, 360) : aStartRad) * LtsCoordTrans::deg2rad(); // convert to rad } // angle sectorEnd { aEndRad = rotationMath + angle / 2.; aEndRad = (aEndRad > 360. ? std::fmod(aEndRad, 360) : aEndRad) * LtsCoordTrans::deg2rad(); } } bool InterfaceImpl::getCircleSectorFixRadius(QObject *objectToInform, const char *replySlot, const char *errorSlot, double radius, const QPointF ¢er, double openingAngle, double rotationDegNorth) { TRACE_LOG(m_logger) << LOGFUNCTION << " START"; // verify mapReady if (!m_situationMap || !m_situationMap->isReady()) { ERROR_LOG(m_logger) << LOGFUNCTION << " Failure - map is not ready yet!!!"; return false; } // verify Mode: if (m_situationMap && m_situationMap->mode() == Mode::Mode_3D) { ERROR_LOG(m_logger) << LOGFUNCTION << " requested Rubberband is not allowd in this mode."; return false; } if (!checkSlots(objectToInform, SIGNAL(circleDataXY(QPointF, double, double, double)), replySlot, errorSlot)) return false; SituationMap::RB::RubberbandEllipse *rubberband = createRubberband(objectToInform); if (!rubberband) return false; if (!center.isNull()) { rubberband->buildFromRectangleParamter(center, radius * 2, radius * 2, QPointF(1, 0)); adjustMapAccordingRubberband(rubberband->coordinateVector(RB::CoordinateSystem::Geo)); } rubberband->constrainQuadratic(true); //rubberband->constrainOrthogonal(true); rubberband->setSectorAngleFixed(true); rubberband->enableSector(true); rubberband->minWidth(radius * 2); rubberband->maxWidth(radius * 2); rubberband->minHeight(radius * 2); rubberband->maxHeight(radius * 2); double aStartRad=0, aEndRad=0; getSectorStartEnd(openingAngle, rotationDegNorth, aStartRad, aEndRad); rubberband->setSectorStart(std::sin(aStartRad), std::cos(aStartRad)); rubberband->setSectorEnd(std::sin(aEndRad), std::cos(aEndRad)); QObject::connect(rubberband, &SituationMap::RB::Rubberband::apply, this, [this, rubberband]() { const QVector data = rubberband->rectangleVerticies(); const LtsCoordTrans::UtmCoordinate p0(LtsCoordTrans::UtmCoordinate::fromGeographic(data.at(0))); const LtsCoordTrans::UtmCoordinate p1(LtsCoordTrans::UtmCoordinate::fromGeographic(data.at(2), p0.zone)); const double radius = fabs((p0.x - p1.x) / 2); double rotationDeg = 0; double centralAngleDeg = 90.; getCircleSectorRotationAndAngles(rubberband->sectorStart(),rubberband->sectorEnd(), rotationDeg, centralAngleDeg); m_replySlot.invoke(m_objToInform, Qt::QueuedConnection, Q_ARG(QPointF, rubberband->centerPoint()), Q_ARG(double, radius), Q_ARG(double, rotationDeg), Q_ARG(double, centralAngleDeg)); }); if(m_errorSlot.isValid()) QObject::connect(rubberband, &SituationMap::RB::Rubberband::abort, this, [this]() { m_errorSlot.invoke(m_objToInform, Qt::QueuedConnection, Q_ARG(QString, QLatin1String("rubberband Abborted"))); }); return true; } bool InterfaceImpl::getCircleSector(QObject *objectToInform, const char *replySlot, const char *errorSlot, double radiusInitial, double radiusMin, double radiusMax, const QPointF &pos, double openingAngle, double rotationDegNorth) { TRACE_LOG(m_logger) << LOGFUNCTION << " START"; // verify mapReady if (!m_situationMap || !m_situationMap->isReady()) { ERROR_LOG(m_logger) << LOGFUNCTION << " Failure - map is not ready yet!!!"; return false; } // verify Mode: if (m_situationMap && m_situationMap->mode() == Mode::Mode_3D) { ERROR_LOG(m_logger) << LOGFUNCTION << " requested Rubberband is not allowd in this mode."; return false; } if (!checkSlots(objectToInform, SIGNAL(circleDataXY(QPointF, double, double, double)), replySlot, errorSlot)) return false; SituationMap::RB::RubberbandMultiEllipseFeature *rubberband = createRubberband(objectToInform); if (!rubberband) return false; rubberband->constrainQuadratic(true); rubberband->setSectorAngleFixed(true); rubberband->enableSector(true); double aStartRad=0, aEndRad=0; getSectorStartEnd(openingAngle, rotationDegNorth, aStartRad, aEndRad); rubberband->setSectorStart(std::sin(aStartRad), std::cos(aStartRad)); rubberband->setSectorEnd(std::sin(aEndRad), std::cos(aEndRad)); rubberband->setSectorAngleFixed(true); if (pos.isNull()) { rubberband->prepareFixedNumberOfRadiiWithConstraints( {{radiusInitial, radiusMin, radiusMax}} );// radius, minRadius, maxRadius } else { QVector radii = { {radiusInitial, radiusInitial} }; rubberband->setCenterAndRadii(pos, RB::CoordinateSystem::Geo, radii); adjustMapAccordingRubberband(rubberband->coordinateVector(RB::CoordinateSystem::Geo)); } QObject::connect(rubberband, &SituationMap::RB::Rubberband::apply, this, [this, rubberband]() { // qCritical() << " FIRST1 centerCoord " << rubberband->centerCoordinate(RB::CoordinateSystem::Map) << ", radii = " << rubberband->radii(); // qCritical() << " FIRST1 Sector sectorStart " << rubberband->sectorStart(); // qCritical() << " FIRST1 Sector sectorEnd " << rubberband->sectorEnd(); // qCritical() << " FIRST1 Sector sectorStartDegMath " << rubberband->sectorStartDegMath(); // qCritical() << " FIRST1 Sector sectorEndDegMath " << rubberband->sectorEndDegMath(); double rotationDeg = 0, centralAngleDeg = 90; getCircleSectorRotationAndAngles(rubberband->sectorStart(),rubberband->sectorEnd(), rotationDeg, centralAngleDeg); m_replySlot.invoke(m_objToInform, Qt::QueuedConnection, Q_ARG(QPointF, rubberband->centerCoordinate(RB::CoordinateSystem::Geo)), Q_ARG(double, rubberband->getBiggestRadius().x()), // constrainQuadratic ->> x==y Q_ARG(double, rotationDeg), Q_ARG(double, centralAngleDeg)); }); if(m_errorSlot.isValid()) QObject::connect(rubberband, &SituationMap::RB::Rubberband::abort, this, [this]() { m_errorSlot.invoke(m_objToInform, Qt::QueuedConnection, Q_ARG(QString, QLatin1String("rubberband Abborted"))); }); return true; } bool InterfaceImpl::getTwoCircleSector(QObject *objectToInform, const char *replySlot, const char *errorSlot, double radius1Initial, double radius1Min, double radius1Max, double radius2Initial, double radius2Min, double radius2Max, const QPointF &pos, double openingAngle, double rotationDegNorth) { TRACE_LOG(m_logger) << LOGFUNCTION << " START"; // verify mapReady if (!m_situationMap || !m_situationMap->isReady()) { ERROR_LOG(m_logger) << LOGFUNCTION << " Failure - map is not ready yet!!!"; return false; } // verify Mode: if (m_situationMap && m_situationMap->mode() == Mode::Mode_3D) { ERROR_LOG(m_logger) << LOGFUNCTION << " requested Rubberband is not allowd in this mode."; return false; } if (!checkSlots(objectToInform, SIGNAL(circleDataXY2(QPointF, double, double, double, double)), replySlot, errorSlot)) return false; SituationMap::RB::RubberbandMultiEllipseFeature *rubberband = createRubberband(objectToInform); if (!rubberband) return false; rubberband->constrainQuadratic(true); rubberband->setSectorAngleFixed(true); rubberband->enableSector(true); double aStartRad=0, aEndRad=0; getSectorStartEnd(openingAngle, rotationDegNorth, aStartRad, aEndRad); rubberband->setSectorStart(std::sin(aStartRad), std::cos(aStartRad)); rubberband->setSectorEnd(std::sin(aEndRad), std::cos(aEndRad)); rubberband->setSectorAngleFixed(true); if (pos.isNull()) { using RWC = RB::RubberbandMultiEllipseFeature::RadiusWithContraints; QVector radii = { {radius1Initial, radius1Min, radius1Max}, // radius, minRadius, maxRadius {radius2Initial, radius2Min, radius2Max} } ; rubberband->prepareFixedNumberOfRadiiWithConstraints( radii ); } else { QVector radii = { {radius1Initial, radius1Initial}, {radius2Initial, radius2Initial} }; rubberband->setCenterAndRadii(pos, RB::CoordinateSystem::Geo, radii); adjustMapAccordingRubberband(rubberband->coordinateVector(RB::CoordinateSystem::Geo)); } QObject::connect(rubberband, &SituationMap::RB::Rubberband::apply, this, [this, rubberband]() { const QVector &radii = rubberband->radii(); // qCritical() << " FIRST2 centerCoord " << rubberband->centerCoordinate(RB::CoordinateSystem::Map) << ", radii = " << radii; // qCritical() << " FIRST2 Sector sectorStart " << rubberband->sectorStart(); // qCritical() << " FIRST2 Sector sectorEnd " << rubberband->sectorEnd(); // qCritical() << " FIRST2 Sector sectorStartDegMath " << rubberband->sectorStartDegMath(); // qCritical() << " FIRST2 Sector sectorEndDegMath " << rubberband->sectorEndDegMath(); double rotationDeg = 0, centralAngleDeg = 90; getCircleSectorRotationAndAngles(rubberband->sectorStart(),rubberband->sectorEnd(), rotationDeg, centralAngleDeg); double radius1 = -1; double radius2 = -1; if (radii.size() > 0) radius1 = radii[0].x(); // constrainQuadratic ->> x==y if (radii.size() > 1) radius2 = radii[1].x(); // constrainQuadratic ->> x==y m_replySlot.invoke(m_objToInform, Qt::QueuedConnection, Q_ARG(QPointF, rubberband->centerCoordinate(RB::CoordinateSystem::Geo)), Q_ARG(double, radius1), Q_ARG(double, radius2), Q_ARG(double, rotationDeg), Q_ARG(double, centralAngleDeg)); }); if(m_errorSlot.isValid()) QObject::connect(rubberband, &SituationMap::RB::Rubberband::abort, this, [this]() { m_errorSlot.invoke(m_objToInform, Qt::QueuedConnection, Q_ARG(QString, QLatin1String("rubberband Abborted"))); }); return true; } bool InterfaceImpl::getRectangle(QObject *objectToInform, const char *replySlot, const char *errorSlot, double widthMin, double widthMax, double heightMin, double heightMax, const QPointF &bottomLeft, double width, double height, double angleNorth) { // verify mapReady if (!m_situationMap || !m_situationMap->isReady()) { ERROR_LOG(m_logger) << LOGFUNCTION << " Failure - map is not ready yet!!!"; return false; } // verify Mode: if (m_situationMap && m_situationMap->mode() == Mode::Mode_3D) { ERROR_LOG(m_logger) << LOGFUNCTION << " requested Rubberband is not allowd in this mode."; return false; } if (!checkSlots(objectToInform, SIGNAL(rectData(QPointF,double,double,double,QPolygonF)), replySlot, errorSlot)) return false; SituationMap::RB::RubberbandRectangle *rubberband = getRubberbandRectangle(objectToInform, false, widthMin, widthMax, heightMin, heightMax); if (!rubberband) return false; if (!bottomLeft.isNull()) { QLineF line(0, 0, 1, 0); line.setAngle(angleNorth); rubberband->buildRectangleRelativeToBottomLeftCorner(bottomLeft, width, height, line.p2()); adjustMapAccordingRubberband(rubberband->coordinateVector(RB::CoordinateSystem::Geo)); } QObject::connect(rubberband, &SituationMap::RB::Rubberband::apply, this, [this, rubberband]() { QPointF center, direction; double width = 0; double height = 0; rubberband->rectangleParameter(center, width, height, direction); double rotation = QLineF(0, 0, direction.x(), direction.y()).angle(); QPointF orthoDirection(-direction.y(), direction.x()); QPointF diff = direction * (width / 2) + orthoDirection * (height / 2); LtsCoordTrans::UtmCoordinate utm = LtsCoordTrans::UtmCoordinate::fromGeographic(rubberband->centerPoint()); QPointF bottomLeft = utm.geographic(-diff); m_replySlot.invoke(m_objToInform, Qt::QueuedConnection, Q_ARG(QPointF, bottomLeft), Q_ARG(double, width), Q_ARG(double, height), Q_ARG(double, rotation), Q_ARG(QPolygonF, rubberband->coordinateVector()) ); }); if(m_errorSlot.isValid()) QObject::connect(rubberband, &SituationMap::RB::Rubberband::abort, this, [this]() { m_errorSlot.invoke(m_objToInform, Qt::QueuedConnection, Q_ARG(QString, QLatin1String("rubberband Abborted"))); }); return true; } bool InterfaceImpl::getRectangleNorth(QObject *objectToInform, const char *replySlot, const char *errorSlot, double widthMin, double widthMax, double heightMin, double heightMax, const QPointF ¢er, double width, double height) { // verify mapReady if (!m_situationMap || !m_situationMap->isReady()) { ERROR_LOG(m_logger) << LOGFUNCTION << " Failure - map is not ready yet!!!"; return false; } // verify Mode: if (m_situationMap && m_situationMap->mode() == Mode::Mode_3D) { ERROR_LOG(m_logger) << LOGFUNCTION << " requested Rubberband is not allowd in this mode."; return false; } if (!checkSlots(objectToInform, SIGNAL(rectDataNorth(QPointF,double,double,QPolygonF)), replySlot, errorSlot)) return false; SituationMap::RB::RubberbandRectangle *rubberband = getRubberbandRectangle(objectToInform, false, widthMin, widthMax, heightMin, heightMax); if (!rubberband) return false; if (!center.isNull()) { rubberband->buildFromRectangleParamter(center, width, height, QPointF(1, 0)); adjustMapAccordingRubberband(rubberband->coordinateVector(RB::CoordinateSystem::Geo)); } rubberband->constrainOrthogonal(true); QObject::connect(rubberband, &SituationMap::RB::Rubberband::apply, this, [this, rubberband]() { // m_situationMap->setViewpoint2D(vp, 2); QPointF center, direction; double width = 0; double height = 0; rubberband->rectangleParameter(center, width, height, direction); center = rubberband->centerPoint(); m_replySlot.invoke(m_objToInform, Qt::QueuedConnection, Q_ARG(QPointF, center), Q_ARG(double, width), Q_ARG(double, height), Q_ARG(QPolygonF, rubberband->coordinateVector()) ); }); if(m_errorSlot.isValid()) QObject::connect(rubberband, &SituationMap::RB::Rubberband::abort, this, [this]() { m_errorSlot.invoke(m_objToInform, Qt::QueuedConnection, Q_ARG(QString, QLatin1String("rubberband Abborted"))); }); return true; } bool InterfaceImpl::getPolygon(QObject *objectToInform, const char *replySlot, const char *errorSlot, unsigned int minPoints, unsigned int maxPoints, double minSegmentLength, double maxSegmentLength, const QPolygonF &coordinates) { // verify mapReady if (!m_situationMap || !m_situationMap->isReady()) { ERROR_LOG(m_logger) << LOGFUNCTION << " Failure - map is not ready yet!!!"; return false; } // verify Mode: if (m_situationMap && m_situationMap->mode() == Mode::Mode_3D) { ERROR_LOG(m_logger) << LOGFUNCTION << " requested Rubberband is not allowd in this mode."; return false; } if (!checkSlots(objectToInform, SIGNAL(polyData(QPolygonF)), replySlot, errorSlot)) return false; SituationMap::RB::RubberbandMultiPointFeature *rubberband = getRubberbandMultiPoint(objectToInform, true, minPoints, maxPoints, minSegmentLength, maxSegmentLength, coordinates); if (!rubberband) return false; adjustMapAccordingRubberband(rubberband->coordinateVector(RB::CoordinateSystem::Geo)); QObject::connect(rubberband, &SituationMap::RB::Rubberband::apply, this, [this, rubberband]() { m_replySlot.invoke(m_objToInform, Qt::QueuedConnection, Q_ARG(QPolygonF, rubberband->coordinateVector())); }); if(m_errorSlot.isValid()) QObject::connect(rubberband, &SituationMap::RB::Rubberband::abort, this, [this]() { m_errorSlot.invoke(m_objToInform, Qt::QueuedConnection, Q_ARG(QString, QLatin1String("rubberband Abborted"))); }); return true; } bool InterfaceImpl::getPolyline(QObject *objectToInform, const char *replySlot, const char *errorSlot, unsigned int minPoints, unsigned int maxPoints, double minSegmentLength, double maxSegmentLength, const QPolygonF &coordinates) { // verify mapReady if (!m_situationMap || !m_situationMap->isReady()) { ERROR_LOG(m_logger) << LOGFUNCTION << " Failure - map is not ready yet!!!"; return false; } // verify Mode: if (m_situationMap && m_situationMap->mode() == Mode::Mode_3D) { ERROR_LOG(m_logger) << LOGFUNCTION << " requested Rubberband is not allowd in this mode."; return false; } if (!checkSlots(objectToInform, SIGNAL(polyData(QPolygonF)), replySlot, errorSlot)) return false; SituationMap::RB::RubberbandMultiPointFeature *rubberband = getRubberbandMultiPoint(objectToInform, false, minPoints, maxPoints, minSegmentLength, maxSegmentLength, coordinates); if (!rubberband) return false; adjustMapAccordingRubberband(rubberband->coordinateVector(RB::CoordinateSystem::Geo)); QObject::connect(rubberband, &SituationMap::RB::Rubberband::apply, this, [this, rubberband]() { m_replySlot.invoke(m_objToInform, Qt::QueuedConnection, Q_ARG(QPolygonF, rubberband->coordinateVector())); }); if(m_errorSlot.isValid()) QObject::connect(rubberband, &SituationMap::RB::Rubberband::abort, this, [this]() { m_errorSlot.invoke(m_objToInform, Qt::QueuedConnection, Q_ARG(QString, QLatin1String("rubberband Abborted"))); }); return true; } void InterfaceImpl::cancelActiveRubberbands() { if (!m_situationMap) { ERROR_LOG(m_logger) << LOGFUNCTION << " no situationMap"; return; } // remove any pending/active rubberbands of our map: SituationMap::RB::Rubberband::deleteAllActiveRubberbands(m_situationMap.data()); } bool InterfaceImpl::displayPreviewObject(QObject *parent, const QPolygonF &poly, bool closed) { // return displayPreviewObjects(parent, {poly}, closed); // DO NOT return displayPreviewObjects(parent, QVector() << poly, closed); } bool InterfaceImpl::displayPreviewObjects(QObject *parent, const QVector &polyVec, bool closed) { // verify mapReady if (!m_situationMap || !m_situationMap->isReady()) { ERROR_LOG(m_logger) << LOGFUNCTION << " Failure - map is not ready yet!!!"; return false; } // remove old PreviewObject: removePreviewObject(); // create new PreviewObject: const QString &logicalLayerRubberband = m_situationMap->layerFactory().rubberbandLayer(); bool success = true; QColor lineCol = Qt::magenta; lineCol.setAlpha(150); LineStyle lineStyle(lineCol, 3); lineStyle.setLinePattern(LinePattern::Dash); QColor fillCol = lineCol; fillCol.setAlpha(64); for (const QPolygonF &poly : polyVec) { PositionCont posCont = convert2D3D(poly); if (closed) { RefPointer tempRbObject = m_situationMap->objectFactory().create(logicalLayerRubberband, QStringLiteral("TemporaryRubberbandObject")); if (!tempRbObject) return false; m_uniqueMapIdOfPreviewObject.insert(tempRbObject->uniqueMapId()); tempRbObject->setPositions(posCont); tempRbObject->setLineStyle(lineStyle); tempRbObject->rFillStyle().setFillPattern(FillPattern::Solid); tempRbObject->rFillStyle().setFillColor(fillCol); success &= tempRbObject->updateView(); } else { RefPointer tempRbObject = m_situationMap->objectFactory().create(logicalLayerRubberband, QStringLiteral("TemporaryRubberbandObject")); if (!tempRbObject) return false; m_uniqueMapIdOfPreviewObject.insert(tempRbObject->uniqueMapId()); tempRbObject->setPositions(posCont); tempRbObject->setLineStyle(lineStyle); success &= tempRbObject->updateView(); } // remove PreviewObject if parent (edit dlg) is destroyed: if (success && parent) connect(parent, &QObject::destroyed, this, &InterfaceImpl::removePreviewObject, Qt::UniqueConnection); } // for return success; } bool InterfaceImpl::displayPreviewObject(QObject *parent, const QPointF ¢erGeo, double radius) { // return displayPreviewObjects(parent, {centerGeo}, radius); // DO NOT return displayPreviewObjects(parent, QVector() << centerGeo, radius); } bool InterfaceImpl::displayPreviewObjects(QObject *parent, const QVector ¢erGeoVec, double radius) { // verify mapReady if (!m_situationMap || !m_situationMap->isReady()) { ERROR_LOG(m_logger) << LOGFUNCTION << " Failure - map is not ready yet!!!"; return false; } // remove old PreviewObject: removePreviewObject(); // create new PreviewObject: const QString &logicalLayerRubberband = m_situationMap->layerFactory().rubberbandLayer(); bool success = true; QColor lineCol = Qt::magenta; lineCol.setAlpha(150); LineStyle lineStyle(lineCol, 3); lineStyle.setLinePattern(LinePattern::Dash); QColor fillCol = lineCol; fillCol.setAlpha(64); for (const QPointF ¢erGeo : centerGeoVec) { RefPointer tempRbObject = m_situationMap->objectFactory().create(logicalLayerRubberband, QStringLiteral("TemporaryRubberbandObject")); if (!tempRbObject) return false; m_uniqueMapIdOfPreviewObject.insert(tempRbObject->uniqueMapId()); tempRbObject->setSymbol(SymbolData()); // no TacticalAppearance tempRbObject->setVisibility(ObjectAppearance::Tactical, false); tempRbObject->setOrigin(Point3D::fromQPointF(centerGeo)); tempRbObject->setRadius(radius, 50); // maxPointCount: it´s just a single temporary object... tempRbObject->setLineStyle(lineStyle); tempRbObject->rFillStyle().setFillPattern(FillPattern::Solid); tempRbObject->rFillStyle().setFillColor(fillCol); success = tempRbObject->updateView(); // remove PreviewObject if parent (edit dlg) is destroyed: if (success && parent) connect(parent, &QObject::destroyed, this, &InterfaceImpl::removePreviewObject, Qt::UniqueConnection); } return success; } bool InterfaceImpl::displayPreviewObject(QObject *parent, const QPointF ¢erPoint, double radius, double rotationDeg, double centralAngleDeg) { // verify mapReady if (!m_situationMap || !m_situationMap->isReady()) { ERROR_LOG(m_logger) << LOGFUNCTION << " Failure - map is not ready yet!!!"; return false; } // remove old PreviewObject: removePreviewObject(); // create new PreviewObject: const QString &logicalLayerRubberband = m_situationMap->layerFactory().rubberbandLayer(); bool success = true; QColor lineCol = Qt::magenta; lineCol.setAlpha(150); LineStyle lineStyle(lineCol, 3); lineStyle.setLinePattern(LinePattern::Dash); QColor fillCol = lineCol; fillCol.setAlpha(64); // introduced for BoobyTraps: QPolygonF polyVec = SituationMap::MathUtils::getCircleSectorPolygon(centerPoint, radius, rotationDeg, centralAngleDeg); PositionCont posCont = convert2D3D(polyVec); RefPointer tempRbObject = m_situationMap->objectFactory().create(logicalLayerRubberband, QStringLiteral("TemporaryRubberbandObject")); if (!tempRbObject) return false; m_uniqueMapIdOfPreviewObject.insert(tempRbObject->uniqueMapId()); tempRbObject->setPositions(posCont); tempRbObject->setLineStyle(lineStyle); tempRbObject->rFillStyle().setFillPattern(FillPattern::Solid); tempRbObject->rFillStyle().setFillColor(fillCol); success &= tempRbObject->updateView(); // remove PreviewObject if parent (edit dlg) is destroyed: if (success && parent) connect(parent, &QObject::destroyed, this, &InterfaceImpl::removePreviewObject, Qt::UniqueConnection); return success; } bool InterfaceImpl::displayPreviewObjects(QObject *parent, const QVector &previewCirclesAscending) { // verify mapReady if (!m_situationMap || !m_situationMap->isReady()) { ERROR_LOG(m_logger) << LOGFUNCTION << " Failure - map is not ready yet!!!"; return false; } // remove old PreviewObject: removePreviewObject(); // create new PreviewObject: const QString &logicalLayerRubberband = m_situationMap->layerFactory().rubberbandLayer(); bool success = true; int drawOrder = 0; for (const PreviewCircleData &previewCircle : qAsConst(previewCirclesAscending)) { RefPointer tempObject = m_situationMap->objectFactory().create(logicalLayerRubberband, QStringLiteral("TemporaryPreviewCircle")); if (!tempObject) return false; m_uniqueMapIdOfPreviewObject.insert(tempObject->uniqueMapId()); tempObject->setSymbol(SymbolData()); // no TacticalAppearance tempObject->setVisibility(ObjectAppearance::Tactical, false); tempObject->setOrigin(Point3D::fromQPointF(previewCircle.centerGeo)); tempObject->setRadius(previewCircle.radius, 50); // maxPointCount: it´s just a single temporary object... const LineStyle ls(previewCircle.lineColor, previewCircle.lineWidth, static_cast(previewCircle.linePattern)); tempObject->setLineStyle(ls); const FillStyle fs(previewCircle.fillColor, static_cast(previewCircle.fillPattern)); tempObject->setFillStyle(fs); tempObject->setDrawOrder(++drawOrder); bool localSuccess = tempObject->updateView(); success = localSuccess && success; // remove PreviewObject if parent (edit dlg) is destroyed: if (localSuccess && parent) connect(parent, &QObject::destroyed, this, &InterfaceImpl::removePreviewObject, Qt::UniqueConnection); } // for return success; } bool InterfaceImpl::skipMapObjectSelectionDialog() const { CHECK_SMI_RETVAL; return m_situationMapInit->skipMapObjectSelectionDialog(); } void InterfaceImpl::setSkipMapObjectSelectionDialog(bool asList) { CHECK_SMI; m_situationMapInit->setSkipMapObjectSelectionDialog(asList); } void InterfaceImpl::startMeasureLength() { // verify mapReady if (!m_situationMap || !m_situationMap->isReady()) { ERROR_LOG(m_logger) << LOGFUNCTION << " Failure - map is not ready yet!!!"; return; } CHECK_SMI; m_situationMapInit->startMeasureLength(); } void InterfaceImpl::clearMeasureLength() { CHECK_SMI; m_situationMapInit->clearMeasureLength(); } void InterfaceImpl::startTerrainProfile() { if (!m_terrainProfileHandler) return; m_terrainProfileHandler->startTerrainProfile(); } void InterfaceImpl::clearTerrainProfile() { if (!m_terrainProfileHandler) return; m_terrainProfileHandler->clearTerrainProfile(); } void InterfaceImpl::buildViewshedDialog() { ViewshedDialog *dlg = new ViewshedDialog(m_session->baseLayout()); dlg->initValues(m_ViewshedAlpha, m_ViewshedInnerRadius, m_ViewshedObserverHeight, m_ViewshedTargetHeight, m_ViewshedBeamAngle); connect(dlg, &ViewshedDialog::createViewshed, this, [this, dlg]() { CHECK_SMI; m_ViewshedAlpha = dlg->alpha(); m_ViewshedInnerRadius = dlg->innerRadius(); m_ViewshedObserverHeight = dlg->observerHeight(); m_ViewshedTargetHeight = dlg->targetHeight(); m_ViewshedBeamAngle = dlg->beamAngle(); m_situationMapInit->startViewshed(m_ViewshedAlpha, m_ViewshedInnerRadius, m_ViewshedObserverHeight, m_ViewshedTargetHeight, m_ViewshedBeamAngle); }); connect(dlg, &ViewshedDialog::removeViewshed, this, [this]() { clearViewshed(); }); connect(dlg, &ViewshedDialog::parameterChanged, this, [this, dlg]() { CHECK_SMI; m_ViewshedAlpha = dlg->alpha(); m_ViewshedInnerRadius = dlg->innerRadius(); m_ViewshedObserverHeight = dlg->observerHeight(); m_ViewshedTargetHeight = dlg->targetHeight(); m_ViewshedBeamAngle = dlg->beamAngle(); m_situationMapInit->modifyViewshed(m_ViewshedAlpha, m_ViewshedInnerRadius, m_ViewshedObserverHeight, m_ViewshedTargetHeight, m_ViewshedBeamAngle); }); m_session->addWidget(dlg, tr("Situation Map"), QStringLiteral("ViewshedDialog"), LtsWidgets::LayoutArea::eDialogTab, true); } // void InterfaceImpl::buildViewshedDialog() void InterfaceImpl::startViewshed() { CHECK_SMI; m_situationMapInit->startViewshed(); } void InterfaceImpl::clearViewshed() { CHECK_SMI; m_situationMapInit->clearViewshed(); } bool InterfaceImpl::showExpiredEmergencyCalls(bool showExpired) { if (!(m_situationMapInit)) { LOG_ERROR_SIT; return false; } return m_situationMapInit->showExpiredEmergencyCalls(showExpired); } bool InterfaceImpl::ocSituationRange_create(const QPointF &origin_lonLatRadiant, double radius_meter, const ocSituationRangeAttributes &attributes) { CHECK_SMI_RETVAL; // verify if (!m_situationMap || !m_situationMap->isReady()) { ERROR_LOG(m_logger) << LOGFUNCTION << " Failure - map is not ready yet!!!"; return false; } // remove old: this->ocSituationRange_remove(); const QString &toolLayerName = m_situationMap->layerFactory().toolLayer(); // use ChemicalAgent as Circle RefPointer ocSituationRangeObject = m_situationMap->objectFactory().create(toolLayerName, QStringLiteral("OcSituationRange")); if (!ocSituationRangeObject) { ERROR_LOG(m_logger) << LOGFUNCTION << " create failed"; return false; } m_ocRange.uniqueMapId = ocSituationRangeObject->uniqueMapId(); // no ObjectAppearance::Tactical ocSituationRangeObject->setVisibility(ObjectAppearance::Tactical, false); ocSituationRangeObject->setVisibility(LtsUtils::OperatorSettings::getInstance()->value(QStringLiteral("ObserverController"), QStringLiteral("OcSituationBorder"), false).toBool()); // set origin, radius ocSituationRangeObject->setOrigin(Point3D::fromQPointF(origin_lonLatRadiant)); ocSituationRangeObject->setRadius(radius_meter); // set attributes: ocSituationRangeObject->rLineStyle().setLineColor(attributes.lineColor.isValid() ? attributes.lineColor : Qt::black); ocSituationRangeObject->rLineStyle().setLineWidth(attributes.lineWidth > 1 ? attributes.lineWidth : 2); SituationMap::FillStyle fs; if (attributes.opacity >= 0) { fs.setFillPattern(SituationMap::FillPattern::Solid); QColor fillColor = ocSituationRangeObject->rLineStyle().lineColor(); fillColor.setAlphaF(attributes.opacity); fs.setFillColor(fillColor); } else fs.setFillPattern(SituationMap::FillPattern::Null); ocSituationRangeObject->setFillStyle(fs); if (!ocSituationRangeObject->updateView()) { ERROR_LOG(m_logger) << LOGFUNCTION << " updateView failed"; return false; } return true; } bool InterfaceImpl::ocSituationRange_create(int participantId, double radius_meter, const ocSituationRangeAttributes &attributes) { CHECK_SMI_RETVAL; // verify if (!m_situationMap || !m_situationMap->isReady()) { ERROR_LOG(m_logger) << LOGFUNCTION << " Failure - map is not ready yet!!!"; return false; } // remove old: this->ocSituationRange_remove(); m_ocRange.participantId = participantId; // find participant: RefPointer participant = m_situationMapInit->simId2Participant(m_ocRange.participantId); if (!participant) { ERROR_LOG(m_logger) << LOGFUNCTION << " Failure - participantId not found" << " (" << participantId << ")"; return false; } ocSituationRangeAttributes attributesLocal = attributes; attributesLocal.lineColor = participant->majorColor(); if (!ocSituationRange_create(participant->origin().toPointF(), radius_meter, attributesLocal)) { ERROR_LOG(m_logger) << LOGFUNCTION << " Failure - ocSituationRange_create failed" << " (" << participantId << ")"; } // connect for positionUpdates: m_ocRange.connection = connect(m_situationMapInit.data(), &SituationMapInit::participantPositionChanged, this, &InterfaceImpl::onParticipantPositionChanged); return true; } bool InterfaceImpl::ocSituationRange_show(bool visible) { CHECK_SMI_RETVAL; // verify if (!m_situationMap || !m_situationMap->isReady()) { ERROR_LOG(m_logger) << LOGFUNCTION << " Failure - map is not ready yet!!!"; return false; } RefPointer ocSituationRangeObject = m_situationMap->objectFactory().get(m_ocRange.uniqueMapId); if (!ocSituationRangeObject) { DEBUG_LOG(m_logger) << LOGFUNCTION << " not found"; return false; } ocSituationRangeObject->setVisibility(visible); if (ocSituationRangeObject->updateView()) { ERROR_LOG(m_logger) << LOGFUNCTION << " updateView failed"; return false; } return true; } bool InterfaceImpl::ocSituationRange_remove() { CHECK_SMI_RETVAL; disconnect(m_ocRange.connection); // verify if (!m_situationMap || !m_situationMap->isReady()) { ERROR_LOG(m_logger) << LOGFUNCTION << " Failure - map is not ready yet!!!"; return false; } if (!isUniqueMapIdValid(m_ocRange.uniqueMapId)) return true; if (!m_situationMap->objectFactory().contains(m_ocRange.uniqueMapId)) return true; RefPointer ocSituationRangeObject = m_situationMap->objectFactory().get(m_ocRange.uniqueMapId); if (!ocSituationRangeObject) { DEBUG_LOG(m_logger) << LOGFUNCTION << " not found"; return false; } ocSituationRangeObject->removeMySelf(); m_ocRange.uniqueMapId = INVALID_MAP_ID; return true; } // Rotiert ein Rechteck um die 'cornerPosition' (linke untere Ecke) mit dem 'rotationAngle' // Die Drehrichtung ist nordbezogen rechtsdrehend positiv // Ausgabe der Koordinaten in rad static QPolygonF rectangle(const QPointF &cornerPosition, double width, double length, double rotationAngle) { QPolygonF polyUtm = QPolygonF({QPointF(0, 0), QPointF(length, 0), QPointF(length, width), QPointF(0, width) }); QTransform trans; trans.translate(length / 2, width / 2); trans.rotate(-rotationAngle); trans.translate(-(length / 2), -(width / 2)); //polyUtm = QTransform().rotate(-rotationAngle).map(polyUtm); polyUtm = trans.map(polyUtm); QPolygonF poly; poly.reserve(polyUtm.size()); LtsCoordTrans::UtmCoordinate cord = LtsCoordTrans::UtmCoordinate::fromGeographic(cornerPosition); cord.y = cord.y - (width / 2); cord.x = cord.x - (length / 2); for (const QPointF &point : qAsConst(polyUtm)) poly << cord.geographic(point); return poly; } //------------------------------------------------ bool InterfaceImpl::escOrderPosition_create(const QPointF &origin_lonLatRadiant, int areaWidth, int areaDepth, int rotation, bool is_smoke, const escOrderPositionAttributes &attributes) { CHECK_SMI_RETVAL; // verify if (!m_situationMap || !m_situationMap->isReady()) { ERROR_LOG(m_logger) << LOGFUNCTION << " Failure - map is not ready yet!!!"; return false; } // remove old: this->escOrderPosition_remove(); const QString &toolLayerName = m_situationMap->layerFactory().toolLayer(); // use Polygon Object for ESC Order Position if (is_smoke) { RefPointer escOrderAreaPositionObject = m_situationMap->objectFactory().create(toolLayerName, QStringLiteral("EscOrderAreaPosition")); if (!escOrderAreaPositionObject) { ERROR_LOG(m_logger) << LOGFUNCTION << " create failed"; return false; } m_escOrderAreaPosition.uniqueMapId = escOrderAreaPositionObject->uniqueMapId(); // no ObjectAppearance::Tactical escOrderAreaPositionObject->setVisibility(ObjectAppearance::Tactical, false); escOrderAreaPositionObject->setVisibility(true); QPolygonF polygon_rad = rectangle(origin_lonLatRadiant, areaWidth, -areaDepth, rotation); // set rectangle points and show it PositionCont posContainer; posContainer.reserve(polygon_rad.size()); for (const QPointF &p : qAsConst(polygon_rad)) posContainer.append(Point3D(p.x(), p.y(), 0)); escOrderAreaPositionObject->setPositions(posContainer); // set attributes escOrderAreaPositionObject->rLineStyle().setLineColor(attributes.lineColor.isValid() ? attributes.lineColor : Qt::black); escOrderAreaPositionObject->rLineStyle().setLineWidth(attributes.lineWidth > 1 ? attributes.lineWidth : 2); SituationMap::FillStyle fs; if (attributes.opacity >= 0) { fs.setFillPattern(SituationMap::FillPattern::Solid); QColor fillColor = escOrderAreaPositionObject->rLineStyle().lineColor(); fillColor.setAlphaF(attributes.opacity); fs.setFillColor(fillColor); } else fs.setFillPattern(SituationMap::FillPattern::Null); escOrderAreaPositionObject->setFillStyle(fs); if (!escOrderAreaPositionObject->updateView()) { ERROR_LOG(m_logger) << LOGFUNCTION << " updateView failed"; return false; } } else { //here we display the starting point, on smoke vehicles it's the lower left position, on explosions it's the center RefPointer escOrderStartPositionObject = m_situationMap->objectFactory().create(toolLayerName, QStringLiteral("EscOrderStartPosition")); if (!escOrderStartPositionObject) { ERROR_LOG(m_logger) << LOGFUNCTION << " create failed"; return false; } m_escOrderStartPosition.uniqueMapId = escOrderStartPositionObject->uniqueMapId(); // no ObjectAppearance::Tactical escOrderStartPositionObject->setVisibility(ObjectAppearance::Tactical, false); escOrderStartPositionObject->setVisibility(true); // set origin, radius escOrderStartPositionObject->setOrigin(Point3D::fromQPointF(origin_lonLatRadiant)); //use fixed radius for now escOrderStartPositionObject->setRadius(15); // set attributes: escOrderStartPositionObject->rLineStyle().setLineColor(attributes.lineColor.isValid() ? attributes.lineColor : Qt::black); escOrderStartPositionObject->rLineStyle().setLineWidth(attributes.lineWidth > 1 ? attributes.lineWidth : 2); SituationMap::FillStyle fs; if (attributes.opacity >= 0) { fs.setFillPattern(SituationMap::FillPattern::Solid); QColor fillColor = escOrderStartPositionObject->rLineStyle().lineColor(); fillColor.setAlphaF(attributes.opacity); fs.setFillColor(fillColor); } else fs.setFillPattern(SituationMap::FillPattern::Null); escOrderStartPositionObject->setFillStyle(fs); if (!escOrderStartPositionObject->updateView()) { ERROR_LOG(m_logger) << LOGFUNCTION << " updateView failed"; return false; } } return true; } //------------------------------------------------ bool InterfaceImpl::escOrderPosition_show(bool visible) { CHECK_SMI_RETVAL; // verify if (!m_situationMap || !m_situationMap->isReady()) { ERROR_LOG(m_logger) << LOGFUNCTION << " Failure - map is not ready yet!!!"; return false; } if (isUniqueMapIdValid(m_escOrderAreaPosition.uniqueMapId)) { RefPointer escOrderAreaPositionObject = m_situationMap->objectFactory().get(m_escOrderAreaPosition.uniqueMapId); if (escOrderAreaPositionObject) { escOrderAreaPositionObject->setVisibility(visible); if (!escOrderAreaPositionObject->updateView()) { ERROR_LOG(m_logger) << LOGFUNCTION << " updateView failed"; return false; } } } if (isUniqueMapIdValid(m_escOrderStartPosition.uniqueMapId)) { RefPointer escOrderStartPositionObject = m_situationMap->objectFactory().get(m_escOrderStartPosition.uniqueMapId); if (escOrderStartPositionObject) { escOrderStartPositionObject->setVisibility(visible); if (!escOrderStartPositionObject->updateView()) { ERROR_LOG(m_logger) << LOGFUNCTION << " updateView failed"; return false; } } } return true; } void InterfaceImpl::showExerciseTimeString(bool visible) { if (!m_situationMap || !m_situationMap->isReady()) { ERROR_LOG(m_logger) << LOGFUNCTION << " Failure - map is not ready yet!!!"; return; } m_situationMap->showExerciseTimeString(visible); } bool InterfaceImpl::escOrderPosition_remove() { CHECK_SMI_RETVAL; disconnect(m_escOrderStartPosition.connection); disconnect(m_escOrderAreaPosition.connection); // verify if (!m_situationMap || !m_situationMap->isReady()) { ERROR_LOG(m_logger) << LOGFUNCTION << " Failure - map is not ready yet!!!"; return false; } if (!isUniqueMapIdValid(m_escOrderStartPosition.uniqueMapId) && !isUniqueMapIdValid(m_escOrderAreaPosition.uniqueMapId)) return true; if (!m_situationMap->objectFactory().contains(m_escOrderStartPosition.uniqueMapId) && !m_situationMap->objectFactory().contains(m_escOrderAreaPosition.uniqueMapId)) return true; if (isUniqueMapIdValid(m_escOrderStartPosition.uniqueMapId)) { RefPointer escOrderStartPositionObject = m_situationMap->objectFactory().get(m_escOrderStartPosition.uniqueMapId); if (!escOrderStartPositionObject) { DEBUG_LOG(m_logger) << LOGFUNCTION << " not found"; return false; } escOrderStartPositionObject->removeMySelf(); } if (isUniqueMapIdValid(m_escOrderAreaPosition.uniqueMapId)) { RefPointer escOrderAreaPositionObject = m_situationMap->objectFactory().get(m_escOrderAreaPosition.uniqueMapId); if (!escOrderAreaPositionObject) { DEBUG_LOG(m_logger) << LOGFUNCTION << " not found"; return false; } escOrderAreaPositionObject->removeMySelf(); } m_escOrderStartPosition.uniqueMapId = INVALID_MAP_ID; m_escOrderAreaPosition.uniqueMapId = INVALID_MAP_ID; return true; } bool InterfaceImpl::isEscOrderPositionVisible() { if (!m_situationMap || !m_situationMap->isReady()) { ERROR_LOG(m_logger) << LOGFUNCTION << " Failure - map is not ready yet!!!"; return false; } if (!isUniqueMapIdValid(m_escOrderStartPosition.uniqueMapId)) return false; RefPointer escOrderStartPositionObject = m_situationMap->objectFactory().get(m_escOrderStartPosition.uniqueMapId); if (escOrderStartPositionObject) return true; //not found return false; } //------------------------------------------------ void InterfaceImpl::onParticipantPositionChanged(const int32_t participantId, const Point3D &newPos) { if (m_ocRange.participantId != participantId) return; // verify if (!m_situationMap || !m_situationMap->isReady()) { ERROR_LOG(m_logger) << LOGFUNCTION << " Failure - map is not ready yet!!!"; return; } RefPointer ocSituationRangeObject = m_situationMap->objectFactory().get(m_ocRange.uniqueMapId); if (!ocSituationRangeObject) { ERROR_LOG(m_logger) << LOGFUNCTION << " not found"; return; } // update: ocSituationRangeObject->setOrigin(newPos); if (!ocSituationRangeObject->updateView()) { ERROR_LOG(m_logger) << LOGFUNCTION << " updateView failed"; return; } return; } void InterfaceImpl::onTrainingAreaChanged(const AssetManagement::TrainingArea &trainingArea, DataModification modType) { TRACE_LOG(m_logger) << LOGFUNCTION << " START" << " TrainingArea = " << trainingArea << ", modType=" << modType; if (modType == DataModification::eRemoved) return; if (!m_pluginProvider->exmDtc()) return; const int curExerciseId = m_session->exerciseId(); m_pluginProvider->exmDtc()->waitForHistoricalDataExercise(2000); const int trainingAreaIdOfCurrentExercise = m_pluginProvider->exmDtc()->exercise(curExerciseId).trainingAreaId(); if ( (curExerciseId > 0) && (trainingAreaIdOfCurrentExercise == trainingArea.id()) ) { const Core::GeoPosition2D &bottomLeft = trainingArea.bottomLeft(); const LtsCoordTrans::UtmCoordinate referencePointUTM = LtsCoordTrans::UtmCoordinate::fromGeographic(bottomLeft.lon(), bottomLeft.lat()); const QPointF size(trainingArea.width(), trainingArea.height()); QVector trainingAreaCoords; trainingAreaCoords.reserve(4); trainingAreaCoords.push_back(QPointF(bottomLeft.lon(), bottomLeft.lat())); trainingAreaCoords.push_back(QPointF(referencePointUTM.geographic(0 , size.y()))); trainingAreaCoords.push_back(QPointF(referencePointUTM.geographic(size.x(), size.y()))); trainingAreaCoords.push_back(QPointF(referencePointUTM.geographic(size.x(), 0))); m_trainingsAreaExtent = trainingAreaCoords; if (m_situationMap) m_situationMap->setTrainingsAreaExtent(m_trainingsAreaExtent); } } bool InterfaceImpl::setInitialOperatorMapSettings(const QByteArray &data) { return setInitialOperatorMapSettings(QJsonDocument::fromJson(data).object()); } bool InterfaceImpl::isAutoSetExerciseTimeString() const { return (m_session->isReplayPartition() && m_session->app() != LtsAppDescriptor::App::Snapshot); // time string is required by GÜZ in replay partitions (but not for Snapshots) } void InterfaceImpl::getCircleSectorRotationAndAngles(QPointF sectStart, QPointF sectEnd, double &rotationDegOut, double &openAngleDegOut) { double startAngle = SituationMap::MathUtils::getMathAngle(sectStart) * LtsCoordTrans::rad2deg(); double endAngle = SituationMap::MathUtils::getMathAngle(sectEnd) * LtsCoordTrans::rad2deg(); startAngle = std::fmod(startAngle, 360.); endAngle = std::fmod(endAngle, 360.); // get central angle value in deg { if ( startAngle > endAngle) openAngleDegOut = 360 + (endAngle - startAngle); else openAngleDegOut = endAngle - startAngle; } // get rotation angle north (in deg) orientated 0° North(12h) { rotationDegOut = SituationMap::MathUtils::getAngleDegree2North((startAngle + (openAngleDegOut/2.))); if (rotationDegOut == 360.) rotationDegOut = 0; } } bool InterfaceImpl::setInitialOperatorMapSettings(const QJsonValue &data) { OperatorMapSettings oms; oms.fromJsonObject(data.toObject()); if (oms.isEmpty()) ERROR_LOG(m_logger) << LOGFUNCTION << " oms.isEmpty (mode is undefined)"; else { INFO_LOG(m_logger) << LOGFUNCTION << " got data :-)" << ", mode = " << oms.mode << ", viewpoint = " << oms.viewpoint << ", camera = " << oms.camera; if (isAutoSetExerciseTimeString()) // time string is required by GÜZ in replay partitions oms.mapWidgetSettings.exerciseTimeStringVisibility = true; m_operatorMapSettings2achieve = oms; if (m_waitForInitialOperatorMapSettings) m_waitForInitialOperatorMapSettings->start(10); } return oms.mode == Mode::Undefined; } QByteArray InterfaceImpl::operatorMapSettingsJson() const { CHECK_SMI_RETVAL; const QJsonDocument jDoc(operatorMapSettings().toObject()); return jDoc.toJson(QJsonDocument::Compact); // QJsonObject objTemp; //// // 1. MovementTrackManager //// QPointer movementTrackManager = m_situationMapInit->movementTrackManager(); //// if(movementTrackManager) //// objTemp[QLatin1String("movementTrackManager")] = movementTrackManager->toJsonObject(); // // 2. main operatorMapSettings // objTemp[QLatin1String("operatorMapSettings")] = m_situationMap->operatorMapSettings().toJsonObject(); // // final: // QJsonDocument jDoc(objTemp); // const QByteArray &ba = jDoc.toJson(); // return QString::fromUtf8(ba); } bool InterfaceImpl::setOperatorMapSettingsJson(const QByteArray &data) { DEBUG_LOG(m_logger) << LOGFUNCTION << " START" << ", this->isMapReady()=" << this->isMapReady() << ", data=>>>" << data << "<<<"; return setOperatorMapSettings(QJsonDocument::fromJson(data).object()); } QJsonValue InterfaceImpl::operatorMapSettings() const { CHECK_SMI_RETVAL; if (!m_situationMap) return {}; return m_situationMap->operatorMapSettings().toJsonObject(); } bool InterfaceImpl::setOperatorMapSettings(const QJsonValue &data) { bool bIsTimerActive = false; if (m_waitForInitialOperatorMapSettings) bIsTimerActive = m_waitForInitialOperatorMapSettings->isActive(); DEBUG_LOG(m_logger) << LOGFUNCTION << " START" << ", this->isMapReady()=" << this->isMapReady() << ", data.isNull() =" << data.isNull() << ", m_waitForInitialOperatorMapSettings->isActive() =" << bIsTimerActive; if (data.isNull() && m_waitForInitialOperatorMapSettings && m_waitForInitialOperatorMapSettings->isActive()) { INFO_LOG(m_logger) << LOGFUNCTION << " skip waitForInitialOperatorMapSettings"; m_waitForInitialOperatorMapSettings->start(10); return true; } // it´s not evil: this->setInitialOperatorMapSettings(data); bool bRet = true; if (this->isMapReady()) { CHECK_SMI_RETVAL; OperatorMapSettings oms; oms.fromJsonObject(data.toObject()); if (isAutoSetExerciseTimeString()) // time string is required by GÜZ in replay partitions oms.mapWidgetSettings.exerciseTimeStringVisibility = true; if (oms.mode == Mode::Undefined) { ERROR_LOG(m_logger) << LOGFUNCTION << " mode of map settings is invalid (0 / undefined)"; bRet = false; } else if (oms.mode != static_cast(this->mapMode())) { INFO_LOG(m_logger) << LOGFUNCTION << " mode switching required"; // [GUEZE-862] moved to InterfaceImpl::reCreateSituationMapInit // delete m_situationMapInit; // m_situationMapInit.clear(); // store oms (to be used while re-creation): m_operatorMapSettings2achieve = oms; // destroy current and restart reCreateSituationMapInitAndAddToLayoutAndReInit(); } else bRet = restoreOperatorMapSettingsOverlays(oms); } else { ERROR_LOG(m_logger) << LOGFUNCTION << " map not ready yet!"; bRet = false; } return bRet; } QByteArray InterfaceImpl::movementTrackManagerSettingsJson() const { QJsonObject obj; obj[QLatin1String("MovemenTrackManager")] = movementTrackManagerSettings(); const QJsonDocument jDoc(obj); return jDoc.toJson(QJsonDocument::Compact); } bool InterfaceImpl::setMovementTrackManagerSettingsJSon(const QByteArray &data) { if (!m_movementTrackManager) { ERROR_LOG(m_logger) << LOGFUNCTION << " no MovementTrackManager"; return false; } QJsonParseError parserError; const QJsonDocument jDoc(QJsonDocument::fromJson(data, &parserError)); if (parserError.error != QJsonParseError::NoError) { ERROR_LOG(m_logger) << LOGFUNCTION << " Error parsing json document: " << parserError.errorString(); return false; } const QJsonObject &object = jDoc.object(); const QJsonObject &innerObj = object[QLatin1String("MovemenTrackManager")].toObject(); if (innerObj.isEmpty()) { ERROR_LOG(m_logger) << "inner content MovementTracks is empty"; return false; } // apply return setMovementTrackManagerSettings(innerObj); } QJsonObject InterfaceImpl::movementTrackManagerSettings() const { if (!m_movementTrackManager) return QJsonObject(); return m_movementTrackManager->toJsonObject(); } bool InterfaceImpl::setMovementTrackManagerSettings(const QJsonValue &data) { if (!m_movementTrackManager) return false; INFO_LOG(m_logger) << LOGFUNCTION << " read MovementTrackManagerSettings"; bool success = m_movementTrackManager->read(data.toObject()); return success; } bool InterfaceImpl::restoreOperatorMapSettingsOverlays(OperatorMapSettings &oms) { CHECK_SMI_RETVAL; if (!m_situationMap->isReady()) { ERROR_LOG(m_logger) << LOGFUNCTION << " Failure - map is not ready yet!!!"; return false; } if (oms.isEmpty()) { ERROR_LOG(m_logger) << LOGFUNCTION << " Failure - oms empty"; return false; } DEBUG_LOG(m_logger) << LOGFUNCTION << " oms = " << QJsonDocument(oms.toJsonObject()).toJson(QJsonDocument::Indented) ; // remove all current: m_situationMap->overlayHandler().removeAllOverlays(); // 1 restoreOperatorMapSettings if (!m_situationMap->restoreOperatorMapSettings(oms)) WARNING_LOG(m_logger) << LOGFUNCTION << " restoreOperatorMapSettings failed"; // continue!!! maybe just LayerOrder failed.... ToDo // 2. handle Overlays : // SituationMap can`t restore the overlays on it´s own since access to FileManagement is required. // So we have to do it here: // process required: const QList orderedOverlayIds = oms.orderedOverlays; INFO_LOG(m_logger) << LOGFUNCTION << " restore OverlayIds: " << orderedOverlayIds; QVector unloadableOverlayIds; if (!orderedOverlayIds.isEmpty()) { std::shared_ptr ovrDtc; if (m_session->getForeignGuiInterface(ovrDtc)) { for (const int overlayId : orderedOverlayIds) { // for snapshotOverlay id '-4711' is used. // Of course there is no plan/file for this id... if (overlayId < 0) continue; INFO_LOG(m_logger) << LOGFUNCTION << " restore overlayId: " << overlayId; if (!ovrDtc->loadPlan(overlayId)) { unloadableOverlayIds.append(overlayId); oms.orderedOverlays.removeAll(overlayId); } } // for } else WARNING_LOG(m_logger) << LOGFUNCTION << " getForeignGuiInterface for PlanOverlaysPlugin::ForeignGuiInterface failed, but it is optional"; } // GUEZE-2848 Ebeneneinstellungen - OverlayLayer_XXX verweist auf veraltete DB Einträge if (m_logger.isDebugEnabled()) { qCritical() << " unloadableOverlayIds = " << unloadableOverlayIds; auto overlayIds = m_situationMap->overlayHandler().overlays(); qCritical() << " m_situationMap->overlayHandler().overlays() = " << overlayIds; } for (const int unloadableOverlayId : qAsConst(unloadableOverlayIds)) { NOTICE_LOG(m_logger) << " due to error on loading, following overlayId is removed: " << unloadableOverlayId; if (!m_situationMap->overlayHandler().removeOverlay(unloadableOverlayId)) ERROR_LOG(m_logger) << " due to error on loading, following overlayId is removed: " << unloadableOverlayId << ", but removeOverlay failed"; } // for // QVector appsToSuppressMsg {LtsAppDescriptor::App::Scripts}; if (!unloadableOverlayIds.isEmpty() && (m_session->app() != LtsAppDescriptor::App::Scripts)) { // LtsMessageDialogNew -> NON-BLOCKING Popup-Dialog //: "Einige Overlays scheinen entfernt worden zu sein, daher wurden Ihre Einstellungen angepasst." //: "Lage" LtsWidgets::LtsMessageDialogNew(m_situationMap, tr("Some overlays seem to be removed from database and therefore your settings were adopted."), tr("Situation Map")); } return true; } bool InterfaceImpl::restoreOcSituationRange() { CHECK_SMI_RETVAL; if (!m_situationMap->isReady()) { ERROR_LOG(m_logger) << LOGFUNCTION << " Failure - map is not ready yet!!!"; return false; } LtsUtils::OperatorSettings *opSettings = LtsUtils::OperatorSettings::getInstance(); QString ocDemandGroupString(QStringLiteral("ObserverControllerDemand")); //load old settings double range = static_cast(opSettings->value(ocDemandGroupString, QStringLiteral("Range"), 100).toInt()); int participantId = opSettings->value(ocDemandGroupString, QStringLiteral("ParticipantId"), 0).toInt(); if (participantId > 0) ocSituationRange_create(participantId, range); else if (opSettings->value(ocDemandGroupString, QStringLiteral("PosLon"), -1).toDouble() > 0) { QPointF pos(opSettings->value(ocDemandGroupString, QStringLiteral("PosLon"), -1).toDouble(), opSettings->value(ocDemandGroupString, QStringLiteral("PosLat"), -1).toDouble()); ocSituationRange_create(pos, range); } return true; } void InterfaceImpl::onTriggerFilterDataChanged(const FilterManagement::TriggerFilterData &data, DataModification modType) { // Someone would like to use our (Filter) settings if (modType == DataModification::eRemoved) return; const int operatorId = m_pluginProvider->operatorId(); if (data.operatorId() != operatorId) return; DEBUG_LOG(m_logger) << LOGFUNCTION << " Someone would like to use our (Filter) settings "; std::shared_ptr fltFtc = m_pluginProvider->fltFtc(); std::shared_ptr fltParticipantIfc = m_pluginProvider->fltParticipantIfc(); std::shared_ptr fltAesIfc = m_pluginProvider->fltAesIfc(); // Nachtrag zu GUEZE-1769: since fltBuildingComponentIfc is optional: std::shared_ptr fltBuildingComponentIfc = m_pluginProvider->fltBuildingComponentIfc(); if (!fltFtc || !fltParticipantIfc || !fltAesIfc // Nachtrag zu GUEZE-1769: since fltBuildingComponentIfc is optional: // || !fltBuildingComponentIfc ) { ERROR_LOG(m_logger) << LOGFUNCTION << " no fltIfc/fltFtc"; return; } const QString &context = m_pluginProvider->workspaceId(); FilterManagement::FilterData req; // MetaData req.operatorId(operatorId); req.screenTypeId(m_session->screenTypeId()); req.screenId(m_session->screenId()); req.screenContainerId(m_session->screenContainerId()); req.requestTime(m_session->partitionTime()); req.id(req.operatorId() * 1000 + req.screenId()); { // data AesFilterContent std::shared_ptr displayFilter = fltAesIfc->aesFilterForOperator(operatorId, context); if (displayFilter) { FilterManagement::AesFilter aesFilter = displayFilter->filterToData(); req.aesFilterContent(aesFilter.content()); } else { ERROR_LOG(m_logger) << LOGFUNCTION << " no AesDisplayFilter"; } } { // data SymbolAppearanceContent std::shared_ptr symbolAppearanceSettings = fltParticipantIfc->symbolAppearanceForOperator(operatorId, context); if (symbolAppearanceSettings) { FilterManagement::SymbolAppearance symApp = symbolAppearanceSettings->settingsToData(); req.symbolAppearanceContent(symApp.content()); } else { ERROR_LOG(m_logger) << LOGFUNCTION << " no SymbolAppearanceSettings"; } } { // data BuildingComponentSettingsContent // Nachtrag zu GUEZE-1769: since fltBuildingComponentIfc is optional: if (fltBuildingComponentIfc) { std::shared_ptr buildingComponentSettings = fltBuildingComponentIfc->buildingComponentSettingsForOperator(operatorId, context); if (buildingComponentSettings) { FilterManagement::BuildingComponentFilter filter = buildingComponentSettings->bldCmpSettingsToData(); req.buildingComponentsFilterContent(filter.content()); } else { WARNING_LOG(m_logger) << LOGFUNCTION << " no BuildingComponentSettings"; } } } { // data OperatorMapSettingsContent req.operatorMapSettingsContent(operatorMapSettingsJson().constData()); } DEBUG_LOG(m_logger) << LOGFUNCTION << " filterDataUpdateRequest:" << ", OperatorId= " << req.operatorId() << ", screenId= " << req.screenId() << ", screenContainerId= " << req.screenContainerId() << ", Aes size = " << req.aesFilterContent().size() << ", SA size = " << req.symbolAppearanceContent().size() << ", BC size = " << req.buildingComponentsFilterContent().size() << ", OMS size = " << req.operatorMapSettingsContent().size(); // no request helper needed - we don't care (much) if this is received and // we don't want to disturb the current operator with this request even more fltFtc->filterDataUpdateRequest(req, nullptr); } QList InterfaceImpl::planOverlayList() const { if (!m_situationMap) return QList(); const SituationMap::OverlayHandler &overlayHandler = m_situationMap->overlayHandler(); return overlayHandler.overlays(); } // QList InterfaceImpl::planOverlayList() const QList InterfaceImpl::planOverlayIdsFromOperatorMapSettings(const QJsonValue &data) const { OperatorMapSettings oms; oms.fromJsonObject(data.toObject()); return oms.orderedOverlays; } // QVector InterfaceImpl::planOverlayIdsFromOperatorMapSettings() const QByteArray InterfaceImpl::planOverlayContent(int id) const { if (!m_situationMap) return QByteArray(); const SituationMap::OverlayHandler &overlayHandler = m_situationMap->overlayHandler(); if (!overlayHandler.containsOverlay(id)) return QByteArray(); return overlayHandler.content(id); } // QByteArray InterfaceImpl::planOverlayContent( int id ) const bool InterfaceImpl::planOverlaySetContent(int id, const QString &name, const QByteArray &xmlContent, bool isSnapshot) { TRACE_LOG(m_logger) << LOGFUNCTION << " START" << " id=" << id << " name='" << name << "'" << " isSnapshot=" << isSnapshot; if (!m_situationMap || !m_situationMap->isReady()) { ERROR_LOG(m_logger) << LOGFUNCTION << " Failure - map is not ready yet!!!"; return false; } SituationMap::OverlayHandler &overlayHandler = m_situationMap->overlayHandler(); return overlayHandler.setOverlay(id, tr("Plan '%1'").arg(name), xmlContent, isSnapshot); } // unsigned int InterfaceImpl::planOverlaySetContent( const QString & xmlContent ) bool InterfaceImpl::planOverlayRemove(int id) { if (!m_situationMap) return false; SituationMap::OverlayHandler &overlayHandler = m_situationMap->overlayHandler(); if (!overlayHandler.containsOverlay(id)) return false; return overlayHandler.removeOverlay(id); } // bool InterfaceImpl::planOverlayRemove(int id) void InterfaceImpl::planOverlayChangeOrder(const QVector &orderOfIds) { if (!m_situationMap || !m_situationMap->isReady()) { ERROR_LOG(m_logger) << LOGFUNCTION << " Failure - map is not ready yet!!!"; return; } SituationMap::OverlayHandler &overlayHandler = m_situationMap->overlayHandler(); overlayHandler.reorderOverlays(orderOfIds); } // void InterfaceImpl::planOverlayChangeOrder( QVector orderOfIds ) double InterfaceImpl::planOverlayOpacity(int id) { if (!m_situationMap) return 0.0; const SituationMap::OverlayHandler &overlayHandler = m_situationMap->overlayHandler(); if (!overlayHandler.containsOverlay(id)) return 0.0; return overlayHandler.opacity(id); } // double InterfaceImpl::planOverlayOpacity(int id) double InterfaceImpl::planOverlayMinScale(int id) { if (!m_situationMap) return 0.0; const SituationMap::OverlayHandler &overlayHandler = m_situationMap->overlayHandler(); if (!overlayHandler.containsOverlay(id)) return 0.0; return overlayHandler.minScale(id); } // double InterfaceImpl::planOverlayMinScale(int id) double InterfaceImpl::planOverlayMaxScale(int id) { if (!m_situationMap) return 0.0; const SituationMap::OverlayHandler &overlayHandler = m_situationMap->overlayHandler(); if (!overlayHandler.containsOverlay(id)) return 0.0; return overlayHandler.maxScale(id); } // double InterfaceImpl::planOverlayMaxScale(int id) bool InterfaceImpl::planOverlayVisibility(int id) { if (!m_situationMap) return false; const SituationMap::OverlayHandler &overlayHandler = m_situationMap->overlayHandler(); if (overlayHandler.containsOverlay(id)) return overlayHandler.overlayVisibility(id); return false; } // bool InterfaceImpl::planOverlayVisibility(int id) void InterfaceImpl::setPlanOverlayOpacity(int id, double opacity) { if (!m_situationMap) return; SituationMap::OverlayHandler &overlayHandler = m_situationMap->overlayHandler(); if (overlayHandler.containsOverlay(id)) overlayHandler.setOpacity(id, opacity); } // void InterfaceImpl::setPlanOverlayOpacity(int id, double opacity) void InterfaceImpl::setPlanOverlayMinScale(int id, double minScale) { DEBUG_LOG(m_logger) << LOGFUNCTION << " minScale= " << minScale; if (!m_situationMap) return; SituationMap::OverlayHandler &overlayHandler = m_situationMap->overlayHandler(); if (overlayHandler.containsOverlay(id)) overlayHandler.setMinScale(id, minScale); } // void InterfaceImpl::setPlanOverlayMinScale(int id, double minScale) void InterfaceImpl::setPlanOverlayMaxScale(int id, double maxScale) { DEBUG_LOG(m_logger) << LOGFUNCTION << " maxScale= " << maxScale; if (!m_situationMap) return; SituationMap::OverlayHandler &overlayHandler = m_situationMap->overlayHandler(); if (overlayHandler.containsOverlay(id)) overlayHandler.setMaxScale(id, maxScale); } // void InterfaceImpl::setPlanOverlayMaxScale(int id, double maxScale) void InterfaceImpl::setPlanOverlayVisibility(int id, bool on) { if (!m_situationMap) return; SituationMap::OverlayHandler &overlayHandler = m_situationMap->overlayHandler(); if (overlayHandler.containsOverlay(id)) overlayHandler.setOverlayVisibility(id, on); } // void InterfaceImpl::setPlanOverlayVisibility(int id, bool on) double InterfaceImpl::getCurrentMapScale() const { if (!m_situationMap || !m_situationMap->isReady()) { ERROR_LOG(m_logger) << LOGFUNCTION << " Failure - map is not ready yet!!!"; return 0.0; } return m_situationMap->scale(); } bool InterfaceImpl::toImage(QObject *context, const std::function &imageCompletedCallback) { Q_UNUSED(context); if (!m_situationMap) { ERROR_LOG(m_logger) << LOGFUNCTION << " no situationMap"; return false; } if (!(m_situationMap->isReady() && m_situationMap->isSymbolDictionaryLoaded())) { ERROR_LOG(m_logger) << LOGFUNCTION << " not ready yet"; return false; } bool isFireEventFlashingEnabled = false; if (m_situationMapInit) { isFireEventFlashingEnabled = m_situationMapInit->isFireEventFlashingEnabled(); if (!m_situationMapInit->enableFireEventFlashing(false)) ERROR_LOG(m_logger) << LOGFUNCTION << " enableFireEventFlashing failed"; } // no WaitDialog, otherwise toImageSync will grab that also :-( // LtsWidgets::LtsGlobalWaitDialog::getInstance()->wait(m_situationMap, tr("Creating image")); // give the Participant/SymbolResult time to finish fetching symbol: QTimer::singleShot(1000, this, [this, imageCompletedCallback, isFireEventFlashingEnabled]() { // use toImageSync since there is the pixelBaseTextBox as widget on top of the esri Widget: QImage image = m_situationMap->toImageSync(); // with TextBox, PositionString etc... if (m_situationMapInit) m_situationMapInit->enableFireEventFlashing(isFireEventFlashingEnabled); imageCompletedCallback(image); }); /* LtsWidgets::LtsGlobalWaitDialog::getInstance()->wait(m_situationMap, tr("Creating image")); // give the Participant/SymbolResult time to finish fetching symbol: QTimer::singleShot(1000, this, [this, context, imageCompletedCallback, isFireEventFlashingEnabled]() { LtsWidgets::LtsGlobalWaitDialog::getInstance()->done(); if (!context) return; if (!m_situationMap) return; if (!m_situationMapInit) return; const QUuid myTaskId = m_situationMap->toImage(); connect(m_situationMap.data(), &SituationMap::Map::imageCompleted, context, [this, myTaskId, imageCompletedCallback, isFireEventFlashingEnabled](const QUuid & taskId, const QImage & image) { if (myTaskId == taskId) { if (m_situationMapInit) m_situationMapInit->enableFireEventFlashing(isFireEventFlashingEnabled); imageCompletedCallback(image); } }); }); */ return true; } void InterfaceImpl::onSaveAsImageRequested() { auto cb = [this](const QImage & img) { auto ev = new LtsWidgets::SaveImageEvent(m_situationMap.data(), QPixmap::fromImage(img)); ev->setAccepted(false); QCoreApplication::postEvent(qApp, ev); }; toImage(this, cb); } bool InterfaceImpl::removePreviewObject() { // remove old PreviewObject: for (const UniqueMapId id : qAsConst(m_uniqueMapIdOfPreviewObject)) { if (m_situationMap->objectFactory().contains(id)) { RefPointer oldObj = m_situationMap->objectFactory().get(id); if (oldObj) oldObj->removeMySelf(); } } // for // cleanup: m_uniqueMapIdOfPreviewObject.clear(); return true; } /// /// \brief The LtsGlobalWaitDialogGuard class /// class LtsGlobalWaitDialogGuard : public QObject { public: LtsGlobalWaitDialogGuard(int objCount, const QString &customText) : m_objCount(objCount), m_customText(customText) { if (m_objCount > m_maxObjWithoutWaitDialog) LtsWidgets::LtsGlobalWaitDialog::getInstance()->wait(m_customText); } ~LtsGlobalWaitDialogGuard() { if (m_objCount > m_maxObjWithoutWaitDialog) LtsWidgets::LtsGlobalWaitDialog::getInstance()->done(); } private: int m_objCount{-1}; int m_maxObjWithoutWaitDialog {500}; // tuned on CTCAP15, maybe reduce for other device QString m_customText; }; void InterfaceImpl::onMapObjectsClickedByIds(const QVector &uniqueMapIds, bool supportWaitDialog) { // ScopedLockingIdiom int size = 0; if (supportWaitDialog) size = uniqueMapIds.size(); LtsGlobalWaitDialogGuard guard(size, tr("Preparing Map Objects ...")); // ScopedLockingIdiom: if (supportWaitDialog) { QTimer::singleShot(100, this, [this, uniqueMapIds]() { this->onMapObjectsClickedByIds(uniqueMapIds, false); //false -> no GlobalWaitDialog }); return; } const LtsWidgets::LayoutArea layoutArea = LtsWidgets::LayoutArea::eDialogTab; const QString &identifier = QStringLiteral("MapObjectSelection"); // create if not exists: if (!m_dialogMapObjectSelection) { m_dialogMapObjectSelection = QPointer(new SituationMap::MapObjectSelectionLtsDialog(m_situationMap.data())); if (m_dialogMapObjectSelection->init(m_situationMap.data(), m_situationMapInit->adapterDds(), m_pluginProvider->ppmDtc(), m_pluginProvider->ppmFtc(), m_pluginProvider->bldFtc())) { connect(m_dialogMapObjectSelection.data(), &SituationMap::MapObjectSelectionLtsDialog::mapObjectsClicked, m_situationMapInit.data(), &SituationMapInit::onProcessMapObjectClicked); connect(m_dialogMapObjectSelection.data(), &SituationMap::MapObjectSelectionLtsDialog::serviceMonitorRequested, this, &InterfaceImpl::onServiceMonitorRequested); m_session->addWidget(m_dialogMapObjectSelection.data(), menuGroup(), identifier, layoutArea); } else { ERROR_LOG(m_logger) << LOGFUNCTION << " MapObjectSelectionLtsDialog::init() failed"; delete m_dialogMapObjectSelection; } } if (!m_dialogMapObjectSelection) return; const bool bEnableServiceMonitorRequest = LtsSessionData::LtsSessionData::getInstance()->hasOperatorRight(OperatorRights::EquipmentCheckMonitorShow) && (m_session->app() != LtsAppDescriptor::App::OC) && (m_session->app() != LtsAppDescriptor::App::ResourceManager); m_dialogMapObjectSelection->enableServiceMonitorRequest(bEnableServiceMonitorRequest); m_dialogMapObjectSelection->focusDialog(menuGroup(), identifier, layoutArea); m_dialogMapObjectSelection->setMapObjectsToDisplay(uniqueMapIds); m_dialogMapObjectSelection->show(); } void InterfaceImpl::onMapObjectsClicked(const SituationMap::Map::RefPointerMapObjectList &mapObjList) { // to Ids: QVector uniqueMapIds; uniqueMapIds.reserve(mapObjList.size()); for (const auto &mapObj : mapObjList) if (mapObj && (isUniqueMapIdValid(mapObj->uniqueMapId()))) uniqueMapIds.append(mapObj->uniqueMapId()); onMapObjectsClickedByIds(uniqueMapIds); } void InterfaceImpl::onServiceMonitorRequested(const QVector &equipmentNumbers, bool replace) { if (!m_pluginProvider) return; if (m_pluginProvider->smoServiceMonitorIfc()) m_pluginProvider->smoServiceMonitorIfc()->showSingleServiceEquipmentCheck(equipmentNumbers, replace); } //private bool InterfaceImpl::checkSlots(QObject *objToInform, const char *signalToConnect, const char *replySlot, const char *errorSlot) { m_objToInform = objToInform; m_replySlot = getMethod(m_objToInform, replySlot, signalToConnect); if (m_replySlot.methodIndex() < 0) { assert(false); return false; } if (errorSlot) { const QByteArray baError = QByteArray::number(QSIGNAL_CODE) + "signalSignature(QString)"; m_errorSlot = getMethod(m_objToInform, errorSlot, baError.data()); if (m_errorSlot.methodIndex() < 0) return false; } else m_errorSlot = QMetaMethod(); return true; } QMetaMethod InterfaceImpl::getMethod(QObject *objectToInform, const char *slotToExecute, const char *signalSignature) { QMetaMethod ret; if (!slotToExecute || !objectToInform) return ret; int slotCode = slotToExecute[0] - '0'; // check if it's really a signal or slot if (slotCode != QSLOT_CODE && slotCode != QSIGNAL_CODE) return ret; slotToExecute++; // skip code const QMetaObject *mo = objectToInform->metaObject(); const QByteArray slot = QMetaObject::normalizedSignature(slotToExecute); const int indexOfSlot = mo->indexOfSlot(slot.data()); if (indexOfSlot < 0) return ret; QByteArray signal = QMetaObject::normalizedSignature(signalSignature); if (!QMetaObject::checkConnectArgs(signal.data(), slot.data())) return ret; return mo->method(indexOfSlot); } void InterfaceImpl::onError(SituationMap::RB::Rubberband *rb, const QString &errMsg) { if (rb) rb->deleteMySelf(); if (m_errorSlot.isValid()) m_replySlot.invoke(m_objToInform, Qt::QueuedConnection, Q_ARG(QString, errMsg)); } void InterfaceImpl::adjustMapAccordingRubberband(const QVector &coords) { if (!m_situationMap || !m_situationMap->isReady() || coords.isEmpty()) return; bool visible = false; const QRectF ¤tExtent = m_situationMap->extent(); for (auto coord : coords) if (currentExtent.contains(coord)) { visible = true; break; } DEBUG_LOG(m_logger) << LOGFUNCTION << " visible" << visible; if (!visible) m_situationMap->zoomToArea(coords, 100); } SituationMap::RB::RubberbandRectangle *InterfaceImpl::getRubberbandRectangle(QObject *objectToInform , bool finishAfterCreation , double minWidth , double maxWidth , double minHeight , double maxHeight) { SituationMap::RB::RubberbandRectangle *rubberband = createRubberband(objectToInform); if (!rubberband) return nullptr; rubberband->minHeight(minHeight); rubberband->maxHeight(maxHeight); rubberband->minWidth(minWidth); rubberband->maxWidth(maxWidth); rubberband->enableFinishAfterConstruction(finishAfterCreation); return rubberband; } SituationMap::RB::RubberbandMultiPointFeature *InterfaceImpl::getRubberbandMultiPoint(QObject *objectToInform, bool closed, int minPoints, int maxPoints, double minSegmentLength, double maxSegmentLength, const QPolygonF &coordinates) { Q_UNUSED(minSegmentLength); SituationMap::RB::RubberbandMultiPointFeature *rubberband = createRubberband(objectToInform); if (!rubberband) return nullptr; rubberband->enableClosed(closed); rubberband->minimumPointCount(minPoints); rubberband->maximumPointCount(maxPoints); rubberband->maximumLength(maxSegmentLength); if (!coordinates.isEmpty()) rubberband->setCoordinateVector(coordinates); return rubberband; } template T *InterfaceImpl::createRubberband(QObject *parent) { // remove any pending/active rubberbands of our map: SituationMap::RB::Rubberband::deleteAllActiveRubberbands(m_situationMap.data()); T *rb = m_situationMap->rubberbandFactory().create(parent); if (!rb || !rb->rubberbandIsAlive()) { onError(rb, QStringLiteral("Creating rubberband failed")); return nullptr; } rb->setAutoDelete(true); return rb; } void InterfaceImpl::doPrint() { // hide everything except for the main layout LtsWidgets::LtsBaseLayoutWidget *blw = m_session->baseLayout(); bool menuVisible = blw->isMenuVisible(); bool topBarVisible = blw->isTopBarVisible(); blw->setMenuVisible(false); blw->setTopBarVisible(false); blw->hideVisibleLayouts(); std::function onImage = [this, menuVisible, topBarVisible](const QImage & image) { // m_pluginProvider should contain the time the snapshot was taken :-) QString timeStr(QStringLiteral("-")); if (m_pluginProvider) timeStr = DTG::toStringMSec(m_pluginProvider->partitionTime()); LtsPrinting::printImage(m_session, m_ltsDialogSitMapWidget, image, timeStr, QString()); // done! restore LtsWidgets::LtsBaseLayoutWidget *blw = m_session->baseLayout(); blw->setMenuVisible(menuVisible); blw->setTopBarVisible(topBarVisible); blw->resetLayoutVisibility(); }; if (!toImage(this, onImage)) { ERROR_LOG(m_logger) << LOGFUNCTION << " toImage failed"; // error! restore blw->setMenuVisible(menuVisible); blw->setTopBarVisible(topBarVisible); blw->resetLayoutVisibility(); } } // class TopicReplayInterface: TopicReplayInterface::TopicReplayInterface() : m_startTimeSec(0) , m_durationSec(0) , m_logger(getLogger("TopicReplayInterface")) { } TopicReplayInterface::~TopicReplayInterface() {} QWidget *TopicReplayInterface::createWidget() { Q_ASSERT(false); return nullptr; } void TopicReplayInterface::setExportPlaybackTimes(qint64 startTimeSec, qint64 durationSec, const QVector &sitReplayTimes) { m_startTimeSec = startTimeSec; m_durationSec = durationSec; m_sitReplayTimes = sitReplayTimes; } bool TopicReplayInterface::exportTopic(const QJsonObject &attributes, const QString &folderPath, TopicEditorBase::ExportNotifier *pExportNotifier) { const QString filename(QStringLiteral("sitmap.json")); QFile f(folderPath + QLatin1Char('/') + filename); if (!f.open(QIODevice::WriteOnly)) { WARNING_LOG(m_logger) << "Can not open file '" << f.fileName() << "' for writing!"; pExportNotifier->setExportFailed(); return false; } QJsonObject obj; obj[QStringLiteral("attributes")] = attributes; obj[QStringLiteral("timeInPresentation")] = timeRange(m_startTimeSec * 1000, (m_startTimeSec + m_durationSec) * 1000); QJsonArray arr; for (const SituationReplayTime &rt : qAsConst(m_sitReplayTimes)) { if (m_startTimeSec > rt.topicEnd_s) continue; const double lenReplay = (rt.replayEnd_ms - rt.replayStart_ms) * rt.replaySpeedFactor; const double endReplay = rt.replayStart_ms + lenReplay; // TODO: check - looks not correct const double maxReplay = std::min(rt.replayStart_ms + m_durationSec * 1000. * rt.replaySpeedFactor, endReplay); arr.push_back(rt.toJson(maxReplay)); } obj[QStringLiteral("replays")] = arr; f.write(QJsonDocument(obj).toJson(QJsonDocument::Indented)); f.close(); if(arr.empty()) { bool ret = f.remove(); WARNING_LOG(m_logger) << " remove sitmap.json file with empty 'replays' ? " <setExportSuccessful({}); return true; } DEBUG_LOG(m_logger) << "SitMap filename: " << f.fileName(); pExportNotifier->setExportSuccessful(filename); return true; } } // namespace SituationMap