1507 lines
55 KiB
C++
Executable File
1507 lines
55 KiB
C++
Executable File
/**
|
|
* Handler for all exercise objects
|
|
* $Id$
|
|
* $HeadURL$
|
|
* $Author$
|
|
* Created by Hanna E. Rathje, SLSE, 2015-09-03
|
|
*/
|
|
|
|
#include "handler_mine_area.h"
|
|
#include "Utils/polygons.h"
|
|
#include "handler_effect_cluster.h"
|
|
#include "handler_mine_corridor.h"
|
|
#include "object_mine_area_null.h"
|
|
#include "settings.h"
|
|
#include <QPainterPath>
|
|
#include <QPolygonF>
|
|
#include <QSet>
|
|
#include <TrainingAreaBase/tab_dtc.h>
|
|
#include <TrainingAreaBase/Plugins/AdlerJson/telegrams.h>
|
|
|
|
namespace AreaEffectSimulation
|
|
{
|
|
|
|
HandlerMineArea::HandlerMineArea(MainHandler *mainHandler)
|
|
: HandlerBaseTmpl<ObjectMineArea>(mainHandler, QStringLiteral("MineArea"), s_areaCount[AesType::AtMineArea], s_areaCountCentral[AesType::AtMineArea])
|
|
, Interface::Fts::MineAreaModifyRequestHandler(mainHandler->dds()->fts())
|
|
, Interface::Fts::MineAreaRemoveRequestHandler(mainHandler->dds()->fts())
|
|
, Interface::Fts::MineResetRequestHandler(mainHandler->dds()->fts())
|
|
, Interface::Fts::MineTriggeredRequestHandler(mainHandler->dds()->fts())
|
|
, Interface::Fts::MineAreaModifyFromCtaDataRequestHandler(mainHandler->dds()->fts())
|
|
, Interface::Fts::MineAreaReferenceModifyRequestHandler(mainHandler->dds()->fts())
|
|
, m_nullArea(new ObjectMineAreaNull(mainHandler, this))
|
|
{
|
|
}
|
|
|
|
bool HandlerMineArea::isDusMineArea(int chargeTypeId, int igniterTypeId, int igniterFunctionId) const
|
|
{
|
|
return static_cast<MineClass::type>(m_mainHandler->dds()->pdmDtc()->mineClass(chargeTypeId, igniterTypeId, igniterFunctionId)) == MineClass::DUS;
|
|
}
|
|
|
|
bool HandlerMineArea::isConcreteMine(int chargeTypeId, int igniterTypeId, int igniterFunctionId) const
|
|
{
|
|
return static_cast<MineClass::type>(m_mainHandler->dds()->pdmDtc()->mineClass(chargeTypeId, igniterTypeId, igniterFunctionId)) == MineClass::Concrete;
|
|
}
|
|
|
|
bool HandlerMineArea::isFromMineLayer(int chargeTypeId, int igniterTypeId, int igniterFunctionId) const
|
|
{
|
|
return m_mainHandler->dds()->pdmDtc()->isFromMineLayer(chargeTypeId, igniterTypeId, igniterFunctionId);
|
|
}
|
|
|
|
bool HandlerMineArea::isSingleVirtualMine(int chargeTypeId, int igniterTypeId, int igniterFunctionId) const
|
|
{
|
|
return static_cast<MineClass::type>(m_mainHandler->dds()->pdmDtc()->mineClass(chargeTypeId, igniterTypeId, igniterFunctionId)) == MineClass::VirtualSingle;
|
|
}
|
|
|
|
bool HandlerMineArea::isVirtualMine(int chargeTypeId, int igniterTypeId, int igniterFunctionId) const
|
|
{
|
|
return static_cast<MineClass::type>(m_mainHandler->dds()->pdmDtc()->mineClass(chargeTypeId, igniterTypeId, igniterFunctionId)) == MineClass::Virtual;
|
|
}
|
|
|
|
bool HandlerMineArea::init()
|
|
{
|
|
QVector<Database::AesMineArea> areaVec;
|
|
// read all MineAreas from database
|
|
if (!m_mainHandler->db()->select(areaVec))
|
|
{
|
|
ERROR_LOG(m_logger) << "Error reading data from database!";
|
|
return false;
|
|
}
|
|
|
|
// create area mine objects
|
|
for (const Database::AesMineArea &area : qAsConst(areaVec))
|
|
{
|
|
|
|
if (area.layingProcedureTypeId == AesMaLayingProcedureType::LptArtillery && !area.isCentral
|
|
&& (area.effectStateId == AesEffectState::EsPrepared || area.effectStateId == AesEffectState::EsActivated))
|
|
++m_totalPzAbwWMis;
|
|
|
|
// Create and init Object
|
|
ObjectMineArea *ifs(new ObjectMineArea(m_mainHandler, this));
|
|
connect(ifs, &ObjectMineArea::effectStateChanged, this, &HandlerMineArea::onEffectStateChanged);
|
|
Core::FunctionReplyObject ret = ifs->createObject(area);
|
|
if (ret.error())
|
|
{
|
|
delete ifs;
|
|
ERROR_LOG(m_logger) << ret();
|
|
return false;
|
|
}
|
|
|
|
// Check concrete Mines on lastest value
|
|
if (isConcreteMine(area.chargeTypeId, area.igniterTypeId, area.igniterFunctionId) || isDusMineArea(area.chargeTypeId, area.igniterTypeId, area.igniterFunctionId))
|
|
{
|
|
if (ifs->lastMineNo() > s_startPzAbwWMiCCount)
|
|
s_startPzAbwWMiCCount = ifs->lastMineNo();
|
|
}
|
|
// If active or prepared, check if it still can be handled and increment area count
|
|
|
|
if (!ifs->data().isCentral)
|
|
{
|
|
if (totalAreas() >= s_maxActiveAreas[AesType::AtMineArea])
|
|
{
|
|
ERROR_LOG(m_logger) << "More active mine areas in database than allowed - ignoring the rest!";
|
|
ifs->removeObject();
|
|
delete ifs;
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (totalAreasCentral() >= s_maxActiveAreasCentral[AesType::AtMineArea])
|
|
{
|
|
ERROR_LOG(m_logger) << "More active mine areas in database than allowed - ignoring the rest!";
|
|
ifs->removeObject();
|
|
delete ifs;
|
|
continue;
|
|
}
|
|
}
|
|
if (ifs->isObjectInTrainingArea())
|
|
{
|
|
if (ifs->data().isCentral)
|
|
++m_areaCountCentral;
|
|
else
|
|
++m_areaCount;
|
|
}
|
|
|
|
// Push into Map
|
|
m_objectMap.insert(ifs->id(), ifs);
|
|
connect(ifs, &ObjectMineArea::newAiv, this, &HandlerMineArea::newAiv);
|
|
connect(ifs, &ObjectMineArea::removeAiv, this, &HandlerMineArea::removeAiv);
|
|
connect(ifs, &ObjectMineArea::releaseMines, this, &HandlerMineArea::redistributeMines);
|
|
connect(ifs, &ObjectMineArea::shapeChanged, this, &HandlerMineArea::assignMinesFromNullArea);
|
|
|
|
// self trigger EffectStateChangedSlot or DUS-Mines from recently Expired MineAreas arent't released
|
|
ifs->onEffectStateChanged();
|
|
}
|
|
if (m_nullArea->lastConcreteMineNo() > s_startPzAbwWMiCCount)
|
|
s_startPzAbwWMiCCount = m_nullArea->lastConcreteMineNo();
|
|
|
|
DEBUG_LOG(m_logger) << "s_startPzAbwWMiCCount: " << s_startPzAbwWMiCCount;
|
|
|
|
connect(m_mainHandler->dds()->tabDtc().get(), &TrainingAreaBase::Interface::Dtc::mineTriggeredChanged, this, &HandlerMineArea::onMineTriggered);
|
|
m_mainHandler->dds()->tabDtc()->enableMineTriggered();
|
|
|
|
connect(m_mainHandler->dds()->tabDtc().get(), &TrainingAreaBase::Interface::Dtc::minelayerTrailerPositionChanged, this, &HandlerMineArea::onMinelayerPositionChanged);
|
|
m_mainHandler->dds()->tabDtc()->enableMinelayerTrailerPosition();
|
|
|
|
connect(m_mainHandler->mineCorridorHandler().get(), &HandlerBase::newAiv, this, &HandlerMineArea::onNewMineCorridor);
|
|
|
|
DEBUG_LOG(m_logger) << "m_exeObjMap.size() = " << m_objectMap.size();
|
|
|
|
return true;
|
|
}
|
|
|
|
void HandlerMineArea::redistributeMines(int aesId, QList<Database::AesMineAreaTriggeredMines> mines)
|
|
{
|
|
if (!m_objectMap.contains(aesId))
|
|
return;
|
|
|
|
DEBUG_LOG(m_logger) << "Putting mines from " << aesId << " into other MineAreas if applicable or in NullArea.";
|
|
|
|
// check if any other MineArea will handle some of the mines
|
|
for (const auto &mineArea : qAsConst(m_objectMap))
|
|
{
|
|
if (mineArea->id() != aesId)
|
|
{
|
|
QMutableListIterator<Database::AesMineAreaTriggeredMines> it(mines);
|
|
while (it.hasNext())
|
|
{
|
|
auto mine = it.next();
|
|
if (mineArea->canHandleMine(mine.mineId, mine.chargeTypeId, mine.position))
|
|
{
|
|
DEBUG_LOG(m_logger) << "Assigning mine " << mine.mineId << " to mine Area " << mineArea->id();
|
|
mineArea->updateMine(mine);
|
|
it.remove();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
DEBUG_LOG(m_logger) << mines.size() << " unhandled mines will be assigned to NullArea";
|
|
// anything not handled is added to NullArea
|
|
if (!mines.isEmpty())
|
|
m_nullArea->triggerMines(mines);
|
|
}
|
|
|
|
bool HandlerMineArea::removeDuplicateMine(int mineId)
|
|
{
|
|
for (const auto &mineArea : qAsConst(m_objectMap))
|
|
{
|
|
if (mineArea->isDusMineArea() && mineArea->hasMine(mineId))
|
|
{
|
|
mineArea->takeMine(mineId);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
int HandlerMineArea::totalAreas() const { return s_areaCount[AesType::AtMineArea]; }
|
|
|
|
int HandlerMineArea::totalAreasCentral() const { return s_areaCountCentral[AesType::AtMineArea]; }
|
|
|
|
template <typename T> T getValueHelper(T in) { return in; }
|
|
|
|
template <typename T> T getValueHelper(const dds::core::optional<T> &in) { return in.is_set() ? in.get() : T(); }
|
|
|
|
template <typename T> static void fillData(const T &src, Database::AesMineArea &dst)
|
|
{
|
|
if (src.id() < 0) // is the id given as negative? set id -> used by OC-Laptop
|
|
dst.id = src.id();
|
|
|
|
dst.name = QString::fromStdString(src.name());
|
|
dst.effectStart = src.effectStart().is_set() && src.effectStart().get() > 0 ? QDateTime::fromMSecsSinceEpoch(src.effectStart().get()) : QDateTime();
|
|
dst.effectDuration = src.effectDuration();
|
|
dst.effectSourceId = src.effectSourceId();
|
|
dst.partyId = src.partyId().is_set() ? src.partyId().get() : 0;
|
|
dst.chargeTypeId = src.chargeStruct().chargeTypeId();
|
|
dst.participantId = src.participantId().is_set() ? src.participantId().get() : 0;
|
|
dst.density = src.density();
|
|
dst.width = src.width();
|
|
dst.layingProcedureTypeId = src.layingProcedureType();
|
|
dst.isLaidHidden = src.isLaidHidden();
|
|
dst.effectMarkingInTa = src.effectMarkingInTa();
|
|
dst.isCenterLine = src.isCenterLine();
|
|
dst.externalId = getValueHelper(src.externalId());
|
|
}
|
|
|
|
static inline bool intersects(const QPolygonF &p1, const std::vector<Core::GeoPosition> &ddsp2)
|
|
{
|
|
QPolygonF p2(ddsp2.size());
|
|
int i = 0;
|
|
for (const auto &point : ddsp2)
|
|
p2[i++] = QPointF(point.lon(), point.lat());
|
|
|
|
QPainterPath pp1;
|
|
pp1.addPolygon(p1);
|
|
QPainterPath pp2;
|
|
pp2.addPolygon(p2);
|
|
return pp1.intersects(pp2);
|
|
}
|
|
|
|
void HandlerMineArea::onMineAreaModifyRequest(const rti::core::SampleIdentity &cookie, const MineAreaModifyRequest &request)
|
|
{
|
|
DEBUG_LOG(m_logger) << "onMineAreaModifyRequest: " << request << "totalAreas=" << totalAreas()
|
|
<< " s_maxActiveAreas[AesType::AtMineArea]=" << s_maxActiveAreas[AesType::AtMineArea];
|
|
|
|
const Core::FunctionReplyObject ret = mineAreaModifyRequest(request);
|
|
if (ret.error())
|
|
WARNING_LOG(m_logger) << ret();
|
|
m_mainHandler->dds()->fts()->mineAreaModifyReply(cookie, ret);
|
|
}
|
|
|
|
template <typename T> Core::FunctionReplyObject HandlerMineArea::mineAreaCreateRequest(const T &request)
|
|
{
|
|
// if ( !isDusMineArea(request.chargeTypeId())
|
|
// && (totalAreas() >= s_maxActiveAreas[AesType::AtMineArea] && request.effectStart().is_set()))
|
|
// return Core::FunctionReplyObject(1, tr_lts("dds", "Too many peripheral mine areas."));
|
|
|
|
Database::AesMineArea newData;
|
|
fillData(request, newData);
|
|
|
|
// Check in advance if mines in null area are in the new mine area
|
|
if (isDusMineArea(newData.chargeTypeId, newData.igniterTypeId, newData.igniterFunctionId)
|
|
|| isConcreteMine(newData.chargeTypeId, newData.igniterTypeId, newData.igniterFunctionId))
|
|
{
|
|
if (!checkIfNullMineIsInArea(request.segments(), newData, request.distance()))
|
|
{
|
|
QString chargeTypeName = QString::fromStdString(m_mainHandler->dds()->pdmDtc()->chargeType(newData.chargeTypeId).name());
|
|
return Core::FunctionReplyObject(1, tr_lts("dds", "No mines of type '%1' found in chosen area")).arg(chargeTypeName);
|
|
}
|
|
}
|
|
// check: effectStart > time(NULL) ?
|
|
|
|
ObjectMineArea *ifs(new ObjectMineArea(m_mainHandler, this));
|
|
connect(ifs, &ObjectMineArea::effectStateChanged, this, &HandlerMineArea::onEffectStateChanged);
|
|
|
|
Core::FunctionReplyObject ret = ifs->createObject(newData, request.segments());
|
|
|
|
DEBUG_LOG(m_logger) << ">>> mineAreaCreateRequest: re.segSize: " << request.segments().size() << " // ifs.segSize: " << ifs->segments().size()
|
|
<< " // mineCount: " << ifs->mineCount();
|
|
if (ret.error())
|
|
{
|
|
delete ifs;
|
|
return ret;
|
|
}
|
|
|
|
auto poly = Polygons::mineArea(ifs->segments(), newData.width, newData.density, newData.isCenterLine); // FIXME:Is segements filled here
|
|
|
|
// Check if mine field is in building only
|
|
bool isGroundLevel = true;
|
|
if (m_mainHandler->dds()->ismDtc()->getSurroundingBuildingByPolygon(m_mainHandler->dds()->exerciseId(), poly, isGroundLevel) > 0)
|
|
{
|
|
ifs->removeObject(); // Not finally deleted from db after this,Fallback if DB deletion is not working correct
|
|
ifs->removeObjectFromDb();
|
|
delete ifs;
|
|
return Core::FunctionReplyObject(1, tr_lts("dds", "The mine field is within a building"));
|
|
}
|
|
|
|
std::vector<Core::GeoPosition> _form;
|
|
ObjectBase::ddsVecFromPoly(poly, _form);
|
|
bool isCentral = ifs->checkIsCentral(_form);
|
|
if (isCentral)
|
|
{
|
|
if (totalAreasCentral() >= s_maxActiveAreasCentral[AesType::AtMineArea] && request.effectStart().is_set())
|
|
{
|
|
ifs->removeObject(); // Not finally deleted from db after this,Fallback if DB deletion is not working correct
|
|
ifs->removeObjectFromDb();
|
|
delete ifs;
|
|
return Core::FunctionReplyObject(1, tr_lts("dds", "Too many central mine areas."));
|
|
}
|
|
else if (ifs->mineCount() > s_maxCentralSingleMinesCount)
|
|
{
|
|
ifs->removeObject(); // Not finally deleted from db after this,Fallback if DB deletion is not working correct
|
|
ifs->removeObjectFromDb();
|
|
delete ifs;
|
|
return Core::FunctionReplyObject(1, tr_lts("dds", "Too many central single mines."));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (ifs->mineCount() > s_maxSingleMinesCount) // > 1200
|
|
{
|
|
ifs->removeObject(); // Not finally deleted from db after this,Fallback if DB deletion is not working correct
|
|
ifs->removeObjectFromDb();
|
|
delete ifs;
|
|
return Core::FunctionReplyObject(1, tr_lts("dds", "Too many single mines."));
|
|
}
|
|
int pzAbwWMiSafe = s_safePzAbwWMiCount - m_totalPzAbwWMis;
|
|
|
|
if (newData.layingProcedureTypeId == AesMaLayingProcedureType::LptArtillery /*PzAbwWmiV */)
|
|
{
|
|
if (request.effectStart().is_set())
|
|
--pzAbwWMiSafe;
|
|
}
|
|
|
|
if (pzAbwWMiSafe < 0)
|
|
pzAbwWMiSafe = 0;
|
|
|
|
if (totalAreas() >= s_maxActiveAreas[AesType::AtMineArea] - pzAbwWMiSafe && request.effectStart().is_set())
|
|
{
|
|
ifs->removeObject(); // Not finally deleted from db after this,Fallback if DB deletion is not working correct
|
|
ifs->removeObjectFromDb();
|
|
delete ifs;
|
|
return Core::FunctionReplyObject(1, tr_lts("dds", "Too many peripheral mine areas."));
|
|
}
|
|
|
|
if (newData.layingProcedureTypeId == AesMaLayingProcedureType::LptArtillery /*PzAbwWmiV */)
|
|
{
|
|
if (request.effectStart().is_set())
|
|
++m_totalPzAbwWMis;
|
|
}
|
|
}
|
|
|
|
connect(ifs, &ObjectMineArea::newAiv, this, &HandlerMineArea::newAiv);
|
|
connect(ifs, &ObjectMineArea::removeAiv, this, &HandlerMineArea::removeAiv);
|
|
connect(ifs, &ObjectMineArea::releaseMines, this, &HandlerMineArea::redistributeMines);
|
|
connect(ifs, &ObjectMineArea::shapeChanged, this, &HandlerMineArea::assignMinesFromNullArea);
|
|
|
|
ifs->clearBuildings();
|
|
|
|
m_objectMap.insert(ifs->id(), ifs);
|
|
|
|
if (isCentral)
|
|
{
|
|
++m_areaCountCentral;
|
|
DEBUG_LOG(m_logger) << "s_areaCountCentral[AesType::AtMineArea] = " << m_areaCountCentral;
|
|
}
|
|
else if (ifs->isObjectInTrainingArea())
|
|
{
|
|
++m_areaCount;
|
|
DEBUG_LOG(m_logger) << "s_areaCount[AesType::AtMineArea] = " << m_areaCount;
|
|
}
|
|
|
|
if (ifs->isDusMineArea() || ifs->isConcreteMine())
|
|
{
|
|
assignMinesFromNullArea(ifs->id());
|
|
DEBUG_LOG(m_logger) << "Start change to Line: " << request.setMineSorted();
|
|
ret = ifs->changeSegmentsToLine(request.setMineSorted());
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
template <typename T> Core::FunctionReplyObject HandlerMineArea::mineAreaModifyRequest(const T &request)
|
|
{
|
|
Core::FunctionReplyObject ret;
|
|
ObjectMineArea *ifs = nullptr;
|
|
if (getValueHelper(request.externalId()) > 0)
|
|
ifs = getObjectFromMapByExternalId(m_objectMap, getValueHelper(request.externalId()), ret);
|
|
|
|
if (!ifs)
|
|
{
|
|
if (request.id() == 0 || ((request.id() < 0) && !getObjectFromMap(m_objectMap, std::abs(request.id()), ret)))
|
|
return mineAreaCreateRequest(request);
|
|
|
|
ifs = getObjectFromMap(m_objectMap, std::abs(request.id()), ret);
|
|
|
|
if (!ifs)
|
|
return ret;
|
|
}
|
|
|
|
if (request.effectStart().is_set() && (request.effectStart().get() + request.effectDuration() < m_mainHandler->dds()->currentPartitionTime().toMSecsSinceEpoch()))
|
|
return removeObject(ifs);
|
|
|
|
Database::AesMineArea newData(ifs->data());
|
|
fillData(request, newData);
|
|
|
|
QVector<Database::AesMineAreaSegment> vecSegments;
|
|
double totalLength = 0.0;
|
|
|
|
ifs->createSegments(request.segments(), request.id(), vecSegments, totalLength);
|
|
auto poly = Polygons::mineArea(vecSegments, newData.width, newData.density, newData.isCenterLine); // FIXME:Is segements filled here
|
|
|
|
// Check if mine field is in building only
|
|
bool isGroundLevel = true;
|
|
if (m_mainHandler->dds()->ismDtc()->getSurroundingBuildingByPolygon(m_mainHandler->dds()->exerciseId(), poly, isGroundLevel) > 0)
|
|
return Core::FunctionReplyObject(1, tr_lts("dds", "The mine field is within a building"));
|
|
|
|
std::vector<Core::GeoPosition> _form;
|
|
ObjectBase::ddsVecFromPoly(poly, _form);
|
|
bool isCentral = ifs->checkIsCentral(_form);
|
|
|
|
/*!
|
|
* If the effect start added after creation, the max amount need to be checked
|
|
*/
|
|
if (!ifs->isActivationTimeSet() && request.effectStart().is_set())
|
|
{
|
|
if (isCentral)
|
|
{
|
|
|
|
if (totalAreasCentral() >= s_maxActiveAreasCentral[AesType::AtMineArea] /*&& request.effectStart().is_set()*/)
|
|
return Core::FunctionReplyObject(1, tr_lts("dds", "Too many central mine areas."));
|
|
|
|
ret = ifs->checkDensity(newData.density, totalLength, s_maxCentralSingleMinesCount);
|
|
if (ret.error())
|
|
return ret;
|
|
}
|
|
else
|
|
{
|
|
if (ifs->mineCount() >= s_maxSingleMinesCount) // > 1200
|
|
return Core::FunctionReplyObject(1, tr_lts("dds", "Too many single mines."));
|
|
|
|
ret = ifs->checkDensity(newData.density, totalLength, s_maxSingleMinesCount);
|
|
if (ret.error())
|
|
return ret;
|
|
|
|
int pzAbwWMiSafe = s_safePzAbwWMiCount - m_totalPzAbwWMis;
|
|
|
|
if (newData.layingProcedureTypeId == AesMaLayingProcedureType::LptArtillery /*PzAbwWmiV */)
|
|
{
|
|
--pzAbwWMiSafe;
|
|
}
|
|
|
|
if (pzAbwWMiSafe < 0)
|
|
pzAbwWMiSafe = 0;
|
|
|
|
if (totalAreas() >= s_maxActiveAreas[AesType::AtMineArea] - pzAbwWMiSafe /*&& request.effectStart().is_set()*/)
|
|
return Core::FunctionReplyObject(1, tr_lts("dds", "Too many peripheral mine areas."));
|
|
|
|
if (newData.layingProcedureTypeId == AesMaLayingProcedureType::LptArtillery /*PzAbwWmiV */)
|
|
{
|
|
++m_totalPzAbwWMis;
|
|
}
|
|
}
|
|
}
|
|
|
|
// For counting, only Elements being at least prepared are important:
|
|
if (request.effectStart().is_set() && ifs->isObjectModifiable())
|
|
{
|
|
// Calculate new polygon here. Not nice, though
|
|
|
|
bool wasCentral = ifs->data().isCentral;
|
|
|
|
// only change if element changed from central to training area or vice versa
|
|
if (isCentral != wasCentral)
|
|
{
|
|
// Change from central to training area
|
|
if (wasCentral)
|
|
{
|
|
|
|
int pzAbwWMiSafe = s_safePzAbwWMiCount - m_totalPzAbwWMis;
|
|
|
|
if (newData.layingProcedureTypeId == AesMaLayingProcedureType::LptArtillery /*PzAbwWmiV */)
|
|
{
|
|
if (request.effectStart().is_set())
|
|
--pzAbwWMiSafe;
|
|
}
|
|
|
|
if (pzAbwWMiSafe < 0)
|
|
pzAbwWMiSafe = 0;
|
|
|
|
if (totalAreas() >= s_maxActiveAreas[AesType::AtMineArea] - pzAbwWMiSafe) // Minus PzAbwWmiV
|
|
return Core::FunctionReplyObject(request.id(), tr_lts("dds", "Too many peripheral mine areas."));
|
|
|
|
if (newData.layingProcedureTypeId == AesMaLayingProcedureType::LptArtillery /*&& newData.chargeTypeId == 216*/ /*PzAbwWmiV */)
|
|
m_totalPzAbwWMis++;
|
|
m_areaCount++;
|
|
m_areaCountCentral--;
|
|
DEBUG_LOG(m_logger) << "s_areaCount[AesType::AtMineArea] = " << m_areaCount;
|
|
DEBUG_LOG(m_logger) << "s_areaCountCentral[AesType::AtMineArea] = " << m_areaCountCentral;
|
|
}
|
|
else // Change from training area to central
|
|
{
|
|
|
|
if (totalAreasCentral() >= s_maxActiveAreasCentral[AesType::AtMineArea])
|
|
return Core::FunctionReplyObject(request.id(), tr_lts("dds", "Too many central mine areas."));
|
|
m_areaCount--;
|
|
m_areaCountCentral++;
|
|
|
|
if (newData.layingProcedureTypeId == AesMaLayingProcedureType::LptArtillery)
|
|
--m_totalPzAbwWMis;
|
|
|
|
DEBUG_LOG(m_logger) << "s_areaCount[AesType::AtMineArea] = " << m_areaCount;
|
|
DEBUG_LOG(m_logger) << "s_areaCountCentral[AesType::AtMineArea] = " << m_areaCountCentral;
|
|
}
|
|
}
|
|
|
|
if (request.layingProcedureType() == AesMaLayingProcedureType::LptPioneer && ifs->get().layingProcedureTypeId == AesMaLayingProcedureType::LptArtillery && !isCentral)
|
|
{
|
|
|
|
--m_totalPzAbwWMis;
|
|
DEBUG_LOG(m_logger) << "Change from Artillery to Pioneer Total Art: " << m_totalPzAbwWMis << " Total All: " << totalAreas();
|
|
|
|
int pzAbwWMiSafe = s_safePzAbwWMiCount - m_totalPzAbwWMis;
|
|
|
|
if (pzAbwWMiSafe < 0)
|
|
pzAbwWMiSafe = 0;
|
|
|
|
if (totalAreas() > s_maxActiveAreas[AesType::AtMineArea] - pzAbwWMiSafe) // Minus PzAbwWmiV
|
|
{
|
|
++m_totalPzAbwWMis;
|
|
return Core::FunctionReplyObject(request.id(), tr_lts("dds", "Too many peripheral mine areas."));
|
|
}
|
|
}
|
|
else if (request.layingProcedureType() == AesMaLayingProcedureType::LptArtillery && ifs->get().layingProcedureTypeId == AesMaLayingProcedureType::LptPioneer
|
|
&& !isCentral)
|
|
{
|
|
|
|
++m_totalPzAbwWMis;
|
|
DEBUG_LOG(m_logger) << "Change from Pioneer to Artillery Total Art: " << m_totalPzAbwWMis << " Total All: " << totalAreas();
|
|
}
|
|
}
|
|
|
|
if (request.id() < 0 && checkStateForSfm(ifs))
|
|
{
|
|
DEBUG_LOG(m_logger) << "Overwrite mine area Effect State for OC";
|
|
newData.effectStateId = AesEffectState::EsPrepared;
|
|
}
|
|
|
|
// check: effectStart > time(NULL) ?
|
|
int32_t oldChargeTypeId = ifs->data().chargeTypeId;
|
|
|
|
ret = ifs->updateObject(newData, request.segments());
|
|
|
|
// assign mines from NullArea if applicable
|
|
if (oldChargeTypeId != newData.chargeTypeId)
|
|
if (ifs->isDusMineArea() || ifs->isConcreteMine())
|
|
{
|
|
assignMinesFromNullArea(ifs->id());
|
|
DEBUG_LOG(m_logger) << "Start change to Line(modify): " << request.setMineSorted();
|
|
|
|
ifs->changeSegmentsToLine(request.setMineSorted());
|
|
}
|
|
|
|
ifs->clearBuildings();
|
|
|
|
return ret;
|
|
}
|
|
|
|
void HandlerMineArea::onMineAreaRemoveRequest(const rti::core::SampleIdentity &cookie, const Core::RemoveElementRequest &request)
|
|
{
|
|
Core::FunctionReplyObject ret;
|
|
const qint32 id = request.id() < 0 ? (request.id() * -1) : request.id();
|
|
ObjectMineArea *ifs = getObjectFromMap(m_objectMap, id, ret);
|
|
|
|
if (ifs == nullptr)
|
|
{
|
|
m_mainHandler->dds()->fts()->mineAreaRemoveReply(cookie, ret);
|
|
return;
|
|
}
|
|
|
|
if (ifs->data().layingProcedureTypeId == AesMaLayingProcedureType::LptArtillery && ifs->isActivationTimeSet())
|
|
m_totalPzAbwWMis--;
|
|
|
|
m_mainHandler->dds()->fts()->mineAreaRemoveReply(cookie, removeReply(&DatabaseInterface::removeAesMineArea, request));
|
|
}
|
|
|
|
void HandlerMineArea::onMineResetRequest(const rti::core::SampleIdentity &cookie, const MineResetRequest &request)
|
|
{
|
|
DEBUG_LOG(m_logger) << "mineResetRequest: " << request;
|
|
auto ret = mineResetRequest(request);
|
|
if (ret.error())
|
|
WARNING_LOG(m_logger) << ret();
|
|
m_mainHandler->dds()->fts()->mineResetReply(cookie, ret);
|
|
}
|
|
|
|
Core::FunctionReplyObject HandlerMineArea::mineResetRequest(const MineResetRequest &request)
|
|
{
|
|
// If they are DUS Mines that are not part of a mine area [yet]
|
|
// request does not contain position, so it cannot be assigned to an area
|
|
if (request.mineAreaId() == 0)
|
|
{
|
|
// If single mine...
|
|
if (request.mineId().is_set())
|
|
{
|
|
DEBUG_LOG(m_logger) << "Checking in DUS-Mine-Areas";
|
|
bool found = false;
|
|
auto it = m_objectMap.cbegin();
|
|
while (it != m_objectMap.cend() && !found)
|
|
{
|
|
found = (*it)->resetMine(request.mineId().get());
|
|
++it;
|
|
}
|
|
if (!found)
|
|
{
|
|
DEBUG_LOG(m_logger) << "Not found in DUS Mine Areas, resetting in NullArea!";
|
|
m_nullArea->resetMine(request.mineId().get());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DEBUG_LOG(m_logger) << "Resetting all unassociated DUS mines (NullArea) and all DUS mine areas";
|
|
// Do this first!
|
|
m_nullArea->resetMines();
|
|
for (auto mineAreaObj : qAsConst(m_objectMap))
|
|
{
|
|
if (!mineAreaObj->isDusMineArea() && !mineAreaObj->isConcreteMine())
|
|
continue;
|
|
mineAreaObj->resetMines();
|
|
}
|
|
}
|
|
return Core::FunctionReplyObject(request.mineAreaId());
|
|
}
|
|
|
|
// Both Virtual and DUS Mine Area
|
|
ObjectMineArea *ifs = m_objectMap.value(request.mineAreaId());
|
|
if (!ifs)
|
|
return Core::FunctionReplyObject(request.mineAreaId(), tr_lts("dds", "Mine area with id %1 not found.")).arg(request.mineAreaId());
|
|
|
|
bool bOk;
|
|
if (request.mineId().is_set())
|
|
bOk = ifs->resetMine(request.mineId().get());
|
|
else
|
|
bOk = ifs->resetMines();
|
|
|
|
if (!bOk)
|
|
return Core::FunctionReplyObject(request.mineAreaId(), tr_lts("dds", "Reset Virtual Mine(s) failed."));
|
|
|
|
return Core::FunctionReplyObject(request.mineAreaId());
|
|
}
|
|
|
|
void HandlerMineArea::onMineTriggered(const TrainingAreaBase::MineTriggered &data, DataModification modType)
|
|
{
|
|
if (modType != DataModification::eAdded && modType != DataModification::eModified)
|
|
return;
|
|
|
|
MineTriggeredRequest mtr;
|
|
mtr.mineAreaId(data.mineAreaId());
|
|
// from tab - mine area mine index starts at 1 ...
|
|
mtr.mineId(data.mineAreaId() == 0 ? data.mineIndex() : data.mineIndex() - 1);
|
|
if (data.position().is_set())
|
|
mtr.position(data.position().get());
|
|
if (data.chargeTypeId().is_set())
|
|
mtr.chargeTypeId(data.chargeTypeId().get());
|
|
|
|
auto ret = mineTriggeredRequest(mtr);
|
|
if (ret.error())
|
|
WARNING_LOG(m_logger) << ret();
|
|
}
|
|
|
|
void HandlerMineArea::onMineTriggeredRequest(const rti::core::SampleIdentity &cookie, const MineTriggeredRequest &request)
|
|
{
|
|
auto ret = mineTriggeredRequest(request);
|
|
if (ret.error())
|
|
WARNING_LOG(m_logger) << ret();
|
|
m_mainHandler->dds()->fts()->mineTriggeredReply(cookie, ret);
|
|
}
|
|
|
|
Core::FunctionReplyObject HandlerMineArea::mineTriggeredRequest(const MineTriggeredRequest &request)
|
|
{
|
|
DEBUG_LOG(m_logger) << "mineTriggeredRequest: " << request;
|
|
// NOTE: igniterType/IgniterFunciton = 0 as long as MineTriggeredRequest does not contain values
|
|
if (request.mineAreaId() == 0 || (request.chargeTypeId().is_set() && isConcreteMine(request.chargeTypeId().get(), 0, 0)))
|
|
{
|
|
int chargeTypeId = request.chargeTypeId().is_set() ? request.chargeTypeId().get() : 0;
|
|
|
|
// DUS Mines:
|
|
// NOTE: igniterType/IgniterFunciton = 0 as long as MineTriggeredRequest does not contain values
|
|
QPointF position;
|
|
if (request.position().is_set() && !isFromMineLayer(chargeTypeId, 0, 0))
|
|
{
|
|
position.setX(request.position().get().lon());
|
|
position.setY(request.position().get().lat());
|
|
}
|
|
|
|
Database::AesMineAreaTriggeredMines mine;
|
|
bool mineFound = false;
|
|
|
|
// check if mine is already in a mine area and is still handled there
|
|
auto it = m_objectMap.cbegin();
|
|
while (it != m_objectMap.cend() && !mineFound)
|
|
{
|
|
int mineId = request.mineId();
|
|
ObjectMineArea *mineArea = it.value();
|
|
DEBUG_LOG(m_logger) << "mineId: " << mineId << ", areaId:" << mineArea->id();
|
|
if (request.mineAreaId() > 0 && request.mineAreaId() != mineArea->id())
|
|
{
|
|
it++;
|
|
continue;
|
|
}
|
|
|
|
DEBUG_LOG(m_logger) << "request.mineAreaId: " << request.mineAreaId();
|
|
if (mineArea->isConcreteMine())
|
|
{
|
|
DEBUG_LOG(m_logger) << "isConcrete = true";
|
|
mineId = mineArea->getMineIdByIndex(request.mineId());
|
|
}
|
|
|
|
if ((mineArea->isDusMineArea() || mineArea->isConcreteMine()) && mineArea->hasMine(mineId)) // is mine in a DUS minearea
|
|
{
|
|
mineFound = true;
|
|
DEBUG_LOG(m_logger) << "Mine found in Area " << mineArea->id();
|
|
if (mineArea->canHandleMine(mineId, chargeTypeId, position)) // is the mine area still handling the mine with the new position
|
|
{
|
|
DEBUG_LOG(m_logger) << "triggerMine: mineId: " << mineId;
|
|
mineArea->triggerMine(mineId, true, position);
|
|
return Core::FunctionReplyObject(request.mineAreaId());
|
|
}
|
|
mine = mineArea->takeMine(mineId); // take the mine, as it is not handled anymore
|
|
}
|
|
++it;
|
|
}
|
|
|
|
// search for a handling area (doesn't matter if new or existing mine at this point)
|
|
int handlingAreaId = 0;
|
|
it = m_objectMap.cbegin();
|
|
while (it != m_objectMap.cend() && handlingAreaId == 0)
|
|
{
|
|
const ObjectMineArea *mineArea = it.value();
|
|
if ((mineArea->isDusMineArea() || mineArea->isConcreteMine()) && mineArea->canHandleMine(request.mineId(), chargeTypeId, position))
|
|
handlingAreaId = mineArea->id();
|
|
++it;
|
|
}
|
|
|
|
// if mine was not already in a mine area and there is an area that wants the mine, check if it can be taken from the null area
|
|
if (!mineFound && handlingAreaId != 0)
|
|
mine = m_nullArea->takeMine(request.mineId());
|
|
|
|
if (mine.id != 0) // mine did exist already
|
|
{
|
|
if (request.position().is_set()) // update position
|
|
mine.position = position;
|
|
}
|
|
|
|
if (handlingAreaId != 0)
|
|
{
|
|
ObjectMineArea *ifs = m_objectMap.value(handlingAreaId);
|
|
|
|
// if mine already exists -> move mine to handling mine area else just handle new mine
|
|
if (mine.id != 0)
|
|
{
|
|
mine.isTriggered = true;
|
|
ifs->updateMine(mine);
|
|
}
|
|
else
|
|
{
|
|
if (!triggerUnpairedMine(request))
|
|
ifs->triggerMine(request.mineId(), true, position);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// if mine already exists -> move mine to null area else just handle new mine
|
|
if (mine.id != 0)
|
|
m_nullArea->triggerMine(mine);
|
|
else
|
|
{
|
|
if (!triggerUnpairedMine(request))
|
|
m_nullArea->triggerMine(request.mineId(), true, chargeTypeId, position);
|
|
}
|
|
}
|
|
|
|
return Core::FunctionReplyObject(request.mineAreaId());
|
|
}
|
|
|
|
// Virtual:
|
|
ObjectMineArea *ifs = m_objectMap.value(request.mineAreaId());
|
|
if (!ifs)
|
|
return Core::FunctionReplyObject(request.mineAreaId(), tr_lts("dds", "Mine area with id %1 not found.")).arg(request.mineAreaId());
|
|
|
|
ifs->triggerMine(request.mineId());
|
|
return Core::FunctionReplyObject(request.mineAreaId());
|
|
}
|
|
|
|
void HandlerMineArea::onMineAreaModifyFromCtaDataRequest(const rti::core::SampleIdentity &cookie, const MineArea &request)
|
|
{
|
|
DEBUG_LOG(m_logger) << "onMineAreaModifyRequest: " << request;
|
|
const Core::FunctionReplyObject ret = mineAreaModifyRequest(request);
|
|
if (ret.error())
|
|
WARNING_LOG(m_logger) << ret();
|
|
m_mainHandler->dds()->fts()->mineAreaModifyFromCtaDataReply(cookie, ret);
|
|
}
|
|
|
|
void HandlerMineArea::onNewMineCorridor(const AesItemView &aiv)
|
|
{
|
|
if (aiv.effectStateId() != AesEffectState::EsActivated)
|
|
return;
|
|
|
|
for (ObjectMineArea *ma : qAsConst(m_objectMap))
|
|
{
|
|
if (intersects(ma->boundingRect(), aiv.form()))
|
|
ma->clearCorridor(aiv);
|
|
}
|
|
}
|
|
|
|
/*!
|
|
* \brief HandlerMineArea::mineAreaReferenceCreateRequest
|
|
* \warning this method is use for central mine only
|
|
* \param refRequest
|
|
* \return
|
|
*/
|
|
Core::FunctionReplyObject HandlerMineArea::mineAreaReferenceCreateRequest(const MineAreaReferenceModifyRequest &refRequest)
|
|
{
|
|
Core::FunctionReplyObject ret;
|
|
if (refRequest.mineData().empty() || refRequest.referenceAesItemId() <= 0)
|
|
return Core::FunctionReplyObject(1, tr_lts("dds", "Invalid MineAreaReference data"));
|
|
|
|
DEBUG_LOG(m_logger) << "--[mineAreaReferenceCreateRequest] referenceAesItemId: " << refRequest.referenceAesItemId()
|
|
<< " mindeData size: " << refRequest.mineData().size();
|
|
|
|
Database::AesMineArea newData;
|
|
if (!fillFromMineAreaReferenceRequest(refRequest, newData))
|
|
return Core::FunctionReplyObject(1, tr_lts("dds", "Invalid Referenced mine data"));
|
|
|
|
// add referencedAesItemId into the properties
|
|
QJsonObject propObj = QJsonDocument::fromJson(newData.properties.toUtf8()).object();
|
|
propObj.insert(QStringLiteral("referencedAesItemId"), refRequest.referenceAesItemId());
|
|
newData.properties = QString::fromStdString(QJsonDocument(propObj).toJson().toStdString());
|
|
|
|
ObjectMineArea *ifs(new ObjectMineArea(m_mainHandler, this));
|
|
std::vector<Core::GeoPosition2D> vecGeoSegment;
|
|
double newWidth = newData.width; // always central
|
|
ret = ifs->createGeoSegmentsFromMineData(newWidth, refRequest.mineData(), vecGeoSegment); // segments will be filled through mineData
|
|
if (ret.error())
|
|
{
|
|
delete ifs;
|
|
return ret;
|
|
}
|
|
|
|
newData.width = newWidth;
|
|
connect(ifs, &ObjectMineArea::effectStateChanged, this, &HandlerMineArea::onEffectStateChanged);
|
|
ret = ifs->createObjectFromMineData(newData, vecGeoSegment, refRequest.mineData());
|
|
|
|
if (ret.error())
|
|
{
|
|
ERROR_LOG(m_logger) << "--[mineAreaReferenceCreateRequest] Couldn't create mine area !!!!";
|
|
delete ifs;
|
|
return ret;
|
|
}
|
|
|
|
if (ifs->mineCount() > s_maxCentralSingleMinesCount)
|
|
{
|
|
ifs->removeObject(); // Not finally deleted from db after this,Fallback if DB deletion is not working correct
|
|
ifs->removeObjectFromDb();
|
|
delete ifs;
|
|
return Core::FunctionReplyObject(1, tr_lts("dds", "Too many central single mines."));
|
|
}
|
|
|
|
connect(ifs, &ObjectMineArea::newAiv, this, &HandlerMineArea::newAiv);
|
|
connect(ifs, &ObjectMineArea::removeAiv, this, &HandlerMineArea::removeAiv);
|
|
|
|
ifs->clearBuildings();
|
|
m_objectMap.insert(ifs->id(), ifs);
|
|
++m_areaCountCentral; // is always central
|
|
if (ifs->isObjectInTrainingArea())
|
|
++m_areaCount;
|
|
|
|
DEBUG_LOG(m_logger) << "--[mineAreaReferenceCreateRequest]- -----> Mine Area created from MineData with refAesItemId: " << refRequest.referenceAesItemId()
|
|
<< " ifs->id: " << ifs->id();
|
|
return ret;
|
|
}
|
|
|
|
/*!
|
|
* \brief HandlerMineArea::mineAreaReferenceModifyRequest
|
|
* \warning this method is use for central mine only
|
|
* \param refRequest
|
|
* \return
|
|
*/
|
|
Core::FunctionReplyObject HandlerMineArea::mineAreaReferenceModifyRequest(const MineAreaReferenceModifyRequest &refRequest)
|
|
{
|
|
DEBUG_LOG(m_logger) << "--[mineAreaReferenceModifyRequest]- Modify/Create Mine with refAesItemId: ";
|
|
Core::FunctionReplyObject ret;
|
|
ObjectMineArea *ifs = getObjecMapByreferenceAesItemId(refRequest.referenceAesItemId());
|
|
if (ifs == nullptr)
|
|
{
|
|
DEBUG_LOG(m_logger) << "--[mineAreaReferenceModifyRequest]- #### no Ref mine create one... refAesItemId: "<<refRequest.referenceAesItemId();
|
|
return mineAreaReferenceCreateRequest(refRequest);
|
|
}
|
|
|
|
Database::AesMineArea newData(ifs->data());
|
|
if (!fillFromMineAreaReferenceRequest(refRequest, newData))
|
|
return Core::FunctionReplyObject(1, tr_lts("dds", "Invalid MineAreaReference data"));
|
|
|
|
// create Geo Pos segments
|
|
// reconstruct GeoPosSegment from (new)MineData + (existing)TriggerMineData
|
|
std::vector<Core::GeoPosition2D> vecGeoSegment;
|
|
DEBUG_LOG(m_logger) << "--[mineAreaReferenceModifyRequest] create vector GeoPos from Mine data segments.. ";
|
|
double newWidth = newData.width;
|
|
ret = ifs->createGeoSegmentsFromMineData(newWidth, refRequest.mineData(), vecGeoSegment);
|
|
if (ret.error())
|
|
return ret;
|
|
|
|
newData.width = newWidth;
|
|
double totalLength = 0.0;
|
|
|
|
QVector<Database::AesMineAreaSegment> vecDbSegments;
|
|
DEBUG_LOG(m_logger) << "--[mineAreaReferenceModifyRequest] create vector DB MineArea segment from generated vec GeoPos.. ";
|
|
ret = ifs->createSegments(vecGeoSegment, ifs->id(), vecDbSegments, totalLength);
|
|
if (ret.error() || vecDbSegments.empty())
|
|
return ret;
|
|
|
|
// run update
|
|
ret = ifs->updateObjectFromMineData(newData, vecGeoSegment, refRequest.mineData());
|
|
ifs->clearBuildings();
|
|
DEBUG_LOG(m_logger) << "--[mineAreaReferenceModifyRequest] Mine Area Updated with MineData. AesItemId" << refRequest.referenceAesItemId()
|
|
<< " // data.id: " << ifs->id();
|
|
|
|
return ret;
|
|
}
|
|
|
|
void HandlerMineArea::onMineAreaReferenceModifyRequest(const rti::core::SampleIdentity &cookie, const MineAreaReferenceModifyRequest &request)
|
|
{
|
|
DEBUG_LOG(m_logger) << " onMineAreaReferenceModifyRequest: ADD MINE DATA with refAesItemId: " << request.referenceAesItemId();
|
|
|
|
const Core::FunctionReplyObject ret = mineAreaReferenceModifyRequest(request);
|
|
if (ret.error())
|
|
WARNING_LOG(m_logger) << ret();
|
|
m_mainHandler->dds()->fts()->mineAreaReferenceModifyReply(cookie, ret);
|
|
}
|
|
|
|
/*!
|
|
* \brief HandlerMineArea::fillFromMineAreaReferenceRequest
|
|
* segments will not be filled from hier because they will be build (minedata + triggerMine)
|
|
* \param inReq
|
|
* \param outReq
|
|
*/
|
|
bool HandlerMineArea::fillFromMineAreaReferenceRequest(const MineAreaReferenceModifyRequest &inReq, Database::AesMineArea &dbData)
|
|
{
|
|
if (inReq.mineData().empty())
|
|
return false;
|
|
|
|
const auto &mineData = std::min_element(inReq.mineData().begin(),
|
|
inReq.mineData().end(),
|
|
[](const MineData &first, const MineData &second) { return first.armingTime() < second.armingTime(); });
|
|
|
|
// get effect duration from chargeType properties
|
|
const auto chargeType = m_mainHandler->dds()->pdmDtc()->chargeType(inReq.chargeTypeId());
|
|
const QJsonObject chargeTypePropObj = QJsonDocument::fromJson(chargeType.properties().c_str()).object();
|
|
|
|
const qint64 effectStart = mineData->armingTime();
|
|
const int effectDurationMsec = inReq.effectDurationMsec();
|
|
auto effectCluster = m_mainHandler->effectClusterHandler()->getEffectClusterObj(inReq.referenceAesItemId()); // get partyId from effect cluster object
|
|
if (!effectCluster)
|
|
{
|
|
ERROR_LOG(m_logger) << " -- fillFromMineAreaReferenceRequest Unknown effect cluster id: " << inReq.referenceAesItemId();
|
|
return false;
|
|
}
|
|
|
|
double width = 250.0; // default
|
|
double density = 1.0; // default
|
|
bool effectMarkingTa = false; // default
|
|
bool isLaidHidden = false; // default
|
|
bool isCenterLine = true; // default
|
|
AreaEffectSimulation::AesMaLayingProcedureType layingProcedure = AreaEffectSimulation::AesMaLayingProcedureType_def::LptPioneer;
|
|
|
|
// get effectDuration from effectorData
|
|
int id = 0;
|
|
QString name = QStringLiteral("%1 %2");
|
|
ObjectMineArea *ifs = getObjecMapByreferenceAesItemId(inReq.referenceAesItemId());
|
|
if (ifs) // purpose is to get existing segments
|
|
{
|
|
id = ifs->id();
|
|
width = ifs->data().width;
|
|
density = ifs->data().density;
|
|
layingProcedure = ifs->data().layingProcedureTypeId;
|
|
effectMarkingTa = ifs->data().effectMarkingInTa;
|
|
isLaidHidden = ifs->data().isLaidHidden;
|
|
isCenterLine = ifs->data().isCenterLine;
|
|
name = ifs->data().name;
|
|
}
|
|
else
|
|
{
|
|
const auto chargeEffectChargeType = m_mainHandler->dds()->pdmDtc()->chargeType(effectCluster->data().chargeTypeId);
|
|
name = name.arg(QString::fromStdString(chargeEffectChargeType.shortName())).arg(effectCluster->name());
|
|
}
|
|
|
|
DEBUG_LOG(m_logger) << " Fill Mine from MineData effectCluster: id: " << effectCluster->data().id << " // effectClusterParty: " << effectCluster->data().partyId;
|
|
dbData.id = id;
|
|
dbData.name = name;
|
|
dbData.effectStart = QDateTime::fromMSecsSinceEpoch(effectStart);
|
|
dbData.effectDuration = effectDurationMsec;
|
|
dbData.effectSourceId = effectCluster->data().effectSourceId;
|
|
dbData.partyId = effectCluster->data().partyId;
|
|
dbData.chargeTypeId = chargeType.id();
|
|
dbData.participantId = LtsUtils::toOptional(0);
|
|
dbData.density = density;
|
|
dbData.width = width;
|
|
dbData.layingProcedureTypeId = layingProcedure;
|
|
dbData.isLaidHidden = isLaidHidden;
|
|
dbData.effectMarkingInTa = effectMarkingTa;
|
|
dbData.isCenterLine = isCenterLine;
|
|
dbData.externalId = LtsUtils::toOptional(0LL);
|
|
dbData.isCentral = true;
|
|
|
|
return true;
|
|
}
|
|
|
|
ObjectMineArea *HandlerMineArea::getObjecMapByreferenceAesItemId(int referenceAesItemId)
|
|
{
|
|
if (referenceAesItemId <= 0)
|
|
return nullptr;
|
|
|
|
std::function<int(std::string)> referenceIdFromProps = [](const std::string &props) -> int
|
|
{
|
|
if (props.empty())
|
|
return -1;
|
|
const QJsonObject &propObj = QJsonDocument::fromJson(props.c_str()).object();
|
|
return propObj.value(QStringLiteral("referencedAesItemId")).toInt(-1);
|
|
};
|
|
|
|
for (const auto &obj : m_objectMap)
|
|
{
|
|
if (referenceIdFromProps(obj->data().properties.toStdString()) == referenceAesItemId && obj->data().effectStateId != AreaEffectSimulation::AesEffectState::EsExpired
|
|
&& obj->data().effectStateId != AreaEffectSimulation::AesEffectState::EsRemoved && obj->data().effectStateId != AreaEffectSimulation::AesEffectState::EsError)
|
|
{
|
|
DEBUG_LOG(m_logger) << ">>>> found objectId: " << obj->data().id;
|
|
return obj;
|
|
}
|
|
}
|
|
return nullptr; // object with referenceAesItemId not found
|
|
}
|
|
|
|
void HandlerMineArea::assignMinesFromNullArea(int aesId)
|
|
{
|
|
|
|
ERROR_LOG(m_logger) << "Assign Mine State " << aesId;
|
|
auto mineArea = m_objectMap.value(aesId);
|
|
|
|
if (!mineArea->isDusMineArea() && !mineArea->isConcreteMine())
|
|
return;
|
|
|
|
// check if there are already mines to assign from NullArea
|
|
const QList<Database::AesMineAreaTriggeredMines> mines = m_nullArea->mines();
|
|
for (const auto &mine : mines)
|
|
{
|
|
if (mineArea->canHandleMine(mine.mineId, mine.chargeTypeId, mine.position))
|
|
{
|
|
auto nullMine = m_nullArea->takeMine(mine.mineId);
|
|
mineArea->updateMine(nullMine);
|
|
}
|
|
}
|
|
}
|
|
|
|
void HandlerMineArea::onMinelayerPositionChanged(const TrainingAreaBase::MinelayerTrailerPosition &data, DataModification modType)
|
|
{
|
|
if (data.sampleTime() + 5000 < QDateTime::currentMSecsSinceEpoch())
|
|
{
|
|
DEBUG_LOG(m_logger) << "ignore old layer data";
|
|
return;
|
|
}
|
|
if (modType == DataModification::eRemoved)
|
|
return;
|
|
|
|
DEBUG_LOG(m_logger) << "lat: " << data.position().lat() << ", lon: " << data.position().lon();
|
|
auto utm = LtsCoordTrans::UtmCoordinate::fromGeographic(data.position().lon(), data.position().lat());
|
|
QPointF position(utm.x, utm.y);
|
|
QPointF positionGeo(data.position().lon(), data.position().lat());
|
|
m_zoneMap.insert(data.equipmentNumber(), utm.zone);
|
|
|
|
DEBUG_LOG(m_logger) << "data." << data.equipmentNumber() << ", position: " << utm.mgrs();
|
|
|
|
if (m_timerMap.contains(data.equipmentNumber()))
|
|
{
|
|
QTimer *timer = m_timerMap.value(data.equipmentNumber());
|
|
if (timer->isActive())
|
|
{
|
|
// Save Positions as QPolygon -> Vector not Map
|
|
QPolygonF pointsUtm = m_dusMinePosMapUtm.value(data.equipmentNumber());
|
|
pointsUtm.append(position);
|
|
m_dusMinePosMapUtm.insert(data.equipmentNumber(), pointsUtm);
|
|
|
|
// Save Positions as QPolygon -> Vector not Map
|
|
QPolygonF pointsGeo = m_dusMinePosMapGeo.value(data.equipmentNumber());
|
|
pointsGeo.append(positionGeo);
|
|
m_dusMinePosMapGeo.insert(data.equipmentNumber(), pointsGeo);
|
|
// m_dusMinePosMapUtm.insert(data.equipmentNumber(), position);
|
|
// m_dusMinePosMapGeo.insert(data.equipmentNumber(), positionGeo);
|
|
timer->start();
|
|
DEBUG_LOG(m_logger) << "Timer restart for equipNo: " << data.equipmentNumber();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DEBUG_LOG(m_logger) << "Start Timer for equipNo: " << data.equipmentNumber();
|
|
QTimer *timer = new QTimer(this);
|
|
timer->setInterval(s_mineAreaCreationInterval);
|
|
int equipNo = data.equipmentNumber();
|
|
int chargeTypeId = data.chargeTypeId();
|
|
connect(timer,
|
|
&QTimer::timeout,
|
|
this,
|
|
[equipNo, chargeTypeId, this]()
|
|
{
|
|
ERROR_LOG(m_logger) << "Timeout for equipNo: " << equipNo;
|
|
onTimeoutEquipNo(equipNo, chargeTypeId);
|
|
});
|
|
QPolygonF pointUtm;
|
|
pointUtm.append(position);
|
|
m_dusMinePosMapUtm.insert(data.equipmentNumber(), pointUtm);
|
|
|
|
QPolygonF pointGeo;
|
|
pointGeo.append(positionGeo);
|
|
m_dusMinePosMapGeo.insert(data.equipmentNumber(), pointGeo);
|
|
|
|
// m_dusMinePosMapUtm.insert(data.equipmentNumber(), position);
|
|
// m_dusMinePosMapGeo.insert(data.equipmentNumber(), positionGeo);
|
|
timer->start();
|
|
m_timerMap.insert(equipNo, timer);
|
|
}
|
|
|
|
int dusSerialNo = data.dusSerialNo();
|
|
// DusMines with serialNo 0 should get a new serialNo ( > 70000), too
|
|
// NOTE: igniterType/IgniterFunciton = 0 as long as MinelayerTrailerPosition does not contain values
|
|
if (isConcreteMine(data.chargeTypeId(), 0, 0) || (isDusMineArea(data.chargeTypeId(), 0, 0) && dusSerialNo == 0))
|
|
dusSerialNo = ++s_startPzAbwWMiCCount;
|
|
else
|
|
{
|
|
if (data.dusSerialNo() != 0 && removeDuplicateMine(data.dusSerialNo()))
|
|
INFO_LOG(m_logger) << "Existing mine with serialNo: " << data.dusSerialNo() << " removed";
|
|
}
|
|
|
|
DEBUG_LOG(m_logger) << "dusSerialNo: " << dusSerialNo;
|
|
DEBUG_LOG(m_logger) << "isConcrete: " << isConcreteMine(data.chargeTypeId(), 0, 0);
|
|
|
|
m_nullArea->triggerMine(dusSerialNo, false, data.chargeTypeId(), {data.position().lon(), data.position().lat()});
|
|
}
|
|
|
|
void HandlerMineArea::onTimeoutEquipNo(int equipNo, int chargeTypeId)
|
|
{
|
|
QTimer *timer = m_timerMap.value(equipNo);
|
|
timer->stop();
|
|
delete timer;
|
|
m_timerMap.remove(equipNo);
|
|
|
|
// NOTE: igniterType/IgniterFunciton = 0 as long as MinelayerTrailerPosition does not contain values
|
|
if (!isDusMineArea(chargeTypeId, 0, 0) && !isConcreteMine(chargeTypeId, 0, 0))
|
|
return;
|
|
|
|
DEBUG_LOG(m_logger) << "Timer for equipNo " << equipNo << " stopped";
|
|
QPolygonF points = m_dusMinePosMapGeo.value(equipNo);
|
|
m_dusMinePosMapGeo.remove(equipNo);
|
|
m_dusMinePosMapUtm.remove(equipNo);
|
|
|
|
int mineCount = points.size();
|
|
TRACE_LOG(m_logger) << "mineCount: " << mineCount;
|
|
|
|
// QPolygonF boundingBox = msGetBoundingBoxPolygon(points, &width);
|
|
|
|
MineAreaModifyRequest req;
|
|
req.chargeStruct().chargeTypeId(chargeTypeId);
|
|
req.density(0.7);
|
|
req.distance(0.5);
|
|
DEBUG_LOG(m_logger) << "density1: " << req.density();
|
|
req.effectDuration(0);
|
|
req.effectStart(QDateTime::currentMSecsSinceEpoch() + Settings::getMineAreaByMiVSysEffectStart());
|
|
req.isCenterLine(true);
|
|
req.isLaidHidden(false);
|
|
req.layingProcedureType(AesMaLayingProcedureType_def::LptPioneer);
|
|
QString name = QString::number(equipNo);
|
|
req.name(name.toStdString());
|
|
int participantID = m_mainHandler->dds()->ppmDtc()->participantIdByEquipmentNumber(equipNo);
|
|
req.partyId(m_mainHandler->dds()->ppmDtc()->participant(participantID).partyId());
|
|
req.width(0);
|
|
|
|
std::vector<Core::GeoPosition2D> vec;
|
|
vec.reserve(points.size());
|
|
for (QPointF bbPoint : qAsConst(points))
|
|
{
|
|
Core::GeoPosition2D pos;
|
|
pos.lon(bbPoint.x());
|
|
pos.lat(bbPoint.y());
|
|
|
|
vec.push_back(pos);
|
|
}
|
|
// vec.reserve(boundingBox.size());
|
|
// for( QPointF bbPoint : qAsConst(boundingBox))
|
|
// {
|
|
// Core::GeoPosition2D pos;
|
|
// LtsCoordTrans::UtmCoordinate utm;
|
|
// utm.x = bbPoint.x();
|
|
// utm.y = bbPoint.y();
|
|
// utm.zone = m_zoneMap.value(equipNo);
|
|
// QPointF point = utm.geographic();
|
|
// DEBUG_LOG(m_logger) << "position: " << utm.mgrs();
|
|
// pos.lon(point.x());
|
|
// pos.lat(point.y());
|
|
// vec.push_back(pos);
|
|
// }
|
|
req.segments(vec);
|
|
|
|
// Cannot create a minefield with only one segment => create two new segments with 10m distance
|
|
if (req.segments().size() < 2)
|
|
{
|
|
DEBUG_LOG(m_logger) << "only one segment - create 2 new with distance 10m";
|
|
const LtsCoordTrans::UtmCoordinate pointUtm = LtsCoordTrans::UtmCoordinate::fromGeographic(vec[0].lon(), vec[0].lat());
|
|
LtsCoordTrans::UtmCoordinate point1Utm = pointUtm;
|
|
LtsCoordTrans::UtmCoordinate point2Utm = pointUtm;
|
|
point1Utm.y = pointUtm.y - 5.0;
|
|
point2Utm.y = pointUtm.y + 5.0;
|
|
|
|
vec.clear();
|
|
vec.reserve(2);
|
|
QPointF point = point1Utm.geographic();
|
|
Core::GeoPosition2D pos(point.x(), point.y());
|
|
vec.push_back(pos);
|
|
point = point2Utm.geographic();
|
|
pos.lon(point.x());
|
|
pos.lat(point.y());
|
|
vec.push_back(pos);
|
|
req.segments(vec);
|
|
req.distance(10.0);
|
|
}
|
|
|
|
Core::FunctionReplyObject reply = mineAreaCreateRequest(req);
|
|
if (reply.error())
|
|
ERROR_LOG(m_logger) << "Could not create mineArea from dus mines: " << reply();
|
|
else
|
|
DEBUG_LOG(m_logger) << "MineArea created with " << mineCount << " mines";
|
|
}
|
|
|
|
bool HandlerMineArea::checkIfNullMineIsInArea(const std::vector<Core::GeoPosition2D> &segments, const Database::AesMineArea &data, double distance)
|
|
{
|
|
QVector<Database::AesMineAreaSegment> vecSeg;
|
|
vecSeg.reserve(segments.size());
|
|
if (segments.size() == 0)
|
|
return false;
|
|
|
|
for (unsigned int i = 0; i < segments.size() - 1; i++)
|
|
{
|
|
Database::AesMineAreaSegment dataSeg;
|
|
dataSeg.startPosition = QPointF(segments[i].lon(), segments[i].lat());
|
|
dataSeg.endPosition = QPointF(segments[i + 1].lon(), segments[i + 1].lat());
|
|
vecSeg.append(dataSeg);
|
|
}
|
|
|
|
return checkIfNullMineIsInArea(vecSeg, data, distance);
|
|
}
|
|
bool HandlerMineArea::checkIfNullMineIsInArea(const std::vector<AreaEffectSimulation::MineSegment> &segments, const Database::AesMineArea &data, double distance)
|
|
{
|
|
QVector<Database::AesMineAreaSegment> vecSeg;
|
|
vecSeg.reserve(segments.size());
|
|
|
|
for (const AreaEffectSimulation::MineSegment &seg : qAsConst(segments))
|
|
{
|
|
Database::AesMineAreaSegment dbSeg;
|
|
dbSeg.startPosition = QPointF(seg.positionStart().lon(), seg.positionStart().lat());
|
|
dbSeg.endPosition = QPointF(seg.positionEnd().lon(), seg.positionEnd().lat());
|
|
vecSeg.append(dbSeg);
|
|
}
|
|
|
|
return checkIfNullMineIsInArea(vecSeg, data, distance);
|
|
}
|
|
|
|
bool HandlerMineArea::checkIfNullMineIsInArea(const QVector<Database::AesMineAreaSegment> &segments, const Database::AesMineArea &data, double distance)
|
|
{
|
|
QPolygonF poly = Polygons::mineArea(segments, data.width, data.density, data.isCenterLine);
|
|
|
|
const QList<Database::AesMineAreaTriggeredMines> mines = m_nullArea->mines();
|
|
DEBUG_LOG(m_logger) << "Mines in null area: " << mines.size();
|
|
|
|
for (const Database::AesMineAreaTriggeredMines &mine : mines)
|
|
{
|
|
if (containsPointInExpandedMinefield(mine.position, poly, distance))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool HandlerMineArea::containsPointInExpandedMinefield(const QPointF &positionGeo, const QPolygonF &polygon, double distance) const
|
|
{
|
|
QPolygonF mineAreaPolygonUtm;
|
|
mineAreaPolygonUtm.reserve(polygon.size());
|
|
|
|
const LtsCoordTrans::UtmCoordinate pointUtm = LtsCoordTrans::UtmCoordinate::fromGeographic(positionGeo.x(), positionGeo.y());
|
|
DEBUG_LOG(m_logger) << "centerPoint=" << pointUtm.x << "/" << pointUtm.y << " zone=" << pointUtm.zone << "- mgrs: " << pointUtm.mgrs();
|
|
|
|
for (const auto &pos : polygon)
|
|
{
|
|
const LtsCoordTrans::UtmCoordinate &pointMineAreaUtm = LtsCoordTrans::UtmCoordinate::fromGeographic(pos, pointUtm.zone);
|
|
DEBUG_LOG(m_logger) << "pointMineAreaUtm=" << pointMineAreaUtm.x << "/" << pointMineAreaUtm.y << " zone=" << pointMineAreaUtm.zone
|
|
<< " - mgrs: " << pointMineAreaUtm.mgrs();
|
|
|
|
mineAreaPolygonUtm.push_back(QPointF(pointMineAreaUtm.x, pointMineAreaUtm.y));
|
|
}
|
|
|
|
for (const QPointF &mineAreaPointUTM : qAsConst(mineAreaPolygonUtm))
|
|
{
|
|
|
|
double x = pointUtm.x - mineAreaPointUTM.x();
|
|
double y = pointUtm.y - mineAreaPointUTM.y();
|
|
|
|
double distancePointPointValue = sqrt(x * x + y * y);
|
|
DEBUG_LOG(m_logger) << "distancePointPointValue=" << distancePointPointValue << " Point =" << pointUtm.x << "/" << pointUtm.y << " PointPoly=" << mineAreaPointUTM.x()
|
|
<< "/" << mineAreaPointUTM.y();
|
|
if (distancePointPointValue < distance)
|
|
{
|
|
DEBUG_LOG(m_logger) << "HandlerMineArea::containsPoint return true";
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
double HandlerMineArea::msGetDistanceFromLine(float px, float py, float px0, float py0, float px1, float py1)
|
|
{
|
|
double dist;
|
|
|
|
double a11;
|
|
double a12;
|
|
double a21;
|
|
double a22;
|
|
double b1;
|
|
double b2;
|
|
double det;
|
|
double x;
|
|
|
|
a11 = px1 - px0;
|
|
a12 = py1 - py0;
|
|
a21 = py1 - py0;
|
|
a22 = px0 - px1;
|
|
b1 = px - px0;
|
|
b2 = py - py0;
|
|
|
|
det = a11 * a22 - a12 * a21;
|
|
if (fabs(det) < 0.001)
|
|
return 0.0;
|
|
|
|
x = (a11 * b2 - b1 * a21) / det;
|
|
dist = x * sqrt(a21 * a21 + a22 * a22);
|
|
|
|
return dist;
|
|
}
|
|
|
|
QPolygonF HandlerMineArea::msGetBoundingBoxPolygon(const QPolygonF &minen, double *widthBoundingBox)
|
|
{
|
|
QPolygonF bb;
|
|
double dist;
|
|
double distMax;
|
|
double width;
|
|
double width_minus;
|
|
double width_plus;
|
|
double x;
|
|
double y;
|
|
double x0;
|
|
double y0;
|
|
double x1;
|
|
double y1;
|
|
double vx;
|
|
double vy;
|
|
double px0;
|
|
double py0;
|
|
double px1;
|
|
double py1;
|
|
double bbv;
|
|
int idxPolygon0;
|
|
int idxPolygon1;
|
|
|
|
distMax = 0.0;
|
|
idxPolygon0 = 0;
|
|
idxPolygon1 = 1;
|
|
for (int i = 0; i < minen.size(); i++)
|
|
{
|
|
for (int j = i + 1; j < minen.size(); j++)
|
|
{
|
|
x0 = minen.toPolygon().at(i).x();
|
|
y0 = minen.toPolygon().at(i).y();
|
|
x1 = minen.toPolygon().at(j).x();
|
|
y1 = minen.toPolygon().at(j).y();
|
|
dist = sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0));
|
|
if (dist > distMax)
|
|
{
|
|
distMax = dist;
|
|
idxPolygon0 = i;
|
|
idxPolygon1 = j;
|
|
}
|
|
}
|
|
}
|
|
bbv = 5.0;
|
|
if (distMax < 0.001)
|
|
{
|
|
x0 = minen.toPolygon().at(idxPolygon0).x();
|
|
y0 = minen.toPolygon().at(idxPolygon0).y();
|
|
bb.append(QPointF(x0 - 0.71 * bbv, y0 - 0.71 * bbv));
|
|
bb.append(QPointF(x0 + 0.71 * bbv, y0 + 0.71 * bbv));
|
|
*widthBoundingBox = 2 * bbv;
|
|
return bb;
|
|
}
|
|
|
|
vx = (minen.toPolygon().at(idxPolygon1).x() - minen.toPolygon().at(idxPolygon0).x()) / distMax;
|
|
vy = (minen.toPolygon().at(idxPolygon1).y() - minen.toPolygon().at(idxPolygon0).y()) / distMax;
|
|
|
|
width_minus = 0.0;
|
|
width_plus = 0.0;
|
|
for (int i = 0; i < minen.size(); i++)
|
|
{
|
|
if (i != idxPolygon0 && i != idxPolygon1)
|
|
{
|
|
x = minen.toPolygon().at(i).x();
|
|
y = minen.toPolygon().at(i).y();
|
|
x0 = minen.toPolygon().at(idxPolygon0).x();
|
|
y0 = minen.toPolygon().at(idxPolygon0).y();
|
|
x1 = minen.toPolygon().at(idxPolygon1).x();
|
|
y1 = minen.toPolygon().at(idxPolygon1).y();
|
|
width = msGetDistanceFromLine(x, y, x0, y0, x1, y1);
|
|
if (width < width_minus)
|
|
width_minus = width;
|
|
if (width > width_plus)
|
|
width_plus = width;
|
|
}
|
|
}
|
|
|
|
width = (width_plus + width_minus) / 2.0;
|
|
px0 = minen.toPolygon().at(idxPolygon0).x() + vy * width - vx * bbv;
|
|
py0 = minen.toPolygon().at(idxPolygon0).y() - vx * width - vy * bbv;
|
|
bb.append(QPointF(px0, py0));
|
|
px1 = minen.toPolygon().at(idxPolygon1).x() + vy * width + vx * bbv;
|
|
py1 = minen.toPolygon().at(idxPolygon1).y() - vx * width + vy * bbv;
|
|
bb.append(QPointF(px1, py1));
|
|
*widthBoundingBox = width_plus - width_minus + 2 * bbv;
|
|
|
|
return bb;
|
|
}
|
|
|
|
bool HandlerMineArea::triggerUnpairedMine(const MineTriggeredRequest &request)
|
|
{
|
|
if (!request.position().is_set())
|
|
{
|
|
DEBUG_LOG(m_logger) << LOGFUNCTION << " failed, because there is no position.";
|
|
|
|
return false;
|
|
}
|
|
|
|
qint32 halfLookupDistance = Settings::getUnpairedMinesLookupRange() / 2;
|
|
LtsCoordTrans::UtmCoordinate mineUtmPos = LtsCoordTrans::UtmCoordinate::fromGeographic(request.position().get().lon(), request.position().get().lat());
|
|
QPointF lookupTopLeft = mineUtmPos.geographic(-halfLookupDistance, -halfLookupDistance);
|
|
QPointF lookupBottomRight = mineUtmPos.geographic(halfLookupDistance, halfLookupDistance);
|
|
QRectF lookupRect = QRectF(lookupTopLeft, lookupBottomRight);
|
|
Database::AesMineAreaTriggeredMines nearestMine;
|
|
bool hasUnpairedMine = false;
|
|
qreal shortestDistance = std::numeric_limits<qreal>::max();
|
|
QPointF positionPoint;
|
|
|
|
for (auto it = m_objectMap.constBegin(); it != m_objectMap.constEnd(); ++it)
|
|
{
|
|
if (it.value()->isConcreteMine() || !it.value()->boundingRect().intersects(lookupRect))
|
|
continue;
|
|
|
|
const QVector<Database::AesMineAreaTriggeredMines> unpairedMines = it.value()->unpairedMines();
|
|
|
|
for (const Database::AesMineAreaTriggeredMines ¤tMine : unpairedMines)
|
|
{
|
|
positionPoint.setX(request.position().get().lon());
|
|
positionPoint.setY(request.position().get().lat());
|
|
|
|
qreal currentDistance = LtsCoordTrans::distance(positionPoint, currentMine.position);
|
|
|
|
if (currentDistance >= shortestDistance)
|
|
continue;
|
|
|
|
shortestDistance = currentDistance;
|
|
nearestMine = currentMine;
|
|
hasUnpairedMine = true;
|
|
}
|
|
}
|
|
|
|
if (!hasUnpairedMine)
|
|
{
|
|
DEBUG_LOG(m_logger) << LOGFUNCTION << " failed, because there is no unpaired mine in range.";
|
|
|
|
return false;
|
|
}
|
|
|
|
ObjectMineArea *ifs = m_objectMap.value(nearestMine.mineAreaId);
|
|
qint32 oldMineId = nearestMine.mineId;
|
|
|
|
nearestMine.mineId = request.mineId();
|
|
nearestMine.isTriggered = true;
|
|
|
|
ifs->updateMineByOldMineId(nearestMine, oldMineId);
|
|
|
|
DEBUG_LOG(m_logger) << LOGFUNCTION << " was successful.";
|
|
|
|
return true;
|
|
}
|
|
|
|
} // Namespace AreaEffectSimulation
|