651 lines
22 KiB
C++
Executable File
651 lines
22 KiB
C++
Executable File
/**
|
||
* @RDE_HEADER@
|
||
* Handle situation display in thp
|
||
* $Id$
|
||
* $HeadURL$
|
||
* $Author$
|
||
*/
|
||
|
||
#include "thp_situation_widget.h"
|
||
#include "ui_thp_situation_building_base.h"
|
||
|
||
#include "thp_situation_filter_aes.h"
|
||
#include "thp_situation_filter_symbol_appearance.h"
|
||
#include "thp_situation_filter_collapse_expand.h"
|
||
#include "thp_situation_filter_types.h"
|
||
#include "thp_situation_filter_building_components.h"
|
||
#include "thp_plugin_provider.h"
|
||
|
||
#include <QDir>
|
||
#include <QFileInfo>
|
||
#include <QJsonDocument>
|
||
#include <QJsonObject>
|
||
#include <QJsonParseError>
|
||
#include <QKeyEvent>
|
||
#include <QMenu>
|
||
#include <QMessageBox>
|
||
#include <QPainter>
|
||
#include <QSvgRenderer>
|
||
#include <QTimer>
|
||
#include <QThread>
|
||
#include <FileManagement/flm_db_structs.h>
|
||
#include <FilterManagement/flt_participant_plugin_interface.h>
|
||
#include <FilterManagement/flt_aes_plugin_interface.h>
|
||
#include <FilterManagement/flt_building_cmpnt_plugin_interface.h>
|
||
#include <FilterManagement/flt_building_cmpnt_settings.h>
|
||
#include <FilterManagement/Gui/Aes/Common/aes_display_filter_impl.h>
|
||
#include <FilterManagement/Gui/Aes/Common/symbol_appearance_settings_impl.h>
|
||
|
||
#include <SituationReplay/handler_situation_replay_sqlite.h>
|
||
|
||
#include <SituationMap/situation_map_init.h>
|
||
#include <SituationMap/Utils/movement_track_manager.h>
|
||
#include <SituationMap/Map/grid.h>
|
||
#include <SituationMap/Map/point3D.h>
|
||
#include <SituationMap/Map/map_initializer.h>
|
||
#include <SituationMap/Map/map_notifier.h>
|
||
#include <SituationMap/Map/operator_map_settings.h>
|
||
#include <SituationMap/Map/overlay_handler.h>
|
||
#include <SituationMap/Symbology/sidc_codec.h>
|
||
#include <PlanOverlays/Gui/plan_overlay_model.h>
|
||
|
||
#include <LtsCoordTrans/lts_coord_trans.h>
|
||
#include <NGLLogger/INGLLogger.h>
|
||
#include <ngltools/ngltools_dtg.h>
|
||
|
||
namespace THP
|
||
{
|
||
|
||
class MySitMapIinit final : public SituationMap::SituationMapInit
|
||
{
|
||
Q_OBJECT
|
||
public:
|
||
using SituationMap::SituationMapInit::SituationMapInit;
|
||
|
||
bool trainingAreaExists() const override { return true; }
|
||
SituationMap::MapSettingsJson getMapSettingsFromService() const override { return m_mapSettingsJson; }
|
||
void setMapSettingsJson(const SituationMap::MapSettingsJson &settings) { m_mapSettingsJson = settings; }
|
||
const SituationMap::MapSettingsJson & getMapSettingsJson() const { return m_mapSettingsJson; }
|
||
|
||
private:
|
||
SituationMap::MapSettingsJson m_mapSettingsJson;
|
||
};
|
||
|
||
using namespace SituationReplay;
|
||
|
||
SituationWidget::SituationWidget(QWidget *parent)
|
||
: SituationBuildingBase("THP.SituationWidget", parent)
|
||
, m_pluginProvider(new SitMapPluginProvider)
|
||
, m_situationMapInit(new MySitMapIinit(nullptr))
|
||
{
|
||
QMenu *m = new QMenu(m_ui->btnFilter);
|
||
m->addAction(tr("AES Filter"), this, &SituationWidget::onFilterAes);
|
||
// 29.09.2022, Norbert Thoden
|
||
// SWPÄ 2:22 GUEZE-1477 Kartenfilter für Komponenten:
|
||
// Es wurde der Komponenten Filter eingeführt.
|
||
// in der LiveLage werden allerdings nur MountingPoints angezeigt, die auch eine
|
||
// zugeordnetes Asset haben. Die Zuordnug befindet sich in der Tabelle ism.sim_mounting_point_asset.
|
||
// ism.sim_mounting_point_asset wird derzeit nicht in die sitreplay.sqlite
|
||
// überführt. Es koennen also keine Komponenten angezeigt / gefiltert werden...
|
||
// FilterDialog nicht anzeigen:
|
||
// m->addAction(tr("Building / Component"), this, &SituationWidget::onFilterBuildingComponent);
|
||
|
||
m->addAction(tr("Symbol Appearance"), this, &SituationWidget::onFilterSymbolAppearance);
|
||
m->addAction(tr("Collpase/Expand"), this, &SituationWidget::onFilterCollapseExpand);
|
||
m->addAction(tr("Type filter"), this, &SituationWidget::onFilterTypes);
|
||
m_ui->btnFilter->setMenu(m);
|
||
}
|
||
|
||
SituationWidget::~SituationWidget()
|
||
{
|
||
if (m_replayHandler->handlerSrp())
|
||
m_replayHandler->handlerSrp()->onStopReplayRequest();
|
||
delete m_situationMapInit;
|
||
delete m_pluginProvider;
|
||
delete m_replayHandler;
|
||
}
|
||
|
||
bool SituationWidget::init(const QString &homePath, int exerciseId)
|
||
{
|
||
m_pluginProvider->setExerciseId(exerciseId);
|
||
delete m_replayHandler;
|
||
m_replayHandler = new SituationReplay::MainHandlerSqlite;
|
||
|
||
if (!SituationBuildingBase::init(m_replayHandler))
|
||
return false;
|
||
|
||
loadLayerMappings(homePath);
|
||
|
||
SituationReplay::ConnectionParams connParams;
|
||
connParams.domainId = 1;
|
||
connParams.partitionId = 1;
|
||
if (!m_replayHandler->initDds(connParams))
|
||
return false;
|
||
|
||
if (!m_pluginProvider->init(m_replayHandler->ddsReplay()))
|
||
return false;
|
||
if (!m_situationMapInit->initPluginProvider(m_pluginProvider))
|
||
return false;
|
||
|
||
QPointer<SituationMap::MovementTrackManager> movementTrackMgr =
|
||
QPointer<SituationMap::MovementTrackManager>(new SituationMap::MovementTrackManager(m_situationMapInit));
|
||
|
||
FATAL_LOG(m_logger) << LOGFUNCTION << " XXXX initMap....";
|
||
|
||
if (!m_situationMapInit->initMap(false, SituationMap::Mode::Mode_2D))
|
||
return false;
|
||
|
||
if (!m_situationMapInit->initAdapter(movementTrackMgr, false))
|
||
return false;
|
||
|
||
SituationMap::Map *map = m_situationMapInit->getWidget();
|
||
if (!map)
|
||
return false;
|
||
|
||
connect(map, &SituationMap::Map::mouseGeoPositionChanged,
|
||
this, &SituationWidget::updatePositionLabel,
|
||
Qt::UniqueConnection);
|
||
connect(map, &SituationMap::Map::extentChanged,
|
||
this, &SituationWidget::updateZoomSlider);
|
||
|
||
map->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||
m_ui->vLayout->insertWidget(0, map);
|
||
|
||
m_aesDisplayFilter = m_pluginProvider->fltAesIfc()->aesFilterForOperator(0, QString());
|
||
m_symbolAppaearanceSettings = m_pluginProvider->fltParticipantIfc()->symbolAppearanceForOperator(0, QString());
|
||
m_buildingComponentSettings = m_pluginProvider->fltBuildingComponentIfc()->buildingComponentSettingsForOperator(0, QString());
|
||
|
||
return true;
|
||
}
|
||
|
||
bool SituationWidget::showSituationInternal()
|
||
{
|
||
// cleanup 'old' map:
|
||
// remove old overlays from former session:
|
||
{
|
||
SituationMap::Map *map = m_situationMapInit->getWidget();
|
||
if (map)
|
||
map->overlayHandler().removeAllOverlays();
|
||
}
|
||
|
||
|
||
m_ui->cbPlaybackParts->setVisible(m_replayInformation.size() > 1);
|
||
|
||
// MAYBE there are filter to be applied:
|
||
applyFilterFromReplayConfigFile();
|
||
|
||
if (m_replayInformation.isEmpty())
|
||
{
|
||
WARNING_LOG(m_logger) << "No replay information given...";
|
||
return false;
|
||
}
|
||
|
||
const QString sqliteDb = m_replayInformation.first().databaseFilePath;
|
||
if (sqliteDb.isEmpty())
|
||
{
|
||
WARNING_LOG(m_logger) << "No database given...";
|
||
return false;
|
||
}
|
||
QFileInfo fi(sqliteDb);
|
||
if (!fi.exists() || !fi.isFile() || !fi.isReadable())
|
||
{
|
||
Q_ASSERT(false);
|
||
WARNING_LOG(m_logger) << "Can not access sqlite database '" << fi.absoluteFilePath() << "'";
|
||
return false;
|
||
}
|
||
|
||
m_ui->cbPlaybackParts->clear();
|
||
m_ui->cbPlaybackParts->blockSignals(true);
|
||
for (int i = 0; i < m_replayInformation.size(); ++i)
|
||
{
|
||
const ReplayInformation &info = m_replayInformation.at(i);
|
||
m_ui->cbPlaybackParts->addItem(QStringLiteral("%1: %2 - %3").arg(i+1).arg(DTG::toStringMSec(info.timeSpan.begin, DTG::Long),
|
||
DTG::toStringMSec(info.timeSpan.end, DTG::Long)), i);
|
||
}
|
||
m_ui->cbPlaybackParts->setCurrentIndex(0);
|
||
m_ui->cbPlaybackParts->blockSignals(false);
|
||
onCbPlaybackPartsChanged(); // creates replayHandler for correct db etc.
|
||
|
||
SituationMap::Map *map = m_situationMapInit->getWidget();
|
||
if (map->isReady())
|
||
QTimer::singleShot(0, this, &SituationWidget::onInitDone);
|
||
else
|
||
connect(map, &SituationMap::Map::mapReady,
|
||
this, &SituationWidget::onInitDone, Qt::QueuedConnection);
|
||
|
||
return true;
|
||
}
|
||
|
||
bool SituationWidget::applyFilterFromReplayConfigFile()
|
||
{
|
||
// Maybe the Situation topic has own Filter (AesFilter, SymbolAppearance; OperatorMapSettings)
|
||
// Read and apply them:
|
||
if (m_replayInformation.isEmpty())
|
||
{
|
||
WARNING_LOG(m_logger) << "No replay information given...";
|
||
return false;
|
||
}
|
||
|
||
const QString replayConfigFile = m_replayInformation.first().replayConfigPath; // sitreplay.json
|
||
if (replayConfigFile.isEmpty())
|
||
{
|
||
WARNING_LOG(m_logger) << "No replayConfigFile given...";
|
||
return false;
|
||
}
|
||
|
||
QFileInfo fi(replayConfigFile);
|
||
if (!fi.exists() || !fi.isFile() || !fi.isReadable())
|
||
{
|
||
WARNING_LOG(m_logger) << "Can not access replayConfigFile '" << fi.absoluteFilePath() << "'";
|
||
return false;
|
||
}
|
||
|
||
QFile f(replayConfigFile);
|
||
if (!f.open(QIODevice::ReadOnly))
|
||
{
|
||
WARNING_LOG(m_logger) << "Can not open replayConfigFile '" << fi.absoluteFilePath() << "': " << f.errorString();
|
||
return false;
|
||
}
|
||
|
||
QJsonParseError jError;
|
||
const QByteArray ba = f.readAll();
|
||
QJsonDocument doc(QJsonDocument::fromJson(ba, &jError));
|
||
if (jError.error)
|
||
{
|
||
WARNING_LOG(m_logger) << "Can not parse json document: "
|
||
<< ", replayConfigFile '" << fi.absoluteFilePath() << "'"
|
||
<< ", errorString= " << jError.errorString();
|
||
return false;
|
||
}
|
||
|
||
const QJsonObject &rootObj = doc.object();
|
||
const QJsonObject &filters = rootObj[QStringLiteral("filters")].toObject(); // optional!!!
|
||
|
||
if (filters.isEmpty())
|
||
{
|
||
WARNING_LOG(m_logger) << "no 'filters' provided at "
|
||
<< " replayConfigFile '" << fi.absoluteFilePath() << "'";
|
||
return false;
|
||
}
|
||
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION << " XXXX replayConfigFile='" << fi.absoluteFilePath() << "'"
|
||
<< " doc.toJson = " << doc.toJson();
|
||
|
||
// fine, put together
|
||
FilterInformation filterInfo;
|
||
filterInfo.aesFilters = filters[QStringLiteral("AesFilterJson")].toObject();
|
||
filterInfo.symbolSettings = filters[QStringLiteral("SymbolAppearanceJson")].toObject();
|
||
filterInfo.buildingComponentSettings = filters[QStringLiteral("BuildingComponentSettingsJson")].toObject();
|
||
|
||
filterInfo.mapSettings = rootObj[QStringLiteral("settings")].toObject();
|
||
|
||
applyCurentFilter(filterInfo);
|
||
|
||
return true;
|
||
}
|
||
|
||
void SituationWidget::applyCurentFilter(const SituationReplay::FilterInformation &filter)
|
||
{
|
||
m_aesDisplayFilter->setFilterFromData(filter.aesFilters);
|
||
m_symbolAppaearanceSettings->setSettings(filter.symbolSettings, FilterManagement::SymbolAppearanceSettings::Part::All);
|
||
m_buildingComponentSettings->setBldCmpSettings(filter.buildingComponentSettings);
|
||
|
||
SituationMap::OperatorMapSettings oms;
|
||
oms.fromJsonObject(filter.mapSettings);
|
||
if (oms.isEmpty() || oms.mode == SituationMap::Mode::Undefined)
|
||
return;
|
||
|
||
|
||
if (oms.mode != m_situationMapInit->getWidget()->mode())
|
||
{
|
||
INFO_LOG(m_logger) << " Switching to new mode : " << oms.mode;
|
||
|
||
SituationMap::MapSettingsJson savedMapSettingsJson;
|
||
if (m_situationMapInit)
|
||
{
|
||
savedMapSettingsJson = m_situationMapInit->getMapSettingsJson(); // containing path from layerMappping.json
|
||
m_situationMapInit->stopDisplay();
|
||
m_situationMapInit->clearObjects();
|
||
}
|
||
delete m_situationMapInit;
|
||
m_situationMapInit = new MySitMapIinit(nullptr);
|
||
m_situationMapInit->setMapSettingsJson(savedMapSettingsJson);
|
||
m_situationMapInit->initPluginProvider(m_pluginProvider);
|
||
|
||
m_situationMapInit->initMap(false, oms.mode);
|
||
|
||
QPointer<SituationMap::MovementTrackManager> movementTrackMgr =
|
||
QPointer<SituationMap::MovementTrackManager>(new SituationMap::MovementTrackManager(m_situationMapInit));
|
||
if (!m_situationMapInit->initAdapter(movementTrackMgr, false))
|
||
return;
|
||
|
||
SituationMap::Map *map = m_situationMapInit->getWidget();
|
||
if (map)
|
||
{
|
||
connect(map, &SituationMap::Map::mouseGeoPositionChanged,
|
||
this, &SituationWidget::updatePositionLabel,
|
||
Qt::UniqueConnection);
|
||
connect(map, &SituationMap::Map::extentChanged,
|
||
this, &SituationWidget::updateZoomSlider);
|
||
|
||
map->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||
m_ui->vLayout->insertWidget(0, map);
|
||
|
||
|
||
static bool s_waitFlag = true;
|
||
|
||
QPointer<SituationMap::MapNotifier> mapNotifier = map->createMapNotifier();
|
||
if (mapNotifier)
|
||
{
|
||
connect(mapNotifier.data(), &SituationMap::MapNotifier::mapReadyAndSymbolDictionaryLoaded, this, [this, oms]()
|
||
{
|
||
s_waitFlag = false;
|
||
if (!restoreOperatorMapSettingsOverlays(oms))
|
||
WARNING_LOG(m_logger) << "restoreOperatorMapSettingsOverlays failed";
|
||
|
||
});
|
||
mapNotifier->run();
|
||
|
||
// snyc wait :-(
|
||
{
|
||
DEBUG_LOG(m_logger) << " WAIT_SYNC BEGIN";
|
||
int i=0;
|
||
while(i<100 && s_waitFlag) // 100 * 50ms = 5000ms
|
||
{
|
||
qApp->processEvents(QEventLoop::ExcludeUserInputEvents|QEventLoop::ExcludeSocketNotifiers, 50);
|
||
QThread::msleep(50);
|
||
++i;
|
||
DEBUG_LOG(m_logger) << " WAIT_SYNC ..., i=" << i;
|
||
}
|
||
DEBUG_LOG(m_logger) << " WAIT_SYNC ...DONE, i=" << i;
|
||
DEBUG_LOG(m_logger) << " WAIT_SYNC, m_situationMapInit->getWidget()->mode()" << m_situationMapInit->getWidget()->mode();
|
||
m_situationMapInit->startDisplay();
|
||
}
|
||
} // if (mapNotifier)
|
||
}
|
||
} else {
|
||
if (!restoreOperatorMapSettingsOverlays(oms))
|
||
WARNING_LOG(m_logger) << "restoreOperatorMapSettingsOverlays failed";
|
||
}
|
||
}
|
||
|
||
bool SituationWidget::restoreOperatorMapSettingsOverlays(const SituationMap::OperatorMapSettings &oms)
|
||
{
|
||
if (!m_situationMapInit || !m_situationMapInit->getWidget() || oms.isEmpty())
|
||
return false;
|
||
|
||
if (!m_situationMapInit->getWidget()->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:
|
||
// So we have to do it here:
|
||
const QList<int> &orderedOverlayIds = oms.orderedOverlays;
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION << " restore OverlayIds...";
|
||
for (auto overlayId : qAsConst(orderedOverlayIds))
|
||
{
|
||
DEBUG_LOG(m_logger) << LOGFUNCTION << " applyNewOverlay , overlayId=" << overlayId;
|
||
applyNewOverlay(overlayId);
|
||
}
|
||
return true;
|
||
}
|
||
|
||
void SituationWidget::applyNewOverlay(int overlayId)
|
||
{
|
||
const QString filename = QStringLiteral("%1/%2.TacticalPlan").arg(m_scriptPath).arg(overlayId);
|
||
QFile f(filename);
|
||
if (!f.open(QIODevice::ReadOnly))
|
||
{
|
||
WARNING_LOG(m_logger) << "Can not open tactical plan '" << filename << "': " << f.errorString();
|
||
return;
|
||
}
|
||
SituationMap::OverlayHandler &overlayHandler = m_situationMapInit->getWidget()->overlayHandler();
|
||
if (!overlayHandler.setOverlay(overlayId, tr("Plan '%1'").arg(overlayId), f.readAll(), false))
|
||
WARNING_LOG(m_logger) << "can not display overlay " << filename;
|
||
|
||
}
|
||
|
||
void SituationWidget::removeOverlay(int overlayId)
|
||
{
|
||
SituationMap::OverlayHandler &overlayHandler = m_situationMapInit->getWidget()->overlayHandler();
|
||
overlayHandler.removeOverlay(overlayId);
|
||
}
|
||
|
||
void SituationWidget::onFilterAes()
|
||
{
|
||
if (!m_filterAesDialog)
|
||
m_filterAesDialog = new SituatationFilterAes(m_aesDisplayFilter,
|
||
m_pluginProvider, this);
|
||
m_filterAesDialog->show();
|
||
}
|
||
|
||
void SituationWidget::onFilterSymbolAppearance()
|
||
{
|
||
if (!m_filterSymbolAppearanceDialog)
|
||
m_filterSymbolAppearanceDialog = new SituatationFilterSymbolAppearance(m_symbolAppaearanceSettings,
|
||
m_pluginProvider, this);
|
||
m_filterSymbolAppearanceDialog->show();
|
||
}
|
||
|
||
void SituationWidget::onFilterCollapseExpand()
|
||
{
|
||
if (!m_filterCollapseExpandDialog)
|
||
m_filterCollapseExpandDialog = new SituatationFilterCollapseExpand(m_symbolAppaearanceSettings,
|
||
m_pluginProvider, this);
|
||
m_filterCollapseExpandDialog->show();
|
||
}
|
||
|
||
void SituationWidget::onFilterTypes()
|
||
{
|
||
if (!m_filterTypesDialog)
|
||
m_filterTypesDialog = new SituatationFilterTypes(m_symbolAppaearanceSettings,
|
||
m_pluginProvider, this);
|
||
m_filterTypesDialog->show();
|
||
}
|
||
|
||
void SituationWidget::onFilterBuildingComponent()
|
||
{
|
||
if (!m_filterBuildingComponentDialog)
|
||
m_filterBuildingComponentDialog = new SituationFilterBuildingComponent(m_buildingComponentSettings,
|
||
m_pluginProvider, this);
|
||
m_filterBuildingComponentDialog->show();
|
||
}
|
||
|
||
void SituationWidget::emitPartitionTimeChanged(qint64 curTime)
|
||
{
|
||
m_pluginProvider->emitPartitionTimeChanged(curTime);
|
||
}
|
||
|
||
void SituationWidget::updateZoomSlider()
|
||
{
|
||
// this is not really what we want to display... but currently we hide the slider anyway
|
||
m_ui->zoomSlider->setZoomValue(m_situationMapInit->getWidget()->scale() / 1000);
|
||
}
|
||
|
||
|
||
QString SituationWidget::centerPointString() const
|
||
{
|
||
const QPointF center = m_situationMapInit->getWidget()->centerPoint();
|
||
LtsCoordTrans::UtmCoordinate coord(LtsCoordTrans::UtmCoordinate::fromGeographic(center.x(), center.y()));
|
||
return coord.mgrs();
|
||
}
|
||
|
||
QRectF SituationWidget::extentMgrs() const
|
||
{
|
||
const QRectF r = m_situationMapInit->getWidget()->extent();
|
||
LtsCoordTrans::UtmCoordinate topLeft(LtsCoordTrans::UtmCoordinate::fromGeographic(r.left(), r.top()));
|
||
LtsCoordTrans::UtmCoordinate bottomRight(LtsCoordTrans::UtmCoordinate::fromGeographic(r.right(), r.bottom(), topLeft.zone));
|
||
return QRectF(QPointF(topLeft.x, topLeft.y), QPointF(bottomRight.x, bottomRight.y));
|
||
}
|
||
|
||
QImage SituationWidget::grabFrameBuffer() const
|
||
{
|
||
return m_situationMapInit->getWidget()->grab().toImage();
|
||
}
|
||
|
||
void SituationWidget::onInitDone()
|
||
{
|
||
SituationBuildingBase::onInitDone();
|
||
m_situationMapInit->startDisplay();
|
||
}
|
||
|
||
void SituationWidget::keyPressEvent(QKeyEvent *event)
|
||
{
|
||
switch (event->key())
|
||
{
|
||
case Qt::Key_F10:
|
||
onMgrsGrid();
|
||
break;
|
||
case Qt::Key_PageUp:
|
||
onRotate(10);
|
||
break;
|
||
case Qt::Key_PageDown:
|
||
onRotate(-10);
|
||
break;
|
||
default:
|
||
QFrame::keyPressEvent(event);
|
||
break;
|
||
}
|
||
}
|
||
|
||
void SituationWidget::onMgrsGrid()
|
||
{
|
||
SituationMap::Map *m = m_situationMapInit->getWidget();
|
||
m->grid().setVisible(!m->grid().isVisible());
|
||
}
|
||
|
||
void SituationWidget::onRotate(int degrees)
|
||
{
|
||
SituationMap::Map *m = m_situationMapInit->getWidget();
|
||
m->setRotation(m->rotation() + degrees);
|
||
}
|
||
|
||
void SituationWidget::onFileContentAvailable(const FileManagement::Database::FlmFileContent &data)
|
||
{
|
||
if (data.fileTypeId != FileManagement::FileType::OperatorDefinedSymbol ||
|
||
data.fileStatusId != FileManagement::FileStatus::Valid ||
|
||
data.content.size() == 0)
|
||
return;
|
||
|
||
QColor colorToBeReplaced;
|
||
bool bIsXml = false;
|
||
|
||
if (!data.properties.isEmpty())
|
||
{
|
||
QJsonParseError parseError;
|
||
const QJsonDocument jDoc(QJsonDocument::fromJson(data.properties.toUtf8(), &parseError));
|
||
const QJsonObject obj(jDoc.object());
|
||
const QLatin1String imageFormatKey("imageFormat");
|
||
bIsXml = obj.value(imageFormatKey).toString() == QLatin1String("xml");
|
||
if (!bIsXml)
|
||
{
|
||
// partyColor
|
||
const QLatin1String partyColorStr("partyColor");
|
||
if (obj.contains(partyColorStr))
|
||
{
|
||
const QJsonObject partyColor = obj[partyColorStr].toObject();
|
||
if (partyColor.size() == 3) // r, g, b
|
||
{
|
||
// update map:
|
||
colorToBeReplaced.setRgb(
|
||
partyColor[QLatin1String("r")].toInt(),
|
||
partyColor[QLatin1String("g")].toInt(),
|
||
partyColor[QLatin1String("b")].toInt());
|
||
} // if (partyColor.size() == 3)
|
||
} // if (obj.contains(partyColorStr))
|
||
}
|
||
}
|
||
|
||
AdvancedSymbology::SymbologyType symType = AdvancedSymbology::SymbolDictionary::defaultSymbologyType();
|
||
AdvancedSymbology::SymbolDictionary &dict =
|
||
AdvancedSymbology::SymbolDictionary::dictionary(symType);
|
||
if (bIsXml)
|
||
{
|
||
dict.setXmlSymbol(data.id, data.name, QStringLiteral("OperatorName"), 0, QString::fromUtf8(data.content), AdvancedSymbology::SymbolProperties());
|
||
}
|
||
else
|
||
{
|
||
QImage image;
|
||
QSvgRenderer svgRenderer;
|
||
if (!svgRenderer.load(data.content))
|
||
return;
|
||
|
||
// prepare Image:
|
||
constexpr int size = 200; // pixel
|
||
QImage imageOut(size, size, QImage::Format_ARGB32);
|
||
imageOut.fill(Qt::transparent);
|
||
|
||
// render
|
||
QPainter painter(&imageOut);
|
||
svgRenderer.render(&painter);
|
||
painter.end();
|
||
|
||
AdvancedSymbology::SymbolProperties symProps;
|
||
symProps.setKey(data.name);
|
||
symProps.setSidc(AdvancedSymbology::SidcCodec::encodeCivilEts(data.name));
|
||
symProps.setName(data.name);
|
||
symProps.setSymbolClass(QLatin1String("3")); // 18.10.2016, N.Thoden: 3 == PointSymbol (mil2525d.stylx - QuartzRelease)
|
||
symProps.setGeometryType(AdvancedSymbology::GeometryType::Point); // ETS-Symbols are always Points
|
||
symProps.setTags({data.name});
|
||
symProps.setColorToBeReplaced(colorToBeReplaced);
|
||
|
||
dict.setEtsSymbol(data.id, data.name, symProps, image);
|
||
}
|
||
}
|
||
|
||
void SituationWidget::loadLayerMappings(const QString &homePath)
|
||
{
|
||
const QString mappingsFile = homePath + QStringLiteral("/layerMapping.json");
|
||
|
||
QFile f(mappingsFile);
|
||
if (!f.open(QIODevice::ReadOnly))
|
||
{
|
||
fprintf(stderr, "Could not load layer mappings from '%s' - %s\n", mappingsFile.toStdString().c_str(), f.errorString().toStdString().c_str());
|
||
WARNING_LOG(m_logger) << "Could not load layer mappings from " << mappingsFile << ": " << f.errorString();
|
||
return;
|
||
}
|
||
m_layerMapping.clear();
|
||
const QJsonObject obj = QJsonDocument::fromJson(f.readAll()).object();
|
||
|
||
SituationMap::MapSettingsJson settings;
|
||
if (!settings.fromJsonObject(obj))
|
||
{
|
||
WARNING_LOG(m_logger) << "Could not parse layer mappings from " << mappingsFile;
|
||
return;
|
||
}
|
||
|
||
settings.setMapUrls(fixupUrls(settings.getMapUrls(), homePath));
|
||
settings.setSceneUrls(fixupUrls(settings.getSceneUrls(), homePath));
|
||
settings.setSceneObjectUrls(fixupUrls(settings.getSceneObjectUrls(), homePath));
|
||
settings.setElevationUrls(fixupUrls(settings.getElevationUrls(), homePath));
|
||
|
||
m_situationMapInit->setMapSettingsJson(settings);
|
||
}
|
||
|
||
QVector<SituationMap::BaseUrl> SituationWidget::fixupUrls(const QVector<SituationMap::BaseUrl> &in,
|
||
const QString &homePath)
|
||
{
|
||
QVector<SituationMap::BaseUrl> out;
|
||
for (auto url : in)
|
||
{
|
||
const QString fn = QStringLiteral("%1/Maps/%2").arg(homePath, url.url());
|
||
if (!QFile::exists(fn))
|
||
{
|
||
fprintf(stderr, "Can not find map data file '%s'\n", fn.toStdString().c_str());
|
||
QMessageBox::warning(this, tr("Can not find map data"),
|
||
tr("Can not find map data file '%1' - can't start application").arg(fn));
|
||
QCoreApplication::quit();
|
||
return out;
|
||
}
|
||
url.setUrl(QUrl::fromLocalFile(fn).toString());
|
||
out.push_back(std::move(url));
|
||
}
|
||
return out;
|
||
}
|
||
|
||
} // namespace THP
|
||
|
||
#include "thp_situation_widget.moc"
|