//
// 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.
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
/*==========================================================
globals->get_sim_time_sec() );
*//*
_model = model;
- _model->ref();
_aip.init(_model);
*/
//SetModel(model);
contactTower = false;
contactGround = false;
_taxiToGA = false;
+ _removeSelf = false;
descending = false;
targetDescentRate = 0.0;
_savedSlope = 0.0;
_controlled = false;
+
+ _invisible = false;
}
FGAILocalTraffic::~FGAILocalTraffic() {
- //_model->deRef();
}
-void FGAILocalTraffic::GetAirportDetails(string id) {
+void FGAILocalTraffic::GetAirportDetails(const string& id) {
AirportATC a;
if(ATC->GetAirportATCDetails(airportID, &a)) {
if(a.tower_freq) { // Has a tower - TODO - check the opening hours!!!
- tower = (FGTower*)ATC->GetATCPointer(airportID, TOWER); // Maybe need some error checking here
+ tower = (FGTower*)ATC->GetATCPointer(airportID, TOWER);
if(tower == NULL) {
// Something has gone wrong - abort or carry on with un-towered operation?
SG_LOG(SG_ATC, SG_ALERT, "ERROR - can't get a tower pointer from tower control for " << airportID << " in FGAILocalTraffic::GetAirportDetails() :-(");
_controlled = false;
}
// Get the airport elevation
- aptElev = dclGetAirportElev(airportID.c_str());
+ aptElev = fgGetAirportElev(airportID.c_str());
//cout << "Airport elev in AILocalTraffic = " << aptElev << '\n';
// WARNING - we use this elev for the whole airport - some assumptions in the code
// might fall down with very slopey airports.
// Get details of the active runway
// It is assumed that by the time this is called the tower control and airport code will have been set up.
-void FGAILocalTraffic::GetRwyDetails(string id) {
+void FGAILocalTraffic::GetRwyDetails(const string& id) {
//cout << "GetRwyDetails called" << endl;
- rwy.rwyID = tower->GetActiveRunway();
- //cout << "id = " << id << '\n';
- //cout << "Returned id is " << tower->get_ident() << '\n';
- //cout << "Returned name is " << tower->get_name() << '\n';
- //cout << "rwy.rwyID = " << rwy.rwyID << '\n';
+ if(_controlled) {
+ rwy.rwyID = tower->GetActiveRunway();
+ } else {
+ // TODO - get a proper runway ID from uncontrolled airports
+ rwy.rwyID = "00";
+ }
// Now we need to get the threshold position and rwy heading
FGRunway runway;
bool rwyGood = globals->get_runways()->search(id, rwy.rwyID, &runway);
if(rwyGood) {
- double hdg = runway.heading;
+ double hdg = runway._heading;
double other_way = hdg - 180.0;
while(other_way <= 0.0) {
other_way += 360.0;
}
// move to the +l end/center of the runway
- //cout << "Runway center is at " << runway.lon << ", " << runway.lat << '\n';
- Point3D origin = Point3D(runway.lon, runway.lat, aptElev);
+ //cout << "Runway center is at " << runway._lon << ", " << runway._lat << '\n';
+ Point3D origin = Point3D(runway._lon, runway._lat, aptElev);
Point3D ref = origin;
double tshlon, tshlat, tshr;
double tolon, tolat, tor;
- rwy.length = runway.length * SG_FEET_TO_METER;
- rwy.width = runway.width * SG_FEET_TO_METER;
+ rwy.length = runway._length * SG_FEET_TO_METER;
+ rwy.width = runway._width * SG_FEET_TO_METER;
geo_direct_wgs_84 ( aptElev, ref.lat(), ref.lon(), other_way,
rwy.length / 2.0 - 25.0, &tshlat, &tshlon, &tshr );
geo_direct_wgs_84 ( aptElev, ref.lat(), ref.lon(), hdg,
sufficient initialisation functionality within the plane classes to allow the manager
to initially position them where and how required.
*/
-bool FGAILocalTraffic::Init(const string& callsign, string ICAO, OperatingState initialState, PatternLeg initialLeg) {
+bool FGAILocalTraffic::Init(const string& callsign, const string& ICAO, OperatingState initialState, PatternLeg initialLeg) {
//cout << "FGAILocalTraffic.Init(...) called" << endl;
airportID = ICAO;
patternDirection = (rwy.rwyID.substr(2,1) == "R" ? 1 : -1);
}
- // TODO - this assumes a controlled airport - make sure we revert to CTAF etc if uncontrolled or after-hours.
- if((initialState == PARKED) || (initialState == TAXIING)) {
- freq = (double)ground->get_freq() / 100.0;
+ if(_controlled) {
+ if((initialState == PARKED) || (initialState == TAXIING)) {
+ freq = (double)ground->get_freq() / 100.0;
+ } else {
+ freq = (double)tower->get_freq() / 100.0;
+ }
} else {
- freq = (double)tower->get_freq() / 100.0;
+ freq = 122.8;
+ // TODO - find the proper freq if CTAF or unicom or after-hours.
}
//cout << "In Init(), initialState = " << initialState << endl;
// FIXME - implement this case properly
// For now we'll assume that the plane should start at the hold short in this case
// and that we're working without ground network elements. Ie. an airport with no facility file.
- tuned_station = tower;
+ if(_controlled) {
+ tuned_station = tower;
+ } else {
+ tuned_station = NULL;
+ }
freeTaxi = true;
// Set a position and orientation in an approximate place for hold short.
//cout << "rwy.width = " << rwy.width << '\n';
//cout << "Starting in pattern...\n";
- tuned_station = tower;
+ if(_controlled) {
+ tuned_station = tower;
+ } else {
+ tuned_station = NULL;
+ }
circuitsToFly = 0; // ie just fly this circuit and then stop
touchAndGo = false;
IAS = 90.0;
descending = false;
_aip.setVisible(true);
- tower->RegisterAIPlane(plane, this, CIRCUIT, DOWNWIND);
+ if(_controlled) {
+ tower->RegisterAIPlane(plane, this, CIRCUIT, DOWNWIND);
+ }
Transform();
} else {
// Default to initial position on threshold for now
// Run the internal calculations
void FGAILocalTraffic::Update(double dt) {
//cout << "U" << flush;
+
+ // we shouldn't really need this since there's a LOD of 10K on the whole plane anyway I think.
+ // At the moment though I need to to avoid DList overflows - the whole plane LOD obviously isn't getting picked up.
+ if(!_invisible) {
+ if(dclGetHorizontalSeparation(_pos, Point3D(fgGetDouble("/position/longitude-deg"), fgGetDouble("/position/latitude-deg"), 0.0)) > 8000) _aip.setVisible(false);
+ else _aip.setVisible(true);
+ } else {
+ _aip.setVisible(false);
+ }
+
//double responseTime = 10.0; // seconds - this should get more sophisticated at some point
responseCounter += dt;
if((contactTower) && (responseCounter >= 8.0)) {
string trns = "GA Parking, Thank you and Good Day";
//double f = globals->get_ATC_mgr()->GetFrequency(airportID, GROUND) / 100.0;
pending_transmission = trns;
- ConditionalTransmit(5.0);
- tower->DeregisterAIPlane(plane.callsign);
+ ConditionalTransmit(5.0, 99);
_taxiToGA = false;
- // HACK - check if we are at a simple airport or not first
- globals->get_AI_mgr()->ScheduleRemoval(plane.callsign);
- }
+ if(_controlled) {
+ tower->DeregisterAIPlane(plane.callsign);
+ }
+ // NOTE - we can't delete this instance yet since then the frequency won't get release when the message display finishes.
+ }
+
+ if((_removeSelf) && (responseCounter >= 8.0)) {
+ _removeSelf = false;
+ // MEGA HACK - check if we are at a simple airport or not first instead of simply hardwiring KEMT as the only non-simple airport.
+ // TODO FIXME TODO FIXME !!!!!!!
+ if(airportID != "KEMT") globals->get_AI_mgr()->ScheduleRemoval(plane.callsign);
+ }
if((changeFreq) && (responseCounter > 8.0)) {
switch(changeFreqType) {
case TOWER:
+ if(!tower) {
+ SG_LOG(SG_ATC, SG_ALERT, "ERROR: Trying to change frequency to tower in FGAILocalTraffic, but tower is NULL!!!");
+ break;
+ }
tuned_station = tower;
freq = (double)tower->get_freq() / 100.0;
//Transmit("DING!");
Transmit(2);
break;
case GROUND:
+ if(!tower) {
+ SG_LOG(SG_ATC, SG_ALERT, "ERROR: Trying to change frequency to ground in FGAILocalTraffic, but tower is NULL!!!");
+ break;
+ }
+ if(!ground) {
+ SG_LOG(SG_ATC, SG_ALERT, "ERROR: Trying to change frequency to ground in FGAILocalTraffic, but ground is NULL!!!");
+ break;
+ }
tower->DeregisterAIPlane(plane.callsign);
tuned_station = ground;
freq = (double)ground->get_freq() / 100.0;
- // HACK - check if we are at a simple airport or not first
- // TODO FIXME TODO FIXME !!!!!!!
- if(airportID != "KEMT") globals->get_AI_mgr()->ScheduleRemoval(plane.callsign);
break;
// And to avoid compiler warnings...
case APPROACH: break;
// Do some communication
// airport name + tower + airplane callsign + location + request taxi for + operation type + ?
string trns = "";
- trns += tower->get_name();
- trns += " tower ";
+ if(_controlled) {
+ trns += tower->get_name();
+ trns += " tower ";
+ } else {
+ trns += "Traffic ";
+ // TODO - get the airport name somehow if uncontrolled
+ }
trns += plane.callsign;
trns += " on apron parking request taxi for traffic pattern";
//cout << "trns = " << trns << endl;
if(descending) {
if(orthopos.y() < -50.0) {
double thesh_offset = 30.0;
- slope = atan((_pos.elev() - dclGetAirportElev(airportID)) / (orthopos.y() - thesh_offset)) * DCL_RADIANS_TO_DEGREES;
- //cout << "slope = " << slope << ", elev = " << _pos.elev() << ", apt_elev = " << dclGetAirportElev(airportID) << ", op.y = " << orthopos.y() << '\n';
+ slope = atan((_pos.elev() - fgGetAirportElev(airportID)) / (orthopos.y() - thesh_offset)) * DCL_RADIANS_TO_DEGREES;
+ //cout << "slope = " << slope << ", elev = " << _pos.elev() << ", apt_elev = " << fgGetAirportElev(airportID) << ", op.y = " << orthopos.y() << '\n';
if(slope < -10.0) slope = -10.0;
_savedSlope = slope;
_pitch = -4.0;
tower->ReportDownwind(plane.callsign);
} else if(code == 13) {
tower->ReportFinal(plane.callsign);
+ } else if(code == 99) { // Flag this instance for deletion
+ responseCounter = 0;
+ _removeSelf = true;
+ SG_LOG(SG_ATC, SG_INFO, "AI local traffic " << plane.callsign << " delete instance callback called.");
}
}
-void FGAILocalTraffic::ExitRunway(Point3D orthopos) {
+void FGAILocalTraffic::ExitRunway(const Point3D& orthopos) {
//cout << "In ExitRunway" << endl;
//cout << "Runway ID is " << rwy.ID << endl;
} else {
// Something must have gone wrong with the ground network file - or there is only a rwy here and no exits defined
SG_LOG(SG_ATC, SG_INFO, "No exits found by FGAILocalTraffic from runway " << rwy.rwyID << " at " << airportID << '\n');
- //cout << "No exits found by " << plane.callsign << " from runway " << rwy.rwyID << " at " << airportID << '\n';
+ //if(airportID == "KRHV") cout << "No exits found by " << plane.callsign << " from runway " << rwy.rwyID << " at " << airportID << '\n';
// What shall we do - just remove the plane from sight?
_aip.setVisible(false);
+ _invisible = true;
//cout << "Setting visible false\n";
//tower->ReportRunwayVacated(plane.callsign);
string trns = "Clear of the runway ";
_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() );
-
- //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());
+
+ // FIXME: make shure the pos.lat/pos.lon values are in degrees ...
+ double range = 500.0;
+ double lat = _aip.getSGLocation()->getLatitude_deg();
+ double lon = _aip.getSGLocation()->getLongitude_deg();
+ if (!globals->get_tile_mgr()->scenery_available(lat, lon, range)) {
+ // Try to shedule tiles for that position.
+ globals->get_tile_mgr()->update( _aip.getSGLocation(), range );
+ }
+
+ // FIXME: make shure the pos.lat/pos.lon values are in degrees ...
+ double alt;
+ if (globals->get_scenery()->get_elevation_m(lat, lon, 20000.0, alt, 0))
+ _aip.getSGLocation()->set_cur_elev_m(alt);
}