From da3c098a4bb9c5c4b16d2ae286ee0183271374cf Mon Sep 17 00:00:00 2001 From: Durk Talsma Date: Sun, 9 Oct 2011 23:44:42 +0200 Subject: [PATCH] AITraffic exits the runway as soon as possible (in theory; the code still needs some fine tuning). --- src/AIModel/AIAircraft.cxx | 18 ++++++-- src/AIModel/AIFlightPlan.cxx | 19 +++++++- src/AIModel/AIFlightPlan.hxx | 3 ++ src/AIModel/AIFlightPlanCreate.cxx | 70 ++++++++++++++++++++++++++---- src/AIModel/performancedata.hxx | 1 + src/Airports/dynamicloader.cxx | 4 ++ src/Airports/groundnetwork.cxx | 23 ++++++++++ src/Airports/groundnetwork.hxx | 6 +++ src/Traffic/Schedule.cxx | 22 +++++++++- src/Traffic/Schedule.hxx | 1 + 10 files changed, 151 insertions(+), 16 deletions(-) diff --git a/src/AIModel/AIAircraft.cxx b/src/AIModel/AIAircraft.cxx index efb346a6b..0b23e2c06 100644 --- a/src/AIModel/AIAircraft.cxx +++ b/src/AIModel/AIAircraft.cxx @@ -805,7 +805,7 @@ bool FGAIAircraft::leadPointReached(FGAIWaypoint* curr) { // << lead_dist << " " << curr->name // << " Ground target speed " << groundTargetSpeed << endl; double bearing = 0; - if (speed > 50) { // don't do bearing calculations for ground traffic + // don't do bearing calculations for ground traffic bearing = getBearing(fp->getBearing(pos.getLatitudeDeg(), pos.getLongitudeDeg(), curr)); if (bearing < minBearing) { minBearing = bearing; @@ -817,8 +817,7 @@ bool FGAIAircraft::leadPointReached(FGAIWaypoint* curr) { } else { speedFraction = 1.0; } - } - } + } if (trafficRef) { //cerr << "Tracking callsign : \"" << fgGetString("/ai/track-callsign") << "\"" << endl; /* if (trafficRef->getCallSign() == fgGetString("/ai/track-callsign")) { @@ -826,11 +825,14 @@ bool FGAIAircraft::leadPointReached(FGAIWaypoint* curr) { << _getAltitude() << " "<< _getLatitude() << " " << _getLongitude() << " " << dist_to_go << " " << lead_dist << " " << curr->name << " " << vs << " " << tgt_vs << " " << bearing << " " << minBearing << " " << speedFraction << endl; }*/ } - if ((dist_to_go < lead_dist) || (bearing > (minBearing * 1.1))) { + if ((dist_to_go < lead_dist) || + ((dist_to_go > prev_dist_to_go) && (bearing > (minBearing * 1.1))) ) { minBearing = 360; speedFraction = 1.0; + prev_dist_to_go = HUGE_VAL; return true; } else { + prev_dist_to_go = dist_to_go; return false; } } @@ -880,6 +882,11 @@ bool FGAIAircraft::handleAirportEndPoints(FGAIWaypoint* prev, time_t now) { if (prev->contains(string("Accel"))) { takeOffStatus = 3; } + //if (prev->contains(string("landing"))) { + // if (speed < _performance->vTaxi() * 2) { + // fp->shortenToFirst(2, "legend"); + // } + //} /*if (prev->contains(string("final"))) { cerr << getCallSign() << " " @@ -1114,6 +1121,9 @@ void FGAIAircraft::updateHeading() { // << hdg << ". Target " << tgt_heading << ". Diff " << fabs(sum - tgt_heading) << ". Speed " << speed << "Heading change rate : " << headingChangeRate << " bacnk sence " << bank_sense << endl; hdg += headingChangeRate * dt * sqrt(fabs(speed) / 15); headingError = headingDiff; + if (fabs(headingError) < 1.0) { + hdg = tgt_heading; + } } else { if (fabs(speed) > 1.0) { turn_radius_ft = 0.088362 * speed * speed diff --git a/src/AIModel/AIFlightPlan.cxx b/src/AIModel/AIFlightPlan.cxx index fd639f787..a0487c273 100644 --- a/src/AIModel/AIFlightPlan.cxx +++ b/src/AIModel/AIFlightPlan.cxx @@ -409,10 +409,19 @@ void FGAIFlightPlan::DecrementWaypoint(bool eraseWaypoints ) } else wpt_iterator--; +} +void FGAIFlightPlan::eraseLastWaypoint() +{ + delete (waypoints.back()); + waypoints.pop_back();; + wpt_iterator = waypoints.begin(); + wpt_iterator++; } + + // gives distance in feet from a position to a waypoint double FGAIFlightPlan::getDistanceToGo(double lat, double lon, FGAIWaypoint* wp) const{ return SGGeodesy::distanceM(SGGeod::fromDeg(lon, lat), @@ -545,4 +554,12 @@ double FGAIFlightPlan::checkTrackLength(string wptName) { trackDistance = 0; // name not found } return trackDistance; -} \ No newline at end of file +} + +void FGAIFlightPlan::shortenToFirst(unsigned int number, string name) +{ + while (waypoints.size() > number + 3) { + eraseLastWaypoint(); + } + (waypoints.back())->setName((waypoints.back())->getName() + name); +} diff --git a/src/AIModel/AIFlightPlan.hxx b/src/AIModel/AIFlightPlan.hxx index 1b95cad47..0ab27c2c0 100644 --- a/src/AIModel/AIFlightPlan.hxx +++ b/src/AIModel/AIFlightPlan.hxx @@ -164,6 +164,8 @@ public: FGAIFlightPlan* getSID() { return sid; }; FGAIWaypoint *getWayPoint(int i) { return waypoints[i]; }; FGAIWaypoint *getLastWaypoint() { return waypoints.back(); }; + + void shortenToFirst(unsigned int number, std::string name); private: FGAIFlightPlan *sid; @@ -195,6 +197,7 @@ private: bool createParking(FGAIAircraft *, FGAirport *, double radius); void deleteWaypoints(); void resetWaypoints(); + void eraseLastWaypoint(); bool createLandingTaxi(FGAIAircraft *, FGAirport *apt, double radius, const std::string& fltType, const std::string& acType, const std::string& airline); void createDefaultLandingTaxi(FGAIAircraft *, FGAirport* aAirport); diff --git a/src/AIModel/AIFlightPlanCreate.cxx b/src/AIModel/AIFlightPlanCreate.cxx index edeff639f..215d3fb17 100644 --- a/src/AIModel/AIFlightPlanCreate.cxx +++ b/src/AIModel/AIFlightPlanCreate.cxx @@ -36,6 +36,7 @@ #include #include +#include /* FGAIFlightPlan::create() @@ -242,7 +243,12 @@ bool FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft * ac, bool firstFlight, } intVec ids; - int runwayId = gn->findNearestNode(runwayTakeoff); + int runwayId = 0; + if (gn->getVersion() > 0) { + runwayId = gn->findNearestNodeOnRunway(runwayTakeoff); + } else { + runwayId = gn->findNearestNode(runwayTakeoff); + } // A negative gateId indicates an overflow parking, use a // fallback mechanism for this. @@ -379,7 +385,13 @@ bool FGAIFlightPlan::createLandingTaxi(FGAIAircraft * ac, FGAirport * apt, } intVec ids; - int runwayId = gn->findNearestNode(lastWptPos); + int runwayId = 0; + if (gn->getVersion() == 1) { + runwayId = gn->findNearestNodeOnRunway(lastWptPos); + } else { + runwayId = gn->findNearestNode(lastWptPos); + } + //cerr << "Using network node " << runwayId << endl; // A negative gateId indicates an overflow parking, use a // fallback mechanism for this. // Starting from gate 0 is a bit of a hack... @@ -878,7 +890,12 @@ bool FGAIFlightPlan::createLanding(FGAIAircraft * ac, FGAirport * apt, const string & fltType) { double vTouchdown = ac->getPerformance()->vTouchdown(); - //double vTaxi = ac->getPerformance()->vTaxi(); + double vTaxi = ac->getPerformance()->vTaxi(); + double decel = ac->getPerformance()->deceleration() * 1.5; + + double vTouchdownMetric = (vTouchdown * SG_NM_TO_METER) / 3600; + double vTaxiMetric = (vTaxi * SG_NM_TO_METER) / 3600; + double decelMetric = (decel * SG_NM_TO_METER) / 3600; //string rwyClass = getRunwayClassFromTrafficType(fltType); //double heading = ac->getTrafficRef()->getCourse(); @@ -917,15 +934,50 @@ bool FGAIFlightPlan::createLanding(FGAIAircraft * ac, FGAirport * apt, coord = rwy->pointOnCenterline((currentDist * (i / nPoints))); wpt = createInAir(ac, buffer, coord, currentAltitude, (vTouchdown)); }*/ - - for (int i = 1; i < 10; i++) { - snprintf(buffer, 12, "wpt%d", i); + double rolloutDistance = + (vTouchdownMetric * vTouchdownMetric - vTaxiMetric * vTaxiMetric) / (2 * decelMetric); + //cerr << " touchdown speed = " << vTouchdown << ". Rollout distance " << rolloutDistance << endl; + int nPoints = 50; + for (int i = 1; i < nPoints; i++) { + snprintf(buffer, 12, "landing03%d", i); - coord = rwy->pointOnCenterline((rwy->lengthM() * 0.9) * (i / 10.0)); - wpt = createOnGround(ac, buffer, coord, currElev, (vTouchdown / i)); - wpt->setCrossat(apt->getElevation()); + coord = rwy->pointOnCenterline((rolloutDistance * ((double) i / (double) nPoints))); + wpt = createOnGround(ac, buffer, coord, currElev, vTaxi); + wpt->setCrossat(currElev); waypoints.push_back(wpt); } + double mindist = 1.1 * rolloutDistance; + double maxdist = rwy->lengthM(); + //cerr << "Finding nearest exit" << endl; + FGGroundNetwork *gn = apt->getDynamics()->getGroundNetwork(); + if (gn) { + double min = 0; + for (int i = ceil(mindist); i < floor(maxdist); i++) { + coord = rwy->pointOnCenterline(mindist); + int nodeId = 0; + if (gn->getVersion() > 0) { + nodeId = gn->findNearestNodeOnRunway(coord); + } else { + nodeId = gn->findNearestNode(coord); + } + if (tn) + tn = gn->findNode(nodeId); + else { + break; + } + + double dist = SGGeodesy::distanceM(coord, tn->getGeod()); + if (dist < (min + 0.75)) { + break; + } + min = dist; + } + if (tn) { + wpt = createOnGround(ac, buffer, tn->getGeod(), currElev, vTaxi); + waypoints.push_back(wpt); + } + } + cerr << "Done. " << endl; /* //Runway Threshold diff --git a/src/AIModel/performancedata.hxx b/src/AIModel/performancedata.hxx index d18e24b86..a966b5776 100644 --- a/src/AIModel/performancedata.hxx +++ b/src/AIModel/performancedata.hxx @@ -43,6 +43,7 @@ public: inline double vRotate () { return _vRotate; }; inline double maximumBankAngle () { return _maxbank; }; inline double acceleration () { return _acceleration; }; + inline double deceleration () { return _deceleration; }; inline double vTaxi () { return _vTaxi; }; inline double vTakeoff () { return _vTakeOff; }; inline double vClimb () { return _vClimb; }; diff --git a/src/Airports/dynamicloader.cxx b/src/Airports/dynamicloader.cxx index 7da29ae73..26af2b711 100644 --- a/src/Airports/dynamicloader.cxx +++ b/src/Airports/dynamicloader.cxx @@ -146,6 +146,10 @@ void FGAirportDynamicsXMLLoader::startElement (const char * name, const XMLAttr void FGAirportDynamicsXMLLoader::endElement (const char * name) { //cout << "End element " << name << endl; + if (name == string("version")) { + _dynamics->getGroundNetwork()->addVersion(atoi(value.c_str())); + //std::cerr << "version" << value<< std::endl; + } if (name == string("AWOS")) { _dynamics->addAwosFreq(atoi(value.c_str())); //cerr << "Adding AWOS" << value<< endl; diff --git a/src/Airports/groundnetwork.cxx b/src/Airports/groundnetwork.cxx index 12faa8515..a3a3245fe 100644 --- a/src/Airports/groundnetwork.cxx +++ b/src/Airports/groundnetwork.cxx @@ -220,6 +220,7 @@ FGGroundNetwork::FGGroundNetwork() count = 0; currTraffic = activeTraffic.begin(); group = 0; + version = 0; networkInitialized = false; } @@ -452,6 +453,28 @@ int FGGroundNetwork::findNearestNode(const SGGeod & aGeod) return index; } +int FGGroundNetwork::findNearestNodeOnRunway(const SGGeod & aGeod) +{ + double minDist = HUGE_VAL; + int index = -1; + + for (FGTaxiNodeVectorIterator itr = nodes.begin(); itr != nodes.end(); + itr++) { + if (!((*itr)->getIsOnRunway())) { + continue; + } + double d = SGGeodesy::distanceM(aGeod, (*itr)->getGeod()); + if (d < minDist) { + minDist = d; + index = (*itr)->getIndex(); + //cerr << "Minimum distance of " << minDist << " for index " << index << endl; + } + } + + return index; +} + + int FGGroundNetwork::findNearestNode(double lat, double lon) { return findNearestNode(SGGeod::fromDeg(lon, lat)); diff --git a/src/Airports/groundnetwork.hxx b/src/Airports/groundnetwork.hxx index cec19d38b..c80829a3b 100644 --- a/src/Airports/groundnetwork.hxx +++ b/src/Airports/groundnetwork.hxx @@ -292,6 +292,7 @@ private: time_t nextSave; //int maxDepth; int count; + int version; FGTaxiNodeVector nodes; FGTaxiNodeVector pushBackNodes; FGTaxiSegmentVector segments; @@ -324,6 +325,9 @@ public: void addNode (const FGTaxiNode& node); void addNodes (FGParkingVec *parkings); void addSegment(const FGTaxiSegment& seg); + void setVersion (int v) { version = v;}; + + int getVersion() { return version; }; void init(); bool exists() { @@ -335,6 +339,7 @@ public: int findNearestNode(double lat, double lon); int findNearestNode(const SGGeod& aGeod); + int findNearestNodeOnRunway(const SGGeod& aGeod); FGTaxiNode *findNode(unsigned idx); FGTaxiSegment *findSegment(unsigned idx); @@ -365,6 +370,7 @@ public: virtual void update(double dt); void saveElevationCache(); + void addVersion(int v) {version = v; }; }; diff --git a/src/Traffic/Schedule.cxx b/src/Traffic/Schedule.cxx index 235154385..1af0ca112 100644 --- a/src/Traffic/Schedule.cxx +++ b/src/Traffic/Schedule.cxx @@ -423,7 +423,7 @@ void FGAISchedule::scheduleFlights(time_t now) << " " << arrT << ":"); flights.push_back(flight); - } while (1); //(currentDestination != startingPort); + } while (currentDestination != startingPort); SG_LOG(SG_GENERAL, SG_BULK, " Done "); } @@ -507,7 +507,8 @@ FGScheduledFlight* FGAISchedule::findAvailableFlight (const string ¤tDesti } if (flights.size()) { time_t arrival = flights.back()->getArrivalTime(); - if ((*i)->getDepartureTime() < (arrival+(20*60))) + int groundTime = groundTimeFromRadius(); + if ((*i)->getDepartureTime() < (arrival+(groundTime))) continue; } if (min != 0) { @@ -531,6 +532,23 @@ FGScheduledFlight* FGAISchedule::findAvailableFlight (const string ¤tDesti return NULL; } +int FGAISchedule::groundTimeFromRadius() +{ + if (radius < 10) + return 15 * 60; + else if (radius < 15) + return 20 * 60; + else if (radius < 20) + return 30 * 60; + else if (radius < 25) + return 50 * 60; + else if (radius < 30) + return 90 * 60; + else + return 120 * 60; +} + + double FGAISchedule::getSpeed() { FGScheduledFlightVecIterator i = flights.begin(); diff --git a/src/Traffic/Schedule.hxx b/src/Traffic/Schedule.hxx index 27385ed0d..e41334e6b 100644 --- a/src/Traffic/Schedule.hxx +++ b/src/Traffic/Schedule.hxx @@ -63,6 +63,7 @@ class FGAISchedule bool valid; void scheduleFlights(time_t now); + int groundTimeFromRadius(); /** * Transition this schedule from distant mode to AI mode; -- 2.39.5