Files
qt5-legatus-legacy/Lts/Services/AreaEffectSimulation/Trajectory/trajectory_helper.cpp
T
2026-08-13 18:33:10 +02:00

221 lines
5.4 KiB
C++
Executable File

/**
* @RDE_HEADER@
* Trajectory Helper
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, SLTE, 2023-11-08
*/
#include "trajectory_helper.h"
#include "../logger.h"
#include <LtsUtilsCore/qpoint3d.h>
#include <QObject>
#include <QString>
#include <QDebug>
#include <iostream>
#include <cmath>
namespace AreaEffectSimulation
{
double TrajectoryHelper::flightDurationSec(const LtsUtils::QPoint3D &posStart, const LtsUtils::QPoint3D &posEnd, double peakHeightAbs,
double *betaRadiantOut, double *vOut,
QString *reasonOut)
{
if ((posStart.z() > peakHeightAbs) || (posEnd.z() > peakHeightAbs))
{
if (reasonOut)
{
//: "Höhenfehler"
*reasonOut = QObject::tr("HeightElevationError(%1 %2 %3)").arg(posStart.z()).arg(peakHeightAbs).arg(posEnd.z());
}
return -1.0;
}
double z = posEnd.z() - posStart.z();
double h = peakHeightAbs - posStart.z();
double x = posEnd.x() - posStart.x();
double y = posEnd.y() - posStart.y();
double r = sqrt(x * x + y * y);
if (r < 0.01)
{
if (reasonOut)
{
//: "StartEndeAbstandsfehler"
*reasonOut = QObject::tr("StartEndDistanceError(%1)").arg(r);
}
return 0.0; // No distance -> no duration -> 0.0
}
double beta; // Abschusswinkel / elevation_angle in radiant
double v;
if (fabs(z) < 0.01)
{
beta = atan(4.0 * h / r);
v = sqrt(9.81 * r / sin(2.0 * beta));
}
else
{
double b;
double p = - 4.0 * h / r;
double q = 4.0 * h * z / (r * r); // ehemals double q = - 4.0 * h * z / (r * r);
if (p * p / 4.0 > q)
b = - (p / 2.0) + sqrt(p * p / 4.0 - q);
else
return -1.0;
beta = atan(b);
double a = b * b / (4.0 * h);
double rh = b / a;
v = sqrt(9.81 * rh / sin(2.0 * beta));
}
// handle optional values:
if (betaRadiantOut)
*betaRadiantOut = beta;
if (vOut)
*vOut = v;
const double result = r / (v * cos(beta));
if ((result < 0) && reasonOut)
{
//: "FlugzeitFehlerUnbekannt"
*reasonOut = QObject::tr("FlightDurationSecErrorUnknown(%1)").arg(result);
}
return result;
}
double TrajectoryHelper::peakHeightAbs(const LtsUtils::QPoint3D &posStart, const LtsUtils::QPoint3D &posEnd, double timeSec,
double *betaRadiantOut, double *vOut,
QString *reasonOut)
{
double x = posEnd.x() - posStart.x();
double y = posEnd.y() - posStart.y();
double r = sqrt(x * x + y * y);
if (r < 0.01)
{
if (reasonOut)
{
//: "StartEndeAbstandsfehler"
*reasonOut = QObject::tr("StartEndDistanceError(%1)").arg(r);
}
return 0.0;
}
double v, rh;
double t2 = timeSec * timeSec;
double z = posEnd.z() - posStart.z();
if (fabs(z) < 0.01)
{
v = sqrt((9.81 * 9.81 * t2 / 4.0) + (r * r / t2));
rh = r;
}
else
{
double vx = r / timeSec;
double vy = (9.81 * timeSec * timeSec / 2.0 + z) / timeSec;
v = sqrt(vx * vx + vy * vy);
rh = 2.0 * r * sqrt((v * v - r * r / t2)) / (9.81 * timeSec);
}
double arcSin = 9.81 * rh / (v * v);
if (arcSin > 1.0)
{
if (reasonOut)
{
//: "45GradSchuss"
*reasonOut = QObject::tr("45DegreeShot(%1)").arg(arcSin);
}
return -1;
}
// beta: Abschusswinkel / elevationsWinkel in radiant
double beta;
if (fabs(9.81 * rh - v * v) < 0.0001)
{
beta = M_PI_4;
}
else
{
if (9.81 * rh > (v * v))
{
if (reasonOut)
{
//: "GipfelhöhenFehlerUnbekannt"
*reasonOut = QObject::tr("PeakHeightUnknownError(rh=%1,v=%2)").arg(rh).arg(v);
}
return -1;
}
beta = asin( 9.81 * rh / (v * v)) / 2.0;
}
// [GUEZE-2472] Inkonsitente Werte bei der Berechnung der Gipfelhöhe (peakHeight)
// Es gibt nur eine Flugzeit zu einer maximalen Höhe h bei Vorgabe der Zielentfernung.
// if (beta < M_PI_2)
// {
// if (trajMode == TrajectoryMode::TrajectoryModeHigh)
// beta = M_PI_2 - beta;
// }
// else
// {
// if (trajMode == TrajectoryMode::TrajectoryModeLow)
// beta = M_PI_2 - beta;
// }
double beta2;
if (beta < M_PI_2)
beta2 = M_PI_2 - beta;
else
beta2 = M_PI_2 + beta;
if (fabs((timeSec * v) * cos(beta) - r) > fabs((timeSec * v) * cos(beta2) - r))
beta = beta2;
double h = v * v * sin(beta) * sin(beta) / (2.0 * 9.81);
h += posStart.z();
// handle optional values:
if (betaRadiantOut)
*betaRadiantOut = beta;
if (vOut)
*vOut = v;
return h;
}
LtsUtils::QPoint3D TrajectoryHelper::realStartPoint(const LtsUtils::QPoint3D &apogaeum, const LtsUtils::QPoint3D &endPos)
{
LtsUtils::QPoint3D realStart = apogaeum - (endPos-apogaeum);
realStart.setZ(endPos.z());
return realStart;
}
//const QString TrajectoryGenerator::string4poly(const TrajectoryPoint3D &trajectory)
//{
// if (trajectory.isEmpty())
// return (QStringLiteral("Empty Polygon!"));
// const Point3D &p3D = trajectory.first();
// int zone = LtsCoordTrans::UtmCoordinate::fromGeographic(p3D.toPointF()).zone;
// QStringList pointSl;
// pointSl.reserve(trajectory.size());
// for (int i = 0; i < trajectory.size(); ++i)
// pointSl << QString(QStringLiteral("utm=%1 h=%2")).arg(LtsCoordTrans::UtmCoordinate::fromGeographic(p3D.toPointF(), zone).mgrs(), QString::number(p3D.z(), 'f', 1));
// return QStringLiteral("%1 Values (%2)").arg(trajectory.count()).arg(pointSl.join(QStringLiteral(" # ")));
//}
} // namespace AreaEffectSimulation