/** * Handler for player data * $Id$ * $HeadURL$ * $Author$ * Created by hjl, SLSE, 2017-02-20 */ #include "handler_geopairing.h" #include "settings.h" #include "GBL_ConfigSystem/geoconfig.h" #include "GeoPairingImpl/GeoPairingImpl.hpp" #include "GeoPairingImpl/GeoPairingImplFactory.hpp" #include "GeoPairingImpl/GeoPairingImplDted.hpp" #include "GeoPairingImpl/GeoPairingImplBalistic.hpp" #include #include #include #include #include #include using namespace N_ConfigSystem; namespace CesGeoPairing { HandlerGeoPairing::HandlerGeoPairing(const std::shared_ptr &ddsHandlerAes, const std::shared_ptr &participantHandler, const std::shared_ptr &ballisticService, QObject *parent) : QObject(parent) , m_ddsHandlerAes(ddsHandlerAes) , m_handlerParticipant(participantHandler) , m_ballisticService(ballisticService) , m_requestMap() , m_timer(new QTimer(this)) , m_logger(getLogger("Plugin.GeoPairing.HandlerGeoPairing")) { m_timer->setSingleShot(true); m_ballisticService->init(Settings::cesGeopairingIniPath(), Settings::cesGeopairingIniFile(), Settings::cesAmmunitionIniFile()); auto ftcAes = m_ddsHandlerAes->ftcAes(); ftcAes->enableExplosionSingleModify(); auto ftcTab = m_ddsHandlerAes->ftcTab(); ftcTab->enableSendCesHit(); connect(m_timer, &QTimer::timeout, this, &HandlerGeoPairing::sendFtcCesHitRequestTimeout); INFO_LOG(m_logger) << "configPath = " << m_ballisticService->getConfigPath(); INFO_LOG(m_logger) << "configFile = " << m_ballisticService->getConfigFile(); INFO_LOG(m_logger) << "ammunitionFile = " << m_ballisticService->getAmmunitionFile(); const QString s_configFile = Settings::cesGeopairingIniPath() + QStringLiteral("/") + Settings::cesGeopairingIniFile(); INFO_LOG(m_logger) << "GeoPairing Config location : " << s_configFile; N_GeoPairingImpl::GeoPairingImpl *l_impl = new N_GeoPairingImpl::GeoPairingImplDted; INFO_LOG(m_logger) << "--> Installing GeoPairingImplDted..."; N_GeoPairingImpl::GeoPairingImplFactory::setImpl(l_impl); // initialize the GeoPairing implementation if (!N_GeoPairingImpl::GeoPairingImplFactory::initialize(Settings::cesGeopairingIniPath())) { ERROR_LOG(m_logger) << "Couldn't initialize GeoPairingImplFactory with GeoPairingImplDted!"; l_impl = new N_GeoPairingImpl::GeoPairingImplBalistic(); INFO_LOG(m_logger) << "--> Installing GeoPairingImplBalistic..."; N_GeoPairingImpl::GeoPairingImplFactory::setImpl(l_impl); if (!N_GeoPairingImpl::GeoPairingImplFactory::initialize(s_configFile)) { ERROR_LOG(m_logger) << "Couldn't initialize GeoPairingImplFactory with GeoPairingImplBalistic!"; abort(); } else INFO_LOG(m_logger) << "GeoPairingImplBalistic correctly initialized"; } else INFO_LOG(m_logger) << "GeoPairingImplDted correctly initialized"; INFO_LOG(m_logger) << "Initialization finished"; } // end of ctor() //----------------------------------------------------------------------------- HandlerGeoPairing::~HandlerGeoPairing() { } // end of dtor() //----------------------------------------------------------------------------- bool HandlerGeoPairing::init() { DEBUG_LOG(m_logger) << "init"; auto dtcTab = m_ddsHandlerAes->dtcTab(); auto dtcMdm = m_ddsHandlerAes->dtcMdm(); dtcMdm->enableMeteoData(); connect(dtcMdm.get(), &MeteoDataManagement::Interface::Dtc::meteoDataChanged, this, &HandlerGeoPairing::onMeteoDataChanged); dtcTab->enableGeopairingData(); connect(dtcTab.get(), &TrainingAreaBase::Interface::Dtc::geopairingDataChanged, this, &HandlerGeoPairing::onGeoPairingDataChanged); // create GeoConfig for this process && initFilename, just one time, just here GeoConfig *o_config = GeoConfig::getInstance(); const QString &fileName = Settings::cesGeopairingIniPath() + QStringLiteral("/") + Settings::cesGeopairingIniFile(); DEBUG_LOG(m_logger) << "fileName= " << fileName; if (!o_config || !o_config->initFilename(fileName)) { // Fehlerfall: const QFileInfo qFileInfo(fileName); ERROR_LOG(m_logger) << LOGFUNCTION << " initFilename failed: '" << qFileInfo.absoluteFilePath() << "'"; return false; } QString s_group = QStringLiteral("GeoPairing"); UInt32 n_numberOfAmmunitions = o_config->getInteger(s_group, QStringLiteral("NumberOfEntries"), 0); QString s_keyOfEntries = QStringLiteral("KeyOfEntries"); QString s_ammunition = QStringLiteral("Ammunition"); QString s_filter = o_config->getString(s_group, s_keyOfEntries, s_ammunition); DEBUG_LOG(m_logger) << "s_group=" << s_group << " n_numberOfAmmunitions=" << n_numberOfAmmunitions << " s_keyOfEntries=" << s_keyOfEntries << " s_ammunition=" << s_ammunition << " s_filter=" << s_filter; s_group = QStringLiteral("AmmunitionMap"); for (UInt32 i = 0; i < n_numberOfAmmunitions; i++) { QString s_ammu_group = s_filter + QString::number(i + 1); QString s_unknown = QStringLiteral(""); QString s_ammu_value = o_config->getString(s_group, s_ammu_group, s_unknown); DEBUG_LOG(m_logger) << "s_ammu_value=" << s_ammu_value << " s_group=" << s_group << " s_ammu_group=" << s_ammu_group; } //m_geoPairingPtr = new GeoPairing(m_ballisticService, loggerName); return true; } // end of init() //----------------------------------------------------------------------------- void HandlerGeoPairing::onSendCesHitReply(const Core::FunctionReplyObject &replyObject) { if (replyObject.error()) WARNING_LOG(m_logger) << "Can not send hit on participant to training area: " << replyObject(); else DEBUG_LOG(m_logger) << "onSendCesHitReply for id " << replyObject.id() << " success"; } void HandlerGeoPairing::onSendCesHitInformationReply(const Core::FunctionReplyObject &replyObject) { if (replyObject.error()) WARNING_LOG(m_logger) << "Can not send hit information on participant to training area: " << replyObject(); else DEBUG_LOG(m_logger) << "onSendCesHitInformationReply for id " << replyObject.id() << " success"; } void HandlerGeoPairing::onExplosionSingleModifyReply(const Core::FunctionReplyObject &replyObject) { if (replyObject.error()) WARNING_LOG(m_logger) << "Can not send ExplosionSingleModify: " << replyObject(); else DEBUG_LOG(m_logger) << "onExplosionSingleModifyReply for id " << replyObject.id() << " success"; } void HandlerGeoPairing::onExplosionAreaModifyReply(const Core::FunctionReplyObject &replyObject) { if (replyObject.error()) WARNING_LOG(m_logger) << "Can not send ExplosionAreaModify: " << replyObject(); else DEBUG_LOG(m_logger) << "onExplosionAreaModifyReply for id " << replyObject.id() << " success"; } // /////////////////////////////////// // M D M (MeteoDataManagement) // /////////////////////////////////// void HandlerGeoPairing::onMeteoDataChanged(const MeteoDataManagement::MeteoData &data, DataModification modType) { if (modType == DataModification::eRemoved) { DEBUG_LOG(m_logger) << "onMeteoDataChanged eRemoved"; return; } m_meteoData = data; DEBUG_LOG(m_logger) << "Got onMeteoDataChanged " << " id=" << m_meteoData.id() << " windSpeed=" << m_meteoData.windSpeed() << " windDirection=" << m_meteoData.windDirection() << " pressure=" << m_meteoData.pressure() << " temperature=" << m_meteoData.temperature(); } // /////////////////////////////////// // T A B (TrainingAreaBase) // /////////////////////////////////// //void HandlerGeoPairing::onGeoPairingDataChanged(const TrainingAreaBase::GeopairingData &data, DataModification modType) //{ // if (modType == DataModification::eRemoved) // { // DEBUG_LOG(m_logger) << "onGeoPairingDataChanged eRemoved"; // return; // } // m_geoPairingPtr = new GeoPairing(m_ballisticService); // DEBUG_LOG(m_logger) << "Got onGeoPairingDataChanged " // << " equipmentNumber=" << data.equipmentNumber() // << " position lat=" << data.position().lat() // << " lon=" << data.position().lon() // << " sampleTime=" << data.sampleTime(); // m_geoPairingPtr->setMeteo(m_meteoData.windDirection(), // m_meteoData.windSpeed(), // m_meteoData.temperature(), // m_meteoData.pressure()); // QByteArray payloadAr; // for (unsigned int i = 0; i < data.payload().size(); i++) // payloadAr[i] = data.payload().at(i); // //double x = 8.89854; // //double y = 53.0587; // double y = static_cast(data.position().lat() * 180.0 / M_PI); // double x = static_cast(data.position().lon() * 180.0 / M_PI); // QHash aircrafts = m_handlerParticipant->positionsAircraft(); // QHashIterator i(aircrafts); // while (i.hasNext()) // { // i.next(); // DEBUG_LOG(m_logger) << i.key() << ": participantId=" << i.value().participantId() // << " participantTypeId= " << i.value().participantTypeId(); // } // m_geoPairingPtr->geoPairingData(m_ballisticService, // static_cast(data.equipmentNumber()), // static_cast(data.sampleTime()) / 1000, // Time in s // y, // x, // payloadAr, // aircrafts); // int participantId = m_ddsHandlerAes->equipNo2ParticipantId(data.equipmentNumber()); // CentralEffectSimulation::HandlerParticipant::CesParticipantData pos = m_handlerParticipant->position(participantId); // int participantParty = pos.partyId(); // GeoPairing::SingleFireToCtas singleFireToCtas = m_geoPairingPtr->singleFireToCtas(); // GeoPairing::AreaFireToCtas areaFireToCtas = m_geoPairingPtr->areaFireToCtas(); // GeoPairing::FireToAircraft fireToAircaft = m_geoPairingPtr->fireToAircraft(); // GeoPairing::ReportTarget reportTarget = m_geoPairingPtr->reportTarget(); // if (singleFireToCtas.hit) // { // AreaEffectSimulation::ExplosionSingleModifyRequest explosionSingleModifyRequest; // explosionSingleModifyRequest.id(0); // explosionSingleModifyRequest.impactPosition().lat(singleFireToCtas.impactPositionLat * M_PI / 180.0); // explosionSingleModifyRequest.impactPosition().lon(singleFireToCtas.impactPositionLong * M_PI / 180.0); // // Statement by the 5000: impactTime must be in the future // explosionSingleModifyRequest.effectStart(singleFireToCtas.impactTime * 1000 + 5000); // explosionSingleModifyRequest.chargeTypeId(singleFireToCtas.ammunitionType); // explosionSingleModifyRequest.participantId(participantId); // QString name = QStringLiteral("Geopairing:") + QString::number(data.equipmentNumber()); // explosionSingleModifyRequest.name(name.toStdString()); // const CentralEffectSimulation::HandlerParticipant::CesParticipantData pos = m_handlerParticipant->position(participantId); // explosionSingleModifyRequest.partyId(pos.partyId()); // auto ftcAes = m_ddsHandlerAes->ftcAes(); // ftcAes->explosionSingleModifyRequest(explosionSingleModifyRequest, this); // } // if (areaFireToCtas.hit) // { // INFO_LOG(m_logger) << "AreaFireToCtas" // << " playerId=" << areaFireToCtas.playerId // << " impactTime=" << areaFireToCtas.impactTime // << " duration=" << areaFireToCtas.duration // << " impactPosition Lat=" << areaFireToCtas.impactPositionLat // << " Long=" << areaFireToCtas.impactPositionLong // << " fieldWidth=" << areaFireToCtas.fieldWidth // << " fieldLength=" << areaFireToCtas.fieldLength // << " heading=" << areaFireToCtas.heading // << " nbrRounds=" << areaFireToCtas.nbrRounds // << " ammunitionType=" << areaFireToCtas.ammunitionType // << " ammunitionTypeOSAG=" << areaFireToCtas.ammunitionTypeOSAG; // AreaEffectSimulation::ExplosionAreaModifyRequest explosionAreaModifyRequest; // QString name = QStringLiteral("Geopairing:") + QString::number(data.equipmentNumber()); // explosionAreaModifyRequest.id(0); // explosionAreaModifyRequest.name(name.toStdString()); // // Statement by the 5000: impactTime must be in the future // explosionAreaModifyRequest.effectStart(areaFireToCtas.impactTime * 1000 + 5000); // ms // explosionAreaModifyRequest.effectDuration(areaFireToCtas.duration + 1); // s duration must be > 0 // explosionAreaModifyRequest.cannonCount(1); // explosionAreaModifyRequest.cannonRounds(areaFireToCtas.nbrRounds); // explosionAreaModifyRequest.cannonRounds(areaFireToCtas.nbrRounds); // explosionAreaModifyRequest.chargeTypeId(areaFireToCtas.ammunitionType); // //explosionAreaModifyRequest.chargeTypeId(7004); // explosionAreaModifyRequest.participantId(participantId); // explosionAreaModifyRequest.partyId(participantParty); // Core::GeoPosition2D pos; // pos.lat(areaFireToCtas.impactPositionLat * M_PI / 180.0); // pos.lon(areaFireToCtas.impactPositionLong * M_PI / 180.0); // AreaEffectSimulation::Area area; // area.height(areaFireToCtas.fieldLength); // area.width(areaFireToCtas.fieldWidth); // area.cornerBottomLeft(pos); // area.rotation(areaFireToCtas.heading); // explosionAreaModifyRequest.area(area); // // AES // auto ftcAes = m_ddsHandlerAes->ftcAes(); // ftcAes->explosionAreaModifyRequest(explosionAreaModifyRequest, this); // } // if (fireToAircaft.hit) // { // TrainingAreaBase::SendCesHitInformation chi; // INFO_LOG(m_logger) << "send CesHitInformation to Ctas " // << " equipmentNumberGunner: " << fireToAircaft.equipmentNumberGunner // << " participantIdTarget: " << fireToAircaft.participantIdTarget // << " impactTime: " << fireToAircaft.impactTime // << " ammunitionTypeId: " << fireToAircaft.ammunitionTypeId // << " hit: " << fireToAircaft.hit << "\n\n"; // // publish Event (input for HLA Proxy) // int participantIdTarget = fireToAircaft.participantIdTarget; // int participantIdGunner = m_handlerParticipant->getParticipantId(fireToAircaft.equipmentNumberGunner); // chi.equipmentNumber(m_ddsHandlerAes->participantId2EquipNo(fireToAircaft.participantIdTarget)); // chi.participantId(fireToAircaft.participantIdTarget); // chi.originatorId(participantIdGunner); // chi.originatorEquipmentNumber(data.equipmentNumber()); // chi.chargeTypeId(fireToAircaft.ammunitionTypeId); // chi.directionDegree(m_handlerParticipant->getDirection(participantIdGunner, participantIdTarget)); // chi.distanceToOrignator(m_handlerParticipant->getDistance(participantIdGunner, participantIdTarget)); // chi.effectPercent(100); // chi.effectTime(fireToAircaft.impactTime); // m_ddsHandlerAes->ftcTab()->sendCesHitInformationRequest(chi, this); // } // if (reportTarget.send) // { // TrainingAreaBase::SendGeopairingDataRequest gpd; // gpd.equipmentNumber(data.equipmentNumber()); // gpd.participantId(participantId); // gpd.payload(LtsUtils::convert>(reportTarget.sendData)); // INFO_LOG(m_logger) << " send Geopairing-Data to Ctas" // << " equipmentNumber: " << data.equipmentNumber() // << " playerId: " << reportTarget.playerId // << " participantId: " << participantId // << " payload.size: " << reportTarget.sendData.size() // << " payload.data: " << reportTarget.sendData.toHex(); // m_ddsHandlerAes->ftcTab()->sendGeopairingDataRequest(gpd, this); // } //} void HandlerGeoPairing::onGeoPairingDataChanged(const TrainingAreaBase::GeopairingData &data, DataModification modType) { DEBUG_LOG(m_logger) << "Got onGeoPairingDataChanged "; if (modType == DataModification::eRemoved) { DEBUG_LOG(m_logger) << "onGeoPairingDataChanged eRemoved"; return; } unsigned char msgType = 0xE3; if (static_cast(data.payload().at(0)) != msgType) { DEBUG_LOG(m_logger) << "data.payload().at(0) != msgType"; return; } double y = static_cast(data.position().lat() * 180.0 / M_PI); double x = static_cast(data.position().lon() * 180.0 / M_PI); int zone = -1; const QPointF posUtm = CentralEffectSimulation::geographic2Utm(data.position(), &zone); double impactPositionLat = 0.0; double impactPositionLon = 0.0; int64_t impactTime = 0; // [ms] //QByteArray time = payloadAr.mid(2, 3); // Byte 2 ..3 int time = 0; int startIndex = 2; time += (static_cast(data.payload().at(startIndex))); time += (static_cast(data.payload().at(startIndex + 1)) << 8); // QByteArray elevationBa = payloadAr.mid(5, 8); // Byte 5 .. 8 int elevation = 0; startIndex = 5; elevation += (static_cast(data.payload().at(startIndex))); elevation += (static_cast(data.payload().at(startIndex + 1)) << 8); elevation += (static_cast(data.payload().at(startIndex + 2)) << 16); elevation += (static_cast(data.payload().at(startIndex + 3)) << 24); // QByteArray azimutBa = payloadAr.mid(9, 12); // Byte 9.. 12 int azimut = 0; startIndex = 9; azimut += (static_cast(data.payload().at(startIndex))); azimut += (static_cast(data.payload().at(startIndex + 1)) << 8); azimut += (static_cast(data.payload().at(startIndex + 2)) << 16); azimut += (static_cast(data.payload().at(startIndex + 3)) << 24); int temperature = (static_cast(data.payload().at(13))); // QByteArray timeToDetonationBa = payloadAr.mid(14, 15); // Byte 14-15; int timeToDetonation = 0; startIndex = 14; timeToDetonation += (static_cast(data.payload().at(startIndex))); timeToDetonation += (static_cast(data.payload().at(startIndex + 1)) << 8); N_Ballistic::ammunitionTypeIndirectFire ammunitionType = N_Ballistic::MOERSER; int ammunition = (data.payload().at(4) >> 1) & 0x03; QString ammunitionStr; switch (ammunition) { case 0: ammunitionStr = QStringLiteral("00: reserviert"); break; case 1: ammunitionStr = QStringLiteral("01: Munition 1"); ammunitionType = N_Ballistic::MOERSER; break; case 2: ammunitionStr = QStringLiteral("02: Munition2"); ammunitionType = N_Ballistic::NEBEL; break; case 3: ammunitionStr = QStringLiteral("03: reserviert"); break; } int treibmittel = (data.payload().at(4) >> 3) & 0x07; //int participantId = m_handlerParticipant->getParticipantId(data.equipmentNumber()); int participantId = m_ddsHandlerAes->dtcPpm()->participantIdByEquipmentNumber(data.equipmentNumber()); int partyId = m_ddsHandlerAes->dtcPpm()->participant(participantId).partyId(); float v0 = 200.0; if ( treibmittel == 0) v0 = Settings::moerserLoad_0(); else if ( treibmittel == 1) v0 = Settings::moerserLoad_1(); else if ( treibmittel == 2) v0 = Settings::moerserLoad_2(); else if ( treibmittel == 3) v0 = Settings::moerserLoad_3(); else if ( treibmittel == 4) v0 = Settings::moerserLoad_4(); else if ( treibmittel == 5) v0 = Settings::moerserLoad_5(); else if ( treibmittel == 6) v0 = Settings::moerserLoad_6(); DEBUG_LOG(m_logger) << "Got onGeoPairingDataChanged " << "\nequipmentNumber=" << data.equipmentNumber() << "\nposition lat=" << data.position().lat() << "/" << data.position().lon() << "\nposition xy=" << x << "/" << y << "\nposition UTM=" << posUtm.x() << "/" << posUtm.y() << " zone=" << zone << "\nsampleTime=" << data.sampleTime() << "\nammunitionType=" << ammunitionType << "\ntemperature=" << temperature << "\nelevation=" << elevation << "\nazimut=" << azimut << "\ntimeToDetonation=" << timeToDetonation << "\nAmmunition=" << ammunitionStr << "\ntreibmittel=" << treibmittel << " v0=" << v0; float rw = calculateDistance(v0, elevation / 10.0); float t1 = calculateFlightTime(rw, v0, elevation / 10.0); impactTime = data.sampleTime() + static_cast (t1) * 1000; //QPointF distVector = calculateDistVector ( rw, azimut/10.0); QPointF explosionPosUtm = calculateExplosionPosUtm(rw, azimut / 10.0, posUtm); DEBUG_LOG(m_logger) << "Result: rw=" << rw << " v0=" << v0 << "\n t1=" << t1 << "\n explosionPosUtm=" << explosionPosUtm.x() << "/" << explosionPosUtm.y(); LtsCoordTrans::UtmCoordinate explosionPosUtmCoordinate(zone, explosionPosUtm.x(), explosionPosUtm.y(), true); QPointF explosionPosGeoCoordinate = explosionPosUtmCoordinate.geographic(); impactPositionLon = explosionPosGeoCoordinate.x(); impactPositionLat = explosionPosGeoCoordinate.y(); AreaEffectSimulation::ExplosionSingleModifyRequest explosionSingleModifyRequest; explosionSingleModifyRequest.id(0); explosionSingleModifyRequest.impactPosition().lat(impactPositionLat); explosionSingleModifyRequest.impactPosition().lon(impactPositionLon); // Statement by the 5000: impactTime must be in the future explosionSingleModifyRequest.effectStart(impactTime); explosionSingleModifyRequest.chargeTypeId(ammunitionType); explosionSingleModifyRequest.participantId(participantId); QString name = QStringLiteral("Geopairing:") + QString::number(data.equipmentNumber()); explosionSingleModifyRequest.name(name.toStdString()); //const CentralEffectSimulation::HandlerParticipant::CesParticipantData pos = m_handlerParticipant->position(participantId); explosionSingleModifyRequest.partyId(partyId); DEBUG_LOG(m_logger) << "impactTime=" << data.sampleTime() << " name=" << name << " m_ddsHandler->currentPartitionTime=" << m_ddsHandlerAes->currentPartitionTime() << " participantId=" << participantId << " " << participantId << " partyId=" << partyId; if (impactTime > m_ddsHandlerAes->currentPartitionTime()) { DEBUG_LOG(m_logger) << "Send explosionSingleModifyRequest"; auto ftcAes = m_ddsHandlerAes->ftcAes(); ftcAes->explosionSingleModifyRequest(explosionSingleModifyRequest, this); } else DEBUG_LOG(m_logger) << "NOT Send explosionSingleModifyRequest impactTime is in the past"; } void HandlerGeoPairing::onSendGeopairingDataReply(const Core::FunctionReplyObject &replyObject) { if (replyObject.error()) WARNING_LOG(m_logger) << "Can not send GeopPairing Data participant : " << replyObject(); else DEBUG_LOG(m_logger) << "onSendGeopairingDataReply for id " << replyObject.id() << " success"; } void HandlerGeoPairing::sendFtcCesHitRequestTimeout() { auto ftcTab = m_ddsHandlerAes->ftcTab(); for (const TrainingAreaBase::SendCesHitRequest &hr : qAsConst(m_requestMap)) { DEBUG_LOG(m_logger) << "sendFtcCesHitRequest: " << hr; ftcTab->sendCesHitRequest(hr, this); } m_requestMap.clear(); } ////////////////////////////////////////////////////////////////////////////// /// Algorithmus: der schiefe Wurf (the crooked throw) /// /// /// /// Annahme: Hoehe ist bei Abschussposition und bei -Zielposition gleich /// ////////////////////////////////////////////////////////////////////////////// // v0 [m/s] // elevation [degree] double HandlerGeoPairing::calculateDistance(const float v0, const float elevation) { float rw; rw = v0 * v0 * sin(2.0 * 3.1415927 * elevation / 180.0) / 9.81; return rw; } // rw Reichweite [m] // v0 [m/s] // elevation [degree] double HandlerGeoPairing::calculateFlightTime(const float rw, const float v0, const float elevation) { float t1; t1 = rw / (v0 * cos(3.1415927 * elevation / 180.0)); return t1; } // rw Reichweite [m] // azimut [degree] // posUtm Position Shooter UTM QPointF HandlerGeoPairing::calculateExplosionPosUtm(const float rw, const float azimut, const QPointF &posUtm) { float dir; QPointF explosionPosUtm; if (azimut > 90.0) dir = 450.0 - azimut; else dir = 90.0 - azimut; explosionPosUtm.setX(posUtm.x() + rw * cos(M_PI * dir / 180.0)); explosionPosUtm.setY(posUtm.y() + rw * sin(M_PI * dir / 180.0)); return explosionPosUtm; } } // namespace CesGeoPairing