4365 lines
149 KiB
C++
Executable File
4365 lines
149 KiB
C++
Executable File
/**
|
||
* @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 ¢er, double scale, float durationSeconds)
|
||
{
|
||
CHECK_SMI;
|
||
m_situationMapInit->setCenterPoint(center, scale, durationSeconds);
|
||
}
|
||
|
||
void InterfaceImpl::centerMapToParticipant(int participantId)
|
||
{
|
||
CHECK_SMI;
|
||
m_situationMapInit->centerMapToParticipant(participantId);
|
||
}
|
||
|
||
void InterfaceImpl::centerMapToAesObject(int entityId)
|
||
{
|
||
CHECK_SMI;
|
||
m_situationMapInit->centerMapToAesObject(entityId);
|
||
}
|
||
|
||
void InterfaceImpl::centerMapToBuildingObject(int entityId)
|
||
{
|
||
CHECK_SMI;
|
||
m_situationMapInit->centerMapToBuildingObject(entityId);
|
||
}
|
||
|
||
void InterfaceImpl::centerMapToGuezIedObject(int entityId)
|
||
{
|
||
CHECK_SMI;
|
||
m_situationMapInit->centerMapToGuezIedObject(entityId);
|
||
}
|
||
|
||
void InterfaceImpl::centerMapToChargeEffectObject(int entityId)
|
||
{
|
||
CHECK_SMI;
|
||
m_situationMapInit->centerMapToChargeEffectObject(entityId);
|
||
}
|
||
|
||
void InterfaceImpl::centerMapToMapObject(MapObjectType mot, int entityId)
|
||
{
|
||
CHECK_SMI;
|
||
m_situationMapInit->centerMapToMapObject(mot, entityId);
|
||
}
|
||
|
||
void InterfaceImpl::zoomMapTo(const QVector<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> ¶llelLine = SituationMap::MathUtils::GeometryEngine::parallelTranslation(mapCtFunctor, line, distance/*, angleFault*/);
|
||
|
||
if (parallelLine.isEmpty())
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " Failure - calculation of parallel line failed! May be invalid input line!";
|
||
return QVector<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 ¢er, double openingAngle, double rotationDegNorth)
|
||
{
|
||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||
|
||
// verify mapReady
|
||
if (!m_situationMap || !m_situationMap->isReady())
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " Failure - map is not ready yet!!!";
|
||
return false;
|
||
}
|
||
// verify Mode:
|
||
if (m_situationMap && m_situationMap->mode() == Mode::Mode_3D)
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " requested Rubberband is not allowd in this mode.";
|
||
return false;
|
||
}
|
||
|
||
if (!checkSlots(objectToInform, SIGNAL(circleDataXY(QPointF, double, double, double)), replySlot, errorSlot))
|
||
return false;
|
||
|
||
|
||
SituationMap::RB::RubberbandEllipse *rubberband =
|
||
createRubberband<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 ¢er, double width, double height)
|
||
{
|
||
// verify mapReady
|
||
if (!m_situationMap || !m_situationMap->isReady())
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " Failure - map is not ready yet!!!";
|
||
return false;
|
||
}
|
||
// verify Mode:
|
||
if (m_situationMap && m_situationMap->mode() == Mode::Mode_3D)
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " requested Rubberband is not allowd in this mode.";
|
||
return false;
|
||
}
|
||
|
||
if (!checkSlots(objectToInform, SIGNAL(rectDataNorth(QPointF,double,double,QPolygonF)), replySlot, errorSlot))
|
||
return false;
|
||
|
||
SituationMap::RB::RubberbandRectangle *rubberband =
|
||
getRubberbandRectangle(objectToInform, false, widthMin, widthMax, heightMin, heightMax);
|
||
if (!rubberband)
|
||
return false;
|
||
|
||
if (!center.isNull())
|
||
{
|
||
rubberband->buildFromRectangleParamter(center, width, height, QPointF(1, 0));
|
||
adjustMapAccordingRubberband(rubberband->coordinateVector(RB::CoordinateSystem::Geo));
|
||
}
|
||
|
||
rubberband->constrainOrthogonal(true);
|
||
QObject::connect(rubberband, &SituationMap::RB::Rubberband::apply, this, [this, rubberband]()
|
||
{
|
||
// m_situationMap->setViewpoint2D(vp, 2);
|
||
|
||
QPointF center, direction;
|
||
double width = 0;
|
||
double height = 0;
|
||
rubberband->rectangleParameter(center, width, height, direction);
|
||
|
||
center = rubberband->centerPoint();
|
||
m_replySlot.invoke(m_objToInform, Qt::QueuedConnection,
|
||
Q_ARG(QPointF, center),
|
||
Q_ARG(double, width),
|
||
Q_ARG(double, height),
|
||
Q_ARG(QPolygonF, rubberband->coordinateVector())
|
||
);
|
||
|
||
});
|
||
if(m_errorSlot.isValid())
|
||
QObject::connect(rubberband, &SituationMap::RB::Rubberband::abort, this, [this]()
|
||
{
|
||
m_errorSlot.invoke(m_objToInform, Qt::QueuedConnection,
|
||
Q_ARG(QString, QLatin1String("rubberband Abborted")));
|
||
});
|
||
return true;
|
||
}
|
||
|
||
bool InterfaceImpl::getPolygon(QObject *objectToInform, const char *replySlot, const char *errorSlot, unsigned int minPoints, unsigned int maxPoints,
|
||
double minSegmentLength, double maxSegmentLength, const QPolygonF &coordinates)
|
||
{
|
||
// verify mapReady
|
||
if (!m_situationMap || !m_situationMap->isReady())
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " Failure - map is not ready yet!!!";
|
||
return false;
|
||
}
|
||
// verify Mode:
|
||
if (m_situationMap && m_situationMap->mode() == Mode::Mode_3D)
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " requested Rubberband is not allowd in this mode.";
|
||
return false;
|
||
}
|
||
|
||
if (!checkSlots(objectToInform, SIGNAL(polyData(QPolygonF)), replySlot, errorSlot))
|
||
return false;
|
||
|
||
SituationMap::RB::RubberbandMultiPointFeature *rubberband =
|
||
getRubberbandMultiPoint(objectToInform, true, minPoints, maxPoints, minSegmentLength, maxSegmentLength, coordinates);
|
||
if (!rubberband)
|
||
return false;
|
||
|
||
adjustMapAccordingRubberband(rubberband->coordinateVector(RB::CoordinateSystem::Geo));
|
||
|
||
QObject::connect(rubberband, &SituationMap::RB::Rubberband::apply, this, [this, rubberband]()
|
||
{
|
||
m_replySlot.invoke(m_objToInform, Qt::QueuedConnection,
|
||
Q_ARG(QPolygonF, rubberband->coordinateVector()));
|
||
});
|
||
if(m_errorSlot.isValid())
|
||
QObject::connect(rubberband, &SituationMap::RB::Rubberband::abort, this, [this]()
|
||
{
|
||
m_errorSlot.invoke(m_objToInform, Qt::QueuedConnection,
|
||
Q_ARG(QString, QLatin1String("rubberband Abborted")));
|
||
});
|
||
return true;
|
||
}
|
||
|
||
bool InterfaceImpl::getPolyline(QObject *objectToInform, const char *replySlot, const char *errorSlot,
|
||
unsigned int minPoints, unsigned int maxPoints,
|
||
double minSegmentLength, double maxSegmentLength,
|
||
const QPolygonF &coordinates)
|
||
{
|
||
// verify mapReady
|
||
if (!m_situationMap || !m_situationMap->isReady())
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " Failure - map is not ready yet!!!";
|
||
return false;
|
||
}
|
||
// verify Mode:
|
||
if (m_situationMap && m_situationMap->mode() == Mode::Mode_3D)
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " requested Rubberband is not allowd in this mode.";
|
||
return false;
|
||
}
|
||
|
||
if (!checkSlots(objectToInform, SIGNAL(polyData(QPolygonF)), replySlot, errorSlot))
|
||
return false;
|
||
|
||
SituationMap::RB::RubberbandMultiPointFeature *rubberband =
|
||
getRubberbandMultiPoint(objectToInform, false, minPoints, maxPoints, minSegmentLength, maxSegmentLength, coordinates);
|
||
if (!rubberband)
|
||
return false;
|
||
|
||
adjustMapAccordingRubberband(rubberband->coordinateVector(RB::CoordinateSystem::Geo));
|
||
|
||
QObject::connect(rubberband, &SituationMap::RB::Rubberband::apply, this, [this, rubberband]()
|
||
{
|
||
m_replySlot.invoke(m_objToInform, Qt::QueuedConnection,
|
||
Q_ARG(QPolygonF, rubberband->coordinateVector()));
|
||
});
|
||
if(m_errorSlot.isValid())
|
||
QObject::connect(rubberband, &SituationMap::RB::Rubberband::abort, this, [this]()
|
||
{
|
||
m_errorSlot.invoke(m_objToInform, Qt::QueuedConnection,
|
||
Q_ARG(QString, QLatin1String("rubberband Abborted")));
|
||
});
|
||
return true;
|
||
}
|
||
|
||
void InterfaceImpl::cancelActiveRubberbands()
|
||
{
|
||
if (!m_situationMap)
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " no situationMap";
|
||
return;
|
||
}
|
||
|
||
// remove any pending/active rubberbands of our map:
|
||
SituationMap::RB::Rubberband::deleteAllActiveRubberbands(m_situationMap.data());
|
||
}
|
||
|
||
bool InterfaceImpl::displayPreviewObject(QObject *parent, const QPolygonF &poly, bool closed)
|
||
{
|
||
// return displayPreviewObjects(parent, {poly}, closed); // DO NOT
|
||
return displayPreviewObjects(parent, QVector<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 ¢erGeo, double radius)
|
||
{
|
||
// return displayPreviewObjects(parent, {centerGeo}, radius); // DO NOT
|
||
return displayPreviewObjects(parent, QVector<QPointF>() << centerGeo, radius);
|
||
}
|
||
|
||
bool InterfaceImpl::displayPreviewObjects(QObject *parent, const QVector<QPointF> ¢erGeoVec, double radius)
|
||
{
|
||
// verify mapReady
|
||
if (!m_situationMap || !m_situationMap->isReady())
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " Failure - map is not ready yet!!!";
|
||
return false;
|
||
}
|
||
|
||
// remove old PreviewObject:
|
||
removePreviewObject();
|
||
|
||
// create new PreviewObject:
|
||
const QString &logicalLayerRubberband = m_situationMap->layerFactory().rubberbandLayer();
|
||
bool success = true;
|
||
|
||
QColor lineCol = Qt::magenta;
|
||
lineCol.setAlpha(150);
|
||
|
||
LineStyle lineStyle(lineCol, 3);
|
||
lineStyle.setLinePattern(LinePattern::Dash);
|
||
|
||
QColor fillCol = lineCol;
|
||
fillCol.setAlpha(64);
|
||
|
||
for (const QPointF ¢erGeo : centerGeoVec)
|
||
{
|
||
RefPointer<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 ¢erPoint, double radius, double rotationDeg, double centralAngleDeg)
|
||
{
|
||
// verify mapReady
|
||
if (!m_situationMap || !m_situationMap->isReady())
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << " Failure - map is not ready yet!!!";
|
||
return false;
|
||
}
|
||
|
||
// remove old PreviewObject:
|
||
removePreviewObject();
|
||
|
||
// create new PreviewObject:
|
||
const QString &logicalLayerRubberband = m_situationMap->layerFactory().rubberbandLayer();
|
||
bool success = true;
|
||
|
||
QColor lineCol = Qt::magenta;
|
||
lineCol.setAlpha(150);
|
||
|
||
LineStyle lineStyle(lineCol, 3);
|
||
lineStyle.setLinePattern(LinePattern::Dash);
|
||
|
||
QColor fillCol = lineCol;
|
||
fillCol.setAlpha(64);
|
||
|
||
// introduced for BoobyTraps:
|
||
QPolygonF polyVec = SituationMap::MathUtils::getCircleSectorPolygon(centerPoint, radius, rotationDeg, centralAngleDeg);
|
||
|
||
PositionCont posCont = convert2D3D(polyVec);
|
||
|
||
RefPointer<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 ¤tExtent = m_situationMap->extent();
|
||
|
||
for (auto coord : coords)
|
||
if (currentExtent.contains(coord))
|
||
{
|
||
visible = true;
|
||
break;
|
||
}
|
||
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION << " visible" << visible;
|
||
|
||
if (!visible)
|
||
m_situationMap->zoomToArea(coords, 100);
|
||
}
|
||
|
||
SituationMap::RB::RubberbandRectangle *InterfaceImpl::getRubberbandRectangle(QObject *objectToInform
|
||
, bool finishAfterCreation
|
||
, double minWidth
|
||
, double maxWidth
|
||
, double minHeight
|
||
, double maxHeight)
|
||
{
|
||
SituationMap::RB::RubberbandRectangle *rubberband =
|
||
createRubberband<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
|