Files
qt-migration-legatus/qt5-before/dlbo/Lts/Proxies/CombatNetRadio/positions_cnr.cpp
T
torstenandCopilot 7173785915 Qt6 Migration: Complete migration with DDS/RTI support and build validation
Major Changes:
- Merged latest Qt5 devel content from dlbo (292 files changed, 7 new dirs)
- Consolidated forward-declarations and include folders
- Removed unneeded modules per Niklas' repo check list

Build System Fixes:
- Fixed CMake VERSION_GREATER syntax in ParticipantManagement/CMakeLists.txt
- Added VLC packages (libvlc-dev, vlc-plugin-base) to docker_build.sh
- Added PostgreSQL dev packages (libpq-dev, postgresql-server-dev-all) to Dockerfile
- Fixed locale warnings (ANSI_X3.4-1968 → C.UTF-8)
- Fixed ArcGIS SDK path warnings when BUILD_ARCGIS=OFF

Code Generation Fixes:
- Fixed IDL enum collisions (PortType→CorePortType/DdsutPortType, PdmEventType)
- Fixed Grantlee template svc_translation.cpp.grantlee:
  - Changed {{ idl_enum.name }}_def:: to {{ idl_enum.name }}::
  - Fixed .underlying() calls for C++11 scoped enums (enum class)
- Removed generated files from repo (moc_*, *_dtc.h, *_ftc.h)

Validation:
- BUILD_RTI=ON: SUCCESS
- BUILD_RTI=OFF: SUCCESS
- C++17 standard maintained for RTI 7.7 compatibility
- Ubuntu 26.04 Docker environment verified

Remaining Warnings (expected):
- BgViewer, KDChart, KDReports, Poppler-Qt6 not found (optional features)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-09-15 18:20:26 +00:00

147 lines
4.5 KiB
C++

/**
* @RDE_HEADER@
* PositionsCnr
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Fröbel, NLE, 2019-08-05
*/
#include "positions_cnr.h"
#include "exercise_manager.h"
#include "helper.h"
#include <AudioVideoManagement/avm_dtc.h>
#include <ParticipantManagement/ppm_dtc.h>
#include <LtsUtilsCore/outdated_position.h>
#include <QtGlobal>
#include <QDateTime>
#include <QSet>
namespace
{
QSet<int> participantIdsFromParty(const QMap<int32_t, ParticipantManagement::Participant> &participants, int partyId, bool isGlobal)
{
QSet<int> ret;
if (isGlobal)
{
ret.reserve(participants.size());
for (const auto &p : participants)
ret += p.id();
}
else
{
for (const auto &participant : participants)
if (participant.partyId() == partyId)
ret += participant.id();
}
return ret;
}
} // anonymous namespace
namespace CombatNetRadio
{
PositionsCnr::PositionsCnr(int exerciseId, ExerciseManager *exerciseManager, ParticipantManagement::Interface::Dtc *ppmDtc, AudioVideoManagement::Interface::Dtc *avmDtc)
: m_exerciseId(exerciseId)
, m_exerciseManager(exerciseManager)
, m_ppmDtc(ppmDtc)
, m_avmDtc(avmDtc)
{
Q_ASSERT(exerciseId > 0);
Q_ASSERT(exerciseManager);
Q_ASSERT(ppmDtc);
Q_ASSERT(avmDtc);
}
WebSocketInterface::Messages::PositionsCnrMessage::PositionsCnrMessageData PositionsCnr::data() const
{
WebSocketInterface::Messages::PositionsCnrMessage::PositionsCnrMessageData positionsData;
positionsData.time = QDateTime::currentDateTime().toString(Qt::ISODate);
boost::optional<AudioVideoManagement::FrequencyPlanning> plan = activePlan();
if (!plan)
return positionsData;
for (const auto &entry : plan->data())
{
AudioVideoManagement::CnrConfig cnrConfig = m_avmDtc->cnrConfig(entry.cnrConfigId());
AudioVideoManagement::CnrChannel cnrChannel = m_avmDtc->cnrChannel(cnrConfig.cnrChannelId());
positionsData.radioCircuit.push_back({toRcIdString(cnrChannel), positionsFor(cnrConfig)});
}
return positionsData;
}
QVector<WebSocketInterface::Messages::ReplyMessage::LonLatPoint> PositionsCnr::positionsForGlobal(const AudioVideoManagement::CnrConfig &config) const
{
bool isGlobal = !config.exerciseId().is_set();
Q_ASSERT(isGlobal);
return positionsForLocal(config);
}
QVector<WebSocketInterface::Messages::ReplyMessage::LonLatPoint> PositionsCnr::positionsFor(const AudioVideoManagement::CnrConfig &config) const
{
bool isLocal = config.exerciseId().is_set();
if (isLocal)
return positionsForLocal(config);
else
return m_exerciseManager->positionsForGlobal(config);
}
/**
* Can be called for a global config, too. But then only positions for Participants of this Exercise will be returned.
*/
QVector<WebSocketInterface::Messages::ReplyMessage::LonLatPoint> PositionsCnr::positionsForLocal(const AudioVideoManagement::CnrConfig &config) const
{
auto allParticipants = m_ppmDtc->participants();
QSet<int> participantIdsInUnit;
if (config.unitId().is_set())
m_ppmDtc->participantIdsByUnit(config.unitId().get(), allParticipants, participantIdsInUnit);
else
{
bool isGlobal = !config.exerciseId().is_set();
participantIdsInUnit = participantIdsFromParty(allParticipants, config.partyId(), isGlobal);
}
const qint64 now = QDateTime::currentMSecsSinceEpoch();
QVector<WebSocketInterface::Messages::ReplyMessage::LonLatPoint> positions;
for (int participantId : qAsConst(participantIdsInUnit))
{
const ParticipantManagement::Participant &participant = allParticipants.value(participantId);
if (!participant.equipmentNumber().is_set())
continue;
const ParticipantManagement::Type &type = m_ppmDtc->type(participant.typeId());
if (type.radioCount() < 1)
continue; // participant has no radio equipped
const auto &pos = m_ppmDtc->participantPosition(participantId);
if (pos.participantId() != participantId)
continue; // participant has no position
if (LtsUtils::isPositionTimeOutdated(now, pos.sampleTime()))
continue; // position invalid
positions.push_back({toDeg(pos.pos().lon()), toDeg(pos.pos().lat())});
}
return positions;
}
boost::optional<AudioVideoManagement::FrequencyPlanning> PositionsCnr::activePlan() const
{
AudioVideoManagement::ActiveFrequencyPlanning activePlanning = m_avmDtc->activeFrequencyPlanning(m_exerciseId);
if (activePlanning.exerciseId() != m_exerciseId)
return boost::none;
return m_avmDtc->frequencyPlanning(activePlanning.frequencyPlanningId());
}
} // namespace CombatNetRadio