/** * Handler for one indirect fire single object * $Id$ * $HeadURL$ * $Author$ */ #include "object_explosion_single_central.h" #include "special_area_provider.h" #include "handler_explosion_single_central.h" #include "Utils/polygons.h" #include #include #include using Utm = LtsCoordTrans::UtmCoordinate; namespace AreaEffectSimulation { ObjectExplosionSingleCentral::ObjectExplosionSingleCentral(MainHandler *mainHandler, QObject *parent) : ObjectBaseTmpl(mainHandler, QStringLiteral("ExplosionSingleCentral"), parent) {} ObjectExplosionSingleCentral::~ObjectExplosionSingleCentral() { removeTopics(); } Core::FunctionReplyObject ObjectExplosionSingleCentral::updateObject(const Database::AesExplosionSingleCentral &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; // 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 if (!m_mainHandler->db()->update(tmpData)) return Core::FunctionReplyObject(data.id, tr_lts("dds", "Error updating single explosion central 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 ObjectExplosionSingleCentral::chargeRadius() const { return m_mainHandler->dds()->pdmDtc()->impactRadius(m_data.chargeTypeId); } void ObjectExplosionSingleCentral::onPublishData() { ObjectBaseTmpl::onPublishData(); if (!m_mainHandler->db()->update(m_data)) ERROR_LOG(m_logger) << "Error updating AesIndirectFireSingleCentral-data in database"; ExplosionSingleCentral ddsData(m_data.id, m_data.name.toStdString(), effectState() == AesEffectState::EsRemoved, false, partitionTimeMSec(), m_data.chargeTypeId, m_data.effectDuration, toOptional(toMSec(m_data.effectStart)), m_data.effectStateId, toOptional(m_data.partyId), toOptional(m_data.participantId), m_data.effectMarkingInTa, m_data.externalId, m_data.isCentral, Core::GeoPosition2D(m_data.impactPosition.x(), m_data.impactPosition.y()), toMSec(m_data.fireRequestTime), m_data.altitude, m_data.firePurpose.toStdString(), // m_data.participantId, m_data.angle, m_data.fuseTypeId); m_mainHandler->dds()->dts()->publish(ddsData); const Trajectory trajectory = Polygons::explosionSingleCentralTrajectory( m_data, positionOf(m_data.participantId), m_mainHandler->explosionSingleCentralHandler().get()->elevationMap() ); ddsVecFromPoly(trajectory.first, trajectory.second, m_trajectory); const DetonationLocationRequest request = detonationLocationRequest(trajectory); m_mainHandler->dds()->cesFtc()->detonationLocationRequest(request, this); } QPointF ObjectExplosionSingleCentral::positionOf(int participantId) { Q_UNUSED(participantId); LtsCoordTrans::UtmCoordinate iPosition = LtsCoordTrans::UtmCoordinate::fromGeographic(m_data.impactPosition); return iPosition.geographic(QPointF(-500, -2000)); } void ObjectExplosionSingleCentral::publishTrajectoryAiv() { QPolygonF poly; poly << QPointF(m_trajectory.front().lon(), m_trajectory.front().lat()); poly << QPointF(m_trajectory.back().lon(), m_trajectory.back().lat()); const QRectF boundsTrajectory(poly.boundingRect()); AesItemView aivTrajectory(m_aivTrajectory); aivTrajectory.aesItemId(m_data.id); aivTrajectory.chargeTypeId(m_data.chargeTypeId); aivTrajectory.form(m_trajectory); aivTrajectory.effectStart(toMSec(m_data.effectStart)); aivTrajectory.boundingBoxBottomLeft(Core::GeoPosition2D(boundsTrajectory.bottomLeft().x(), boundsTrajectory.bottomLeft().y())); aivTrajectory.boundingBoxTopRight(Core::GeoPosition2D(boundsTrajectory.topRight().x(), boundsTrajectory.topRight().y())); aivTrajectory.aesTypeId(AesType::AtExplosionSingleCentralTrajectory); aivTrajectory.effectStateId(effectState()); aivTrajectory.id(1000 * m_data.id + AesType::AtExplosionSingleCentralTrajectory); if (m_data.partyId != 0) aivTrajectory.partyId(m_data.partyId); checkIsCentralAndPublish(aivTrajectory.form(), m_aivTrajectory.form(), m_data.isCentral); if (aivTrajectory != m_aivTrajectory) { aivTrajectory.sampleTime(partitionTimeMSec()); m_aivTrajectory = aivTrajectory; m_mainHandler->dds()->dts()->publish(aivTrajectory); emit newAiv(aivTrajectory); } } void ObjectExplosionSingleCentral::publishDetonationAiv() { const Core::GeoPosition &geoPos = m_detonationLocation; Trajectory poly3DDetonation; poly3DDetonation.first << QPointF(geoPos.lon(), geoPos.lat()); poly3DDetonation.first << QPointF(geoPos.lon(), geoPos.lat()); poly3DDetonation.second << geoPos.z(); poly3DDetonation.second << geoPos.z() + chargeRadius(); const QRectF boundsDetonation(poly3DDetonation.first.boundingRect()); AesItemView aivDetonation(m_aivDetonation); aivDetonation.aesItemId(m_data.id); aivDetonation.chargeTypeId(m_data.chargeTypeId); ddsVecFromPoly(poly3DDetonation.first, poly3DDetonation.second, aivDetonation.form()); aivDetonation.effectStart(toMSec(m_data.effectStart)); aivDetonation.boundingBoxBottomLeft(Core::GeoPosition2D(boundsDetonation.bottomLeft().x(), boundsDetonation.bottomLeft().y())); aivDetonation.boundingBoxTopRight(Core::GeoPosition2D(boundsDetonation.topRight().x(), boundsDetonation.topRight().y())); aivDetonation.aesTypeId(AesType::AtExplosionSingleCentral); aivDetonation.effectStateId(effectState()); aivDetonation.id(1000 * m_data.id + AesType::AtExplosionSingleCentral); if (m_data.partyId != 0) aivDetonation.partyId(m_data.partyId); if (aivDetonation != m_aivDetonation) { aivDetonation.sampleTime(partitionTimeMSec()); m_aivDetonation = aivDetonation; m_mainHandler->dds()->dts()->publish(aivDetonation); emit newAiv(aivDetonation); } } void ObjectExplosionSingleCentral::adjustTrajectoryToDetonationLocation(const Core::GeoPosition &detonationLocation) { if (m_trajectory.back() == detonationLocation) // no adjustment necessary { DEBUG_LOG(m_logger) << "Detonation location coincides with last point of trajectory for ID: " << m_data.id; return; } // if const double distToOriginSquared = LtsCoordTrans::squareDistance( m_trajectory.front().lon(), m_trajectory.front().lat(), detonationLocation.lon(), detonationLocation.lat() ); const double distTrajectorySquared = LtsCoordTrans::squareDistance( m_trajectory.back().lon(), m_trajectory.back().lat(), m_trajectory.front().lon(), m_trajectory.front().lat() ); if (distToOriginSquared > distTrajectorySquared) { WARNING_LOG(m_logger) << "Detonation location is outside of trajectory for ID: " << m_data.id; return; } // if for (unsigned int i = m_trajectory.size() - 1; i > 0; --i) { const double distStartSegmentSquared = LtsCoordTrans::squareDistance( m_trajectory[i-1].lon(), m_trajectory[i-1].lat(), m_trajectory.front().lon(), m_trajectory.front().lat() ); if (distStartSegmentSquared > distToOriginSquared) { m_trajectory.pop_back(); continue; } // if m_trajectory.pop_back(); m_trajectory.push_back(detonationLocation); return; } // for } DetonationLocationRequest ObjectExplosionSingleCentral::detonationLocationRequest(const Trajectory &trajectory) const { DetonationLocationRequest req; req.aesItemId(m_data.id); req.chargeTypeId(m_data.chargeTypeId); req.trajectory().reserve(trajectory.first.size()); for (int i = 0; i < trajectory.first.size(); ++i) req.trajectory().push_back(Core::GeoPosition(trajectory.first[i].x(), trajectory.first[i].y(), trajectory.second[i])); return req; } void ObjectExplosionSingleCentral::onDetonationLocationReply(const DetonationLocationReply &reply) { if (reply.id() != m_data.id) { DEBUG_LOG(m_logger) << "ID mismatch: " << reply.id() << " != " << m_data.id; return; } // if adjustTrajectoryToDetonationLocation(reply.position()); m_detonationLocation = reply.position(); publishTrajectoryAiv(); publishDetonationAiv(); } void ObjectExplosionSingleCentral::removeTopics() { auto dts = m_mainHandler->dds()->dts(); dts->removeExplosionSingleByKey(m_data.id); dts->removeAesItemViewByKey(1000 * m_data.id + AesType::AtExplosionSingleCentral); emit removeAiv(m_data.id); } QPolygonF ObjectExplosionSingleCentral::generateForm() { const Trajectory trajectory = Polygons::explosionSingleCentralTrajectory( m_data, positionOf(m_data.participantId), m_mainHandler->explosionSingleCentralHandler().get()->elevationMap() ); ddsVecFromPoly(trajectory.first, trajectory.second, m_trajectory); QPolygonF poly; poly << QPointF(m_trajectory.front().lon(), m_trajectory.front().lat()); poly << QPointF(m_trajectory.back().lon(), m_trajectory.back().lat()); return poly; } } // Namespace AreaEffectSimulation