Files
flightgear/src/AIModel/AIFlightPlanCreateCruise.cxx
T
2022-10-20 20:29:11 +08:00

336 lines
11 KiB
C++

/******************************************************************************
* AIFlightPlanCreateCruise.cxx
* Written by Durk Talsma, started February, 2006.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
**************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <fstream>
#include <Airports/airport.hxx>
#include <Airports/runways.hxx>
#include <Airports/dynamics.hxx>
#include <Environment/environment_mgr.hxx>
#include <Environment/environment.hxx>
#include <Traffic/Schedule.hxx>
#include "AIFlightPlan.hxx"
#include "AIAircraft.hxx"
#include "performancedata.hxx"
using std::string;
/*
void FGAIFlightPlan::evaluateRoutePart(double deplat,
double deplon,
double arrlat,
double arrlon)
{
// First do a prescan of all the waypoints that are within a reasonable distance of the
// ideal route.
intVec nodes;
int tmpNode, prevNode;
SGGeoc dep(SGGeoc::fromDegM(deplon, deplat, 100.0));
SGGeoc arr(SGGeoc::fromDegM(arrlon, arrlat, 100.0));
SGVec3d a = SGVec3d::fromGeoc(dep);
SGVec3d nb = normalize(SGVec3d::fromGeoc(arr));
SGVec3d na = normalize(a);
SGVec3d _cross = cross(nb, na);
double angle = acos(dot(na, nb));
const double angleStep = 0.05 * SG_DEGREES_TO_RADIANS;
tmpNode = 0;
for (double ang = 0.0; ang < angle; ang += angleStep)
{
SGQuatd q = SGQuatd::fromAngleAxis(ang, _cross);
SGGeod geod = SGGeod::fromCart(q.transform(a));
prevNode = tmpNode;
tmpNode = globals->get_airwaynet()->findNearestNode(geod);
FGNode* node = globals->get_airwaynet()->findNode(tmpNode);
if ((tmpNode != prevNode) && (SGGeodesy::distanceM(geod, node->getPosition()) < 25000)) {
nodes.push_back(tmpNode);
}
}
intVecIterator i = nodes.begin();
intVecIterator j = nodes.end();
while (i != nodes.end())
{
j = nodes.end();
while (j != i)
{
j--;
FGAirRoute routePart = globals->get_airwaynet()->findShortestRoute(*i, *j);
if (!(routePart.empty()))
{
airRoute.add(routePart);
i = j;
break;
}
}
i++;
}
}
*/
/*
void FGAIFlightPlan::createCruise(bool firstFlight, FGAirport *dep,
FGAirport *arr, double latitude,
double longitude, double speed, double alt)
{
bool useInitialWayPoint = true;
bool useCurrentWayPoint = false;
double heading;
double lat, lon, az;
double lat2, lon2, az2;
double azimuth;
waypoint *wpt;
waypoint *init_waypoint;
intVec ids;
char buffer[32];
SGPath routefile = globals->get_fg_root();
init_waypoint = new waypoint;
init_waypoint->name = "Initial waypoint";
init_waypoint->latitude = latitude;
init_waypoint->longitude = longitude;;
//wpt->altitude = apt->getElevation(); // should maybe be tn->elev too
init_waypoint->altitude = alt;
init_waypoint->speed = 450; //speed;
init_waypoint->crossat = -10000;
init_waypoint->gear_down = false;
init_waypoint->flaps_down= false;
init_waypoint->finished = false;
init_waypoint->on_ground = false;
pushBackWaypoint(init_waypoint);
routefile.append("Data/AI/FlightPlans");
snprintf(buffer, 32, "%s-%s.txt",
dep->getId().c_str(),
arr->getId().c_str());
routefile.append(buffer);
SG_LOG(SG_AI, SG_DEBUG, "trying to read " << routefile.c_str());
//exit(1);
if (routefile.exists())
{
sg_gzifstream in( routefile.str() );
do {
in >> route;
} while (!(in.eof()));
}
else {
//int runwayId = apt->getDynamics()->getGroundNetwork()->findNearestNode(lat2, lon2);
//int startId = globals->get_airwaynet()->findNearestNode(dep->getLatitude(), dep->getLongitude());
//int endId = globals->get_airwaynet()->findNearestNode(arr->getLatitude(), arr->getLongitude());
//FGAirRoute route;
evaluateRoutePart(dep->getLatitude(), dep->getLongitude(),
arr->getLatitude(), arr->getLongitude());
//exit(1);
}
route.first();
int node;
if (route.empty()) {
// if no route could be found, create a direct gps route...
SG_LOG(SG_AI, SG_DEBUG, "still no route found from " << dep->getName() << " to << " << arr->getName());
//exit(1);
} else {
while(route.next(&node))
{
FGNode *fn = globals->get_airwaynet()->findNode(node);
SG_LOG(SG_AI, SG_BULK, "Checking status of each waypoint: " << fn->getIdent());
SGWayPoint first(init_waypoint->longitude,
init_waypoint->latitude,
alt);
SGWayPoint curr (fn->getLongitude(),
fn->getLatitude(),
alt);
SGWayPoint arr (arr->getLongitude(),
arr->getLatitude(),
alt);
double crse, crsDiff;
double dist;
first.CourseAndDistance(arr, &course, &distance);
first.CourseAndDistance(curr, &crse, &dist);
dist *= SG_METER_TO_NM;
// We're only interested in the absolute value of crsDiff
// wich should fall in the 0-180 deg range.
crsDiff = fabs(crse-course);
if (crsDiff > 180)
crsDiff = 360-crsDiff;
// These are the three conditions that we consider including
// in our flight plan:
// 1) current waypoint is less then 100 miles away OR
// 2) curren waypoint is ahead of us, at any distance
SG_LOG(SG_AI, SG_BULK, " Distance : " << dist << " : Course diff " << crsDiff
<< " crs to dest : " << course
<< " crs to wpt : " << crse);
if ((dist > 20.0) && (crsDiff > 90.0))
{
//useWpt = false;
// Once we start including waypoints, we have to continue, even though
// one of the following way point would suffice.
// so once is the useWpt flag is set to true, we cannot reset it to false.
SG_LOG(SG_AI, SG_BULK, " discarding ");
// << ": Course difference = " << crsDiff
// << "Course = " << course
// << "crse = " << crse);
}
else {
//i = ids.end()-1;
SG_LOG(SG_AI, SG_BULK, " accepting ")
//ids.pop_back();
wpt = new waypoint;
wpt->name = "Airway"; // fixme: should be the name of the waypoint
wpt->latitude = fn->getLatitude();
wpt->longitude = fn->getLongitude();
//wpt->altitude = apt->getElevation(); // should maybe be tn->elev too
wpt->altitude = alt;
wpt->speed = 450; //speed;
wpt->crossat = -10000;
wpt->gear_down = false;
wpt->flaps_down= false;
wpt->finished = false;
wpt->on_ground = false;
pushBackWaypoint(wpt);
}
if (!(routefile.exists()))
{
route.first();
fstream outf( routefile.c_str(), fstream::out );
while (route.next(&node))
outf << node << endl;
}
}
}
arr->getDynamics()->getActiveRunway("com", 2, activeRunway);
if (!(globals->get_runways()->search(arr->getId(),
activeRunway,
&rwy)))
{
SG_LOG(SG_AI, SG_WARN, "Failed to find runway for " << arr->getId());
// Hmm, how do we handle a potential error like this?
exit(1);
}
//string test;
//arr->getActiveRunway(string("com"), 1, test);
//exit(1);
SG_LOG(SG_AI, SG_DEBUG, "Altitude = " << alt);
SG_LOG(SG_AI, SG_DEBUG, "Done");
SG_LOG(SG_AI, SG_DEBUG, "Creating cruise to " << arr->getId() << " " << latitude << " " << longitude);
heading = rwy._heading;
azimuth = heading + 180.0;
while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
// Note: This places us at the location of the active
// runway during initial cruise. This needs to be
// fixed later.
geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth,
110000,
&lat2, &lon2, &az2 );
wpt = new waypoint;
wpt->name = "BOD"; //wpt_node->getStringValue("name", "END");
wpt->latitude = lat2;
wpt->longitude = lon2;
wpt->altitude = alt;
wpt->speed = speed;
wpt->crossat = alt;
wpt->gear_down = false;
wpt->flaps_down= false;
wpt->finished = false;
wpt->on_ground = false;
pushBackWaypoint(wpt);
}
*/
/*******************************************************************
* CreateCruise
* initialize the Aircraft at the parking location
*
* Note that this is the original version that does not
* do any dynamic route computation.
******************************************************************/
bool FGAIFlightPlan::createCruise(FGAIAircraft *ac, bool firstFlight, FGAirport *dep,
FGAirport *arr,
const SGGeod& current,
double speed,
double alt,
const string& fltType)
{
double vCruise = ac->getPerformance()->vCruise();
FGAIWaypoint *wpt;
//FIXME usually that will be "before" the next WP
wpt = createInAir(ac, "Cruise", current, alt, vCruise);
if (waypoints.size() == 0) {
pushBackWaypoint(wpt);
SG_LOG(SG_AI, SG_DEBUG, "Cruise spawn " << ac->getCallSign());
} else {
SG_LOG(SG_AI, SG_DEBUG, "Cruise start " << ac->getCallSign());
}
//
const string& rwyClass = getRunwayClassFromTrafficType(fltType);
double heading = ac->getTrafficRef()->getCourse();
arr->getDynamics()->getActiveRunway(rwyClass, 2, activeRunway, heading);
if (!arr->hasRunwayWithIdent(activeRunway)) {
SG_LOG(SG_AI, SG_WARN, ac->getCallSign() << " cruise to" << arr->getId() << activeRunway << " not active");
return false;
}
FGRunway* rwy = arr->getRunwayByIdent(activeRunway);
assert( rwy != NULL );
// begin descent 110km out
double distanceOut = arr->getDynamics()->getApproachController()->getRunway(rwy->name())->getApproachDistance(); //12 * SG_NM_TO_METER;
SGGeod beginDescentPoint = rwy->pointOnCenterline(-3*distanceOut);
SGGeod secondaryDescentPoint = rwy->pointOnCenterline(0);
double distanceToRwy = SGGeodesy::distanceM(current, secondaryDescentPoint);
if (distanceToRwy>4*distanceOut) {
FGAIWaypoint *bodWpt = createInAir(ac, "BOD", beginDescentPoint, alt, vCruise);
pushBackWaypoint(bodWpt);
FGAIWaypoint *bod2Wpt = createInAir(ac, "BOD2", secondaryDescentPoint, alt, vCruise);
pushBackWaypoint(bod2Wpt);
} else {
// We are too near. The descent leg takes care of this (teardrop etc)
FGAIWaypoint *bodWpt = createInAir(ac, "BOD", SGGeodesy::direct(current, ac->getTrueHeadingDeg(), 10000), alt, vCruise);
pushBackWaypoint(bodWpt);
FGAIWaypoint *bod2Wpt = createInAir(ac, "BOD2", SGGeodesy::direct(current, ac->getTrueHeadingDeg(), 15000), alt, vCruise);
pushBackWaypoint(bod2Wpt);
}
return true;
}