455 lines
17 KiB
C++
Executable File
455 lines
17 KiB
C++
Executable File
/**
|
|
* Handler for player data
|
|
* $Id$
|
|
* $HeadURL$
|
|
* $Author$
|
|
* Created by hjl, SLSE, 2017-02-20
|
|
*/
|
|
|
|
#include "handler_aes_data.h"
|
|
#include "settings.h"
|
|
|
|
#include <CentralEffectSimulation/handler_participant.h>
|
|
#include <CentralEffectSimulation/handler_building_data.h>
|
|
|
|
#include <QPainterPath>
|
|
#include <QPointF>
|
|
#include <QPolygonF>
|
|
#include <QTimer>
|
|
#include <QTransform>
|
|
|
|
#include <LtsUtilsCore/dds_bitarray.h>
|
|
#include <LtsUtilsCore/qpoint3d.h>
|
|
#include <LtsCoordTrans/lts_coord_trans.h>
|
|
|
|
|
|
namespace Ces2D
|
|
{
|
|
|
|
HandlerAesData::HandlerAesData(const std::shared_ptr<CentralEffectSimulation::DdsHandler> &ddsHandler,
|
|
const std::shared_ptr<CentralEffectSimulation::HandlerBuildingData> &buildingDataHandler,
|
|
QObject *parent)
|
|
|
|
: QObject(parent)
|
|
, m_ddsHandler(ddsHandler)
|
|
, m_handlerBuildingData(buildingDataHandler)
|
|
, m_logger(getLogger("HandlerAesData"))
|
|
{
|
|
} // end of ctor()
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HandlerAesData::~HandlerAesData()
|
|
{
|
|
} // end of dtor()
|
|
//-----------------------------------------------------------------------------
|
|
bool HandlerAesData::init()
|
|
{
|
|
auto dtcAes = m_ddsHandler->dtcAes();
|
|
auto dtcIsm = m_ddsHandler->dtcIsm();
|
|
auto ftcTab = m_ddsHandler->ftcTab();
|
|
dtcIsm->enableMainFootprint();
|
|
dtcAes->enableAirSupportImpact();
|
|
dtcAes->waitForHistoricalDataExplosionSingleCentral(20000);
|
|
ftcTab->enableSendCesHitInformation();
|
|
|
|
connect(dtcAes.get(), &AreaEffectSimulation::Interface::Dtc::explosionSingleChanged,
|
|
this, &HandlerAesData::onExplosionSingleChanged);
|
|
connect(dtcAes.get(), &AreaEffectSimulation::Interface::Dtc::airSupportImpactChanged,
|
|
this, &HandlerAesData::onAirSupportImpactChanged);
|
|
connect(dtcAes.get(), &AreaEffectSimulation::Interface::Dtc::triggeredImpactsChanged,
|
|
this, &HandlerAesData::onTriggeredImpactsChanged);
|
|
connect(dtcAes.get(), &AreaEffectSimulation::Interface::Dtc::aesItemViewChanged,
|
|
this, &HandlerAesData::onAesItemViewChanged);
|
|
connect(dtcIsm.get(), &InfrastructureManagement::Interface::Dtc::mainFootprintChanged,
|
|
this, &HandlerAesData::onMainFootprintChanged);
|
|
|
|
// Get 'static' data for all MainFootprints
|
|
{
|
|
auto cb = [this](const InfrastructureManagement::MainFootprint & mfp)
|
|
{
|
|
onMainFootprintChanged(mfp, DataModification::eAdded);
|
|
};
|
|
if (!dtcIsm->mainFootprints(cb))
|
|
return false;
|
|
}
|
|
// Get 'static' data for all AesItemView
|
|
{
|
|
auto cb = [this](const AreaEffectSimulation::AesItemView & aiv)
|
|
{
|
|
onAesItemViewChanged(aiv, DataModification::eAdded);
|
|
};
|
|
if (!dtcAes->aesItemViews(cb))
|
|
return false;
|
|
}
|
|
|
|
//Get AesNames for all Danger Areas
|
|
connect(dtcAes.get(), &AreaEffectSimulation::Interface::Dtc::dangerAreaChanged,
|
|
this, cbGetNames);
|
|
dtcAes->dangerAreas(cbGetNames);
|
|
|
|
//Get AesNames for all Nuclear Contaminations
|
|
connect(dtcAes.get(), &AreaEffectSimulation::Interface::Dtc::nContaminationChanged,
|
|
this, cbGetNames);
|
|
dtcAes->nContaminations(cbGetNames);
|
|
|
|
//Get AesNames for all Mine Areas
|
|
connect(dtcAes.get(), &AreaEffectSimulation::Interface::Dtc::mineAreaChanged,
|
|
this, cbGetNames);
|
|
dtcAes->mineAreas(cbGetNames);
|
|
|
|
//Get AesNames for all Functionsl Areas
|
|
connect(dtcAes.get(), &AreaEffectSimulation::Interface::Dtc::functionalAreaChanged,
|
|
this, cbGetNames);
|
|
dtcAes->functionalAreas(cbGetNames);
|
|
|
|
return true;
|
|
} // end of init()
|
|
//-----------------------------------------------------------------------------
|
|
// ///////////////////////////////////
|
|
// A E S (AreaEffectSimulation)
|
|
// ///////////////////////////////////
|
|
|
|
void HandlerAesData::onAesItemViewChanged(const AreaEffectSimulation::AesItemView &data, DataModification modType)
|
|
{
|
|
if (modType != DataModification::eAdded &&
|
|
modType != DataModification::eModified)
|
|
return;
|
|
|
|
DEBUG_LOG(m_logger) << "Got AesItemView: " << data.effectStateId();
|
|
switch (data.effectStateId().underlying())
|
|
{
|
|
case AreaEffectSimulation::AesEffectState_def::EsUnknown:
|
|
case AreaEffectSimulation::AesEffectState_def::EsError:
|
|
case AreaEffectSimulation::AesEffectState_def::EsExpired:
|
|
case AreaEffectSimulation::AesEffectState_def::EsRemoved:
|
|
removeStates(data);
|
|
m_aesItemViews.remove(data.aesItemId());
|
|
break;
|
|
case AreaEffectSimulation::AesEffectState_def::EsPrepared:
|
|
case AreaEffectSimulation::AesEffectState_def::EsPaused:
|
|
case AreaEffectSimulation::AesEffectState_def::EsActivated:
|
|
case AreaEffectSimulation::AesEffectState_def::EsFired:
|
|
m_aesItemViews.insert(data.aesItemId(), data);
|
|
break;
|
|
case AreaEffectSimulation::AesEffectState_def::EsCreated:
|
|
case AreaEffectSimulation::AesEffectState_def::EsReceived:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void HandlerAesData::removeStates(const AreaEffectSimulation::AesItemView &data)
|
|
{
|
|
if (data.aesTypeId() != AreaEffectSimulation::AesType_def::AtExplosionArea)
|
|
return;
|
|
DEBUG_LOG(m_logger) << "Remove aesItemId=" << data.aesItemId();
|
|
// remove State for each building
|
|
for (BitfieldStates &bfs : m_bitfieldStatesBld)
|
|
bfs.remove(data.aesItemId());
|
|
} // end removeStates
|
|
|
|
void HandlerAesData::onExplosionSingleChanged(const AreaEffectSimulation::ExplosionSingle &data, DataModification modType)
|
|
{
|
|
bool handleExplosion = false;
|
|
if (modType != DataModification::eAdded &&
|
|
modType != DataModification::eModified)
|
|
{
|
|
m_explosionSingleState.remove(data.id());
|
|
return;
|
|
}
|
|
|
|
if (data.effectStateId() == AreaEffectSimulation::AesEffectState_def::EsRemoved)
|
|
{
|
|
DEBUG_LOG(m_logger) << "Remove SingleExplosion";
|
|
m_explosionSingleState.remove(data.id());
|
|
return;
|
|
}
|
|
// Only handle transitions from prepared to activated
|
|
if (m_explosionSingleState.value(data.id()) == AreaEffectSimulation::AesEffectState_def::EsPrepared
|
|
&& data.effectStateId() == AreaEffectSimulation::AesEffectState_def::EsActivated)
|
|
{
|
|
DEBUG_LOG(m_logger) << "Handle SingleExplosion";
|
|
handleExplosion = true;
|
|
}
|
|
m_explosionSingleState.insert(data.id(), data.effectStateId());
|
|
|
|
|
|
DEBUG_LOG(m_logger) << "Got ExplosionSingle";
|
|
if (handleExplosion)
|
|
{
|
|
const double impactRadius = m_ddsHandler->chargeTypeRadius(data.chargeTypeId());
|
|
DEBUG_LOG(m_logger) << "Handle ExplosionSingle (EsActivated)";
|
|
|
|
// Bounding-Box-Check
|
|
// QMap<int, Footprint> m_footprints;
|
|
for (const Footprint &footprint : qAsConst(m_footprints))
|
|
{
|
|
const QPointF impactPos(CentralEffectSimulation::geographic2Utm(data.impactPosition(), footprint.zone));
|
|
const QPolygonF polyBldgRadius({QPointF(footprint.boundingBoxPolyUtm.bottomLeft().rx() - impactRadius,
|
|
footprint.boundingBoxPolyUtm.bottomLeft().ry() + impactRadius),
|
|
QPointF(footprint.boundingBoxPolyUtm.topRight().rx() + impactRadius,
|
|
footprint.boundingBoxPolyUtm.bottomLeft().ry() + impactRadius),
|
|
QPointF(footprint.boundingBoxPolyUtm.topRight().rx() + impactRadius,
|
|
footprint.boundingBoxPolyUtm.topRight().ry() - impactRadius),
|
|
QPointF(footprint.boundingBoxPolyUtm.bottomLeft().rx() - impactRadius,
|
|
footprint.boundingBoxPolyUtm.topRight().ry() - impactRadius)});
|
|
if (polyBldgRadius.containsPoint(impactPos, Qt::OddEvenFill))
|
|
{
|
|
//calculateImpacts(data, footprint.mseId);
|
|
// check, if impact-pos + munition-radius touch the building
|
|
// get radius of munition
|
|
const Core::GeoPosition2D impactPosition(data.impactPosition().lon(), data.impactPosition().lat());
|
|
if (inFootprint(impactPosition, impactRadius, footprint))
|
|
{
|
|
DEBUG_LOG(m_logger) << "ftc sendCESHitOnBuilding mseId = " << footprint.mseId
|
|
<< " chargeTypeId = " << data.chargeTypeId()
|
|
<< " id = " << data.id()
|
|
<< " currentPartitionTime = " << m_ddsHandler->currentPartitionTime()
|
|
<< " impactPosition.lon = " << impactPosition.lon()
|
|
<< " impactPosition.lat = " << impactPosition.lat();
|
|
|
|
Buildings::SendCesHitOnBuildingRequest requestBld(
|
|
footprint.mseId,
|
|
data.chargeTypeId(),
|
|
data.id(),
|
|
m_ddsHandler->currentPartitionTime(),
|
|
Core::GeoPosition(impactPosition.lon(), impactPosition.lat(), 0.0));
|
|
m_ddsHandler->ftcBld()->sendCesHitOnBuildingRequest(requestBld, this);
|
|
}
|
|
else
|
|
DEBUG_LOG(m_logger) << "Not sendCESHitOnBuilding mseId = " << footprint.mseId;
|
|
|
|
DEBUG_LOG(m_logger) << "boundingBoxImpact.contains(footprint)";
|
|
}
|
|
} // for
|
|
}
|
|
} // onExplosionSingleChanged
|
|
|
|
void HandlerAesData::onAirSupportImpactChanged(const AreaEffectSimulation::AirSupportImpact &data, DataModification modType)
|
|
{
|
|
DEBUG_LOG(m_logger) << "Got onAirSupportImpactChanged()";
|
|
AreaEffectSimulation::ExplosionSingle esData;
|
|
esData.id(data.id());
|
|
esData.chargeTypeId(data.chargeTypeId());
|
|
esData.impactPosition(data.impactPosition());
|
|
esData.effectStateId(data.effectStateId());
|
|
onExplosionSingleChanged(esData, modType);
|
|
} // onExplosionSingleChanged
|
|
|
|
void HandlerAesData::onTriggeredImpactsChanged(const AreaEffectSimulation::TriggeredImpacts &data, DataModification modType)
|
|
{
|
|
if (modType != DataModification::eAdded &&
|
|
modType != DataModification::eModified)
|
|
return;
|
|
|
|
DEBUG_LOG(m_logger) << "Got TriggeredImpacts";
|
|
preCalculateImpacts(data);
|
|
}
|
|
|
|
// ///////////////////////////////////
|
|
// I S M (InfrastructureManagement)
|
|
// ///////////////////////////////////
|
|
void HandlerAesData::onMainFootprintChanged(const InfrastructureManagement::MainFootprint &data, DataModification modType)
|
|
{
|
|
switch (modType)
|
|
{
|
|
case DataModification::eAdded:
|
|
case DataModification::eModified:
|
|
DEBUG_LOG(m_logger) << "Got MainFootprint (Building)";
|
|
calculateFootprint(data);
|
|
break;
|
|
case DataModification::eRemoved:
|
|
m_footprints.remove(data.id());
|
|
break;
|
|
}
|
|
}
|
|
|
|
// ///////////////////////////////////
|
|
// Calculations:
|
|
// ///////////////////////////////////
|
|
|
|
void HandlerAesData::calculateFootprint(const InfrastructureManagement::MainFootprint &mainFootprint)
|
|
{
|
|
DEBUG_LOG(m_logger) << "Footprint: " << mainFootprint.id() << ": " << mainFootprint;
|
|
DEBUG_LOG(m_logger) << "Footprint: " << " mainFootprint.elements().size()=" << mainFootprint.elements().size();
|
|
|
|
// If poly is Empty continue with next Footprint
|
|
if (mainFootprint.elements().size() <= 0)
|
|
return;
|
|
|
|
const InfrastructureManagement::MainStructureElement mse
|
|
= m_handlerBuildingData->mainStructureElement(mainFootprint.id());
|
|
if (mse.id() != mainFootprint.id())
|
|
{
|
|
// not (yet) there
|
|
QTimer::singleShot(1000, this, [this, mainFootprint]() { calculateFootprint(mainFootprint); });
|
|
return;
|
|
}
|
|
|
|
// insert all Points to poly
|
|
QPolygonF poly;
|
|
poly.reserve(mainFootprint.elements().size());
|
|
for (const InfrastructureManagement::FootprintElement &element : mainFootprint.elements())
|
|
{
|
|
const auto &relPos = element.relPosition();
|
|
poly.push_back(QPointF(relPos.offsetX(), relPos.offsetY()));
|
|
}
|
|
|
|
// rotate poly
|
|
QTransform trans;
|
|
trans.rotate(mse.angle());
|
|
poly = trans.map(poly);
|
|
|
|
Footprint footprint;
|
|
footprint.mseId = mainFootprint.id();
|
|
footprint.geoPosition = mse.geoPosition();
|
|
const QPointF utmFpPosition = CentralEffectSimulation::geographic2Utm(footprint.geoPosition, &footprint.zone);
|
|
footprint.polyUtm.reserve(poly.size());
|
|
for (const QPointF &point : qAsConst(poly))
|
|
footprint.polyUtm.push_back(utmFpPosition + point);
|
|
footprint.boundingBoxPolyUtm = footprint.polyUtm.boundingRect();
|
|
|
|
m_footprints.insert(footprint.mseId, footprint);
|
|
}
|
|
|
|
bool HandlerAesData::inFootprint(const Core::GeoPosition2D &geoPosition, const double radius, const Footprint &footPrint) const
|
|
{
|
|
const QPointF impact(CentralEffectSimulation::geographic2Utm(geoPosition, footPrint.zone));
|
|
|
|
if (m_logger.isDebugEnabled())
|
|
{
|
|
const QPointF utmBuilding(CentralEffectSimulation::geographic2Utm(footPrint.geoPosition, footPrint.zone));
|
|
DEBUG_LOG(m_logger) << "Impact (x/y)=" << CentralEffectSimulation::debug(impact - utmBuilding);
|
|
for (int i = 0; i < footPrint.polyUtm.length(); i++)
|
|
DEBUG_LOG(m_logger) << " poly (x/y)=" << CentralEffectSimulation::debug(footPrint.polyUtm[i] - utmBuilding);
|
|
}
|
|
|
|
// Check, if hit direct on building
|
|
if (footPrint.polyUtm.containsPoint(impact, Qt::OddEvenFill))
|
|
return true;
|
|
|
|
// Check, if hit in munition-radius
|
|
QPainterPath ppFp;
|
|
ppFp.addPolygon(footPrint.polyUtm);
|
|
QPainterPath ppCircle;
|
|
ppCircle.addEllipse(impact, radius, radius);
|
|
return ppFp.intersects(ppCircle);
|
|
}
|
|
|
|
void HandlerAesData::preCalculateImpacts(const AreaEffectSimulation::TriggeredImpacts &data)
|
|
{
|
|
if (data.id() <= 0)
|
|
return;
|
|
DEBUG_LOG(m_logger) << "preCalculateImpacts";
|
|
// Find AES ItemView and set Bounding-Box of Aes-Field
|
|
|
|
// Search corresponding itemView and get boundingBox data in UTM
|
|
const bool bFound = m_aesItemViews.contains(data.aesItemId());
|
|
if (!bFound)
|
|
{
|
|
WARNING_LOG(m_logger) << "Could not find item view for aes with id " << data.aesItemId();
|
|
return;
|
|
}
|
|
// Bounding-Box-Check
|
|
// QMap<int, Footprint> m_footprints;
|
|
for (const Footprint &footprint : qAsConst(m_footprints))
|
|
{
|
|
//if (boundingBoxImpact.contains(footprint.boundingBoxPolyUtm))
|
|
calculateImpacts(data, footprint);
|
|
} // for
|
|
|
|
}
|
|
|
|
void HandlerAesData::onSendCesHitOnBuildingReply(const Core::FunctionReplyObject &replyObject)
|
|
{
|
|
if (replyObject.error())
|
|
WARNING_LOG(m_logger) << "Can not send hit on building to building service: " << replyObject();
|
|
else
|
|
DEBUG_LOG(m_logger) << "onSendCesHitOnBuildingReply for id " << replyObject.id() << " success\n"
|
|
<< " replyObject.str() = " << replyObject.str();
|
|
}
|
|
|
|
void HandlerAesData::onSendCesHitInformationReply(const Core::FunctionReplyObject &reply)
|
|
{
|
|
if (reply.error())
|
|
WARNING_LOG(m_logger) << "onSendCesHitInformationReply for id " << reply.id() << " failed: " << reply.str();
|
|
else
|
|
DEBUG_LOG(m_logger) << "onSendCesHitInformationReply for id " << reply.id() << " successful";
|
|
}
|
|
|
|
// calculate impacts for one building
|
|
void HandlerAesData::calculateImpacts(const AreaEffectSimulation::TriggeredImpacts &data, const Footprint &footprint)
|
|
{
|
|
// check for correct AES type artillery only
|
|
switch (data.aesTypeId().underlying())
|
|
{
|
|
case AreaEffectSimulation::AesType_def::AtExplosionArea:
|
|
case AreaEffectSimulation::AesType_def::AtExplosionSingle:
|
|
case AreaEffectSimulation::AesType_def::AtExplosionAreaSingleExplosions:
|
|
DEBUG_LOG(m_logger) << "Calculate";
|
|
break;
|
|
default:
|
|
DEBUG_LOG(m_logger) << "No Calculation";
|
|
return;
|
|
}
|
|
|
|
DEBUG_LOG(m_logger) << "calculateImpacts mseId=" << footprint.mseId << " data.aesItemId() " << data.aesItemId();
|
|
|
|
|
|
// get position(s) of impact(s):
|
|
|
|
// Search corresponding itemView. If not available no impact to participant.
|
|
auto it = m_aesItemViews.constFind(data.aesItemId());
|
|
if (it == m_aesItemViews.constEnd())
|
|
{
|
|
WARNING_LOG(m_logger) << "TriggeredExplosions.aesItemId=" << data.aesItemId() << " No aesItemView available";
|
|
return;
|
|
}
|
|
|
|
BitfieldStates &bitfieldStates = m_bitfieldStatesBld[footprint.mseId];
|
|
QSet<int> &bitfieldState = bitfieldStates[data.aesItemId()];
|
|
for (int i : qAsConst(bitfieldState))
|
|
DEBUG_LOG(m_logger) << "bitfieldState for " << data.aesItemId() << ": " << i;
|
|
|
|
const AreaEffectSimulation::AesItemView &aesItemView = *it;
|
|
for (int32_t bitFieldIdx = 0; bitFieldIdx < data.impactCount(); ++bitFieldIdx)
|
|
{
|
|
// no break, because every bit can be a hit
|
|
if (LtsUtils::BitArray::testBit(data.bitfield(), bitFieldIdx))
|
|
continue;
|
|
|
|
// get position of impact to corresponding bit
|
|
if (aesItemView.form().size() <= size_t(bitFieldIdx))
|
|
continue;
|
|
|
|
const Core::GeoPosition2D &impactPosition = aesItemView.form()[bitFieldIdx];
|
|
DEBUG_LOG(m_logger) << LOGFUNCTION
|
|
<< " impactPosition: lat/lon" << impactPosition.lat() << "/" << impactPosition.lon()
|
|
<< " UTM=" << CentralEffectSimulation::debug(CentralEffectSimulation::geographic2Utm(impactPosition));
|
|
|
|
// check, if impact-pos + munition-radius touch the building
|
|
// get radius of munition
|
|
const double impactRadius = m_ddsHandler->chargeTypeRadius(aesItemView.chargeTypeId());
|
|
if (inFootprint(impactPosition, impactRadius, footprint))
|
|
{
|
|
DEBUG_LOG(m_logger) << "In Footprint mseId = " << footprint.mseId;
|
|
if (!bitfieldState.contains(bitFieldIdx))
|
|
{
|
|
bitfieldState.insert(bitFieldIdx);
|
|
|
|
DEBUG_LOG(m_logger) << "m_bitfieldStates.insert(data.aesItemId()=" << data.aesItemId() << ", bitfieldState)" << " bitFieldIdx=" << bitFieldIdx;
|
|
|
|
DEBUG_LOG(m_logger) << "ftc sendCESHitOnBuilding mseId = " << footprint.mseId << " bitFieldIdx= " << bitFieldIdx ;
|
|
Buildings::SendCesHitOnBuildingRequest requestBld(
|
|
footprint.mseId,
|
|
aesItemView.chargeTypeId(),
|
|
aesItemView.aesItemId(),
|
|
m_ddsHandler->currentPartitionTime(),
|
|
Core::GeoPosition(impactPosition.lon(), impactPosition.lat(), 0.0));
|
|
m_ddsHandler->ftcBld()->sendCesHitOnBuildingRequest(requestBld, this);
|
|
}
|
|
}
|
|
} // foreach Impact
|
|
}
|
|
|
|
} // namespace Ces2D
|