/** * Handler for one indirect fire single object * $Id$ * $HeadURL$ * $Author$ */ #include "object_explosion_single.h" #include "special_area_provider.h" #include "handler_charge_administration.h" #include "Utils/polygons.h" #include namespace AreaEffectSimulation { ObjectExplosionSingle::ObjectExplosionSingle(MainHandler *mainHandler, QObject *parent) : ObjectBaseTmpl(mainHandler, QStringLiteral("ExplosionSingle"), parent) {} ObjectExplosionSingle::~ObjectExplosionSingle() { removeTopics(); } Core::FunctionReplyObject ObjectExplosionSingle::updateObject(const Database::AesExplosionSingle &data) { Core::FunctionReplyObject ret = ObjectBaseTmpl::updateObject(data); if (ret.error() || (isOnlyObjectNameModifiable() && (data.id > 0))) // data.id > 0 -> negative values from oc always get a full update return ret; if (data.id != 0 && (data.partyId != m_data.partyId || data.chargeTypeId != m_data.chargeTypeId) ) { ret = m_mainHandler->chargeAdministrationHandler()->claimPlannedCharge(m_data.chargeTypeId, m_data.partyId, -1); if (ret.error()) return ret; ret = m_mainHandler->chargeAdministrationHandler()->claimPlannedCharge(data.chargeTypeId, data.partyId, 1); if (ret.error()) return ret; } // only allow some fields auto tmpData(m_data); tmpData.id = std::abs(data.id); tmpData.name = data.name; tmpData.effectStart = data.effectStart; tmpData.impactPosition = data.impactPosition; tmpData.participantId = data.participantId; tmpData.partyId = data.partyId; tmpData.chargeTypeId = data.chargeTypeId; tmpData.fireRequestTime = data.fireRequestTime; tmpData.altitude = data.altitude; tmpData.effectMarkingInTa = data.effectMarkingInTa; tmpData.firePurpose = data.firePurpose; tmpData.rotationAngle = data.rotationAngle; tmpData.effectStateId = data.effectStateId; // overwrite for oc tmpData.properties = data.properties; if (!m_mainHandler->db()->update(tmpData)) return Core::FunctionReplyObject(data.id, tr_lts("dds", "Error updating single explosion with id %1 in database.")).arg(m_data.id); m_data = std::move(tmpData); m_publishDataTimer->start(); checkEnterNewState(); return Core::FunctionReplyObject(data.id); // data not m_data for the possible negative id in the oc-laptop } double ObjectExplosionSingle::chargeRadius() const { return m_mainHandler->dds()->pdmDtc()->impactRadius(m_data.chargeTypeId, m_data.igniterTypeId, m_data.igniterFunctionId); } Core::FunctionReplyObject ObjectExplosionSingle::createObject(const Database::AesExplosionSingle &data) { Core::FunctionReplyObject ret; // No need to create object, if there is not enough charge left. if (data.id == 0 && data.externalId == 0) // new, not read from db ret = m_mainHandler->chargeAdministrationHandler()->claimPlannedCharge(data.chargeTypeId, data.partyId, 1); if (ret.error()) return ret; ret = ObjectBaseTmpl::createObject(data); if (ret.error()) { if (data.id == 0 && data.externalId == 0) m_mainHandler->chargeAdministrationHandler()->claimPlannedCharge(data.chargeTypeId, data.partyId, -1); } return ret; } void ObjectExplosionSingle::setEffectState(AesEffectState newState) { if (newState == AesEffectState::EsExpired) { Core::FunctionReplyObject ret = m_mainHandler->chargeAdministrationHandler()->consumeCharge(m_data.chargeTypeId, m_data.partyId, 1); DEBUG_LOG(m_logger) << "Explosion Single Charge marked used"; if (ret.error()) ERROR_LOG(m_logger) << "Could not consume Charge! " << ret(); } ObjectBaseTmpl::setEffectState(newState); } Core::FunctionReplyObject ObjectExplosionSingle::removeObject() { Core::FunctionReplyObject ret = ObjectBaseTmpl::removeObject(); if (ret.error()) return ret; // If not yet activated, free the charge again. if (!isActivationTimeReached()) ret = m_mainHandler->chargeAdministrationHandler()->claimPlannedCharge(m_data.chargeTypeId, m_data.partyId, -1); return ret; } bool ObjectExplosionSingle::removeObjectFromDb() { return m_mainHandler->db()->removeAesExplosionSingle(m_data.id); } void ObjectExplosionSingle::onPublishData() { ObjectBaseTmpl::onPublishData(); if (!m_mainHandler->db()->update(m_data)) ERROR_LOG(m_logger) << "Error updating AesIndirectFireSingle-data in database"; ExplosionSingle ddsData(m_data.id, m_data.name.toStdString(), effectState() == AesEffectState::EsRemoved, false, partitionTimeMSec(), {m_data.chargeTypeId,0,0}, m_data.effectDuration, toOptional(toMSec(m_data.effectStart)), m_data.effectStateId, m_data.effectSourceId, toOptional(m_data.partyId), toOptional(m_data.participantId), m_data.effectMarkingInTa, m_data.externalId, m_data.isCentral, m_data.properties.toStdString(), Core::GeoPosition2D(m_data.impactPosition.x(), m_data.impactPosition.y()), toMSec(m_data.fireRequestTime), m_data.altitude, m_data.firePurpose.toStdString()); m_mainHandler->dds()->dts()->publish(ddsData); publishAiv(); } void ObjectExplosionSingle::publishAiv() { const double cr = chargeRadius(); const QPolygonF poly = Polygons::explosionSingle(m_data, cr); const QRectF bounds(poly.boundingRect()); AesItemView aiv(m_aiv); aiv.aesItemId(m_data.id); aiv.chargeStruct().chargeTypeId(m_data.chargeTypeId); ddsVecFromPoly(poly, aiv.form()); aiv.effectStart(toMSec(m_data.effectStart)); aiv.boundingBoxBottomLeft(Core::GeoPosition2D(bounds.bottomLeft().x(), bounds.bottomLeft().y())); aiv.boundingBoxTopRight(Core::GeoPosition2D(bounds.topRight().x(), bounds.topRight().y())); aiv.aesTypeId(AesType::AtExplosionSingle); aiv.effectStateId(effectState()); aiv.id(1000 * m_data.id + AesType::AtExplosionSingle); if (m_data.partyId != 0) aiv.partyId(m_data.partyId); checkIsCentralAndPublish(aiv.form(), m_aiv.form(), m_data.isCentral); if (aiv != m_aiv) { aiv.sampleTime(partitionTimeMSec()); m_aiv = aiv; m_mainHandler->dds()->dts()->publish(aiv); emit newAiv(aiv); } } void ObjectExplosionSingle::removeTopics() { auto dts = m_mainHandler->dds()->dts(); dts->removeExplosionSingleByKey(m_data.id); dts->removeAesItemViewByKey(1000 * m_data.id + AesType::AtExplosionSingle); emit removeAiv(m_data.id); } QPolygonF ObjectExplosionSingle::generateForm() { const double cr = chargeRadius(); return Polygons::explosionSingle(m_data, cr); } } // Namespace AreaEffectSimulation