# include <config.h>
#endif
-#include <simgear/scene/model/location.hxx>
-
#include <Airports/runways.hxx>
#include <Main/globals.hxx>
#include <Main/viewer.hxx>
#include <Scenery/scenery.hxx>
#include <Scenery/tilemgr.hxx>
-#include <simgear/math/point3d.hxx>
-#include <simgear/math/sg_geodesy.hxx>
+#include <simgear/math/SGMath.hxx>
#include <simgear/misc/sg_path.hxx>
#include <string>
#include <math.h>
#include "AIMgr.hxx"
FGAILocalTraffic::FGAILocalTraffic() {
- /*ssgBranch *model = sgLoad3DModel( globals->get_fg_root(),
- planepath.c_str(),
- globals->get_props(),
- globals->get_sim_time_sec() );
- *//*
- _model = model;
- _aip.init(_model);
- */
- //SetModel(model);
-
ATC = globals->get_ATC_mgr();
// TODO - unhardwire this
// move to the +l end/center of the runway
//cout << "Runway center is at " << runway._lon << ", " << runway._lat << '\n';
- Point3D origin = Point3D(runway->longitude(), runway->latitude(), aptElev);
- Point3D ref = origin;
double tshlon, tshlat, tshr;
double tolon, tolat, tor;
rwy.length = runway->lengthM();
rwy.width = runway->widthM();
- geo_direct_wgs_84 ( aptElev, ref.lat(), ref.lon(), other_way,
+ geo_direct_wgs_84 ( aptElev, runway->latitude(), runway->longitude(), other_way,
rwy.length / 2.0 - 25.0, &tshlat, &tshlon, &tshr );
- geo_direct_wgs_84 ( aptElev, ref.lat(), ref.lon(), hdg,
+ geo_direct_wgs_84 ( aptElev, runway->latitude(), runway->longitude(), hdg,
rwy.length / 2.0 - 25.0, &tolat, &tolon, &tor );
// Note - 25 meters in from the runway end is a bit of a hack to put the plane ahead of the user.
// now copy what we need out of runway into rwy
- rwy.threshold_pos = Point3D(tshlon, tshlat, aptElev);
- Point3D takeoff_end = Point3D(tolon, tolat, aptElev);
+ rwy.threshold_pos = SGGeod::fromDegM(tshlon, tshlat, aptElev);
+ SGGeod takeoff_end = SGGeod::fromDegM(tolon, tolat, aptElev);
//cout << "Threshold position = " << tshlon << ", " << tshlat << ", " << aptElev << '\n';
//cout << "Takeoff position = " << tolon << ", " << tolat << ", " << aptElev << '\n';
rwy.hdg = hdg;
//cout << "In Init(), initialState = " << initialState << endl;
operatingState = initialState;
- Point3D orthopos;
+ SGVec3d orthopos;
switch(operatingState) {
case PARKED:
tuned_station = ground;
vel = 0.0;
slope = 0.0;
_pos = ourGate->pos;
- _pos.setelev(aptElev);
+ _pos.setElevationM(aptElev);
_hdg = ourGate->heading;
Transform();
freeTaxi = true;
// Set a position and orientation in an approximate place for hold short.
//cout << "rwy.width = " << rwy.width << '\n';
- orthopos = Point3D((rwy.width / 2.0 + 10.0) * -1.0, 0.0, 0.0);
+ orthopos = SGVec3d((rwy.width / 2.0 + 10.0) * -1.0, 0.0, 0.0);
// TODO - set the x pos to be +ve if a RH parallel rwy.
_pos = ortho.ConvertFromLocal(orthopos);
- _pos.setelev(aptElev);
+ _pos.setElevationM(aptElev);
_hdg = rwy.hdg + 90.0;
// TODO - reset the heading if RH rwy.
_pitch = 0.0;
touchAndGo = false;
if(initialLeg == DOWNWIND) {
- _pos = ortho.ConvertFromLocal(Point3D(1000*patternDirection, 800, 0.0));
- _pos.setelev(rwy.threshold_pos.elev() + 1000 * SG_FEET_TO_METER);
+ _pos = ortho.ConvertFromLocal(SGVec3d(1000*patternDirection, 800, 0.0));
+ _pos.setElevationM(rwy.threshold_pos.getElevationM() + 1000 * SG_FEET_TO_METER);
_hdg = rwy.hdg + 180.0;
leg = DOWNWIND;
elevInitGood = false;
Transform();
} else {
// Default to initial position on threshold for now
- _pos.setlat(rwy.threshold_pos.lat());
- _pos.setlon(rwy.threshold_pos.lon());
- _pos.setelev(rwy.threshold_pos.elev());
+ _pos = rwy.threshold_pos;
_hdg = rwy.hdg;
// Now we've set the position we can do the ground elev
// 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);
+ if(dclGetHorizontalSeparation(_pos, SGGeod::fromDegM(fgGetDouble("/position/longitude-deg"), fgGetDouble("/position/latitude-deg"), 0.0)) > 8000) _aip.setVisible(false);
else _aip.setVisible(true);
} else {
_aip.setVisible(false);
// And to avoid compiler warnings...
case APPROACH: break;
case ATIS: break;
+ case AWOS: break;
case ENROUTE: break;
case DEPARTURE: break;
case INVALID: break;
DoGroundElev();
if(!elevInitGood) {
if(_ground_elevation_m > -9990.0) {
- _pos.setelev(_ground_elevation_m + wheelOffset);
+ _pos.setElevationM(_ground_elevation_m + wheelOffset);
//cout << "TAKEOFF_ROLL, POS = " << pos.lon() << ", " << pos.lat() << ", " << pos.elev() << '\n';
//Transform();
_aip.setVisible(true);
if(!elevInitGood) {
//DoGroundElev();
if(_ground_elevation_m > -9990.0) {
- _pos.setelev(_ground_elevation_m + wheelOffset);
+ _pos.setElevationM(_ground_elevation_m + wheelOffset);
//Transform();
_aip.setVisible(true);
//Transform();
//cout << "C" << endl;
node* np = new node;
np->struct_type = NODE;
- np->pos = ortho.ConvertFromLocal(Point3D(0.0, 10.0, 0.0));
+ np->pos = ortho.ConvertFromLocal(SGVec3d(0.0, 10.0, 0.0));
path.push_back(np);
} else {
//cout << "D" << endl;
if(!elevInitGood) {
DoGroundElev();
if(_ground_elevation_m > -9990.0) {
- _pos.setelev(_ground_elevation_m + wheelOffset);
+ _pos.setElevationM(_ground_elevation_m + wheelOffset);
//Transform();
_aip.setVisible(true);
//Transform();
double turn_time = 60.0; // seconds - TODO - check this guess
double turn_circumference;
double turn_radius;
- Point3D orthopos = ortho.ConvertToLocal(_pos); // ortho position of the plane
- //cout << "runway elev = " << rwy.threshold_pos.elev() << ' ' << rwy.threshold_pos.elev() * SG_METER_TO_FEET << '\n';
+ SGVec3d orthopos = ortho.ConvertToLocal(_pos); // ortho position of the plane
+ //cout << "runway elev = " << rwy.threshold_pos.getElevationM() << ' ' << rwy.threshold_pos.getElevationM() * SG_METER_TO_FEET << '\n';
//cout << "elev = " << _pos.elev() << ' ' << _pos.elev() * SG_METER_TO_FEET << '\n';
// HACK FOR TESTING - REMOVE
vel += dveldt * dt;
}
if(_ground_elevation_m > -9990.0) {
- _pos.setelev(_ground_elevation_m + wheelOffset);
+ _pos.setElevationM(_ground_elevation_m + wheelOffset);
}
IAS = vel + (cos((_hdg - wind_from) * DCL_DEGREES_TO_RADIANS) * wind_speed);
if(IAS >= 70) {
// (decided in FGTower and accessed through GetCrosswindConstraint(...)).
// According to AIM, traffic should climb to within 300ft of pattern altitude before commencing crosswind turn.
// TODO - At hot 'n high airports this may be 500ft AGL though - need to make this a variable.
- if((_pos.elev() - rwy.threshold_pos.elev()) * SG_METER_TO_FEET > 700) {
+ if((_pos.getElevationM() - rwy.threshold_pos.getElevationM()) * SG_METER_TO_FEET > 700) {
double cc = 0.0;
- if(tower->GetCrosswindConstraint(cc)) {
+ if(tower && tower->GetCrosswindConstraint(cc)) {
if(orthopos.y() > cc) {
//cout << "Turning to crosswind, distance from threshold = " << orthopos.y() << '\n';
leg = TURN1;
}
// Need to check for levelling off in case we can't turn crosswind as soon
// as we would like due to other traffic.
- if((_pos.elev() - rwy.threshold_pos.elev()) * SG_METER_TO_FEET > 1000) {
+ if((_pos.getElevationM() - rwy.threshold_pos.getElevationM()) * SG_METER_TO_FEET > 1000) {
slope = 0.0;
_pitch = 0.0;
IAS = 80.0; // FIXME - use smooth transistion to new speed and attitude.
break;
case CROSSWIND:
goAround = false;
- if((_pos.elev() - rwy.threshold_pos.elev()) * SG_METER_TO_FEET > 1000) {
+ if((_pos.getElevationM() - rwy.threshold_pos.getElevationM()) * SG_METER_TO_FEET > 1000) {
slope = 0.0;
_pitch = 0.0;
IAS = 80.0; // FIXME - use smooth transistion to new speed
// turn 1000m out for now, taking other traffic into accout
if(fabs(orthopos.x()) > 900) {
double dd = 0.0;
- if(tower->GetDownwindConstraint(dd)) {
+ if(tower && tower->GetDownwindConstraint(dd)) {
if(fabs(orthopos.x()) > fabs(dd)) {
//cout << "Turning to downwind, distance from centerline = " << fabs(orthopos.x()) << '\n';
leg = TURN2;
case TURN2:
SetTrack(rwy.hdg - (180 * patternDirection));
// just in case we didn't make height on crosswind
- if((_pos.elev() - rwy.threshold_pos.elev()) * SG_METER_TO_FEET > 1000) {
+ if((_pos.getElevationM() - rwy.threshold_pos.getElevationM()) * SG_METER_TO_FEET > 1000) {
slope = 0.0;
_pitch = 0.0;
IAS = 80.0; // FIXME - use smooth transistion to new speed
break;
case DOWNWIND:
// just in case we didn't make height on crosswind
- if(((_pos.elev() - rwy.threshold_pos.elev()) * SG_METER_TO_FEET > 995) && ((_pos.elev() - rwy.threshold_pos.elev()) * SG_METER_TO_FEET < 1015)) {
+ if(((_pos.getElevationM() - rwy.threshold_pos.getElevationM()) * SG_METER_TO_FEET > 995) && ((_pos.getElevationM() - rwy.threshold_pos.getElevationM()) * SG_METER_TO_FEET < 1015)) {
slope = 0.0;
_pitch = 0.0;
IAS = 90.0; // FIXME - use smooth transistion to new speed
}
- if((_pos.elev() - rwy.threshold_pos.elev()) * SG_METER_TO_FEET >= 1015) {
+ if((_pos.getElevationM() - rwy.threshold_pos.getElevationM()) * SG_METER_TO_FEET >= 1015) {
slope = -1.0;
_pitch = -1.0;
IAS = 90.0; // FIXME - use smooth transistion to new speed
// For now we're assuming that we aim to follow the same glidepath regardless of wind.
double d1;
double d2;
- CalculateSoD((tower->GetBaseConstraint(d1) ? d1 : -1000.0), (tower->GetDownwindConstraint(d2) ? d2 : 1000.0 * patternDirection), (patternDirection ? true : false));
+ CalculateSoD(((tower && tower->GetBaseConstraint(d1)) ? d1 : -1000.0), ((tower && tower->GetDownwindConstraint(d2)) ? d2 : 1000.0 * patternDirection), (patternDirection ? true : false));
if(SoD.leg == DOWNWIND) {
descending = (orthopos.y() < SoD.y ? true : false);
}
if(orthopos.y() < -1000.0 + turn_radius) {
//if(orthopos.y() < -980) {
double bb = 0.0;
- if(tower->GetBaseConstraint(bb)) {
+ if(tower && tower->GetBaseConstraint(bb)) {
if(fabs(orthopos.y()) > fabs(bb)) {
//cout << "Turning to base, distance from threshold = " << fabs(orthopos.y()) << '\n';
leg = TURN3;
double d1;
// Make downwind leg position artifically large to avoid any chance of SoD being returned as
// on downwind when we are already on base.
- CalculateSoD((tower->GetBaseConstraint(d1) ? d1 : -1000.0), (10000.0 * patternDirection), (patternDirection ? true : false));
+ CalculateSoD(((tower && tower->GetBaseConstraint(d1)) ? d1 : -1000.0), (10000.0 * patternDirection), (patternDirection ? true : false));
if(SoD.leg == BASE) {
descending = (fabs(orthopos.y()) < fabs(SoD.y) ? true : false);
}
if(descending) {
if(orthopos.y() < -50.0) {
double thesh_offset = 30.0;
- slope = atan((_pos.elev() - fgGetAirportElev(airportID)) / (orthopos.y() - thesh_offset)) * DCL_RADIANS_TO_DEGREES;
+ slope = atan((_pos.getElevationM() - 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;
IAS = 70.0;
} else {
- if(_pos.elev() < (rwy.threshold_pos.elev()+10.0+wheelOffset)) {
+ if(_pos.getElevationM() < (rwy.threshold_pos.getElevationM()+10.0+wheelOffset)) {
if(_ground_elevation_m > -9990.0) {
- if(_pos.elev() < (_ground_elevation_m + wheelOffset + 1.0)) {
+ if(_pos.getElevationM() < (_ground_elevation_m + wheelOffset + 1.0)) {
slope = -2.0;
_pitch = 1.0;
IAS = 55.0;
- } else if(_pos.elev() < (_ground_elevation_m + wheelOffset + 5.0)) {
+ } else if(_pos.getElevationM() < (_ground_elevation_m + wheelOffset + 5.0)) {
slope = -4.0;
_pitch = -2.0;
IAS = 60.0;
// Try and track the extended centreline
SetTrack(rwy.hdg - (0.2 * orthopos.x()));
//cout << "orthopos.x() = " << orthopos.x() << " hdg = " << hdg << '\n';
- if(_pos.elev() < (rwy.threshold_pos.elev()+20.0+wheelOffset)) {
+ if(_pos.getElevationM() < (rwy.threshold_pos.getElevationM()+20.0+wheelOffset)) {
DoGroundElev(); // Need to call it here expicitly on final since it's only called
// for us in update(...) when the inAir flag is false.
}
- if(_pos.elev() < (rwy.threshold_pos.elev()+10.0+wheelOffset)) {
+ if(_pos.getElevationM() < (rwy.threshold_pos.getElevationM()+10.0+wheelOffset)) {
//slope = -1.0;
//_pitch = 1.0;
if(_ground_elevation_m > -9990.0) {
- if((_ground_elevation_m + wheelOffset) > _pos.elev()) {
+ if((_ground_elevation_m + wheelOffset) > _pos.getElevationM()) {
slope = 0.0;
_pitch = 0.0;
leg = LANDING_ROLL;
//inAir = false;
descending = false;
if(_ground_elevation_m > -9990.0) {
- _pos.setelev(_ground_elevation_m + wheelOffset);
+ _pos.setElevationM(_ground_elevation_m + wheelOffset);
}
track = rwy.hdg;
dveldt = -5.0;
void FGAILocalTraffic::TransmitPatternPositionReport(void) {
// airport name + "traffic" + airplane callsign + pattern direction + pattern leg + rwy + ?
- string trns = "";
+ string trns;
int code = 0;
-
- trns += tower->get_name();
+ const string& apt_name = tower ? tower->get_name() : airportID;
+
+ trns += apt_name;
trns += " Traffic ";
trns += plane.callsign;
if(patternDirection == 1) {
}
trns += ConvertRwyNumToSpokenString(rwy.rwyID);
- trns += " ";
+ trns += ' ';
// And add the airport name again
- trns += tower->get_name();
+ trns += apt_name;
pending_transmission = trns;
ConditionalTransmit(60.0, code); // Assume a report of this leg will be invalid if we can't transmit within a minute.
}
}
-void FGAILocalTraffic::ExitRunway(const Point3D& orthopos) {
+void FGAILocalTraffic::ExitRunway(const SGVec3d& orthopos) {
//cout << "In ExitRunway" << endl;
//cout << "Runway ID is " << rwy.ID << endl;
node* rwyExit = *(exitNodes.begin());
//int gateID; //This might want to be more persistant at some point
while(nItr != exitNodes.end()) {
- d = ortho.ConvertToLocal((*nItr)->pos).y() - ortho.ConvertToLocal(_pos).y(); //FIXME - consider making orthopos a class variable
+ d = ortho.ConvertToLocal((*nItr)->pos).y() - ortho.ConvertToLocal(_pos).y(); //FIXME - consider making orthopos a class variable
if(d > 0.0) {
if(d < dist) {
dist = d;
// If we have reached turning point then get next point and turn onto that heading
// Look out for the finish!!
- //Point3D orthopos = ortho.ConvertToLocal(pos); // ortho position of the plane
- desiredTaxiHeading = GetHeadingFromTo(_pos, nextTaxiNode->pos);
+ desiredTaxiHeading = GetHeadingFromTo(_pos, nextTaxiNode->pos);
bool lastNode = (taxiPathPos == path.size() ? true : false);
if(lastNode) {
_pos = dclUpdatePosition(_pos, track, slope, dist);
//cout << "Updated position...\n";
if(_ground_elevation_m > -9990) {
- _pos.setelev(_ground_elevation_m + wheelOffset);
+ _pos.setElevationM(_ground_elevation_m + wheelOffset);
} // else don't change the elev until we get a valid ground elev again!
} else if(lastNode) {
if(taxiState == TD_LINING_UP) {
_pos = dclUpdatePosition(_pos, track, slope, dist);
//cout << "Updated position...\n";
if(_ground_elevation_m > -9990) {
- _pos.setelev(_ground_elevation_m + wheelOffset);
+ _pos.setElevationM(_ground_elevation_m + wheelOffset);
} // else don't change the elev until we get a valid ground elev again!
if(fabs(_hdg - rwy.hdg) <= 1.0) {
operatingState = IN_PATTERN;
// 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();
- if(dclGetHorizontalSeparation(_pos, Point3D(vw->getLongitude_deg(), vw->getLatitude_deg(), 0.0)) > visibility_meters) {
+ if(dclGetHorizontalSeparation(_pos, SGGeod::fromGeodM(vw->getPosition(), 0.0)) > visibility_meters) {
_ground_elevation_m = aptElev;
return;
}
- // FIXME: make shure the pos.lat/pos.lon values are in degrees ...
- double range = 500.0;
- if (!globals->get_tile_mgr()->scenery_available(_aip.getPosition(), range)) {
- // Try to shedule tiles for that position.
- globals->get_tile_mgr()->update( _aip.getPosition(), range );
- }
+ // FIXME: make shure the pos.lat/pos.lon values are in degrees ...
+ double range = 500.0;
+ if (!globals->get_tile_mgr()->scenery_available(_aip.getPosition(), range)) {
+ // Try to shedule tiles for that position.
+ globals->get_tile_mgr()->update( _aip.getPosition(), range );
+ }
- // FIXME: make shure the pos.lat/pos.lon values are in degrees ...
- double alt;
- if (globals->get_scenery()->get_elevation_m(SGGeod::fromGeodM(_aip.getPosition(), 20000), alt, 0))
- _ground_elevation_m = alt;
+ // FIXME: make shure the pos.lat/pos.lon values are in degrees ...
+ double alt;
+ if (globals->get_scenery()->get_elevation_m(SGGeod::fromGeodM(_aip.getPosition(), 20000), alt, 0, _aip.getSceneGraph()))
+ _ground_elevation_m = alt;
}