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

4365 lines
149 KiB
C++
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* @RDE_HEADER@
* 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 <Common/situation_map_logging.h>
#include <ngltools/ngltools_dtg.h>
#include <LtsPrinting/printing.h>
#include <LtsSession/lts_session.h>
#include <LtsWidgets/lts_base_layout_widget.h> // findChild
#include <LtsWidgets/lts_events.h>
#include <LtsWidgets/lts_global_wait_dialog.h>
#include <LtsUtilsSettings/settings.h>
#include <LtsAppManager/lts_app_manager.h>
#include <BuildingViewer/bdv_viewer_gui_plugin_interface.h>
#include <FilterManagement/flt_data_plugin_interface.h>
#include <FilterManagement/flt_data_plugin_aes_display_filter.h>
#include <FilterManagement/flt_symbol_appearance_settings.h>
#include <FilterManagement/flt_building_cmpnt_settings.h>
#include <Services/ServiceMonitor/smo_operator_rights.h>
#include <Services/SituationMap/map_operator_rights.h>
#include <Map/map_notifier.h>
#include <Map/layer_factory.h>
#include <Map/measurement.h>
#include <Map/geometry_model_renderer.h>
#include <Map/object_factory.h>
#include <Map/operator_map_settings.h>
#include <Map/overlay_handler.h>
#include <MapObjects/polygon.h>
#include <MapObjects/polyline.h>
#include <MathUtils/geometry_engine.h>
#include <LayerAggregation/layer_aggregation_widget.h>
#include <LayerAggregation/participant_aggregation_dialog.h>
#include <MapObjects/participant.h>
#include <MapObjects/chemical_agent.h>
#include <MapObjects/geometry.h>
#include <GeometryModel/geometry_model_factory.h>
#include <Symbology/symbol_dictionary.h>
#include <LtsCoordTrans/lts_coord_trans.h>
#include <LtsNotification/lts_notification.h>
#include <LtsWidgets/lts_message_dialog.h>
#include <MathUtils/simple_helper.h>
#include <MathUtils/math_const.h>
#include <QCoreApplication>
#include <QLocale>
#include <QLayout>
#include <QFormLayout>
#include <QJsonDocument>
#include <QJsonParseError>
#include <QUuid>
#include <QIcon>
#include <math.h>
#include <Map/viewshed.h>
// LocalServer
// #define USE_LOCAL_SERVER
#ifdef USE_LOCAL_SERVER
# include <LocalSrv/local_server.h>
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 <QThread>
// 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<GuiPluginBase::Interface> GuiPlugin::createGuiInterface(LtsSession::LtsSession *session)
{
return std::make_shared<InterfaceImpl>(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<LtsWidgets::PluginData> InterfaceImpl::getActions()
{
QVector<LtsWidgets::PluginData> 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<BuildingViewer::ForeignGuiInterface> bdvGuiIfc;
m_session->getForeignGuiInterface<BuildingViewer::ForeignGuiInterface>(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<int>(m_session->app());
// mandatory
if (!m_session->getForeignGuiInterface<AdvancedSymbology::ForeignGuiFlmSymbolsProxyInterface>(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<FilterManagement::Interface::Dtc> 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 <typename T>
void deleteLaterClear(QPointer<T> &ptr)
{
if (!ptr)
return;
ptr->deleteLater();
ptr = nullptr;
}
template <typename T>
void deleteClear(QPointer<T> &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<SituationMap::MovementTrackManager>(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<FilterManagement::ForeignFltParticipantGuiInterface> fltParticipantIfc = m_pluginProvider->fltParticipantIfc();
std::shared_ptr<FilterManagement::ForeignAesGuiInterface> fltAesIfc = m_pluginProvider->fltAesIfc();
std::shared_ptr<FilterManagement::SymbolAppearanceSettings> preventDestruction1;
std::shared_ptr<FilterManagement::AesDisplayFilter> 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> 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<LtsWidgets::LtsDragIcon *>(QStringLiteral("SituationMap-MapWidget"));
// menueBtnLayerControl = baseLayout->findChild<LtsWidgets::LtsDragIcon*>(QStringLiteral("LayerControl"));
menueBtnParticipantAggregation = baseLayout->findChild<LtsWidgets::LtsDragIcon *>(QStringLiteral("SituationMap-ParticipantAggregation"));
menueBtnRocket = baseLayout->findChild<LtsWidgets::LtsDragIcon *>(QStringLiteral("SituationMap-Rocket"));
menueBtnStartMeasurement = baseLayout->findChild<LtsWidgets::LtsDragIcon *>(QStringLiteral("SituationMap-MeasureLength"));
menueBtnClearMeasurement = baseLayout->findChild<LtsWidgets::LtsDragIcon *>(QStringLiteral("SituationMap-clearMeasurement"));
menueBtnStartTerrainProfile = baseLayout->findChild<LtsWidgets::LtsDragIcon *>(QStringLiteral("SituationMap-TerrainProfile"));
menueBtnClearTerrainProfile = baseLayout->findChild<LtsWidgets::LtsDragIcon *>(QStringLiteral("SituationMap-clearTerrainProfile"));
menueBtnStartViewshed = baseLayout->findChild<LtsWidgets::LtsDragIcon *>(QStringLiteral("SituationMap-Viewshed"));
menueBtnClearViewshed = baseLayout->findChild<LtsWidgets::LtsDragIcon *>(QStringLiteral("SituationMap-clearViewshed"));
menueBtnBuildingOwnership = baseLayout->findChild<LtsWidgets::LtsDragIcon *>(QStringLiteral("SituationMap-ShowBuildingOwnership"));
menueBtnBuildingContamination = baseLayout->findChild<LtsWidgets::LtsDragIcon *>(QStringLiteral("SituationMap-ShowBuildingContamination"));
menueBtn3dBuildingsVisible = baseLayout->findChild<LtsWidgets::LtsDragIcon *>(QStringLiteral("SituationMap-3D_Buildings"));
menueBtnConfigureMapUrls = baseLayout->findChild<LtsWidgets::LtsDragIcon *>(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<Map> 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<void()> &mapReadyCallback)
{
if (m_situationMap.isNull())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no situationMap";
return false;
}
QPointer<SituationMap::MapNotifier> 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<MapMode>(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<void ()> &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<void (const QVector<int32_t> &activeSimIds)> &movementTrackCallback)
{
if (m_situationMapInit.isNull())
{
ERROR_LOG(m_logger) << LOGFUNCTION << " no m_situationMapInit";
return false;
}
QPointer<SituationMap::MovementTrackManager> 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 &center, 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<QPair<MapObjectType, int> > &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<int> &entityIds)
{
CHECK_SMI_RETVAL;
const QVector<UniqueMapId> &uniqueMapIdVec = m_situationMapInit->simIds2UniqueMapIds(mot, entityIds);
if (uniqueMapIdVec.isEmpty())
return false;
onMapObjectsClickedByIds(uniqueMapIdVec);
return true;
}
bool InterfaceImpl::openMapObjectSelection(const QVector<MapObjectTypeEntityId> &mapObjectTypeEntityIdPairs)
{
CHECK_SMI_RETVAL;
QVector<UniqueMapId> 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<int> &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<SituationMap::RB::RubberbandPointFeature>(objectToInform);
if (!rubberband)
return false;
QObject::connect(rubberband, &SituationMap::RB::Rubberband::apply, this, [this, rubberband]()
{
const QVector<QPointF> 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<SituationMap::RB::RubberbandPointFeature3D>(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<QPointF> 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<QPointF> &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<QPointF>,QPolygonF)), replySlot, errorSlot))
return false;
SituationMap::RB::RubberbandCorridor *rubberband =
createRubberband<SituationMap::RB::RubberbandCorridor>(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<QPointF>, 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<QPointF> InterfaceImpl::getParallelTranslation(const QVector<QPointF> &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<QPointF>();
}
if (line.size() < 2)
{
ERROR_LOG(m_logger) << LOGFUNCTION << " Failure - line has less than 2 coordinates!!!";
return QVector<QPointF>();
}
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<QPointF>();
}
const QVector<QPointF> &parallelLine = 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<QPointF>();
}
return parallelLine;
} // QVector<QPointF> InterfaceImpl::getParallelTranslation(const QVector<QPointF> &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<SituationMap::RB::RubberbandEllipse>(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<QPointF> 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 &center, 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<SituationMap::RB::RubberbandEllipse>(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<QPointF> 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<SituationMap::RB::RubberbandMultiEllipseFeature>(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<QPointF> 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<SituationMap::RB::RubberbandMultiEllipseFeature>(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<RWC> radii = { {radius1Initial, radius1Min, radius1Max}, // radius, minRadius, maxRadius
{radius2Initial, radius2Min, radius2Max} } ;
rubberband->prepareFixedNumberOfRadiiWithConstraints( radii );
}
else
{
QVector<QPointF> 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<QPointF> &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 &center, 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<QPolygonF>() << poly, closed);
}
bool InterfaceImpl::displayPreviewObjects(QObject *parent, const QVector<QPolygonF> &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<Polygon> tempRbObject = m_situationMap->objectFactory().create<Polygon>(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<Polyline> tempRbObject = m_situationMap->objectFactory().create<Polyline>(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 &centerGeo, double radius)
{
// return displayPreviewObjects(parent, {centerGeo}, radius); // DO NOT
return displayPreviewObjects(parent, QVector<QPointF>() << centerGeo, radius);
}
bool InterfaceImpl::displayPreviewObjects(QObject *parent, const QVector<QPointF> &centerGeoVec, 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 &centerGeo : centerGeoVec)
{
RefPointer<ChemicalAgent> tempRbObject = m_situationMap->objectFactory().create<ChemicalAgent>(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 &centerPoint, 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<Polygon> tempRbObject = m_situationMap->objectFactory().create<Polygon>(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<PreviewCircleData> &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<ChemicalAgent> tempObject = m_situationMap->objectFactory().create<ChemicalAgent>(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<LinePattern>(previewCircle.linePattern));
tempObject->setLineStyle(ls);
const FillStyle fs(previewCircle.fillColor,
static_cast<FillPattern>(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<ChemicalAgent> ocSituationRangeObject =
m_situationMap->objectFactory().create<ChemicalAgent>(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> 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<ChemicalAgent> ocSituationRangeObject =
m_situationMap->objectFactory().get<ChemicalAgent>(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<ChemicalAgent> ocSituationRangeObject =
m_situationMap->objectFactory().get<ChemicalAgent>(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<Polygon> escOrderAreaPositionObject =
m_situationMap->objectFactory().create<Polygon>(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<ChemicalAgent> escOrderStartPositionObject =
m_situationMap->objectFactory().create<ChemicalAgent>(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<Polygon> escOrderAreaPositionObject =
m_situationMap->objectFactory().get<Polygon>(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<ChemicalAgent> escOrderStartPositionObject =
m_situationMap->objectFactory().get<ChemicalAgent>(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<ChemicalAgent> escOrderStartPositionObject =
m_situationMap->objectFactory().get<ChemicalAgent>(m_escOrderStartPosition.uniqueMapId);
if (!escOrderStartPositionObject)
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " not found";
return false;
}
escOrderStartPositionObject->removeMySelf();
}
if (isUniqueMapIdValid(m_escOrderAreaPosition.uniqueMapId))
{
RefPointer<Polygon> escOrderAreaPositionObject =
m_situationMap->objectFactory().get<Polygon>(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<ChemicalAgent> escOrderStartPositionObject =
m_situationMap->objectFactory().get<ChemicalAgent>(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<ChemicalAgent> ocSituationRangeObject =
m_situationMap->objectFactory().get<ChemicalAgent>(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<QPointF> 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<SituationMap::MovementTrackManager> 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<Mode>(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<int> orderedOverlayIds = oms.orderedOverlays;
INFO_LOG(m_logger) << LOGFUNCTION << " restore OverlayIds: " << orderedOverlayIds;
QVector<int> unloadableOverlayIds;
if (!orderedOverlayIds.isEmpty())
{
std::shared_ptr<PlanOverlaysPlugin::ForeignGuiInterface> ovrDtc;
if (m_session->getForeignGuiInterface<PlanOverlaysPlugin::ForeignGuiInterface>(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<LtsAppDescriptor::App> 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<double>(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<FilterManagement::Interface::Ftc> fltFtc = m_pluginProvider->fltFtc();
std::shared_ptr<FilterManagement::ForeignFltParticipantGuiInterface> fltParticipantIfc = m_pluginProvider->fltParticipantIfc();
std::shared_ptr<FilterManagement::ForeignAesGuiInterface> fltAesIfc = m_pluginProvider->fltAesIfc();
// Nachtrag zu GUEZE-1769: since fltBuildingComponentIfc is optional:
std::shared_ptr<FilterManagement::ForeignFltBuildingComponentGuiInterface> 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<FilterManagement::AesDisplayFilter> 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<FilterManagement::SymbolAppearanceSettings> 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<FilterManagement::BuildingComponentSettings> 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<int> InterfaceImpl::planOverlayList() const
{
if (!m_situationMap)
return QList<int>();
const SituationMap::OverlayHandler &overlayHandler = m_situationMap->overlayHandler();
return overlayHandler.overlays();
} // QList<int> InterfaceImpl::planOverlayList() const
QList<int> InterfaceImpl::planOverlayIdsFromOperatorMapSettings(const QJsonValue &data) const
{
OperatorMapSettings oms;
oms.fromJsonObject(data.toObject());
return oms.orderedOverlays;
} // QVector<int> 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<int> &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<int> 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<void(const QImage &)> &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<AbstractMapObject> 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<SituationMap::UniqueMapId> &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<SituationMap::MapObjectSelectionLtsDialog>(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<UniqueMapId> 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<int> &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<QPointF> &coords)
{
if (!m_situationMap || !m_situationMap->isReady() || coords.isEmpty())
return;
bool visible = false;
const QRectF &currentExtent = 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<SituationMap::RB::RubberbandRectangle>(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<SituationMap::RB::RubberbandMultiPointFeature>(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<typename T>
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<T>(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<void(const QImage &)> 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<SituationReplayTime> &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' ? " <<ret;
pExportNotifier->setExportSuccessful({});
return true;
}
DEBUG_LOG(m_logger) << "SitMap filename: " << f.fileName();
pExportNotifier->setExportSuccessful(filename);
return true;
}
} // namespace SituationMap