# 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
const FGAirport* apt = fgFindAirportID(id);
assert(apt);
- FGRunway runway(apt->getActiveRunwayForUsage());
+ FGRunway* runway(apt->getActiveRunwayForUsage());
- double hdg = runway._heading;
+ double hdg = runway->headingDeg();
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);
- 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;
- geo_direct_wgs_84 ( aptElev, ref.lat(), ref.lon(), other_way,
+ rwy.length = runway->lengthM();
+ rwy.width = runway->widthM();
+ 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);
if(!inAir) {
DoGroundElev();
if(!elevInitGood) {
- if(_aip.getSGLocation()->get_cur_elev_m() > -9990.0) {
- _pos.setelev(_aip.getSGLocation()->get_cur_elev_m() + wheelOffset);
+ if(_ground_elevation_m > -9990.0) {
+ _pos.setElevationM(_ground_elevation_m + wheelOffset);
//cout << "TAKEOFF_ROLL, POS = " << pos.lon() << ", " << pos.lat() << ", " << pos.elev() << '\n';
//Transform();
_aip.setVisible(true);
//cout << "*" << flush;
if(!elevInitGood) {
//DoGroundElev();
- if(_aip.getSGLocation()->get_cur_elev_m() > -9990.0) {
- _pos.setelev(_aip.getSGLocation()->get_cur_elev_m() + wheelOffset);
+ if(_ground_elevation_m > -9990.0) {
+ _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;
//cout << "In PARKED\n";
if(!elevInitGood) {
DoGroundElev();
- if(_aip.getSGLocation()->get_cur_elev_m() > -9990.0) {
- _pos.setelev(_aip.getSGLocation()->get_cur_elev_m() + wheelOffset);
+ if(_ground_elevation_m > -9990.0) {
+ _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
double dveldt = 5.0;
vel += dveldt * dt;
}
- if(_aip.getSGLocation()->get_cur_elev_m() > -9990.0) {
- _pos.setelev(_aip.getSGLocation()->get_cur_elev_m() + wheelOffset);
+ if(_ground_elevation_m > -9990.0) {
+ _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(orthopos.y() > cc) {
}
// 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
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
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(_aip.getSGLocation()->get_cur_elev_m() > -9990.0) {
- if(_pos.elev() < (_aip.getSGLocation()->get_cur_elev_m() + wheelOffset + 1.0)) {
+ if(_pos.getElevationM() < (rwy.threshold_pos.getElevationM()+10.0+wheelOffset)) {
+ if(_ground_elevation_m > -9990.0) {
+ if(_pos.getElevationM() < (_ground_elevation_m + wheelOffset + 1.0)) {
slope = -2.0;
_pitch = 1.0;
IAS = 55.0;
- } else if(_pos.elev() < (_aip.getSGLocation()->get_cur_elev_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(_aip.getSGLocation()->get_cur_elev_m() > -9990.0) {
- if((_aip.getSGLocation()->get_cur_elev_m() + wheelOffset) > _pos.elev()) {
+ if(_ground_elevation_m > -9990.0) {
+ if((_ground_elevation_m + wheelOffset) > _pos.getElevationM()) {
slope = 0.0;
_pitch = 0.0;
leg = LANDING_ROLL;
case LANDING_ROLL:
//inAir = false;
descending = false;
- if(_aip.getSGLocation()->get_cur_elev_m() > -9990.0) {
- _pos.setelev(_aip.getSGLocation()->get_cur_elev_m() + wheelOffset);
+ if(_ground_elevation_m > -9990.0) {
+ _pos.setElevationM(_ground_elevation_m + wheelOffset);
}
track = rwy.hdg;
dveldt = -5.0;
}
}
-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) {
double slope = 0.0;
_pos = dclUpdatePosition(_pos, track, slope, dist);
//cout << "Updated position...\n";
- if(_aip.getSGLocation()->get_cur_elev_m() > -9990) {
- _pos.setelev(_aip.getSGLocation()->get_cur_elev_m() + wheelOffset);
+ if(_ground_elevation_m > -9990) {
+ _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) {
double slope = 0.0;
_pos = dclUpdatePosition(_pos, track, slope, dist);
//cout << "Updated position...\n";
- if(_aip.getSGLocation()->get_cur_elev_m() > -9990) {
- _pos.setelev(_aip.getSGLocation()->get_cur_elev_m() + wheelOffset);
+ if(_ground_elevation_m > -9990) {
+ _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;
// Either this function or the logic of how often it is called
// will almost certainly change.
void FGAILocalTraffic::DoGroundElev() {
- // 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();
- if(dclGetHorizontalSeparation(_pos, Point3D(vw->getLongitude_deg(), vw->getLatitude_deg(), 0.0)) > visibility_meters) {
- _aip.getSGLocation()->set_cur_elev_m(aptElev);
+ if(dclGetHorizontalSeparation(_pos, SGGeod::fromDegM(vw->getLongitude_deg(), vw->getLatitude_deg(), 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;
- double lat = _aip.getSGLocation()->getLatitude_deg();
- double lon = _aip.getSGLocation()->getLongitude_deg();
- if (!globals->get_tile_mgr()->scenery_available(lat, lon, range)) {
+ if (!globals->get_tile_mgr()->scenery_available(_aip.getPosition(), range)) {
// Try to shedule tiles for that position.
- globals->get_tile_mgr()->update( _aip.getSGLocation(), range );
+ 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(lat, lon, 20000.0, alt, 0))
- _aip.getSGLocation()->set_cur_elev_m(alt);
+ if (globals->get_scenery()->get_elevation_m(SGGeod::fromGeodM(_aip.getPosition(), 20000), alt, 0))
+ _ground_elevation_m = alt;
}