From 54594e521947b8238fa73efd02f6a4d90d809eb4 Mon Sep 17 00:00:00 2001 From: ehofman Date: Tue, 18 Oct 2005 18:44:37 +0000 Subject: [PATCH] Durk Talsma: Auf Niederlandisch: Bij deze de patch voor de taxiway code. Deze code is nog gebaseerd op de bestaaande architectuur, gebaseerd op de FGAirport class in simple.[ch]xx Ik heb me voornamelijk gericht op nieuwe functionaliteit; de volgende submissie zal waarschijnlijk bestaan uit opschoning, opsplitsing en een implementatie van de nieuwe airport architectuur, zoals voorgesteld door David Luff. En Anglais: Here is the patch for the taxiway code. This code is still based on the exsisting architecture, which is based on the FGAirport class in simple.[ch]xx I've aimed mostly at new functionality; The next batch will probably contain code cleanups, splitups and the implementation fo the new airport architecture, as proposed by David Luff. --- src/AIModel/AIFlightPlan.hxx | 3 +- src/AIModel/AIFlightPlanCreate.cxx | 356 ++++++++++++++++++-------- src/Airports/simple.cxx | 386 +++++++++++++++++++++++++++-- src/Airports/simple.hxx | 149 ++++++++++- src/Traffic/Schedule.cxx | 10 +- 5 files changed, 772 insertions(+), 132 deletions(-) diff --git a/src/AIModel/AIFlightPlan.hxx b/src/AIModel/AIFlightPlan.hxx index a6ae1182e..15c479672 100644 --- a/src/AIModel/AIFlightPlan.hxx +++ b/src/AIModel/AIFlightPlan.hxx @@ -104,9 +104,10 @@ private: time_t start_time; int leg; int gateId; + string activeRunway; void createPushBack(bool, FGAirport*, double, double, double, string, string, string); - void createTaxi(bool, int, FGAirport *, double, string, string, string); + void createTaxi(bool, int, FGAirport *, double, double, double, string, string, string); void createTakeOff(bool, FGAirport *, double); void createClimb(bool, FGAirport *, double, double); void createCruise(bool, FGAirport*, FGAirport*, double, double, double, double); diff --git a/src/AIModel/AIFlightPlanCreate.cxx b/src/AIModel/AIFlightPlanCreate.cxx index f5455effe..c851a6e71 100644 --- a/src/AIModel/AIFlightPlanCreate.cxx +++ b/src/AIModel/AIFlightPlanCreate.cxx @@ -50,7 +50,7 @@ void FGAIFlightPlan::create(FGAirport *dep, FGAirport *arr, int legNr, double al break; case 2: //cerr << "Creating Taxi" << endl; - createTaxi(firstFlight, 1, dep, radius, fltType, aircraftType, airline); + createTaxi(firstFlight, 1, dep, latitude, longitude, radius, fltType, aircraftType, airline); break; case 3: //cerr << "Creating TAkeoff" << endl; @@ -74,7 +74,7 @@ void FGAIFlightPlan::create(FGAirport *dep, FGAirport *arr, int legNr, double al break; case 8: //cerr << "Creating Taxi 2" << endl; - createTaxi(false, 2, arr, radius, fltType, aircraftType, airline); + createTaxi(false, 2, arr, latitude, longitude, radius, fltType, aircraftType, airline); break; case 9: //cerr << "Creating Parking" << endl; @@ -161,7 +161,7 @@ void FGAIFlightPlan::createPushBack(bool firstFlight, FGAirport *dep, wpt->on_ground = true; waypoints.push_back(wpt); geo_direct_wgs_84 ( 0, lat, lon, heading, - 100, + radius, // push back one entire aircraft radius &lat2, &lon2, &az2 ); wpt = new waypoint; wpt->name = "taxiStart"; @@ -176,22 +176,14 @@ void FGAIFlightPlan::createPushBack(bool firstFlight, FGAirport *dep, wpt->on_ground = true; waypoints.push_back(wpt); - //wpt = new waypoint; - //wpt->name = "END"; - //wpt->finished = false; - //waypoints.push_back(wpt); // add one more to prevent a segfault. - //waypoints.push_back(wpt); // add one more to prevent a segfault. - //wpt_iterator = waypoints.begin(); - //if (!firstFlight) - // wpt_iterator++; - //wpt_iterator = waypoints.begin()+currWpt; + } /******************************************************************* * createCreate Taxi. * initialize the Aircraft at the parking location ******************************************************************/ -void FGAIFlightPlan::createTaxi(bool firstFlight, int direction, FGAirport *apt, double radius, string fltType, string acType, string airline) +void FGAIFlightPlan::createTaxi(bool firstFlight, int direction, FGAirport *apt, double latitude, double longitude, double radius, string fltType, string acType, string airline) { double wind_speed; double wind_heading; @@ -208,29 +200,13 @@ void FGAIFlightPlan::createTaxi(bool firstFlight, int direction, FGAirport *apt, //int currWpt = wpt_iterator - waypoints.begin(); if (direction == 1) { - - - - - // Get the current active runway, based on code from David Luff - // This should actually be unified and extended to include - // Preferential runway use schema's - //FGEnvironment - //stationweather = ((FGEnvironmentMgr *) globals->get_subsystem("environment")) - //->getEnvironment(apt->getLatitude(), apt->getLongitude(), apt->getElevation()); - - //wind_speed = stationweather.get_wind_speed_kt(); - //wind_heading = stationweather.get_wind_from_heading_deg(); - //if (wind_speed == 0) { - //wind_heading = 270; // This forces West-facing rwys to be used in no-wind situations - // which is consistent with Flightgear's initial setup. - //} - - //string rwy_no = globals->get_runways()->search(apt->getId(), int(wind_heading)); - string name; - apt->getActiveRunway("com", 1, &name); + //string name; + // "NOTE: this is currently fixed to "com" for commercial traffic + // Should be changed to be used dynamically to allow "gen" and "mil" + // as well + apt->getActiveRunway("com", 1, &activeRunway); if (!(globals->get_runways()->search(apt->getId(), - name, + activeRunway, &rwy))) { cout << "Failed to find runway for " << apt->getId() << endl; @@ -247,49 +223,137 @@ void FGAIFlightPlan::createTaxi(bool firstFlight, int direction, FGAirport *apt, geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth, rwy._length * SG_FEET_TO_METER * 0.5 - 5.0, &lat2, &lon2, &az2 ); - - //Add the runway startpoint; - wpt = new waypoint; - wpt->name = "Airport Center"; - wpt->latitude = apt->getLatitude(); - wpt->longitude = apt->getLongitude(); - wpt->altitude = apt->getElevation(); - wpt->speed = 15; - wpt->crossat = -10000; - wpt->gear_down = true; - wpt->flaps_down= true; - wpt->finished = false; - wpt->on_ground = true; - waypoints.push_back(wpt); - - //Add the runway startpoint; - wpt = new waypoint; - wpt->name = "Runway Takeoff"; - wpt->latitude = lat2; - wpt->longitude = lon2; - wpt->altitude = apt->getElevation(); - wpt->speed = 15; - wpt->crossat = -10000; - wpt->gear_down = true; - wpt->flaps_down= true; - wpt->finished = false; - wpt->on_ground = true; - waypoints.push_back(wpt); - //wpt = new waypoint; - //wpt->finished = false; - //waypoints.push_back(wpt); // add one more to prevent a segfault. + if (apt->getGroundNetwork()->exists()) + { + intVec ids; + int runwayId = apt->getGroundNetwork()->findNearestNode(lat2, lon2); + //int currId = apt->getGroundNetwork()->findNearestNode(latitude,longitude); + //exit(1); + + // A negative gateId indicates an overflow parking, use a + // fallback mechanism for this. + // Starting from gate 0 is a bit of a hack... + FGTaxiRoute route; + if (gateId >= 0) + route = apt->getGroundNetwork()->findShortestRoute(gateId, runwayId); + else + route = apt->getGroundNetwork()->findShortestRoute(0, runwayId); + intVecIterator i; + //cerr << "creating route : "; + // No route found: go from gate directly to runway + if (route.empty()) { + //Add the runway startpoint; + wpt = new waypoint; + wpt->name = "Airport Center"; + wpt->latitude = latitude; + wpt->longitude = longitude; + wpt->altitude = apt->getElevation(); + wpt->speed = 15; + wpt->crossat = -10000; + wpt->gear_down = true; + wpt->flaps_down= true; + wpt->finished = false; + wpt->on_ground = true; + waypoints.push_back(wpt); + + //Add the runway startpoint; + wpt = new waypoint; + wpt->name = "Runway Takeoff"; + wpt->latitude = lat2; + wpt->longitude = lon2; + wpt->altitude = apt->getElevation(); + wpt->speed = 15; + wpt->crossat = -10000; + wpt->gear_down = true; + wpt->flaps_down= true; + wpt->finished = false; + wpt->on_ground = true; + waypoints.push_back(wpt); + } else { + int node; + route.first(); + while(route.next(&node)) + { + //i = ids.end()-1; + //cerr << "Creating Node: " << node << endl; + FGTaxiNode *tn = apt->getGroundNetwork()->findNode(node); + //ids.pop_back(); + wpt = new waypoint; + wpt->name = "taxiway"; // fixme: should be the name of the taxiway + wpt->latitude = tn->getLatitude(); + wpt->longitude = tn->getLongitude(); + wpt->altitude = apt->getElevation(); // should maybe be tn->elev too + wpt->speed = 15; + wpt->crossat = -10000; + wpt->gear_down = true; + wpt->flaps_down= true; + wpt->finished = false; + wpt->on_ground = true; + waypoints.push_back(wpt); + } + cerr << endl; + } + //exit(1); + } + else + { + //Add the runway startpoint; + wpt = new waypoint; + wpt->name = "Airport Center"; + wpt->latitude = apt->getLatitude(); + wpt->longitude = apt->getLongitude(); + wpt->altitude = apt->getElevation(); + wpt->speed = 15; + wpt->crossat = -10000; + wpt->gear_down = true; + wpt->flaps_down= true; + wpt->finished = false; + wpt->on_ground = true; + waypoints.push_back(wpt); + + //Add the runway startpoint; + wpt = new waypoint; + wpt->name = "Runway Takeoff"; + wpt->latitude = lat2; + wpt->longitude = lon2; + wpt->altitude = apt->getElevation(); + wpt->speed = 15; + wpt->crossat = -10000; + wpt->gear_down = true; + wpt->flaps_down= true; + wpt->finished = false; + wpt->on_ground = true; + waypoints.push_back(wpt); + //wpt = new waypoint; + //wpt->finished = false; + //waypoints.push_back(wpt); // add one more to prevent a segfault. + } } - else + else // Landing taxi { - //direction = (rand() % 360); - //geo_direct_wgs_84 ( 0, arr->getLatitude(), arr->getLongitude(), direction, - //100, - //&lat2, &lon2, &az2 ); + //string name; + // "NOTE: this is currently fixed to "com" for commercial traffic + // Should be changed to be used dynamically to allow "gen" and "mil" + // as well + //apt->getActiveRunway("com", 1, &name); + //if (!(globals->get_runways()->search(apt->getId(), + // name, + // &rwy))) + //{// + //cout << "Failed to find runway for " << apt->getId() << endl; + // Hmm, how do we handle a potential error like this? + // exit(1); + // } + //string test; + //apt->getActiveRunway(string("com"), 1, &test); + //exit(1); - // This next statement really requires the flight plan to be - // split up into smaller sections, because - // gate assignments will typically not be known until minutes before - // landing, and certainly not at the start of a 10 hour flight. + //heading = rwy._heading; + //double azimuth = heading + 180.0; + //while ( azimuth >= 360.0 ) { azimuth -= 360.0; } + //geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth, + // rwy._length * SG_FEET_TO_METER * 0.5 - 5.0, + // &lat2, &lon2, &az2 ); apt->getAvailableParking(&lat, &lon, &heading, &gateId, radius, fltType, acType, airline); heading += 180.0; if (heading > 360) @@ -297,23 +361,105 @@ void FGAIFlightPlan::createTaxi(bool firstFlight, int direction, FGAirport *apt, geo_direct_wgs_84 ( 0, lat, lon, heading, 100, &lat2, &lon2, &az2 ); - //Add the runway center - wpt = new waypoint; - wpt->name = "Airport Center"; - wpt->latitude = apt->getLatitude(); - wpt->longitude = apt->getLongitude(); - wpt->altitude = apt->getElevation(); - wpt->speed = 15; - wpt->crossat = -10000; - wpt->gear_down = true; - wpt->flaps_down= true; - wpt->finished = false; - wpt->on_ground = true; - waypoints.push_back(wpt); + double lat3 = (*(waypoints.end()-1))->latitude; + double lon3 = (*(waypoints.end()-1))->longitude; + cerr << (*(waypoints.end()-1))->name << endl; + if (apt->getGroundNetwork()->exists()) + { + intVec ids; + int runwayId = apt->getGroundNetwork()->findNearestNode(lat3, lon3); + //int currId = apt->getGroundNetwork()->findNearestNode(latitude,longitude); + //exit(1); + + // A negative gateId indicates an overflow parking, use a + // fallback mechanism for this. + // Starting from gate 0 is a bit of a hack... + FGTaxiRoute route; + if (gateId >= 0) + route = apt->getGroundNetwork()->findShortestRoute(runwayId, gateId); + else + route = apt->getGroundNetwork()->findShortestRoute(runwayId, 0); + intVecIterator i; + //cerr << "creating route : "; + // No route found: go from gate directly to runway + if (route.empty()) { + //Add the runway startpoint; + wpt = new waypoint; + wpt->name = "Airport Center"; + wpt->latitude = latitude; + wpt->longitude = longitude; + wpt->altitude = apt->getElevation(); + wpt->speed = 15; + wpt->crossat = -10000; + wpt->gear_down = true; + wpt->flaps_down= true; + wpt->finished = false; + wpt->on_ground = true; + waypoints.push_back(wpt); + + //Add the runway startpoint; + wpt = new waypoint; + wpt->name = "Runway Takeoff"; + wpt->latitude = lat2; + wpt->longitude = lon2; + wpt->altitude = apt->getElevation(); + wpt->speed = 15; + wpt->crossat = -10000; + wpt->gear_down = true; + wpt->flaps_down= true; + wpt->finished = false; + wpt->on_ground = true; + waypoints.push_back(wpt); + } else { + int node; + route.first(); + while(route.next(&node)) + { + //i = ids.end()-1; + //cerr << "Creating Node: " << node << endl; + FGTaxiNode *tn = apt->getGroundNetwork()->findNode(node); + //ids.pop_back(); + wpt = new waypoint; + wpt->name = "taxiway"; // fixme: should be the name of the taxiway + wpt->latitude = tn->getLatitude(); + wpt->longitude = tn->getLongitude(); + wpt->altitude = apt->getElevation(); // should maybe be tn->elev too + wpt->speed = 15; + wpt->crossat = -10000; + wpt->gear_down = true; + wpt->flaps_down= true; + wpt->finished = false; + wpt->on_ground = true; + waypoints.push_back(wpt); + } + cerr << endl; + } + //exit(1); + } + else + { + //Add the runway startpoint; + wpt = new waypoint; + wpt->name = "Airport Center"; + wpt->latitude = apt->getLatitude(); + wpt->longitude = apt->getLongitude(); + wpt->altitude = apt->getElevation(); + wpt->speed = 15; + wpt->crossat = -10000; + wpt->gear_down = true; + wpt->flaps_down= true; + wpt->finished = false; + wpt->on_ground = true; + waypoints.push_back(wpt); + + } + + + // Add the final destination waypoint wpt = new waypoint; - wpt->name = "Begin Parkingg"; //apt->getId(); //wpt_node->getStringValue("name", "END"); + wpt->name = "Begin Parking"; //apt->getId(); //wpt_node->getStringValue("name", "END"); wpt->latitude = lat2; wpt->longitude = lon2; wpt->altitude = apt->getElevation(); @@ -364,10 +510,13 @@ void FGAIFlightPlan::createTakeOff(bool firstFlight, FGAirport *apt, double spee // Preferential runway use schema's if (firstFlight) { - string name; - apt->getActiveRunway("com", 1, &name); + //string name; + // "NOTE: this is currently fixed to "com" for commercial traffic + // Should be changed to be used dynamically to allow "gen" and "mil" + // as well + apt->getActiveRunway("com", 1, &activeRunway); if (!(globals->get_runways()->search(apt->getId(), - name, + activeRunway, &rwy))) { cout << "Failed to find runway for " << apt->getId() << endl; @@ -456,10 +605,13 @@ void FGAIFlightPlan::createClimb(bool firstFlight, FGAirport *apt, double speed, // Preferential runway use schema's if (firstFlight) { - string name; - apt->getActiveRunway("com", 1, &name); + //string name; + // "NOTE: this is currently fixed to "com" for commercial traffic + // Should be changed to be used dynamically to allow "gen" and "mil" + // as well + apt->getActiveRunway("com", 1, &activeRunway); if (!(globals->get_runways()->search(apt->getId(), - name, + activeRunway, &rwy))) { cout << "Failed to find runway for " << apt->getId() << endl; @@ -554,10 +706,11 @@ void FGAIFlightPlan::createCruise(bool firstFlight, FGAirport *dep, FGAirport *a waypoints.push_back(wpt); //Beginning of Decent - string name; - arr->getActiveRunway("com", 2, &name); + //string name; + // should be changed dynamically to allow "gen" and "mil" + arr->getActiveRunway("com", 2, &activeRunway); if (!(globals->get_runways()->search(arr->getId(), - name, + activeRunway, &rwy))) { cout << "Failed to find runway for " << arr->getId() << endl; @@ -632,10 +785,11 @@ void FGAIFlightPlan::createDecent(FGAirport *apt) //resetWaypoints(); //Beginning of Decent - string name; - apt->getActiveRunway("com", 2, &name); + //string name; + // allow "mil" and "gen" as well + apt->getActiveRunway("com", 2, &activeRunway); if (!(globals->get_runways()->search(apt->getId(), - name, + activeRunway, &rwy))) { cout << "Failed to find runway for " << apt->getId() << endl; diff --git a/src/Airports/simple.cxx b/src/Airports/simple.cxx index 4a9a8837c..e862af61e 100644 --- a/src/Airports/simple.cxx +++ b/src/Airports/simple.cxx @@ -37,6 +37,7 @@ #include #include +#include #include #include @@ -53,6 +54,7 @@ #include "simple.hxx" SG_USING_STD(sort); +SG_USING_STD(random_shuffle); /****************************************************************************** * ScheduleTime @@ -563,28 +565,10 @@ void FGRunwayPreference::error (const char * message, int line, int column) { << endl; } -/********************************************************************************* - * FGParking - ********************************************************************************/ -FGParking::FGParking(double lat, - double lon, - double hdg, - double rad, - int idx, - string name, - string tpe, - string codes) -{ - latitude = lat; - longitude = lon; - heading = hdg; - parkingName = name; - index = idx; - type = tpe; - airlineCodes = codes; -} - -double FGParking::processPosition(string pos) +/***************************************************************************** + * Helper function for parsing position string + ****************************************************************************/ +double processPosition(string pos) { string prefix; string subs; @@ -608,6 +592,29 @@ double FGParking::processPosition(string pos) return value; } + +/********************************************************************************* + * FGParking + ********************************************************************************/ +FGParking::FGParking(double lat, + double lon, + double hdg, + double rad, + int idx, + string name, + string tpe, + string codes) +{ + latitude = lat; + longitude = lon; + heading = hdg; + parkingName = name; + index = idx; + type = tpe; + airlineCodes = codes; +} + + /*************************************************************************** * FGAirport ***************************************************************************/ @@ -664,6 +671,22 @@ FGAirport::FGAirport(string id, double lon, double lat, double elev, string name } +// Initialization required after XMLRead +void FGAirport::init() +{ + // This may seem a bit weird to first randomly shuffle the parkings + // and then sort them again. However, parkings are sorted here by ascending + // radius. Since many parkings have similar radii, with each radius class they will + // still be allocated relatively systematically. Randomizing prior to sorting will + // prevent any initial orderings to be destroyed, leading (hopefully) to a more + // naturalistic gate assignment. + random_shuffle(parkings.begin(), parkings.end()); + sort(parkings.begin(), parkings.end()); + // add the gate positions to the ground network. + groundNetwork.addNodes(&parkings); + groundNetwork.init(); +} + bool FGAirport::getAvailableParking(double *lat, double *lon, double *heading, int *gateId, double rad, string flType, string acType, string airline) { bool found = false; @@ -893,6 +916,10 @@ void FGAirport::endXML () { void FGAirport::startElement (const char * name, const XMLAttributes &atts) { // const char *attval; FGParking park; + FGTaxiNode taxiNode; + FGTaxiSegment taxiSegment; + int index = 0; + taxiSegment.setIndex(index); //cout << "Start element " << name << endl; string attname; string value; @@ -932,9 +959,35 @@ void FGAirport::startElement (const char * name, const XMLAttributes &atts) { } park.setName((gateName+gateNumber)); parkings.push_back(park); - } + } + if (name == string("node")) + { + for (int i = 0; i < atts.size() ; i++) + { + attname = atts.getName(i); + if (attname == string("index")) + taxiNode.setIndex(atoi(atts.getValue(i))); + if (attname == string("lat")) + taxiNode.setLatitude(atts.getValue(i)); + if (attname == string("lon")) + taxiNode.setLongitude(atts.getValue(i)); + } + groundNetwork.addNode(taxiNode); + } + if (name == string("arc")) + { + taxiSegment.setIndex(++index); + for (int i = 0; i < atts.size() ; i++) + { + attname = atts.getName(i); + if (attname == string("begin")) + taxiSegment.setStartNodeRef(atoi(atts.getValue(i))); + if (attname == string("end")) + taxiSegment.setEndNodeRef(atoi(atts.getValue(i))); + } + groundNetwork.addSegment(taxiSegment); + } // sort by radius, in asending order, so that smaller gates are first in the list - sort(parkings.begin(), parkings.end()); } void FGAirport::endElement (const char * name) { @@ -1145,6 +1198,290 @@ void FGAirport::chooseRunwayFallback(string *runway) return; // generic fall back goes here } + + +/************************************************************************** + * FGTaxiNode + *************************************************************************/ +FGTaxiNode::FGTaxiNode() +{ +} + +/*************************************************************************** + * FGTaxiSegment + **************************************************************************/ +FGTaxiSegment::FGTaxiSegment() +{ +} + +void FGTaxiSegment::setStart(FGTaxiNodeVector *nodes) +{ + FGTaxiNodeVectorIterator i = nodes->begin(); + while (i != nodes->end()) + { + if (i->getIndex() == startNode) + { + start = i->getAddress(); + i->addSegment(this); + return; + } + i++; + } +} + +void FGTaxiSegment::setEnd(FGTaxiNodeVector *nodes) +{ + FGTaxiNodeVectorIterator i = nodes->begin(); + while (i != nodes->end()) + { + if (i->getIndex() == endNode) + { + end = i->getAddress(); + return; + } + i++; + } +} + +// There is probably a computationally cheaper way of +// doing this. +void FGTaxiSegment::setTrackDistance() +{ + double course; + SGWayPoint first (start->getLongitude(), + start->getLatitude(), + 0); + SGWayPoint second (end->getLongitude(), + end->getLatitude(), + 0); + first.CourseAndDistance(second, &course, &length); + +} + +bool FGTaxiRoute::next(int *val) +{ + //for (intVecIterator i = nodes.begin(); i != nodes.end(); i++) + // cerr << "FGTaxiRoute contains : " << *(i) << endl; + //cerr << "Offset from end: " << nodes.end() - currNode << endl; + //if (currNode != nodes.end()) + // cerr << "true" << endl; + //else + // cerr << "false" << endl; + + if (currNode == nodes.end()) + return false; + *val = *(currNode); + currNode++; + return true; +}; +/*************************************************************************** + * FGGroundNetwork() + **************************************************************************/ + +FGGroundNetwork::FGGroundNetwork() +{ + hasNetwork = false; +} + +void FGGroundNetwork::addSegment(FGTaxiSegment seg) +{ + segments.push_back(seg); +} + +void FGGroundNetwork::addNode(FGTaxiNode node) +{ + nodes.push_back(node); +} + +void FGGroundNetwork::addNodes(FGParkingVec *parkings) +{ + FGTaxiNode n; + FGParkingVecIterator i = parkings->begin(); + while (i != parkings->end()) + { + n.setIndex(i->getIndex()); + n.setLatitude(i->getLatitude()); + n.setLongitude(i->getLongitude()); + nodes.push_back(n); + + i++; + } +} + + + +void FGGroundNetwork::init() +{ + hasNetwork = true; + FGTaxiSegmentVectorIterator i = segments.begin(); + while(i != segments.end()) { + //cerr << "initializing node " << i->getIndex() << endl; + i->setStart(&nodes); + i->setEnd (&nodes); + i->setTrackDistance(); + //cerr << "Track distance = " << i->getLength() << endl; + //cerr << "Track ends at" << i->getEnd()->getIndex() << endl; + i++; + } + //exit(1); +} + +int FGGroundNetwork::findNearestNode(double lat, double lon) +{ + double minDist = HUGE; + double course, dist; + int index; + SGWayPoint first (lon, + lat, + 0); + + for (FGTaxiNodeVectorIterator + itr = nodes.begin(); + itr != nodes.end(); itr++) + { + double course; + SGWayPoint second (itr->getLongitude(), + itr->getLatitude(), + 0); + first.CourseAndDistance(second, &course, &dist); + if (dist < minDist) + { + minDist = dist; + index = itr->getIndex(); + //cerr << "Minimum distance of " << minDist << " for index " << index << endl; + } + } + return index; +} + +FGTaxiNode *FGGroundNetwork::findNode(int idx) +{ + for (FGTaxiNodeVectorIterator + itr = nodes.begin(); + itr != nodes.end(); itr++) + { + if (itr->getIndex() == idx) + return itr->getAddress(); + } + return 0; +} + +FGTaxiRoute FGGroundNetwork::findShortestRoute(int start, int end) +{ + foundRoute = false; + totalDistance = 0; + FGTaxiNode *firstNode = findNode(start); + FGTaxiNode *lastNode = findNode(end); + //prevNode = prevPrevNode = -1; + //prevNode = start; + routes.clear(); + traceStack.clear(); + trace(firstNode, end, 0, 0); + FGTaxiRoute empty; + + if (!foundRoute) + { + cerr << "Failed to find route from waypoint " << start << " to " << end << endl; + exit(1); + } + sort(routes.begin(), routes.end()); + //for (intVecIterator i = route.begin(); i != route.end(); i++) + // { + // rte->push_back(*i); + // } + + if (routes.begin() != routes.end()) + return *(routes.begin()); + else + return empty; +} + + +void FGGroundNetwork::trace(FGTaxiNode *currNode, int end, int depth, double distance) +{ + traceStack.push_back(currNode->getIndex()); + totalDistance += distance; + //cerr << "Starting trace " << depth << " total distance: " << totalDistance<< endl; + //<< currNode->getIndex() << endl; + + // If the current route matches the required end point we found a valid route + // So we can add this to the routing table + if (currNode->getIndex() == end) + { + //cerr << "Found route : " << totalDistance << "" << " " << *(traceStack.end()-1) << endl; + routes.push_back(FGTaxiRoute(traceStack,totalDistance)); + traceStack.pop_back(); + if (!(foundRoute)) + maxDistance = totalDistance; + else + if (totalDistance < maxDistance) + maxDistance = totalDistance; + foundRoute = true; + totalDistance -= distance; + return; + } + + + // search if the currentNode has been encountered before + // if so, we should step back one level, because it is + // rather rediculous to proceed further from here. + // if the current node has not been encountered before, + // i should point to traceStack.end()-1; and we can continue + // if i is not traceStack.end, the previous node was found, + // and we should return. + // This only works at trace levels of 1 or higher though + if (depth > 0) { + intVecIterator i = traceStack.begin(); + while ((*i) != currNode->getIndex()) { + //cerr << "Route so far : " << (*i) << endl; + i++; + } + if (i != traceStack.end()-1) { + traceStack.pop_back(); + totalDistance -= distance; + return; + } + // If the total distance from start to the current waypoint + // is longer than that of a route we can also stop this trace + // and go back one level. + if ((totalDistance > maxDistance) && foundRoute) + { + //cerr << "Stopping rediculously long trace: " << totalDistance << endl; + traceStack.pop_back(); + totalDistance -= distance; + return; + } + } + + //cerr << "2" << endl; + if (currNode->getBeginRoute() != currNode->getEndRoute()) + { + //cerr << "3" << endl; + for (FGTaxiSegmentPointerVectorIterator + i = currNode->getBeginRoute(); + i != currNode->getEndRoute(); + i++) + { + //cerr << (*i)->getLenght() << endl; + trace((*i)->getEnd(), end, depth+1, (*i)->getLength()); + // { + // // cerr << currNode -> getIndex() << " "; + // route.push_back(currNode->getIndex()); + // return true; + // } + } + } + else + { + cerr << "4" << endl; + } + traceStack.pop_back(); + totalDistance -= distance; + return; +} + + + /****************************************************************************** * FGAirportList *****************************************************************************/ @@ -1199,6 +1536,7 @@ void FGAirportList::add( const string id, const double longitude, { try { readXML(parkpath.str(),*a); + a->init(); } catch (const sg_exception &e) { //cerr << "unable to read " << parkpath.str() << endl; diff --git a/src/Airports/simple.hxx b/src/Airports/simple.hxx index 901cb06d1..eea3c0ede 100644 --- a/src/Airports/simple.hxx +++ b/src/Airports/simple.hxx @@ -36,7 +36,8 @@ #ifdef HAVE_CONFIG_H # include #endif - +#include +#include #include #include @@ -56,6 +57,8 @@ typedef vector::const_iterator stringVecConstIterator; typedef vector timeVec; typedef vector::const_iterator timeVecConstIterator; + + /***************************************************************************/ class ScheduleTime { private: @@ -177,6 +180,8 @@ public: virtual void error (const char * message, int line, int column); }; +double processPosition(string pos); + class FGParking { private: double latitude; @@ -188,10 +193,9 @@ private: string type; string airlineCodes; - bool available; - double processPosition(string pos); + public: FGParking() { available = true;}; @@ -232,7 +236,138 @@ typedef vector FGParkingVec; typedef vector::iterator FGParkingVecIterator; typedef vector::const_iterator FGParkingVecConstIterator; +class FGTaxiSegment; // forward reference + +typedef vector FGTaxiSegmentVector; +typedef vector FGTaxiSegmentPointerVector; +typedef vector::iterator FGTaxiSegmentVectorIterator; +typedef vector::iterator FGTaxiSegmentPointerVectorIterator; + +/************************************************************************************** + * class FGTaxiNode + *************************************************************************************/ +class FGTaxiNode +{ +private: + double lat; + double lon; + int index; + FGTaxiSegmentPointerVector next; // a vector to all the segments leaving from this node + +public: + FGTaxiNode(); + FGTaxiNode(double, double, int); + + void setIndex(int idx) { index = idx;}; + void setLatitude (double val) { lat = val;}; + void setLongitude(double val) { lon = val;}; + void setLatitude (string val) { lat = processPosition(val); }; + void setLongitude(string val) { lon = processPosition(val); }; + void addSegment(FGTaxiSegment *segment) { next.push_back(segment); }; + + double getLatitude() { return lat;}; + double getLongitude(){ return lon;}; + + int getIndex() { return index; }; + FGTaxiNode *getAddress() { return this;}; + FGTaxiSegmentPointerVectorIterator getBeginRoute() { return next.begin(); }; + FGTaxiSegmentPointerVectorIterator getEndRoute() { return next.end(); }; +}; + +typedef vector FGTaxiNodeVector; +typedef vector::iterator FGTaxiNodeVectorIterator; + +/*************************************************************************************** + * class FGTaxiSegment + **************************************************************************************/ +class FGTaxiSegment +{ +private: + int startNode; + int endNode; + double length; + FGTaxiNode *start; + FGTaxiNode *end; + int index; + +public: + FGTaxiSegment(); + FGTaxiSegment(FGTaxiNode *, FGTaxiNode *, int); + + void setIndex (int val) { index = val; }; + void setStartNodeRef (int val) { startNode = val; }; + void setEndNodeRef (int val) { endNode = val; }; + void setStart(FGTaxiNodeVector *nodes); + void setEnd (FGTaxiNodeVector *nodes); + void setTrackDistance(); + + FGTaxiNode * getEnd() { return end;}; + double getLength() { return length; }; + int getIndex() { return index; }; + + +}; + + +typedef vector intVec; +typedef vector::iterator intVecIterator; + +class FGTaxiRoute +{ +private: + intVec nodes; + double distance; + intVecIterator currNode; + +public: + FGTaxiRoute() { distance = 0; currNode = nodes.begin(); }; + FGTaxiRoute(intVec nds, double dist) { nodes = nds; distance = dist; currNode = nodes.begin();}; + bool operator< (const FGTaxiRoute &other) const {return distance < other.distance; }; + bool empty () { return nodes.begin() == nodes.end(); }; + bool next(int *val); + + void first() { currNode = nodes.begin(); }; +}; + +typedef vector TaxiRouteVector; +typedef vector::iterator TaxiRouteVectorIterator; + +/************************************************************************************** + * class FGGroundNetWork + *************************************************************************************/ +class FGGroundNetwork +{ +private: + bool hasNetwork; + FGTaxiNodeVector nodes; + FGTaxiSegmentVector segments; + //intVec route; + intVec traceStack; + TaxiRouteVector routes; + + bool foundRoute; + double totalDistance, maxDistance; + +public: + FGGroundNetwork(); + + void addNode (FGTaxiNode node); + void addNodes (FGParkingVec *parkings); + void addSegment(FGTaxiSegment seg); + + void init(); + bool exists() { return hasNetwork; }; + int findNearestNode(double lat, double lon); + FGTaxiNode *findNode(int idx); + FGTaxiRoute findShortestRoute(int start, int end); + void trace(FGTaxiNode *, int, int, double dist); + +}; + +/*************************************************************************************** + * + **************************************************************************************/ class FGAirport : public XMLVisitor{ private: string _id; @@ -244,6 +379,7 @@ private: bool _has_metar; FGParkingVec parkings; FGRunwayPreference rwyPrefs; + FGGroundNetwork groundNetwork; time_t lastUpdate; string prevTrafficType; @@ -262,6 +398,8 @@ public: FGAirport(const FGAirport &other); //operator= (FGAirport &other); FGAirport(string id, double lon, double lat, double elev, string name, bool has_metar); + + void init(); void getActiveRunway(string trafficType, int action, string *runway); void chooseRunwayFallback(string *runway); bool getAvailableParking(double *lat, double *lon, double *heading, int *gate, double rad, string fltype, @@ -272,6 +410,8 @@ public: string getParkingName(int i); string getId() const { return _id;}; const string &getName() const { return _name;}; + //FGAirport *getAddress() { return this; }; + //const string &getName() const { return _name;}; // Returns degrees double getLongitude() const { return _longitude;}; // Returns degrees @@ -279,6 +419,7 @@ public: // Returns ft double getElevation() const { return _elevation;}; bool getMetar() const { return _has_metar;}; + FGGroundNetwork* getGroundNetwork() { return &groundNetwork; }; void setId(string id) { _id = id;}; @@ -325,7 +466,7 @@ public: const double elevation, const string name, const bool has_metar ); // search for the specified id. - // Returns NULL if unsucessfull. + // Returns NULL if unsucessfull. FGAirport* search( const string& id ); // Search for the next airport in ASCII sequence to the supplied id. diff --git a/src/Traffic/Schedule.cxx b/src/Traffic/Schedule.cxx index 6af4287f1..6dfe218da 100644 --- a/src/Traffic/Schedule.cxx +++ b/src/Traffic/Schedule.cxx @@ -392,9 +392,15 @@ bool FGAISchedule::update(time_t now) return true; } } - + //cerr << "Traffic schedule got to beyond last clause" << endl; // EMH: prevent a warning, should this be 'true' instead? - return false; + // DT: YES. Originally, this code couldn't be reached, but + // when the "if(!(AIManagerManager))" clause is false we + // fall through right to the end. This is a valid flow. + // the actual value is pretty innocent, only it triggers + // warning in TrafficManager::update(). + // (which was added as a sanity check for myself in the first place. :-) + return true; } -- 2.39.5