Files
qt-migration-legatus/qt6-after/qt6-migrated-legatus/Lts/Proxies/TrainingAreaBase/ism_handler.cpp
T
2026-10-03 09:20:13 +02:00

619 lines
21 KiB
C++
Executable File

#include "ism_handler.h"
#include <utility>
#include "main_handler.h"
#include "settings.h"
#include <NGLLogger/NGLLoggerBootstrap.h>
#include <QtCore/QJsonDocument>
#include <QJsonParseError>
#include <QtCore/QJsonObject>
namespace TrainingAreaBase
{
IsmHandler::IsmHandler(MainHandler *mainHandler) : m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger())
, m_mainHandler(mainHandler)
, m_dtcIsm(nullptr)
, m_distanceIpsToGps(Settings::distanceIpsToGps())
, m_distanceOpsToGps(Settings::distanceOpsToGps()) {}
bool IsmHandler::init()
{
if (m_dtcIsm)
return true;
m_dtcIsm = InfrastructureManagement::Interface::Dtc::create(m_mainHandler->ddsHandler()->ddsConnector());
connect(m_dtcIsm.get(), &InfrastructureManagement::Interface::Dtc::instrumentationAssetChanged,
this, &IsmHandler::onInstrumentationAssetChanged);
connect(m_dtcIsm.get(), &InfrastructureManagement::Interface::Dtc::mountingPointAssetChanged,
this, &IsmHandler::onMountingPointAssetChanged);
connect(m_dtcIsm.get(), &InfrastructureManagement::Interface::Dtc::mainStructureElementChanged,
this, &IsmHandler::onMainStructureElementChanged);
connect(m_dtcIsm.get(), &InfrastructureManagement::Interface::Dtc::mainFootprintChanged,
this, &IsmHandler::onMainFootprintChanged);
if (!m_dtcIsm->enableInstrumentationAsset() ||
!m_dtcIsm->enableMainStructureElement() ||
!m_dtcIsm->enableMountingPointAsset() ||
!m_dtcIsm->enableMainFootprint())
{
ERROR_LOG(m_logger) << "Can not read data from ISM";
return false;
}
return true;
}
IsmHandler::OpsData IsmHandler::dataFromOpsCode(int ipsCode)
{
if ( m_opsData.contains(ipsCode))
{
DEBUG_LOG(m_logger) << "dataFromOpsCode contains ipsCode:" << ipsCode
<< " assetId=" << m_opsData.value(ipsCode).assetId
<< " roomId=" << m_opsData.value(ipsCode).roomId
<< " mainStructureElementId=" << m_opsData.value(ipsCode).mainStructureElementId
<< " structureElementId=" << m_opsData.value(ipsCode).structureElementId
<< " mountingPointTypeId" << m_opsData.value(ipsCode).mountingPointTypeId;
if (m_opsData.value(ipsCode).mainStructureElementId > 0 || m_opsData.value(ipsCode).structureElementId > 0)
return m_opsData.value(ipsCode);
}
int assetId = m_dtcIsm->getAssetIdFromOpticalCode(ipsCode);
OpsData opsData;
if ( assetId < 0)
{
WARNING_LOG(m_logger) << "No asset for ops code=" << ipsCode << " found";
return {};
}
opsData.opsCode = ipsCode;
opsData.assetId = assetId;
DEBUG_LOG(m_logger) << "OpsData.structureElementId=" << opsData.structureElementId
<< " assetId=" << opsData.assetId
<< " mountingPointTypeId=" << opsData.mountingPointTypeId
<< " opsCode=" << opsData.opsCode
<< " mainStructureElementId=" << opsData.mainStructureElementId
<< " roomId=" << opsData.roomId;
{
DEBUG_LOG(m_logger) <<"---------------- UPDATE OPS-Data ------------------";
updateOpsData(opsData, true);
opsData= m_opsData[opsData.opsCode] ;
}
return opsData;
}
void IsmHandler::onInstrumentationAssetChanged(const InfrastructureManagement::InstrumentationAsset &data, DataModification modType)
{
if (data.mountingPointTypeId != InfrastructureManagement::MountingPointType::IndoorIPS &&
data.mountingPointTypeId != InfrastructureManagement::MountingPointType::OutdoorIPS)
return;
switch (modType)
{
case DataModification::eAdded:
case DataModification::eModified:
{
int opsCode = 0;
QHashIterator<int, OpsData> i(m_opsData);
while (i.hasNext()) {
i.next();
if ( i.value().assetId == data.id)
{
opsCode = i.value().opsCode;
DEBUG_LOG(m_logger) << "onInstrumentationAssetChanged assetId=" << data.id;
break;
}
}
OpsData &d = m_opsData[opsCode];
d.assetId = data.id;
d.opsCode = getOpsCodeFromJSon(data.properties);
d.opsTunnel = getIsOpsTunnel(data.properties);
d.mountingPointTypeId = static_cast<int>(data.mountingPointTypeId);
updateOpsData(d);
break;
}
case DataModification::eRemoved:
{
int opsCode = 0;
QHashIterator<int, OpsData> i(m_opsData);
while (i.hasNext()) {
i.next();
if ( i.value().assetId == data.id)
{
opsCode = i.value().opsCode;
DEBUG_LOG(m_logger) << "onInstrumentationAssetChanged assetId=" << data.id;
break;
}
}
m_opsData.remove(opsCode);
break;
}
}
}
void IsmHandler::onMountingPointAssetChanged(const InfrastructureManagement::MountingPointAsset &data, DataModification modType)
{
switch (modType)
{
case DataModification::eAdded:
case DataModification::eModified:
{
OpsData opsData;
opsData.opsCode = m_dtcIsm->getOpticalCodeFromAssetId(data.assetId);
opsData.assetId = data.assetId;
updateOpsData(opsData, true);
break;
}
case DataModification::eRemoved:
DEBUG_LOG(m_logger) << "onMountingPointAssetChanged Unmount id=" << data.id
<< " assetId=" << data.assetId;
removeOpsAsset(data.assetId);
break;
}
}
void IsmHandler::rotateBuildingFootprint(int mseId)
{
if ( m_relBuildingFootprintsRotated.contains(mseId))
{
DEBUG_LOG(m_logger) << " mainStructureElements.Rotate already done id=" << mseId;
return;
}
InfrastructureManagement::MainStructureElement mse = m_dtcIsm->mainStructureElement(mseId);
TetraIcd::RelativePosition relBldgPosition = m_mainHandler->posHandler()->geographicToRelative(mse.geoPosition);
DEBUG_LOG(m_logger) << " mainStructureElements.Rotate id=" << mseId;
QTransform matrix;
QPolygonF relBuildingFootprintMgrs;
qreal angle = mse.angle;
matrix.rotate(angle);
const QPolygonF relBuildingFootprint = m_relBuildingFootprints.value(mseId);
const QPolygonF relBuildingFootprintRotated = matrix.map(relBuildingFootprint);
m_relBuildingFootprintsRotated.insert(mseId, relBuildingFootprintRotated);
relBuildingFootprintMgrs.reserve(m_relBuildingFootprintsRotated.size());
for (const QPointF &p : relBuildingFootprintRotated)
{
QPointF relBuildingPoint(p.x() + relBldgPosition.offsetX,
p.y() + relBldgPosition.offsetY);
relBuildingFootprintMgrs.append(relBuildingPoint);
DEBUG_LOG(m_logger) << " relBuildingFootprintRotated = " << p.x() << "/" << p.y()
<< " relBuildingPointMgrs=" << relBuildingPoint.x() << "/" << relBuildingPoint.y()
<< " angle=" << angle;
}
m_relBuildingFootprintsRotatedMgrs.insert(mseId, relBuildingFootprintMgrs);
m_buildingBoundingBoxesMgrs.insert(mseId, relBuildingFootprintMgrs.boundingRect());
DEBUG_LOG(m_logger) << "BoundingBox bottomLeft=" << relBuildingFootprintMgrs.boundingRect().bottomLeft().x() << "/" << relBuildingFootprintMgrs.boundingRect().bottomLeft().x()
<< " topRight=" << relBuildingFootprintMgrs.boundingRect().topRight().x() << "/" << relBuildingFootprintMgrs.boundingRect().topRight().x();
}
void IsmHandler::onMainStructureElementChanged(const InfrastructureManagement::MainStructureElement &data, DataModification modType)
{
switch (modType)
{
case DataModification::eAdded:
case DataModification::eModified:
{
int exerciseId = m_mainHandler->ddsHandler()->getExerciseId();
if ( !m_dtcIsm->isElementAssignedToExercise(data, exerciseId))
{
INFO_LOG(m_logger) << "HandlerBuildingData::onMainStructureElementChanged() id=" << data.id << " remove";
m_buildingBoundingBoxes.remove(data.id);
m_relBuildingFootprints.remove(data.id);
m_relBuildingFootprintsRotated.remove((data.id));
m_buildingBoundingBoxesMgrs.remove(data.id);
m_relBuildingFootprintsRotatedMgrs.remove(data.id);
for (const auto &se : data.elements)
{
if (se.mountingPointTypeId != InfrastructureManagement::MountingPointType::IndoorIPS &&
se.mountingPointTypeId != InfrastructureManagement::MountingPointType::OutdoorIPS)
continue;
removeOpsDataByStructureElementId(se.id);
}
QMutableHashIterator<int, OpsData> iter(m_opsData);
while (iter.hasNext())
{
iter.next();
if (iter.value().mainStructureElementId == data.id)
{
DEBUG_LOG(m_logger) << "remove from m_opsData, key=" << iter.key();
iter.remove();
break;
}
}
return;
}
for (const InfrastructureManagement::StructureElement &se : data.elements)
{
if (se.mountingPointTypeId != InfrastructureManagement::MountingPointType::IndoorIPS &&
se.mountingPointTypeId != InfrastructureManagement::MountingPointType::OutdoorIPS)
continue;
auto it = std::find_if(m_opsData.begin(), m_opsData.end(), [se](const OpsData & d)
{
return d.structureElementId == se.id;
});
if (it != m_opsData.end())
updateOpsData(it.value());
}
DEBUG_LOG(m_logger) << " mainStructureElements Vor Rotate id=" << data.id;
QMap<int, InfrastructureManagement::MainFootprint> mainFootprints = m_dtcIsm->getFootprintsByExerciseId(exerciseId);
if (mainFootprints.contains(data.id))
{
rotateBuildingFootprint(data.id);
}
break;
}
case DataModification::eRemoved:
for (const auto &se : data.elements)
{
if (se.mountingPointTypeId != InfrastructureManagement::MountingPointType::IndoorIPS &&
se.mountingPointTypeId != InfrastructureManagement::MountingPointType::OutdoorIPS)
continue;
removeOpsDataByStructureElementId(se.id);
}
break;
}
}
void IsmHandler::onMainFootprintChanged(const InfrastructureManagement::MainFootprint &data, DataModification modType)
{
DEBUG_LOG(m_logger) << "onMainFootprintChanged id=" << data.id
<< " size=" << data.elements.size();
switch (modType)
{
case DataModification::eAdded:
case DataModification::eModified:
{
DEBUG_LOG(m_logger) << "mainStructureElements onMainFootprintChanged id=" << data.id;
double minX = 0;
double maxX = 0;
double minY = 0;
double maxY = 0;
QPolygonF relBuildingFootprint;
relBuildingFootprint.reserve(data.elements.size());
for (const InfrastructureManagement::FootprintElement &fpElem : data.elements)
{
const Core::RelativePosition &relPos = fpElem.relPosition;
minX = std::min(minX, relPos.offsetX);
maxX = std::max(maxX, relPos.offsetX);
minY = std::min(minY, relPos.offsetY);
maxY = std::min(maxY, relPos.offsetY);
QPointF point(relPos.offsetX, relPos.offsetY);
relBuildingFootprint.append(point);
DEBUG_LOG(m_logger) << "relBuildingFootprint.append() " << point.x() << "/" << point.y() << ")";
}
DEBUG_LOG(m_logger) << "minX=" << minX
<< " maxX=" << maxX
<< " minY=" << minY
<< " maxY=" << maxY
<< " m_distanceIpsToGps=" << m_distanceIpsToGps
<< " settings distanceIpsToGps=" << Settings::distanceIpsToGps();
QPointF boundingBoxTopLeft(minX - m_distanceIpsToGps, maxY + m_distanceIpsToGps);
QPointF boundingBoxBottomRight(maxX + m_distanceIpsToGps, minY - m_distanceIpsToGps);
QRectF BoundingBox(boundingBoxTopLeft, boundingBoxBottomRight);
m_buildingBoundingBoxes.insert(data.id, BoundingBox);
m_relBuildingFootprints.insert(data.id, relBuildingFootprint);
for (const QPointF &p : std::as_const(relBuildingFootprint))
DEBUG_LOG(m_logger) << "relBuildingFootprint = " << p.x() << "/" << p.y();
rotateBuildingFootprint(data.id);
break;
}
case DataModification::eRemoved:
{
break;
}
}
}
void IsmHandler::removeOpsDataByStructureElementId(int structureElementId)
{
auto copy = m_opsData;
for (const OpsData &pd : std::as_const(copy))
{
if (pd.structureElementId == structureElementId)
{
removeOpsAsset(pd.assetId);
break;
}
}
}
void IsmHandler::removeOpsAsset(int assetId)
{
int opsCode = 0;
for (const OpsData &pd : std::as_const(m_opsData))
{
if (pd.assetId == assetId)
{
m_structureElementId2AssetId.remove(pd.structureElementId);
opsCode = pd.opsCode;
break;
}
}
m_opsData.remove(opsCode);
}
int IsmHandler::getOpsCodeFromJSon(const std::string &s) const
{
QJsonParseError jError;
QJsonDocument doc(QJsonDocument::fromJson(s.c_str(), &jError));
if (jError.error != QJsonParseError::NoError ||
!doc.isObject())
{
ERROR_LOG(m_logger) << "Can not read json data from IPS asset - properties are not parsable: "
<< jError.errorString() << " - '" << s << "'";
return 0;
}
QJsonObject obj(doc.object());
return obj[QStringLiteral("opticalCode")].toInt();
}
bool IsmHandler::getIsOpsTunnel(const std::string &s) const
{
QJsonParseError jError;
QJsonDocument doc(QJsonDocument::fromJson(s.c_str(), &jError));
if (jError.error != QJsonParseError::NoError ||
!doc.isObject())
{
ERROR_LOG(m_logger) << "Can not read json data from IPS asset - properties are not parsable: "
<< jError.errorString() << " - '" << s << "'";
return false;
}
QJsonObject obj(doc.object());
if ( obj.contains(QStringLiteral("opsTunnel")))
return obj[QStringLiteral("opsTunnel")].toBool();
else
return false;
}
void IsmHandler::updateOpsData(OpsData &data, bool force)
{
DEBUG_LOG(m_logger) << "updateOpsData"
<< " opsCode=" << data.opsCode
<< " assetId=" << data.assetId
<< " force=" << force;
int exerciseId = m_mainHandler->ddsHandler()->getExerciseId();
DEBUG_LOG(m_logger) << "updateOpsData for asset " << data.assetId << " with ops id " << data.opsCode;
const int seId = m_dtcIsm->getStructueElementIdFromAssetId(data.assetId);
data.structureElementId = 0;
data.mainStructureElementId = 0;
data.roomId = 0;
data.position = Core::GeoPosition();
const auto &mainStructureElements = m_dtcIsm->mainStructureElements();
for (const auto &mse : std::as_const(mainStructureElements))
{
if (!force && !m_dtcIsm->isElementAssignedToExercise(mse, exerciseId))
continue;
for (const InfrastructureManagement::StructureElement &se : mse.elements)
{
if (se.id == seId)
{
data.structureElementId = seId;
data.mainStructureElementId = mse.id;
if (se.path.size() > 1)
data.roomId = se.path.at(se.path.size() - 2);
data.position = se.geoPosition;
data.position.z = data.position.z - mse.geoPosition.z;
m_structure_ElementId2AssetTypeId[seId] = static_cast<int>(se.mountingPointTypeId);
DEBUG_LOG(m_logger) << "found position for asset " << data.assetId << " with se id " << seId
<< " " << data.position.lon << "/" << data.position.lat << "/" << data.position.z
<< " name=" << se.name
<< " type=" << se.mountingPointTypeId
<< " m_structure_ElementId2AssetTypeId.size()=" << m_structure_ElementId2AssetTypeId.size();
data.mountingPointTypeId = static_cast<int>(se.mountingPointTypeId);
m_opsData[data.opsCode] = data;
return;
}
}
}
DEBUG_LOG(m_logger) << "found no position for asset " << data.assetId << " with se id " << seId;
}
bool IsmHandler::posInExtendedBuildingFootprint(int mainStructureElementId, const Core::GeoPosition &position, const int mountPointTypeId) const
{
int distance = 0;
DEBUG_LOG(m_logger) << "IsmHandler::posInExtendedBuildingFootprint mainStructureElementId=" << mainStructureElementId
<< " mountPointTypeId=" << mountPointTypeId;
if (m_distanceIpsToGps <= 0 && m_distanceOpsToGps <= 0)
return false;
switch (mountPointTypeId) {
case static_cast<int>(InfrastructureManagement::MountingPointType::OutdoorIPS):
DEBUG_LOG(m_logger) << "posInExtendedBuildingFootprint Distance = m_distanceOpsToGps";
distance = m_distanceOpsToGps;
break;
case static_cast<int>(InfrastructureManagement::MountingPointType::IndoorIPS):
DEBUG_LOG(m_logger) << "posInExtendedBuildingFootprint Distance = m_distanceIpsToGps";
distance = m_distanceIpsToGps;
break;
default:
return false;
}
DEBUG_LOG(m_logger) << "mainStructureElementId=" << mainStructureElementId
<< " position=" << position;
int exerciseId = m_mainHandler->ddsHandler()->getExerciseId();
InfrastructureManagement::MainStructureElement mse = m_dtcIsm->mainStructureElement(mainStructureElementId);
if ( !m_dtcIsm->isElementAssignedToExercise(mse, exerciseId))
return false;
if (!m_buildingBoundingBoxes.contains(mainStructureElementId))
return false;
TetraIcd::RelativePosition relBldgPosition = m_mainHandler->posHandler()->geographicToRelative(mse.geoPosition);
TetraIcd::RelativePosition relPosition = m_mainHandler->posHandler()->geographicToRelative(position);
DEBUG_LOG(m_logger) << "relBldgPosition=" << relBldgPosition.offsetX << "/" << relBldgPosition.offsetY
<< ", relPosition=" << relPosition.offsetX << "/" << relPosition.offsetY;
QPointF relPositionMgrs(relPosition.offsetX, relPosition.offsetY);
QPolygonF relBuildingFootprint = m_relBuildingFootprintsRotated[mainStructureElementId];
QPointF relPositionF(relPosition.offsetX - relBldgPosition.offsetX, relPosition.offsetY - relBldgPosition.offsetY);
if (relBuildingFootprint.containsPoint(relPositionF, Qt::OddEvenFill))
{
DEBUG_LOG(m_logger) << "Position is inside Building-Footprint";
return true;
}
DEBUG_LOG(m_logger) << "relBuildingFootprint.size=" << relBuildingFootprint.size();
for (int i = 0; i < relBuildingFootprint.size() ; i++)
{
int nextPoint = i + 1;
if (i == relBuildingFootprint.size() - 1)
nextPoint = 0;
QPointF l1(relBuildingFootprint[i].x() + relBldgPosition.offsetX, relBuildingFootprint[i].y() + relBldgPosition.offsetY);
QPointF l2(relBuildingFootprint[nextPoint].x() + relBldgPosition.offsetX, relBuildingFootprint[nextPoint].y() + relBldgPosition.offsetY);
double distancePointLineValue = distancePointLine(relPositionMgrs, l1, l2);
DEBUG_LOG(m_logger) << "distancePointLineValue=" << distancePointLineValue
<< " Point =" << relPositionMgrs.x() << "/" << relPositionMgrs.y()
<< " Line=" << l1.x() << "/" << l1.y()
<< " " << l2.x() << "/" << l2.y();
if (distancePointLineValue < distance)
{
DEBUG_LOG(m_logger) << "IsmHandler::posInExtendedBuildingFootprint return true";
return true;
}
}
DEBUG_LOG(m_logger) << "IsmHandler::posInExtendedBuildingFootprint return false";
return false;
}
double IsmHandler::distancePointLine(const QPointF &p, const QPointF &l1,
const QPointF &l2) const
{
const double u = (((p.x() - l1.x()) * (l2.x() - l1.x())) +
((p.y() - l1.y()) * (l2.y() - l1.y()))) / squareLen(l2, l1);
if (u < 0.0f || u > 1.0f)
{
QLineF pToP1(p, l1);
QLineF pToP2(p, l2);
qreal length1 = pToP1.length();
qreal length2 = pToP2.length();
if (length1 < length2)
{
DEBUG_LOG(m_logger) << "a distancePointLine p=" << p.x() << "/" << p.y()
<< " line: p1=" << l1.x() << "/" << l1.y()
<< " p2=" << l2.x() << "/" << l2.y()
<< " distance=" << length1
<< ", return=" << length1;
return length1;
}
else
{
DEBUG_LOG(m_logger) << "b distancePointLine p=" << p.x() << "/" << p.y()
<< " line: p1=" << l1.x() << "/" << l1.y()
<< " p2=" << l2.x() << "/" << l2.y()
<< " distance=" << length2
<< ", return=" << length2;
return length2;
}
}
QPointF intersectPnt(l1.x() + u * (l2.x() - l1.x()),
l1.y() + u * (l2.y() - l1.y()));
double distance = sqrt(squareLen(p, intersectPnt));
DEBUG_LOG(m_logger) << "c distancePointLine p=" << p.x() << "/" << p.y()
<< " line: p1=" << l1.x() << "/" << l1.y()
<< " p2=" << l2.x() << "/" << l2.y()
<< " distance=" << distance;
return distance;
}
double IsmHandler::squareLen(const QPointF &p1, const QPointF &p2)
{
double vx = p2.x() - p1.x();
double vy = p2.y() - p1.y();
return vx * vx + vy * vy;
}
}