Files
qt-migration-legatus/qt6-after/qt6-migrated-legatus/Lts/Plugins/BuildingViewer/Common/bdv_dds_controller.cpp
T
torsten 950d669538 Qt6 Migration: BUILD_RTI guards und CMake fixes
- BUILD_RTI conditional compilation für RTI Connext DDS dependencies
- Namespace fixes in core_dtc.h (Core:: → DDS::Core::)
- CMakeLists.txt: BUILD_RTI option und conditional dependencies
- Handler minelayer: namespace closing mit BUILD_RTI guard
- Build erfolgreich mit BUILD_RTI=OFF validiert

Signed-off-by: Torsten Wierschin <torsten.wierschin@life-maps.com>
2026-08-21 18:37:18 +02:00

1609 lines
61 KiB
C++

#include "bdv_dds_controller.h"
#include "bdv_communication_interface_internal.h"
#include "bdv_controller.h"
#include "bdv_helper.h"
#include "bdv_plugin_provider.h"
#include "logger.h"
#include <InfrastructureManagement/ism_dtc.h>
#include <LtsSession/lts_session_data.h>
#include <LtsUtils/LtsUtilsCore/outdated_position.h>
#include <LtsUtilsSettings/settings.h>
#include <LtsWidgets/lts_message_dialog.h>
#include <Plugins/InfrastructureManagement/Shared/ism_mounting_point.h>
#include <QDateTime>
#include <QDir>
#include <QFile>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonParseError>
#include <QPixmap>
#include <QTimer>
#include <QXmlStreamWriter>
#include <ngltools/ngltools_filesystem.h>
#include <utility>
namespace BuildingViewer
{
static inline QString gStrSymbolFolderPath()
{
return QDir::tempPath() + QStringLiteral("/excon_bgviewer_symbols/");
}
BuildingViewerDdsController::BuildingViewerDdsController(CommunicationInterfaceInternal* connection,
VCtrl::ViewerInterface* viewerInterface)
: m_connection(connection), m_viewerInterface(viewerInterface), m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger())
{
}
BuildingViewerDdsController::~BuildingViewerDdsController()
{
stopAndClearTimer();
QDir dir(gStrSymbolFolderPath());
dir.removeRecursively();
QFile::remove(getBuildingConfigurationXml());
}
bool BuildingViewerDdsController::init(QWidget* irreplacableWidget, const QString& modelPath, PluginProvider* session)
{
DEBUG_LOG(m_logger) << "BDV:: init";
m_session = session;
m_irreplacableWidget = irreplacableWidget;
m_buildingHeight.clear();
if (!m_session)
{
ERROR_LOG(m_logger) << "No m_session for BuildingViewerController!";
return false;
}
connect(m_session, &PluginProvider::destroyed, this, [this]() {
if (static_cast<QObject*>(m_session) == sender())
{
m_session = nullptr;
DEBUG_LOG(m_logger) << getSessionInfo()
<< "BDV:: BuildingViewerDdsController: m_session has been destroyed!";
stopAndClearTimer();
uninitialize();
}
});
m_asbIfc = session->asbIfc();
if (!m_asbIfc)
{
ERROR_LOG(m_logger) << "Fetching 'm_asbIfc' failed!";
return false;
}
m_bldDtc = session->bldDtc();
if (!m_bldDtc)
{
ERROR_LOG(m_logger) << "Fetching 'm_bldDtc' failed!";
return false;
}
m_ismDtc = session->ismDtc();
if (!m_ismDtc)
{
ERROR_LOG(m_logger) << "Fetching 'm_ismDtc' failed!";
return false;
}
m_pdmDtc = session->pdmDtc();
if (!m_pdmDtc)
{
ERROR_LOG(m_logger) << "Fetching 'm_pdmDtc' failed!";
return false;
}
m_ismIfc = session->ismDataIfc();
if (!m_ismIfc)
{
WARNING_LOG(m_logger) << "Fetching 'm_ismIfc' failed!";
return false;
}
connect(m_ismIfc.get(), &InfrastructureManagement::ForeignDataInterface::mountingPointChanged, this,
&BuildingViewerDdsController::onMountingPointChanged);
m_avmIfc = session->avmDataIfc();
m_blgGuiIfc = session->bldInfoIfc();
m_ppmGuiIfc = session->ppmParticipantInfoIfc();
m_aesDtc = session->aesDtc();
m_ppmDtc = session->ppmDtc();
m_srpDtc = session->srpDtc();
m_exerciseId = m_session->exerciseId();
QDir dir(gStrSymbolFolderPath());
dir.removeRecursively();
if (!dir.mkpath(QStringLiteral(".")))
{
ERROR_LOG(m_logger) << getSessionInfo() << "Could not create path \"" << gStrSymbolFolderPath()
<< "\" which is required to store BgViewer symbol files!";
return false;
}
connect(m_connection, &CommunicationInterfaceInternal::signalPlayerPicked, this,
&BuildingViewerDdsController::onPlayerPicked, Qt::UniqueConnection);
connect(m_connection, &CommunicationInterfaceInternal::signalAssetPicked, this,
&BuildingViewerDdsController::onAssetPicked, Qt::UniqueConnection);
connect(m_connection, &CommunicationInterfaceInternal::signalBgViewerInitFinished, this,
&BuildingViewerDdsController::onBgViewerInitFinished, Qt::UniqueConnection);
INFO_LOG(m_logger)
<< getSessionInfo()
<< "BuildingViewerDdsController::init: The order of the following output must be [1],[2],[3],[4],[5],[6]";
setCurrentTrainingAreaMap(modelPath);
if (m_session->isReplayPartition())
{
if (m_reCheckTimer)
{
m_reCheckTimer->stop();
delete m_reCheckTimer;
m_reCheckTimer = nullptr;
}
m_reCheckTimer = new QTimer(this);
connect(m_reCheckTimer, &QTimer::timeout, this, &BuildingViewerDdsController::reCheckHitLine);
m_reCheckTimer->start(5000);
}
else
{
m_connection->setSimuationPace(1.0);
}
return true;
}
void BuildingViewerDdsController::onBgViewerInitFinished()
{
DEBUG_LOG(m_logger) << "onBgViewerInitFinished";
INFO_LOG(m_logger) << getSessionInfo() << "[2] Training area initialization acknowledged by BgViewer";
INFO_LOG(m_logger) << getSessionInfo() << "[3] Sending mounting points, teams, ..., to BgViewer";
if (!m_pSimTimeSyncTimer)
{
m_pSimTimeSyncTimer = new QTimer(this);
m_pSimTimeSyncTimer->setInterval(m_bgviewer_simSyncTimeInterval_ms);
connect(m_pSimTimeSyncTimer, &QTimer::timeout, this, &BuildingViewerDdsController::onSynchronizeSimulationTime);
}
m_pSimTimeSyncTimer->start();
onSynchronizeSimulationTime();
syncTeams();
setPaused(false);
sendAssets();
LtsUtils::ProjectSettings* ps = LtsUtils::ProjectSettings::getInstance();
const bool useExactPositioning = ps->value(QStringLiteral("bld"), QStringLiteral("useExactPositioning")).toBool();
m_connection->excUseExactPositioning(useExactPositioning);
INFO_LOG(m_logger) << getSessionInfo() << "[4] Getting building DDS data ('mainStructureElements')";
connect(m_ismDtc.get(), &InfrastructureManagement::Interface::Dtc::mainStructureElementChanged, this,
&BuildingViewerDdsController::onMainStructureElementChanged);
m_ismDtc->mainStructureElements([this](const InfrastructureManagement::MainStructureElement& data) {
onMainStructureElementChanged(data, DataModification::eAdded);
});
INFO_LOG(m_logger) << getSessionInfo() << "\t[4.1] Done";
INFO_LOG(m_logger) << getSessionInfo() << "[5] Creating participants";
createParticipants();
INFO_LOG(m_logger) << getSessionInfo() << "\t[5.1] Done";
INFO_LOG(m_logger) << getSessionInfo() << "[5] Creating Booby Trap";
createBoobyTraps();
INFO_LOG(m_logger) << getSessionInfo() << "\t[5.2] Done";
INFO_LOG(m_logger) << getSessionInfo() << "[6] Getting building DDS data ('buildingStates')";
connect(m_bldDtc.get(), &Buildings::Interface::Dtc::buildingStateChanged, this,
&BuildingViewerDdsController::onBuildingStateChanged, Qt::UniqueConnection);
m_bldDtc->buildingStates(
[this](const Buildings::BuildingState& data) { onBuildingStateChanged(data, DataModification::eAdded); });
connect(m_bldDtc.get(), &Buildings::Interface::Dtc::buildingHitLineInfoChanged, this,
&BuildingViewerDdsController::onBuildingHitLineInfoChanged, Qt::UniqueConnection);
INFO_LOG(m_logger) << getSessionInfo() << "\t[6.1] Done";
m_connection->excSetGlobalTransparency(
LtsUtils::OperatorSettings::getInstance()
->value(QStringLiteral("BgViewer"), QStringLiteral("GlobalTransparency"), 75)
.toInt());
m_connection->excSetGlobalViewMode(LtsUtils::OperatorSettings::getInstance()
->value(QStringLiteral("BgViewer"), QStringLiteral("UseIsoMode"), false)
.toBool());
m_connection->excSetGlobalDotsMode(LtsUtils::OperatorSettings::getInstance()
->value(QStringLiteral("BgViewer"), QStringLiteral("UseDotsMode"), false)
.toBool());
m_hitlineDuration_ms = LtsUtils::OperatorSettings::getInstance()
->value(QStringLiteral("BgViewer"), QStringLiteral("maxHitlineDurationTime_s"), 10)
.toInt() *
1000;
if (m_hitlineDuration_ms < 0)
m_hitlineDuration_ms = 0;
m_connection->excSetHitlineDuration(m_hitlineDuration_ms / 1000);
if (!m_pFireEventFlashTimer)
{
m_pFireEventFlashTimer = new QTimer(this);
m_pFireEventFlashTimer->setInterval(1000);
connect(m_pFireEventFlashTimer, &QTimer::timeout, this, &BuildingViewerDdsController::onFireEventFlashTimer);
}
m_pFireEventFlashTimer->start();
if (m_srpDtc)
{
connect(m_srpDtc.get(), &SituationReplay::Interface::Dtc::sitReplayChanged, this,
&BuildingViewerDdsController::onReplayChanged, Qt::UniqueConnection);
if (m_srpDtc && m_srpDtc->isSitReplayEnabled())
{
m_srpDtc->sitReplays(
[this](const SituationReplay::SitReplay& srp) { onReplayChanged(srp, DataModification::eAdded); });
}
}
if (!m_pBuildingHitlineCleanupTimer)
{
m_pBuildingHitlineCleanupTimer = new QTimer(this);
m_pBuildingHitlineCleanupTimer->setInterval(1000 * 60 * 5);
connect(m_pBuildingHitlineCleanupTimer, &QTimer::timeout, this,
&BuildingViewerDdsController::onCleanupBuildingHitlines);
}
m_pBuildingHitlineCleanupTimer->start();
INFO_LOG(m_logger) << getSessionInfo() << "[7] Emitting 'signalDdsInitFinished'";
m_ddsInitFinished = true;
emit signalDdsInitFinished();
onSynchronizeSimulationTime();
}
void BuildingViewerDdsController::stopAndClearTimer()
{
DEBUG_LOG(m_logger) << "stopAndClearTimer";
if (m_pFireEventFlashTimer)
m_pFireEventFlashTimer->stop();
if (m_pBuildingHitlineCleanupTimer)
m_pBuildingHitlineCleanupTimer->stop();
if (m_pSimTimeSyncTimer)
m_pSimTimeSyncTimer->stop();
}
void BuildingViewerDdsController::uninitialize()
{
DEBUG_LOG(m_logger) << "uninitialize";
if (!m_bldDtc)
return;
if (m_ddsInitFinished)
DEBUG_LOG(m_logger)
<< "Flag 'm_ddsInitFinished' set which means that initialization had been finished completely";
else
WARNING_LOG(m_logger) << "Flag 'm_ddsInitFinished' has not been set within timeout value, forcing quit!";
stopAndClearTimer();
m_connection->disconnect(this);
m_connection->systemDisconnect();
m_aesDtc->disconnect(this);
m_ppmDtc->disconnect(this);
m_ismDtc->disconnect(this);
m_ismIfc->disconnect(this);
m_bldDtc->disconnect(this);
m_avmIfc = nullptr;
m_asbIfc = nullptr;
m_aesDtc = nullptr;
m_ppmDtc = nullptr;
m_ppmGuiIfc = nullptr;
m_ismDtc = nullptr;
m_ismIfc = nullptr;
m_bldDtc = nullptr;
m_blgGuiIfc = nullptr;
m_ddsInitFinished = false;
m_buildingHeight.clear();
DEBUG_LOG(m_logger) << "BuildingViewerDdsController::uninitialize() finished";
}
QPointF BuildingViewerDdsController::toRelativePosition(const Core::GeoPosition& geoPos) const
{
if (std::isnan(geoPos.lon()) || std::isnan(geoPos.lat()) || qIsNull(geoPos.lon()) || qIsNull(geoPos.lat()))
return {};
LtsCoordTrans::UtmCoordinate coord(
LtsCoordTrans::UtmCoordinate::fromGeographic(geoPos.lon(), geoPos.lat(), m_baseCoordinate.zone));
return coord.relativeTo(m_baseCoordinate);
}
LtsUtils::QPoint3D BuildingViewerDdsController::toRelative3D(const Core::GeoPosition& geoPos) const
{
const auto ret = toRelativePosition(geoPos);
if (ret.isNull())
return {};
return LtsUtils::QPoint3D(ret.x(), ret.y(), geoPos.z());
}
bool BuildingViewerDdsController::clear()
{
DEBUG_LOG(m_logger) << "clear m_connection->playerClear();";
m_connection->playerClear();
return true;
}
bool BuildingViewerDdsController::syncTeams()
{
if (!m_ppmDtc)
return false;
INFO_LOG(m_logger) << "BuildingViewerDdsController::syncTeams";
m_connection->setTeamConfiguration(m_ppmDtc->partys());
return true;
}
bool BuildingViewerDdsController::setPaused(bool bPaused)
{
m_connection->systemSetPaused(bPaused);
return true;
}
bool BuildingViewerDdsController::calcBaseCoordinate(
const QMap<qint32, InfrastructureManagement::MainStructureElement>& mseMap)
{
bool bAtLeasOneFound = false;
Core::GeoPosition geoPosition;
for (const auto& mse : mseMap)
{
if (!bAtLeasOneFound)
{
bAtLeasOneFound = true;
geoPosition = mse.geoPosition();
}
else
{
geoPosition.lat() = std::min(geoPosition.lat(), mse.geoPosition().lat());
geoPosition.lon() = std::min(geoPosition.lon(), mse.geoPosition().lon());
}
}
if (!bAtLeasOneFound)
{
WARNING_LOG(m_logger) << "No building available in exercise " << m_exerciseId;
return false;
}
m_baseCoordinate = LtsCoordTrans::UtmCoordinate::fromGeographic(geoPosition.lon(), geoPosition.lat());
return true;
}
bool BuildingViewerDdsController::isOutdatedPosition(qint64 sampleTime) const
{
if (m_session == nullptr)
return true;
return LtsUtils::isPositionTimeOutdated(m_session->partitionTime(), sampleTime);
}
bool BuildingViewerDdsController::writeBuildingDataToXML(const QString& modelPath)
{
QFile f(getBuildingConfigurationXml());
if (!f.open(QIODevice::WriteOnly))
{
WARNING_LOG(m_logger) << "Can not open file " << f.fileName() << " for writing: " << f.errorString();
return false;
}
m_knownBuildings.clear();
QMap<qint32, InfrastructureManagement::MainStructureElement> mseMap;
QFile jsonConfig(modelPath + QStringLiteral("/buildings.json"));
if (!jsonConfig.exists())
jsonConfig.setFileName(modelPath + QStringLiteral("/../buildings.json"));
DEBUG_LOG(m_logger) << "jsonConfig:" << jsonConfig.fileName();
if (jsonConfig.exists() && jsonConfig.open(QIODevice::ReadOnly))
{
m_ismDtc->disconnect(this);
InfrastructureManagement::MainStructureElement mse;
const QJsonArray arr = QJsonDocument::fromJson(jsonConfig.readAll()).array();
for (const auto& ele : arr)
{
const auto bi = BuildingInfo::fromJson(ele.toObject());
if (!bi.isValid())
continue;
mse.id(bi.id);
mse.angle(bi.angleDegree);
mse.geoPosition(Core::GeoPosition(bi.position.x(), bi.position.y(), bi.position.z()));
mse.name(bi.name.toStdString());
mseMap.insert(mse.id(), mse);
}
}
else
{
m_ismDtc->waitForHistoricalDataMainStructureElement(m_dtc_timeout_ms);
const auto mMap = m_ismDtc->mainStructureElements();
for (const auto& mse : mMap)
{
if (mse.modelId() == 0)
continue;
if (!m_ismDtc->isElementAssignedToExercise(mse, m_exerciseId))
{
DEBUG_LOG(m_logger)
<< "Not writing mse with id " << mse.id()
<< " to building xml file since it is not assigned to the current exercise which has id "
<< m_exerciseId;
continue;
}
mseMap.insert(mse.id(), mse);
}
}
INFO_LOG(m_logger) << getSessionInfo()
<< "writeBuildingDataToXML(): Identified Main Structure Elements: " << mseMap.size();
if (!calcBaseCoordinate(mseMap))
{
WARNING_LOG(m_logger) << "failed to calc base coordinate";
return false;
}
QXmlStreamWriter sw(&f);
sw.setAutoFormatting(true);
sw.setAutoFormattingIndent(2);
sw.setCodec("UTF-8");
sw.writeStartDocument(QStringLiteral("1.0"), true);
sw.writeStartElement(QStringLiteral("MetaData"));
{
sw.writeStartElement(QStringLiteral("Origin"));
{
const auto geo = m_baseCoordinate.geographic();
sw.writeAttribute(QStringLiteral("Longitude"), QString::number(geo.x() * 180 / M_PI, 'f', 13));
sw.writeAttribute(QStringLiteral("Latitude"), QString::number(geo.y() * 180 / M_PI, 'f', 13));
}
sw.writeEndElement();
sw.writeStartElement(QStringLiteral("Tag"));
sw.writeStartElement(QStringLiteral("Group"));
for (const InfrastructureManagement::MainStructureElement& mse : std::as_const(mseMap))
{
m_knownBuildings += mse.id();
sw.writeStartElement(QStringLiteral("Model"));
sw.writeAttribute(QStringLiteral("Type"), QStringLiteral("House"));
{
const QString name(QString::fromStdString(mse.name()));
sw.writeStartElement(QStringLiteral("Description"));
sw.writeAttribute(QStringLiteral("Name"), name);
sw.writeEndElement();
sw.writeStartElement(QStringLiteral("Feature"));
sw.writeAttribute(QStringLiteral("Id"), BuildingViewer::databaseId2FeatureId(mse.id()));
sw.writeEndElement();
sw.writeStartElement(QStringLiteral("Orientation"));
sw.writeAttribute(QStringLiteral("Angle"), QString::number(360 - mse.angle()));
sw.writeEndElement();
const QPointF offset(toRelativePosition(mse.geoPosition()));
sw.writeStartElement(QStringLiteral("Position"));
sw.writeAttribute(QStringLiteral("X"), QString::number(offset.x(), 'f', 13));
sw.writeAttribute(QStringLiteral("Y"), QString::number(offset.y(), 'f', 13));
sw.writeAttribute(QStringLiteral("Z"), QString::number(mse.geoPosition().z(), 'f', 13));
sw.writeEndElement();
sw.writeStartElement(QStringLiteral("File"));
sw.writeAttribute(QStringLiteral("Name"), name + QStringLiteral(".flt"));
sw.writeEndElement();
sw.writeStartElement(QStringLiteral("STREIF"));
sw.writeAttribute(QStringLiteral("Name"), name + QStringLiteral(".flt.xml"));
sw.writeEndElement();
}
sw.writeEndElement();
}
sw.writeEndElement();
sw.writeEndElement();
}
sw.writeEndElement();
sw.writeEndDocument();
f.close();
std::sort(m_knownBuildings.begin(), m_knownBuildings.end());
return true;
}
QString BuildingViewerDdsController::getBuildingConfigurationXml() const
{
return QDir::tempPath() + QStringLiteral("/buildings_%1.xml").arg(m_exerciseId);
}
void BuildingViewerDdsController::clearAssets()
{
INFO_LOG(m_logger) << "clearAssets: Removing " << m_knownAssetsInBgViewer.size() << " assets";
for (const auto& strUniqueAsset : std::as_const(m_knownAssetsInBgViewer))
m_connection->extHideMountingPointAsset(strUniqueAsset);
m_mountingPointId2AssetType.clear();
m_knownAssetsInBgViewer.clear();
}
void BuildingViewerDdsController::sendAssets()
{
clearAssets();
std::function<void(const InfrastructureManagement::MountingPoint&)> cb =
[this](const InfrastructureManagement::MountingPoint& mp) {
handleMountingPoint(mp, DataModification::eAdded);
};
m_ismIfc->mountingPoints(cb);
}
void BuildingViewerDdsController::onReplayChanged(const SituationReplay::SitReplay& srp, DataModification modType)
{
Q_UNUSED(modType)
switch (srp.state().underlying())
{
case SituationReplay::SrpState::Stopped:
m_connection->setSimuationPace(1.0);
break;
case SituationReplay::SrpState::Started:
case SituationReplay::SrpState::Resumed:
m_connection->setSimuationPace(srp.pace());
break;
case SituationReplay::SrpState::Paused:
m_connection->setSimuationPace(0.0);
break;
default:
break;
}
}
void BuildingViewerDdsController::handleMountingPoint(const InfrastructureManagement::MountingPoint& mp,
DataModification modType)
{
if (!isBuildingKnown(mp.buildingId()))
return;
if (m_session->isReplayPartition())
return;
const int mountingPointId = mp.id();
auto itMp = m_knownAssetsInBgViewer.find(mountingPointId);
if (itMp != m_knownAssetsInBgViewer.end())
{
if (modType == DataModification::eRemoved || !mp.hasAssociatedAsset())
{
m_connection->extHideMountingPointAsset(itMp.value());
m_knownAssetsInBgViewer.erase(itMp);
}
m_mountingPointId2AssetType.remove(mountingPointId);
if (modType == DataModification::eRemoved)
return;
}
if (!mp.hasAssociatedAsset())
return;
BuildingViewer::AssetTypes assetType;
QString strAssetType;
switch (mp.type().underlying())
{
case InfrastructureManagement::MountingPointType_def::AnnouncementUnit:
assetType = BuildingViewer::AssetTypes::AnnouncementUnit;
strAssetType = QStringLiteral("AnnouncementUnit");
break;
case InfrastructureManagement::MountingPointType_def::EffectGenerationControlUnit:
assetType = BuildingViewer::AssetTypes::EffectGenerationUnit;
strAssetType = QStringLiteral("EffectGenerationControlUnit");
break;
case InfrastructureManagement::MountingPointType_def::IndoorCamera: {
bool hasSpeaker = false;
QJsonParseError jError;
const QJsonDocument doc(QJsonDocument::fromJson(mp.properties(), &jError));
if (jError.error == QJsonParseError::NoError)
{
const QJsonObject obj(doc.object());
hasSpeaker = obj[QStringLiteral("hasSpeaker")].toBool();
}
assetType = hasSpeaker ? BuildingViewer::AssetTypes::IndoorCameraWithSpeaker
: BuildingViewer::AssetTypes::IndoorCamera;
strAssetType = hasSpeaker ? QStringLiteral("IndoorCameraWithSpeaker") : QStringLiteral("IndoorCamera");
break;
}
default:
return;
}
QVector3D position(mp.relPosition().offsetX(), mp.relPosition().offsetY(), mp.relPosition().offsetZ());
QString strfeatureID = BuildingViewer::databaseId2FeatureId(mp.buildingId());
QString strMountingPointID = strfeatureID + QStringLiteral("_MountingPoint_") + QString::number(mountingPointId);
DEBUG_LOG(m_logger) << "Sending asset for building id " << mp.buildingId() << " (" << strfeatureID << ")"
<< " with asset_id " << mp.associatedAssetId() << " matched to structure_element_id " << mp.id()
<< " as \"" << strMountingPointID << " \""
<< " with asset type \"" << strAssetType << "\"";
if (m_mountingPointId2AssetType.contains(mountingPointId))
WARNING_LOG(m_logger) << "Mounting point id " << mountingPointId
<< " already used for other asset?! Overriding...";
m_mountingPointId2AssetType[mountingPointId] = assetType;
m_knownAssetsInBgViewer[mountingPointId] = strMountingPointID;
m_connection->extSetMountingPointAsset(strfeatureID, strMountingPointID, position, assetType);
}
void BuildingViewerDdsController::setCurrentTrainingAreaMap(const QString& modelPath)
{
if (!m_connection)
{
WARNING_LOG(m_logger) << "BuildingViewerDdsController::setCurrentTrainingAreaMap: (!m_connection)";
return;
}
m_connection->excDeleteBuildingList();
INFO_LOG(m_logger) << getSessionInfo() << "[1] Initializing BgViewer with training area...";
if (modelPath.isEmpty())
{
QString strErr = tr("Error initializing Building Viewer - can not find map directory.");
DEBUG_LOG(m_logger) << getSessionInfo() << "setCurrentTrainingAreaMap: " << strErr;
QWidget* parentWidgetx = (m_viewerInterface ? m_viewerInterface->getMainWindow() : nullptr);
LtsWidgets::LtsMessageDialog::showMessage(parentWidgetx, strErr, tr("Error"));
return;
}
INFO_LOG(m_logger) << "Map path for building viewer: " << modelPath;
writeBuildingDataToXML(modelPath);
QString pathToXml = getBuildingConfigurationXml();
QFileInfo file(pathToXml);
if (!file.exists())
{
FATAL_LOG(m_logger) << getSessionInfo()
<< "setCurrentTrainingAreaMap: Required buildings xml file does not exist: \"" << pathToXml
<< "\", BuildingViewer initialization FAILED!";
return;
}
const QString shadersPath = NGL::directory(NGL::FileType::ConfigFile, QStringLiteral("BuildingViewer"));
QString additionalPath;
QVector<QString> directoriesToSearch = NGL::directories(NGL::FileType::ConfigFile);
#ifndef WIN32
directoriesToSearch += QStringLiteral("/opt");
#endif
for (const QString& d : std::as_const(directoriesToSearch))
{
const QDir dir(d + QStringLiteral("/BuildingModels/StaticMeshes/"));
if (dir.exists() && dir.isReadable())
additionalPath = dir.absolutePath();
INFO_LOG(getLogger("BgViewerController"))
<< "Map path '" << dir.absolutePath() << "' either does not exist or is not readable - skipping";
}
std::vector<std::string> paths;
paths.push_back(modelPath.toStdString());
paths.push_back(shadersPath.toStdString());
if (!additionalPath.isEmpty())
{
paths.push_back(additionalPath.toStdString());
}
m_connection->excConnect(paths, pathToXml);
}
bool BuildingViewerDdsController::isValidParticipant(const ParticipantManagement::Participant& participant) const
{
if (participant.id() == 0)
{
if (m_logger.isDebugEnabled())
DEBUG_LOG(m_logger) << getSessionInfo()
<< "isValidParticipant: Not handling invalid participant with invalid id (0)";
return false;
}
if (participant.isDeleted())
{
DEBUG_LOG(m_logger) << getSessionInfo() << "isValidParticipant: Not handling participant with id "
<< participant.id() << " since it is marked as 'deleted'";
return false;
}
if (m_session == nullptr)
return false;
if (!m_session->isVisibleParty(participant.partyId()))
{
DEBUG_LOG(m_logger) << getSessionInfo() << "isValidParticipant: Not handling participant with id "
<< participant.id() << " since it is not visible for party with id "
<< participant.partyId();
return false;
}
if (!m_ppmDtc)
return false;
ParticipantManagement::TypeClass tc = m_ppmDtc->type(participant.typeId()).typeClass();
if (tc == ParticipantManagement::TypeClass_def::SupportUnit || tc == ParticipantManagement::TypeClass_def::Unit)
{
DEBUG_LOG(m_logger) << getSessionInfo() << "isValidParticipant: Not handling participant with id "
<< participant.id() << " since its type is 'SupportUnit', 'Unit' or 'Structure'";
return false;
}
return true;
}
void BuildingViewerDdsController::createBoobyTraps()
{
if (!m_aesDtc)
return;
DEBUG_LOG(m_logger) << "BDV:: create Booby Traps: " << m_session->exerciseId()
<< " is replay: " << m_session->isReplayPartition();
m_aesDtc->enableBoobyTrap();
const int sizeL = LtsUtils::OperatorSettings::getInstance()
->value(QStringLiteral("BgViewer"), QStringLiteral("PlayerSymbolSize"), 20)
.toInt();
auto cb = [this, sizeL](const AreaEffectSimulation::BoobyTrap& trap) { createBoobyTrap(trap, sizeL); };
m_aesDtc->boobyTraps(cb);
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::boobyTrapChanged, this,
&BuildingViewerDdsController::onBoobyTrapChanged, Qt::UniqueConnection);
}
void BuildingViewerDdsController::createParticipants()
{
if (!m_ppmDtc)
return;
DEBUG_LOG(m_logger) << "BDV:: create participants: " << m_session->exerciseId()
<< " is replay: " << m_session->isReplayPartition();
const int sizeL = LtsUtils::OperatorSettings::getInstance()
->value(QStringLiteral("BgViewer"), QStringLiteral("PlayerSymbolSize"), 20)
.toInt();
const QMap<int, ParticipantManagement::ParticipantPosition> positionMap = m_ppmDtc->participantPositions();
auto cb = [this, &positionMap, sizeL](const ParticipantManagement::Participant& part) {
if (!isValidParticipant(part))
return;
createParticipant(part, positionMap.value(part.id()), sizeL);
};
m_ppmDtc->participants(cb);
m_ppmDtc->enableParticipant();
connect(m_ppmDtc.get(), &ParticipantManagement::Interface::Dtc::participantChanged, this,
&BuildingViewerDdsController::onParticipantChanged, Qt::UniqueConnection);
connect(m_ppmDtc.get(), &ParticipantManagement::Interface::Dtc::hitLineInfoChanged, this,
&BuildingViewerDdsController::onHitLineInfoChanged, Qt::UniqueConnection);
m_ppmDtc->enableHitLineInfo();
m_ppmDtc->enableParty();
connect(m_ppmDtc.get(), &ParticipantManagement::Interface::Dtc::partyChanged, this,
&BuildingViewerDdsController::onPartyChanged, Qt::UniqueConnection);
m_ppmDtc->enableParticipantPosition();
connect(m_ppmDtc.get(), &ParticipantManagement::Interface::Dtc::participantPositionChanged, this,
&BuildingViewerDdsController::onPositionChanged, Qt::UniqueConnection);
m_ppmDtc->enableParticipantGearEvent();
connect(m_ppmDtc.get(), &ParticipantManagement::Interface::Dtc::participantGearEventChanged, this,
&BuildingViewerDdsController::onParticipantGearEventChanged, Qt::UniqueConnection);
m_ppmDtc->enableDynamicParticipantData();
connect(m_ppmDtc.get(), &ParticipantManagement::Interface::Dtc::dynamicParticipantDataChanged, this,
&BuildingViewerDdsController::onDynParticipantChanged, Qt::UniqueConnection);
m_ppmDtc->participantGearEvents([this](const ParticipantManagement::ParticipantGearEvent& data) {
onParticipantGearEventChanged(data, DataModification::eAdded);
});
}
void BuildingViewerDdsController::onBoobyTrapChanged(const AreaEffectSimulation::BoobyTrap& boobyTrap,
DataModification modType)
{
switch (modType)
{
case DataModification::eModified:
deleteParticipant(990000 + boobyTrap.id());
Q_FALLTHROUGH();
case DataModification::eAdded: {
int sizeL = LtsUtils::OperatorSettings::getInstance()
->value(QStringLiteral("BgViewer"), QStringLiteral("PlayerSymbolSize"), 20)
.toInt();
createBoobyTrap(boobyTrap, sizeL);
break;
}
case DataModification::eRemoved: {
deleteParticipant(990000 + boobyTrap.id());
break;
}
}
}
void BuildingViewerDdsController::onParticipantChanged(const ParticipantManagement::Participant& participant,
DataModification modType)
{
if (!isValidParticipant(participant))
return;
switch (modType)
{
case DataModification::eModified:
deleteParticipant(participant.id());
Q_FALLTHROUGH();
case DataModification::eAdded: {
int sizeL = LtsUtils::OperatorSettings::getInstance()
->value(QStringLiteral("BgViewer"), QStringLiteral("PlayerSymbolSize"), 20)
.toInt();
createParticipant(participant, m_ppmDtc->participantPosition(participant.id()), sizeL);
break;
}
case DataModification::eRemoved: {
deleteParticipant(participant.id());
break;
}
}
}
void BuildingViewerDdsController::onDynParticipantChanged(const ParticipantManagement::DynamicParticipantData& data,
DataModification modType)
{
int sizeL = LtsUtils::OperatorSettings::getInstance()
->value(QStringLiteral("BgViewer"), QStringLiteral("PlayerSymbolSize"), 20)
.toInt();
switch (modType)
{
case DataModification::eAdded:
case DataModification::eModified:
if (m_ppmDtc)
createParticipant(m_ppmDtc->participant(data.participantId()),
m_ppmDtc->participantPosition(data.participantId()), sizeL);
break;
case DataModification::eRemoved: {
break;
}
}
}
void BuildingViewerDdsController::onHitLineInfoChanged(const ParticipantManagement::HitLineInfo& hli,
DataModification modType)
{
DEBUG_LOG(m_logger) << "X 0000 onHitLineInfoChanged id=" << hli.id();
if (modType == DataModification::eRemoved)
{
DEBUG_LOG(m_logger) << "onHitLineInfoChanged removeHit id=" << hli.id();
m_connection->removeRoomHit(hli.id());
return;
}
if (!m_ppmDtc)
return;
m_ppmDtc->waitForHistoricalDataParticipant();
const ParticipantManagement::Participant& partSrc = m_ppmDtc->participant(hli.originatorParticipantId());
const ParticipantManagement::Participant& partDst = m_ppmDtc->participant(hli.injuryParticipantId());
if (partSrc.id() == 0 || partDst.id() == 0)
{
ERROR_LOG(m_logger) << "no knownn part: " << partSrc.id() << " dst: " << partDst.id();
return;
}
const QString& strFeatureID = BuildingViewer::databaseId2FeatureId(hli.injuryBuildingId());
if (!m_viewerInterface->isViewOpen(strFeatureID.toStdString()))
{
DEBUG_LOG(m_logger) << "building not opened: hli.buildingId()=" << hli;
return;
}
if (hli.injuryBuildingId() != 0)
{
auto itBuildingHit = m_buildingHits.constFind(hli.injuryBuildingId());
if (itBuildingHit != m_buildingHits.constEnd())
{
const QVector<BuildingHit>& bHits = itBuildingHit.value();
DEBUG_LOG(m_logger) << "Got Hit lines to add? " << bHits.size();
for (const BuildingHit& bh : bHits)
{
const bool testFlag = (bh.chargeTypeId == hli.chargeTypeId() &&
bh.originatorParticipantId == hli.originatorParticipantId() &&
hli.sampleTime() - m_hitlineDuration_ms < bh.sampleTime);
DEBUG_LOG(m_logger) << "testFlag " << testFlag;
if (bh.chargeTypeId == hli.chargeTypeId() &&
bh.originatorParticipantId == hli.originatorParticipantId() &&
hli.sampleTime() - m_hitlineDuration_ms < bh.sampleTime)
return;
}
}
}
DEBUG_LOG(m_logger) << "onHitLineInfoChanged: " << hli;
int sizeL = LtsUtils::OperatorSettings::getInstance()
->value(QStringLiteral("BgViewer"), QStringLiteral("PlayerSymbolSize"), 20)
.toInt();
DEBUG_LOG(m_logger) << "onHitLineInfoChanged createPlayerSymbols";
createPlayerSymbols(partDst, sizeL);
LtsUtils::QPoint3D originatorSrc = toRelative3D(hli.originatorPos());
LtsUtils::QPoint3D injuryDest = toRelative3D(hli.injuryPos());
DEBUG_LOG(m_logger) << "onHitLineInfoChanged playerHit"
<< " hli.originatorPos() z=" << hli.originatorPos().z()
<< " hli.injuryPos() z=" << hli.injuryPos().z() << " Src=" << originatorSrc.x() << "/"
<< originatorSrc.y() << "/" << originatorSrc.z() << " Dest= " << injuryDest.x() << "/"
<< injuryDest.y() << "/" << injuryDest.z()
<< " hli.originatorBuildingId=" << hli.originatorBuildingId()
<< " hli.originatorRoomId=" << hli.originatorRoomId()
<< " hli.injuryBuildingId=" << hli.injuryBuildingId()
<< " hli.injuryRoomId=" << hli.injuryRoomId();
DEBUG_LOG(m_logger) << "Before z-correction:"
<< " Src=" << originatorSrc.x() << "/" << originatorSrc.y() << "/" << originatorSrc.z()
<< " Dest= " << injuryDest.x() << "/" << injuryDest.y() << "/" << injuryDest.z();
double zAddOriginator = m_buildingHeight.value(hli.originatorBuildingId(), 0);
double zAddInjury = m_buildingHeight.value(hli.injuryBuildingId(), 0);
DEBUG_LOG(m_logger) << "z-correction: zAddOriginator=" << zAddOriginator;
DEBUG_LOG(m_logger) << "z-correction: zAddInjury=" << zAddInjury;
if (hli.originatorBuildingId() <= 0)
zAddOriginator = zAddInjury;
if (hli.injuryBuildingId() <= 0)
zAddInjury = zAddOriginator;
originatorSrc.setZ(originatorSrc.z() + zAddInjury);
injuryDest.setZ(injuryDest.z() + zAddInjury);
DEBUG_LOG(m_logger) << "After z-correction:"
<< " Src=" << originatorSrc.x() << "/" << originatorSrc.y() << "/" << originatorSrc.z()
<< " Dest= " << injuryDest.x() << "/" << injuryDest.y() << "/" << injuryDest.z();
int buildingIdSrc = -1;
int roomNumberSrc = -1;
{
auto itId2Number = m_roomId2RoomNumber.constFind(hli.originatorBuildingId());
if (itId2Number != m_roomId2RoomNumber.constEnd())
{
const auto& mapRooms = itId2Number.value();
const auto itRoom = mapRooms.constFind(hli.originatorRoomId());
if (itRoom != mapRooms.constEnd())
{
buildingIdSrc = hli.originatorBuildingId();
roomNumberSrc = itRoom.value();
}
else
WARNING_LOG(m_logger) << "onHitLineInfoChanged: Room id can not be mapped! Building id: "
<< hli.injuryBuildingId() << ", originatorRoomId: " << hli.originatorRoomId();
}
}
int buildingIdDst = -1;
int roomNumberDst = -1;
{
auto itId2Number = m_roomId2RoomNumber.constFind(hli.injuryBuildingId());
if (itId2Number != m_roomId2RoomNumber.constEnd())
{
const auto& mapRooms = itId2Number.value();
const auto itRoom = mapRooms.constFind(hli.injuryRoomId());
if (itRoom != mapRooms.constEnd())
{
buildingIdDst = hli.injuryBuildingId();
roomNumberDst = itRoom.value();
}
else
WARNING_LOG(m_logger) << "onHitLineInfoChanged: Room id can not be mapped! Building id: "
<< hli.injuryBuildingId() << ", room id: " << hli.injuryRoomId();
}
}
DEBUG_LOG(m_logger) << "After translate buildingId, roomId:"
<< " hli.originatorBuildingId=" << hli.originatorBuildingId() << " -> " << buildingIdSrc
<< " hli.originatorRoomId=" << hli.originatorRoomId() << " -> " << roomNumberSrc
<< " hli.injuryBuildingId=" << hli.injuryBuildingId() << " -> " << buildingIdDst
<< " hli.injuryRoomId=" << hli.injuryBuildingId() << " -> " << roomNumberDst
<< " hli.sampleTime=" << hli.sampleTime();
int lineType = 2;
m_pdmDtc->chargeType(hli.chargeTypeId());
lineType = m_pdmDtc->getChargeTypeSpecialProperty(hli.chargeTypeId(), 0, 0).underlying();
m_connection->playerHit(hli.id(), partSrc.id(), partDst.id(), originatorSrc, injuryDest, buildingIdSrc,
roomNumberSrc, buildingIdDst, roomNumberDst, lineType, hli.sampleTime());
}
void BuildingViewerDdsController::onPartyChanged(const ParticipantManagement::Party& party, DataModification modType)
{
if (modType == DataModification::eRemoved)
return;
int sizeL = LtsUtils::OperatorSettings::getInstance()
->value(QStringLiteral("BgViewer"), QStringLiteral("PlayerSymbolSize"), 20)
.toInt();
updatePlayerSymbols(sizeL, party.id());
syncTeams();
}
void BuildingViewerDdsController::onPositionChanged(const ParticipantManagement::ParticipantPosition& position,
DataModification modType)
{
if (modType == DataModification::eRemoved)
{
return;
}
DEBUG_LOG(m_logger) << "onPositionChanged: " << position;
int buildingID = -1;
int roomNumber = -1;
auto itId2Number = m_roomId2RoomNumber.constFind(position.buildingId());
if (itId2Number != m_roomId2RoomNumber.constEnd())
{
const auto& mapRooms = itId2Number.value();
const auto itRoom = mapRooms.constFind(position.roomId());
if (itRoom != mapRooms.constEnd())
{
buildingID = position.buildingId();
roomNumber = itRoom.value();
}
else
{
WARNING_LOG(m_logger) << "onPositionChanged: Room id can not be mapped! Building id: "
<< position.buildingId() << ", room id: " << position.roomId();
}
}
if ((roomNumber < 0) && (buildingID <= 0) && (position.buildingId() > 0) &&
(position.reportingSource() == Core::PositionReportingSource::Ops ||
position.reportingSource() == Core::PositionReportingSource::Wls))
{
buildingID = position.buildingId();
}
const int playerId = position.participantId();
auto it = m_lastPositionTime.find(playerId);
if (it == m_lastPositionTime.end())
{
m_lastPositionTime.insert(playerId, position.sampleTime());
if (isOutdatedPosition(position))
m_connection->setPlayerVisible(playerId, false);
}
else
{
if (isOutdatedPosition(it.value()) && !isOutdatedPosition(position))
m_connection->setPlayerVisible(playerId, true);
it.value() = position.sampleTime();
}
if (buildingID <= 0 && roomNumber <= 0)
{
m_connection->setPlayerVisible(playerId, false);
}
else
{
m_connection->setPlayerVisible(playerId, true);
}
if (!m_baseCoordinate.isValid())
{
WARNING_LOG(m_logger)
<< "not calling playerPlace as there is no base coordinate set - are there no buildings in this exercise?";
return;
}
m_connection->playerPlace(position.participantId(), toRelative3D(position.pos()), buildingID, roomNumber,
position.reportingSource());
}
void BuildingViewerDdsController::onParticipantGearEventChanged(const ParticipantManagement::ParticipantGearEvent& data,
DataModification modType)
{
switch (modType)
{
case DataModification::eAdded:
case DataModification::eModified: {
m_participantGearEvents[data.participantId()] = data.sampleTime();
break;
}
case DataModification::eRemoved: {
const int playerId = data.participantId();
m_participantGearEvents.remove(playerId);
m_connection->playerUpdatePlayerSymbol(playerId, buildPlayerSymbolFilePath(playerId, cColorSymbolId));
break;
}
}
}
void BuildingViewerDdsController::createParticipant(const ParticipantManagement::Participant& participant,
const ParticipantManagement::ParticipantPosition& position,
int sizeL)
{
if (!m_baseCoordinate.isValid())
{
WARNING_LOG(m_logger)
<< "not calling playerPlace as there is no base coordinate set - are there no buildings in this exercise?";
return;
}
if (!isValidParticipant(participant))
return;
createPlayerSymbols(participant, sizeL);
m_connection->playerCreate(participant.id(), participant.partyId(), buildPlayerSymbolFilePath(participant.id()),
toRelative3D(position.pos()), position.buildingId(),
m_roomId2RoomNumber.value(position.buildingId()).value(position.roomId()),
position.reportingSource());
const bool isOutdated = isOutdatedPosition(position);
const int participantId = participant.id();
const bool isValid =
(position.buildingId() > 0 && m_roomId2RoomNumber.value(position.buildingId()).value(position.roomId()) > 0);
m_connection->setPlayerVisible(participantId, (!isOutdated && isValid));
m_lastPositionTime.insert(participantId, position.sampleTime());
}
void BuildingViewerDdsController::createBoobyTrap(const AreaEffectSimulation::BoobyTrap& trap, int sizeL)
{
if (trap.effectStateId() != AreaEffectSimulation::AesEffectState::EsActivated &&
trap.effectStateId() != AreaEffectSimulation::AesEffectState::EsPrepared)
return;
ParticipantManagement::Participant participant;
if (trap.partyId().is_set())
participant.partyId() = trap.partyId().get();
participant.designator() = trap.name();
participant.designator() = trap.name();
participant.id() = trap.id() + 990000;
participant.sampleTime() = trap.sampleTime();
participant.symbol() = "AP6D|CMPL|10011500002104000000";
createPlayerSymbols(participant, sizeL);
Core::GeoPosition pos;
pos.lat() = trap.impactPosition().lat();
pos.lon() = trap.impactPosition().lon();
DEBUG_LOG(m_logger) << "Try create Booby trap with id " << trap.id() << " internal id " << participant.id();
DEBUG_LOG(m_logger) << "Try create Booby trap with pos " << pos.lat() << " " << pos.lon();
m_connection->playerCreate(participant.id(), participant.partyId(), buildPlayerSymbolFilePath(participant.id()),
toRelative3D(pos), -1, -1, Core::PositionReportingSource::External);
m_connection->setPlayerVisible(participant.id(), true);
}
void BuildingViewerDdsController::updatePlayerSymbols(const int sizeL, const int forParty)
{
if (!m_ppmDtc)
return;
auto cb = [this, sizeL, forParty](const ParticipantManagement::Participant& participant) {
if (!isValidParticipant(participant))
return;
if (forParty == -1 || participant.partyId() == forParty)
createPlayerSymbols(participant, sizeL);
};
m_ppmDtc->participants(cb);
}
void BuildingViewerDdsController::createPlayerSymbols(const ParticipantManagement::Participant& participant,
const int sizeL)
{
SymbolInfo symbolinfo;
for (int i = 0; i < m_vecFlashColors.size(); ++i)
{
Q_ASSERT(participant.id() != 0);
symbolinfo.participantId = participant.id();
symbolinfo.strPathToSymbolFile = buildPlayerSymbolFilePath(participant.id(), i);
symbolinfo.color = m_vecFlashColors.at(i);
symbolinfo.useThisSymbolNow = !symbolinfo.color.isValid();
createSymbolResultWatcher(participant, symbolinfo, sizeL);
}
}
void BuildingViewerDdsController::createSymbolResultWatcher(const ParticipantManagement::Participant& participant,
const SymbolInfo& symbolInfo, const int sizeL)
{
AdvancedSymbology::SymbolResultWatcher* pSymbolWatcher = new AdvancedSymbology::SymbolResultWatcher(this);
bool symbolWatcherBenchmark = false;
if (symbolWatcherBenchmark)
{
pSymbolWatcher->m_et = new QElapsedTimer;
pSymbolWatcher->m_et->start();
}
bool writeParticipantSymbols = true;
if (writeParticipantSymbols)
{
QFile f(symbolInfo.strPathToSymbolFile);
if (!f.exists())
{
QPixmap pm(1, 1);
pm.fill(Qt::black);
pm.save(symbolInfo.strPathToSymbolFile, "PNG");
}
}
connect(pSymbolWatcher, &AdvancedSymbology::SymbolResultWatcher::resultReady, this,
[this, pSymbolWatcher, symbolInfo, writeParticipantSymbols, symbolWatcherBenchmark]() {
std::shared_ptr<int> symbolWatcherDeleter(
nullptr, [this, pSymbolWatcher, symbolWatcherBenchmark](int*) {
if (symbolWatcherBenchmark && pSymbolWatcher->m_et != nullptr)
DEBUG_LOG(m_logger) << "Symbol creation took " << pSymbolWatcher->m_et->elapsed() << " ms";
pSymbolWatcher->deleteLater();
});
(void)symbolWatcherDeleter;
if (!pSymbolWatcher->symbolResult()->symbolImage().isValid())
{
WARNING_LOG(m_logger) << getSessionInfo()
<< "'slot_SymbolWatcherResultReady': Symbol creation failed -> "
"'!symbolImage.isValid()', BgViewer might not display symbol(s)!";
return;
}
int32_t playerID = symbolInfo.participantId;
if (writeParticipantSymbols)
if (!pSymbolWatcher->symbolResult()->symbolImage().image().save(symbolInfo.strPathToSymbolFile))
{
WARNING_LOG(m_logger)
<< getSessionInfo() << "Could not write symbol file for BgViewer: \""
<< symbolInfo.strPathToSymbolFile << "\", BgViewer might not display symbol(s)!";
return;
}
if (symbolInfo.useThisSymbolNow)
m_connection->playerUpdatePlayerSymbol(playerID, symbolInfo.strPathToSymbolFile);
});
pSymbolWatcher->setSymbolResult(m_asbIfc->findImage(participant, sizeL, symbolInfo.color));
}
void BuildingViewerDdsController::reCheckHitLine()
{
if (m_ppmDtc && m_ppmDtc->isHitLineInfoEnabled())
{
m_ppmDtc->hitLineInfos([this](const ParticipantManagement::HitLineInfo& hli) {
onHitLineInfoChanged(hli, DataModification::eAdded);
});
}
if (m_bldDtc && m_bldDtc->isBuildingHitLineInfoEnabled())
{
QMap<qint32, Buildings::BuildingHitLineInfo> hitMap = m_bldDtc->buildingHitLineInfos();
for (const auto& hli : hitMap)
{
if (hli.sampleTime() < (m_session->partitionTime() - 3000))
onBuildingHitLineInfoChanged(hli, DataModification::eAdded);
}
}
}
QString BuildingViewerDdsController::buildPlayerSymbolFilePath(int playerID, int postfix)
{
return gStrSymbolFolderPath() + QStringLiteral("symbol_player_%1_%2.png").arg(playerID).arg(postfix);
}
void BuildingViewerDdsController::onSynchronizeSimulationTime()
{
if (m_session != nullptr)
{
m_connection->systemSetSimulationTime(m_session->partitionTime());
}
else
WARNING_LOG(m_logger)
<< getSessionInfo()
<< "'slotSynchronizeSimulationTime': m_session is nullptr, could not query partitionTime!";
}
void BuildingViewerDdsController::updateBuildingRoomNames(
const InfrastructureManagement::MainStructureElement& building)
{
const std::vector<InfrastructureManagement::StructureElement>& vecElements = building.elements();
int32_t buildingDatabaseId = building.id();
QString featureID = BuildingViewer::databaseId2FeatureId(buildingDatabaseId);
for (const auto& se : vecElements)
{
if (se.structureElementTypeId() == InfrastructureManagement::StructureElementType_def::Building)
m_connection->excSetBuildingDisplayName(featureID, QString::fromStdString(se.displayName()));
if (se.structureElementTypeId() == InfrastructureManagement::StructureElementType_def::Room)
m_connection->excSetRoomDisplayName(featureID, QString::number(se.mountingPointId()),
QString::fromStdString(se.displayName()));
}
}
void BuildingViewerDdsController::deleteParticipant(int participantId)
{
m_connection->playerDelete(participantId);
}
void BuildingViewerDdsController::onPlayerPicked(int playerId)
{
if (m_ppmGuiIfc)
m_ppmGuiIfc->showParticipantInfoWindow(playerId, true);
else
INFO_LOG(m_logger) << "No m_ppmGuiIfc";
}
void BuildingViewerDdsController::effectGenerationUnitPicked(int structureElementId)
{
if (m_blgGuiIfc)
m_blgGuiIfc->showEffectGenerationUnitWindow(structureElementId);
else
INFO_LOG(m_logger) << "No m_blgGuiIfc";
}
void BuildingViewerDdsController::onAssetPicked(int structureElementId)
{
DEBUG_LOG(m_logger) << "User clicked on asset with structureElementId " << structureElementId << " from "
<< QString::number((quintptr)m_session->adr(), 16);
if (m_session->isReplayPartition())
return;
if (strcmp(PROJECTBUILD, "guez") == 0 && LtsSessionData::LtsSessionData::getInstance()->isTablet())
return;
auto it = m_mountingPointId2AssetType.find(structureElementId);
if (it == m_mountingPointId2AssetType.end())
{
WARNING_LOG(m_logger) << "onAssetPicked: User clicked on asset mounted to structureElementId "
<< structureElementId << " which was not added beforehand?! Ignoring...";
return;
}
const BuildingViewer::AssetTypes assetType = it.value();
switch (assetType)
{
case BuildingViewer::AssetTypes::AnnouncementUnit:
DEBUG_LOG(m_logger) << "Clicked asset is of type is AnnouncementUnit";
if (m_avmIfc)
m_avmIfc->showAnnouncementUnit(structureElementId);
return;
case BuildingViewer::AssetTypes::EffectGenerationUnit:
DEBUG_LOG(m_logger) << "Clicked asset is of type is EffectGenerationUnit";
effectGenerationUnitPicked(structureElementId);
return;
case BuildingViewer::AssetTypes::IndoorCameraWithSpeaker:
DEBUG_LOG(m_logger) << "Clicked asset is of type is IndoorCameraWithSpeaker";
if (m_avmIfc)
{
m_avmIfc->showCamera(m_irreplacableWidget, structureElementId);
m_avmIfc->showAnnouncementUnit(structureElementId);
}
return;
case BuildingViewer::AssetTypes::IndoorCamera:
DEBUG_LOG(m_logger) << "Clicked asset is of type is IndoorCamera";
if (m_avmIfc)
m_avmIfc->showCamera(m_irreplacableWidget, structureElementId);
return;
}
WARNING_LOG(m_logger) << "onAssetPicked: BuildingViewer::AssetTypes is unknown: " << assetType;
}
void BuildingViewerDdsController::onMountingPointChanged(const InfrastructureManagement::MountingPoint& data,
DataModification modType)
{
handleMountingPoint(data, modType);
}
void BuildingViewerDdsController::onBuildingStateChanged(const Buildings::BuildingState& data, DataModification modType)
{
if (modType != DataModification::eAdded && modType != DataModification::eModified)
return;
QMap<int, int> roomDestructions;
for (const Buildings::RoomState& rs : data.roomStates())
{
roomDestructions.insert(rs.mountingPointId(), rs.damagePercent());
}
m_connection->buildingHit(data.id(), data.id(), data.damagePercent(), roomDestructions);
}
void BuildingViewerDdsController::onBuildingHitLineInfoChanged(const Buildings::BuildingHitLineInfo& hli,
DataModification modType)
{
int topidId = static_cast<int>(hli.id());
DEBUG_LOG(m_logger) << "onBuildingHitLineInfoChanged: " << hli;
const QString& strFeatureID = BuildingViewer::databaseId2FeatureId(hli.buildingId());
if (!m_viewerInterface->isViewOpen(strFeatureID.toStdString()))
{
DEBUG_LOG(m_logger) << "building not opened: hli.buildingId()=" << hli.buildingId();
return;
}
const bool isRemove = (modType == DataModification::eRemoved);
DEBUG_LOG(m_logger) << "isRemove=" << isRemove;
if (isRemove)
{
DEBUG_LOG(m_logger) << "onBuildingHitLineInfoChanged: remove ";
QVector<BuildingHit>& bhl = m_buildingHits[hli.buildingId()];
auto it = std::find_if(bhl.begin(), bhl.end(), [hli](const BuildingHit& bh) { return (bh.id == hli.id()); });
if (it != bhl.end())
{
DEBUG_LOG(m_logger) << "bhl.erase(it)";
bhl.erase(it);
}
m_connection->removeRoomHit(hli.id());
return;
}
else
{
BuildingHit bh;
bh.id = hli.id();
bh.sampleTime = hli.sampleTime();
bh.originatorParticipantId = hli.originatorParticipantId();
bh.chargeTypeId = hli.chargeTypeId();
bool contains = false;
for (const auto& it : m_buildingHits[hli.buildingId()])
{
if (it.id == bh.id)
contains = true;
}
if (!contains)
{
m_buildingHits[hli.buildingId()].push_back(bh);
}
}
int lineType = 2;
m_connection->roomHit(topidId, hli.originatorParticipantId(), hli.buildingId(), hli.hitOnRoomId(),
toRelative3D(hli.originatorPos()), lineType, isRemove ? 0 : hli.sampleTime());
}
void BuildingViewerDdsController::onCleanupBuildingHitlines()
{
DEBUG_LOG(m_logger) << "onCleanupBuildingHitlines: ";
const qint64 tNow = QDateTime::currentMSecsSinceEpoch();
const auto isOutdated = [tNow](const BuildingHit& bh) {
return LtsUtils::isPositionTimeOutdated(tNow, bh.sampleTime);
};
for (auto& hitLines : m_buildingHits)
hitLines.erase(std::remove_if(hitLines.begin(), hitLines.end(), isOutdated), hitLines.end());
}
void BuildingViewerDdsController::onMainStructureElementChanged(
const InfrastructureManagement::MainStructureElement& mse, DataModification modType)
{
if (!isBuildingKnown(mse.id()))
return;
switch (modType)
{
case DataModification::eAdded:
case DataModification::eModified: {
if (mse.modelId() != 0 && m_ismDtc->isElementAssignedToExercise(mse, m_exerciseId))
{
DEBUG_LOG(m_logger) << "m_buildingHeight.insert id=" << mse.id() << " z=" << mse.geoPosition().z();
m_buildingHeight.insert(mse.id(), mse.geoPosition().z());
QHash<int, int> roomId2RoomNumber;
for (const InfrastructureManagement::StructureElement& se : mse.elements())
{
if (se.structureElementTypeId() != InfrastructureManagement::StructureElementType::Room)
continue;
roomId2RoomNumber[se.id()] = se.mountingPointId();
}
m_roomId2RoomNumber[mse.id()] = roomId2RoomNumber;
updateBuildingRoomNames(mse);
}
break;
}
case DataModification::eRemoved:
m_roomId2RoomNumber.remove(mse.id());
m_buildingHeight.remove(mse.id());
break;
}
}
QString BuildingViewerDdsController::getSessionInfo() const
{
if (m_session == nullptr)
return QStringLiteral("session == nullptr: ");
return m_session->toString() + QStringLiteral(": ");
}
void BuildingViewerDdsController::onFireEventFlashTimer()
{
static int currFlashState = 0;
if (m_session == nullptr)
{
DEBUG_LOG(m_logger) << getSessionInfo()
<< "onFireEventFlashTimer: Session is not available, flashing not possible!";
return;
}
++currFlashState;
if (currFlashState >= m_vecFlashColors.size())
currFlashState = 0;
qint64 currTime_ms = m_session->partitionTime();
int gearFlashTime_ms = LtsUtils::OperatorSettings::getInstance()
->value(QStringLiteral("BgViewer"), QStringLiteral("GearFlashTime_s"), 10)
.toInt() *
1000;
int maxGearFlashTime_ms = LtsUtils::OperatorSettings::getInstance()
->value(QStringLiteral("BgViewer"), QStringLiteral("maxGearFlashTime_s"), 120)
.toInt() *
1000;
auto itB = m_participantGearEvents.begin();
while (itB != m_participantGearEvents.end())
{
const int playerID = itB.key();
qint64 eventStartTime_ms = itB.value();
qint64 diff_ms = currTime_ms - eventStartTime_ms;
if (diff_ms > gearFlashTime_ms)
{
if (diff_ms > maxGearFlashTime_ms)
itB = m_participantGearEvents.erase(itB);
else
++itB;
m_connection->playerUpdatePlayerSymbol(playerID, buildPlayerSymbolFilePath(playerID, cColorSymbolId));
continue;
}
m_connection->playerUpdatePlayerSymbol(playerID, buildPlayerSymbolFilePath(playerID, currFlashState));
++itB;
}
for (auto it = m_lastPositionTime.cbegin(); it != m_lastPositionTime.cend(); ++it)
{
const int playerId = it.key();
const qint64 sampleTime = it.value();
if (isOutdatedPosition(sampleTime))
m_connection->setPlayerVisible(playerId, false);
}
}
} // namespace BuildingViewer