2006-07-27 14:42:15 +00:00
|
|
|
/******************************************************************************
|
|
|
|
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
**************************************************************************/
|
2008-12-27 16:09:01 +00:00
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include <config.h>
|
|
|
|
#endif
|
|
|
|
|
2006-07-27 14:42:15 +00:00
|
|
|
#include <fstream>
|
|
|
|
#include <iostream>
|
|
|
|
#include "AIFlightPlan.hxx"
|
|
|
|
#include <simgear/math/polar3d.hxx>
|
|
|
|
#include <simgear/math/sg_geodesy.hxx>
|
|
|
|
#include <simgear/route/waypoint.hxx>
|
|
|
|
|
|
|
|
#include <Navaids/awynet.hxx>
|
|
|
|
#include <Airports/runways.hxx>
|
2008-08-14 18:13:39 +00:00
|
|
|
#include <Airports/dynamics.hxx>
|
2006-07-27 14:42:15 +00:00
|
|
|
|
|
|
|
#include <Environment/environment_mgr.hxx>
|
|
|
|
#include <Environment/environment.hxx>
|
|
|
|
|
2008-07-27 16:25:13 +00:00
|
|
|
using std::iostream;
|
2006-07-27 14:42:15 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
|
|
SGWayPoint first (deplon,
|
|
|
|
deplat,
|
|
|
|
100);
|
|
|
|
SGWayPoint sec (arrlon,
|
|
|
|
arrlat,
|
|
|
|
100);
|
2007-07-08 08:46:29 +00:00
|
|
|
double course, distance;
|
2006-07-27 14:42:15 +00:00
|
|
|
first.CourseAndDistance(sec, &course, &distance);
|
|
|
|
distance *= SG_METER_TO_NM;
|
|
|
|
|
2007-07-08 08:46:29 +00:00
|
|
|
SGVec3d a = SGVec3d::fromGeoc(SGGeoc::fromDegM(deplon, deplat, 1));
|
|
|
|
SGVec3d b = SGVec3d::fromGeoc(SGGeoc::fromDegM(arrlon, arrlat, 1));
|
|
|
|
SGVec3d _cross = cross(b, a);
|
2006-07-27 14:42:15 +00:00
|
|
|
|
2007-07-08 08:46:29 +00:00
|
|
|
double angle = sgACos(dot(a, b));
|
2006-07-27 14:42:15 +00:00
|
|
|
tmpNode = 0;
|
|
|
|
for (double ang = 0.0; ang < angle; ang += 0.05)
|
|
|
|
{
|
2007-07-08 08:46:29 +00:00
|
|
|
sgdVec3 newPos;
|
|
|
|
sgdMat4 matrix;
|
2006-07-27 14:42:15 +00:00
|
|
|
//cerr << "Angle = " << ang << endl;
|
2007-07-08 08:46:29 +00:00
|
|
|
sgdMakeRotMat4(matrix, ang, _cross.sg());
|
2006-07-27 14:42:15 +00:00
|
|
|
for(int j = 0; j < 3; j++)
|
|
|
|
{
|
|
|
|
newPos[j] =0.0;
|
|
|
|
for (int k = 0; k<3; k++)
|
|
|
|
{
|
|
|
|
newPos[j] += matrix[j][k]*a[k];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//cerr << "1"<< endl;
|
2007-07-27 19:31:44 +00:00
|
|
|
SGGeoc geoc = SGGeoc::fromCart(SGVec3d(newPos[0], newPos[1], newPos[2]));
|
2007-07-15 14:08:31 +00:00
|
|
|
|
2007-07-27 19:31:44 +00:00
|
|
|
double midlat = geoc.getLatitudeDeg();
|
|
|
|
double midlon = geoc.getLongitudeDeg();
|
2006-07-27 14:42:15 +00:00
|
|
|
|
|
|
|
prevNode = tmpNode;
|
|
|
|
tmpNode = globals->get_airwaynet()->findNearestNode(midlat, midlon);
|
|
|
|
|
|
|
|
double nodelat = globals->get_airwaynet()->findNode(tmpNode)->getLatitude ();
|
|
|
|
double nodelon = globals->get_airwaynet()->findNode(tmpNode)->getLongitude ();
|
|
|
|
SGWayPoint curr(midlat,
|
|
|
|
midlon,
|
|
|
|
100);
|
|
|
|
SGWayPoint node(nodelat,
|
|
|
|
nodelon,
|
|
|
|
100);
|
|
|
|
curr.CourseAndDistance(node, &course, &distance);
|
|
|
|
if ((distance < 25000) && (tmpNode != prevNode))
|
|
|
|
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()))
|
|
|
|
{
|
2006-07-29 18:17:19 +00:00
|
|
|
airRoute.add(routePart);
|
2006-07-27 14:42:15 +00:00
|
|
|
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;
|
|
|
|
waypoints.push_back(init_waypoint);
|
|
|
|
routefile.append("Data/AI/FlightPlans");
|
|
|
|
snprintf(buffer, 32, "%s-%s.txt",
|
|
|
|
dep->getId().c_str(),
|
|
|
|
arr->getId().c_str());
|
|
|
|
routefile.append(buffer);
|
|
|
|
cerr << "trying to read " << routefile.c_str()<< endl;
|
|
|
|
//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...
|
|
|
|
cerr << "still no route found from " << dep->getName() << " to << " << arr->getName() <<endl;
|
|
|
|
|
|
|
|
//exit(1);
|
|
|
|
} else {
|
|
|
|
while(route.next(&node))
|
|
|
|
{
|
|
|
|
FGNode *fn = globals->get_airwaynet()->findNode(node);
|
|
|
|
//cerr << "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
|
|
|
|
//cerr << " 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.
|
|
|
|
//cerr << " discarding " << endl;
|
|
|
|
// << ": Course difference = " << crsDiff
|
|
|
|
// << "Course = " << course
|
|
|
|
// << "crse = " << crse << endl;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
//i = ids.end()-1;
|
|
|
|
//cerr << " accepting " << endl;
|
|
|
|
|
|
|
|
//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;
|
|
|
|
waypoints.push_back(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)))
|
|
|
|
{
|
|
|
|
cout << "Failed to find runway for " << arr->getId() << endl;
|
|
|
|
// Hmm, how do we handle a potential error like this?
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
//string test;
|
|
|
|
//arr->getActiveRunway(string("com"), 1, test);
|
|
|
|
//exit(1);
|
|
|
|
|
|
|
|
//cerr << "Altitude = " << alt << endl;
|
|
|
|
//cerr << "Done" << endl;
|
|
|
|
//if (arr->getId() == "EHAM")
|
|
|
|
// {
|
|
|
|
// cerr << "Creating cruise to EHAM " << latitude << " " << longitude << endl;
|
|
|
|
// }
|
James Turner:
Convert FGRunway to be heap-based, and inherit FGPositioned. This is a large, ugly change, since FGRunway was essentially a plain struct, with no accessors or abstraction. This change adds various helpers and accessors to FGRunway, but doesn't change many places to use them - that will be a follow up series of patches. It's still a large patch, but outside of FGAirport and FGRunway, mostly mechanical search-and-replace.
An interesting part of this change is that reciprocal runways now exist as independent objects, rather than being created on the fly by the search methods. This simplifies some pieces of code that search for and iterate runways. For users who only want one 'end' of a runway, the new 'isReciprocal' predicate allows them to ignore the 'other' end. Current the only user of this is the 'ground-radar' ATC feature. If we had data on which runways are truly 'single-ended', it would now be trivial to use this in the airport loader to *not* create the reciprocal.
2008-09-11 08:38:09 +00:00
|
|
|
heading = rwy->headingDeg();
|
2006-07-27 14:42:15 +00:00
|
|
|
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;
|
|
|
|
waypoints.push_back(wpt);
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
* CreateCruise
|
|
|
|
* initialize the Aircraft at the parking location
|
|
|
|
*
|
|
|
|
* Note that this is the original version that does not
|
|
|
|
* do any dynamic route computation.
|
|
|
|
******************************************************************/
|
|
|
|
void FGAIFlightPlan::createCruise(bool firstFlight, FGAirport *dep,
|
|
|
|
FGAirport *arr, double latitude,
|
|
|
|
double longitude, double speed,
|
2007-06-28 18:30:35 +00:00
|
|
|
double alt, const string& fltType)
|
2006-07-27 14:42:15 +00:00
|
|
|
{
|
|
|
|
double wind_speed;
|
|
|
|
double wind_heading;
|
|
|
|
double heading;
|
|
|
|
double lat, lon, az;
|
|
|
|
double lat2, lon2, az2;
|
|
|
|
double azimuth;
|
|
|
|
waypoint *wpt;
|
|
|
|
|
|
|
|
wpt = new waypoint;
|
|
|
|
wpt->name = "Cruise"; //wpt_node->getStringValue("name", "END");
|
|
|
|
wpt->latitude = latitude;
|
|
|
|
wpt->longitude = longitude;
|
|
|
|
wpt->altitude = alt;
|
|
|
|
wpt->speed = speed;
|
|
|
|
wpt->crossat = -10000;
|
|
|
|
wpt->gear_down = false;
|
|
|
|
wpt->flaps_down= false;
|
|
|
|
wpt->finished = false;
|
|
|
|
wpt->on_ground = false;
|
2006-08-26 07:22:20 +00:00
|
|
|
wpt->routeIndex = 0;
|
2006-07-27 14:42:15 +00:00
|
|
|
waypoints.push_back(wpt);
|
|
|
|
|
|
|
|
|
2007-06-28 18:30:35 +00:00
|
|
|
string rwyClass = getRunwayClassFromTrafficType(fltType);
|
|
|
|
arr->getDynamics()->getActiveRunway(rwyClass, 2, activeRunway);
|
2008-08-14 18:13:39 +00:00
|
|
|
rwy = arr->getRunwayByIdent(activeRunway);
|
|
|
|
|
James Turner:
Convert FGRunway to be heap-based, and inherit FGPositioned. This is a large, ugly change, since FGRunway was essentially a plain struct, with no accessors or abstraction. This change adds various helpers and accessors to FGRunway, but doesn't change many places to use them - that will be a follow up series of patches. It's still a large patch, but outside of FGAirport and FGRunway, mostly mechanical search-and-replace.
An interesting part of this change is that reciprocal runways now exist as independent objects, rather than being created on the fly by the search methods. This simplifies some pieces of code that search for and iterate runways. For users who only want one 'end' of a runway, the new 'isReciprocal' predicate allows them to ignore the 'other' end. Current the only user of this is the 'ground-radar' ATC feature. If we had data on which runways are truly 'single-ended', it would now be trivial to use this in the airport loader to *not* create the reciprocal.
2008-09-11 08:38:09 +00:00
|
|
|
heading = rwy->headingDeg();
|
2006-07-27 14:42:15 +00:00
|
|
|
azimuth = heading + 180.0;
|
|
|
|
while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
|
|
|
|
|
|
|
|
|
James Turner:
Convert FGRunway to be heap-based, and inherit FGPositioned. This is a large, ugly change, since FGRunway was essentially a plain struct, with no accessors or abstraction. This change adds various helpers and accessors to FGRunway, but doesn't change many places to use them - that will be a follow up series of patches. It's still a large patch, but outside of FGAirport and FGRunway, mostly mechanical search-and-replace.
An interesting part of this change is that reciprocal runways now exist as independent objects, rather than being created on the fly by the search methods. This simplifies some pieces of code that search for and iterate runways. For users who only want one 'end' of a runway, the new 'isReciprocal' predicate allows them to ignore the 'other' end. Current the only user of this is the 'ground-radar' ATC feature. If we had data on which runways are truly 'single-ended', it would now be trivial to use this in the airport loader to *not* create the reciprocal.
2008-09-11 08:38:09 +00:00
|
|
|
geo_direct_wgs_84 ( 0, rwy->latitude(), rwy->longitude(), azimuth,
|
2006-07-27 14:42:15 +00:00
|
|
|
110000,
|
|
|
|
&lat2, &lon2, &az2 );
|
|
|
|
wpt = new waypoint;
|
|
|
|
wpt->name = "BOD";
|
|
|
|
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;
|
2006-08-26 07:22:20 +00:00
|
|
|
wpt->routeIndex = 0;
|
2006-07-27 14:42:15 +00:00
|
|
|
waypoints.push_back(wpt);
|
|
|
|
}
|