Files
qt5-legatus-legacy/Lts/Services/ParticipantManagement/ppm_dtc_impl_custom.cpp
T
2026-08-13 18:33:10 +02:00

862 lines
23 KiB
C++
Executable File

/**
* @RDE_HEADER@
* Custom ppm functions (extends tab_db_impl.cpp/.h)
* $Id$
* $HeadURL$
* $Author$
*/
#include "ppm_dtc_impl_custom.h"
#include "ppm_common.h"
#include <DDS/DTC/generic_dtc.h>
#include <DDS/Generic/generic_data_reader.h>
#include <LtsCoordTrans/lts_coord_trans.h>
#include <LtsUtilsCore/json_object.h>
#include <QJsonObject>
#include <QJsonParseError>
#include <QPolygonF>
#include <QSet>
#include <QVector>
namespace ParticipantManagement
{
namespace Interface
{
DtcImplCustom::DtcImplCustom(const std::shared_ptr<DDSConnector::DdsConnector> &ddsConnector)
: DtcImpl(ddsConnector)
{
}
bool DtcImplCustom::rootTemplates(QVector<TemplateParticipant> &templateVector) const
{
if (!m_dtcTemplateParticipant)
{
ERROR_LOG(m_logger) << "Error retrieving data topic TemplateParticipant";
return false;
}
for (const auto &sample : m_dtcTemplateParticipant->readAlive())
{
if (sample.data().superiorTemplateId() == 0)
templateVector.append(sample.data());
}
return !templateVector.isEmpty();
}
bool DtcImplCustom::templateParticipantsFromTemplateId(int rootTemplateId, QVector<TemplateParticipant> &templateVector)
{
templateVector.append(inferiorTemplates(rootTemplateId));
return !templateVector.isEmpty();
}
TemplateData DtcImplCustom::convertFromParticipantTemplateToTemplateData(const TemplateParticipant &inputTemplate) const
{
TemplateData outputData;
TemplateBase &out = outputData;
out = inputTemplate;
// in cases where the ids are not updated by the treeModel
outputData.modId(inputTemplate.templateId());
outputData.superiorModId(inputTemplate.superiorTemplateId());
return outputData;
}
ParticipantData Interface::DtcImplCustom::convertParticipantToParticipantData(const Participant &inputParticipant) const
{
ParticipantData outputData;
ParticipantBase &out = outputData;
out = inputParticipant;
// in cases where the ids are not updated by the treeModel
outputData.modId(inputParticipant.id());
outputData.superiorModId(inputParticipant.superiorId());
return outputData;
}
ParticipantManagement::StateInformation DtcImplCustom::youngestStateInformation(
const std::vector<ParticipantManagement::StateInformation> &stateList /*, bool debug*/) const
{
return ParticipantManagement::youngestStateInformation(stateList /*, true, true, debug*/);
}
ParticipantManagement::SanitationResult DtcImplCustom::proceduresDone(const std::vector<StateInformation> &stateList) const
{
return ParticipantManagement::proceduresDone(stateList);
}
QMap<int, Participant> DtcImplCustom::units() const
{
QMap<int, Participant> ret;
if (!m_dtcType)
{
ERROR_LOG(m_logger) << "Error retrieving data topic Type";
return ret;
}
if (!m_dtcParticipant)
{
ERROR_LOG(m_logger) << "Error retrieving data topic Participant";
return ret;
}
QSet<int> unitTypeIds;
for (const auto &sample : m_dtcType->readAlive())
{
if (sample.data().typeClass() == TypeClass::Unit || sample.data().typeClass() == TypeClass::SupportUnit)
unitTypeIds.insert(sample.data().id());
}
for (const auto &sample : m_dtcParticipant->readAlive())
{
if (unitTypeIds.contains(sample.data().typeId()))
ret.insert(sample.data().id(), sample.data());
}
return ret;
}
bool DtcImplCustom::participantIdsByUnit(int unitId, const QMap<int, Participant> &participants, QSet<int> &participantIds)
{
const ParticipantManagement::Participant unit(participants.value(unitId));
if (unit.id() != unitId)
return false;
const ParticipantManagement::Type unitType(type(unit.typeId()));
if (unitType.typeClass() != ParticipantManagement::TypeClass::Unit && unitType.typeClass() != ParticipantManagement::TypeClass::SupportUnit)
return false;
participantIds += recursiveInferiosForParticipant(unitId, participants);
return true;
}
bool DtcImplCustom::visibleParties(QMap<int32_t, Party> &visibleParties, const QVector<int> &filter) const
{
if (!m_dtcParty)
{
ERROR_LOG(m_logger) << "Error retrieving data topic Party";
return false;
}
const bool bAll = (filter.size() == 1 && filter.first() == -1);
for (const auto &sample : m_dtcParty->readAlive())
if (bAll || filter.contains(sample.data().id()))
visibleParties.insert(sample.data().id(), sample);
return true;
}
QString DtcImplCustom::hierarchyFromParticipant(int participantId) { return lookUpHierachy(participantId, participants()); }
QString DtcImplCustom::hierarchyFromParticipant(int participantId, const QMap<int, Participant> &participants) const
{
return lookUpHierachy(participantId, participants);
}
bool DtcImplCustom::isEquipmentNumberInUse(int equipmentNumber, int &exerciseId) const
{
if (!m_dtcEquipmentExerciseMapping)
return true; // we're not sure - return true ...
for (const auto &sample : m_dtcEquipmentExerciseMapping->readAlive())
{
for (const Equipment2ParticipantId &e2p : sample.data().mapping())
{
if (e2p.equipmentNumber() == equipmentNumber)
{
exerciseId = sample.data().exerciseId();
return true;
}
}
}
return false;
}
bool DtcImplCustom::isTypeInUse(int typeId) const
{
if (!m_dtcParticipant)
return true; // we're not sure - return true ...
for (const auto &sample : m_dtcParticipant->readAlive())
{
if (sample.data().typeId() == typeId)
return true;
}
return false;
}
int DtcImplCustom::participantIdByEquipmentNumber(int equipmentNumber) const
{
if (!m_dtcParticipant)
return -1;
for (const auto &sample : m_dtcParticipant->readAlive())
{
if (sample.data().equipmentNumber().is_set() && sample.data().equipmentNumber().get() == equipmentNumber)
return sample.data().id();
}
return -1;
}
int DtcImplCustom::equipmentNumberByParticipantId(int participantId) const
{
if (!m_dtcParticipant)
return -1;
for (const auto &sample : m_dtcParticipant->readAlive())
{
if (sample.data().id() == participantId)
{
if (sample.data().equipmentNumber().is_set())
return sample.data().equipmentNumber().get();
}
}
return -1;
}
int DtcImplCustom::uasMissionIdByEquipmentNumber(int equipmentNumber) const
{
if (m_dtcMissionPlan == nullptr)
{
return -1;
}
const int participantId = participantIdByEquipmentNumber(equipmentNumber);
if (participantId < 0)
{
return -1;
}
for (const auto &sample : m_dtcMissionPlan->readAlive())
{
if (sample.data().participantId() == participantId)
{
return sample.data().id();
}
}
return -1;
}
int DtcImplCustom::partyIdFromForceIdentifier(HlaForceIdentifierEnum inputForceIdentifier) const
{
if (!m_dtcParty)
return -1;
for (const auto &sample : m_dtcParty->readAlive())
{
if (sample.data().hlaForceIdentifier() == inputForceIdentifier)
return sample.data().id();
}
return -1;
}
ConnectState DtcImplCustom::saaConnectedState(const int partyId)
{
ConnectState ret = ConnectState::Undefined;
if (!isPartyEnabled())
{
enableParty();
waitForHistoricalDataParty(10);
}
if (!m_dtcParty)
return ret;
for (const auto &sample : m_dtcParty->readAlive())
{
if (partyId != sample.data().id())
continue;
QJsonDocument doc = QJsonDocument::fromJson(QByteArray::fromStdString(sample.data().properties()));
QJsonObject prop = doc.object();
QJsonObject propAdler;
if (prop.contains(QStringLiteral("Adler")))
{
propAdler = prop[QStringLiteral("Adler")].toObject();
if (propAdler.contains(QStringLiteral("saaConnectedState")))
return static_cast<ConnectState::inner_enum>(propAdler[QStringLiteral("saaConnectedState")].toInt());
}
}
return ret;
}
QVector<int> DtcImplCustom::getSubordinatesByParticipant(const int participantId)
{
QVector<int> result;
if (!m_dtcParticipant)
return result;
for (const auto &sample : m_dtcParticipant->readAlive())
{
if (sample.data().superiorId() == participantId)
result.append(sample.data().id());
}
return result;
}
QVector<int> DtcImplCustom::getParticipantsByPolygon(const QPolygonF &polygon, bool includeUnits, bool includeOc)
{
QVector<int> participantsInPolygon;
QSet<int> unitTypeIds;
if (!isParticipantPositionEnabled())
{
enableParticipantPosition();
waitForHistoricalDataParticipantPosition(10);
}
if (!includeUnits)
{
if (!isTypeEnabled())
{
enableType();
waitForHistoricalDataType(10);
}
for (const auto &sample : m_dtcType->readAlive())
{
if (sample.data().typeClass() == TypeClass::Unit || sample.data().typeClass() == TypeClass::SupportUnit)
unitTypeIds.insert(sample.data().id());
}
}
participantsInPolygon.reserve(m_dtcParticipantPosition->readAlive().length());
for (const auto &currentPosition : m_dtcParticipantPosition->readAlive())
{
if (!includeUnits && unitTypeIds.contains(currentPosition.data().participantTypeId()))
continue;
if (!includeOc && currentPosition.data().partyId() == 1) // partyId 1 = OC
continue;
const Core::GeoPosition &currentGeoPosition = currentPosition.data().pos();
const QPointF positionPoint(currentGeoPosition.lon(), currentGeoPosition.lat());
if (polygon.containsPoint(positionPoint, Qt::OddEvenFill))
participantsInPolygon.append(currentPosition.data().participantId());
}
return participantsInPolygon;
}
// All Participant-Ids of Type UAS
QVector<int> DtcImplCustom::getUasIds()
{
QVector<int> result;
if (!m_dtcParticipant)
return result;
for (const auto &sample : m_dtcParticipant->readAlive())
{
if (isTypeUas(sample.data().typeId()))
{
result.append(sample.data().id());
}
}
return result;
}
UAS DtcImplCustom::getUasByParticipantId(int participantId, int exerciseId) const
{
ParticipantManagement::UAS uas;
uas.id(-1); // if not found
for (const auto &sample : m_dtcUAS->readAlive())
{
if (sample.data().participantId() != participantId)
continue;
if (sample.data().exerciseId() != exerciseId)
continue;
uas = sample;
break;
}
return uas;
}
MissionAction DtcImplCustom::currentMissionAction(int missionPlanId) const
{
ParticipantManagement::MissionAction missionAction;
missionAction.planId(0); // default compare value in case nothing found
for (const auto &sample : m_dtcMissionPlan->readAlive())
{
if (sample.data().id() != missionPlanId)
continue;
const std::vector<ParticipantManagement::MissionItem> &items = sample.data().items();
for (const auto &item : items)
{
if (item.fulfilled() > 0)
continue;
const std::vector<ParticipantManagement::MissionAction> &actions = item.actions();
for (const auto &action : actions)
{
if (action.fulfilled() > 0)
continue;
return action;
}
}
}
return missionAction;
}
ParticipantManagement::Participant DtcImplCustom::getParticipantByInternalName(int partyId, const QString &unitName, const QString &internalName) const
{
for (const auto &sample : m_dtcParticipant->readAlive())
{
if (sample.data().partyId() != partyId)
continue;
if (sample.data().isDeleted())
continue;
if (sample.data().name() != unitName.toStdString())
continue;
// Found Unit
// looking for Unit only?
if (internalName.isEmpty())
{
return sample;
}
for (auto inferiorId : sample.data().inferiorIds())
{
const auto &inferiorParticipant = m_participantCont.value(inferiorId);
if (inferiorParticipant.id() <= 0 || inferiorParticipant.isDeleted())
continue;
if (inferiorParticipant.name() == internalName.toStdString())
return inferiorParticipant;
}
}
return ParticipantManagement::Participant();
}
QSet<int> DtcImplCustom::recursiveInferiosForParticipant(int32_t participantId, const QMap<int, Participant> &participants)
{
QSet<int> result;
auto it = participants.find(participantId);
if (it == participants.end())
return result;
result += participantId;
const Participant &p = it.value();
for (int childId : p.inferiorIds())
result += recursiveInferiosForParticipant(childId, participants);
return result;
}
QString DtcImplCustom::lookUpHierachy(int participantId, const QMap<int, Participant> &participants)
{
if (participantId <= 0)
return QString();
const auto itPart = participants.find(participantId);
if (itPart == participants.end())
return QString();
const auto &part = itPart.value();
QString supStr = lookUpHierachy(part.superiorId(), participants);
QString ret = QString::fromStdString(part.designator());
// First separator is "./"
if (part.superiorId() == 0)
return (ret + QLatin1String("./"));
if (supStr.endsWith(QLatin1String("./")))
return (supStr + ret);
return (supStr.isEmpty() ? ret : supStr + QLatin1Char(',') + ret);
}
// private
QVector<TemplateParticipant> DtcImplCustom::inferiorTemplates(int templateId)
{
QVector<TemplateParticipant> retVector;
const TemplateParticipant participant = templateParticipant(templateId);
retVector.append(participant);
if (participant.inferiorIds().is_set())
{
retVector.reserve(participant.inferiorIds().get().size() + retVector.size());
for (int inferiorId : participant.inferiorIds().get())
retVector.append(inferiorTemplates(inferiorId));
}
return retVector;
}
bool DtcImplCustom::isTypePatientSimulator(int typeId) const
{
if (!m_dtcParticipant)
return false;
for (const auto &sample : m_dtcParticipant->readAlive())
{
if (sample.data().typeId() == typeId)
{
const std::string &str = sample.data().properties();
if (str.size() > 0 && getNeedsIp(str) && getNeedsPort(str))
return true;
else
return false;
}
}
return false;
}
bool DtcImplCustom::isAdlerType(int typeId) const
{
if (!m_dtcType)
return false;
for (const Type &type : m_dtcType->readAlive())
{
if (type.id() != typeId)
continue;
const auto &prob = type.properties();
QJsonParseError parserError;
const QByteArray props(QByteArray::fromRawData(prob.c_str(), prob.size()));
const QJsonDocument doc(QJsonDocument::fromJson(props, &parserError));
if (parserError.error != QJsonParseError::NoError)
return false;
const QJsonObject obj(doc.object());
const auto val = obj.value(QStringLiteral("isMovable"));
if (val.isNull() || !val.isBool())
return false;
return !val.toBool();
}
return false;
}
bool DtcImplCustom::isArtilleryType(int typeId) const
{
if (!m_dtcType)
return false;
for (const Type &type : m_dtcType->readAlive())
{
if (type.id() != typeId)
continue;
const auto &prob = type.properties();
QJsonParseError parserError;
const QByteArray props(QByteArray::fromRawData(prob.c_str(), prob.size()));
const QJsonDocument doc(QJsonDocument::fromJson(props, &parserError));
if (parserError.error != QJsonParseError::NoError)
return false;
const QJsonObject obj(doc.object());
const auto val = obj.value(QStringLiteral("isArtillery"));
if (val.isNull() || !val.isBool())
return false;
return val.toBool();
}
return false;
}
bool DtcImplCustom::isEditable(int typeId) const
{
if (!m_dtcType)
return false;
for (const Type &type : m_dtcType->readAlive())
{
if (type.id() != typeId)
continue;
const auto &prob = type.properties();
QJsonParseError parserError;
const QByteArray props(QByteArray::fromRawData(prob.c_str(), prob.size()));
const QJsonDocument doc(QJsonDocument::fromJson(props, &parserError));
if (parserError.error != QJsonParseError::NoError)
return false;
const QJsonObject obj(doc.object());
const auto val = obj.value(QStringLiteral("isEditable"));
if (val.isNull() || !val.isBool())
return true;
return val.toBool();
}
return false;
}
bool DtcImplCustom::isAdlerVerbund(int typeId) const
{
if (!m_dtcType)
return false;
for (const Type &type : m_dtcType->readAlive())
{
if (type.id() != typeId)
continue;
const auto &prob = type.properties();
QJsonParseError parserError;
const QByteArray props(QByteArray::fromRawData(prob.c_str(), prob.size()));
const QJsonDocument doc(QJsonDocument::fromJson(props, &parserError));
if (parserError.error != QJsonParseError::NoError)
return false;
const QJsonObject obj(doc.object());
const auto val = obj.value(QStringLiteral("isAdlerVerbund"));
if (val.isNull() || !val.isBool())
return false;
return val.toBool();
}
return false;
}
bool DtcImplCustom::isPartyAdlerVerbund(int partyId) const
{
if (!m_dtcParty)
return false;
for (const Party &party : m_dtcParty->readAlive())
{
if (party.id() != partyId)
continue;
const auto &prob = party.properties();
QJsonParseError parserError;
const QByteArray props(QByteArray::fromRawData(prob.c_str(), prob.size()));
const QJsonDocument doc(QJsonDocument::fromJson(props, &parserError));
if (parserError.error != QJsonParseError::NoError)
return false;
const QJsonObject obj(doc.object());
if (!obj.contains(QStringLiteral("Adler")))
return false;
const QJsonObject adlerObj = obj[QStringLiteral("Adler")].toObject();
const auto val = adlerObj.value(QStringLiteral("isVerbund"));
if (val.isNull() || !val.isBool())
return false;
return val.toBool();
}
return false;
}
Type DtcImplCustom::getTypeFromAdlerType(const QString &adlerTypeName, bool isUnit, bool isVerbund)
{
Type ret;
if (!m_dtcType)
return ret;
for (const Type &type : m_dtcType->readAlive())
{
if (isUnit && type.typeClass() != TypeClass::Unit)
continue;
if (!isUnit && type.typeClass() != TypeClass::WeaponSystem)
continue;
const auto &prob = type.properties();
QJsonParseError parserError;
const QByteArray props(QByteArray::fromRawData(prob.c_str(), prob.size()));
const QJsonDocument doc(QJsonDocument::fromJson(props, &parserError));
if (parserError.error != QJsonParseError::NoError)
continue;
const QJsonObject obj(doc.object());
const auto val = obj.value(QStringLiteral("adlerType"));
if (val.isNull() || !val.isString())
continue;
if (val.toString() != adlerTypeName)
continue;
if (isAdlerVerbund(type.id()) != isVerbund)
continue;
// Found exact Type
DEBUG_LOG(m_logger) << "--- "
<< "Found exact type --> typeId= " << type.id() << " ---";
return type;
}
return ret;
}
// Properties in table ppm.ppm_type
bool DtcImplCustom::isTypeUas(int typeId)
{
if (!m_dtcType)
return false;
if (!isTypeEnabled())
{
enableType();
waitForHistoricalDataType(10);
}
for (const auto &sample : m_dtcType->readAlive())
{
// DEBUG_LOG(m_logger) << " sample equipmentTypeId=" << sample.data().equipmentTypeId();
if (sample.data().id() == typeId)
{
const std::string &str = sample.data().properties();
if (str.size() > 0 && getIsUAS(str))
return true;
else
return false;
}
}
return false;
}
UAS DtcImplCustom::getUasByParticipantId(int participantId, int exerciseId)
{
if (!isUASEnabled())
{
enableUAS();
waitForHistoricalDataUAS();
}
if (!m_dtcUAS)
return {};
for (const auto &sample : m_dtcUAS->readAlive())
{
if (sample.data().participantId() != participantId)
continue;
if (sample.data().exerciseId() != exerciseId)
continue;
return sample;
}
return {};
}
//---------------------------------------------------------------------------------------------------------------------------------------------
int DtcImplCustom::getParticipantFromPrf(int prf) const
{
DEBUG_LOG(m_logger) << "getParticipantFromPrf prf=" << prf;
if (!m_dtcParticipant)
return -1;
for (const DynamicParticipantData &sample : m_dtcDynamicParticipantData->readAlive())
{
for (const auto &designation : qAsConst(sample.designations()))
{
DEBUG_LOG(m_logger) << " code=" << designation.code();
if (designation.code() == prf)
{
DEBUG_LOG(m_logger) << " return code=" << designation.code();
return sample.participantId();
}
}
}
return -1;
}
int DtcImplCustom::getPrfFromParticipant(int participantId) const
{
DEBUG_LOG(m_logger) << "getPrfFromParticipant participantId=" << participantId;
if (!m_dtcParticipant)
return -1;
for (const DynamicParticipantData &sample : m_dtcDynamicParticipantData->readAlive())
{
if (participantId == sample.participantId())
{
DEBUG_LOG(m_logger) << "participantId=" << sample.participantId() << " designations.size()=" << sample.designations().size();
for (const auto &designation : qAsConst(sample.designations()))
{
DEBUG_LOG(m_logger) << " code=" << designation.code();
if (designation.code() > 0)
{
DEBUG_LOG(m_logger) << " return code=" << designation.code();
return designation.code();
}
}
return -1;
}
}
return -1;
}
bool DtcImplCustom::getNeedsIp(const std::string &s) const
{
QJsonParseError jError;
QJsonDocument doc(QJsonDocument::fromJson(s.c_str(), &jError));
if (jError.error != QJsonParseError::NoError || !doc.isObject())
{
return false;
}
QJsonObject obj(doc.object());
return obj[QStringLiteral("needsIP")].toBool();
}
bool DtcImplCustom::getNeedsPort(const std::string &s) const
{
QJsonParseError jError;
QJsonDocument doc(QJsonDocument::fromJson(s.c_str(), &jError));
if (jError.error != QJsonParseError::NoError || !doc.isObject())
{
return false;
}
QJsonObject obj(doc.object());
return obj[QStringLiteral("needsPort")].toBool();
}
QMap<double, int> DtcImplCustom::sortByDistance(const double lon, const double lat, const QVector<int> &participantIds)
{
DEBUG_LOG(m_logger) << " DtcImplCustom::sortByDistance";
int zone = -1;
if (!isParticipantPositionEnabled())
{
enableParticipantPosition();
waitForHistoricalDataParticipantPosition(10);
}
QMap<double, int> distanceMapSorted;
for (const auto &currentPosition : m_dtcParticipantPosition->readAlive())
{
if (participantIds.contains(currentPosition.data().participantId()))
{
auto pOrigin = LtsCoordTrans::UtmCoordinate::fromGeographic(lon, lat, zone);
auto pPos = LtsCoordTrans::UtmCoordinate::fromGeographic(currentPosition.data().pos().lon(), currentPosition.data().pos().lat(), zone);
double distance = LtsCoordTrans::distance(pPos, pOrigin);
DEBUG_LOG(m_logger) << distance;
// Save distance and particiapnt Id into temporar map.
// the map is sorted so we can use that later instead of writing a sort method vor a vec
// for now
distanceMapSorted.insert(distance, currentPosition.data().participantId());
DEBUG_LOG(m_logger) << "insert distance=" << distance << ", participantId=" << currentPosition.data().participantId();
}
}
QMapIterator<double, int> it(distanceMapSorted);
while (it.hasNext())
{
it.next();
DEBUG_LOG(m_logger) << "distance=" << it.key() << ", participantId=" << it.value();
}
return distanceMapSorted;
}
bool DtcImplCustom::getIsUAS(const std::string &s) const
{
QJsonParseError jError;
QJsonDocument doc(QJsonDocument::fromJson(s.c_str(), &jError));
if (jError.error != QJsonParseError::NoError || !doc.isObject())
{
return false;
}
QJsonObject obj(doc.object());
return obj[QStringLiteral("isUAS")].toBool();
}
} // namespace Interface
} // namespace ParticipantManagement