]> git.mxchange.org Git - flightgear.git/blobdiff - src/ATCDCL/tower.cxx
Remove confusing default (missing) path from 2D panel code.
[flightgear.git] / src / ATCDCL / tower.cxx
index 52d50f9a83c6ddc30656c0955e11cd260ae8b0f6..f765fa4ee486eabdb9d480d139da001ce911cb1e 100644 (file)
 #include <Airports/runways.hxx>
 
 #include "tower.hxx"
+#include "ground.hxx"
 #include "ATCmgr.hxx"
 #include "ATCutils.hxx"
 #include "ATCDialog.hxx"
 #include "commlist.hxx"
-#include "AILocalTraffic.hxx"
 
 
 using std::cout;
@@ -54,7 +54,8 @@ using std::cout;
 // TowerPlaneRec
 
 TowerPlaneRec::TowerPlaneRec() :
-       planePtr(NULL),
+       eta(0),
+       dist_out(0),
        clearedToLand(false),
        clearedToLineUp(false),
        clearedToTakeOff(false),
@@ -71,20 +72,21 @@ TowerPlaneRec::TowerPlaneRec() :
        instructedToGoAround(false),
        onRwy(false),
        nextOnRwy(false),
+       gearWasUp(false),
+       gearUpReported(false),
        vfrArrivalReported(false),
        vfrArrivalAcknowledged(false),
        opType(TTT_UNKNOWN),
        leg(LEG_UNKNOWN),
        landingType(AIP_LT_UNKNOWN),
-       gearWasUp(false),
-       gearUpReported(false),
        isUser(false)
 {
        plane.callsign = "UNKNOWN";
 }
 
 TowerPlaneRec::TowerPlaneRec(const PlaneRec& p) :
-       planePtr(NULL),
+       eta(0),
+       dist_out(0),
        clearedToLand(false),
        clearedToLineUp(false),
        clearedToTakeOff(false),
@@ -101,20 +103,21 @@ TowerPlaneRec::TowerPlaneRec(const PlaneRec& p) :
        instructedToGoAround(false),
        onRwy(false),
        nextOnRwy(false),
+       gearWasUp(false),
+       gearUpReported(false),
        vfrArrivalReported(false),
        vfrArrivalAcknowledged(false),
        opType(TTT_UNKNOWN),
        leg(LEG_UNKNOWN),
        landingType(AIP_LT_UNKNOWN),
-       gearWasUp(false),
-       gearUpReported(false),
        isUser(false)
 {
        plane = p;
 }
 
-TowerPlaneRec::TowerPlaneRec(const Point3D& pt) :
-       planePtr(NULL),
+TowerPlaneRec::TowerPlaneRec(const SGGeod& pt) :
+       eta(0),
+       dist_out(0),
        clearedToLand(false),
        clearedToLineUp(false),
        clearedToTakeOff(false),
@@ -131,21 +134,22 @@ TowerPlaneRec::TowerPlaneRec(const Point3D& pt) :
        instructedToGoAround(false),
        onRwy(false),
        nextOnRwy(false),
+       gearWasUp(false),
+       gearUpReported(false),
        vfrArrivalReported(false),
        vfrArrivalAcknowledged(false),
        opType(TTT_UNKNOWN),
        leg(LEG_UNKNOWN),
        landingType(AIP_LT_UNKNOWN),
-       gearWasUp(false),
-       gearUpReported(false),
        isUser(false)
 {
        plane.callsign = "UNKNOWN";
-       pos = pt;
+       pos = pt;
 }
 
-TowerPlaneRec::TowerPlaneRec(const PlaneRec& p, const Point3D& pt) :
-       planePtr(NULL),
+TowerPlaneRec::TowerPlaneRec(const PlaneRec& p, const SGGeod& pt) :
+       eta(0),
+       dist_out(0),
        clearedToLand(false),
        clearedToLineUp(false),
        clearedToTakeOff(false),
@@ -162,17 +166,17 @@ TowerPlaneRec::TowerPlaneRec(const PlaneRec& p, const Point3D& pt) :
        instructedToGoAround(false),
        onRwy(false),
        nextOnRwy(false),
+       gearWasUp(false),
+       gearUpReported(false),
        vfrArrivalReported(false),
        vfrArrivalAcknowledged(false),
        opType(TTT_UNKNOWN),
        leg(LEG_UNKNOWN),
        landingType(AIP_LT_UNKNOWN),
-       gearWasUp(false),
-       gearUpReported(false),
        isUser(false)
 {
        plane = p;
-       pos = pt;
+       pos = pt;
 }
 
 
@@ -320,9 +324,9 @@ void FGTower::Init() {
        DoRwyDetails();
        
        // TODO - this currently assumes only one active runway.
-       rwyOccupied = OnActiveRunway(Point3D(user_lon_node->getDoubleValue(), user_lat_node->getDoubleValue(), 0.0));
+       rwyOccupied = OnActiveRunway(SGGeod::fromDegM(user_lon_node->getDoubleValue(), user_lat_node->getDoubleValue(), 0.0));
        
-       if(!OnAnyRunway(Point3D(user_lon_node->getDoubleValue(), user_lat_node->getDoubleValue(), 0.0), false)) {
+       if(!OnAnyRunway(SGGeod::fromDegM(user_lon_node->getDoubleValue(), user_lat_node->getDoubleValue(), 0.0), false)) {
                //cout << ident << "  ADD 0\n";
                current_atcdialog->add_entry(ident, "@AP Tower, @CS @MI miles @CD of the airport for full stop@AT",
                                "Contact tower for VFR arrival (full stop)", TOWER,
@@ -337,7 +341,6 @@ void FGTower::Init() {
                t->landingType = AIP_LT_UNKNOWN;
                t->leg = TAKEOFF_ROLL;
                t->isUser = true;
-               t->planePtr = NULL;
                t->clearedToTakeOff = false;
                rwyList.push_back(t);
                rwyListItr = rwyList.begin();
@@ -449,22 +452,6 @@ void FGTower::Update(double dt) {
        
        // Call the base class update for the response time handling.
        FGATC::Update(dt);
-
-       /*
-       if(ident == "KEMT") {   
-               // For AI debugging convienience - may be removed
-               Point3D user_pos;
-               user_pos.setlon(user_lon_node->getDoubleValue());
-               user_pos.setlat(user_lat_node->getDoubleValue());
-               user_pos.setelev(user_elev_node->getDoubleValue());
-               Point3D user_ortho_pos = ortho.ConvertToLocal(user_pos);
-               fgSetDouble("/AI/user/ortho-x", user_ortho_pos.x());
-               fgSetDouble("/AI/user/ortho-y", user_ortho_pos.y());
-               fgSetDouble("/AI/user/elev", user_elev_node->getDoubleValue());
-       }
-       */
-       
-       //cout << "Done T" << endl;
 }
 
 void FGTower::ReceiveUserCallback(int code) {
@@ -507,7 +494,7 @@ void FGTower::Respond() {
                        // Should we clear staight in or for downwind entry?
                        // For now we'll clear straight in if greater than 1km from a line drawn through the threshold perpendicular to the rwy.
                        // Later on we might check the actual heading and direct some of those to enter on downwind or base.
-                       Point3D op = ortho.ConvertToLocal(t->pos);
+                       SGVec3d op = ortho.ConvertToLocal(t->pos);
                        float gp = fgGetFloat("/gear/gear/position-norm");
                        if(gp < 1)
                                t->gearWasUp = true; // This will be needed on final to tell "Gear down, ready to land."
@@ -516,8 +503,6 @@ void FGTower::Respond() {
                                t->opType = STRAIGHT_IN;
                                if(t->isUser) {
                                        current_atcdialog->add_entry(ident, "@CS @MI mile final runway @RW@GR", "Report Final", TOWER, (int)USER_REPORT_3_MILE_FINAL);
-                               } else {
-                                       t->planePtr->RegisterTransmission(14);
                                }
                        } else {
                                // For now we'll just request reporting downwind.
@@ -531,8 +516,6 @@ void FGTower::Respond() {
                                // leave it in the app list until it gets into pattern though.
                                if(t->isUser) {
                                        current_atcdialog->add_entry(ident, "@AP Tower, @CS Downwind @RW", "Report Downwind", TOWER, (int)USER_REPORT_DOWNWIND);
-                               } else {
-                                       t->planePtr->RegisterTransmission(15);
                                }
                        }
                        trns += ConvertRwyNumToSpokenString(activeRwy);
@@ -558,7 +541,7 @@ void FGTower::Respond() {
                                trns += " Cleared for take-off" + wtr;
                                t->clearedToTakeOff = true;
                        } else {
-                               if(!OnAnyRunway(Point3D(user_lon_node->getDoubleValue(), user_lat_node->getDoubleValue(), 0.0), true)) {
+                               if(!OnAnyRunway(SGGeod::fromDegM(user_lon_node->getDoubleValue(), user_lat_node->getDoubleValue(), 0.0), true)) {
                                        // TODO: Check if any AI Planes on final and tell something like: "After the landing CALLSIGN line up runway two eight right"
                                        trns += " Line up runway " + ConvertRwyNumToSpokenString(activeRwy);
                                        t->clearedToTakeOff = false;
@@ -643,8 +626,6 @@ void FGTower::Respond() {
                                        // or put rwy vacated at the top since that'll be more common?
                                        current_atcdialog->add_entry(ident, "@CS Going Around", "Report going around", TOWER, USER_REPORT_GOING_AROUND);
                                        current_atcdialog->add_entry(ident, "@CS Clear of the runway", "Report runway vacated", TOWER, USER_REPORT_RWY_VACATED);
-                               } else {
-                                       t->planePtr->RegisterTransmission(7);
                                }
                        } else if(t->eta < 20) {
                                // Do nothing - we'll be telling it to go around in less than 10 seconds if the
@@ -658,8 +639,6 @@ void FGTower::Respond() {
                                t->opType = CIRCUIT;
                                if(t->isUser) {
                                        current_atcdialog->add_entry(ident, "@AP Tower, @CS Downwind @RW", "Report Downwind", TOWER, (int)USER_REPORT_DOWNWIND);
-                               } else {
-                                       t->planePtr->RegisterTransmission(15);
                                }
                                t->clearedToLand = false;
                        }
@@ -713,7 +692,6 @@ void FGTower::ProcessDownwindReport(TowerPlaneRec* t) {
        if((i == 1) && rwyList.empty() && (t->nextOnRwy) && (!cf)) {    // Unfortunately nextOnRwy currently doesn't handle circuit/straight-in ordering properly at present, hence the cf check below.
                trns += "Cleared to land";      // TODO - clear for the option if appropriate
                t->clearedToLand = true;
-               if(!t->isUser) t->planePtr->RegisterTransmission(7);
        } else if((i+a) > 1) {
                //First set tt to point to the correct preceding plane - final or circuit
                if(tc && tf) {
@@ -736,8 +714,6 @@ void FGTower::ProcessDownwindReport(TowerPlaneRec* t) {
                        PatternLeg leg;
                        if(tt->isUser) {
                                leg = tt->leg;
-                       } else {
-                               leg = tt->planePtr->GetLeg();
                        }
                        if(leg == FINAL) {
                                trns += " on final";
@@ -785,11 +761,9 @@ void FGTower::ProcessRunwayVacatedReport(TowerPlaneRec* t) {
                sprintf(buf, "%.2f", f);
                trns += buf;
                trns += " Good Day";
-               if(!t->isUser) t->planePtr->RegisterTransmission(5);
        } else {
                // Cop-out!!
                trns += " cleared for taxi to general aviation parking";
-               if(!t->isUser) t->planePtr->RegisterTransmission(6);    // TODO - this is a mega-hack!!
        }
        //cout << "trns = " << trns << '\n';
        if(_display) {
@@ -814,7 +788,6 @@ void FGTower::ClearHoldingPlane(TowerPlaneRec* t) {
        //if(timeSinceLastDeparture <= 60.0 && departed == true) {
                trns += " line up runway " + ConvertRwyNumToSpokenString(activeRwy);
                t->clearedToLineUp = true;
-               t->planePtr->RegisterTransmission(3);   // cleared to line-up
        //} else if(arriving plane < some threshold away) {
        } else if(GetTrafficETA(2) < 150.0 && (timeSinceLastDeparture > 60.0 || departed == false)) {   // Hack - hardwired time
                trns += " cleared immediate take-off";
@@ -892,7 +865,6 @@ void FGTower::ClearHoldingPlane(TowerPlaneRec* t) {
                        SG_LOG(SG_ATC, SG_WARN, "Warning: Departing traffic cleared for *immediate* take-off despite no arriving traffic in FGTower");
                }
                t->clearedToTakeOff = true;
-               t->planePtr->RegisterTransmission(4);   // cleared to take-off - TODO differentiate between immediate and normal take-off
                departed = false;
                timeSinceLastDeparture = 0.0;
        } else {
@@ -900,7 +872,6 @@ void FGTower::ClearHoldingPlane(TowerPlaneRec* t) {
                trns += " cleared for take-off";
                // TODO - add traffic is... ?
                t->clearedToTakeOff = true;
-               t->planePtr->RegisterTransmission(4);   // cleared to take-off
                departed = false;
                timeSinceLastDeparture = 0.0;
        }
@@ -972,16 +943,12 @@ void FGTower::CheckCircuitList(double dt) {
                TowerPlaneRec* t = *circuitListItr;
                //cout << ident <<  ' ' << circuitList.size() << ' ' << t->plane.callsign << " " << t->leg << " eta " << t->eta << '\n';
                if(t->isUser) {
-                       t->pos.setlon(user_lon_node->getDoubleValue());
-                       t->pos.setlat(user_lat_node->getDoubleValue());
-                       t->pos.setelev(user_elev_node->getDoubleValue());
+                       t->pos.setLongitudeDeg(user_lon_node->getDoubleValue());
+                       t->pos.setLatitudeDeg(user_lat_node->getDoubleValue());
+                       t->pos.setElevationM(user_elev_node->getDoubleValue());
                        //cout << ident <<  ' ' << circuitList.size() << ' ' << t->plane.callsign << " " << t->leg << " eta " << t->eta << '\n';
-               } else {
-                       t->pos = t->planePtr->GetPos();         // We should probably only set the pos's on one walk through the traffic list in the update function, to save a few CPU should we end up duplicating this.
-                       t->landingType = t->planePtr->GetLandingOption();
-                       //cout << "AI plane landing option is " << t->landingType << '\n';
                }
-               Point3D tortho = ortho.ConvertToLocal(t->pos);
+               SGVec3d tortho = ortho.ConvertToLocal(t->pos);
                if(t->isUser) {
                        // Need to figure out which leg he's on
                        //cout << "rwy.hdg = " << rwy.hdg << " user hdg = " << user_hdg_node->getDoubleValue();
@@ -1067,8 +1034,6 @@ void FGTower::CheckCircuitList(double dt) {
                                        t->leg = LANDING_ROLL;
                                }
                        }
-               } else {
-                       t->leg = t->planePtr->GetLeg();
                }
                
                // Set the constraints IF this is the first plane in the circuit
@@ -1159,10 +1124,6 @@ void FGTower::CheckCircuitList(double dt) {
                                        // Assume it complies!!!
                                        t->opType = CIRCUIT;
                                        t->leg = CLIMBOUT;
-                                       if(t->planePtr) {
-                                               //cout << "Registering Go-around transmission with AI plane\n";
-                                               t->planePtr->RegisterTransmission(13);
-                                       }
                                }
                        } else if(!t->clearedToLand) {
                                // The whip through the appList is a hack since currently t->nextOnRwy doesn't always work
@@ -1181,9 +1142,6 @@ void FGTower::CheckCircuitList(double dt) {
                                                Transmit();
                                                //if(t->isUser) cout << "Transmitting cleared to Land!!!\n";
                                                t->clearedToLand = true;
-                                               if(!t->isUser) {
-                                                       t->planePtr->RegisterTransmission(7);
-                                               }
                                        }
                                } else {
                                        //if(t->isUser) cout << "Not next\n";
@@ -1224,11 +1182,9 @@ void FGTower::CheckRunwayList(double dt) {
                        rwyListItr = rwyList.begin();
                        TowerPlaneRec* t = *rwyListItr;
                        if(t->isUser) {
-                               t->pos.setlon(user_lon_node->getDoubleValue());
-                               t->pos.setlat(user_lat_node->getDoubleValue());
-                               t->pos.setelev(user_elev_node->getDoubleValue());
-                       } else {
-                               t->pos = t->planePtr->GetPos();         // We should probably only set the pos's on one walk through the traffic list in the update function, to save a few CPU should we end up duplicating this.
+                               t->pos.setLongitudeDeg(user_lon_node->getDoubleValue());
+                               t->pos.setLatitudeDeg(user_lat_node->getDoubleValue());
+                               t->pos.setElevationM(user_elev_node->getDoubleValue());
                        }
                        bool on_rwy = OnActiveRunway(t->pos);
                        if(!on_rwy) {
@@ -1288,15 +1244,13 @@ void FGTower::CheckApproachList(double dt) {
                //cout << "t = " << t << endl;
                //cout << "Checking " << t->plane.callsign << endl;
                if(t->isUser) {
-                       t->pos.setlon(user_lon_node->getDoubleValue());
-                       t->pos.setlat(user_lat_node->getDoubleValue());
-                       t->pos.setelev(user_elev_node->getDoubleValue());
-               } else {
-                       // TODO - set/update the position if it's an AI plane
+                       t->pos.setLongitudeDeg(user_lon_node->getDoubleValue());
+                       t->pos.setLatitudeDeg(user_lat_node->getDoubleValue());
+                       t->pos.setElevationM(user_elev_node->getDoubleValue());
                }
                doThresholdETACalc();   // We need this here because planes in the lists are not guaranteed to *always* have the correct ETA
                //cout << "eta is " << t->eta << ", rwy is " << (rwyList.size() ? "occupied " : "clear ") << '\n';
-               Point3D tortho = ortho.ConvertToLocal(t->pos);
+               SGVec3d tortho = ortho.ConvertToLocal(t->pos);
                if(t->eta < 12 && rwyList.size() && !(t->instructedToGoAround)) {
                        // TODO - need to make this more sophisticated 
                        // eg. is the plane accelerating down the runway taking off [OK],
@@ -1321,12 +1275,7 @@ void FGTower::CheckApproachList(double dt) {
                                // Assume it complies!!!
                                t->opType = CIRCUIT;
                                t->leg = CLIMBOUT;
-                               if(!t->isUser) {
-                                       if(t->planePtr) {
-                                               //cout << "Registering Go-around transmission with AI plane\n";
-                                               t->planePtr->RegisterTransmission(13);
-                                       }
-                               } else {
+                               if(t->isUser) {
                                        // TODO - add Go-around ack to comm options,
                                        // remove report rwy vacated. (possibly).
                                }
@@ -1366,9 +1315,6 @@ void FGTower::CheckApproachList(double dt) {
                                        Transmit();
                                        //if(t->isUser) cout << "Transmitting cleared to Land!!!\n";
                                        t->clearedToLand = true;
-                                       if(!t->isUser) {
-                                               t->planePtr->RegisterTransmission(7);
-                                       }
                                }
                        } else {
                                //if(t->isUser) cout << "Not next\n";
@@ -1377,15 +1323,7 @@ void FGTower::CheckApproachList(double dt) {
                
                // Check for landing...
                bool landed = false;
-               if(!t->isUser) {
-                       if(t->planePtr) {
-                               if(t->planePtr->GetLeg() == LANDING_ROLL) {
-                                       landed = true;
-                               }
-                       } else {
-                               SG_LOG(SG_ATC, SG_ALERT, "WARNING - not user and null planePtr in CheckApproachList!");
-                       }
-               } else {        // user
+               if(t->isUser) {
                        if(OnActiveRunway(t->pos)) {
                                landed = true;
                        }
@@ -1425,11 +1363,13 @@ void FGTower::CheckDepartureList(double dt) {
                //cout << "Dep list, checking " << t->plane.callsign;
                
                double distout; // meters
-               if(t->isUser) distout = dclGetHorizontalSeparation(Point3D(lon, lat, elev), Point3D(user_lon_node->getDoubleValue(), user_lat_node->getDoubleValue(), user_elev_node->getDoubleValue()));
-               else distout = dclGetHorizontalSeparation(Point3D(lon, lat, elev), t->planePtr->GetPos());
+               if(t->isUser) {
+                       distout = dclGetHorizontalSeparation(_geod, 
+                               SGGeod::fromDegM(user_lon_node->getDoubleValue(), user_lat_node->getDoubleValue(), user_elev_node->getDoubleValue()));
+               }
                //cout << " distout = " << distout << '\n';
                if(t->isUser && !(t->clearedToTakeOff)) {       // HACK - we use clearedToTakeOff to check if ATC already contacted with plane (and cleared take-off) or not
-                       if(!OnAnyRunway(Point3D(user_lon_node->getDoubleValue(), user_lat_node->getDoubleValue(), 0.0), false)) {
+                       if(!OnAnyRunway(SGGeod::fromDegM(user_lon_node->getDoubleValue(), user_lat_node->getDoubleValue(), 0.0), false)) {
                                current_atcdialog->remove_entry(ident, USER_REQUEST_TAKE_OFF, TOWER);
                                t->clearedToTakeOff = true;     // FIXME
                        }
@@ -1444,9 +1384,6 @@ void FGTower::CheckDepartureList(double dt) {
                                RemoveAllUserDialogOptions();
                                //cout << "ADD A\n";
                                current_atcdialog->add_entry(ident, "@AP Tower, @CS @MI miles @CD of the airport for full stop@AT", "Contact tower for VFR arrival (full stop)", TOWER, (int)USER_REQUEST_VFR_ARRIVAL_FULL_STOP);
-                       } else {
-                               // Send a clear-of-airspace signal
-                               // TODO - implement this once we actually have departing AI traffic (currently all circuits or arrivals).
                        }
                        RemovePlane(t->plane.callsign);
                } else {
@@ -1512,7 +1449,11 @@ void FGTower::DoRwyDetails() {
        // Based on the airport-id and wind get the active runway
        
   const FGAirport* apt = fgFindAirportID(ident);
-  assert(apt);
+  if (!apt) {
+    SG_LOG(SG_ATC, SG_WARN, "FGTower::DoRwyDetails: unknown ICAO:" << ident);
+    return;
+  }
+  
        FGRunway* runway = apt->getActiveRunwayForUsage();
 
   activeRwy = runway->ident();
@@ -1526,20 +1467,18 @@ void FGTower::DoRwyDetails() {
   }
     // 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;
+  double tshlon = 0.0, tshlat = 0.0, tshr = 0.0;
+  double tolon = 0.0, tolat = 0.0, tor = 0.0;
   rwy.length = runway->lengthM();
-    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(), runway->headingDeg(), 
-                        rwy.length / 2.0 - 25.0, &tolat, &tolon, &tor );
-
+  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, runway->latitude(), runway->longitude(), runway->headingDeg(), 
+                      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 = runway->headingDeg();
@@ -1561,10 +1500,10 @@ void FGTower::DoRwyDetails() {
 
 // Figure out if a given position lies on the active runway
 // Might have to change when we consider more than one active rwy.
-bool FGTower::OnActiveRunway(const Point3D& pt) {
+bool FGTower::OnActiveRunway(const SGGeod& pt) {
        // TODO - check that the centre calculation below isn't confused by displaced thesholds etc.
-       Point3D xyc((rwy.end1ortho.x() + rwy.end2ortho.x())/2.0, (rwy.end1ortho.y() + rwy.end2ortho.y())/2.0, 0.0);
-       Point3D xyp = ortho.ConvertToLocal(pt);
+       SGVec3d xyc((rwy.end1ortho.x() + rwy.end2ortho.x())/2.0, (rwy.end1ortho.y() + rwy.end2ortho.y())/2.0, 0.0);
+       SGVec3d xyp = ortho.ConvertToLocal(pt);
        
        //cout << "Length offset = " << fabs(xyp.y() - xyc.y()) << '\n';
        //cout << "Width offset = " << fabs(xyp.x() - xyc.x()) << '\n';
@@ -1579,9 +1518,9 @@ bool FGTower::OnActiveRunway(const Point3D& pt) {
 
 // Figure out if a given position lies on any runway or not
 // Only call this at startup - reading the runways database is expensive and needs to be fixed!
-bool FGTower::OnAnyRunway(const Point3D& pt, bool onGround) {
+bool FGTower::OnAnyRunway(const SGGeod& pt, bool onGround) {
        ATCData ad;
-       double dist = current_commlist->FindClosest(lon, lat, elev, ad, TOWER, 7.0);
+       double dist = current_commlist->FindClosest(_geod, ad, TOWER, 7.0);
        if(dist < 0.0) {
                return(false);
        }
@@ -1832,7 +1771,7 @@ void FGTower::CalcETA(TowerPlaneRec* tpr, bool printout) {
        // Sign convention - dist_out is -ve for approaching planes and +ve for departing planes
        // dist_across is +ve in the pattern direction - ie a plane correctly on downwind will have a +ve dist_across
        
-       Point3D op = ortho.ConvertToLocal(tpr->pos);
+       SGVec3d op = ortho.ConvertToLocal(tpr->pos);
        //if(printout) {
        //if(!tpr->isUser) cout << "Orthopos is " << op.x() << ", " << op.y() << ' ';
        //cout << "opType is " << tpr->opType << '\n';
@@ -1952,16 +1891,12 @@ void FGTower::doThresholdETACalc() {
        // Do the approach list first
        for(twrItr = appList.begin(); twrItr != appList.end(); twrItr++) {
                TowerPlaneRec* tpr = *twrItr;
-               if(!(tpr->isUser)) tpr->pos = tpr->planePtr->GetPos();
-               //cout << "APP: ";
                CalcETA(tpr);
        }       
        // Then the circuit list
        //cout << "Circuit list size is " << circuitList.size() << '\n';
        for(twrItr = circuitList.begin(); twrItr != circuitList.end(); twrItr++) {
                TowerPlaneRec* tpr = *twrItr;
-               if(!(tpr->isUser)) tpr->pos = tpr->planePtr->GetPos();
-               //cout << "CIRC: ";
                CalcETA(tpr);
        }
        //cout << "Done doThresholdETCCalc" << endl;
@@ -2040,65 +1975,6 @@ double FGTower::GetTrafficETA(unsigned int list_pos, bool printout) {
        //cout << "ETA returned = " << tpr->eta << '\n';
        return(tpr->eta);
 }
-       
-
-void FGTower::ContactAtHoldShort(const PlaneRec& plane, FGAIPlane* requestee, tower_traffic_type operation) {
-       // HACK - assume that anything contacting at hold short is new for now - FIXME LATER
-       TowerPlaneRec* t = new TowerPlaneRec;
-       t->plane = plane;
-       t->planePtr = requestee;
-       t->holdShortReported = true;
-       t->clearedToLineUp = false;
-       t->clearedToTakeOff = false;
-       t->opType = operation;
-       t->pos = requestee->GetPos();
-       
-       //cout << "Hold Short reported by " << plane.callsign << '\n';
-       SG_LOG(SG_ATC, SG_BULK, "Hold Short reported by " << plane.callsign);
-
-/*     
-       bool next = AddToTrafficList(t, true);
-       if(next) {
-               double teta = GetTrafficETA(2);
-               if(teta < 150.0) {
-                       t->clearanceCounter = 7.0;      // This reduces the delay before response to 3 secs if an immediate takeoff is reqd
-                       //cout << "Reducing response time to request due imminent traffic\n";
-               }
-       } else {
-       }
-*/
-       // TODO - possibly add the reduced interval to clearance when immediate back in under the new scheme
-
-       holdList.push_back(t);
-       
-       responseReqd = true;
-}
-
-// Register the presence of an AI plane at a point where contact would already have been made in real life
-// CAUTION - currently it is assumed that this plane's callsign is unique - it is up to AIMgr to generate unique callsigns.
-void FGTower::RegisterAIPlane(const PlaneRec& plane, FGAIPlane* ai, const tower_traffic_type& op, const PatternLeg& lg) {
-       // At the moment this is only going to be tested with inserting an AI plane on downwind
-       TowerPlaneRec* t = new TowerPlaneRec;
-       t->plane = plane;
-       t->planePtr = ai;
-       t->opType = op;
-       t->leg = lg;
-       t->pos = ai->GetPos();
-       
-       CalcETA(t);
-       
-       if(op == CIRCUIT && lg != LEG_UNKNOWN) {
-               AddToCircuitList(t);
-       } else {
-               // FLAG A WARNING
-       }
-       
-       doThresholdUseOrder();
-}
-
-void FGTower::DeregisterAIPlane(const string& id) {
-       RemovePlane(id);
-}
 
 // Contact tower for VFR approach
 // eg "Cessna Charlie Foxtrot Golf Foxtrot Sierra eight miles South of the airport for full stop with Bravo"
@@ -2117,9 +1993,9 @@ void FGTower::VFRArrivalContact(const string& ID, const LandingType& opt) {
                        //cout << "NOT t\n";
                        t = new TowerPlaneRec;
                        t->isUser = true;
-                       t->pos.setlon(user_lon_node->getDoubleValue());
-                       t->pos.setlat(user_lat_node->getDoubleValue());
-                       t->pos.setelev(user_elev_node->getDoubleValue());
+                       t->pos.setLongitudeDeg(user_lon_node->getDoubleValue());
+                       t->pos.setLatitudeDeg(user_lat_node->getDoubleValue());
+                       t->pos.setElevationM(user_elev_node->getDoubleValue());
                } else {
                        //cout << "IS t\n";
                        // Oops - the plane is already registered with this tower - maybe we took off and flew a giant circuit without
@@ -2142,6 +2018,7 @@ void FGTower::VFRArrivalContact(const string& ID, const LandingType& opt) {
        
        t->plane.type = GA_SINGLE;      // FIXME - Another assumption!
        t->plane.callsign = usercall;
+       CalcETA(t);
        
        t->vfrArrivalReported = true;
        responseReqd = true;
@@ -2155,33 +2032,6 @@ void FGTower::VFRArrivalContact(const string& ID, const LandingType& opt) {
        current_atcdialog->remove_entry(ident, USER_REQUEST_VFR_ARRIVAL_TOUCH_AND_GO, TOWER);
 }
 
-// landingType defaults to AIP_LT_UNKNOWN
-void FGTower::VFRArrivalContact(const PlaneRec& plane, FGAIPlane* requestee, const LandingType& lt) {
-       //cout << "VFRArrivalContact called for plane " << plane.callsign << " at " << ident << '\n';
-       // Possible hack - assume this plane is new for now - TODO - should check really
-       TowerPlaneRec* t = new TowerPlaneRec;
-       t->plane = plane;
-       t->planePtr = requestee;
-       t->landingType = lt;
-       t->pos = requestee->GetPos();
-       
-       //cout << "Hold Short reported by " << plane.callsign << '\n';
-       SG_LOG(SG_ATC, SG_BULK, "VFR arrival contact made by " << plane.callsign);
-       //cout << "VFR arrival contact made by " << plane.callsign << '\n';
-
-       // HACK - to get up and running I'm going to assume a staight-in final for now.
-       t->opType = STRAIGHT_IN;
-       
-       t->vfrArrivalReported = true;
-       responseReqd = true;
-       
-       //cout << "Before adding, appList.size = " << appList.size() << " at " << ident << '\n';
-       appList.push_back(t);   // Not necessarily permanent
-       appListItr = appList.begin();
-       //cout << "After adding, appList.size = " << appList.size() << " at " << ident << '\n';
-       AddToTrafficList(t);
-}
-
 void FGTower::RequestDepartureClearance(const string& ID) {
        //cout << "Request Departure Clearance called...\n";
 }
@@ -2389,12 +2239,9 @@ void FGTower::ReportDownwind(const string& ID) {
                RemoveFromAppList(ID);
                t->leg = DOWNWIND;
                if(t->isUser) {
-                       t->pos.setlon(user_lon_node->getDoubleValue());
-                       t->pos.setlat(user_lat_node->getDoubleValue());
-                       t->pos.setelev(user_elev_node->getDoubleValue());
-               } else {
-                       // ASSERT(t->planePtr != NULL);
-                       t->pos = t->planePtr->GetPos();
+                       t->pos.setLongitudeDeg(user_lon_node->getDoubleValue());
+                       t->pos.setLatitudeDeg(user_lat_node->getDoubleValue());
+                       t->pos.setElevationM(user_elev_node->getDoubleValue());
                }
                CalcETA(t);
                AddToCircuitList(t);
@@ -2418,12 +2265,9 @@ void FGTower::ReportGoingAround(const string& ID) {
                RemoveFromAppList(ID);
                t->leg = CLIMBOUT;
                if(t->isUser) {
-                       t->pos.setlon(user_lon_node->getDoubleValue());
-                       t->pos.setlat(user_lat_node->getDoubleValue());
-                       t->pos.setelev(user_elev_node->getDoubleValue());
-               } else {
-                       // ASSERT(t->planePtr != NULL);
-                       t->pos = t->planePtr->GetPos();
+                       t->pos.setLongitudeDeg(user_lon_node->getDoubleValue());
+                       t->pos.setLatitudeDeg(user_lat_node->getDoubleValue());
+                       t->pos.setElevationM(user_elev_node->getDoubleValue());
                }
                CalcETA(t);
                AddToCircuitList(t);
@@ -2546,7 +2390,7 @@ string FGTower::GenText(const string& m, int c) {
                                        if (rwyOccupied) {
                                                tmp = "Ready for take-off";
                                        } else {
-                                               if (OnAnyRunway(Point3D(user_lon_node->getDoubleValue(),
+                                               if (OnAnyRunway(SGGeod::fromDegM(user_lon_node->getDoubleValue(),
                                                                user_lat_node->getDoubleValue(), 0.0),true)) {
                                                        tmp = "Request take-off clearance";
                                                } else {
@@ -2558,7 +2402,7 @@ string FGTower::GenText(const string& m, int c) {
                                else if ( strcmp ( tag, "@MI" ) == 0 ) {
                                        char buf[10];
                                        //sprintf( buf, "%3.1f", tpars.miles );
-                                       int dist_miles = (int)dclGetHorizontalSeparation(Point3D(lon, lat, elev), Point3D(user_lon_node->getDoubleValue(), user_lat_node->getDoubleValue(), user_elev_node->getDoubleValue())) / 1600;
+                                       int dist_miles = (int)dclGetHorizontalSeparation(_geod, SGGeod::fromDegM(user_lon_node->getDoubleValue(), user_lat_node->getDoubleValue(), user_elev_node->getDoubleValue())) / 1600;
                                        sprintf(buf, "%i", dist_miles);
                                        strcat( &dum[0], &buf[0] );
                                }
@@ -2578,7 +2422,7 @@ string FGTower::GenText(const string& m, int c) {
                                        }
                                }
                                else if(strcmp(tag, "@CD") == 0) {      // @CD = compass direction
-                                       double h = GetHeadingFromTo(Point3D(lon, lat, elev), Point3D(user_lon_node->getDoubleValue(), user_lat_node->getDoubleValue(), user_elev_node->getDoubleValue()));
+                                       double h = GetHeadingFromTo(_geod, SGGeod::fromDegM(user_lon_node->getDoubleValue(), user_lat_node->getDoubleValue(), user_elev_node->getDoubleValue()));
                                        while(h < 0.0) h += 360.0;
                                        while(h > 360.0) h -= 360.0;
                                        if(h < 22.5 || h > 337.5) {
@@ -2643,9 +2487,13 @@ string FGTower::GetWeather() {
 }
 
 string FGTower::GetATISID() {
-       int hours = fgGetInt("/sim/time/utc/hour");
-       int phonetic_id = current_commlist->GetCallSign(ident, hours, 0);
-       return GetPhoneticIdent(phonetic_id);
+        double tstamp = atof(fgGetString("sim/time/elapsed-sec"));
+        const int minute(60);                   // in SI units
+        int interval = ATIS ? 60*minute : 2*minute;    // AWOS updated frequently
+        int sequence = current_commlist->GetAtisSequence(ident, 
+                              tstamp, interval);
+
+       return GetPhoneticLetter(sequence);  // the sequence letter
 }
 
 ostream& operator << (ostream& os, tower_traffic_type ttt) {
@@ -2659,3 +2507,32 @@ ostream& operator << (ostream& os, tower_traffic_type ttt) {
        return(os << "ERROR - Unknown switch in tower_traffic_type operator << ");
 }
 
+ostream& operator << (ostream& os, PatternLeg pl) {
+       switch(pl) {
+       case(TAKEOFF_ROLL):   return(os << "TAKEOFF ROLL");
+       case(CLIMBOUT):       return(os << "CLIMBOUT");
+       case(TURN1):          return(os << "TURN1");
+       case(CROSSWIND):      return(os << "CROSSWIND");
+       case(TURN2):          return(os << "TURN2");
+       case(DOWNWIND):       return(os << "DOWNWIND");
+       case(TURN3):          return(os << "TURN3");
+       case(BASE):           return(os << "BASE");
+       case(TURN4):          return(os << "TURN4");
+       case(FINAL):          return(os << "FINAL");
+       case(LANDING_ROLL):   return(os << "LANDING ROLL");
+       case(LEG_UNKNOWN):    return(os << "UNKNOWN");
+       }
+       return(os << "ERROR - Unknown switch in PatternLeg operator << ");
+}
+
+
+ostream& operator << (ostream& os, LandingType lt) {
+       switch(lt) {
+       case(FULL_STOP):      return(os << "FULL STOP");
+       case(STOP_AND_GO):    return(os << "STOP AND GO");
+       case(TOUCH_AND_GO):   return(os << "TOUCH AND GO");
+       case(AIP_LT_UNKNOWN): return(os << "UNKNOWN");
+       }
+       return(os << "ERROR - Unknown switch in LandingType operator << ");
+}
+