363 lines
14 KiB
C++
Executable File
363 lines
14 KiB
C++
Executable File
/**
|
|
* Handler for all exercise objects
|
|
* $Id$
|
|
* $HeadURL$
|
|
* $Author$
|
|
* Created by Hanna E. Rathje, SLSE, 2015-09-03
|
|
*/
|
|
|
|
#include "handler_explosion_area.h"
|
|
#include "handler_charge_administration.h"
|
|
#include <Services/AreaEffectSimulation/Utils/polygons.h>
|
|
#include <QPolygonF>
|
|
|
|
namespace AreaEffectSimulation
|
|
{
|
|
|
|
HandlerExplosionArea::HandlerExplosionArea(MainHandler *mainHandler)
|
|
: HandlerBaseTmpl<ObjectExplosionArea>(mainHandler, QStringLiteral("ExplosionArea"), s_areaCount[AesType::AtExplosionArea], s_areaCountCentral[AesType::AtExplosionArea])
|
|
, Interface::Fts::ExplosionAreaModifyRequestHandler(mainHandler->dds()->fts())
|
|
, Interface::Fts::ExplosionAreaRemoveRequestHandler(mainHandler->dds()->fts())
|
|
, Interface::Fts::ExplosionAreaPauseResumeRequestHandler(m_mainHandler->dds()->fts())
|
|
{
|
|
}
|
|
|
|
bool HandlerExplosionArea::init()
|
|
{
|
|
// create area explosion objects
|
|
bool bRet = true;
|
|
auto cb = [this, &bRet] (const Database::AesExplosionArea &data)
|
|
{
|
|
ObjectExplosionArea *ifs(new ObjectExplosionArea(m_mainHandler, this));
|
|
connect(ifs, &ObjectExplosionArea::effectStateChanged, this, &HandlerExplosionArea::onEffectStateChanged);
|
|
Core::FunctionReplyObject ret = ifs->createObject(data);
|
|
if (ret.error())
|
|
{
|
|
delete ifs;
|
|
ERROR_LOG(m_logger) << ret();
|
|
bRet = false;
|
|
return;
|
|
}
|
|
if (!ifs->data().isCentral)
|
|
{
|
|
if (totalAreas() >= (s_maxActiveAreas[AesType::AtExplosionArea] + s_maxActiveAreas[AesType::AtExplosionSingle]))
|
|
{
|
|
ERROR_LOG(m_logger) << "More active explosion areas in database than allowed - ignoring the rest!";
|
|
ifs->removeObject();
|
|
delete ifs;
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (totalAreasCentral() >= (s_maxActiveAreasCentral[AesType::AtExplosionArea] + s_maxActiveAreasCentral[AesType::AtExplosionSingle]))
|
|
{
|
|
ERROR_LOG(m_logger) << "More active explosion areas in database than allowed - ignoring the rest!";
|
|
ifs->removeObject();
|
|
delete ifs;
|
|
return;
|
|
}
|
|
}
|
|
if (ifs->isObjectInTrainingArea())
|
|
{
|
|
if (ifs->data().isCentral)
|
|
++m_areaCountCentral;
|
|
else
|
|
++m_areaCount;
|
|
}
|
|
m_objectMap.insert(ifs->id(), ifs);
|
|
connect(ifs, &ObjectExplosionArea::newAiv, this, &HandlerExplosionArea::newAiv);
|
|
connect(ifs, &ObjectExplosionArea::removeAiv, this, &HandlerExplosionArea::removeAiv);
|
|
};
|
|
if (!m_mainHandler->db()->select(cb) || !bRet)
|
|
{
|
|
ERROR_LOG(m_logger) << "Error reading data from database!";
|
|
return false;
|
|
}
|
|
|
|
DEBUG_LOG(m_logger) << "m_exeObjMap.size() = " << m_objectMap.size();
|
|
DEBUG_LOG(m_logger) << "m_areaCount = " << m_areaCount;
|
|
DEBUG_LOG(m_logger) << "m_areaCountCentral = " << m_areaCountCentral;
|
|
return true;
|
|
}
|
|
|
|
int HandlerExplosionArea::totalAreas() const
|
|
{
|
|
return s_areaCount[AesType::AtExplosionArea] + s_areaCount[AesType::AtExplosionSingle];
|
|
}
|
|
|
|
int HandlerExplosionArea::totalAreasCentral() const
|
|
{
|
|
return s_areaCountCentral[AesType::AtExplosionArea] + s_areaCountCentral[AesType::AtExplosionSingle];
|
|
}
|
|
|
|
|
|
static void fillData(const ExplosionAreaModifyRequest &src, Database::AesExplosionArea &dst)
|
|
{
|
|
if (src.id() < 0) // is the id given as negative? set id -> used by OC-Laptop
|
|
dst.id = src.id();
|
|
|
|
dst.impactPosition.rx() = src.area().cornerBottomLeft().lon();
|
|
dst.impactPosition.ry() = src.area().cornerBottomLeft().lat();
|
|
dst.rotationAngle = src.area().rotation();
|
|
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.impactLength = src.area().height();
|
|
dst.impactWidth = src.area().width();
|
|
dst.partyId = src.partyId().is_set() ? src.partyId().get() : 0;
|
|
dst.chargeTypeId = src.chargeTypeId();
|
|
dst.participantId = src.participantId().is_set() ? src.participantId().get() : 0;
|
|
dst.cannonCount = src.cannonCount();
|
|
dst.cannonRounds = src.cannonRounds();
|
|
dst.altitude = src.altitude();
|
|
dst.firePurpose = QString::fromStdString(src.purpose());
|
|
dst.fireRequestTime = QDateTime::fromMSecsSinceEpoch(src.fireRequestTime());
|
|
dst.effectMarkingInTa = src.effectMarkingInTa();
|
|
dst.externalId = src.externalId().is_set() ? src.externalId().get() : 0;
|
|
}
|
|
|
|
void HandlerExplosionArea::onExplosionAreaModifyRequest(const rti::core::SampleIdentity &cookie,
|
|
const ExplosionAreaModifyRequest &request)
|
|
{
|
|
DEBUG_LOG(m_logger) << "onExplosionAreaModifyRequest: " << request;
|
|
Core::FunctionReplyObject ret = explosionAreaModifyRequest(request);
|
|
if (ret.error())
|
|
WARNING_LOG(m_logger) << ret();
|
|
m_mainHandler->dds()->fts()->explosionAreaModifyReply(cookie, ret);
|
|
}
|
|
|
|
Core::FunctionReplyObject HandlerExplosionArea::explosionAreaCreateRequest(const ExplosionAreaModifyRequest &request)
|
|
{
|
|
if (!request.partyId().is_set())
|
|
return Core::FunctionReplyObject(tr_lts("dds", "Explosion areas need a party id."));
|
|
|
|
int chargeNeeded = request.cannonCount() * request.cannonRounds();
|
|
if (chargeNeeded <= 0)
|
|
return Core::FunctionReplyObject(tr_lts("dds", "Invalid impact count (cannon round or cannon count <= 0)."));
|
|
|
|
if (request.id() == 0)
|
|
{
|
|
int chargeLeft = m_mainHandler->chargeAdministrationHandler()->availableCharge(request.chargeTypeId(), request.partyId().get());
|
|
if (chargeNeeded > chargeLeft)
|
|
return Core::FunctionReplyObject(tr_lts("dds", "Invalid impact count (%1 charges needed but only %2 charges available for Charge Id %3 and Party Id %4)."))
|
|
.arg(chargeNeeded)
|
|
.arg(chargeLeft)
|
|
.arg(request.chargeTypeId())
|
|
.arg(request.partyId().get());
|
|
}
|
|
|
|
Database::AesExplosionArea newData;
|
|
fillData(request, newData);
|
|
|
|
// check: effectStart > time(NULL) ?
|
|
|
|
ObjectExplosionArea *ifs(new ObjectExplosionArea(m_mainHandler, this));
|
|
connect(ifs, &ObjectExplosionArea::effectStateChanged, this, &HandlerExplosionArea::onEffectStateChanged);
|
|
const Core::FunctionReplyObject ret = ifs->createObject(newData);
|
|
if (ret.error())
|
|
{
|
|
delete ifs;
|
|
return ret;
|
|
}
|
|
|
|
if (ifs->data().isCentral)
|
|
{
|
|
if (totalAreasCentral() >= (s_maxActiveAreasCentral[AesType::AtExplosionArea] + s_maxActiveAreasCentral[AesType::AtExplosionSingle]) && 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 active central explosion areas and explosion singles"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (totalAreas() >= (s_maxActiveAreas[AesType::AtExplosionArea] + s_maxActiveAreas[AesType::AtExplosionSingle]) && 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 active explosion areas and explosion singles"));
|
|
}
|
|
}
|
|
|
|
if (ifs->data().isCentral)
|
|
{
|
|
++m_areaCountCentral;
|
|
DEBUG_LOG(m_logger) << "m_areaCountCentral " << m_areaCountCentral;
|
|
}
|
|
else if (ifs->isObjectInTrainingArea())
|
|
{
|
|
++m_areaCount;
|
|
DEBUG_LOG(m_logger) << "m_areaCount = " << m_areaCount;
|
|
}
|
|
else
|
|
{
|
|
DEBUG_LOG(m_logger) << "Counting of [AesType::AtExplosionArea] not affected";
|
|
}
|
|
|
|
m_objectMap.insert(ifs->id(), ifs);
|
|
|
|
connect(ifs, &ObjectExplosionArea::newAiv, this, &HandlerExplosionArea::newAiv);
|
|
connect(ifs, &ObjectExplosionArea::removeAiv, this, &HandlerExplosionArea::removeAiv);
|
|
return ret;
|
|
}
|
|
|
|
Core::FunctionReplyObject HandlerExplosionArea::explosionAreaModifyRequest(const ExplosionAreaModifyRequest &request)
|
|
{
|
|
Core::FunctionReplyObject ret;
|
|
if (request.id() == 0 || ((request.id() < 0) && !getObjectFromMap(m_objectMap, std::abs(request.id()), ret)))
|
|
return explosionAreaCreateRequest(request);
|
|
|
|
ObjectExplosionArea *ifs = getObjectFromMap(m_objectMap, std::abs(request.id()), ret);
|
|
if (!ifs)
|
|
return ret;
|
|
|
|
// Todo: IsObjectModifiable() ?!?
|
|
|
|
AreaEffectSimulation::Database::AesExplosionArea aea(ifs->data());
|
|
fillData(request, aea);
|
|
|
|
auto poly = Polygons::explosionArea(aea);
|
|
|
|
std::vector<Core::GeoPosition> _form;
|
|
ObjectBase::ddsVecFromPoly(poly, _form);
|
|
bool isCentral = ifs->checkIsCentral(_form);
|
|
bool wasCentral = ifs->data().isCentral;
|
|
|
|
/*!
|
|
* Check if the max amount is reached if the effect start added after creation.
|
|
!*/
|
|
if(!ifs->isActivationTimeSet() && request.effectStart().is_set())
|
|
{
|
|
if (isCentral)
|
|
{
|
|
if (totalAreasCentral() >= (s_maxActiveAreasCentral[AesType::AtExplosionArea] + s_maxActiveAreasCentral[AesType::AtExplosionSingle]))
|
|
{
|
|
return Core::FunctionReplyObject(1, tr_lts("dds", "Too many active central explosion areas and explosion singles"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (totalAreas() >= (s_maxActiveAreas[AesType::AtExplosionArea] + s_maxActiveAreas[AesType::AtExplosionSingle]))
|
|
{
|
|
return Core::FunctionReplyObject(1, tr_lts("dds", "Too many active explosion areas and explosion singles"));
|
|
}
|
|
}
|
|
}
|
|
|
|
// For counting, only Elements being at least prepared are important:
|
|
if (request.effectStart().is_set() && ifs->isObjectModifiable())
|
|
{
|
|
|
|
// Calculate new polygon here. Not nice, though
|
|
|
|
|
|
DEBUG_LOG(m_logger) << "isCentral: " << isCentral;
|
|
DEBUG_LOG(m_logger) << "wasCentral: " << wasCentral;
|
|
|
|
// only change if element changed from central to training area or vice versa
|
|
if (isCentral != wasCentral)
|
|
{
|
|
// Change from central to training area
|
|
if (wasCentral)
|
|
{
|
|
if (totalAreas() >= (s_maxActiveAreas[AesType::AtExplosionArea] + s_maxActiveAreas[AesType::AtExplosionSingle]))
|
|
return Core::FunctionReplyObject(request.id(), tr_lts("dds", "Too many active explosion areas and explosion singles"));
|
|
|
|
m_areaCount++;
|
|
m_areaCountCentral--;
|
|
DEBUG_LOG(m_logger) << "s_areaCount[AesType::AtExplosionArea] = " << m_areaCount;
|
|
DEBUG_LOG(m_logger) << "s_areaCountCentral[AesType::AtExplosionArea] = " << m_areaCountCentral;
|
|
}
|
|
else // Change from training area to central
|
|
{
|
|
if (totalAreasCentral() >= (s_maxActiveAreasCentral[AesType::AtExplosionArea] + s_maxActiveAreasCentral[AesType::AtExplosionSingle]))
|
|
return Core::FunctionReplyObject(request.id(), tr_lts("dds", "Too many active central explosion areas and explosion singles"));
|
|
m_areaCount--;
|
|
m_areaCountCentral++;
|
|
DEBUG_LOG(m_logger) << "s_areaCount[AesType::AtExplosionArea] = " << m_areaCount;
|
|
DEBUG_LOG(m_logger) << "s_areaCountCentral[AesType::AtExplosionArea] = " << m_areaCountCentral;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (request.id() < 0 && checkStateForSfm(ifs))
|
|
{
|
|
DEBUG_LOG(m_logger) << "Overwrite Effect State for OC";
|
|
aea.effectStateId = AesEffectState::EsPrepared;
|
|
}
|
|
|
|
return ifs->updateObject(aea);
|
|
}
|
|
|
|
Core::FunctionReplyObject HandlerExplosionArea::explosionAreaModifyGeometryRequest(const ExplosionAreaModifyRequest &request)
|
|
{
|
|
// WARNING: request.area.cornerBottomLeft() contains center point!
|
|
Core::FunctionReplyObject ret;
|
|
ObjectExplosionArea *ifs = getObjectFromMap(m_objectMap, request.id(), ret);
|
|
if (!ifs)
|
|
return ret;
|
|
|
|
// Anzahl aktiver Areas ist erreicht, der Wirkbeginn ist (soll) gesetzt sein, aber die Area war
|
|
// vorher noch ohne Wirkbeginn
|
|
if (totalAreas() >= (s_maxActiveAreas[AesType::AtExplosionArea] + s_maxActiveAreas[AesType::AtExplosionSingle])
|
|
&& request.effectStart().is_set()
|
|
&& !ifs->isActivationTimeSet() // if time was not set before change and now check count
|
|
&& !ifs->isObjectModifiable())
|
|
return Core::FunctionReplyObject(request.id(), tr_lts("dds", "Too many active explosion areas and explosion singles"));
|
|
|
|
// Todo: IsObjectModifiable() ?!?
|
|
AreaEffectSimulation::Database::AesExplosionArea aea(ifs->data());
|
|
|
|
aea.impactPosition = Polygons::centerPoint2BottomLeft(QPointF(request.area().cornerBottomLeft().lon(),
|
|
request.area().cornerBottomLeft().lat()),
|
|
ifs->data().impactWidth,
|
|
ifs->data().impactLength,
|
|
request.area().rotation());
|
|
aea.rotationAngle = request.area().rotation();
|
|
return ifs->updateObject(aea);
|
|
}
|
|
|
|
Core::FunctionReplyObject HandlerExplosionArea::modifyPartyParticipant(qint32 itemId, qint32 partyId, qint32 participantId)
|
|
{
|
|
ObjectExplosionArea *ifs = m_objectMap.value(itemId);
|
|
if (!ifs)
|
|
return Core::FunctionReplyObject(itemId, tr_lts("dds", "Explosion Area with id %1 not found.")).arg(itemId);
|
|
AreaEffectSimulation::Database::AesExplosionArea aea(ifs->data());
|
|
aea.partyId = partyId;
|
|
aea.participantId= participantId;
|
|
return ifs->updateObject(aea);
|
|
}
|
|
|
|
void HandlerExplosionArea::onExplosionAreaRemoveRequest(const rti::core::SampleIdentity &cookie,
|
|
const Core::RemoveElementRequest &request)
|
|
{
|
|
m_mainHandler->dds()->fts()->explosionAreaRemoveReply(cookie, removeReply(&DatabaseInterface::removeAesExplosionArea, request));
|
|
}
|
|
|
|
void HandlerExplosionArea::onExplosionAreaPauseResumeRequest(const rti::core::SampleIdentity &cookie,
|
|
const ExplosionAreaPauseResumeRequest &request)
|
|
{
|
|
DEBUG_LOG(m_logger) << "onExplosionAreaPauseResumeRequest" << request;
|
|
Core::FunctionReplyObject ret;
|
|
ObjectExplosionArea *ifs = getObjectFromMap(m_objectMap, request.id(), ret);
|
|
if (!ifs)
|
|
{
|
|
m_mainHandler->dds()->fts()->explosionAreaPauseResumeReply(cookie, ret);
|
|
return;
|
|
}
|
|
|
|
ret = ifs->resumePause(request);
|
|
|
|
if (ret.error())
|
|
ERROR_LOG(m_logger) << ret();
|
|
m_mainHandler->dds()->fts()->explosionAreaPauseResumeReply(cookie, ret);
|
|
}
|
|
|
|
|
|
} // Namespace AreaEffectSimulation
|
|
|