From 5bc15d7a69813e97a7146742e3b2aa2d784eab73 Mon Sep 17 00:00:00 2001 From: ehofman Date: Thu, 10 Feb 2005 09:01:51 +0000 Subject: [PATCH] Durk Talsma: I just heard from John Wojnaroski that you and he are going to work on getting a flightgear demo machine up for the linux expo thursday and Friday. John indicated that he would very much like to get a CVS version with the new traffic code up and running before the expo. --- src/AIModel/AIAircraft.cxx | 729 +++++++++++++--- src/AIModel/AIAircraft.hxx | 20 +- src/AIModel/AIBase.hxx | 5 +- src/AIModel/AIFlightPlan.cxx | 544 ++++-------- src/AIModel/AIFlightPlan.hxx | 35 +- src/AIModel/AIFlightPlanCreate.cxx | 822 ++++++++++++++++++ src/AIModel/AIManager.cxx | 2 + src/AIModel/Makefile.am | 2 +- src/ATC/AIMgr.cxx | 2 +- src/ATC/ATCDialog.cxx | 2 +- src/ATC/ATCmgr.cxx | 12 +- src/ATC/ATCutils.cxx | 10 +- src/ATC/commlist.cxx | 2 +- src/Airports/apt_loader.cxx | 4 +- src/Airports/simple.cxx | 1170 +++++++++++++++++++++++++- src/Airports/simple.hxx | 254 +++++- src/Autopilot/auto_gui.cxx | 2 +- src/Environment/environment_ctrl.cxx | 20 +- src/GUI/AirportList.cxx | 6 +- src/GUI/Makefile.am | 2 +- src/Instrumentation/gps.cxx | 26 +- src/Main/fg_init.cxx | 22 +- src/Navaids/navdb.cxx | 4 +- src/Traffic/SchedFlight.cxx | 38 +- src/Traffic/SchedFlight.hxx | 11 +- src/Traffic/Schedule.cxx | 209 ++++- src/Traffic/Schedule.hxx | 31 +- src/Traffic/TrafficMgr.cxx | 68 +- src/Traffic/TrafficMgr.hxx | 5 +- 29 files changed, 3436 insertions(+), 623 deletions(-) create mode 100644 src/AIModel/AIFlightPlanCreate.cxx diff --git a/src/AIModel/AIAircraft.cxx b/src/AIModel/AIAircraft.cxx index 4dc084bcc..da2159b21 100644 --- a/src/AIModel/AIAircraft.cxx +++ b/src/AIModel/AIAircraft.cxx @@ -23,9 +23,13 @@ #endif #include +#include #include
#include
+#include
#include +#include + #include #include #include @@ -33,7 +37,7 @@ SG_USING_STD(string); #include "AIAircraft.hxx" - + static string tempReg; // // accel, decel, climb_rate, descent_rate, takeoff_speed, climb_speed, // cruise_speed, descent_speed, land_speed @@ -54,17 +58,24 @@ const FGAIAircraft::PERF_STRUCT FGAIAircraft::settings[] = { FGAIAircraft::FGAIAircraft(FGAIManager* mgr, FGAISchedule *ref) { trafficRef = ref; + if (trafficRef) + groundOffset = trafficRef->getGroundOffset(); + else + groundOffset = 0; manager = mgr; _type_str = "aircraft"; _otype = otAircraft; fp = 0; dt_count = 0; + dt_elev_count = 0; use_perf_vs = true; isTanker = false; // set heading and altitude locks hdg_lock = false; alt_lock = false; + roll = 0; + headingChangeRate = 0.0; } @@ -118,13 +129,24 @@ void FGAIAircraft::Run(double dt) { if (fp) { - ProcessFlightPlan(dt); time_t now = time(NULL) + fgGetLong("/sim/time/warp"); + ProcessFlightPlan(dt, now); if (now < fp->getStartTime()) - return; - //ProcessFlightPlan(dt); + { + // Do execute Ground elev for inactive aircraft, so they + // Are repositioned to the correct ground altitude when the user flies within visibility range. + if (no_roll) + { + Transform(); // make sure aip is initialized. + getGroundElev(dt); // make sure it's exectuted first time around, so force a large dt value + //getGroundElev(dt); // Need to do this twice. + //cerr << trafficRef->getRegistration() << " Setting altitude to " << tgt_altitude << endl; + setAltitude(tgt_altitude); + } + return; + } } - + double turn_radius_ft; double turn_circum_ft; double speed_north_deg_sec; @@ -133,11 +155,19 @@ void FGAIAircraft::Run(double dt) { double alpha; // adjust speed - double speed_diff = tgt_speed - speed; + double speed_diff; //= tgt_speed - speed; + if (!no_roll) + { + speed_diff = tgt_speed - speed; + } + else + { + speed_diff = groundTargetSpeed - speed; + } if (fabs(speed_diff) > 0.2) { if (speed_diff > 0.0) speed += performance->accel * dt; if (speed_diff < 0.0) { - if (!no_roll) { + if (no_roll) { // was (!no_roll) but seems more logical this way (ground brakes). speed -= performance->decel * dt * 3; } else { speed -= performance->decel * dt; @@ -154,19 +184,98 @@ void FGAIAircraft::Run(double dt) { // set new position pos.setlat( pos.lat() + speed_north_deg_sec * dt); pos.setlon( pos.lon() + speed_east_deg_sec * dt); + //if (!(finite(pos.lat()) && finite(pos.lon()))) + // { + // cerr << "Position is not finite" << endl; + // cerr << "speed = " << speed << endl; + // cerr << "dt" << dt << endl; + // cerr << "heading " << hdg << endl; + // cerr << "speed east " << speed_east_deg_sec << endl; + // cerr << "speed nrth " << speed_north_deg_sec << endl; + // cerr << "deg_lat " << ft_per_deg_lat << endl; + // cerr << "deg_lon " << ft_per_deg_lon << endl; + // } // adjust heading based on current bank angle + if (roll == 0.0) + roll = 0.01; if (roll != 0.0) { - turn_radius_ft = 0.088362 * speed * speed - / tan( fabs(roll) / SG_RADIANS_TO_DEGREES ); - turn_circum_ft = SGD_2PI * turn_radius_ft; - dist_covered_ft = speed * 1.686 * dt; - alpha = dist_covered_ft / turn_circum_ft * 360.0; - hdg += alpha * sign( roll ); - if ( hdg > 360.0 ) hdg -= 360.0; - if ( hdg < 0.0) hdg += 360.0; + // double turnConstant; + //if (no_roll) + // turnConstant = 0.0088362; + //else + // turnConstant = 0.088362; + // If on ground, calculate heading change directly + if (no_roll) { + double headingDiff = fabs(hdg-tgt_heading); + + if (headingDiff > 180) + headingDiff = fabs(headingDiff - 360); + groundTargetSpeed = tgt_speed - (tgt_speed * (headingDiff/45)); + if (sign(groundTargetSpeed) != sign(tgt_speed)) + groundTargetSpeed = 0.21 * sign(tgt_speed); // to prevent speed getting stuck in 'negative' mode + if (headingDiff > 30.0) + { + + headingChangeRate += dt * sign(roll); // invert if pushed backward + // Print some debug statements to find out why aircraft may get stuck + // forever turning + //if (trafficRef->getDepartureAirport()->getId() == string("EHAM")) + // { + //cerr << "Turning : " << trafficRef->getRegistration() + //cerr << " Speed = " << speed << " Heading " << hdg + //<< " Target Heading " << tgt_heading + // << " Lead Distance " << fp->getLeadDistance() + // << " Distance to go " + // << fp->getDistanceToGo(pos.lat(), pos.lon(), fp->getCurrentWaypoint()) + // << "waypoint name " << fp->getCurrentWaypoint()->name + // << endl; + //} + if (headingChangeRate > 30) + { + headingChangeRate = 30; + } + else if (headingChangeRate < -30) + { + headingChangeRate = -30; + } + } + else + { + if (fabs(headingChangeRate) > headingDiff) + headingChangeRate = headingDiff*sign(roll); + else + headingChangeRate += dt * sign(roll); + } + hdg += headingChangeRate * dt; + //cerr << "On ground. Heading: " << hdg << ". Target Heading: " << tgt_heading << ". Target speed: " << groundTargetSpeed << ". heading change rate" << headingChangeRate << endl; + } + else { + if (fabs(speed) > 1.0) { + turn_radius_ft = 0.088362 * speed * speed + / tan( fabs(roll) / SG_RADIANS_TO_DEGREES ); + } + else + { + turn_radius_ft = 1.0; // Check if turn_radius_ft == 0; this might lead to a division by 0. + } + turn_circum_ft = SGD_2PI * turn_radius_ft; + dist_covered_ft = speed * 1.686 * dt; + alpha = dist_covered_ft / turn_circum_ft * 360.0; + hdg += alpha * sign(roll); + } + while ( hdg > 360.0 ) { + hdg -= 360.0; + spinCounter++; + } + while ( hdg < 0.0) + { + hdg += 360.0; + spinCounter--; + } } - + + // adjust target bank angle if heading lock engaged if (hdg_lock) { double bank_sense = 0.0; @@ -174,7 +283,7 @@ void FGAIAircraft::Run(double dt) { if (diff > 180) diff = fabs(diff - 360); double sum = hdg + diff; if (sum > 360.0) sum -= 360.0; - if (fabs(sum - tgt_heading) < 1.0) { + if (fabs(sum - tgt_heading) < 1.0) { bank_sense = 1.0; // right turn } else { bank_sense = -1.0; // left turn @@ -184,6 +293,27 @@ void FGAIAircraft::Run(double dt) { } else { tgt_roll = 30.0 * bank_sense; } + if ((fabs((double) spinCounter) > 1) && (diff > 30)) + { + tgt_speed *= 0.999; // Ugly hack: If aircraft get stuck, they will continually spin around. + // The only way to resolve this is to make them slow down. + //if (tempReg.empty()) + // tempReg = trafficRef->getRegistration(); + //if (trafficRef->getRegistration() == tempReg) + // { + // cerr << trafficRef->getRegistration() + // << " appears to be spinning: " << spinCounter << endl + // << " speed " << speed << endl + // << " heading " << hdg << endl + // << " lead distance " << fp->getLeadDistance() << endl + // << " waypoint " << fp->getCurrentWaypoint()->name + // << " target heading " << tgt_heading << endl + // << " lead in angle " << fp->getLeadInAngle()<< endl + // << " roll " << roll << endl + // << " target_roll " << tgt_roll << endl; + + // } + } } // adjust bank angle, use 9 degrees per second @@ -191,6 +321,8 @@ void FGAIAircraft::Run(double dt) { if (fabs(bank_diff) > 0.2) { if (bank_diff > 0.0) roll += 9.0 * dt; if (bank_diff < 0.0) roll -= 9.0 * dt; + //while (roll > 180) roll -= 360; + //while (roll < 180) roll += 360; } // adjust altitude (meters) based on current vertical speed (fpm) @@ -198,6 +330,11 @@ void FGAIAircraft::Run(double dt) { pos.setelev(altitude * SG_FEET_TO_METER); double altitude_ft = altitude; + // adjust target Altitude, based on ground elevation when on ground + if (no_roll) + { + getGroundElev(dt); + } // find target vertical speed if altitude lock engaged if (alt_lock && use_perf_vs) { if (altitude_ft < tgt_altitude) { @@ -303,9 +440,28 @@ void FGAIAircraft::SetFlightPlan(FGAIFlightPlan *f) { fp = f; } -void FGAIAircraft::ProcessFlightPlan( double dt ) { - +void FGAIAircraft::ProcessFlightPlan( double dt, time_t now ) +{ + bool eraseWaypoints; + if (trafficRef) + { +// FGAirport *arr; +// FGAirport *dep; + eraseWaypoints = true; +// cerr << trafficRef->getRegistration(); +// cerr << "Departure airport " << endl; +// dep = trafficRef->getDepartureAirport(); +// if (dep) +// cerr << dep->getId() << endl; +// cerr << "Arrival airport " << endl; +// arr = trafficRef->getArrivalAirport(); +// if (arr) +// cerr << arr->getId() <getCurrentWaypoint(); next = fp->getNextWaypoint(); dt_count += dt; - + if (!prev) { //beginning of flightplan, do this initialization once - fp->IncrementWaypoint(); + //setBank(0.0); + spinCounter = 0; + tempReg = ""; + //prev_dist_to_go = HUGE; + //cerr << "Before increment " << curr-> name << endl; + fp->IncrementWaypoint(eraseWaypoints); + //prev = fp->getPreviousWaypoint(); //first waypoint + //curr = fp->getCurrentWaypoint(); //second waypoint + //next = fp->getNextWaypoint(); //third waypoint (might not exist!) + //cerr << "After increment " << prev-> name << endl; + if (!(fp->getNextWaypoint()) && trafficRef) + { + loadNextLeg(); + } + //cerr << "After load " << prev-> name << endl; prev = fp->getPreviousWaypoint(); //first waypoint curr = fp->getCurrentWaypoint(); //second waypoint next = fp->getNextWaypoint(); //third waypoint (might not exist!) + //cerr << "After load " << prev-> name << endl; setLatitude(prev->latitude); setLongitude(prev->longitude); setSpeed(prev->speed); setAltitude(prev->altitude); - setHeading(fp->getBearing(prev->latitude, prev->longitude, curr)); - if (next) fp->setLeadDistance(speed, hdg, curr, next); + if (prev->speed > 0.0) + setHeading(fp->getBearing(prev->latitude, prev->longitude, curr)); + else + { + setHeading(fp->getBearing(curr->latitude, curr->longitude, prev)); + } + // If next doesn't exist, as in incrementally created flightplans for + // AI/Trafficmanager created plans, + // Make sure lead distance is initialized otherwise + if (next) + fp->setLeadDistance(speed, hdg, curr, next); if (curr->crossat > -1000.0) { //use a calculated descent/climb rate - use_perf_vs = false; - tgt_vs = (curr->crossat - prev->altitude)/ - (fp->getDistanceToGo(pos.lat(), pos.lon(), curr)/ - 6076.0/prev->speed*60.0); + use_perf_vs = false; + tgt_vs = (curr->crossat - prev->altitude)/ + (fp->getDistanceToGo(pos.lat(), pos.lon(), curr)/ + 6076.0/prev->speed*60.0); tgt_altitude = curr->crossat; } else { - use_perf_vs = true; - tgt_altitude = prev->altitude; + use_perf_vs = true; + tgt_altitude = prev->altitude; } alt_lock = hdg_lock = true; no_roll = prev->on_ground; + if (no_roll) + { + Transform(); // make sure aip is initialized. + getGroundElev(60.1); // make sure it's exectuted first time around, so force a large dt value + //getGroundElev(60.1); // Need to do this twice. + //cerr << trafficRef->getRegistration() << " Setting altitude to " << tgt_altitude << endl; + setAltitude(tgt_altitude); + } + prevSpeed = 0; //cout << "First waypoint: " << prev->name << endl; //cout << " Target speed: " << tgt_speed << endl; //cout << " Target altitude: " << tgt_altitude << endl; //cout << " Target heading: " << tgt_heading << endl << endl; + //cerr << "Done Flightplan init" << endl; return; } // end of initialization - + // let's only process the flight plan every 100 ms. - if (dt_count < 0.1) { - return; - } else { - dt_count = 0; - - // check to see if we've reached the lead point for our next turn - double dist_to_go = fp->getDistanceToGo(pos.lat(), pos.lon(), curr); - double lead_dist = fp->getLeadDistance(); - if (lead_dist < (2*speed)) lead_dist = 2*speed; //don't skip over the waypoint - //cout << "dist_to_go: " << dist_to_go << ", lead_dist: " << lead_dist << endl; - - if ( dist_to_go < lead_dist ) { - if (curr->finished) { //end of the flight plan, so terminate - if (trafficRef) - { - delete fp; - //time_t now = time(NULL) + fgGetLong("/sim/time/warp"); - trafficRef->next(); - - FGAIModelEntity entity; - entity.m_class = "jet_transport"; - //entity.path = modelPath.c_str(); - entity.flightplan = "none"; - entity.latitude = _getLatitude(); - entity.longitude = _getLongitude(); - entity.altitude = trafficRef->getCruiseAlt() * 100; // convert from FL to feet - entity.speed = 450; - //entity.fp = new FGAIFlightPlan(&entity, courseToDest, i->getDepartureTime(), dep, arr); - entity.fp = new FGAIFlightPlan(&entity, - 999, // A hack - trafficRef->getDepartureTime(), - trafficRef->getDepartureAirport(), - trafficRef->getArrivalAirport()); - SetFlightPlan(entity.fp); - } - else - { - setDie(true); - return; - } - } - // we've reached the lead-point for the waypoint ahead - if (next) tgt_heading = fp->getBearing(curr, next); - fp->IncrementWaypoint(); - prev = fp->getPreviousWaypoint(); - curr = fp->getCurrentWaypoint(); - next = fp->getNextWaypoint(); - if (next) fp->setLeadDistance(speed, tgt_heading, curr, next); - if (curr->crossat > -1000.0) { - use_perf_vs = false; - tgt_vs = (curr->crossat - altitude)/ - (fp->getDistanceToGo(pos.lat(), pos.lon(), curr)/6076.0/speed*60.0); - tgt_altitude = curr->crossat; - } else { - use_perf_vs = true; - tgt_altitude = prev->altitude; - } - tgt_speed = prev->speed; - hdg_lock = alt_lock = true; - no_roll = prev->on_ground; - //cout << "Crossing waypoint: " << prev->name << endl; - //cout << " Target speed: " << tgt_speed << endl; - //cout << " Target altitude: " << tgt_altitude << endl; - //cout << " Target heading: " << tgt_heading << endl << endl; + if ((dt_count < 0.1) || (now < fp->getStartTime())) + { + //cerr << "done fp dt" << endl; + return; } else { - double calc_bearing = fp->getBearing(pos.lat(), pos.lon(), curr); - double hdg_error = calc_bearing - tgt_heading; - if (fabs(hdg_error) > 1.0) { - TurnTo( calc_bearing ); - } + dt_count = 0; } - - } - + // check to see if we've reached the lead point for our next turn + double dist_to_go = fp->getDistanceToGo(pos.lat(), pos.lon(), curr); + + //cerr << "2" << endl; + double lead_dist = fp->getLeadDistance(); + //cerr << " Distance : " << dist_to_go << ": Lead distance " << lead_dist << endl; + // experimental: Use fabs, because speed can be negative (I hope) during push_back. + if (lead_dist < fabs(2*speed)) + { + lead_dist = fabs(2*speed); //don't skip over the waypoint + //cerr << "Extending lead distance to " << lead_dist << endl; + } +// FGAirport * apt = trafficRef->getDepartureAirport(); +// if ((dist_to_go > prev_dist_to_go) && trafficRef && apt) +// { +// if (apt->getId() == string("EHAM")) +// cerr << "Alert: " << trafficRef->getRegistration() << " is moving away from waypoint " << curr->name << endl +// << "Target heading : " << tgt_heading << "act heading " << hdg << " Tgt speed : " << tgt_speed << endl +// << "Lead distance : " << lead_dist << endl +// << "Distance to go: " << dist_to_go << endl; + +// } + prev_dist_to_go = dist_to_go; + //cerr << "2" << endl; + //if (no_roll) + // lead_dist = 10.0; + //cout << "Leg : " << (fp->getLeg()-1) << ". dist_to_go: " << dist_to_go << ", lead_dist: " << lead_dist << ", tgt_speed " << tgt_speed << ", tgt_heading " << tgt_heading << " speed " << speed << " hdg " << hdg << ". Altitude " << altitude << " TAget alt :" << tgt_altitude << endl; + + if ( dist_to_go < lead_dist ) { + //prev_dist_to_go = HUGE; + // For traffic manager generated aircraft: + // check if the aircraft flies of of user range. And adjust the + // Current waypoint's elevation according to Terrain Elevation + if (curr->finished) { //end of the flight plan + { + setDie(true); + //cerr << "Done die end of fp" << endl; + } + return; + } + + // we've reached the lead-point for the waypoint ahead + //cerr << "4" << endl; + //cerr << "Situation after lead point" << endl; + //cerr << "Prviious: " << prev->name << endl; + //cerr << "Current : " << curr->name << endl; + //cerr << "Next : " << next->name << endl; + if (next) + { + tgt_heading = fp->getBearing(curr, next); + spinCounter = 0; + } + fp->IncrementWaypoint(eraseWaypoints); + if (!(fp->getNextWaypoint()) && trafficRef) + { + loadNextLeg(); + } + prev = fp->getPreviousWaypoint(); + curr = fp->getCurrentWaypoint(); + next = fp->getNextWaypoint(); + // Now that we have incremented the waypoints, excute some traffic manager specific code + // based on the name of the waypoint we just passed. + if (trafficRef) + { + double userLatitude = fgGetDouble("/position/latitude-deg"); + double userLongitude = fgGetDouble("/position/longitude-deg"); + double course, distance; + SGWayPoint current (pos.lon(), + pos.lat(), + 0); + SGWayPoint user ( userLongitude, + userLatitude, + 0); + user.CourseAndDistance(current, &course, &distance); + if ((distance * SG_METER_TO_NM) > TRAFFICTOAIDIST) + { + setDie(true); + //cerr << "done fp die out of range" << endl; + return; + } + + FGAirport * dep = trafficRef->getDepartureAirport(); + FGAirport * arr = trafficRef->getArrivalAirport(); + // At parking the beginning of the airport + if (!( dep && arr)) + { + setDie(true); + return; + } + //if ((dep->getId() == string("EHAM") || (arr->getId() == string("EHAM")))) + // { + // cerr << trafficRef->getRegistration() + // << " Enroute from " << dep->getId() + // << " to " << arr->getId() + // << " just crossed " << prev->name + // << " Assigned rwy " << fp->getRunwayId() + // << " " << fp->getRunway() << endl; + // } + //if ((dep->getId() == string("EHAM")) && (prev->name == "park2")) + // { + // cerr << "Schiphol ground " + // << trafficRef->getCallSign(); + // if (trafficRef->getHeavy()) + // cerr << "Heavy"; + // cerr << ", is type " + // << trafficRef->getAircraft() + // << " ready to go. IFR to " + // << arr->getId() <name == "park2") + dep->releaseParking(fp->getGate()); + + //if ((arr->getId() == string("EHAM")) && (prev->name == "Center")) + // { + // + // cerr << "Schiphol ground " + // << trafficRef->getCallSign(); + // if (trafficRef->getHeavy()) + // cerr << "Heavy"; + // cerr << " landed runway " + // << fp->getRunway() + // << " request taxi to gate " + // << arr->getParkingName(fp->getGate()) + // << endl; + // } + if (prev->name == "END") + fp->setTime(trafficRef->getDepartureTime()); + //cerr << "5" << endl; + } + if (next) + { + //cerr << "Current waypoint" << curr->name << endl; + //cerr << "Next waypoint" << next->name << endl; + fp->setLeadDistance(speed, tgt_heading, curr, next); + } + //cerr << "5.1" << endl; + if (curr->crossat > -1000.0) { + //cerr << "5.1a" << endl; + use_perf_vs = false; + tgt_vs = (curr->crossat - altitude)/ + (fp->getDistanceToGo(pos.lat(), pos.lon(), curr)/6076.0/speed*60.0); + //cerr << "5.1b" << endl; + tgt_altitude = curr->crossat; + } else { + //cerr << "5.1c" << endl; + use_perf_vs = true; + //cerr << "5.1d" << endl; + tgt_altitude = prev->altitude; + //cerr << "Setting target altitude : " <speed; + hdg_lock = alt_lock = true; + no_roll = prev->on_ground; + //cout << "Crossing waypoint: " << prev->name << endl; + //cout << " Target speed: " << tgt_speed << endl; + //cout << " Target altitude: " << tgt_altitude << endl; + //cout << " Target heading: " << tgt_heading << endl << endl; + } else { + + double calc_bearing = fp->getBearing(pos.lat(), pos.lon(), curr); + //cerr << "Bearing = " << calc_bearing << endl; + if (speed < 0) + { + calc_bearing +=180; + if (calc_bearing > 360) + calc_bearing -= 360; + } + if (finite(calc_bearing)) + { + double hdg_error = calc_bearing - tgt_heading; + if (fabs(hdg_error) > 1.0) { + TurnTo( calc_bearing ); + } + } + else + { + cerr << "calc_bearing is not a finite number : " + << "Speed " << speed + << "pos : " << pos.lat() << ", " << pos.lon() + << "waypoint " << curr->latitude << ", " << curr->longitude << endl; + cerr << "waypoint name " << curr->name; + exit(1); + } + double speed_diff = speed - prevSpeed; + // Update the lead distance calculation if speed has changed sufficiently + // to prevent spinning (hopefully); + if (fabs(speed_diff) > 10) + { + prevSpeed = speed; + fp->setLeadDistance(speed, tgt_heading, curr, next); + } + + //cerr << "Done Processing FlightPlan"<< endl; + } // if (dt count) else } - -bool FGAIAircraft::_getGearDown() const { + bool FGAIAircraft::_getGearDown() const { return ((props->getFloatValue("position/altitude-agl-ft") < 900.0) && (props->getFloatValue("velocities/airspeed-kt") < performance->land_speed*1.25)); } + + +void FGAIAircraft::loadNextLeg() +{ + //delete fp; + //time_t now = time(NULL) + fgGetLong("/sim/time/warp"); + + + //FGAIModelEntity entity; + //entity.m_class = "jet_transport"; + //entity.path = modelPath.c_str(); + //entity.flightplan = "none"; + //entity.latitude = _getLatitude(); + //entity.longitude = _getLongitude(); + //entity.altitude = trafficRef->getCruiseAlt() * 100; // convert from FL to feet + //entity.speed = 450; // HACK ALERT + //entity.fp = new FGAIFlightPlan(&entity, courseToDest, i->getDepartureTime(), dep, arr); + int leg; + if ((leg = fp->getLeg()) == 10) + { + trafficRef->next(); + leg = 1; + fp->setLeg(leg); + + //cerr << "Resetting leg : " << leg << endl; + } + //{ + //leg++; + //fp->setLeg(leg); + //cerr << "Creating leg number : " << leg << endl; + FGAirport *dep = trafficRef->getDepartureAirport(); + FGAirport *arr = trafficRef->getArrivalAirport(); + if (!(dep && arr)) + { + setDie(true); + //cerr << "Failed to get airport in AIAircraft::ProcessFlightplan()" << endl; + //if (dep) + // cerr << "Departure " << dep->getId() << endl; + //if (arr) + // cerr << "Arrival " << arr->getId() << endl; + } + else + { + double cruiseAlt = trafficRef->getCruiseAlt() * 100; + //cerr << "Creating new leg using " << cruiseAlt << " as cruise altitude."<< endl; + + fp->create (dep, + arr, + leg, + cruiseAlt, //(trafficRef->getCruiseAlt() * 100), // convert from FL to feet + trafficRef->getSpeed(), + _getLatitude(), + _getLongitude(), + false, + trafficRef->getRadius(), + trafficRef->getFlightType(), + acType, + company); + //prev = fp->getPreviousWaypoint(); + //curr = fp->getCurrentWaypoint(); + //next = fp->getNextWaypoint(); + //cerr << "25" << endl; + //if (next) + // { + // //cerr << "Next waypoint" << next->name << endl; + // fp->setLeadDistance(speed, tgt_heading, curr, next); + // } + //cerr << "25.1" << endl; + //if (curr->crossat > -1000.0) { + // //cerr << "25.1a" << endl; + // use_perf_vs = false; + // + // tgt_vs = (curr->crossat - altitude)/ + // (fp->getDistanceToGo(pos.lat(), pos.lon(), curr)/6076.0/speed*60.0); + // //cerr << "25.1b" << endl; + // tgt_altitude = curr->crossat; + //} else { + // //cerr << "25.1c" << endl; + // use_perf_vs = true; + // //cerr << "25.1d" << endl; + // tgt_altitude = prev->altitude; + // //cerr << "Setting target altitude : " <speed; + //hdg_lock = alt_lock = true; + //no_roll = prev->on_ground; + + } + //} + //else + //{ + //delete entity.fp; + //entity.fp = new FGAIFlightPlan(&entity, + // 999, // A hack + // trafficRef->getDepartureTime(), + // trafficRef->getDepartureAirport(), + // trafficRef->getArrivalAirport(), + // false, + // acType, + // company); + //SetFlightPlan(entity.fp); +} + + + +// Note: This code is copied from David Luff's AILocalTraffic +// Warning - ground elev determination is CPU intensive +// Either this function or the logic of how often it is called +// will almost certainly change. + +void FGAIAircraft::getGroundElev(double dt) { + dt_elev_count += dt; + //return; + if (dt_elev_count < (10.0 + (rand() % 100))) // Update minimally every 10 secs, but add some randomness to prevent them all IA objects doing this synced + { + return; + } + else + { + dt_elev_count = 0; + } + // It would be nice if we could set the correct tile center here in order to get a correct + // answer with one call to the function, but what I tried in the two commented-out lines + // below only intermittently worked, and I haven't quite groked why yet. + //SGBucket buck(pos.lon(), pos.lat()); + //aip.getSGLocation()->set_tile_center(Point3D(buck.get_center_lon(), buck.get_center_lat(), 0.0)); + + // Only do the proper hitlist stuff if we are within visible range of the viewer. + double visibility_meters = fgGetDouble("/environment/visibility-m"); + + + FGViewer* vw = globals->get_current_view(); + double + course, + distance; + + //Point3D currView(vw->getLongitude_deg(), + // vw->getLatitude_deg(), 0.0); + SGWayPoint current (pos.lon(), + pos.lat(), + 0); + SGWayPoint view ( vw->getLongitude_deg(), + vw->getLatitude_deg(), + 0); + view.CourseAndDistance(current, &course, &distance); + if(distance > visibility_meters) { + //aip.getSGLocation()->set_cur_elev_m(aptElev); + return; + } + + + //globals->get_tile_mgr()->prep_ssg_nodes( acmodel_location, + globals->get_tile_mgr()->prep_ssg_nodes( aip.getSGLocation(), visibility_meters ); + Point3D scenery_center = globals->get_scenery()->get_center(); + + globals->get_tile_mgr()->update( aip.getSGLocation(), + visibility_meters, + (aip.getSGLocation())->get_absolute_view_pos( scenery_center ) ); + // save results of update in SGLocation for fdm... + + //if ( globals->get_scenery()->get_cur_elev() > -9990 ) { + // acmodel_location-> + // set_cur_elev_m( globals->get_scenery()->get_cur_elev() ); + //} + + // The need for this here means that at least 2 consecutive passes are needed :-( + aip.getSGLocation()->set_tile_center( globals->get_scenery()->get_next_center() ); + globals->get_tile_mgr()->prep_ssg_nodes( aip.getSGLocation(), visibility_meters ); + //Point3D scenery_center = globals->get_scenery()->get_center(); + + globals->get_tile_mgr()->update( aip.getSGLocation(), + visibility_meters, + (aip.getSGLocation())->get_absolute_view_pos( scenery_center ) ); + // save results of update in SGLocation for fdm... + + //if ( globals->get_scenery()->get_cur_elev() > -9990 ) { + // acmodel_location-> + // set_cur_elev_m( globals->get_scenery()->get_cur_elev() ); + //} + + // The need for this here means that at least 2 consecutive passes are needed :-( + aip.getSGLocation()->set_tile_center( globals->get_scenery()->get_next_center() ); + //cerr << "Transform Elev is " << globals->get_scenery()->get_cur_elev() << '\n'; + tgt_altitude = (globals->get_scenery()->get_cur_elev() * SG_METER_TO_FEET) + groundOffset; +} + +//globals->get_tile_mgr()->prep_ssg_nodes( _aip.getSGLocation(), visibility_meters ); +//Point3D scenery_center = globals->get_scenery()->get_center(); +//globals->get_tile_mgr()->update(_aip.getSGLocation(), visibility_meters, (_aip.getSGLocation())->get_absolute_view_pos( scenery_center ) ); +// save results of update in SGLocation for fdm... + +//if ( globals->get_scenery()->get_cur_elev() > -9990 ) { +// acmodel_location-> +// set_cur_elev_m( globals->get_scenery()->get_cur_elev() ); +//} + +// The need for this here means that at least 2 consecutive passes are needed :-( +//_aip.getSGLocation()->set_tile_center( globals->get_scenery()->get_next_center() ); + +//cout << "Transform Elev is " << globals->get_scenery()->get_cur_elev() << '\n'; +//_aip.getSGLocation()->set_cur_elev_m(globals->get_scenery()->get_cur_elev()); +//return(globals->get_scenery()->get_cur_elev()); +//} diff --git a/src/AIModel/AIAircraft.hxx b/src/AIModel/AIAircraft.hxx index f22ce44fe..ad1c7dae1 100644 --- a/src/AIModel/AIAircraft.hxx +++ b/src/AIModel/AIAircraft.hxx @@ -48,7 +48,6 @@ private: } PERF_STRUCT; public: - enum aircraft_e {LIGHT=0, WW2_FIGHTER, JET_TRANSPORT, JET_FIGHTER, TANKER}; static const PERF_STRUCT settings[]; @@ -68,7 +67,13 @@ public: void YawTo(double angle); void ClimbTo(double altitude); void TurnTo(double heading); - void ProcessFlightPlan( double dt ); + void ProcessFlightPlan( double dt, time_t now ); + void getGroundElev(double dt); + void loadNextLeg (); + + void setAcType(string ac) { acType = ac; }; + void setCompany(string comp) { company = comp;}; + //void setSchedule(FGAISchedule *ref) { trafficRef = ref;}; inline void SetTanker(bool setting) { isTanker = setting; }; @@ -78,6 +83,10 @@ private: bool hdg_lock; bool alt_lock; double dt_count; + double dt_elev_count; + double headingChangeRate; + double groundTargetSpeed; + double groundOffset; double dt; const PERF_STRUCT *performance; @@ -87,8 +96,15 @@ private: void Run(double dt); double sign(double x); + + string acType; + string company; + int spinCounter; + double prevSpeed; + double prev_dist_to_go; bool _getGearDown() const; + bool reachedWaypoint; }; diff --git a/src/AIModel/AIBase.hxx b/src/AIModel/AIBase.hxx index fd8d8c85c..82c4de886 100644 --- a/src/AIModel/AIBase.hxx +++ b/src/AIModel/AIBase.hxx @@ -26,6 +26,7 @@ #include #include #include +#include #include
@@ -75,7 +76,9 @@ typedef struct { double radius; // used by ship ojects, in feet double x_offset; // used by ship ojects, in meters double y_offset; // used by ship ojects, in meters - double z_offset; // used by ship ojects, in meters + double z_offset; // used by ship ojects, in meters + string acType; // used by aircraft objects + string company; // used by aircraft objects } FGAIModelEntity; diff --git a/src/AIModel/AIFlightPlan.cxx b/src/AIModel/AIFlightPlan.cxx index 7ba7747f4..19321f2bf 100644 --- a/src/AIModel/AIFlightPlan.cxx +++ b/src/AIModel/AIFlightPlan.cxx @@ -45,6 +45,8 @@ FGAIFlightPlan::FGAIFlightPlan(string filename) { int i; start_time = 0; + leg = 10; + gateId = 0; SGPath path( globals->get_fg_root() ); path.append( ("/Data/AI/FlightPlans/" + filename).c_str() ); SGPropertyNode root; @@ -55,7 +57,7 @@ FGAIFlightPlan::FGAIFlightPlan(string filename) SG_LOG(SG_GENERAL, SG_ALERT, "Error reading AI flight plan: " << path.str()); // cout << path.str() << endl; - return; + return; } SGPropertyNode * node = root.getNode("flightplan"); @@ -94,8 +96,15 @@ FGAIFlightPlan::FGAIFlightPlan(FGAIModelEntity *entity, double course, time_t start, FGAirport *dep, - FGAirport *arr) + FGAirport *arr, + bool firstLeg, + double radius, + string fltType, + string acType, + string airline) { + leg = 10; + gateId=0; start_time = start; bool useInitialWayPoint = true; bool useCurrentWayPoint = false; @@ -116,55 +125,86 @@ FGAIFlightPlan::FGAIFlightPlan(FGAIModelEntity *entity, useCurrentWayPoint = true; } - try { - readProperties(path.str(), &root); - - SGPropertyNode * node = root.getNode("flightplan"); - - //waypoints.push_back( init_waypoint ); - for (int i = 0; i < node->nChildren(); i++) { - //cout << "Reading waypoint " << i << endl; - waypoint* wpt = new waypoint; - SGPropertyNode * wpt_node = node->getChild(i); - wpt->name = wpt_node->getStringValue("name", "END"); - wpt->latitude = wpt_node->getDoubleValue("lat", 0); - wpt->longitude = wpt_node->getDoubleValue("lon", 0); - wpt->altitude = wpt_node->getDoubleValue("alt", 0); - wpt->speed = wpt_node->getDoubleValue("ktas", 0); - //wpt->speed = speed; - wpt->crossat = wpt_node->getDoubleValue("crossat", -10000); - wpt->gear_down = wpt_node->getBoolValue("gear-down", false); - wpt->flaps_down= wpt_node->getBoolValue("flaps-down", false); - - if (wpt->name == "END") wpt->finished = true; - else wpt->finished = false; - waypoints.push_back(wpt); + if (path.exists()) + { + try + { + readProperties(path.str(), &root); + + SGPropertyNode * node = root.getNode("flightplan"); + + //waypoints.push_back( init_waypoint ); + for (int i = 0; i < node->nChildren(); i++) { + //cout << "Reading waypoint " << i << endl; + waypoint* wpt = new waypoint; + SGPropertyNode * wpt_node = node->getChild(i); + wpt->name = wpt_node->getStringValue("name", "END"); + wpt->latitude = wpt_node->getDoubleValue("lat", 0); + wpt->longitude = wpt_node->getDoubleValue("lon", 0); + wpt->altitude = wpt_node->getDoubleValue("alt", 0); + wpt->speed = wpt_node->getDoubleValue("ktas", 0); + //wpt->speed = speed; + wpt->crossat = wpt_node->getDoubleValue("crossat", -10000); + wpt->gear_down = wpt_node->getBoolValue("gear-down", false); + wpt->flaps_down= wpt_node->getBoolValue("flaps-down", false); + + if (wpt->name == "END") wpt->finished = true; + else wpt->finished = false; + waypoints.push_back(wpt); + } + } + catch (const sg_exception &e) { + SG_LOG(SG_GENERAL, SG_ALERT, + "Error reading AI flight plan: "); + cerr << "Errno = " << errno << endl; + if (errno == ENOENT) + { + cerr << "Reason: No such file or directory" << endl; + } + } } - } - catch (const sg_exception &e) { - //SG_LOG(SG_GENERAL, SG_ALERT, - // "Error reading AI flight plan: "); - // cout << path.str() << endl; - // cout << "Trying to create this plan dynamically" << endl; - // cout << "Route from " << dep->id << " to " << arr->id << endl; - create(dep,arr, entity->altitude, entity->speed); - // Now that we have dynamically created a flight plan, - // we need to add some code that pops any waypoints already past. - //return; - } - waypoint* init_waypoint = new waypoint; - init_waypoint->name = string("initial position"); - init_waypoint->latitude = entity->latitude; - init_waypoint->longitude = entity->longitude; - init_waypoint->altitude = entity->altitude; - init_waypoint->speed = entity->speed; - init_waypoint->crossat = - 10000; - init_waypoint->gear_down = false; - init_waypoint->flaps_down = false; - init_waypoint->finished = false; - - wpt_vector_iterator i = waypoints.begin(); - while (i != waypoints.end()) + else + { + // cout << path.str() << endl; + // cout << "Trying to create this plan dynamically" << endl; + // cout << "Route from " << dep->id << " to " << arr->id << endl; + time_t now = time(NULL) + fgGetLong("/sim/time/warp"); + time_t timeDiff = now-start; + leg = 1; + if ((timeDiff > 300) && (timeDiff < 1200)) + leg = 2; + else if ((timeDiff >= 1200) && (timeDiff < 1500)) + leg = 3; + else if ((timeDiff >= 1500) && (timeDiff < 2000)) + leg = 4; + else if (timeDiff >= 2000) + leg = 5; + + //cerr << "Set leg to : " << leg << endl; + wpt_iterator = waypoints.begin(); + create(dep,arr, leg, entity->altitude, entity->speed, entity->latitude, entity->longitude, + firstLeg, radius, fltType, acType, airline); + wpt_iterator = waypoints.begin(); + //cerr << "after create: " << (*wpt_iterator)->name << endl; + //leg++; + // Now that we have dynamically created a flight plan, + // we need to add some code that pops any waypoints already past. + //return; + } + /* + waypoint* init_waypoint = new waypoint; + init_waypoint->name = string("initial position"); + init_waypoint->latitude = entity->latitude; + init_waypoint->longitude = entity->longitude; + init_waypoint->altitude = entity->altitude; + init_waypoint->speed = entity->speed; + init_waypoint->crossat = - 10000; + init_waypoint->gear_down = false; + init_waypoint->flaps_down = false; + init_waypoint->finished = false; + + wpt_vector_iterator i = waypoints.begin(); + while (i != waypoints.end()) { //cerr << "Checking status of each waypoint: " << (*i)->name << endl; SGWayPoint first(init_waypoint->longitude, @@ -229,11 +269,13 @@ FGAIFlightPlan::FGAIFlightPlan(FGAIModelEntity *entity, //delete wpt; delete *(i); i = waypoints.erase(i); + } + } - } + */ //for (i = waypoints.begin(); i != waypoints.end(); i++) // cerr << "Using waypoint : " << (*i)->name << endl; - wpt_iterator = waypoints.begin(); + //wpt_iterator = waypoints.begin(); //cout << waypoints.size() << " waypoints read." << endl; } @@ -242,7 +284,13 @@ FGAIFlightPlan::FGAIFlightPlan(FGAIModelEntity *entity, FGAIFlightPlan::~FGAIFlightPlan() { - waypoints.clear(); + deleteWaypoints(); + //waypoints.clear(); + //while (waypoints.begin() != waypoints.end()) + // { + // delete *(waypoints.begin()); + // waypoints.erase (waypoints.begin()); + // } } @@ -266,7 +314,9 @@ FGAIFlightPlan::getCurrentWaypoint( void ) FGAIFlightPlan::waypoint* FGAIFlightPlan::getNextWaypoint( void ) { - if (wpt_iterator == waypoints.end()) { + wpt_vector_iterator i = waypoints.end(); + i--; // end() points to one element after the last one. + if (wpt_iterator == i) { return 0; } else { wpt_vector_iterator next = wpt_iterator; @@ -274,14 +324,27 @@ FGAIFlightPlan::getNextWaypoint( void ) } } -void FGAIFlightPlan::IncrementWaypoint( void ) +void FGAIFlightPlan::IncrementWaypoint(bool eraseWaypoints ) { - wpt_iterator++; + if (eraseWaypoints) + { + if (wpt_iterator == waypoints.begin()) + wpt_iterator++; + else + { + delete *(waypoints.begin()); + waypoints.erase(waypoints.begin()); + wpt_iterator = waypoints.begin(); + wpt_iterator++; + } + } + else + wpt_iterator++; } // gives distance in feet from a position to a waypoint double FGAIFlightPlan::getDistanceToGo(double lat, double lon, waypoint* wp){ - // get size of a degree at the present latitude + // get size of a degree2 at the present latitude // this won't work over large distances double ft_per_deg_lat = 366468.96 - 3717.12 * cos(lat / SG_RADIANS_TO_DEGREES); double ft_per_deg_lon = 365228.16 * cos(lat / SG_RADIANS_TO_DEGREES); @@ -293,12 +356,28 @@ double FGAIFlightPlan::getDistanceToGo(double lat, double lon, waypoint* wp){ // sets distance in feet from a lead point to the current waypoint void FGAIFlightPlan::setLeadDistance(double speed, double bearing, waypoint* current, waypoint* next){ - double turn_radius = 0.1911 * speed * speed; // an estimate for 25 degrees bank + double turn_radius; + if (fabs(speed) > 1) + turn_radius = 0.1911 * speed * speed; // an estimate for 25 degrees bank + else + turn_radius = 1.0; + double inbound = bearing; double outbound = getBearing(current, next); - double diff = fabs(inbound - outbound); - if (diff > 180.0) diff = 360.0 - diff; - lead_distance = turn_radius * sin(diff * SG_DEGREES_TO_RADIANS); + leadInAngle = fabs(inbound - outbound); + if (leadInAngle > 180.0) + leadInAngle = 360.0 - leadInAngle; + if (leadInAngle < 1.0) // To prevent lead_dist from getting so small it is skipped + leadInAngle = 1.0; + + lead_distance = turn_radius * sin(leadInAngle * SG_DEGREES_TO_RADIANS); + // if ((errno == EDOM) || (errno == ERANGE) || lead_distance < 1.0) + // { + // cerr << "Lead Distance = " << lead_distance + // << "Diff = " << diff + // << "Turn Radius = " << turn_radius + // << "Speed = " << speed << endl; + // } } void FGAIFlightPlan::setLeadDistance(double distance_ft){ @@ -345,310 +424,51 @@ double FGAIFlightPlan::getBearing(double lat, double lon, waypoint* wp){ // if (!southerly && !easterly) return 270.0 + angle; SGWayPoint sgWp(wp->longitude,wp->latitude, wp->altitude, SGWayPoint::WGS84, string("temp")); sgWp.CourseAndDistance(lon, lat, wp->altitude, &course, &distance); + return course; - // Omit a compiler warning. - + // Omit a compiler warning. + //if ((errno == EDOM) || (errno == ERANGE)) + // { + // cerr << "Lon: " << wp->longitude + // << "Lat = " << wp->latitude + // << "Tgt Lon = " << + // << "TgT Lat = " << speed << endl; + // } + } -/* FGAIFlightPlan::create() - * dynamically create a flight plan for AI traffic, based on data provided by the - * Traffic Manager, when reading a filed flightplan failes. (DT, 2004/07/10) - * - * Probably need to split this into separate functions for different parts of the flight - * once the code matures a bit more. - * - */ -void FGAIFlightPlan::create(FGAirport *dep, FGAirport *arr, double alt, double speed) + +void FGAIFlightPlan::deleteWaypoints() { -double wind_speed; - double wind_heading; - FGRunway rwy; - double lat, lon, az; - double lat2, lon2, az2; - int direction; - - //waypoints.push_back(wpt); - // Create the outbound taxi leg, for now simplified as a - // Direct route from the airport center point to the start - // of the runway. - /////////////////////////////////////////////////////////// - //cerr << "Cruise Alt << " << alt << endl; - // Temporary code to add some small random variation to aircraft parking positions; - direction = (rand() % 360); -geo_direct_wgs_84 ( 0, dep->_latitude, dep->_longitude, direction, - 100, - &lat2, &lon2, &az2 ); - waypoint *wpt = new waypoint; - wpt->name = dep->_id; //wpt_node->getStringValue("name", "END"); - wpt->latitude = lat2; - wpt->longitude = lon2; - wpt->altitude = dep->_elevation + 19; // probably need to add some model height to it - 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); - - // Get the current active runway, based on code from David Luff - FGEnvironment - stationweather = ((FGEnvironmentMgr *) globals->get_subsystem("environment")) - ->getEnvironment(dep->_latitude, dep->_longitude, dep->_elevation); - - 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(dep->_id, int(wind_heading)); - if (!(globals->get_runways()->search(dep->_id, (int) wind_heading, &rwy ))) - { - cout << "Failed to find runway for " << dep->_id << endl; - // Hmm, how do we handle a potential error like this? - exit(1); - } - - - double 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 ); - - //Add the runway startpoint; - wpt = new waypoint; - wpt->name = rwy._id; - wpt->latitude = lat2; - wpt->longitude = lon2; - wpt->altitude = dep->_elevation + 19; - 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); - - //Next: The point on the runway where we begin to accelerate to take-off speed - //100 meters down the runway seems to work. Shorter distances cause problems with - // the turn with larger aircraft - geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth, - rwy._length * SG_FEET_TO_METER * 0.5 - 105.0, - &lat2, &lon2, &az2 ); - wpt = new waypoint; - wpt->name = "accel"; - wpt->latitude = lat2; - wpt->longitude = lon2; - wpt->altitude = dep->_elevation + 19; - wpt->speed = speed; - wpt->crossat = -10000; - wpt->gear_down = true; - wpt->flaps_down= true; - wpt->finished = false; - wpt->on_ground = true; - waypoints.push_back(wpt); - - lat = lat2; - lon = lon2; - az = az2; - - //Next: the Start of Climb - geo_direct_wgs_84 ( 0, lat, lon, heading, - 2560 * SG_FEET_TO_METER, - &lat2, &lon2, &az2 ); - - wpt = new waypoint; - wpt->name = "SOC"; - wpt->latitude = lat2; - wpt->longitude = lon2; - wpt->altitude = alt + 19; - wpt->speed = speed; - wpt->crossat = -10000; - wpt->gear_down = true; - wpt->flaps_down= true; - wpt->finished = false; - wpt->on_ground = false; - waypoints.push_back(wpt); - -//Next: the Top of Climb - geo_direct_wgs_84 ( 0, lat, lon, heading, - 20*SG_NM_TO_METER, - &lat2, &lon2, &az2 ); - wpt = new waypoint; - wpt->name = "10000ft climb"; - wpt->latitude = lat2; - wpt->longitude = lon2; - wpt->altitude = 10000; - wpt->speed = speed; - wpt->crossat = -10000; - wpt->gear_down = true; - wpt->flaps_down= true; - wpt->finished = false; - wpt->on_ground = false; - waypoints.push_back(wpt); - - - - //Beginning of Decent - stationweather = ((FGEnvironmentMgr *)globals->get_subsystem("environment")) - ->getEnvironment(arr->_latitude, arr->_longitude, arr->_elevation); - - 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. - } - - rwy_no = globals->get_runways()->search(arr->_id, int(wind_heading)); - //cout << "Using runway # " << rwy_no << " for departure at " << dep->_id << endl; - - if (!(globals->get_runways()->search(arr->_id, (int) wind_heading, &rwy ))) - { - cout << "Failed to find runway for " << arr->_id << endl; - // Hmm, how do we handle a potential error like this? - exit(1); - } - //cerr << "Done" << endl; - heading = rwy._heading; - azimuth = heading + 180.0; - while ( azimuth >= 360.0 ) { azimuth -= 360.0; } - - - - geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth, - 100000, - &lat2, &lon2, &az2 ); - wpt = new waypoint; - wpt->name = "BOD"; //wpt_node->getStringValue("name", "END"); - wpt->latitude = lat2; - wpt->longitude = lon2; - wpt->altitude = 10000; - wpt->speed = speed; - wpt->crossat = alt +19; - wpt->gear_down = false; - wpt->flaps_down= false; - wpt->finished = false; - wpt->on_ground = false; - waypoints.push_back(wpt); - - // Ten thousand ft. Slowing down to 240 kts - geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth, - 20*SG_NM_TO_METER, - &lat2, &lon2, &az2 ); - wpt = new waypoint; - wpt->name = "Dec 10000ft"; //wpt_node->getStringValue("name", "END"); - wpt->latitude = lat2; - wpt->longitude = lon2; - wpt->altitude = arr->_elevation + 19; - wpt->speed = 240; - wpt->crossat = 10000; - wpt->gear_down = false; - wpt->flaps_down= false; - wpt->finished = false; - wpt->on_ground = false; - waypoints.push_back(wpt); - - // Three thousand ft. Slowing down to 160 kts - geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth, - 8*SG_NM_TO_METER, - &lat2, &lon2, &az2 ); - wpt = new waypoint; - wpt->name = "DEC 3000ft"; //wpt_node->getStringValue("name", "END"); - wpt->latitude = lat2; - wpt->longitude = lon2; - wpt->altitude = arr->_elevation + 19; - wpt->speed = 160; - wpt->crossat = 3000; - wpt->gear_down = true; - wpt->flaps_down= true; - wpt->finished = false; - wpt->on_ground = false; - waypoints.push_back(wpt); - //Runway Threshold - geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth, - rwy._length*0.45 * SG_FEET_TO_METER, - &lat2, &lon2, &az2 ); - wpt = new waypoint; - wpt->name = "Threshold"; //wpt_node->getStringValue("name", "END"); - wpt->latitude = lat2; - wpt->longitude = lon2; - wpt->altitude = arr->_elevation + 19; - wpt->speed = 15; - wpt->crossat = arr->_elevation + 19; - wpt->gear_down = true; - wpt->flaps_down= true; - wpt->finished = false; - wpt->on_ground = true; - waypoints.push_back(wpt); - - //Full stop at the runway centerpoint - geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth, - rwy._length*0.45, - &lat2, &lon2, &az2 ); - wpt = new waypoint; - wpt->name = "Center"; //wpt_node->getStringValue("name", "END"); - wpt->latitude = rwy._lat; - wpt->longitude = rwy._lon; - wpt->altitude = arr->_elevation + 19; - 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); - -direction = (rand() % 360); -geo_direct_wgs_84 ( 0, arr->_latitude, arr->_longitude, direction, - 100, - &lat2, &lon2, &az2 ); - - // Add the final destination waypoint - wpt = new waypoint; - wpt->name = arr->_id; //wpt_node->getStringValue("name", "END"); - wpt->latitude = lat2; - wpt->longitude = lon2; - wpt->altitude = arr->_elevation+19; - 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); - - // And finally one more named "END" - wpt = new waypoint; - wpt->name = "END"; //wpt_node->getStringValue("name", "END"); - wpt->latitude = lat2; - wpt->longitude = lon2; - wpt->altitude = 19; - wpt->speed = 15; - wpt->crossat = -10000; - wpt->gear_down = true; - wpt->flaps_down= true; - wpt->finished = true; - wpt->on_ground = true; - waypoints.push_back(wpt); - - // And finally one more named "EOF" - wpt = new waypoint; - wpt->name = "EOF"; //wpt_node->getStringValue("name", "END"); - wpt->latitude = lat2; - wpt->longitude = lon2; - wpt->altitude = 19; - wpt->speed = 15; - wpt->crossat = -10000; - wpt->gear_down = true; - wpt->flaps_down= true; - wpt->finished = true; - wpt->on_ground = true; - waypoints.push_back(wpt); + for (wpt_vector_iterator i = waypoints.begin(); i != waypoints.end();i++) + delete (*i); + waypoints.clear(); +} + +// Delete all waypoints except the last, +// which we will recycle as the first waypoint in the next leg; +void FGAIFlightPlan::resetWaypoints() +{ + if (waypoints.begin() == waypoints.end()) + return; + else + { + waypoint *wpt = new waypoint; + wpt_vector_iterator i = waypoints.end(); + i--; + wpt->name = (*i)->name; + wpt->latitude = (*i)->latitude; + wpt->longitude = (*i)->longitude; + wpt->altitude = (*i)->altitude; + wpt->speed = (*i)->speed; + wpt->crossat = (*i)->crossat; + wpt->gear_down = (*i)->gear_down; + wpt->flaps_down= (*i)->flaps_down; + wpt->finished = false; + wpt->on_ground = (*i)->on_ground; + //cerr << "Recycling waypoint " << wpt->name << endl; + deleteWaypoints(); + waypoints.push_back(wpt); + } } diff --git a/src/AIModel/AIFlightPlan.hxx b/src/AIModel/AIFlightPlan.hxx index bc4e21b90..c527a5782 100644 --- a/src/AIModel/AIFlightPlan.hxx +++ b/src/AIModel/AIFlightPlan.hxx @@ -24,6 +24,7 @@ #include #include +#include #include "AIBase.hxx" @@ -53,15 +54,21 @@ public: double course, time_t start, FGAirport *dep, - FGAirport *arr); + FGAirport *arr, + bool firstLeg, + double radius, + string fltType, + string acType, + string airline); ~FGAIFlightPlan(); waypoint* getPreviousWaypoint( void ); waypoint* getCurrentWaypoint( void ); waypoint* getNextWaypoint( void ); - void IncrementWaypoint( void ); + void IncrementWaypoint( bool erase ); double getDistanceToGo(double lat, double lon, waypoint* wp); + int getLeg () { return leg;}; void setLeadDistance(double speed, double bearing, waypoint* current, waypoint* next); void setLeadDistance(double distance_ft); double getLeadDistance( void ) const {return lead_distance;} @@ -69,10 +76,17 @@ public: double getBearing(double lat, double lon, waypoint* next); time_t getStartTime() { return start_time; }; - void create(FGAirport *dep, FGAirport *arr, double alt, double speed); + void create(FGAirport *dep, FGAirport *arr, int leg, double alt, double speed, double lat, double lon, + bool firstLeg, double radius, string fltType, string aircraftType, string airline); + void setLeg(int val) { leg = val;}; + void setTime(time_t st) { start_time = st; }; + int getGate() { return gateId; }; + double getLeadInAngle() { return leadInAngle; }; + string getRunway() { return rwy._rwy_no; }; + string getRunwayId() { return rwy._id; }; private: - + FGRunway rwy; typedef vector wpt_vector_type; typedef wpt_vector_type::iterator wpt_vector_iterator; @@ -81,8 +95,21 @@ private: double distance_to_go; double lead_distance; + double leadInAngle; time_t start_time; + int leg; + int gateId; + void createPushBack(bool, FGAirport*, double, double, double, string, string, string); + void createTaxi(bool, int, FGAirport *, double, string, string, string); + void createTakeOff(bool, FGAirport *, double); + void createClimb(bool, FGAirport *, double, double); + void createCruise(bool, FGAirport*, FGAirport*, double, double, double, double); + void createDecent(FGAirport *); + void createLanding(FGAirport *); + void createParking(FGAirport *); + void deleteWaypoints(); + void resetWaypoints(); }; diff --git a/src/AIModel/AIFlightPlanCreate.cxx b/src/AIModel/AIFlightPlanCreate.cxx new file mode 100644 index 000000000..f800f52ca --- /dev/null +++ b/src/AIModel/AIFlightPlanCreate.cxx @@ -0,0 +1,822 @@ +/****************************************************************************** + * AIFlightPlanCreate.cxx + * Written by Durk Talsma, started May, 2004. + * + * 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. + * + * + **************************************************************************/ +#include +#include +#include + +#include +#include + + +/* FGAIFlightPlan::create() + * dynamically create a flight plan for AI traffic, based on data provided by the + * Traffic Manager, when reading a filed flightplan failes. (DT, 2004/07/10) + * + * This is the top-level function, and the only one that publicly available. + * + */ + + +// Check lat/lon values during initialization; +void FGAIFlightPlan::create(FGAirport *dep, FGAirport *arr, int legNr, double alt, double speed, + double latitude, double longitude, bool firstFlight, + double radius, string fltType, string aircraftType, string airline) +{ + int currWpt = wpt_iterator - waypoints.begin(); + switch(legNr) + { + case 1: + //cerr << "Creating Push_Back" << endl; + createPushBack(firstFlight,dep, latitude, longitude, radius, fltType, aircraftType, airline); + //cerr << "Done" << endl; + break; + case 2: + //cerr << "Creating Taxi" << endl; + createTaxi(firstFlight, 1, dep, radius, fltType, aircraftType, airline); + break; + case 3: + //cerr << "Creating TAkeoff" << endl; + createTakeOff(firstFlight, dep, speed); + break; + case 4: + //cerr << "Creating Climb" << endl; + createClimb(firstFlight, dep, speed, alt); + break; + case 5: + //cerr << "Creating Cruise" << endl; + createCruise(firstFlight, dep,arr, latitude, longitude, speed, alt); + break; + case 6: + //cerr << "Creating Decent" << endl; + createDecent(arr); + break; + case 7: + //cerr << "Creating Landing" << endl; + createLanding(arr); + break; + case 8: + //cerr << "Creating Taxi 2" << endl; + createTaxi(false, 2, arr, radius, fltType, aircraftType, airline); + break; + case 9: + //cerr << "Creating Parking" << endl; + createParking(arr); + break; + default: + //exit(1); + cerr << "Unknown case: " << legNr << endl; + } + wpt_iterator = waypoints.begin()+currWpt; + leg++; +} + +/******************************************************************* + * createPushBack + * initialize the Aircraft at the parking location + ******************************************************************/ +void FGAIFlightPlan::createPushBack(bool firstFlight, FGAirport *dep, + double latitude, + double longitude, + double radius, + string fltType, + string aircraftType, + string airline) +{ + double heading; + double lat; + double lon; + double lat2; + double lon2; + double az2; + + //int currWpt = wpt_iterator - waypoints.begin(); + // Erase all existing waypoints. + //resetWaypoints(); + + // We only need to get a valid parking if this is the first leg. + // Otherwise use the current aircraft position. + if (firstFlight) + { + if (!(dep->getAvailableParking(&lat, &lon, &heading, &gateId, radius, fltType, aircraftType, airline))) + { + cerr << "Could not find parking " << endl; + } + } + else + { + dep->getParking(gateId, &lat, &lon, &heading); + //lat = latitude; + //lon = longitude; + //heading = getHeading(); + } + heading += 180.0; + if (heading > 360) + heading -= 360; + waypoint *wpt = new waypoint; + wpt->name = "park"; + wpt->latitude = lat; + wpt->longitude = lon; + wpt->altitude = dep->getElevation(); + wpt->speed = -10; + wpt->crossat = -10000; + wpt->gear_down = true; + wpt->flaps_down= true; + wpt->finished = false; + wpt->on_ground = true; + waypoints.push_back(wpt); + + // Add park twice, because it uses park once for initialization and once + // to trigger the departure ATC message + geo_direct_wgs_84 ( 0, lat, lon, heading, + 10, + &lat2, &lon2, &az2 ); + wpt = new waypoint; + wpt->name = "park2"; + wpt->latitude = lat2; + wpt->longitude = lon2; + wpt->altitude = dep->getElevation(); + wpt->speed = -10; + wpt->crossat = -10000; + wpt->gear_down = true; + wpt->flaps_down= true; + wpt->finished = false; + wpt->on_ground = true; + waypoints.push_back(wpt); + geo_direct_wgs_84 ( 0, lat, lon, heading, + 100, + &lat2, &lon2, &az2 ); + wpt = new waypoint; + wpt->name = "taxiStart"; + wpt->latitude = lat2; + wpt->longitude = lon2; + wpt->altitude = dep->getElevation(); + wpt->speed = 10; + 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->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) +{ + double wind_speed; + double wind_heading; + double heading; + //FGRunway rwy; + double lat, lon, az; + double lat2, lon2, az2; + //int direction; + waypoint *wpt; + + // Erase all existing waypoints. + // wpt_vector_iterator i= waypoints.begin(); + //resetWaypoints(); + //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); + 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); + + 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 ); + + //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 + { + //direction = (rand() % 360); + //geo_direct_wgs_84 ( 0, arr->getLatitude(), arr->getLongitude(), direction, + //100, + //&lat2, &lon2, &az2 ); + + // 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. + apt->getAvailableParking(&lat, &lon, &heading, &gateId, radius, fltType, acType, airline); + heading += 180.0; + if (heading > 360) + heading -= 360; + 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); + + // Add the final destination waypoint + wpt = new waypoint; + wpt->name = "Begin Parkingg"; //apt->getId(); //wpt_node->getStringValue("name", "END"); + 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_iterator = waypoints.begin(); + //if (!firstFlight) + // wpt_iterator++; + //wpt_iterator = waypoints.begin()+currWpt; +} + +/******************************************************************* + * CreateTakeOff + * initialize the Aircraft at the parking location + ******************************************************************/ +void FGAIFlightPlan::createTakeOff(bool firstFlight, FGAirport *apt, double speed) +{ + double wind_speed; + double wind_heading; + double heading; + //FGRunway rwy; + double lat, lon, az; + double lat2, lon2, az2; + //int direction; + waypoint *wpt; + + + // Erase all existing waypoints. + // wpt_vector_iterator i= waypoints.begin(); + //while(waypoints.begin() != waypoints.end()) + // { + // delete *(i); + // waypoints.erase(i); + // } + //resetWaypoints(); + + + // 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 + if (firstFlight) + { + string name; + 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); + } + + 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 - 105.0, + &lat2, &lon2, &az2 ); + wpt = new waypoint; + wpt->name = "accel"; + wpt->latitude = lat2; + wpt->longitude = lon2; + wpt->altitude = apt->getElevation(); + wpt->speed = speed; + wpt->crossat = -10000; + wpt->gear_down = true; + wpt->flaps_down= true; + wpt->finished = false; + wpt->on_ground = true; + waypoints.push_back(wpt); + + lat = lat2; + lon = lon2; + az = az2; + + //Next: the Start of Climb + geo_direct_wgs_84 ( 0, lat, lon, heading, + 2560 * SG_FEET_TO_METER, + &lat2, &lon2, &az2 ); + + wpt = new waypoint; + wpt->name = "SOC"; + wpt->latitude = lat2; + wpt->longitude = lon2; + wpt->altitude = apt->getElevation()+3000; + wpt->speed = speed; + wpt->crossat = -10000; + wpt->gear_down = true; + wpt->flaps_down= true; + wpt->finished = false; + wpt->on_ground = false; + waypoints.push_back(wpt); + // waypoints.push_back(wpt); + //waypoints.push_back(wpt); // add one more to prevent a segfault. + // wpt_iterator = waypoints.begin(); + //if (!firstFlight) + // wpt_iterator++; +} + +/******************************************************************* + * CreateClimb + * initialize the Aircraft at the parking location + ******************************************************************/ +void FGAIFlightPlan::createClimb(bool firstFlight, FGAirport *apt, double speed, double alt) +{ + double wind_speed; + double wind_heading; + double heading; + //FGRunway rwy; + double lat, lon, az; + double lat2, lon2, az2; + //int direction; + waypoint *wpt; + + // Erase all existing waypoints. + // wpt_vector_iterator i= waypoints.begin(); + //while(waypoints.begin() != waypoints.end()) + // { + // delete *(i); + // waypoints.erase(i); + // } + //resetWaypoints(); + + + // 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 + if (firstFlight) + { + string name; + 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); + } + + + heading = rwy._heading; + double azimuth = heading + 180.0; + while ( azimuth >= 360.0 ) { azimuth -= 360.0; } + geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, heading, + 10*SG_NM_TO_METER, + &lat2, &lon2, &az2 ); + wpt = new waypoint; + wpt->name = "10000ft climb"; + wpt->latitude = lat2; + wpt->longitude = lon2; + wpt->altitude = 10000; + wpt->speed = speed; + wpt->crossat = -10000; + wpt->gear_down = true; + wpt->flaps_down= true; + wpt->finished = false; + wpt->on_ground = false; + waypoints.push_back(wpt); + + + geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, heading, + 20*SG_NM_TO_METER, + &lat2, &lon2, &az2 ); + wpt = new waypoint; + wpt->name = "18000ft climb"; + wpt->latitude = lat2; + wpt->longitude = lon2; + wpt->altitude = 18000; + wpt->speed = speed; + wpt->crossat = -10000; + wpt->gear_down = true; + wpt->flaps_down= true; + wpt->finished = false; + wpt->on_ground = false; + waypoints.push_back(wpt); + //waypoints.push_back(wpt); + //waypoints.push_back(wpt); // add one more to prevent a segfault. + // wpt_iterator = waypoints.begin(); + //if (!firstFlight) + // wpt_iterator++; +} + + +/******************************************************************* + * CreateCruise + * initialize the Aircraft at the parking location + ******************************************************************/ +void FGAIFlightPlan::createCruise(bool firstFlight, FGAirport *dep, FGAirport *arr, double latitude, double longitude, double speed, double alt) +{ + double wind_speed; + double wind_heading; + double heading; + //FGRunway rwy; + double lat, lon, az; + double lat2, lon2, az2; + double azimuth; + //int direction; + waypoint *wpt; + + // Erase all existing waypoints. + // wpt_vector_iterator i= waypoints.begin(); + //while(waypoints.begin() != waypoints.end()) + // { + // delete *(i); + // waypoints.erase(i); + // } + //resetWaypoints(); + + 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; + waypoints.push_back(wpt); + //Beginning of Decent + + string name; + arr->getActiveRunway("com", 2, &name); + if (!(globals->get_runways()->search(arr->getId(), + name, + &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; + // } + 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; + waypoints.push_back(wpt); + //waypoints.push_back(wpt); + //waypoints.push_back(wpt); // add one more to prevent a segfault. + //wpt_iterator = waypoints.begin(); + //if (!firstFlight) + // wpt_iterator++; +} + +/******************************************************************* + * CreateDecent + * initialize the Aircraft at the parking location + ******************************************************************/ +void FGAIFlightPlan::createDecent(FGAirport *apt) +{ + + // Ten thousand ft. Slowing down to 240 kts + double wind_speed; + double wind_heading; + double heading; + //FGRunway rwy; + double lat, lon, az; + double lat2, lon2, az2; + double azimuth; + //int direction; + waypoint *wpt; + + //// Erase all existing waypoints. + // wpt_vector_iterator i= waypoints.begin(); + //while(waypoints.begin() != waypoints.end()) + // { + // delete *(i); + // waypoints.erase(i); + // } + //resetWaypoints(); + + //Beginning of Decent + string name; + apt->getActiveRunway("com", 2, &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); + + //cerr << "Done" << endl; + heading = rwy._heading; + azimuth = heading + 180.0; + while ( azimuth >= 360.0 ) { azimuth -= 360.0; } + + + + geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth, + 100000, + &lat2, &lon2, &az2 ); + + wpt = new waypoint; + wpt->name = "Dec 10000ft"; //wpt_node->getStringValue("name", "END"); + wpt->latitude = lat2; + wpt->longitude = lon2; + wpt->altitude = apt->getElevation(); + wpt->speed = 240; + wpt->crossat = 10000; + wpt->gear_down = false; + wpt->flaps_down= false; + wpt->finished = false; + wpt->on_ground = false; + waypoints.push_back(wpt); + + // Three thousand ft. Slowing down to 160 kts + geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth, + 8*SG_NM_TO_METER, + &lat2, &lon2, &az2 ); + wpt = new waypoint; + wpt->name = "DEC 3000ft"; //wpt_node->getStringValue("name", "END"); + wpt->latitude = lat2; + wpt->longitude = lon2; + wpt->altitude = apt->getElevation(); + wpt->speed = 160; + wpt->crossat = 3000; + wpt->gear_down = true; + wpt->flaps_down= true; + wpt->finished = false; + wpt->on_ground = false; + waypoints.push_back(wpt); + //waypoints.push_back(wpt); + //waypoints.push_back(wpt); // add one more to prevent a segfault. + //wpt_iterator = waypoints.begin(); + //wpt_iterator++; + //if (apt->getId() == "EHAM") + // { + // cerr << "Created Decend to EHAM " << lat2 << " " << lon2 << ": Runway = " << rwy._rwy_no + // << "heading " << heading << endl; + // } +} +/******************************************************************* + * CreateLanding + * initialize the Aircraft at the parking location + ******************************************************************/ +void FGAIFlightPlan::createLanding(FGAirport *apt) +{ + // Ten thousand ft. Slowing down to 240 kts + double wind_speed; + double wind_heading; + double heading; + //FGRunway rwy; + double lat, lon, az; + double lat2, lon2, az2; + double azimuth; + //int direction; + waypoint *wpt; + + + heading = rwy._heading; + azimuth = heading + 180.0; + while ( azimuth >= 360.0 ) { azimuth -= 360.0; } + + //Runway Threshold + geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth, + rwy._length*0.45 * SG_FEET_TO_METER, + &lat2, &lon2, &az2 ); + wpt = new waypoint; + wpt->name = "Threshold"; //wpt_node->getStringValue("name", "END"); + wpt->latitude = lat2; + wpt->longitude = lon2; + wpt->altitude = apt->getElevation(); + wpt->speed = 150; + wpt->crossat = apt->getElevation(); + wpt->gear_down = true; + wpt->flaps_down= true; + wpt->finished = false; + wpt->on_ground = true; + waypoints.push_back(wpt); + + //Full stop at the runway centerpoint + geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth, + rwy._length*0.45, + &lat2, &lon2, &az2 ); + wpt = new waypoint; + wpt->name = "Center"; //wpt_node->getStringValue("name", "END"); + wpt->latitude = rwy._lat; + wpt->longitude = rwy._lon; + wpt->altitude = apt->getElevation(); + wpt->speed = 30; + wpt->crossat = -10000; + wpt->gear_down = true; + wpt->flaps_down= true; + wpt->finished = false; + wpt->on_ground = true; + waypoints.push_back(wpt); + + geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, heading, + rwy._length*0.45 * SG_FEET_TO_METER, + &lat2, &lon2, &az2 ); + wpt = new waypoint; + wpt->name = "Threshold"; //wpt_node->getStringValue("name", "END"); + wpt->latitude = lat2; + wpt->longitude = lon2; + wpt->altitude = apt->getElevation(); + wpt->speed = 15; + wpt->crossat = apt->getElevation(); + wpt->gear_down = true; + wpt->flaps_down= true; + wpt->finished = false; + wpt->on_ground = true; + waypoints.push_back(wpt); + //waypoints.push_back(wpt); + //waypoints.push_back(wpt); // add one more to prevent a segfault. + //wpt_iterator = waypoints.begin(); + //wpt_iterator++; + + //if (apt->getId() == "EHAM") + //{ + // cerr << "Created Landing to EHAM " << lat2 << " " << lon2 << ": Runway = " << rwy._rwy_no + // << "heading " << heading << endl; + //} +} + +/******************************************************************* + * CreateParking + * initialize the Aircraft at the parking location + ******************************************************************/ +void FGAIFlightPlan::createParking(FGAirport *apt) +{ + waypoint* wpt; + double lat; + double lon; + double heading; + apt->getParking(gateId, &lat, &lon, &heading); + heading += 180.0; + if (heading > 360) + heading -= 360; + + // Erase all existing waypoints. + // wpt_vector_iterator i= waypoints.begin(); + //while(waypoints.begin() != waypoints.end()) + // { + // delete *(i); + // waypoints.erase(i); + // } + //resetWaypoints(); + // And finally one more named "END" + wpt = new waypoint; + wpt->name = "END"; //wpt_node->getStringValue("name", "END"); + wpt->latitude = lat; + wpt->longitude = lon; + wpt->altitude = 19; + 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); + //waypoints.push_back(wpt); + //waypoints.push_back(wpt); // add one more to prevent a segfault. + //wpt_iterator = waypoints.begin(); + //wpt_iterator++; +} diff --git a/src/AIModel/AIManager.cxx b/src/AIModel/AIManager.cxx index 25f5425c7..52d8e3da9 100644 --- a/src/AIModel/AIManager.cxx +++ b/src/AIModel/AIManager.cxx @@ -156,6 +156,8 @@ FGAIManager::createAircraft( FGAIModelEntity *entity, FGAISchedule *ref) { } else { ai_plane->SetPerformance(&FGAIAircraft::settings[FGAIAircraft::JET_TRANSPORT]); } + ai_plane->setAcType(entity->acType); + ai_plane->setCompany(entity->company); ai_plane->setHeading(entity->heading); ai_plane->setSpeed(entity->speed); ai_plane->setPath(entity->path.c_str()); diff --git a/src/AIModel/Makefile.am b/src/AIModel/Makefile.am index a44c13f90..fc2aafeec 100644 --- a/src/AIModel/Makefile.am +++ b/src/AIModel/Makefile.am @@ -9,7 +9,7 @@ libAIModel_a_SOURCES = \ AIBallistic.hxx AIBallistic.cxx \ AIStorm.hxx AIStorm.cxx \ AIThermal.hxx AIThermal.cxx \ - AIFlightPlan.hxx AIFlightPlan.cxx \ + AIFlightPlan.hxx AIFlightPlan.cxx AIFlightPlanCreate.cxx \ AIScenario.hxx AIScenario.cxx \ AICarrier.hxx AICarrier.cxx diff --git a/src/ATC/AIMgr.cxx b/src/ATC/AIMgr.cxx index 50662f547..93a878388 100644 --- a/src/ATC/AIMgr.cxx +++ b/src/ATC/AIMgr.cxx @@ -133,7 +133,7 @@ void FGAIMgr::init() { f_ident = file.substr(0, pos); FGAirport a; if(dclFindAirportID(f_ident, &a)) { - SGBucket sgb(a._longitude, a._latitude); + SGBucket sgb(a.getLongitude(), a.getLatitude()); int idx = sgb.gen_index(); if(facilities.find(idx) != facilities.end()) { facilities[idx]->push_back(f_ident); diff --git a/src/ATC/ATCDialog.cxx b/src/ATC/ATCDialog.cxx index 0c96b36ce..42d8bf7be 100644 --- a/src/ATC/ATCDialog.cxx +++ b/src/ATC/ATCDialog.cxx @@ -460,7 +460,7 @@ void FGATCDialog::FreqDisplay(string ident) { FGAirport a; if ( dclFindAirportID( ident, &a ) ) { comm_list_type stations; - int found = current_commlist->FindByPos(a._longitude, a._latitude, a._elevation, 20.0, &stations); + int found = current_commlist->FindByPos(a.getLongitude(), a.getLatitude(), a.getElevation(), 20.0, &stations); if(found) { ostringstream ostr; comm_list_iterator itr = stations.begin(); diff --git a/src/ATC/ATCmgr.cxx b/src/ATC/ATCmgr.cxx index 26b1bc801..8084b0822 100644 --- a/src/ATC/ATCmgr.cxx +++ b/src/ATC/ATCmgr.cxx @@ -221,9 +221,9 @@ bool FGATCMgr::AIRegisterAirport(string ident) { //cout << "ident = " << ident << '\n'; AirportATC *a = new AirportATC; // I'm not entirely sure that this AirportATC structure business is actually needed - it just duplicates what we can find out anyway! - a->lon = ap._longitude; - a->lat = ap._latitude; - a->elev = ap._elevation; + a->lon = ap.getLongitude(); + a->lat = ap.getLatitude(); + a->elev = ap.getElevation(); a->atis_freq = GetFrequency(ident, ATIS); //cout << "ATIS freq = " << a->atis_freq << '\n'; a->atis_active = false; @@ -270,9 +270,9 @@ bool FGATCMgr::CommRegisterAirport(string ident, int chan, atc_type tp) { if(dclFindAirportID(ident, &ap)) { AirportATC *a = new AirportATC; // I'm not entirely sure that this AirportATC structure business is actually needed - it just duplicates what we can find out anyway! - a->lon = ap._longitude; - a->lat = ap._latitude; - a->elev = ap._elevation; + a->lon = ap.getLongitude(); + a->lat = ap.getLatitude(); + a->elev = ap.getElevation(); a->atis_freq = GetFrequency(ident, ATIS); a->atis_active = false; a->tower_freq = GetFrequency(ident, TOWER); diff --git a/src/ATC/ATCutils.cxx b/src/ATC/ATCutils.cxx index 55e9be7aa..02b0dc619 100644 --- a/src/ATC/ATCutils.cxx +++ b/src/ATC/ATCutils.cxx @@ -314,7 +314,7 @@ bool dclFindAirportID( const string& id, FGAirport *a ) { SG_LOG( SG_GENERAL, SG_INFO, "Searching for airport code = " << id ); result = globals->get_airports()->search( id ); - if ( result._id.empty() ) { + if ( result.getId().empty() ) { SG_LOG( SG_GENERAL, SG_WARN, "Failed to find " << id << " in basic.dat.gz" ); return false; @@ -327,8 +327,8 @@ bool dclFindAirportID( const string& id, FGAirport *a ) { SG_LOG( SG_GENERAL, SG_INFO, "Position for " << id << " is (" - << a->_longitude << ", " - << a->_latitude << ")" ); + << a->getLongitude() << ", " + << a->getLatitude() << ")" ); return true; } @@ -342,7 +342,7 @@ double dclGetAirportElev( const string& id ) { "Finding elevation for airport: " << id ); if ( dclFindAirportID( id, &a ) ) { - return a._elevation * SG_FEET_TO_METER; + return a.getElevation() * SG_FEET_TO_METER; } else { return -9999.0; } @@ -357,7 +357,7 @@ Point3D dclGetAirportPos( const string& id ) { "Finding position for airport: " << id ); if ( dclFindAirportID( id, &a ) ) { - return Point3D(a._longitude, a._latitude, a._elevation); + return Point3D(a.getLongitude(), a.getLatitude(), a.getElevation()); } else { return Point3D(0.0, 0.0, -9999.0); } diff --git a/src/ATC/commlist.cxx b/src/ATC/commlist.cxx index a88ba3521..18e171730 100644 --- a/src/ATC/commlist.cxx +++ b/src/ATC/commlist.cxx @@ -276,7 +276,7 @@ bool FGCommList::FindByCode( string ICAO, ATCData& ad, atc_type tp ) { FGAirport a; if ( dclFindAirportID( ICAO, &a ) ) { comm_list_type stations; - int found = FindByPos(a._longitude, a._latitude, a._elevation, 10.0, &stations, tp); + int found = FindByPos(a.getLongitude(), a.getLatitude(), a.getElevation(), 10.0, &stations, tp); if(found) { comm_list_iterator itr = stations.begin(); while(itr != stations.end()) { diff --git a/src/Airports/apt_loader.cxx b/src/Airports/apt_loader.cxx index a749bcda9..8de4822a0 100644 --- a/src/Airports/apt_loader.cxx +++ b/src/Airports/apt_loader.cxx @@ -232,8 +232,8 @@ bool fgAirportDBLoad( FGAirportList *airports, FGRunwayList *runways, if ( ident == "#" || ident == "//" ) { metar_in >> skipeol; } else { - FGAirport a = airports->search( ident ); - if ( a._id == ident ) { + const FGAirport &a = airports->search( ident ); + if ( a.getId() == ident ) { airports->has_metar( ident ); } } diff --git a/src/Airports/simple.cxx b/src/Airports/simple.cxx index 5a3e509dc..5c74391b4 100644 --- a/src/Airports/simple.cxx +++ b/src/Airports/simple.cxx @@ -4,6 +4,7 @@ // elevation in feet. // // Written by Curtis Olson, started April 1998. +// Updated by Durk Talsma, started December, 2004. // // Copyright (C) 1998 Curtis L. Olson - http://www.flightgear.org/~curt // @@ -30,8 +31,15 @@ #include #include - +#include +#include +#include +#include +#include #include +#include
+#include
+#include #include STL_STRING @@ -39,21 +47,1147 @@ SG_USING_NAMESPACE(std); +/****************************************************************************** + * ScheduleTime + ***************e*************************************************************/ +void ScheduleTime::clear() +{ + start.clear(); + end.clear(); + scheduleNames.clear(); +} + + +ScheduleTime::ScheduleTime(const ScheduleTime &other) +{ + //timeVec start; + timeVecConstIterator i; + for (i = other.start.begin(); i != other.start.end(); i++) + start.push_back(*i); + for (i = other.end.begin(); i != other.end.end(); i++) + end.push_back(*i); + stringVecConstIterator k; + for (k = other.scheduleNames.begin(); k != other.scheduleNames.end(); k++) + scheduleNames.push_back(*k); + + //timeVec end; + //stringVec scheduleNames; + tailWind = other.tailWind; + crssWind = other.tailWind; +} + + +ScheduleTime & ScheduleTime::operator= (const ScheduleTime &other) +{ + //timeVec start; + clear(); + timeVecConstIterator i; + for (i = other.start.begin(); i != other.start.end(); i++) + start.push_back(*i); + for (i = other.end.begin(); i != other.end.end(); i++) + end.push_back(*i); + stringVecConstIterator k; + for (k = other.scheduleNames.begin(); k != other.scheduleNames.end(); k++) + scheduleNames.push_back(*k); + + //timeVec end; + //stringVec scheduleNames; + tailWind = other.tailWind; + crssWind = other.tailWind; + return *this; +} +string ScheduleTime::getName(time_t dayStart) +{ + if ((start.size() != end.size()) || (start.size() != scheduleNames.size())) + { + cerr << "Unable to parse schedule times" << endl; + exit(1); + } + else + { + int nrItems = start.size(); + //cerr << "Nr of items to process: " << nrItems << endl; + if (nrItems > 0) + { + for (int i = 0; i < start.size(); i++) + { + //cerr << i << endl; + if ((dayStart >= start[i]) && (dayStart <= end[i])) + return scheduleNames[i]; + } + } + //couldn't find one so return 0; + //cerr << "Returning 0 " << endl; + return string(0); + } +} +/****************************************************************************** + * RunwayList + *****************************************************************************/ + +RunwayList::RunwayList(const RunwayList &other) +{ + type = other.type; + stringVecConstIterator i; + for (i = other.preferredRunways.begin(); i != other.preferredRunways.end(); i++) + preferredRunways.push_back(*i); +} +RunwayList& RunwayList::operator= (const RunwayList &other) +{ + type = other.type; + preferredRunways.clear(); + stringVecConstIterator i; + for (i = other.preferredRunways.begin(); i != other.preferredRunways.end(); i++) + preferredRunways.push_back(*i); + return *this; +} +void RunwayList::set(string tp, string lst) +{ + //weekday = atoi(timeCopy.substr(0,1).c_str()); + // timeOffsetInDays = weekday - currTimeDate->getGmt()->tm_wday; + // timeCopy = timeCopy.substr(2,timeCopy.length()); + type = tp; + string rwys = lst; + string rwy; + while (rwys.find(",") != string::npos) + { + rwy = rwys.substr(0, rwys.find(",",0)); + //cerr << "adding runway [" << rwy << "] to the list " << endl; + preferredRunways.push_back(rwy); + rwys.erase(0, rwys.find(",",0)+1); // erase until after the first whitspace + while (rwys[0] == ' ') + rwys.erase(0, 1); // Erase any leading whitespaces. + //cerr << "Remaining runway list " << rwys; + } + preferredRunways.push_back(rwys); + //exit(1); +} + +void RunwayList::clear() +{ + type = ""; + preferredRunways.clear(); +} +/**************************************************************************** + * + ***************************************************************************/ + +RunwayGroup::RunwayGroup(const RunwayGroup &other) +{ + name = other.name; + RunwayListVecConstIterator i; + for (i = other.rwyList.begin(); i != other.rwyList.end(); i++) + rwyList.push_back(*i); + choice[0] = other.choice[0]; + choice[1] = other.choice[1]; + nrActive = other.nrActive; +} +RunwayGroup& RunwayGroup:: operator= (const RunwayGroup &other) +{ + rwyList.clear(); + name = other.name; + RunwayListVecConstIterator i; + for (i = other.rwyList.begin(); i != other.rwyList.end(); i++) + rwyList.push_back(*i); + choice[0] = other.choice[0]; + choice[1] = other.choice[1]; + nrActive = other.nrActive; +} + +void RunwayGroup::setActive(string aptId, + double windSpeed, + double windHeading, + double maxTail, + double maxCross) +{ + + FGRunway rwy; + int activeRwys = rwyList.size(); // get the number of runways active + int nrOfPreferences; + bool found = true; + double heading; + double hdgDiff; + double crossWind; + double tailWind; + string name; + + if (activeRwys > 0) + { + nrOfPreferences = rwyList[0].getRwyList()->size(); + for (int i = 0; i < nrOfPreferences; i++) + { + bool validSelection = true; + for (int j = 0; j < activeRwys; j++) + { + //cerr << "I J " << i << " " << j << endl; + name = rwyList[j].getRwyList(i); + //cerr << "Name of Runway: " << name << endl; + if (globals->get_runways()->search( aptId, + name, + &rwy)) + { + //cerr << "Succes" << endl; + hdgDiff = fabs(windHeading - rwy._heading); + //cerr << "Wind Heading: " << windHeading << "Runway Heading: " < 180) + hdgDiff = 360 - hdgDiff; + //cerr << "Heading diff: " << hdgDiff << endl; + hdgDiff *= ((2*M_PI)/360.0); // convert to radians + crossWind = windSpeed * sin(hdgDiff); + tailWind = -windSpeed * cos(hdgDiff); + //cerr << "Tailwind : " << tailWind << endl; + //cerr << "Crosswnd : " << crossWind << endl; + if ((tailWind > maxTail) || (crossWind > maxCross)) + validSelection = false; + }else { + cerr << "Failed to find runway " << name << " at " << aptId << endl; + exit(1); + } + + } + if (validSelection) + { + //cerr << "Valid runay selection : " << i << endl; + nrActive = activeRwys; + active = i; + return; + } + } + // If this didn't work, due to heavy winds, try again + // but select only one landing and one takeoff runway. + choice[0] = 0; + choice[1] = 0; + for (int i = activeRwys-1; i; i--) + { + if (rwyList[i].getType() == string("landing")) + choice[0] = i; + if (rwyList[i].getType() == string("takeoff")) + choice[1] = i; + } + //cerr << "Choosing " << choice[0] << " for landing and " << choice[1] << "for takeoff" << endl; + nrOfPreferences = rwyList[0].getRwyList()->size(); + for (int i = 0; i < nrOfPreferences; i++) + { + bool validSelection = true; + for (int j = 0; j < 2; j++) + { + //cerr << "I J " << i << " " << j << endl; + name = rwyList[choice[j]].getRwyList(i); + //cerr << "Name of Runway: " << name << endl; + if (globals->get_runways()->search( aptId, + name, + &rwy)) + { + //cerr << "Succes" << endl; + hdgDiff = fabs(windHeading - rwy._heading); + //cerr << "Wind Heading: " << windHeading << "Runway Heading: " < 180) + hdgDiff = 360 - hdgDiff; + //cerr << "Heading diff: " << hdgDiff << endl; + hdgDiff *= ((2*M_PI)/360.0); // convert to radians + crossWind = windSpeed * sin(hdgDiff); + tailWind = -windSpeed * cos(hdgDiff); + //cerr << "Tailwind : " << tailWind << endl; + //cerr << "Crosswnd : " << crossWind << endl; + if ((tailWind > maxTail) || (crossWind > maxCross)) + validSelection = false; + }else { + cerr << "Failed to find runway " << name << " at " << aptId << endl; + exit(1); + } + + } + if (validSelection) + { + //cerr << "Valid runay selection : " << i << endl; + active = i; + nrActive = 2; + return; + } + } + } + active = -1; + //RunwayListVectorIterator i; // = rwlist.begin(); + //stringVecIterator j; + //for (i = rwyList.begin(); i != rwyList.end(); i++) + // { + // cerr << i->getType(); + // for (j = i->getRwyList()->begin(); j != i->getRwyList()->end(); j++) + // { + // cerr << (*j); + // } + // cerr << endl; + // } + //for (int + +} + +void RunwayGroup::getActive(int i, string *name, string *type) +{ + if (i == -1) + { + return; + } + if (nrActive == rwyList.size()) + { + *name = rwyList[i].getRwyList(active); + *type = rwyList[i].getType(); + } + else + { + *name = rwyList[choice[i]].getRwyList(active); + *type = rwyList[choice[i]].getType(); + } +} +/***************************************************************************** + * FGRunway preference + ****************************************************************************/ +FGRunwayPreference::FGRunwayPreference() +{ + //cerr << "Running default Constructor" << endl; + initialized = false; +} + +FGRunwayPreference::FGRunwayPreference(const FGRunwayPreference &other) +{ + initialized = other.initialized; + value = other.value; + scheduleName = other.scheduleName; + + comTimes = other.comTimes; // Commercial Traffic; + genTimes = other.genTimes; // General Aviation; + milTimes = other.milTimes; // Military Traffic; + currTimes= other.currTimes; // Needed for parsing; + + rwyList = other.rwyList; + rwyGroup = other.rwyGroup; + PreferenceListConstIterator i; + for (i = other.preferences.begin(); i != other.preferences.end(); i++) + preferences.push_back(*i); +} + +FGRunwayPreference & FGRunwayPreference::operator= (const FGRunwayPreference &other) +{ + initialized = other.initialized; + value = other.value; + scheduleName = other.scheduleName; + + comTimes = other.comTimes; // Commercial Traffic; + genTimes = other.genTimes; // General Aviation; + milTimes = other.milTimes; // Military Traffic; + currTimes= other.currTimes; // Needed for parsing; + + rwyList = other.rwyList; + rwyGroup = other.rwyGroup; + PreferenceListConstIterator i; + preferences.clear(); + for (i = other.preferences.begin(); i != other.preferences.end(); i++) + preferences.push_back(*i); + return *this; +} + +ScheduleTime *FGRunwayPreference::getSchedule(const char *trafficType) +{ + if (!(strcmp(trafficType, "com"))) { + return &comTimes; + } + if (!(strcmp(trafficType, "gen"))) { + return &genTimes; + } + if (!(strcmp(trafficType, "mil"))) { + return &milTimes; + } +} + +RunwayGroup *FGRunwayPreference::getGroup(const string groupName) +{ + PreferenceListIterator i = preferences.begin(); + if (preferences.begin() == preferences.end()) + return 0; + while (!(i == preferences.end() || i->getName() == groupName)) + i++; + if (i != preferences.end()) + return &(*i); + else + return 0; +} + +void FGRunwayPreference::startXML () { + // cout << "Start XML" << endl; +} + +void FGRunwayPreference::endXML () { + cout << "End XML" << endl; +} + +void FGRunwayPreference::startElement (const char * name, const XMLAttributes &atts) { + //cout << "StartElement " << name << endl; + value = string(""); + if (!(strcmp(name, "wind"))) { + //cerr << "Will be processing Wind" << endl; + for (int i = 0; i < atts.size(); i++) + { + //cout << " " << atts.getName(i) << '=' << atts.getValue(i) << endl; + //attname = atts.getName(i); + if (atts.getName(i) == string("tail")) { + //cerr << "Tail Wind = " << atts.getValue(i) << endl; + currTimes.setTailWind(atof(atts.getValue(i))); + } + if (atts.getName(i) == string("cross")) { + //cerr << "Cross Wind = " << atts.getValue(i) << endl; + currTimes.setCrossWind(atof(atts.getValue(i))); + } + } + } + if (!(strcmp(name, "time"))) { + //cerr << "Will be processing time" << endl; + for (int i = 0; i < atts.size(); i++) + { + if (atts.getName(i) == string("start")) { + //cerr << "Start Time = " << atts.getValue(i) << endl; + currTimes.addStartTime(processTime(atts.getValue(i))); + } + if (atts.getName(i) == string("end")) { + //cerr << "End time = " << atts.getValue(i) << endl; + currTimes.addEndTime(processTime(atts.getValue(i))); + } + if (atts.getName(i) == string("schedule")) { + //cerr << "Schedule Name = " << atts.getValue(i) << endl; + currTimes.addScheduleName(atts.getValue(i)); + } + } + } + if (!(strcmp(name, "takeoff"))) { + rwyList.clear(); + } + if (!(strcmp(name, "landing"))) + { + rwyList.clear(); + } + if (!(strcmp(name, "schedule"))) { + for (int i = 0; i < atts.size(); i++) + { + //cout << " " << atts.getName(i) << '=' << atts.getValue(i) << endl; + //attname = atts.getName(i); + if (atts.getName(i) == string("name")) { + //cerr << "Schedule name = " << atts.getValue(i) << endl; + scheduleName = atts.getValue(i); + } + } + } +} + +//based on a string containing hour and minute, return nr seconds since day start. +time_t FGRunwayPreference::processTime(string tme) +{ + string hour = tme.substr(0, tme.find(":",0)); + string minute = tme.substr(tme.find(":",0)+1, tme.length()); + + //cerr << "hour = " << hour << " Minute = " << minute << endl; + return (atoi(hour.c_str()) * 3600 + atoi(minute.c_str()) * 60); +} + +void FGRunwayPreference::endElement (const char * name) { + //cout << "End element " << name << endl; + if (!(strcmp(name, "rwyuse"))) { + initialized = true; + } + if (!(strcmp(name, "com"))) { // Commercial Traffic + //cerr << "Setting time table for commerical traffic" << endl; + comTimes = currTimes; + currTimes.clear(); + } + if (!(strcmp(name, "gen"))) { // General Aviation + //cerr << "Setting time table for general aviation" << endl; + genTimes = currTimes; + currTimes.clear(); + } + if (!(strcmp(name, "mil"))) { // Military Traffic + //cerr << "Setting time table for military traffic" << endl; + genTimes = currTimes; + currTimes.clear(); + } + + if (!(strcmp(name, "takeoff"))) { + //cerr << "Adding takeoff: " << value << endl; + rwyList.set(name, value); + rwyGroup.add(rwyList); + } + if (!(strcmp(name, "landing"))) { + //cerr << "Adding landing: " << value << endl; + rwyList.set(name, value); + rwyGroup.add(rwyList); + } + if (!(strcmp(name, "schedule"))) { + //cerr << "Adding schedule" << scheduleName << endl; + rwyGroup.setName(scheduleName); + //rwyGroup.addRunways(rwyList); + preferences.push_back(rwyGroup); + rwyGroup.clear(); + //exit(1); + } +} + +void FGRunwayPreference::data (const char * s, int len) { + string token = string(s,len); + //cout << "Character data " << string(s,len) << endl; + //if ((token.find(" ") == string::npos && (token.find('\n')) == string::npos)) + // value += token; + //else + // value = string(""); + value += token; +} + +void FGRunwayPreference::pi (const char * target, const char * data) { + //cout << "Processing instruction " << target << ' ' << data << endl; +} + +void FGRunwayPreference::warning (const char * message, int line, int column) { + cout << "Warning: " << message << " (" << line << ',' << column << ')' + << endl; +} + +void FGRunwayPreference::error (const char * message, int line, int column) { + cout << "Error: " << message << " (" << line << ',' << 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) +{ + string prefix; + string subs; + string degree; + string decimal; + int sign = 1; + double value; + subs = pos; + prefix= subs.substr(0,1); + if (prefix == string("S") || (prefix == string("W"))) + sign = -1; + subs = subs.substr(1, subs.length()); + degree = subs.substr(0, subs.find(" ",0)); + decimal = subs.substr(subs.find(" ",0), subs.length()); + + + //cerr << sign << " "<< degree << " " << decimal << endl; + value = sign * (atof(degree.c_str()) + atof(decimal.c_str())/60.0); + //cerr << value <getIndex() + // << " Type : " << i->getType() + // << " Codes : " << i->getCodes() + // << " Radius: " << i->getRadius() + // << " Name : " << i->getName() + // << " Available: " << i->isAvailable() << endl; + available = true; + // Taken by another aircraft + if (!(i->isAvailable())) + { + available = false; + continue; + } + // No airline codes, so skip + if (i->getCodes().empty()) + { + available = false; + continue; + } + else // Airline code doesn't match + if (i->getCodes().find(airline, 0) == string::npos) + { + available = false; + continue; + } + // Type doesn't match + if (i->getType() != flType) + { + available = false; + continue; + } + // too small + if (i->getRadius() < rad) + { + available = false; + continue; + } + + if (available) + { + *lat = i->getLatitude (); + *lon = i->getLongitude(); + *heading = i->getHeading (); + *gateId = i->getIndex (); + i->setAvailable(false); + found = true; + } + } + // then try again for those without codes. + for (i = parkings.begin(); !(i == parkings.end() || found); i++) + { + available = true; + if (!(i->isAvailable())) + { + available = false; + continue; + } + if (!(i->getCodes().empty())) + { + if ((i->getCodes().find(airline,0) == string::npos)) + { + available = false; + continue; + } + } + if (i->getType() != flType) + { + available = false; + continue; + } + + if (i->getRadius() < rad) + { + available = false; + continue; + } + + if (available) + { + *lat = i->getLatitude (); + *lon = i->getLongitude(); + *heading = i->getHeading (); + *gateId = i->getIndex (); + i->setAvailable(false); + found = true; + } + } + // And finally once more if that didn't work. Now ignore the airline codes, as a last resort + for (i = parkings.begin(); !(i == parkings.end() || found); i++) + { + available = true; + if (!(i->isAvailable())) + { + available = false; + continue; + } + if (i->getType() != flType) + { + available = false; + continue; + } + + if (i->getRadius() < rad) + { + available = false; + continue; + } + + if (available) + { + *lat = i->getLatitude (); + *lon = i->getLongitude(); + *heading = i->getHeading (); + *gateId = i->getIndex (); + i->setAvailable(false); + found = true; + } + } + } + if (!found) + { + //cerr << "Traffic overflow at" << _id + // << ". flType = " << flType + // << ". airline = " << airline + // << " Radius = " <getIndex()) + { + *lat = i->getLatitude(); + *lon = i->getLongitude(); + *heading = i->getLongitude(); + } + } + } +} + +FGParking *FGAirport::getParking(int i) +{ + if (i < parkings.size()) + return &(parkings[i]); + else + return 0; +} +string FGAirport::getParkingName(int i) +{ + if (i < parkings.size() && i >= 0) + return (parkings[i].getName()); + else + return string("overflow"); +} +void FGAirport::releaseParking(int id) +{ + if (id >= 0) + { + + FGParkingVecIterator i = parkings.begin(); + for (i = parkings.begin(); i != parkings.end(); i++) + { + if (id == i->getIndex()) + { + i -> setAvailable(true); + } + } + } +} + +void FGAirport::startXML () { + //cout << "Start XML" << endl; +} + +void FGAirport::endXML () { + //cout << "End XML" << endl; +} + +void FGAirport::startElement (const char * name, const XMLAttributes &atts) { + const char * attval; + FGParking park; + //cout << "Start element " << name << endl; + string attname; + string value; + string gateName; + string gateNumber; + string lat; + string lon; + if (name == string("Parking")) + { + for (int i = 0; i < atts.size(); i++) + { + //cout << " " << atts.getName(i) << '=' << atts.getValue(i) << endl; + attname = atts.getName(i); + if (attname == string("index")) + park.setIndex(atoi(atts.getValue(i))); + else if (attname == string("type")) + park.setType(atts.getValue(i)); + else if (attname == string("name")) + gateName = atts.getValue(i); + else if (attname == string("number")) + gateNumber = atts.getValue(i); + else if (attname == string("lat")) + park.setLatitude(atts.getValue(i)); + else if (attname == string("lon")) + park.setLongitude(atts.getValue(i)); + else if (attname == string("heading")) + park.setHeading(atof(atts.getValue(i))); + else if (attname == string("radius")) { + string radius = atts.getValue(i); + if (radius.find("M") != string::npos) + radius = radius.substr(0, radius.find("M",0)); + //cerr << "Radius " << radius < 600) || trafficType != prevTrafficType) + { + landing.clear(); + takeoff.clear(); + //lastUpdate = dayStart; + prevTrafficType = trafficType; + + FGEnvironment + stationweather = ((FGEnvironmentMgr *) globals->get_subsystem("environment")) + ->getEnvironment(getLatitude(), + getLongitude(), + getElevation()); + + windSpeed = stationweather.get_wind_speed_kt(); + windHeading = stationweather.get_wind_from_heading_deg(); + double averageWindSpeed = 0; + double averageWindHeading = 0; + double cosHeading = 0; + double sinHeading = 0; + // Initialize at the beginning of the next day or startup + if ((lastUpdate == 0) || (dayStart < lastUpdate)) + { + for (int i = 0; i < 10; i++) + { + avWindHeading [i] = windHeading; + avWindSpeed [i] = windSpeed; + } + } + else + { + if (windSpeed != avWindSpeed[9]) // update if new metar data + { + // shift the running average + for (int i = 0; i < 9 ; i++) + { + avWindHeading[i] = avWindHeading[i+1]; + avWindSpeed [i] = avWindSpeed [i+1]; + } + } + avWindHeading[9] = windHeading; + avWindSpeed [9] = windSpeed; + } + + for (int i = 0; i < 10; i++) + { + averageWindSpeed += avWindSpeed [i]; + //averageWindHeading += avWindHeading [i]; + cosHeading += cos(avWindHeading[i] * SG_DEGREES_TO_RADIANS); + sinHeading += sin(avWindHeading[i] * SG_DEGREES_TO_RADIANS); + } + averageWindSpeed /= 10; + //averageWindHeading /= 10; + cosHeading /= 10; + sinHeading /= 10; + averageWindHeading = atan2(sinHeading, cosHeading) *SG_RADIANS_TO_DEGREES; + if (averageWindHeading < 0) + averageWindHeading += 360.0; + //cerr << "Wind Heading " << windHeading << " average " << averageWindHeading << endl; + //cerr << "Wind Speed " << windSpeed << " average " << averageWindSpeed << endl; + lastUpdate = dayStart; + //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 scheduleName; + //cerr << "finding active Runway for" << _id << endl; + //cerr << "Nr of seconds since day start << " << dayStart << endl; + ScheduleTime *currSched; + //cerr << "A"<< endl; + currSched = rwyPrefs.getSchedule(trafficType.c_str()); + if (!(currSched)) + return; + //cerr << "B"<< endl; + scheduleName = currSched->getName(dayStart); + maxTail = currSched->getTailWind (); + maxCross = currSched->getCrossWind (); + //cerr << "SChedule anme = " << scheduleName << endl; + if (scheduleName.empty()) + return; + //cerr << "C"<< endl; + currRunwayGroup = rwyPrefs.getGroup(scheduleName); + //cerr << "D"<< endl; + if (!(currRunwayGroup)) + return; + nrActiveRunways = currRunwayGroup->getNrActiveRunways(); + //cerr << "Nr of Active Runways = " << nrActiveRunways << endl; + currRunwayGroup->setActive(_id, averageWindSpeed, averageWindHeading, maxTail, maxCross); + nrActiveRunways = currRunwayGroup->getNrActiveRunways(); + for (int i = 0; i < nrActiveRunways; i++) + { + type = "unknown"; // initialize to something other than landing or takeoff + currRunwayGroup->getActive(i, &name, &type); + if (type == "landing") + { + landing.push_back(name); + //cerr << "Landing " << name << endl; + } + if (type == "takeoff") + { + takeoff.push_back(name); + //cerr << "takeoff " << name << endl; + } + } + } + if (action == 1) // takeoff + { + int nr = takeoff.size(); + if (nr) + { + *runway = takeoff[(rand() % nr)]; + } + else + { // Fallback + chooseRunwayFallback(runway); + } + } + if (action == 2) // landing + { + int nr = landing.size(); + if (nr) + { + *runway = landing[(rand() % nr)]; + } + else + { //fallback + chooseRunwayFallback(runway); + } + } + + //*runway = globals->get_runways()->search(_id, int(windHeading)); + //cerr << "Seleceted runway: " << *runway << endl; + } +} + +void FGAirport::chooseRunwayFallback(string *runway) +{ + FGEnvironment + stationweather = ((FGEnvironmentMgr *) globals->get_subsystem("environment")) + ->getEnvironment(getLatitude(), + getLongitude(), + getElevation()); + + double windSpeed = stationweather.get_wind_speed_kt(); + double windHeading = stationweather.get_wind_from_heading_deg(); + if (windSpeed == 0) { + windHeading = 270; // This forces West-facing rwys to be used in no-wind situations + //which is consistent with Flightgear's initial setup. + } + + *runway = globals->get_runways()->search(_id, int(windHeading)); + return; // generic fall back goes here +} + +/****************************************************************************** + * FGAirportList + *****************************************************************************/ + // add an entry to the list void FGAirportList::add( const string id, const double longitude, const double latitude, const double elevation, const string name, const bool has_metar ) { - FGAirport a; - a._id = id; - a._longitude = longitude; - a._latitude = latitude; - a._elevation = elevation; - a._name = name; - a._has_metar = has_metar; - airports_by_id[a._id] = a; - airports_array.push_back( &airports_by_id[a._id] ); + FGRunwayPreference rwyPrefs; + FGAirport a(id, longitude, latitude, elevation, name, has_metar); + //a._id = id; + //a._longitude = longitude; + //a._latitude = latitude; + //a._elevation = elevation; + //a._name = name; + //a._has_metar = has_metar; + SGPath parkpath( globals->get_fg_root() ); + parkpath.append( "/Airports/AI/" ); + parkpath.append(id); + parkpath.append("parking.xml"); + + SGPath rwyPrefPath( globals->get_fg_root() ); + rwyPrefPath.append( "/Airports/AI/" ); + rwyPrefPath.append(id); + rwyPrefPath.append("rwyuse.xml"); + if (parkpath.exists()) + { + try { + readXML(parkpath.str(),a); + } + catch (const sg_exception &e) { + //cerr << "unable to read " << parkpath.str() << endl; + } + } + if (rwyPrefPath.exists()) + { + try { + readXML(rwyPrefPath.str(), rwyPrefs); + a.setRwyUse(rwyPrefs); + } + catch (const sg_exception &e) { + //cerr << "unable to read " << rwyPrefPath.str() << endl; + //exit(1); + } + } + + airports_by_id[a.getId()] = a; + // try and read in an auxilary file + + airports_array.push_back( &airports_by_id[a.getId()] ); SG_LOG( SG_GENERAL, SG_BULK, "Adding " << id << " pos = " << longitude << ", " << latitude << " elev = " << elevation ); } @@ -64,6 +1198,12 @@ FGAirport FGAirportList::search( const string& id) { return airports_by_id[id]; } +// search for the specified id and return a pointer +FGAirport* FGAirportList::search( const string& id, FGAirport *result) { + FGAirport* retval = airports_by_id[id].getAddress(); + //cerr << "Returning Airport of string " << id << " results in " << retval->getId(); + return retval; +} // search for the airport nearest the specified position FGAirport FGAirportList::search( double lon_deg, double lat_deg, @@ -73,10 +1213,10 @@ FGAirport FGAirportList::search( double lon_deg, double lat_deg, unsigned int i; for ( i = 0; i < airports_array.size(); ++i ) { // crude manhatten distance based on lat/lon difference - double d = fabs(lon_deg - airports_array[i]->_longitude) - + fabs(lat_deg - airports_array[i]->_latitude); + double d = fabs(lon_deg - airports_array[i]->getLongitude()) + + fabs(lat_deg - airports_array[i]->getLatitude()); if ( d < min_dist ) { - if ( !with_metar || (with_metar&&airports_array[i]->_has_metar) ) { + if ( !with_metar || (with_metar&&airports_array[i]->getMetar()) ) { closest = i; min_dist = d; } @@ -107,7 +1247,7 @@ const FGAirport *FGAirportList::getAirport( int index ) const * Mark the specified airport record as not having metar */ void FGAirportList::no_metar( const string &id ) { - airports_by_id[id]._has_metar = false; + airports_by_id[id].setMetar(false); } @@ -115,5 +1255,5 @@ void FGAirportList::no_metar( const string &id ) { * Mark the specified airport record as (yes) having metar */ void FGAirportList::has_metar( const string &id ) { - airports_by_id[id]._has_metar = true; + airports_by_id[id].setMetar(true); } diff --git a/src/Airports/simple.hxx b/src/Airports/simple.hxx index 4cb19528e..40eed9758 100644 --- a/src/Airports/simple.hxx +++ b/src/Airports/simple.hxx @@ -3,6 +3,7 @@ // elevation in feet. // // Written by Curtis Olson, started April 1998. +// Updated by Durk Talsma, started December 2004. // // Copyright (C) 1998 Curtis L. Olson - http://www.flightgear.org/~curt // @@ -37,6 +38,7 @@ #endif #include +#include #include STL_STRING #include @@ -46,17 +48,249 @@ SG_USING_STD(string); SG_USING_STD(map); SG_USING_STD(vector); +typedef vector stringVec; +typedef vector::iterator stringVecIterator; +typedef vector::const_iterator stringVecConstIterator; -struct FGAirport { - string _id; - double _longitude; - double _latitude; - double _elevation; - string _code; // depricated and can be removed - string _name; - bool _has_metar; +typedef vector timeVec; +typedef vector::const_iterator timeVecConstIterator; +/***************************************************************************/ +class ScheduleTime { +private: + timeVec start; + timeVec end; + stringVec scheduleNames; + double tailWind; + double crssWind; +public: + ScheduleTime() {}; + ScheduleTime(const ScheduleTime &other); + ScheduleTime &operator= (const ScheduleTime &other); + string getName(time_t dayStart); - FGAirport() : _longitude(0), _latitude(0), _elevation(0) {} + void clear(); + void addStartTime(time_t time) { start.push_back(time); }; + void addEndTime (time_t time) { end. push_back(time); }; + void addScheduleName(string sched) { scheduleNames.push_back(sched); }; + void setTailWind(double wnd) { tailWind = wnd; }; + void setCrossWind(double wnd) { tailWind = wnd; }; + + double getTailWind() { return tailWind; }; + double getCrossWind() { return crssWind; }; +}; + +//typedef vector ScheduleTimes; +/*****************************************************************************/ + +class RunwayList +{ +private: + string type; + stringVec preferredRunways; +public: + RunwayList() {}; + RunwayList(const RunwayList &other); + RunwayList& operator= (const RunwayList &other); + + void set(string, string); + void clear(); + + string getType() { return type; }; + stringVec *getRwyList() { return &preferredRunways; }; + string getRwyList(int j) { return preferredRunways[j]; }; +}; + +typedef vector RunwayListVec; +typedef vector::iterator RunwayListVectorIterator; +typedef vector::const_iterator RunwayListVecConstIterator; + + +/*****************************************************************************/ + +class RunwayGroup +{ +private: + string name; + RunwayListVec rwyList; + int active; + //stringVec runwayNames; + int choice[2]; + int nrActive; +public: + RunwayGroup() {}; + RunwayGroup(const RunwayGroup &other); + RunwayGroup &operator= (const RunwayGroup &other); + + void setName(string nm) { name = nm; }; + void add(RunwayList list) { rwyList.push_back(list);}; + void setActive(string aptId, double windSpeed, double windHeading, double maxTail, double maxCross); + + int getNrActiveRunways() { return nrActive;}; + void getActive(int i, string *name, string *type); + + string getName() { return name; }; + void clear() { rwyList.clear(); }; + //void add(string, string); +}; + +typedef vector PreferenceList; +typedef vector::iterator PreferenceListIterator; +typedef vector::const_iterator PreferenceListConstIterator; +/******************************************************************************/ + +class FGRunwayPreference : public XMLVisitor { +private: + string value; + string scheduleName; + + ScheduleTime comTimes; // Commercial Traffic; + ScheduleTime genTimes; // General Aviation; + ScheduleTime milTimes; // Military Traffic; + ScheduleTime currTimes; // Needed for parsing; + + RunwayList rwyList; + RunwayGroup rwyGroup; + PreferenceList preferences; + + time_t processTime(string); + bool initialized; + +public: + FGRunwayPreference(); + FGRunwayPreference(const FGRunwayPreference &other); + + FGRunwayPreference & operator= (const FGRunwayPreference &other); + ScheduleTime *getSchedule(const char *trafficType); + RunwayGroup *getGroup(const string groupName); + bool available() { return initialized; }; + + // Some overloaded virtual XMLVisitor members + virtual void startXML (); + virtual void endXML (); + virtual void startElement (const char * name, const XMLAttributes &atts); + virtual void endElement (const char * name); + virtual void data (const char * s, int len); + virtual void pi (const char * target, const char * data); + virtual void warning (const char * message, int line, int column); + virtual void error (const char * message, int line, int column); +}; + +class FGParking { +private: + double latitude; + double longitude; + double heading; + double radius; + int index; + string parkingName; + string type; + string airlineCodes; + + + bool available; + + double processPosition(string pos); + +public: + FGParking() { available = true;}; + //FGParking(FGParking &other); + FGParking(double lat, + double lon, + double hdg, + double rad, + int idx, + string name, + string tpe, + string codes); + void setLatitude (string lat) { latitude = processPosition(lat); }; + void setLongitude(string lon) { longitude = processPosition(lon); }; + void setHeading (double hdg) { heading = hdg; }; + void setRadius (double rad) { radius = rad; }; + void setIndex (int idx) { index = idx; }; + void setName (string name) { parkingName = name; }; + void setType (string tpe) { type = tpe; }; + void setCodes (string codes){ airlineCodes= codes;}; + + bool isAvailable () { return available;}; + void setAvailable(bool val) { available = val; }; + + double getLatitude () { return latitude; }; + double getLongitude() { return longitude; }; + double getHeading () { return heading; }; + double getRadius () { return radius; }; + int getIndex () { return index; }; + string getType () { return type; }; + string getCodes () { return airlineCodes;}; + string getName () { return parkingName; }; + + bool operator< (const FGParking &other) const {return radius < other.radius; }; +}; + +typedef vector FGParkingVec; +typedef vector::iterator FGParkingVecIterator; +typedef vector::const_iterator FGParkingVecConstIterator; + + +class FGAirport : public XMLVisitor{ +private: + string _id; + double _longitude; + double _latitude; + double _elevation; + string _code; // depricated and can be removed + string _name; + bool _has_metar; + FGParkingVec parkings; + FGRunwayPreference rwyPrefs; + + time_t lastUpdate; + string prevTrafficType; + stringVec landing; + stringVec takeoff; + + // Experimental keep a running average of wind dir and speed to prevent + // Erratic runway changes. + // Note: I should add these to the copy constructor and assigment operator to be + // constistent + double avWindHeading [10]; + double avWindSpeed [10]; + +public: + FGAirport(); + FGAirport(const FGAirport &other); + //operator= (FGAirport &other); + FGAirport(string id, double lon, double lat, double elev, string name, bool has_metar); + 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, + string acType, string airline); + void getParking (int id, double *lat, double* lon, double *heading); + FGParking *getParking(int i); // { if (i < parkings.size()) return parkings[i]; else return 0;}; + void releaseParking(int id); + string getParkingName(int i); + const string getId() const { return _id;}; + const string &getName() const { return _name;}; + FGAirport *getAddress() { return this; }; + double getLongitude() { return _longitude;}; + double getLatitude() { return _latitude; }; + double getElevation() { return _elevation;}; + bool getMetar() { return _has_metar;}; + + + void setId(string id) { _id = id;}; + void setMetar(bool value) { _has_metar = value; }; + + void setRwyUse(FGRunwayPreference& ref); + + // Some overloaded virtual XMLVisitor members + virtual void startXML (); + virtual void endXML (); + virtual void startElement (const char * name, const XMLAttributes &atts); + virtual void endElement (const char * name); + virtual void data (const char * s, int len); + virtual void pi (const char * target, const char * data); + virtual void warning (const char * message, int line, int column); + virtual void error (const char * message, int line, int column); }; typedef map < string, FGAirport > airport_map; @@ -97,6 +331,8 @@ public: // return station id's marked as having metar data. FGAirport search( double lon_deg, double lat_deg, bool with_metar ); + // search and return a pointer; + FGAirport* search( const string& id, FGAirport *result); /** * Return the number of airports in the list. diff --git a/src/Autopilot/auto_gui.cxx b/src/Autopilot/auto_gui.cxx index 38ddeb215..f328d49b8 100644 --- a/src/Autopilot/auto_gui.cxx +++ b/src/Autopilot/auto_gui.cxx @@ -668,7 +668,7 @@ int NewWaypoint( string Tgt_Alt ) sprintf( NewTgtAirportId, "%s", TgtAptId.c_str() ); - SGWayPoint wp( a._longitude, a._latitude, alt, + SGWayPoint wp( a.getLongitude(), a.getLatitude(), alt, SGWayPoint::WGS84, TgtAptId ); rm->add_waypoint( wp ); diff --git a/src/Environment/environment_ctrl.cxx b/src/Environment/environment_ctrl.cxx index d426d0e6e..21fb708e6 100644 --- a/src/Environment/environment_ctrl.cxx +++ b/src/Environment/environment_ctrl.cxx @@ -399,11 +399,11 @@ FGMetarEnvironmentCtrl::init () ->search( longitude->getDoubleValue(), latitude->getDoubleValue(), true ); - FGMetarResult result = fetch_data( a._id ); + FGMetarResult result = fetch_data( a.getId() ); if ( result.m != NULL ) { - SG_LOG( SG_GENERAL, SG_INFO, "closest station w/ metar = " << a._id); + SG_LOG( SG_GENERAL, SG_INFO, "closest station w/ metar = " << a.getId()); last_apt = a; - _icao = a._id; + _icao = a.getId(); search_elapsed = 0.0; fetch_elapsed = 0.0; update_metar_properties( result.m ); @@ -413,8 +413,8 @@ FGMetarEnvironmentCtrl::init () } else { // mark as no metar so it doesn't show up in subsequent // searches. - SG_LOG( SG_GENERAL, SG_INFO, "no metar at metar = " << a._id ); - globals->get_airports()->no_metar( a._id ); + SG_LOG( SG_GENERAL, SG_INFO, "no metar at metar = " << a.getId() ); + globals->get_airports()->no_metar( a.getId() ); } } } @@ -456,13 +456,13 @@ FGMetarEnvironmentCtrl::update(double delta_time_sec) ->search( longitude->getDoubleValue(), latitude->getDoubleValue(), true ); - if ( last_apt._id != a._id + if ( last_apt.getId() != a.getId() || fetch_elapsed > same_station_interval_sec ) { - SG_LOG( SG_GENERAL, SG_INFO, "closest station w/ metar = " << a._id); - request_queue.push( a._id ); + SG_LOG( SG_GENERAL, SG_INFO, "closest station w/ metar = " << a.getId()); + request_queue.push( a.getId() ); last_apt = a; - _icao = a._id; + _icao = a.getId(); search_elapsed = 0.0; fetch_elapsed = 0.0; } else { @@ -534,7 +534,7 @@ FGMetarEnvironmentCtrl::fetch_data( const string &icao ) // fetch station elevation if exists FGAirport a = globals->get_airports()->search( icao ); - station_elevation_ft = a._elevation; + station_elevation_ft = a.getElevation(); // fetch current metar data try { diff --git a/src/GUI/AirportList.cxx b/src/GUI/AirportList.cxx index 88d77494d..16f9785d0 100644 --- a/src/GUI/AirportList.cxx +++ b/src/GUI/AirportList.cxx @@ -18,8 +18,8 @@ AirportList::AirportList (int x, int y, int width, int height) for (int i = 0; i < _nAirports; i++) { const FGAirport *airport = _airports->getAirport(i); snprintf(buf, 1023, "%s %s", - airport->_id.c_str(), - airport->_name.c_str()); + airport->getId().c_str(), + airport->getName().c_str()); unsigned int buf_len = (strlen(buf) > 1023) ? 1023 : strlen(buf); @@ -43,7 +43,7 @@ AirportList::~AirportList () char * AirportList::getListStringValue () { - return (char *)_airports->getAirport(getListIntegerValue())->_id.c_str(); + return (char *)_airports->getAirport(getListIntegerValue())->getId().c_str(); } // end of AirportList.cxx diff --git a/src/GUI/Makefile.am b/src/GUI/Makefile.am index e6979c0b7..9e587fdf7 100644 --- a/src/GUI/Makefile.am +++ b/src/GUI/Makefile.am @@ -22,4 +22,4 @@ layout_test_SOURCES = layout-test.cxx layout_test_LDADD = libGUI.a \ -lsgprops -lsgdebug -lsgstructure -lsgmisc -lsgxml \ - -lplibpw -lplibpu -lplibfnt -lplibul $(opengl_LIBS) \ No newline at end of file + -lplibpw -lplibpu -lplibfnt -lplibul $(opengl_LIBS) diff --git a/src/Instrumentation/gps.cxx b/src/Instrumentation/gps.cxx index e1fe6077b..83dbac7e4 100644 --- a/src/Instrumentation/gps.cxx +++ b/src/Instrumentation/gps.cxx @@ -325,12 +325,12 @@ GPS::update (double delta_time_sec) FGAirport a; //cout << "Airport found" << endl; a = globals->get_airports()->search(longitude_deg, latitude_deg, false); - _wp1_ID_node->setStringValue(a._id.c_str()); - wp1_longitude_deg = a._longitude; - wp1_latitude_deg = a._latitude; - _wp1_name_node->setStringValue(a._name.c_str()); + _wp1_ID_node->setStringValue(a.getId().c_str()); + wp1_longitude_deg = a.getLongitude(); + wp1_latitude_deg = a.getLatitude(); + _wp1_name_node->setStringValue(a.getName().c_str()); _get_nearest_airport_node->setBoolValue(false); - _last_wp1_ID = wp1_ID = a._id.c_str(); + _last_wp1_ID = wp1_ID = a.getId().c_str(); } // If the waypoint 0 ID has changed, try to find the new ID @@ -341,11 +341,11 @@ GPS::update (double delta_time_sec) if (waypont_type == "airport") { FGAirport a; a = globals->get_airports()->search( wp0_ID ); - if ( a._id == wp0_ID ) { + if ( a.getId() == wp0_ID ) { //cout << "Airport found" << endl; - wp0_longitude_deg = a._longitude; - wp0_latitude_deg = a._latitude; - _wp0_name_node->setStringValue(a._name.c_str()); + wp0_longitude_deg = a.getLongitude(); + wp0_latitude_deg = a.getLatitude(); + _wp0_name_node->setStringValue(a.getName().c_str()); } } else if (waypont_type == "nav") { @@ -380,11 +380,11 @@ GPS::update (double delta_time_sec) if (waypont_type == "airport") { FGAirport a; a = globals->get_airports()->search( wp1_ID ); - if ( a._id == wp1_ID ) { + if ( a.getId() == wp1_ID ) { //cout << "Airport found" << endl; - wp1_longitude_deg = a._longitude; - wp1_latitude_deg = a._latitude; - _wp1_name_node->setStringValue(a._name.c_str()); + wp1_longitude_deg = a.getLongitude(); + wp1_latitude_deg = a.getLatitude(); + _wp1_name_node->setStringValue(a.getName().c_str()); } } else if (waypont_type == "nav") { diff --git a/src/Main/fg_init.cxx b/src/Main/fg_init.cxx index 924b1b8cf..176220ba6 100644 --- a/src/Main/fg_init.cxx +++ b/src/Main/fg_init.cxx @@ -636,7 +636,7 @@ bool fgFindAirportID( const string& id, FGAirport *a ) { result = globals->get_airports()->search( id ); - if ( result._id.empty() ) { + if ( result.getId().empty() ) { SG_LOG( SG_GENERAL, SG_ALERT, "Failed to find " << id << " in basic.dat.gz" ); return false; @@ -649,8 +649,8 @@ bool fgFindAirportID( const string& id, FGAirport *a ) { SG_LOG( SG_GENERAL, SG_INFO, "Position for " << id << " is (" - << a->_longitude << ", " - << a->_latitude << ")" ); + << a->getLongitude() << ", " + << a->getLatitude() << ")" ); return true; } @@ -665,7 +665,7 @@ static double fgGetAirportElev( const string& id ) { "Finding elevation for airport: " << id ); if ( fgFindAirportID( id, &a ) ) { - return a._elevation; + return a.getElevation(); } else { return -9999.0; } @@ -718,9 +718,9 @@ static bool fgSetTowerPosFromAirportID( const string& id, double hdg ) { float fudge_lat = .003f - fudge_lon; if ( fgFindAirportID( id, &a ) ) { - fgSetDouble("/sim/tower/longitude-deg", a._longitude + fudge_lon); - fgSetDouble("/sim/tower/latitude-deg", a._latitude + fudge_lat); - fgSetDouble("/sim/tower/altitude-ft", a._elevation + towerheight); + fgSetDouble("/sim/tower/longitude-deg", a.getLongitude() + fudge_lon); + fgSetDouble("/sim/tower/latitude-deg", a.getLatitude() + fudge_lat); + fgSetDouble("/sim/tower/altitude-ft", a.getElevation() + towerheight); return true; } else { return false; @@ -1715,11 +1715,11 @@ bool fgInitSubsystems() { globals->add_subsystem("Traffic Manager", new FGTrafficManager); FGTrafficManager *dispatcher = (FGTrafficManager*) globals->get_subsystem("Traffic Manager"); - SGPath path =globals->get_fg_root(); - path.append("Traffic/fgtraffic.xml"); + SGPath path = globals->get_fg_root(); + path.append("/Traffic/fgtraffic.xml"); readXML(path.str(), - *dispatcher); - globals->get_subsystem("Traffic Manager")->init(); + *dispatcher); + //globals->get_subsystem("Traffic Manager")->init(); globals->add_subsystem("instrumentation", new FGInstrumentMgr); globals->add_subsystem("systems", new FGSystemMgr); diff --git a/src/Navaids/navdb.cxx b/src/Navaids/navdb.cxx index 1595e7a69..22cac4f03 100644 --- a/src/Navaids/navdb.cxx +++ b/src/Navaids/navdb.cxx @@ -96,8 +96,8 @@ bool fgNavDBInit( FGAirportList *airports, // cout << r->get_type() << " " << r->get_apt_id() << " zero elev" // << endl; FGAirport a = airports->search( r->get_apt_id() ); - if ( a._id == r->get_apt_id() ) { - r->set_elev_ft( a._elevation ); + if ( a.getId() == r->get_apt_id() ) { + r->set_elev_ft( a.getElevation() ); // cout << " setting to " << a.elevation << endl; } } diff --git a/src/Traffic/SchedFlight.cxx b/src/Traffic/SchedFlight.cxx index 245d3db0c..e02f54f87 100644 --- a/src/Traffic/SchedFlight.cxx +++ b/src/Traffic/SchedFlight.cxx @@ -81,6 +81,8 @@ FGScheduledFlight::FGScheduledFlight(const FGScheduledFlight &other) callsign = other.callsign; fltRules = other.fltRules; departurePort = other.departurePort; + depId = other.depId; + arrId = other.arrId; departureTime = other.departureTime; cruiseAltitude = other.cruiseAltitude; arrivalPort = other.arrivalPort; @@ -100,8 +102,11 @@ FGScheduledFlight::FGScheduledFlight(string cs, { callsign = cs; fltRules = fr; - departurePort._id = depPrt; - arrivalPort._id = arrPrt; + //departurePort.setId(depPrt); + //arrivalPort.setId(arrPrt); + depId = depPrt; + arrId = arrPrt; + //cerr << "Constructor: departure " << depId << ". arrival " << arrId << endl; //departureTime = processTimeString(deptime); //arrivalTime = processTimeString(arrtime); cruiseAltitude = cruiseAlt; @@ -225,7 +230,10 @@ FGAirport *FGScheduledFlight::getDepartureAirport() { initializeAirports(); } - return &departurePort; + if (initialized) + return departurePort; + else + return 0; } FGAirport * FGScheduledFlight::getArrivalAirport () { @@ -233,7 +241,10 @@ FGAirport * FGScheduledFlight::getArrivalAirport () { initializeAirports(); } - return &arrivalPort; + if (initialized) + return arrivalPort; + else + return 0; } // Upon the first time of requesting airport information @@ -243,15 +254,24 @@ FGAirport * FGScheduledFlight::getArrivalAirport () // but we should improve that. The best idea is probably to cancel // this flight entirely by removing it from the schedule, if one // of the airports cannot be found. -void FGScheduledFlight::initializeAirports() +bool FGScheduledFlight::initializeAirports() { - if(!(fgFindAirportID(arrivalPort._id, &arrivalPort ))) + //cerr << "Initializing using : " << depId << " " << arrId << endl; + departurePort = globals->get_airports()->search( depId, departurePort ); + if(departurePort->getId().empty()) { - //cerr << ": Could not find " << arrivalPort.id << endl; + cerr << "Could not find " << depId << endl; + return false; } - if(!(fgFindAirportID(departurePort._id, &departurePort))) + arrivalPort = globals->get_airports()->search(arrId, arrivalPort); + if(arrivalPort->getId().empty()) { - //cerr << ": Could not find " << departurePort.id << endl; + cerr << "Could not find " << arrId << endl; + return false; } + + //cerr << "Found : " << departurePort->getId() << endl; + //cerr << "Found : " << arrivalPort->getId() << endl; initialized = true; + return true; } diff --git a/src/Traffic/SchedFlight.hxx b/src/Traffic/SchedFlight.hxx index 5f01f346e..2396ae84b 100644 --- a/src/Traffic/SchedFlight.hxx +++ b/src/Traffic/SchedFlight.hxx @@ -51,15 +51,17 @@ class FGScheduledFlight private: string callsign; string fltRules; - FGAirport departurePort; - FGAirport arrivalPort; + FGAirport *departurePort; + FGAirport *arrivalPort; + string depId; + string arrId; time_t departureTime; time_t arrivalTime; time_t repeatPeriod; int cruiseAltitude; bool initialized; - void initializeAirports(); + public: FGScheduledFlight(); @@ -77,6 +79,7 @@ public: ~FGScheduledFlight(); void update(); + bool initializeAirports(); void adjustTime(time_t now); @@ -94,7 +97,7 @@ public: }; time_t processTimeString(string time); - + string getCallSign() {return callsign; }; }; typedef vector FGScheduledFlightVec; diff --git a/src/Traffic/Schedule.cxx b/src/Traffic/Schedule.cxx index 0c622407e..b51a5db4e 100644 --- a/src/Traffic/Schedule.cxx +++ b/src/Traffic/Schedule.cxx @@ -65,11 +65,23 @@ FGAISchedule::FGAISchedule(string mdl, string liv, string reg, bool hvy, + string act, + string arln, + string mclass, + string fltpe, + double rad, + double grnd, FGScheduledFlightVec flt) { modelPath = mdl; livery = liv; registration = reg; + acType = act; + airline = arln; + m_class = mclass; + flightType = fltpe; + radius = rad; + groundOffset = grnd; heavy = hvy; for (FGScheduledFlightVecIterator i = flt.begin(); i != flt.end(); @@ -89,15 +101,49 @@ FGAISchedule::FGAISchedule(const FGAISchedule &other) lat = other.lat; lon = other.lon; AIManagerRef = other.AIManagerRef; + acType = other.acType; + airline = other.airline; + m_class = other.m_class; firstRun = other.firstRun; + radius = other.radius; + groundOffset = other.groundOffset; + flightType = other.flightType; + distanceToUser = other.distanceToUser; } + FGAISchedule::~FGAISchedule() { } -void FGAISchedule::update(time_t now) +bool FGAISchedule::init() +{ + //tm targetTimeDate; + //SGTime* currTimeDate = globals->get_time_params(); + + //tm *temp = currTimeDate->getGmt(); + //char buffer[512]; + //sgTimeFormatTime(&targetTimeDate, buffer); + //cout << "Scheduled Time " << buffer << endl; + //cout << "Time :" << time(NULL) << " SGTime : " << sgTimeGetGMT(temp) << endl; + for (FGScheduledFlightVecIterator i = flights.begin(); + i != flights.end(); + i++) + { + //i->adjustTime(now); + if (!(i->initializeAirports())) + return false; + } + //sort(flights.begin(), flights.end()); + // Since time isn't initialized yet when this function is called, + // Find the closest possible airport. + // This should give a reasonable initialization order. + setClosestDistanceToUser(); + return true; +} + +bool FGAISchedule::update(time_t now) { FGAirport *dep; FGAirport *arr; @@ -110,7 +156,7 @@ void FGAISchedule::update(time_t now) string airport; double courseToUser, courseToDest; - double distanceToUser, distanceToDest; + double distanceToDest; double speed; Point3D temp; @@ -123,7 +169,7 @@ void FGAISchedule::update(time_t now) userLongitude; if (fgGetBool("/sim/traffic-manager/enabled") == false) - return; + return true; aimgr = (FGAIManager *) globals-> get_subsystem("ai_model"); // Before the flight status of this traffic entity is updated @@ -142,11 +188,11 @@ void FGAISchedule::update(time_t now) if (firstRun) { for (FGScheduledFlightVecIterator i = flights.begin(); - i != flights.end(); - i++) - { - i->adjustTime(now); - } + i != flights.end(); + i++) + { + i->adjustTime(now); + } firstRun = false; } @@ -168,13 +214,13 @@ void FGAISchedule::update(time_t now) userLatitude = fgGetDouble("/position/latitude-deg"); userLongitude = fgGetDouble("/position/longitude-deg"); - + //cerr << "Estimated minimum distance to user: " << distanceToUser << endl; // This flight entry is entirely in the past, do we need to // push it forward in time to the next scheduled departure. if ((i->getDepartureTime() < now) && (i->getArrivalTime() < now)) { i->update(); - return; + return true; } // Departure time in the past and arrival time in the future. @@ -189,19 +235,21 @@ void FGAISchedule::update(time_t now) { dep = i->getDepartureAirport(); arr = i->getArrivalAirport (); + if (!(dep && arr)) + return false; - temp = sgPolarToCart3d(Point3D(dep->_longitude * + temp = sgPolarToCart3d(Point3D(dep->getLongitude() * SG_DEGREES_TO_RADIANS, - dep->_latitude * + dep->getLatitude() * SG_DEGREES_TO_RADIANS, 1.0)); a[0] = temp.x(); a[1] = temp.y(); a[2] = temp.z(); - temp = sgPolarToCart3d(Point3D(arr->_longitude * + temp = sgPolarToCart3d(Point3D(arr->getLongitude() * SG_DEGREES_TO_RADIANS, - arr->_latitude * + arr->getLatitude() * SG_DEGREES_TO_RADIANS, 1.0)); b[0] = temp.x(); @@ -219,9 +267,21 @@ void FGAISchedule::update(time_t now) // total time enroute and elapsed time enroute. totalTimeEnroute = i->getArrivalTime() - i->getDepartureTime(); - elapsedTimeEnroute = now - i->getDepartureTime(); - remainingTimeEnroute = i->getArrivalTime() - now; - + if (now > i->getDepartureTime()) + { + //err << "Lat = " << lat << ", lon = " << lon << endl; + //cerr << "Time diff: " << now-i->getDepartureTime() << endl; + elapsedTimeEnroute = now - i->getDepartureTime(); + remainingTimeEnroute = i->getArrivalTime() - now; + } + else + { + lat = dep->getLatitude(); + lon = dep->getLongitude(); + elapsedTimeEnroute = 0; + remainingTimeEnroute = totalTimeEnroute; + } + angle *= ( (double) elapsedTimeEnroute/ (double) totalTimeEnroute); @@ -236,32 +296,30 @@ void FGAISchedule::update(time_t now) newPos[j] += matrix[j][k]*a[k]; } } - + temp = sgCartToPolar3d(Point3D(newPos[0], newPos[1],newPos[2])); - if (now > i->getDepartureTime()) { //cerr << "Lat = " << lat << ", lon = " << lon << endl; //cerr << "Time diff: " << now-i->getDepartureTime() << endl; lat = temp.lat() * SG_RADIANS_TO_DEGREES; lon = temp.lon() * SG_RADIANS_TO_DEGREES; - //err << "Lat = " << lat << ", lon = " << lon << endl; - //cerr << "Time diff: " << now-i->getDepartureTime() << endl; } else { - lat = dep->_latitude; - lon = dep->_longitude; + lat = dep->getLatitude(); + lon = dep->getLongitude(); } + SGWayPoint current (lon, lat, i->getCruiseAlt()); SGWayPoint user ( userLongitude, userLatitude, i->getCruiseAlt()); - SGWayPoint dest ( arr->_longitude, - arr->_latitude, + SGWayPoint dest ( arr->getLongitude(), + arr->getLatitude(), i->getCruiseAlt()); // We really only need distance to user // and course to destination @@ -278,9 +336,9 @@ void FGAISchedule::update(time_t now) //cerr << registration << " is currently enroute from " // << dep->_id << " to " << arr->_id << "distance : " // << distanceToUser*SG_METER_TO_NM << endl; - if ((distanceToUser*SG_METER_TO_NM) < 500.0) + if ((distanceToUser*SG_METER_TO_NM) < TRAFFICTOAIDIST) { - string flightPlanName = dep->_id + string("-") + arr->_id + + string flightPlanName = dep->getId() + string("-") + arr->getId() + string(".xml"); int alt; //if ((i->getDepartureTime() < now)) @@ -294,32 +352,43 @@ void FGAISchedule::update(time_t now) FGAIModelEntity entity; - entity.m_class = "jet_transport"; + entity.m_class = m_class; //"jet_transport"; + entity.company = airline; //i->getAirline(); + entity.acType = acType; //i->getAcType(); entity.path = modelPath.c_str(); entity.flightplan = flightPlanName.c_str(); entity.latitude = lat; entity.longitude = lon; entity.altitude = i->getCruiseAlt() *100; // convert from FL to feet - entity.speed = 450; - entity.fp = new FGAIFlightPlan(&entity, courseToDest, i->getDepartureTime(), dep, arr); - + entity.speed = speed; + entity.roll = 0.0; + entity.fp = new FGAIFlightPlan(&entity, courseToDest, i->getDepartureTime(), dep, + arr,true, radius, flightType, acType, airline); + // Fixme: A non-existent model path results in an // abort, due to an unhandled exeption, in fg main loop. AIManagerRef = aimgr->createAircraft( &entity, this); - //cerr << "Created: " << AIManagerRef << endl; + //cerr << "Class: " << m_class << ". acType: " << acType << ". Airline: " << airline << ". Speed = " << speed << ". From " << dep->getId() << " to " << arr->getId() << ". Time Fraction = " << (remainingTimeEnroute/(double) totalTimeEnroute) << endl; + //cerr << "Latitude : " << lat << ". Longitude : " << lon << endl; + //cerr << "Dep : " << dep->getLatitude()<< ", "<< dep->getLongitude() << endl; + //cerr << "Arr : " << arr->getLatitude()<< ", "<< arr->getLongitude() << endl; + //cerr << "Time remaining = " << (remainingTimeEnroute/3600.0) << endl; + //cerr << "Total time = " << (totalTimeEnroute/3600.0) << endl; + //cerr << "Distance remaining = " << distanceToDest*SG_METER_TO_NM << endl; + } - return; - } + return true; + } // Both departure and arrival time are in the future, so this // the aircraft is parked at the departure airport. // Currently this status is mostly ignored, but in future // versions, code should go here that -if within user range- // positions these aircraft at parking locations at the airport. - if ((i->getDepartureTime() > now) && (i->getArrivalTime() > now)) + if ((i->getDepartureTime() > now) && (i->getArrivalTime() > now)) { dep = i->getDepartureAirport(); - return; + return true; } } } @@ -331,3 +400,71 @@ void FGAISchedule::next() sort(flights.begin(), flights.end()); } +double FGAISchedule::getSpeed() +{ + double courseToUser, courseToDest; + double distanceToUser, distanceToDest; + double speed, remainingTimeEnroute; + FGAirport *dep, *arr; + + FGScheduledFlightVecIterator i = flights.begin(); + dep = i->getDepartureAirport(); + arr = i->getArrivalAirport (); + if (!(dep && arr)) + return 0; + + SGWayPoint dest ( dep->getLongitude(), + dep->getLatitude(), + i->getCruiseAlt()); + SGWayPoint curr ( arr->getLongitude(), + arr->getLatitude(), + i->getCruiseAlt()); + remainingTimeEnroute = i->getArrivalTime() - i->getDepartureTime(); + dest.CourseAndDistance(curr, &courseToDest, &distanceToDest); + speed = (distanceToDest*SG_METER_TO_NM) / + ((double) remainingTimeEnroute/3600.0); + return speed; +} + + +void FGAISchedule::setClosestDistanceToUser() +{ + + + double course; + double dist; + + Point3D temp; + time_t + totalTimeEnroute, + elapsedTimeEnroute; + + double userLatitude = fgGetDouble("/position/latitude-deg"); + double userLongitude = fgGetDouble("/position/longitude-deg"); + + FGAirport *dep; + + distanceToUser = HUGE; + FGScheduledFlightVecIterator i = flights.begin(); + while (i != flights.end()) + { + dep = i->getDepartureAirport(); + //if (!(dep)) + //return HUGE; + + SGWayPoint user ( userLongitude, + userLatitude, + i->getCruiseAlt()); + SGWayPoint current (dep->getLongitude(), + dep->getLatitude(), + 0); + user.CourseAndDistance(current, &course, &dist); + if (dist < distanceToUser) + { + distanceToUser = dist; + //cerr << "Found closest distance to user for " << registration << " to be " << distanceToUser << " at airport " << dep->getId() << endl; + } + i++; + } + //return distToUser; +} diff --git a/src/Traffic/Schedule.hxx b/src/Traffic/Schedule.hxx index a919a7a5b..6ccb5db60 100644 --- a/src/Traffic/Schedule.hxx +++ b/src/Traffic/Schedule.hxx @@ -29,6 +29,7 @@ #ifndef _FGSCHEDULE_HXX_ #define _FGSCHEDULE_HXX_ +#define TRAFFICTOAIDIST 150.0 class FGAISchedule @@ -37,34 +38,56 @@ class FGAISchedule string modelPath; string livery; string registration; + string airline; + string acType; + string m_class; + string flightType; bool heavy; FGScheduledFlightVec flights; float lat; float lon; + double radius; + double groundOffset; + double distanceToUser; void* AIManagerRef; bool firstRun; public: FGAISchedule(); // constructor - FGAISchedule(string, string, string, bool, FGScheduledFlightVec); // construct & init + FGAISchedule(string, string, string, bool, string, string, string, string, double, double, FGScheduledFlightVec); // construct & init FGAISchedule(const FGAISchedule &other); // copy constructor ~FGAISchedule(); //destructor - void update(time_t now); + bool update(time_t now); + bool init(); + + double getSpeed (); + void setClosestDistanceToUser(); void next(); // forces the schedule to move on to the next flight. time_t getDepartureTime () { return flights.begin()->getDepartureTime (); }; FGAirport * getDepartureAirport () { return flights.begin()->getDepartureAirport(); }; FGAirport * getArrivalAirport () { return flights.begin()->getArrivalAirport (); }; int getCruiseAlt () { return flights.begin()->getCruiseAlt (); }; + double getRadius () { return radius; }; + double getGroundOffset () { return groundOffset;}; + string getFlightType () { return flightType;}; + string getAirline () { return airline; }; + string getAircraft () { return acType; }; + string getCallSign () { return flights.begin()->getCallSign (); }; + string getRegistration () { return registration;}; + bool getHeavy () { return heavy; }; + bool operator< (const FGAISchedule &other) const { return (distanceToUser < other.distanceToUser); }; + //void * getAiRef () { return AIManagerRef; }; + //FGAISchedule* getAddress () { return this;}; // More member functions follow later }; -typedef vector ScheduleVector; -typedef vector::iterator ScheduleVectorIterator; +typedef vector ScheduleVector; +typedef vector::iterator ScheduleVectorIterator; #endif diff --git a/src/Traffic/TrafficMgr.cxx b/src/Traffic/TrafficMgr.cxx index 9e6dded35..cf2fa5980 100644 --- a/src/Traffic/TrafficMgr.cxx +++ b/src/Traffic/TrafficMgr.cxx @@ -53,6 +53,7 @@ #include #include +#include #include #include #include @@ -72,22 +73,45 @@ FGTrafficManager::FGTrafficManager() void FGTrafficManager::init() -{ +{ + //cerr << "Initializing Schedules" << endl; + time_t now = time(NULL) + fgGetLong("/sim/time/warp"); currAircraft = scheduledAircraft.begin(); + while (currAircraft != scheduledAircraft.end()) + { + if (!(currAircraft->init())) + { + currAircraft=scheduledAircraft.erase(currAircraft); + //cerr << "Erasing " << currAircraft->getRegistration() << endl; + currAircraft--; + } + else + { + currAircraft++; + } + } + //cerr << "Sorting by distance " << endl; + sort(scheduledAircraft.begin(), scheduledAircraft.end()); + currAircraft = scheduledAircraft.begin(); + currAircraftClosest = scheduledAircraft.begin(); + //cerr << "Done initializing schedules" << endl; } void FGTrafficManager::update(double something) { - - //static const SGPropertyNode *warp = globals->get_props()->getNode("/sim/time/warp"); - - //time_t now = time(NULL) + globals->get_warp(); time_t now = time(NULL) + fgGetLong("/sim/time/warp"); - // cerr << "TrafficManager update" << globals->get_warp() << endl; - if(currAircraft == scheduledAircraft.end()) + if(currAircraft == scheduledAircraft.end()) + { + //cerr << "resetting schedule " << endl; currAircraft = scheduledAircraft.begin(); - currAircraft->update(now); - currAircraft++; + } + if (!(currAircraft->update(now))) + { + // after proper initialization, we shouldnt get here. + // But let's make sure + cerr << "Failed to update aircraft schedule in traffic manager" << endl; + } + currAircraft++; } void FGTrafficManager::release(void *id) @@ -146,6 +170,18 @@ void FGTrafficManager::endElement (const char * name) { livery = value; else if (element == string("registration")) registration = value; + else if (element == string("airline")) + airline = value; + else if (element == string("actype")) + acType = value; + else if (element == string("flighttype")) + flighttype = value; + else if (element == string("radius")) + radius = atoi(value.c_str()); + else if (element == string("offset")) + offset = atoi(value.c_str()); + else if (element == string("performance-class")) + m_class = value; else if (element == string("heavy")) { if(value == string("true")) @@ -195,10 +231,16 @@ void FGTrafficManager::endElement (const char * name) { { //cerr << "Pushing back aircraft " << registration << endl; scheduledAircraft.push_back(FGAISchedule(mdl, - livery, - registration, - heavy, - flights)); + livery, + registration, + heavy, + acType, + airline, + m_class, + flighttype, + radius, + offset, + flights)); while(flights.begin() != flights.end()) flights.pop_back(); } diff --git a/src/Traffic/TrafficMgr.hxx b/src/Traffic/TrafficMgr.hxx index ab39afcf7..4dd3383f7 100644 --- a/src/Traffic/TrafficMgr.hxx +++ b/src/Traffic/TrafficMgr.hxx @@ -42,13 +42,14 @@ class FGTrafficManager : public SGSubsystem, public XMLVisitor { private: ScheduleVector scheduledAircraft; - ScheduleVectorIterator currAircraft; + ScheduleVectorIterator currAircraft, currAircraftClosest; string value; string mdl, livery, registration, callsign, fltrules, port, timeString, departurePort, departureTime, arrivalPort, arrivalTime, - repeat; + repeat, acType, airline, m_class, flighttype; int cruiseAlt; + double radius, offset; bool heavy; IdList releaseList;