]> git.mxchange.org Git - flightgear.git/commitdiff
Merge branch 'next' into durk-atc
authorDurk Talsma <durk@localhost.(none)>
Sun, 24 Jul 2011 06:44:22 +0000 (08:44 +0200)
committerDurk Talsma <durk@localhost.(none)>
Sun, 24 Jul 2011 06:44:22 +0000 (08:44 +0200)
30 files changed:
src/AIModel/AIAircraft.cxx
src/AIModel/AIAircraft.hxx
src/AIModel/AIBase.hxx
src/AIModel/AIFlightPlan.cxx
src/AIModel/AIFlightPlan.hxx
src/AIModel/AIFlightPlanCreate.cxx
src/AIModel/AIFlightPlanCreateCruise.cxx
src/AIModel/AIFlightPlanCreatePushBack.cxx
src/ATC/CMakeLists.txt
src/ATC/Makefile.am
src/ATC/atc_mgr.cxx [new file with mode: 0644]
src/ATC/atc_mgr.hxx [new file with mode: 0644]
src/ATC/atcdialog.cxx [new file with mode: 0644]
src/ATC/atcdialog.hxx [new file with mode: 0644]
src/ATC/trafficcontrol.cxx
src/ATC/trafficcontrol.hxx
src/ATCDCL/ATCDialog.cxx
src/Airports/dynamics.cxx
src/Airports/dynamics.hxx
src/Airports/gnnode.cxx
src/Airports/gnnode.hxx
src/Airports/groundnetwork.cxx
src/Airports/groundnetwork.hxx
src/Main/fg_init.cxx
src/Scenery/tilemgr.cxx
src/Traffic/SchedFlight.cxx
src/Traffic/SchedFlight.hxx
src/Traffic/Schedule.cxx
src/Traffic/Schedule.hxx
src/Traffic/TrafficMgr.cxx

index 1c904b79b482123ac9a39e20eddbd042abd11caf..a153db7f7dc8fd6dcc13ac303207afb84415b201 100644 (file)
@@ -1,4 +1,4 @@
-// FGAIAircraft - FGAIBase-derived class creates an AI airplane
+// // FGAIAircraft - FGAIBase-derived class creates an AI airplane
 //
 // Written by David Culp, started October 2003.
 //
@@ -169,7 +169,12 @@ void FGAIAircraft::setPerformance(const std::string& acclass) {
      handleATCRequests(); // ATC also has a word to say
      updateSecondaryTargetValues(); // target roll, vertical speed, pitch
      updateActualState(); 
-     UpdateRadar(manager);
+    // We currently have one situation in which an AIAircraft object is used that is not attached to the 
+    // AI manager. In this particular case, the AIAircraft is used to shadow the user's aircraft's behavior in the AI world.
+    // Since we perhaps don't want a radar entry of our own aircraft, the following conditional should probably be adequate
+    // enough
+     if (manager)
+        UpdateRadar(manager);
      checkVisibility();
   }
 
@@ -280,6 +285,19 @@ void FGAIAircraft::ProcessFlightPlan( double dt, time_t now ) {
     if (! leadPointReached(curr)) {
         controlHeading(curr);
         controlSpeed(curr, next);
+            if (speed < 0) { 
+                cerr << getCallSign() 
+                     << ": verifying lead distance to waypoint : " 
+                     << fp->getCurrentWaypoint()->name << " "
+                     << fp->getLeadDistance() << ". Distance to go " 
+                     << (fp->getDistanceToGo(pos.getLatitudeDeg(), pos.getLongitudeDeg(), curr)) 
+                     << ". Target speed = " 
+                     << tgt_speed
+                     << ". Current speed = "
+                     << speed
+                     << ". Minimum Bearing " << minBearing
+                     << endl;
+            }
     } else {
         if (curr->finished)      //end of the flight plan
         {
@@ -680,7 +698,15 @@ bool FGAIAircraft::leadPointReached(FGAIFlightPlan::waypoint* curr) {
     //cerr << "2" << endl;
     double lead_dist = fp->getLeadDistance();
     // experimental: Use fabs, because speed can be negative (I hope) during push_back.
-
+    if ((dist_to_go < fabs(10.0* speed)) && (speed < 0) && (tgt_speed < 0) && fp->getCurrentWaypoint()->name == string("PushBackPoint")) {
+          tgt_speed = -(dist_to_go / 10.0);
+          if (tgt_speed > -0.5) {
+                tgt_speed = -0.5;
+          }
+          if (fp->getPreviousWaypoint()->speed < tgt_speed) {
+              fp->getPreviousWaypoint()->speed = tgt_speed;
+          }
+    }
     if (lead_dist < fabs(2*speed)) {
       //don't skip over the waypoint
       lead_dist = fabs(2*speed);
@@ -940,8 +966,8 @@ void FGAIAircraft::updateHeading() {
                 bank_sense = 1.0;
             }
             //if (trafficRef)
-               //cerr << trafficRef->getCallSign() << " Heading " 
-                //     << hdg << ". Target " << tgt_heading <<  ". Diff " << fabs(sum - tgt_heading) << ". Speed " << speed << endl;
+            // cerr << trafficRef->getCallSign() << " Heading " 
+            //         << hdg << ". Target " << tgt_heading <<  ". Diff " << fabs(sum - tgt_heading) << ". Speed " << speed << endl;
             //if (headingDiff > 60) {
             groundTargetSpeed = tgt_speed; // * cos(headingDiff * SG_DEGREES_TO_RADIANS);
                 //groundTargetSpeed = tgt_speed - tgt_speed * (headingDiff/180);
@@ -950,27 +976,34 @@ void FGAIAircraft::updateHeading() {
             //}
             if (sign(groundTargetSpeed) != sign(tgt_speed))
                 groundTargetSpeed = 0.21 * sign(tgt_speed); // to prevent speed getting stuck in 'negative' mode
-
-            if (headingDiff > 30.0) {
-                // invert if pushed backward
-                headingChangeRate += 10.0 * dt * sign(roll);
-
-                // Clamp the maximum steering rate to 30 degrees per second,
-                // But only do this when the heading error is decreasing.
-                if ((headingDiff < headingError)) {
-                    if (headingChangeRate > 30)
-                        headingChangeRate = 30;
-                    else if (headingChangeRate < -30)
-                        headingChangeRate = -30;
+            
+            // Only update the target values when we're not moving because otherwise we might introduce an enormous target change rate while waiting a the gate, or holding.
+            if (speed != 0) {
+                if (headingDiff > 30.0) {
+                    // invert if pushed backward
+                    headingChangeRate += 10.0 * dt * sign(roll);
+
+                    // Clamp the maximum steering rate to 30 degrees per second,
+                    // But only do this when the heading error is decreasing.
+                    if ((headingDiff < headingError)) {
+                        if (headingChangeRate > 30)
+                            headingChangeRate = 30;
+                        else if (headingChangeRate < -30)
+                            headingChangeRate = -30;
+                    }
+                } else {
+                    if (speed != 0) {
+                        if (fabs(headingChangeRate) > headingDiff)
+                            headingChangeRate = headingDiff*sign(roll);
+                        else
+                            headingChangeRate += dt * sign(roll);
+                    }
                 }
-            } else {
-                   if (fabs(headingChangeRate) > headingDiff)
-                       headingChangeRate = headingDiff*sign(roll);
-                   else
-                       headingChangeRate += dt * sign(roll);
             }
-
-           hdg += headingChangeRate * dt * (fabs(speed) / 15);
+            if (trafficRef)
+               //cerr << trafficRef->getCallSign() << " Heading " 
+                //     << hdg << ". Target " << tgt_heading <<  ". Diff " << fabs(sum - tgt_heading) << ". Speed " << speed << "Heading change rate : " << headingChangeRate << " bacnk sence " << bank_sense << endl;
+           hdg += headingChangeRate * dt * sqrt(fabs(speed) / 15);
             headingError = headingDiff;
         } else {
             if (fabs(speed) > 1.0) {
@@ -1092,12 +1125,12 @@ string FGAIAircraft::atGate() {
 void FGAIAircraft::handleATCRequests() {
     //TODO implement NullController for having no ATC to save the conditionals
     if (controller) {
-        controller->update(getID(),
-                           pos.getLatitudeDeg(),
-                           pos.getLongitudeDeg(),
-                           hdg,
-                           speed,
-                           altitude_ft, dt);
+        controller->updateAircraftInformation(getID(),
+                                              pos.getLatitudeDeg(),
+                                              pos.getLongitudeDeg(),
+                                              hdg,
+                                              speed,
+                                              altitude_ft, dt);
         processATC(controller->getInstruction(getID()));
     }
 }
index ea99462d8b5ff1b7984338f0501366e7f352acd4..c1bbaa9f9b1b3b4229d801e90a4f9217b1eb87b0 100644 (file)
@@ -76,6 +76,7 @@ public:
     void setTaxiClearanceRequest(bool arg) { needsTaxiClearance = arg; };
     bool getTaxiClearanceRequest() { return needsTaxiClearance; };
     FGAISchedule * getTrafficRef() { return trafficRef; };
+    void setTrafficRef(FGAISchedule *ref) { trafficRef = ref; };
 
     virtual const char* getTypeString(void) const { return "aircraft"; }
 
@@ -95,6 +96,8 @@ public:
     std::string atGate();
 
     void checkTcas();
+
+    FGATCController * getATCController() { return controller; };
     
 protected:
     void Run(double dt);
index 61351adbbdc2f1f33b42c3f8d82da254b85fcc81..afedabc3f73c50889c903240baebe6565ad4377d 100644 (file)
@@ -304,6 +304,8 @@ public:
         SGPropertyNode *prop_root);
 
     static bool _isNight();
+
+     string & getCallSign();
 };
 
 inline void FGAIBase::setManager(FGAIManager* mgr, SGPropertyNode* p) {
@@ -364,6 +366,10 @@ inline void FGAIBase::setLatitude ( double latitude ) {
 inline void FGAIBase::setCallSign(const string& s) {
     _callsign = s;
 }
+inline string& FGAIBase::getCallSign() {
+    return _callsign;
+}
+
 inline void FGAIBase::setXoffset(double x) {
     _x_offset = x;
 }
index 914f5442c7e6c0990abed8fc341e24044186c2d9..2fa5c36092badad57ca64d0d90ecc620fd41ff64 100644 (file)
@@ -1,4 +1,4 @@
-// FGAIFlightPlan - class for loading and storing  AI flight plans
+// // FGAIFlightPlan - class for loading and storing  AI flight plans
 // Written by David Culp, started May 2004
 // - davidculp2@comcast.net
 //
@@ -50,6 +50,7 @@ FGAIFlightPlan::FGAIFlightPlan()
 {
    sid = 0;
    wpt_iterator = waypoints.begin();
+   isValid = true;
 }
 
 FGAIFlightPlan::FGAIFlightPlan(const string& filename)
@@ -98,6 +99,7 @@ FGAIFlightPlan::FGAIFlightPlan(const string& filename)
    }
 
   wpt_iterator = waypoints.begin();
+  isValid = true;
   //cout << waypoints.size() << " waypoints read." << endl;
 }
 
@@ -137,7 +139,7 @@ FGAIFlightPlan::FGAIFlightPlan(FGAIAircraft *ac,
   path.append( p );
   
   SGPropertyNode root;
-  
+  isValid = true;
   // This is a bit of a hack:
   // Normally the value of course will be used to evaluate whether
   // or not a waypoint will be used for midair initialization of 
@@ -205,7 +207,7 @@ FGAIFlightPlan::FGAIFlightPlan(FGAIAircraft *ac,
       SG_LOG(SG_GENERAL, SG_INFO, "Route from " << dep->getId() << " to " << arr->getId() << ". Set leg to : " << leg << " " << ac->getTrafficRef()->getCallSign());
       wpt_iterator = waypoints.begin();
       bool dist = 0;
-      create(ac, dep,arr, leg, alt, speed, lat, lon,
+      isValid = create(ac, dep,arr, leg, alt, speed, lat, lon,
             firstLeg, radius, fltType, acType, airline, dist);
       wpt_iterator = waypoints.begin();
       //cerr << "after create: " << (*wpt_iterator)->name << endl;
index fd39683056aa4d42f88a84d768dc37ac0da0e3cf..44485ae754923be75dc9db25b496c23ab52ba9c8 100644 (file)
@@ -1,4 +1,4 @@
-// FGAIFlightPlan - class for loading and storing  AI flight plans
+// // FGAIFlightPlan - class for loading and storing  AI flight plans
 // Written by David Culp, started May 2004
 // - davidculp2@comcast.net
 //
@@ -87,12 +87,16 @@ public:
   time_t getStartTime() const { return start_time; }
    time_t getArrivalTime() const { return arrivalTime; }
 
-  void    create(FGAIAircraft *, FGAirport *dep, FGAirport *arr, int leg, double alt, double speed, double lat, double lon,
+  bool    create(FGAIAircraft *, FGAirport *dep, FGAirport *arr, int leg, double alt, double speed, double lat, double lon,
                 bool firstLeg, double radius, const std::string& fltType, const std::string& aircraftType, const std::string& airline, double distance);
+  bool createPushBack(FGAIAircraft *, bool, FGAirport*, double, double, double, const std::string&, const std::string&, const std::string&);
+  bool createTakeOff(FGAIAircraft *, bool, FGAirport *, double, const std::string&);
 
   void setLeg(int val) { leg = val;}
   void setTime(time_t st) { start_time = st; }
   int getGate() const { return gateId; }
+  void setGate(int id) { gateId = id; };
+
   double getLeadInAngle() const { return leadInAngle; }
   const std::string& getRunway() const;
   
@@ -138,22 +142,21 @@ private:
   std::string activeRunway;
   FGTaxiRoute *taxiRoute;
   std::string name;
+  bool isValid;
 
-  void createPushBack(FGAIAircraft *, bool, FGAirport*, double, double, double, const std::string&, const std::string&, const std::string&);
   void createPushBackFallBack(FGAIAircraft *, bool, FGAirport*, double, double, double, const std::string&, const std::string&, const std::string&);
-  void createTakeOff(FGAIAircraft *, bool, FGAirport *, double, const std::string&);
-  void createClimb(FGAIAircraft *, bool, FGAirport *, double, double, const std::string&);
-  void createCruise(FGAIAircraft *, bool, FGAirport*, FGAirport*, double, double, double, double, const std::string&);
-  void createDescent(FGAIAircraft *, FGAirport *,  double latitude, double longitude, double speed, double alt,const std::string&, double distance);
-  void createLanding(FGAIAircraft *, FGAirport *, const std::string&);
-  void createParking(FGAIAircraft *, FGAirport *, double radius);
+  bool createClimb(FGAIAircraft *, bool, FGAirport *, double, double, const std::string&);
+  bool createCruise(FGAIAircraft *, bool, FGAirport*, FGAirport*, double, double, double, double, const std::string&);
+  bool createDescent(FGAIAircraft *, FGAirport *,  double latitude, double longitude, double speed, double alt,const std::string&, double distance);
+  bool createLanding(FGAIAircraft *, FGAirport *, const std::string&);
+  bool createParking(FGAIAircraft *, FGAirport *, double radius);
   void deleteWaypoints(); 
   void resetWaypoints();
 
-  void createLandingTaxi(FGAIAircraft *, FGAirport *apt, double radius, const std::string& fltType, const std::string& acType, const std::string& airline);
+  bool createLandingTaxi(FGAIAircraft *, FGAirport *apt, double radius, const std::string& fltType, const std::string& acType, const std::string& airline);
   void createDefaultLandingTaxi(FGAIAircraft *, FGAirport* aAirport);
   void createDefaultTakeoffTaxi(FGAIAircraft *, FGAirport* aAirport, FGRunway* aRunway);
-  void createTakeoffTaxi(FGAIAircraft *, bool firstFlight, FGAirport *apt, double radius, const std::string& fltType, const std::string& acType, const std::string& airline);
+  bool createTakeoffTaxi(FGAIAircraft *, bool firstFlight, FGAirport *apt, double radius, const std::string& fltType, const std::string& acType, const std::string& airline);
 
   double getTurnRadius(double, bool);
         
@@ -168,7 +171,7 @@ private:
  public:
   wpt_vector_iterator getFirstWayPoint() { return waypoints.begin(); };
   wpt_vector_iterator getLastWayPoint()  { return waypoints.end(); };
-
+    bool isValidPlan() { return isValid; };
 };    
 
 #endif  // _FG_AIFLIGHTPLAN_HXX
index a0a396d8fe02ea0874f77432e78b2d4d41911943..9ba1c4d8b9bf7b18183d7627c58f50d9a4fc250f 100644 (file)
@@ -47,7 +47,7 @@
 
 
 // Check lat/lon values during initialization;
-void FGAIFlightPlan::create(FGAIAircraft * ac, FGAirport * dep,
+bool FGAIFlightPlan::create(FGAIAircraft * ac, FGAirport * dep,
                             FGAirport * arr, int legNr, double alt,
                             double speed, double latitude,
                             double longitude, bool firstFlight,
@@ -55,38 +55,39 @@ void FGAIFlightPlan::create(FGAIAircraft * ac, FGAirport * dep,
                             const string & aircraftType,
                             const string & airline, double distance)
 {
+    bool retVal = true;
     int currWpt = wpt_iterator - waypoints.begin();
     switch (legNr) {
     case 1:
-        createPushBack(ac, firstFlight, dep, latitude, longitude,
-                       radius, fltType, aircraftType, airline);
+        retVal = createPushBack(ac, firstFlight, dep, latitude, longitude,
+                                radius, fltType, aircraftType, airline);
         break;
     case 2:
-        createTakeoffTaxi(ac, firstFlight, dep, radius, fltType,
+        retVal =  createTakeoffTaxi(ac, firstFlight, dep, radius, fltType,
                           aircraftType, airline);
         break;
     case 3:
-        createTakeOff(ac, firstFlight, dep, speed, fltType);
+        retVal = createTakeOff(ac, firstFlight, dep, speed, fltType);
         break;
     case 4:
-        createClimb(ac, firstFlight, dep, speed, alt, fltType);
+        retVal = createClimb(ac, firstFlight, dep, speed, alt, fltType);
         break;
     case 5:
-        createCruise(ac, firstFlight, dep, arr, latitude, longitude, speed,
+        retVal = createCruise(ac, firstFlight, dep, arr, latitude, longitude, speed,
                      alt, fltType);
         break;
     case 6:
-        createDescent(ac, arr, latitude, longitude, speed, alt, fltType,
+        retVal = createDescent(ac, arr, latitude, longitude, speed, alt, fltType,
                       distance);
         break;
     case 7:
-        createLanding(ac, arr, fltType);
+        retVal = createLanding(ac, arr, fltType);
         break;
     case 8:
-        createLandingTaxi(ac, arr, radius, fltType, aircraftType, airline);
+        retVal = createLandingTaxi(ac, arr, radius, fltType, aircraftType, airline);
         break;
     case 9:
-        createParking(ac, arr, radius);
+        retVal = createParking(ac, arr, radius);
         break;
     default:
         //exit(1);
@@ -96,6 +97,7 @@ void FGAIFlightPlan::create(FGAIAircraft * ac, FGAirport * dep,
     }
     wpt_iterator = waypoints.begin() + currWpt;
     leg++;
+    return retVal;
 }
 
 FGAIFlightPlan::waypoint *
@@ -200,7 +202,7 @@ void FGAIFlightPlan::createDefaultTakeoffTaxi(FGAIAircraft * ac,
     waypoints.push_back(wpt);
 }
 
-void FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft * ac, bool firstFlight,
+bool FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft * ac, bool firstFlight,
                                        FGAirport * apt,
                                        double radius,
                                        const string & fltType,
@@ -240,7 +242,7 @@ void FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft * ac, bool firstFlight,
     FGGroundNetwork *gn = apt->getDynamics()->getGroundNetwork();
     if (!gn->exists()) {
         createDefaultTakeoffTaxi(ac, apt, rwy);
-        return;
+        return true;
     }
 
     intVec ids;
@@ -278,7 +280,7 @@ void FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft * ac, bool firstFlight,
 
     if (taxiRoute->empty()) {
         createDefaultTakeoffTaxi(ac, apt, rwy);
-        return;
+        return true;
     }
 
     taxiRoute->first();
@@ -313,6 +315,7 @@ void FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft * ac, bool firstFlight,
         wpt->routeIndex = route;
         waypoints.push_back(wpt);
     }
+    return true;
 }
 
 void FGAIFlightPlan::createDefaultLandingTaxi(FGAIAircraft * ac,
@@ -341,7 +344,7 @@ void FGAIFlightPlan::createDefaultLandingTaxi(FGAIAircraft * ac,
     waypoints.push_back(wpt);
 }
 
-void FGAIFlightPlan::createLandingTaxi(FGAIAircraft * ac, FGAirport * apt,
+bool FGAIFlightPlan::createLandingTaxi(FGAIAircraft * ac, FGAirport * apt,
                                        double radius,
                                        const string & fltType,
                                        const string & acType,
@@ -360,7 +363,7 @@ void FGAIFlightPlan::createLandingTaxi(FGAIAircraft * ac, FGAirport * apt,
     // Find a route from runway end to parking/gate.
     if (!gn->exists()) {
         createDefaultLandingTaxi(ac, apt);
-        return;
+        return true;
     }
 
     intVec ids;
@@ -379,7 +382,7 @@ void FGAIFlightPlan::createLandingTaxi(FGAIAircraft * ac, FGAirport * apt,
 
     if (taxiRoute->empty()) {
         createDefaultLandingTaxi(ac, apt);
-        return;
+        return true;
     }
 
     int node;
@@ -399,6 +402,7 @@ void FGAIFlightPlan::createLandingTaxi(FGAIAircraft * ac, FGAirport * apt,
         wpt->routeIndex = route;
         waypoints.push_back(wpt);
     }
+    return true;
 }
 
 /*******************************************************************
@@ -412,7 +416,7 @@ void FGAIFlightPlan::createLandingTaxi(FGAIAircraft * ac, FGAirport * apt,
  *  more likely however. 
  * 
  ******************************************************************/
-void FGAIFlightPlan::createTakeOff(FGAIAircraft * ac, bool firstFlight,
+bool FGAIFlightPlan::createTakeOff(FGAIAircraft * ac, bool firstFlight,
                                    FGAirport * apt, double speed,
                                    const string & fltType)
 {
@@ -487,13 +491,14 @@ void FGAIFlightPlan::createTakeOff(FGAIAircraft * ac, bool firstFlight,
     wpt = cloneWithPos(ac, wpt, "5000 ft", pt);
     wpt->altitude = airportElev + 5000;
     waypoints.push_back(wpt);
+    return true;
 }
 
 /*******************************************************************
  * CreateClimb
  * initialize the Aircraft at the parking location
  ******************************************************************/
-void FGAIFlightPlan::createClimb(FGAIAircraft * ac, bool firstFlight,
+bool FGAIFlightPlan::createClimb(FGAIAircraft * ac, bool firstFlight,
                                  FGAirport * apt, double speed, double alt,
                                  const string & fltType)
 {
@@ -527,6 +532,7 @@ void FGAIFlightPlan::createClimb(FGAIAircraft * ac, bool firstFlight,
         wpt->altitude = 18000;
         waypoints.push_back(wpt);
     }
+    return true;
 }
 
 
@@ -536,7 +542,7 @@ void FGAIFlightPlan::createClimb(FGAIAircraft * ac, bool firstFlight,
  * Generate a flight path from the last waypoint of the cruise to 
  * the permission to land point
  ******************************************************************/
-void FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt,
+bool FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt,
                                    double latitude, double longitude,
                                    double speed, double alt,
                                    const string & fltType,
@@ -823,8 +829,7 @@ void FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt,
         //cerr << "Repositioning to waypoint " << (*waypoints.begin())->name << endl;
         ac->resetPositionFromFlightPlan();
     }
-
-
+    return true;
 }
 
 /*******************************************************************
@@ -833,7 +838,7 @@ void FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt,
    hardcoded at 5000 meters from the threshold) to the threshold, at
    a standard glide slope angle of 3 degrees. 
  ******************************************************************/
-void FGAIFlightPlan::createLanding(FGAIAircraft * ac, FGAirport * apt,
+bool FGAIFlightPlan::createLanding(FGAIAircraft * ac, FGAirport * apt,
                                    const string & fltType)
 {
     double vTouchdown = ac->getPerformance()->vTouchdown();
@@ -873,13 +878,14 @@ void FGAIFlightPlan::createLanding(FGAIAircraft * ac, FGAirport * apt,
        wpt->crossat   = apt->getElevation();
        waypoints.push_back(wpt); 
      */
+    return true;
 }
 
 /*******************************************************************
  * CreateParking
  * initialize the Aircraft at the parking location
  ******************************************************************/
-void FGAIFlightPlan::createParking(FGAIAircraft * ac, FGAirport * apt,
+bool FGAIFlightPlan::createParking(FGAIAircraft * ac, FGAirport * apt,
                                    double radius)
 {
     waypoint *wpt;
@@ -914,6 +920,7 @@ void FGAIFlightPlan::createParking(FGAIAircraft * ac, FGAirport * apt,
         createOnGround(ac, "END", SGGeod::fromDeg(lon, lat), aptElev,
                        vTaxiReduced);
     waypoints.push_back(wpt);
+    return true;
 }
 
 /**
index 1932de9ce3586c640b4842564e6beb2b3fc95be4..05f80c89a7ff9c4d125b09124d92d7f2b2306c33 100644 (file)
@@ -286,7 +286,7 @@ void FGAIFlightPlan::createCruise(bool firstFlight, FGAirport *dep,
  * Note that this is the original version that does not 
  * do any dynamic route computation.
  ******************************************************************/
-void FGAIFlightPlan::createCruise(FGAIAircraft *ac, bool firstFlight, FGAirport *dep, 
+bool FGAIFlightPlan::createCruise(FGAIAircraft *ac, bool firstFlight, FGAirport *dep, 
                                  FGAirport *arr, double latitude, 
                                  double longitude, double speed, 
                                  double alt, const string& fltType)
index 34f21a1fc196b0faabef515b10a6c18e6b4613fe..de2d83eeb3ce56a2e2260452c24af061c76b7e9a 100644 (file)
@@ -37,7 +37,7 @@
 
 
 // TODO: Use James Turner's createOnGround functions.
-void FGAIFlightPlan::createPushBack(FGAIAircraft *ac,
+bool FGAIFlightPlan::createPushBack(FGAIAircraft *ac,
                                     bool firstFlight, FGAirport *dep, 
                                    double latitude,
                                    double longitude,
@@ -71,6 +71,7 @@ void FGAIFlightPlan::createPushBack(FGAIAircraft *ac,
                                               " of flight type " << fltType << 
                                               " of airline     " << airline <<
                                               " at airport     " << dep->getId());
+                    return false;
                     char buffer[10];
                     snprintf (buffer, 10, "%d", gateId);
                     //FGTaxiNode *tn = dep->getDynamics()->getGroundNetwork()->findNode(node);
@@ -104,7 +105,7 @@ void FGAIFlightPlan::createPushBack(FGAIAircraft *ac,
         if (gateId < 0) {
              createPushBackFallBack(ac, firstFlight, dep, latitude, longitude,
                                     radius, fltType, aircraftType, airline);
-             return;
+             return true;
 
         }
        //cerr << "getting parking " << gateId;
@@ -164,7 +165,66 @@ void FGAIFlightPlan::createPushBack(FGAIAircraft *ac,
               //    cerr << "Waypoint Name: " << (*i)->name << endl;
               //}
         } else {
+           /*
+           string rwyClass = getRunwayClassFromTrafficType(fltType);
+
+           // Only set this if it hasn't been set by ATC already.
+          if (activeRunway.empty()) {
+               //cerr << "Getting runway for " << ac->getTrafficRef()->getCallSign() << " at " << apt->getId() << endl;
+              double depHeading = ac->getTrafficRef()->getCourse();
+             dep->getDynamics()->getActiveRunway(rwyClass, 1, activeRunway,
+                                                 depHeading);
+           }
+           rwy = dep->getRunwayByIdent(activeRunway);
+           SGGeod runwayTakeoff = rwy->pointOnCenterline(5.0);
+
+          FGGroundNetwork *gn = dep->getDynamics()->getGroundNetwork();
+          if (!gn->exists()) {
+              createDefaultTakeoffTaxi(ac, dep, rwy);
+              return true;
+          }
+          int runwayId = gn->findNearestNode(runwayTakeoff);
+          int node = 0;
+           // Find out which node to start from
+          FGParking *park = dep->getDynamics()->getParking(gateId);
+        if (park) {
+            node = park->getPushBackPoint();
+        }
+
+        if (node == -1) {
+            node = gateId;
+        }
+        // HAndle case where parking doens't have a node
+        if ((node == 0) && park) {
+            if (firstFlight) {
+                node = gateId;
+            } else {
+                node = gateId;
+            }
+        }
+        //delete taxiRoute;
+        //taxiRoute = new FGTaxiRoute;
+        FGTaxiRoute tr = gn->findShortestRoute(node, runwayId);
+        int route;
+        FGTaxiNode *tn;
+        waypoint *wpt;
+        int nr = 0;
+        cerr << "Creating taxiroute from gate: " << gateId << " at " << dep->getId() << endl;
+        while (tr.next(&node, &route) && (nr++ < 3)) {
+            char buffer[10];
+            snprintf(buffer, 10, "%d", node);
+             tn = dep->getDynamics()->getGroundNetwork()->findNode(node);
+             wpt = createOnGround(ac, buffer, tn->getGeod(), dep->getElevation(),
+                               vTaxiReduced);
+            wpt->routeIndex = route;
+            waypoints.push_back(wpt);
+        }
+        wpt->name      = "PushBackPoint";
+        lastNodeVisited = tn->getIndex();
+           //FGTaxiNode *firstNode = findNode(gateId);
+           //FGTaxiNode *lastNode =  findNode(runwayId);
            //cerr << "Creating direct forward departure route fragment" << endl;
+           */
            double lat2 = 0.0, lon2 = 0.0, az2 = 0.0;
            waypoint *wpt;
            geo_direct_wgs_84 ( 0, lat, lon, heading, 
@@ -226,11 +286,10 @@ void FGAIFlightPlan::createPushBack(FGAIAircraft *ac,
            wpt->on_ground = true;
            wpt->routeIndex = (*ts)->getIndex();
            waypoints.push_back(wpt);
-
-
         }
 
     }
+    return true;
 }
 /*******************************************************************
  * createPushBackFallBack
index 98b6a0d250a9521e341dc04369a7463fce9132f7..dd1c0039662e29b7b585c850281adc54bb42d87d 100644 (file)
@@ -1,6 +1,7 @@
 include(FlightGearComponent)
 
 set(SOURCES
+       atc_mgr.cxx
        trafficcontrol.cxx
        CommStation.cxx
        )
index 046428e83c9368c0b868c95070db296fca066dfc..522a82033d1a5639c960d97790de2cff73db47c0 100644 (file)
@@ -1,7 +1,9 @@
 noinst_LIBRARIES = libATC.a
 
 libATC_a_SOURCES = \
-    CommStation.cxx CommStation.hxx \
+       atcdialog.cxx atcdialog.hxx \
+       atc_mgr.cxx atc_mgr.hxx \
+       CommStation.cxx CommStation.hxx \
        trafficcontrol.cxx trafficcontrol.hxx 
 
 INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src
diff --git a/src/ATC/atc_mgr.cxx b/src/ATC/atc_mgr.cxx
new file mode 100644 (file)
index 0000000..0bdc5e5
--- /dev/null
@@ -0,0 +1,224 @@
+/******************************************************************************
+ * atc_mgr.cxx
+ * Written by Durk Talsma, started August 1, 2010.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *
+ **************************************************************************/
+
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <iostream>
+
+#include <simgear/math/SGMath.hxx>
+#include <Airports/dynamics.hxx>
+#include <Airports/simple.hxx>
+#include <Scenery/scenery.hxx>
+#include "atc_mgr.hxx"
+
+
+FGATCManager::FGATCManager() {
+
+}
+
+FGATCManager::~FGATCManager() {
+
+}
+
+void FGATCManager::init() {
+    SGSubsystem::init();
+    currentATCDialog = new FGATCDialogNew;
+    currentATCDialog->init();
+
+    int leg = 0;
+
+    // find a reasonable controller for our user's aircraft..
+    // Let's start by working out the following three scenarios: 
+    // Starting on ground at a parking position
+    // Starting on ground at the runway.
+    // Starting in the Air
+    bool onGround  = fgGetBool("/sim/presets/onground");
+    string runway  = fgGetString("/sim/atc/runway");
+    string airport = fgGetString("/sim/presets/airport-id");
+    string parking = fgGetString("/sim/presets/parkpos");
+    
+
+    // Create an (invisible) AIAircraft represenation of the current
+    // Users, aircraft, that mimicks the user aircraft's behavior.
+    string callsign= fgGetString("/sim/multiplay/callsign");
+    double longitude = fgGetDouble("/position/longitude-deg");
+    double latitude  = fgGetDouble("/position/latitude-deg");
+    double altitude  = fgGetDouble("/position/altitude-ft");
+    double heading   = fgGetDouble("/orientation/heading-deg");
+    double speed     = fgGetDouble("/velocities/groundspeed-kt");
+    double aircraftRadius = 40; // note that this is currently hardcoded to a one-size-fits all JumboJet value. Should change later;
+
+
+    ai_ac.setCallSign ( callsign  );
+    ai_ac.setLongitude( longitude );
+    ai_ac.setLatitude ( latitude  );
+    ai_ac.setAltitude ( altitude  );
+    ai_ac.setPerformance("jet_transport");
+
+    // NEXT UP: Create a traffic Schedule and fill that with appropriate information. This we can use to flight plannign.
+    FGAISchedule *trafficRef = new FGAISchedule;
+    trafficRef->setFlightType("gate");
+
+    FGScheduledFlight *flight =  new FGScheduledFlight;
+    flight->setDepartureAirport(airport);
+    flight->setArrivalAirport(airport);
+    flight->initializeAirports();
+    flight->setFlightRules("IFR");
+    flight->setCallSign(callsign);
+    
+    trafficRef->assign(flight);
+    FGAIFlightPlan *fp = new FGAIFlightPlan;
+    ai_ac.setTrafficRef(trafficRef);
+    
+    string flightPlanName = airport + "-" + airport + ".xml";
+    double cruiseAlt = 100; // Doesn't really matter right now.
+    double courseToDest = 180; // Just use something neutral; this value might affect the runway that is used though...
+    time_t deptime = 0;        // just make sure how flightplan processing is affected by this...
+
+
+    FGAirport *apt = FGAirport::findByIdent(airport); 
+    FGAirportDynamics* dcs = apt->getDynamics();
+    int park_index = dcs->getNrOfParkings() - 1;
+    cerr << "found information: " << runway << " " << airport << ": parking = " << parking << endl;
+    if (onGround) {
+        while (park_index >= 0 && dcs->getParkingName(park_index) != parking) park_index--;
+            if (park_index < 0) {
+                  SG_LOG( SG_GENERAL, SG_ALERT,
+                          "Failed to find parking position " << parking <<
+                           " at airport " << airport );
+             }
+        if (parking.empty() || (park_index < 0)) {
+            controller = apt->getDynamics()->getTowerController();
+            int stationFreq = apt->getDynamics()->getTowerFrequency(2);
+            cerr << "Setting radio frequency to in airfrequency: " << stationFreq << endl;
+            fgSetDouble("/instrumentation/comm[0]/frequencies/selected-mhz", ((double) stationFreq / 100.0));
+            leg = 4;
+            string fltType = "ga";
+            fp->createTakeOff(&ai_ac, false, apt, 0, fltType);
+        } else {
+            controller = apt->getDynamics()->getStartupController();
+            int stationFreq = apt->getDynamics()->getGroundFrequency(2);
+            cerr << "Setting radio frequency to : " << stationFreq << endl;
+            fgSetDouble("/instrumentation/comm[0]/frequencies/selected-mhz", ((double) stationFreq / 100.0));
+            leg = 2;
+            //double, lat, lon, head; // Unused variables;
+            //int getId = apt->getDynamics()->getParking(gateId, &lat, &lon, &head);
+            FGParking* parking = dcs->getParking(park_index);
+            aircraftRadius = parking->getRadius();
+            string fltType = parking->getType(); // gate / ramp, ga, etc etc. 
+            string aircraftType; // Unused.
+            string airline;      // Currently used for gate selection, but a fallback mechanism will apply when not specified.
+            fp->setGate(park_index);
+            fp->createPushBack(&ai_ac,
+                               false, 
+                               apt, 
+                               latitude,
+                               longitude,
+                               aircraftRadius,
+                               fltType,
+                               aircraftType,
+                               airline);
+         } 
+     } else {
+        controller = 0;
+     }
+
+    // Create an initial flightplan and assign it to the ai_ac. We won't use this flightplan, but it is necessary to
+    // keep the ATC code happy. 
+    
+    
+    fp->restart();
+    fp->setLeg(leg);
+    ai_ac.SetFlightPlan(fp);
+    if (controller) {
+        controller->announcePosition(ai_ac.getID(), fp, fp->getCurrentWaypoint()->routeIndex,
+                                      ai_ac._getLatitude(), ai_ac._getLongitude(), heading, speed, altitude,
+                                      aircraftRadius, leg, &ai_ac);
+
+    //dialog.init();
+
+   //osg::Node* node = apt->getDynamics()->getGroundNetwork()->getRenderNode();
+   //cerr << "Adding groundnetWork to the scenegraph::init" << endl;
+   //globals->get_scenery()->get_scene_graph()->addChild(node);
+   }
+}
+
+void FGATCManager::addController(FGATCController *controller) {
+    activeStations.push_back(controller);
+}
+
+void FGATCManager::update ( double time ) {
+    //cerr << "ATC update code is running at time: " << time << endl;
+    // Test code: let my virtual co-pilot handle ATC:
+   
+    
+
+    FGAIFlightPlan *fp = ai_ac.GetFlightPlan();
+        
+    /* test code : find out how the routing develops */
+    int size = fp->getNrOfWayPoints();
+    //cerr << "Setting pos" << pos << " ";
+    cerr << "setting intentions " ;
+    for (int i = 0; i < size; i++) {
+        int val = fp->getRouteIndex(i);
+        cerr << val << " ";
+        //if ((val) && (val != pos)) {
+            //intentions.push_back(val);
+            //cerr << "[done ] " << endl;
+        //}
+    }
+    cerr << "[done ] " << endl;
+    double longitude = fgGetDouble("/position/longitude-deg");
+    double latitude  = fgGetDouble("/position/latitude-deg");
+    double heading   = fgGetDouble("/orientation/heading-deg");
+    double speed     = fgGetDouble("/velocities/groundspeed-kt");
+    double altitude  = fgGetDouble("/position/altitude-ft");
+    ai_ac.setLatitude(latitude);
+    ai_ac.setLongitude(longitude);
+    ai_ac.setAltitude(altitude);
+    ai_ac.setHeading(heading);
+    ai_ac.setSpeed(speed);
+    ai_ac.update(time);
+    controller = ai_ac.getATCController();
+    currentATCDialog->update(time);
+    if (controller) {
+       
+
+        //cerr << "Running FGATCManager::update()" << endl;
+        controller->updateAircraftInformation(ai_ac.getID(),
+                                              latitude,
+                                              longitude,
+                                              heading,
+                                              speed,
+                                              altitude, time);
+        //string airport = fgGetString("/sim/presets/airport-id");
+        //FGAirport *apt = FGAirport::findByIdent(airport); 
+        // AT this stage we should update the flightplan, so that waypoint incrementing is conducted as well as leg loading. 
+
+       controller->render();
+
+        //cerr << "Adding groundnetWork to the scenegraph::update" << endl;
+   }
+   //globals->get_scenery()->get_scene_graph()->addChild(node);
+}
diff --git a/src/ATC/atc_mgr.hxx b/src/ATC/atc_mgr.hxx
new file mode 100644 (file)
index 0000000..33fa5c4
--- /dev/null
@@ -0,0 +1,64 @@
+/* -*- Mode: C++ -*- *****************************************************
+ * atic.hxx
+ * Written by Durk Talsma. Started August 1, 2010; based on earlier work
+ * by David C. Luff
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *
+ **************************************************************************/
+
+/**************************************************************************
+ * The ATC Manager interfaces the users aircraft with the AI traffic system
+ * and also monitors the ongoing AI traffic patterns for potential conflicts
+ * and interferes where necessary. 
+ *************************************************************************/ 
+
+#ifndef _ATC_MGR_HXX_
+#define _ATC_MGR_HXX_
+
+//#include <simgear/structure/SGReferenced.hxx>
+//#include <simgear/structure/SGSharedPtr.hxx>
+#include <simgear/structure/subsystem_mgr.hxx>
+
+
+#include <ATC/trafficcontrol.hxx>
+#include <ATC/atcdialog.hxx>
+
+#include <AIModel/AIAircraft.hxx>
+//class FGATCController;
+
+
+typedef vector<FGATCController*> AtcVec;
+typedef vector<FGATCController*>::iterator AtcVecIterator;
+
+class FGATCManager : public SGSubsystem
+{
+private:
+  AtcVec activeStations;
+  FGAIAircraft ai_ac;
+  FGATCController *controller; // The ATC controller that is responsible for the user's aircraft. 
+  //FGATCDialogNew dialog;  // note that this variable should really replace the ugly global "currentATCDialog();
+
+public:
+  FGATCManager();
+  ~FGATCManager();
+  void init();
+  void addController(FGATCController *controller);
+  void update(double time);
+  FGATCDialogNew * getATCDialog() {  return currentATCDialog; };
+};
+  
+#endif // _ATC_MRG_HXX_
\ No newline at end of file
diff --git a/src/ATC/atcdialog.cxx b/src/ATC/atcdialog.cxx
new file mode 100644 (file)
index 0000000..c59bf95
--- /dev/null
@@ -0,0 +1,202 @@
+// atcdialog.cxx - classes to manage user interactions with AI traffic
+// Written by Durk Talsma, started April 3, 2011
+// Based on earlier code written by Alexander Kappes and David Luff
+//
+// 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// $Id$
+
+#include <Main/fg_commands.hxx>
+#include <Main/globals.hxx>
+
+#include <simgear/constants.h>
+#include <simgear/structure/commands.hxx>
+#include <simgear/compiler.h>
+#include <simgear/props/props.hxx>
+#include <simgear/props/props_io.hxx>
+#include <simgear/misc/sgstream.hxx>
+#include <simgear/math/sg_geodesy.hxx>
+#include <simgear/debug/logstream.hxx>
+#include <simgear/structure/SGSharedPtr.hxx>
+
+#include "atcdialog.hxx"
+
+FGATCDialogNew *currentATCDialog;
+
+static bool doATCDialog(const SGPropertyNode* arg) {
+        cerr << "Running doATCDialog" << endl;
+       currentATCDialog->PopupDialog();
+       return(true);
+}
+
+FGATCDialogNew::FGATCDialogNew()
+{
+  dialogVisible = false;
+}
+
+FGATCDialogNew::~FGATCDialogNew()
+{
+}
+
+
+
+void FGATCDialogNew::init() {
+       // Add ATC-dialog to the command list
+       globals->get_commands()->addCommand("ATC-dialog", doATCDialog);
+       // Add ATC-freq-search to the command list
+       //globals->get_commands()->addCommand("ATC-freq-search", do_ATC_freq_search);
+
+       // initialize properties polled in Update()
+       //globals->get_props()->setStringValue("/sim/atc/freq-airport", "");
+       globals->get_props()->setIntValue("/sim/atc/transmission-num", -1);
+}
+
+
+
+// Display the ATC popup dialog box with options relevant to the users current situation.
+// 
+// So, the first thing we need to do is check the frequency that our pilot's nav radio
+// is currently tuned to. The dialog should always contain an option to to tune the 
+// to a particular frequency,
+
+// Okay, let's see, according to my interpretation of David Luff's original code,
+// his ATC subsystem wrote properties to a named node, called "transmission-choice"
+
+static SGPropertyNode *getNamedNode(SGPropertyNode *prop, const char *name) {
+    SGPropertyNode* p;
+
+    for (int i = 0; i < prop->nChildren(); i++)
+        if ((p = getNamedNode(prop->getChild(i), name)))
+            return p;
+
+        if (!strcmp(prop->getStringValue("name"), name))
+            return prop;
+      return 0;
+}
+
+void FGATCDialogNew::addEntry(int nr, string txt) {
+    commands.clear();
+    commands.push_back(txt);
+}
+
+void FGATCDialogNew::removeEntry(int nr) {
+    commands.clear();
+}
+
+
+
+void FGATCDialogNew::PopupDialog() {
+    /*double onBoardRadioFreq0 =
+        fgGetDouble("/instrumentation/comm[0]/frequencies/selected-mhz");
+    double onBoardRadioFreq1 =
+        fgGetDouble("/instrumentation/comm[1]/frequencies/selected-mhz");
+
+    const char *dialog_name = "atc-dialog";
+    _gui = (NewGUI *)globals->get_subsystem("gui");
+    SGPropertyNode_ptr dlg = _gui->getDialogProperties(dialog_name);
+    if (!dlg)
+        return;
+
+    _gui->closeDialog(dialog_name);
+    SGPropertyNode_ptr button_group = getNamedNode(dlg, "transmission-choice");
+    button_group->removeChildren("button", false);
+
+    const int bufsize = 32;
+    char buf[bufsize];
+    int commandNr = 0;
+    // loop over all entries that should fill up the dialog; use 10 items for now...
+    for (StringVecIterator i = commands.begin(); i != commands.end(); i++) {
+        snprintf(buf, bufsize, "/sim/atc/opt[%d]", commandNr);
+            fgSetBool(buf, false);
+        SGPropertyNode *entry = button_group->getNode("button", commandNr, true);
+        copyProperties(button_group->getNode("button-template", true), entry);
+       entry->removeChildren("enabled", true);
+       entry->setStringValue("property", buf);
+       entry->setIntValue("keynum", '1' + commandNr);
+       if (commandNr == 0)
+           entry->setBoolValue("default", true);
+
+       snprintf(buf, bufsize, "%d", 1 + commandNr);
+       string legend = string(buf) + (*i); //"; // + current->menuentry;
+       entry->setStringValue("legend", legend.c_str());
+       entry->setIntValue("binding/value", commandNr);
+        commandNr++;
+       //current++;
+    }
+*/
+    //if (dialogVisible) {
+    //    _gui->closeDialog(dialog_name);
+    //} else {
+    //    _gui->showDialog(dialog_name);
+    //}
+    dialogVisible = !dialogVisible;
+    return;
+}
+
+void FGATCDialogNew::update(double dt) {
+ double onBoardRadioFreq0 =
+        fgGetDouble("/instrumentation/comm[0]/frequencies/selected-mhz");
+    double onBoardRadioFreq1 =
+        fgGetDouble("/instrumentation/comm[1]/frequencies/selected-mhz");
+
+    const char *dialog_name = "atc-dialog";
+    _gui = (NewGUI *)globals->get_subsystem("gui");
+    SGPropertyNode_ptr dlg = _gui->getDialogProperties(dialog_name);
+    if (!dlg)
+        return;
+
+    _gui->closeDialog(dialog_name);
+    SGPropertyNode_ptr button_group = getNamedNode(dlg, "transmission-choice");
+    button_group->removeChildren("button", false);
+
+    const int bufsize = 32;
+    char buf[bufsize];
+    int commandNr = 0;
+    // loop over all entries that should fill up the dialog; use 10 items for now...
+    for (StringVecIterator i = commands.begin(); i != commands.end(); i++) {
+        snprintf(buf, bufsize, "/sim/atc/opt[%d]", commandNr);
+            fgSetBool(buf, false);
+        SGPropertyNode *entry = button_group->getNode("button", commandNr, true);
+        copyProperties(button_group->getNode("button-template", true), entry);
+       entry->removeChildren("enabled", true);
+       entry->setStringValue("property", buf);
+       entry->setIntValue("keynum", '1' + commandNr);
+       if (commandNr == 0)
+           entry->setBoolValue("default", true);
+
+       snprintf(buf, bufsize, "%d", 1 + commandNr);
+       string legend = string(buf) + (*i); //"; // + current->menuentry;
+       entry->setStringValue("legend", legend.c_str());
+       entry->setIntValue("binding/value", commandNr);
+        commandNr++;
+       //current++;
+    }
+
+    if (dialogVisible) {
+        _gui->closeDialog(dialog_name);
+    } else {
+        _gui->showDialog(dialog_name);
+    }
+    //dialogVisible = !dialogVisible;
+    return;
+    /*
+    static SGPropertyNode_ptr trans_num = globals->get_props()->getNode("/sim/atc/transmission-num", true);
+    int n = trans_num->getIntValue();
+    if (n >= 0) {
+        trans_num->setIntValue(-1);
+           // PopupCallback(n);
+        cerr << "Selected transmission message" << n << endl;
+    } */
+}
\ No newline at end of file
diff --git a/src/ATC/atcdialog.hxx b/src/ATC/atcdialog.hxx
new file mode 100644 (file)
index 0000000..f52b5b4
--- /dev/null
@@ -0,0 +1,68 @@
+// atcdialog.hxx - classes to manage user interactions with AI traffic
+// Written by Durk Talsma, started April 3, 2011
+// Based on earlier code written by Alexander Kappes and David Luff
+//
+// 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// $Id$
+
+
+#ifndef _ATC_DIALOG_HXX_
+#define _ATC_DIALOG_HXX_
+
+
+#ifndef __cplusplus
+# error This library requires C++
+#endif
+
+#include <simgear/constants.h>
+#include <simgear/structure/commands.hxx>
+#include <simgear/compiler.h>
+#include <simgear/props/props.hxx>
+#include <simgear/misc/sgstream.hxx>
+#include <simgear/math/sg_geodesy.hxx>
+#include <simgear/debug/logstream.hxx>
+#include <simgear/structure/SGSharedPtr.hxx>
+
+
+#include <GUI/gui.h>           // mkDialog
+#include <GUI/new_gui.hxx>
+
+typedef vector<string> StringVec;
+typedef vector<string>:: iterator StringVecIterator;
+
+static bool doATCDialog(const SGPropertyNode* arg);
+
+class FGATCDialogNew {
+private:
+     NewGUI *_gui;
+     bool dialogVisible;
+     StringVec commands;
+public:
+
+    FGATCDialogNew();
+    ~FGATCDialogNew();
+
+    void init();
+
+    void update(double dt);
+    void PopupDialog();
+    void addEntry(int, string);
+    void removeEntry(int);
+};
+
+extern FGATCDialogNew *currentATCDialog;
+
+#endif // _ATC_DIALOG_HXX_
\ No newline at end of file
index f2ccd33ee7dc106e44926e9b0e86297313daa05b..9a957bd5378370bce47a51973023f10c100415b2 100644 (file)
 
 #include <algorithm>
 
+#include <osg/Geode>
+#include <osg/Geometry>
+#include <osg/MatrixTransform>
+#include <osg/Shape>
+
+#include <simgear/scene/material/EffectGeode.hxx>
+#include <simgear/scene/material/matlib.hxx>
+#include <simgear/scene/material/mat.hxx>
+#include <Scenery/scenery.hxx>
+
 #include "trafficcontrol.hxx"
+#include "atc_mgr.hxx"
 #include <AIModel/AIAircraft.hxx>
 #include <AIModel/AIFlightPlan.hxx>
 #include <AIModel/performancedata.hxx>
 #include <AIModel/performancedb.hxx>
+#include <ATC/atc_mgr.hxx>
 #include <Traffic/TrafficMgr.hxx>
 #include <Airports/groundnetwork.hxx>
 #include <Airports/dynamics.hxx>
@@ -397,6 +409,10 @@ void FGTrafficRecord::setHeadingAdjustment(double heading)
 
 bool FGTrafficRecord::pushBackAllowed()
 {
+    // With the user ATC / AI integration, checking whether the user's aircraft is near no longer works, because
+    // this will effectively block the user's aircraft itself from receiving pushback clearance. 
+    // So, what can we do?
+    /*
     double course, az2, dist;
     SGGeod curr(SGGeod::fromDegM(getLongitude(),
                                  getLatitude(), getAltitude()));
@@ -407,7 +423,13 @@ bool FGTrafficRecord::pushBackAllowed()
     SGGeodesy::inverse(curr, user, course, az2, dist);
     //cerr << "Distance to user : " << dist << endl;
     return (dist > 250);
+    */
+
 
+    // In essence, we should check whether the pusbback route itself, as well as the associcated
+    // taxiways near the pushback point are free of traffic. 
+    // To do so, we need to 
+    return true;
 }
 
 
@@ -447,9 +469,16 @@ bool FGATCInstruction::hasInstruction()
 
 FGATCController::FGATCController()
 {
+    cerr << "running FGATController constructor" << endl;
     dt_count = 0;
     available = true;
     lastTransmission = 0;
+    initialized = false;
+}
+
+FGATCController::~FGATCController()
+{
+     cerr << "running FGATController destructor" << endl;
 }
 
 string FGATCController::getGateName(FGAIAircraft * ref)
@@ -457,8 +486,13 @@ string FGATCController::getGateName(FGAIAircraft * ref)
     return ref->atGate();
 }
 
+bool FGATCController::isUserAircraft(FGAIAircraft* ac) 
+{ 
+    return (ac->getCallSign() == fgGetString("/sim/multiplay/callsign")) ? true : false; 
+};
+
 void FGATCController::transmit(FGTrafficRecord * rec, AtcMsgId msgId,
-                               AtcMsgDir msgDir)
+                               AtcMsgDir msgDir, bool audible)
 {
     string sender, receiver;
     int stationFreq = 0;
@@ -623,22 +657,28 @@ void FGATCController::transmit(FGTrafficRecord * rec, AtcMsgId msgId,
         text = text + sender + ". Transmitting unknown Message";
         break;
     }
-    double onBoardRadioFreq0 =
-        fgGetDouble("/instrumentation/comm[0]/frequencies/selected-mhz");
-    double onBoardRadioFreq1 =
-        fgGetDouble("/instrumentation/comm[1]/frequencies/selected-mhz");
-    int onBoardRadioFreqI0 = (int) floor(onBoardRadioFreq0 * 100 + 0.5);
-    int onBoardRadioFreqI1 = (int) floor(onBoardRadioFreq1 * 100 + 0.5);
-    //cerr << "Using " << onBoardRadioFreq0 << ", " << onBoardRadioFreq1 << " and " << stationFreq << " for " << text << endl;
-
-    // Display ATC message only when one of the radios is tuned
-    // the relevant frequency.
-    // Note that distance attenuation is currently not yet implemented
-    if ((onBoardRadioFreqI0 == stationFreq)
-        || (onBoardRadioFreqI1 == stationFreq)) {
-        if (rec->allowTransmissions()) {
-            fgSetString("/sim/messages/atc", text.c_str());
+    if (audible) {
+        double onBoardRadioFreq0 =
+            fgGetDouble("/instrumentation/comm[0]/frequencies/selected-mhz");
+        double onBoardRadioFreq1 =
+            fgGetDouble("/instrumentation/comm[1]/frequencies/selected-mhz");
+        int onBoardRadioFreqI0 = (int) floor(onBoardRadioFreq0 * 100 + 0.5);
+        int onBoardRadioFreqI1 = (int) floor(onBoardRadioFreq1 * 100 + 0.5);
+        //cerr << "Using " << onBoardRadioFreq0 << ", " << onBoardRadioFreq1 << " and " << stationFreq << " for " << text << endl;
+
+        // Display ATC message only when one of the radios is tuned
+        // the relevant frequency.
+        // Note that distance attenuation is currently not yet implemented
+        if ((onBoardRadioFreqI0 == stationFreq)
+            || (onBoardRadioFreqI1 == stationFreq)) {
+            if (rec->allowTransmissions()) {
+                fgSetString("/sim/messages/atc", text.c_str());
+            }
         }
+    } else {
+        FGATCManager *atc = (FGATCManager*) globals->get_subsystem("atc");
+        atc->getATCDialog()->addEntry(1, text);
+        
     }
 }
 
@@ -663,6 +703,15 @@ string FGATCController::genTransponderCode(string fltRules)
     }
 }
 
+void FGATCController::init() 
+{
+   if (!initialized) {
+       FGATCManager *mgr = (FGATCManager*) globals->get_subsystem("ATC");
+       mgr->addController(this);
+       initialized = true;
+    }
+}
+
 /***************************************************************************
  * class FGTowerController
  *
@@ -681,6 +730,7 @@ void FGTowerController::announcePosition(int id,
                                          double radius, int leg,
                                          FGAIAircraft * ref)
 {
+    init();
     TrafficVectorIterator i = activeTraffic.begin();
     // Search whether the current id alread has an entry
     // This might be faster using a map instead of a vector, but let's start by taking a safe route
@@ -709,9 +759,9 @@ void FGTowerController::announcePosition(int id,
     }
 }
 
-void FGTowerController::update(int id, double lat, double lon,
-                               double heading, double speed, double alt,
-                               double dt)
+void FGTowerController::updateAircraftInformation(int id, double lat, double lon,
+                                                  double heading, double speed, double alt,
+                                                  double dt)
 {
     TrafficVectorIterator i = activeTraffic.begin();
     // Search whether the current id has an entry
@@ -856,13 +906,19 @@ FGATCInstruction FGTowerController::getInstruction(int id)
     return FGATCInstruction();
 }
 
+void FGTowerController::render() {
+    cerr << "FGTowerController::render function not yet implemented" << endl;
+}
+
+
 /***************************************************************************
  * class FGStartupController
  *
  **************************************************************************/
-FGStartupController::FGStartupController():
-FGATCController()
+FGStartupController::FGStartupController(FGAirportDynamics *par):
+    FGATCController()
 {
+    parent = par;
 }
 
 void FGStartupController::announcePosition(int id,
@@ -873,6 +929,7 @@ void FGStartupController::announcePosition(int id,
                                            double radius, int leg,
                                            FGAIAircraft * ref)
 {
+    init();
     TrafficVectorIterator i = activeTraffic.begin();
     // Search whether the current id alread has an entry
     // This might be faster using a map instead of a vector, but let's start by taking a safe route
@@ -893,11 +950,13 @@ void FGStartupController::announcePosition(int id,
         rec.setPositionAndHeading(lat, lon, heading, speed, alt);
         rec.setRunway(intendedRoute->getRunway());
         rec.setLeg(leg);
+        rec.setPositionAndIntentions(currentPosition, intendedRoute);
         //rec.setCallSign(callsign);
         rec.setAircraft(ref);
         rec.setHoldPosition(true);
         activeTraffic.push_back(rec);
     } else {
+        i->setPositionAndIntentions(currentPosition, intendedRoute);
         i->setPositionAndHeading(lat, lon, heading, speed, alt);
 
     }
@@ -974,13 +1033,48 @@ void FGStartupController::signOff(int id)
         SG_LOG(SG_GENERAL, SG_ALERT,
                "AI error: Aircraft without traffic record is signing off from tower");
     } else {
+        cerr << i->getAircraft()->getCallSign() << " signing off from startupcontroller" << endl;
         i = activeTraffic.erase(i);
     }
 }
 
-void FGStartupController::update(int id, double lat, double lon,
-                                 double heading, double speed, double alt,
-                                 double dt)
+bool FGStartupController::checkTransmissionState(int st, time_t now, time_t startTime, TrafficVectorIterator i, AtcMsgId msgId,
+                               AtcMsgDir msgDir)
+{
+    int state = i->getState();
+    if ((state == st) && available) {
+        if ((msgDir == ATC_AIR_TO_GROUND) && isUserAircraft(i->getAircraft())) {
+            
+            cerr << "Checking state " << st << " for " << i->getAircraft()->getCallSign() << endl;
+            static SGPropertyNode_ptr trans_num = globals->get_props()->getNode("/sim/atc/transmission-num", true);
+            int n = trans_num->getIntValue();
+            if (n >= 0) {
+                trans_num->setIntValue(-1);
+                 // PopupCallback(n);
+                 cerr << "Selected transmission message" << n << endl;
+                 FGATCManager *atc = (FGATCManager*) globals->get_subsystem("atc");
+                 atc->getATCDialog()->removeEntry(1);
+            } else {
+                cerr << "creading message for " << i->getAircraft()->getCallSign() << endl;
+                transmit(&(*i), msgId, msgDir, false);
+                return false;
+            }
+        }
+        if (now > startTime) {
+            //cerr << "Transmitting startup msg" << endl;
+            transmit(&(*i), msgId, msgDir, true);
+            i->updateState();
+            lastTransmission = now;
+            available = false;
+            return true;
+        }
+    }
+    return false;
+}
+
+void FGStartupController::updateAircraftInformation(int id, double lat, double lon,
+                                                    double heading, double speed, double alt,
+                                                    double dt)
 {
     TrafficVectorIterator i = activeTraffic.begin();
     // Search search if the current id has an entry
@@ -996,6 +1090,7 @@ void FGStartupController::update(int id, double lat, double lon,
         }
     }
 //    // update position of the current aircraft
+
     if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
         SG_LOG(SG_GENERAL, SG_ALERT,
                "AI error: updating aircraft without traffic record");
@@ -1006,8 +1101,10 @@ void FGStartupController::update(int id, double lat, double lon,
     setDt(getDt() + dt);
 
     int state = i->getState();
-    time_t startTime =
-        i->getAircraft()->getTrafficRef()->getDepartureTime();
+
+    // The user controlled aircraft should have crased here, because it doesn't have a traffic reference. 
+    // NOTE: if we create a traffic schedule for the user aircraft, we can use this to plan a flight.
+    time_t startTime = i->getAircraft()->getTrafficRef()->getDepartureTime();
     time_t now = time(NULL) + fgGetLong("/sim/time/warp");
     //cerr << i->getAircraft()->getTrafficRef()->getCallSign() 
     //     << " is scheduled to depart in " << startTime-now << " seconds. Available = " << available
@@ -1017,91 +1114,29 @@ void FGStartupController::update(int id, double lat, double lon,
         available = true;
     }
 
-    if ((state == 0) && available) {
-        if (now > startTime) {
-            //cerr << "Transmitting startup msg" << endl;
-            transmit(&(*i), MSG_ANNOUNCE_ENGINE_START, ATC_AIR_TO_GROUND);
-            i->updateState();
-            lastTransmission = now;
-            available = false;
-        }
-    }
-    if ((state == 1) && available) {
-        if (now > startTime + 60) {
-            transmit(&(*i), MSG_REQUEST_ENGINE_START, ATC_AIR_TO_GROUND);
-            i->updateState();
-            lastTransmission = now;
-            available = false;
-        }
-    }
-    if ((state == 2) && available) {
-        if (now > startTime + 80) {
-            transmit(&(*i), MSG_PERMIT_ENGINE_START, ATC_GROUND_TO_AIR);
-            i->updateState();
-            lastTransmission = now;
-            available = false;
-        }
-    }
-    if ((state == 3) && available) {
-        if (now > startTime + 100) {
-            transmit(&(*i), MSG_ACKNOWLEDGE_ENGINE_START,
-                     ATC_AIR_TO_GROUND);
-            i->updateState();
-            lastTransmission = now;
-            available = false;
-        }
-    }
-    // Note: The next four stages are only necessesary when Startup control is
-    //  on a different frequency, compared to ground control
-    if ((state == 4) && available) {
-        if (now > startTime + 130) {
-            transmit(&(*i), MSG_ACKNOWLEDGE_SWITCH_GROUND_FREQUENCY,
-                     ATC_AIR_TO_GROUND);
-            i->updateState();
-            i->nextFrequency();
-            lastTransmission = now;
-            available = false;
-        }
-    }
-    if ((state == 5) && available) {
-        if (now > startTime + 140) {
-            transmit(&(*i), MSG_INITIATE_CONTACT, ATC_AIR_TO_GROUND);
-            i->updateState();
-            lastTransmission = now;
-            available = false;
-        }
-    }
-    if ((state == 6) && available) {
-        if (now > startTime + 150) {
-            transmit(&(*i), MSG_ACKNOWLEDGE_INITIATE_CONTACT,
-                     ATC_GROUND_TO_AIR);
-            i->updateState();
-            lastTransmission = now;
-            available = false;
-        }
+    checkTransmissionState(0, now, (startTime + 0  ), i, MSG_ANNOUNCE_ENGINE_START,                     ATC_AIR_TO_GROUND);
+    checkTransmissionState(1, now, (startTime + 60 ), i, MSG_REQUEST_ENGINE_START,                      ATC_AIR_TO_GROUND);
+    checkTransmissionState(2, now, (startTime + 80 ), i, MSG_PERMIT_ENGINE_START,                       ATC_GROUND_TO_AIR);
+    checkTransmissionState(3, now, (startTime + 100), i, MSG_ACKNOWLEDGE_ENGINE_START,                  ATC_AIR_TO_GROUND);
+    if (checkTransmissionState(4, now, (startTime + 130), i, MSG_ACKNOWLEDGE_SWITCH_GROUND_FREQUENCY,       ATC_AIR_TO_GROUND)) {
+        i->nextFrequency();
     }
+    checkTransmissionState(5, now, (startTime + 140), i, MSG_INITIATE_CONTACT,                          ATC_AIR_TO_GROUND);
+    checkTransmissionState(6, now, (startTime + 150), i, MSG_ACKNOWLEDGE_INITIATE_CONTACT,              ATC_GROUND_TO_AIR);
+    checkTransmissionState(7, now, (startTime + 180), i, MSG_REQUEST_PUSHBACK_CLEARANCE,                ATC_AIR_TO_GROUND);
 
-    // TODO: Switch to APRON control and request pushback Clearance.
-    // Get Push back clearance
-    if ((state == 7) && available) {
-        if (now > startTime + 180) {
-            transmit(&(*i), MSG_REQUEST_PUSHBACK_CLEARANCE,
-                     ATC_AIR_TO_GROUND);
-            i->updateState();
-            lastTransmission = now;
-            available = false;
-        }
-    }
+
+   
     if ((state == 8) && available) {
         if (now > startTime + 200) {
             if (i->pushBackAllowed()) {
                 i->allowRepeatedTransmissions();
                 transmit(&(*i), MSG_PERMIT_PUSHBACK_CLEARANCE,
-                         ATC_GROUND_TO_AIR);
+                         ATC_GROUND_TO_AIR, true);
                 i->updateState();
             } else {
                 transmit(&(*i), MSG_HOLD_PUSHBACK_CLEARANCE,
-                         ATC_GROUND_TO_AIR);
+                         ATC_GROUND_TO_AIR, true);
                 i->suppressRepeatedTransmissions();
             }
             lastTransmission = now;
@@ -1113,6 +1148,127 @@ void FGStartupController::update(int id, double lat, double lon,
     }
 }
 
+// Note that this function is copied from simgear. for maintanance purposes, it's probabtl better to make a general function out of that.
+static void WorldCoordinate(osg::Matrix& obj_pos, double lat,
+                            double lon, double elev, double hdg)
+{
+    SGGeod geod = SGGeod::fromDegM(lon, lat, elev);
+    obj_pos = geod.makeZUpFrame();
+    // hdg is not a compass heading, but a counter-clockwise rotation
+    // around the Z axis
+    obj_pos.preMult(osg::Matrix::rotate(hdg * SGD_DEGREES_TO_RADIANS,
+                                        0.0, 0.0, 1.0));
+}
+
+
+void FGStartupController::render()
+{
+
+    SGMaterialLib *matlib = globals->get_matlib();
+    if (group) {
+        //int nr = ;
+        globals->get_scenery()->get_scene_graph()->removeChild(group);
+        //while (group->getNumChildren()) {
+        //  cerr << "Number of children: " << group->getNumChildren() << endl;
+        simgear::EffectGeode* geode = (simgear::EffectGeode*) group->getChild(0);
+          //osg::MatrixTransform *obj_trans = (osg::MatrixTransform*) group->getChild(0);
+           //geode->releaseGLObjects();
+           //group->removeChild(geode);
+           //delete geode;
+    }
+    group = new osg::Group;
+
+    //for ( FGTaxiSegmentVectorIterator i = segments.begin(); i != segments.end(); i++) {
+    double dx = 0;
+    for   (TrafficVectorIterator i = activeTraffic.begin(); i != activeTraffic.end(); i++) {
+        // Handle start point
+        int pos = i->getCurrentPosition();
+        //cerr << "rendering for " << i->getAircraft()->getCallSign() << "pos = " << pos << endl;
+        if (pos > 0) {
+            FGTaxiSegment *segment  = parent->getGroundNetwork()->findSegment(pos);
+            SGGeod start(SGGeod::fromDeg((i->getLongitude()), (i->getLatitude())));
+            SGGeod end  (SGGeod::fromDeg(segment->getEnd()->getLongitude(), segment->getEnd()->getLatitude()));
+
+            double length = SGGeodesy::distanceM(start, end);
+            //heading = SGGeodesy::headingDeg(start->getGeod(), end->getGeod());
+
+            double az2, heading; //, distanceM;
+            SGGeodesy::inverse(start, end, heading, az2, length);
+            double coveredDistance = length * 0.5;
+            SGGeod center;
+            SGGeodesy::direct(start, heading, coveredDistance, center, az2);
+            //cerr << "Active Aircraft : Centerpoint = (" << center.getLatitudeDeg() << ", " << center.getLongitudeDeg() << "). Heading = " << heading << endl;
+            ///////////////////////////////////////////////////////////////////////////////
+            // Make a helper function out of this
+            osg::Matrix obj_pos;
+                osg::MatrixTransform *obj_trans = new osg::MatrixTransform;
+                obj_trans->setDataVariance(osg::Object::STATIC);
+
+                WorldCoordinate( obj_pos, center.getLatitudeDeg(), center.getLongitudeDeg(), parent->getElevation()+8+dx, -(heading) );
+
+                obj_trans->setMatrix( obj_pos );
+                //osg::Vec3 center(0, 0, 0)
+
+                float width = length /2.0;
+                osg::Vec3 corner(-width, 0, 0.25f);
+                osg::Vec3 widthVec(2*width + 1, 0, 0);
+                osg::Vec3 heightVec(0, 1, 0);
+                osg::Geometry* geometry;
+                geometry = osg::createTexturedQuadGeometry(corner, widthVec, heightVec);
+                simgear::EffectGeode* geode = new simgear::EffectGeode;
+                geode->setName("test");
+                geode->addDrawable(geometry);
+                //osg::Node *custom_obj;
+                SGMaterial *mat = matlib->find("UnidirectionalTaper");
+                if (mat)
+                    geode->setEffect(mat->get_effect());
+                obj_trans->addChild(geode);
+                // wire as much of the scene graph together as we can
+                //->addChild( obj_trans );
+                group->addChild( obj_trans );
+        /////////////////////////////////////////////////////////////////////
+        } else {
+             cerr << "BIG FAT WARNING: current position is here : " << pos << endl;
+        }
+        for(intVecIterator j = (i)->getIntentions().begin(); j != (i)->getIntentions().end(); j++) {
+             osg::Matrix obj_pos;
+            int k = (*j);
+            if (k > 0) {
+                //cerr << "rendering for " << i->getAircraft()->getCallSign() << "intention = " << k << endl;
+                osg::MatrixTransform *obj_trans = new osg::MatrixTransform;
+                obj_trans->setDataVariance(osg::Object::STATIC);
+                FGTaxiSegment *segment  = parent->getGroundNetwork()->findSegment(k);
+                WorldCoordinate( obj_pos, segment->getLatitude(), segment->getLongitude(), parent->getElevation()+8+dx, -(segment->getHeading()) );
+
+                obj_trans->setMatrix( obj_pos );
+                //osg::Vec3 center(0, 0, 0)
+
+                float width = segment->getLength() /2.0;
+                osg::Vec3 corner(-width, 0, 0.25f);
+                osg::Vec3 widthVec(2*width + 1, 0, 0);
+                osg::Vec3 heightVec(0, 1, 0);
+                osg::Geometry* geometry;
+                geometry = osg::createTexturedQuadGeometry(corner, widthVec, heightVec);
+                simgear::EffectGeode* geode = new simgear::EffectGeode;
+                geode->setName("test");
+                geode->addDrawable(geometry);
+                //osg::Node *custom_obj;
+                SGMaterial *mat = matlib->find("UnidirectionalTaper");
+                if (mat)
+                    geode->setEffect(mat->get_effect());
+                obj_trans->addChild(geode);
+                // wire as much of the scene graph together as we can
+                //->addChild( obj_trans );
+                group->addChild( obj_trans );
+            } else {
+                cerr << "BIG FAT WARNING: k is here : " << pos << endl;
+            }
+        }
+        //dx += 0.1;
+    }
+    globals->get_scenery()->get_scene_graph()->addChild(group);
+}
+
 
 /***************************************************************************
  * class FGApproachController
@@ -1132,6 +1288,7 @@ void FGApproachController::announcePosition(int id,
                                             double alt, double radius,
                                             int leg, FGAIAircraft * ref)
 {
+    init();
     TrafficVectorIterator i = activeTraffic.begin();
     // Search whether the current id alread has an entry
     // This might be faster using a map instead of a vector, but let's start by taking a safe route
@@ -1160,9 +1317,9 @@ void FGApproachController::announcePosition(int id,
     }
 }
 
-void FGApproachController::update(int id, double lat, double lon,
-                                  double heading, double speed, double alt,
-                                  double dt)
+void FGApproachController::updateAircraftInformation(int id, double lat, double lon,
+                                                     double heading, double speed, double alt,
+                                                     double dt)
 {
     TrafficVectorIterator i = activeTraffic.begin();
     // Search search if the current id has an entry
@@ -1303,3 +1460,7 @@ ActiveRunway *FGApproachController::getRunway(string name)
     }
     return &(*rwy);
 }
+
+void FGApproachController::render() {
+    cerr << "FGApproachController::render function not yet implemented" << endl;
+}
index 7e83a72b476097808a23c9745046a93eab2d1a64..8cc35a7e7e01f64a816d2ea519d72f2620e46e35 100644 (file)
 # error This library requires C++
 #endif
 
+#include <osg/Geode>
+#include <osg/Geometry>
+#include <osg/MatrixTransform>
+#include <osg/Shape>
 
 #include <simgear/compiler.h>
 // There is probably a better include than sg_geodesy to get the SG_NM_TO_METER...
 #include <simgear/math/sg_geodesy.hxx>
 #include <simgear/debug/logstream.hxx>
-
-
+#include <simgear/structure/SGReferenced.hxx>
+#include <simgear/structure/SGSharedPtr.hxx>
 
 #include <string>
 #include <vector>
@@ -48,6 +52,7 @@ typedef vector<int>::iterator intVecIterator;
 class FGAIFlightPlan;  // forward reference
 class FGGroundNetwork; // forward reference
 class FGAIAircraft;    // forward reference
+class FGAirportDynamics;
 
 /**************************************************************************************
  * class FGATCInstruction
@@ -182,6 +187,8 @@ public:
   void allowRepeatedTransmissions () { allowTransmission=true; };
   void nextFrequency() { frequencyId++; };
   int  getNextFrequency() { return frequencyId; };
+  intVec& getIntentions() { return intentions; };
+  int getCurrentPosition() { return currentPos; };
 };
 
 typedef vector<FGTrafficRecord> TrafficVector;
@@ -223,15 +230,19 @@ typedef vector<ActiveRunway>::iterator ActiveRunwayVecIterator;
  *************************************************************************************/
 class FGATCController
 {
+private:
+     bool initialized;
+
 protected:
   bool available;
   time_t lastTransmission;
 
   double dt_count;
-
+  osg::Group* group;
 
   string formatATCFrequency3_2(int );
   string genTransponderCode(string fltRules);
+  bool isUserAircraft(FGAIAircraft*); 
 
 public:
   typedef enum {
@@ -257,21 +268,28 @@ public:
       ATC_AIR_TO_GROUND,
       ATC_GROUND_TO_AIR } AtcMsgDir;
   FGATCController();
-  virtual ~FGATCController() {};
+  virtual ~FGATCController();
+  void init();
+
   virtual void announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentRoute,
-                               double lat, double lon,
-                               double hdg, double spd, double alt, double radius, int leg,
-                               FGAIAircraft *aircraft) = 0;
+                                double lat, double lon,
+                                double hdg, double spd, double alt, double radius, int leg,
+                                FGAIAircraft *aircraft) = 0;
   virtual void             signOff(int id) = 0;
-  virtual void             update(int id, double lat, double lon, 
-                                 double heading, double speed, double alt, double dt) = 0;
+  virtual void             updateAircraftInformation(int id, double lat, double lon, 
+                                                     double heading, double speed, double alt, double dt) = 0;
   virtual bool             hasInstruction(int id) = 0;
   virtual FGATCInstruction getInstruction(int id) = 0;
 
   double getDt() { return dt_count; };
   void   setDt(double dt) { dt_count = dt;};
-  void transmit(FGTrafficRecord *rec, AtcMsgId msgId, AtcMsgDir msgDir);
+  void transmit(FGTrafficRecord *rec, AtcMsgId msgId, AtcMsgDir msgDir, bool audible);
   string getGateName(FGAIAircraft *aircraft);
+  virtual void render() = 0;
+
+private:
+
+ AtcMsgDir lastTransmissionDirection;
 };
 
 /******************************************************************************
@@ -291,11 +309,12 @@ public:
                                double hdg, double spd, double alt, double radius, int leg,
                                FGAIAircraft *aircraft);
   virtual void             signOff(int id);
-  virtual void             update(int id, double lat, double lon, 
+  virtual void             updateAircraftInformation(int id, double lat, double lon, 
                                  double heading, double speed, double alt, double dt);
   virtual bool             hasInstruction(int id);
   virtual FGATCInstruction getInstruction(int id);
 
+  virtual void render();
   bool hasActiveTraffic() { return activeTraffic.size() != 0; };
   TrafficVector &getActiveTraffic() { return activeTraffic; };
 };
@@ -310,23 +329,30 @@ class FGStartupController : public FGATCController
 private:
   TrafficVector activeTraffic;
   //ActiveRunwayVec activeRunways;
+FGAirportDynamics *parent;
   
 public:
-  FGStartupController();
+  FGStartupController(FGAirportDynamics *parent);
   virtual ~FGStartupController() {};
   virtual void announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentRoute,
                                double lat, double lon,
                                double hdg, double spd, double alt, double radius, int leg,
                                FGAIAircraft *aircraft);
   virtual void             signOff(int id);
-  virtual void             update(int id, double lat, double lon, 
+  virtual void             updateAircraftInformation(int id, double lat, double lon, 
                                  double heading, double speed, double alt, double dt);
   virtual bool             hasInstruction(int id);
   virtual FGATCInstruction getInstruction(int id);
 
+  virtual void render();
+
   bool hasActiveTraffic() { return activeTraffic.size() != 0; };
   TrafficVector &getActiveTraffic() { return activeTraffic; };
 
+  // Hpoefully, we can move this function to the base class, but I need to verify what is needed for the other controllers before doing so.
+  bool checkTransmissionState(int st, time_t now, time_t startTime, TrafficVectorIterator i, AtcMsgId msgId,
+                               AtcMsgDir msgDir);
+
 }; 
 
 /******************************************************************************
@@ -346,11 +372,13 @@ public:
                                double hdg, double spd, double alt, double radius, int leg,
                                FGAIAircraft *aircraft);
   virtual void             signOff(int id);
-  virtual void             update(int id, double lat, double lon, 
+  virtual void             updateAircraftInformation(int id, double lat, double lon, 
                                  double heading, double speed, double alt, double dt);
   virtual bool             hasInstruction(int id);
   virtual FGATCInstruction getInstruction(int id);
 
+  virtual void render();
+
   ActiveRunway* getRunway(string name);
 
   bool hasActiveTraffic() { return activeTraffic.size() != 0; };
index ad6e0276321e2872111769bbb5e14ff3461e1a95..026a6544928ef7b524535df8022d091d02147fa0 100644 (file)
@@ -46,6 +46,7 @@ FGATCDialog *current_atcdialog;
 
 // For the command manager - maybe eventually this should go in the built in command list
 static bool do_ATC_dialog(const SGPropertyNode* arg) {
+        cerr << "Running ATCDCL do_ATC_dialog" << endl;
        current_atcdialog->PopupDialog();
        return(true);
 }
@@ -101,39 +102,39 @@ FGATCDialog::~FGATCDialog() {
 
 void FGATCDialog::Init() {
        // Add ATC-dialog to the command list
-       globals->get_commands()->addCommand("ATC-dialog", do_ATC_dialog);
+       //globals->get_commands()->addCommand("ATC-dialog", do_ATC_dialog);
        // Add ATC-freq-search to the command list
-       globals->get_commands()->addCommand("ATC-freq-search", do_ATC_freq_search);
+       //globals->get_commands()->addCommand("ATC-freq-search", do_ATC_freq_search);
 
        // initialize properties polled in Update()
-       globals->get_props()->setStringValue("/sim/atc/freq-airport", "");
-       globals->get_props()->setIntValue("/sim/atc/transmission-num", -1);
+       //globals->get_props()->setStringValue("/sim/atc/freq-airport", "");
+       //globals->get_props()->setIntValue("/sim/atc/transmission-num", -1);
 }
 
 void FGATCDialog::Update(double dt) {
-       static SGPropertyNode_ptr airport = globals->get_props()->getNode("/sim/atc/freq-airport", true);
-       string s = airport->getStringValue();
-       if (!s.empty()) {
-               airport->setStringValue("");
-               FreqDisplay(s);
-       }
-
-       static SGPropertyNode_ptr trans_num = globals->get_props()->getNode("/sim/atc/transmission-num", true);
-       int n = trans_num->getIntValue();
-       if (n >= 0) {
-               trans_num->setIntValue(-1);
-               PopupCallback(n);
-       }
-
-       if(_callbackPending) {
-               if(_callbackTimer > _callbackWait) {
-                       _callbackPtr->ReceiveUserCallback(_callbackCode);
-                       _callbackPtr->NotifyTransmissionFinished(fgGetString("/sim/user/callsign"));
-                       _callbackPending = false;
-               } else {
-                       _callbackTimer += dt;
-               }
-       }
+       //static SGPropertyNode_ptr airport = globals->get_props()->getNode("/sim/atc/freq-airport", true);
+       //string s = airport->getStringValue();
+       //if (!s.empty()) {
+       //      airport->setStringValue("");
+       //      FreqDisplay(s);
+       //}
+
+       //static SGPropertyNode_ptr trans_num = globals->get_props()->getNode("/sim/atc/transmission-num", true);
+       //int n = trans_num->getIntValue();
+       //if (n >= 0) {
+       //      trans_num->setIntValue(-1);
+       //      PopupCallback(n);
+       //}
+
+       //if(_callbackPending) {
+       //      if(_callbackTimer > _callbackWait) {
+       //              _callbackPtr->ReceiveUserCallback(_callbackCode);
+       //              _callbackPtr->NotifyTransmissionFinished(fgGetString("/sim/user/callsign"));
+       //              _callbackPending = false;
+       //      } else {
+       //              _callbackTimer += dt;
+       //      }
+       //}
 }
 
 // Add an entry
index 69f8c051ddfc9152b440a4eb73df930d63416abd..3d443d08fa227456ee6a41227367bdb40dfd6633 100644 (file)
@@ -50,9 +50,10 @@ using std::random_shuffle;
 #include "dynamics.hxx"
 
 FGAirportDynamics::FGAirportDynamics(FGAirport * ap):
-_ap(ap), rwyPrefs(ap), SIDs(ap),
+    _ap(ap), rwyPrefs(ap), SIDs(ap),
     atisSequenceIndex(-1),
-    atisSequenceTimeStamp(0.0)
+    atisSequenceTimeStamp(0.0),
+    startupController(this)
 {
     lastUpdate = 0;
 }
@@ -75,10 +76,11 @@ void FGAirportDynamics::init()
     random_shuffle(parkings.begin(), parkings.end());
     sort(parkings.begin(), parkings.end());
     // add the gate positions to the ground network. 
+    groundNetwork.setParent(_ap);
     groundNetwork.addNodes(&parkings);
     groundNetwork.init();
     groundNetwork.setTowerController(&towerController);
-    groundNetwork.setParent(_ap);
+    
 }
 
 bool FGAirportDynamics::getAvailableParking(double *lat, double *lon,
@@ -514,6 +516,32 @@ int FGAirportDynamics::getGroundFrequency(unsigned leg)
     return groundFreq;
 }
 
+int FGAirportDynamics::getTowerFrequency(unsigned nr)
+{
+    int towerFreq = 0;
+    if (nr < 2) {
+        SG_LOG(SG_ATC, SG_ALERT,
+               "Leg value is smaller than two at " << SG_ORIGIN);
+    }
+    if (freqTower.size() == 0) {
+        return 0;
+    }
+    if ((freqTower.size() > nr - 1) && (nr > 1)) {
+        towerFreq = freqTower[nr - 1];
+    }
+    if ((freqTower.size() < nr - 1) && (nr > 1)) {
+        towerFreq =
+            (freqTower.size() <
+             (nr - 1)) ? freqTower[freqTower.size() -
+                                     1] : freqTower[nr - 2];
+    }
+    if ((freqTower.size() >= nr - 1) && (nr > 1)) {
+        towerFreq = freqTower[nr - 2];
+    }
+    return towerFreq;
+}
+
+
 FGAIFlightPlan *FGAirportDynamics::getSID(string activeRunway,
                                           double heading)
 {
index cf862054e26e00a6266ba5604204b231981accdc..d3dbedaa27b50256e600b5215632e7bf0cf1f1a3 100644 (file)
@@ -64,6 +64,9 @@ private:
   std::string chooseRunwayFallback();
   bool innerGetActiveRunway(const std::string &trafficType, int action, std::string &runway, double heading);
   std::string chooseRwyByHeading(stringVec rwys, double heading);
+
+  double elevation;
+
 public:
   FGAirportDynamics(FGAirport* ap);
   ~FGAirportDynamics();
@@ -110,6 +113,7 @@ public:
   FGApproachController   *getApproachController()   { return &approachController; };
 
   int getGroundFrequency(unsigned leg);
+  int getTowerFrequency  (unsigned nr);
   
   /// get current ATIS sequence letter
   const std::string getAtisSequence();
index c9883d812edda287d5fa6dd8b27f7b2fbe20f943..ae37d59594a03b65fc86847563820028659507ba 100644 (file)
@@ -31,9 +31,9 @@ double processPosition(const string &pos)
   return value;
 }
 
-bool sortByHeadingDiff(FGTaxiSegment *a, FGTaxiSegment *b) {
-  return a->hasSmallerHeadingDiff(*b);
-}
+//bool sortByHeadingDiff(FGTaxiSegment *a, FGTaxiSegment *b) {
+//  return a->hasSmallerHeadingDiff(*b);
+//}
 
 bool sortByLength(FGTaxiSegment *a, FGTaxiSegment *b) {
   return a->getLength() > b->getLength();
@@ -42,7 +42,10 @@ bool sortByLength(FGTaxiSegment *a, FGTaxiSegment *b) {
 /**************************************************************************
  * FGTaxiNode
  *************************************************************************/
-
+void FGTaxiNode::setElevation(double val)
+{
+    geod.setElevationM(val);
+}
 
 void FGTaxiNode::setLatitude (double val)
 {
@@ -64,10 +67,10 @@ void FGTaxiNode::setLongitude(const string& val)
   geod.setLongitudeDeg(processPosition(val));
 }
   
-void FGTaxiNode::sortEndSegments(bool byLength)
-{
-  if (byLength)
-    sort(next.begin(), next.end(), sortByLength);
-  else
-    sort(next.begin(), next.end(), sortByHeadingDiff);
-}
+//void FGTaxiNode::sortEndSegments(bool byLength)
+//{
+//  if (byLength)
+//    sort(next.begin(), next.end(), sortByLength);
+//  else
+//    sort(next.begin(), next.end(), sortByHeadingDiff);
+//}
index 3358ea51e6e891a87adebad77adef2958bb3ec80..a7627715e8e55190add131526e69edc09bcda447 100644 (file)
@@ -83,6 +83,7 @@ FGTaxiNode &operator =(const FGTaxiNode &other)
   void setIndex(int idx)                  { index = idx;                 };
   void setLatitude (double val);
   void setLongitude(double val);
+  void setElevation(double val);
   void setLatitude (const std::string& val);
   void setLongitude(const std::string& val);
   void addSegment(FGTaxiSegment *segment) { next.push_back(segment);     };
@@ -99,6 +100,7 @@ FGTaxiNode &operator =(const FGTaxiNode &other)
   double getPathScore() { return pathScore; };
   double getLatitude() { return geod.getLatitudeDeg();};
   double getLongitude(){ return geod.getLongitudeDeg();};
+  double getElevation() { return geod.getElevationM();};
 
   const SGGeod& getGeod() const { return geod; }
 
@@ -111,7 +113,7 @@ FGTaxiNode &operator =(const FGTaxiNode &other)
   FGTaxiSegmentVectorIterator getEndRoute()   { return next.end();   }; 
   bool operator<(const FGTaxiNode &other) const { return index < other.index; };
 
-  void sortEndSegments(bool);
+  //void sortEndSegments(bool);
 
 };
 
index 2fb8127a5f675b4547b05f33b7ac420c29de6a92..c6a07982f4f9b26c2b1558c2fa29ab009e9d2252 100644 (file)
@@ -1,3 +1,4 @@
+
 // groundnet.cxx - Implimentation of the FlightGear airport ground handling code
 //
 // Written by Durk Talsma, started June 2005.
 #include <math.h>
 #include <algorithm>
 
+
+#include <osg/Geode>
+#include <osg/Geometry>
+#include <osg/MatrixTransform>
+#include <osg/Shape>
+
 #include <simgear/debug/logstream.hxx>
 #include <simgear/route/waypoint.hxx>
+#include <simgear/scene/material/EffectGeode.hxx>
+#include <simgear/scene/material/matlib.hxx>
+#include <simgear/scene/material/mat.hxx>
 
 #include <Airports/simple.hxx>
 #include <Airports/dynamics.hxx>
@@ -36,6 +46,8 @@
 #include <AIModel/AIAircraft.hxx>
 #include <AIModel/AIFlightPlan.hxx>
 
+#include <Scenery/scenery.hxx>
+
 #include "groundnetwork.hxx"
 
 /***************************************************************************
@@ -77,19 +89,26 @@ void FGTaxiSegment::setEnd(FGTaxiNodeVector * nodes)
 
 // There is probably a computationally cheaper way of 
 // doing this.
-void FGTaxiSegment::setTrackDistance()
+void FGTaxiSegment::setDimensions(double elevation)
 {
     length = SGGeodesy::distanceM(start->getGeod(), end->getGeod());
+    //heading = SGGeodesy::headingDeg(start->getGeod(), end->getGeod());
+
+    double az2; //, distanceM;
+    SGGeodesy::inverse(start->getGeod(), end->getGeod(), heading, az2, length);
+    double coveredDistance = length * 0.5;
+    SGGeodesy::direct(start->getGeod(), heading, coveredDistance, center, az2);
+    //cerr << "Centerpoint = (" << center.getLatitudeDeg() << ", " << center.getLongitudeDeg() << "). Heading = " << heading << endl;
 }
 
 
-void FGTaxiSegment::setCourseDiff(double crse)
-{
-    headingDiff = fabs(course - crse);
+//void FGTaxiSegment::setCourseDiff(double crse)
+//{
+//    headingDiff = fabs(course - crse);
 
-    if (headingDiff > 180)
-        headingDiff = fabs(headingDiff - 360);
-}
+//    if (headingDiff > 180)
+//        headingDiff = fabs(headingDiff - 360);
+//}
 
 
 /***************************************************************************
@@ -191,6 +210,7 @@ FGGroundNetwork::FGGroundNetwork()
     //maxDepth    = 1000;
     count = 0;
     currTraffic = activeTraffic.begin();
+    group = 0;
 
 }
 
@@ -227,6 +247,7 @@ void FGGroundNetwork::addNodes(FGParkingVec * parkings)
         n.setIndex(i->getIndex());
         n.setLatitude(i->getLatitude());
         n.setLongitude(i->getLongitude());
+        n.setElevation(parent->getElevation());
         nodes.push_back(new FGTaxiNode(n));
 
         i++;
@@ -245,7 +266,7 @@ void FGGroundNetwork::init()
     while (i != segments.end()) {
         (*i)->setStart(&nodes);
         (*i)->setEnd(&nodes);
-        (*i)->setTrackDistance();
+        (*i)->setDimensions(parent->getElevation());
         (*i)->setIndex(index);
         if ((*i)->isPushBack()) {
             pushBackNodes.push_back((*i)->getEnd());
@@ -460,6 +481,7 @@ void FGGroundNetwork::announcePosition(int id,
                                        double radius, int leg,
                                        FGAIAircraft * aircraft)
 {
+    init();
     TrafficVectorIterator i = activeTraffic.begin();
     // Search search if the current id alread has an entry
     // This might be faster using a map instead of a vector, but let's start by taking a safe route
@@ -510,9 +532,39 @@ void FGGroundNetwork::signOff(int id)
     }
 }
 
-void FGGroundNetwork::update(int id, double lat, double lon,
-                             double heading, double speed, double alt,
-                             double dt)
+bool FGGroundNetwork::checkTransmissionState(int minState, int maxState, TrafficVectorIterator i, time_t now, AtcMsgId msgId,
+                               AtcMsgDir msgDir)
+{
+    int state = i->getState();
+    if ((state >= minState) && (state <= maxState) && available) {
+        if ((msgDir == ATC_AIR_TO_GROUND) && isUserAircraft(i->getAircraft())) {
+            
+            cerr << "Checking state " << state << " for " << i->getAircraft()->getCallSign() << endl;
+            static SGPropertyNode_ptr trans_num = globals->get_props()->getNode("/sim/atc/transmission-num", true);
+            int n = trans_num->getIntValue();
+            if (n >= 0) {
+                trans_num->setIntValue(-1);
+                 // PopupCallback(n);
+                 cerr << "Selected transmission message" << n << endl;
+            } else {
+                cerr << "creading message for " << i->getAircraft()->getCallSign() << endl;
+                transmit(&(*i), msgId, msgDir, false);
+                return false;
+            }
+        }
+        //cerr << "Transmitting startup msg" << endl;
+        transmit(&(*i), msgId, msgDir, true);
+        i->updateState();
+        lastTransmission = now;
+        available = false;
+        return true;
+    }
+    return false;
+}
+
+void FGGroundNetwork::updateAircraftInformation(int id, double lat, double lon,
+                                                double heading, double speed, double alt,
+                                                double dt)
 {
     // Check whether aircraft are on hold due to a preceding pushback. If so, make sure to 
     // Transmit air-to-ground "Ready to taxi request:
@@ -567,23 +619,14 @@ void FGGroundNetwork::update(int id, double lat, double lon,
         if ((now - lastTransmission) > 15) {
             available = true;
         }
-        if ((state < 3) && available) {
-             transmit(&(*current), MSG_REQUEST_TAXI_CLEARANCE, ATC_AIR_TO_GROUND);
-             current->setState(3);
-             lastTransmission = now;
-             available = false;
+        if (checkTransmissionState(0,2, current, now, MSG_REQUEST_TAXI_CLEARANCE, ATC_AIR_TO_GROUND)) {
+            current->setState(3);
         }
-        if ((state == 3) && available) {
-            transmit(&(*current), MSG_ISSUE_TAXI_CLEARANCE, ATC_GROUND_TO_AIR);
+        if (checkTransmissionState(3,3, current, now, MSG_ISSUE_TAXI_CLEARANCE, ATC_GROUND_TO_AIR)) {
             current->setState(4);
-            lastTransmission = now;
-            available = false;
         }
-        if ((state == 4) && available) {
-            transmit(&(*current), MSG_ACKNOWLEDGE_TAXI_CLEARANCE, ATC_AIR_TO_GROUND);
+        if (checkTransmissionState(4,4, current, now, MSG_ACKNOWLEDGE_TAXI_CLEARANCE, ATC_AIR_TO_GROUND)) {
             current->setState(5);
-            lastTransmission = now;
-            available = false;
         }
         if ((state == 5) && available) {
             current->setState(0);
@@ -845,11 +888,11 @@ void FGGroundNetwork::checkHoldPosition(int id, double lat,
     if ((origStatus != currStatus) && available) {
         //cerr << "Issueing hold short instrudtion " << currStatus << " " << available << endl;
         if (currStatus == true) { // No has a hold short instruction
-           transmit(&(*current), MSG_HOLD_POSITION, ATC_GROUND_TO_AIR);
+           transmit(&(*current), MSG_HOLD_POSITION, ATC_GROUND_TO_AIR, true);
            //cerr << "Transmittin hold short instrudtion " << currStatus << " " << available << endl;
            current->setState(1);
         } else {
-           transmit(&(*current), MSG_RESUME_TAXI, ATC_GROUND_TO_AIR);
+           transmit(&(*current), MSG_RESUME_TAXI, ATC_GROUND_TO_AIR, true);
            //cerr << "Transmittig resume instrudtion " << currStatus << " " << available << endl;
            current->setState(2);
         }
@@ -861,10 +904,19 @@ void FGGroundNetwork::checkHoldPosition(int id, double lat,
         //cerr << "Current state " << current->getState() << endl;
     } else {
     }
-    int state = current->getState();
-    if ((state == 1) && (available)) {
+    //int state = current->getState();
+    if (checkTransmissionState(1,1, current, now, MSG_ACKNOWLEDGE_HOLD_POSITION, ATC_AIR_TO_GROUND)) {
+            current->setState(0);
+            current->setHoldPosition(true);
+    }
+    if (checkTransmissionState(2,2, current, now, MSG_ACKNOWLEDGE_RESUME_TAXI, ATC_AIR_TO_GROUND)) {
+            current->setState(0);
+            current->setHoldPosition(false);
+    }
+
+    /*if ((state == 1) && (available)) {
         //cerr << "ACKNOWLEDGE HOLD" << endl;
-        transmit(&(*current), MSG_ACKNOWLEDGE_HOLD_POSITION, ATC_AIR_TO_GROUND);
+        transmit(&(*current), MSG_ACKNOWLEDGE_HOLD_POSITION, ATC_AIR_TO_GROUND, true);
         current->setState(0);
         current->setHoldPosition(true);
         lastTransmission = now;
@@ -873,13 +925,13 @@ void FGGroundNetwork::checkHoldPosition(int id, double lat,
     }
     if ((state == 2) && (available)) {
         //cerr << "ACKNOWLEDGE RESUME" << endl;
-        transmit(&(*current), MSG_ACKNOWLEDGE_RESUME_TAXI, ATC_AIR_TO_GROUND);
+        transmit(&(*current), MSG_ACKNOWLEDGE_RESUME_TAXI, ATC_AIR_TO_GROUND, true);
         current->setState(0);
         current->setHoldPosition(false);
         lastTransmission = now;
         available = false;
-    }
-}
+    }*/
+} 
 
 /**
  * Check whether situations occur where the current aircraft is waiting for itself
@@ -1035,3 +1087,122 @@ FGATCInstruction FGGroundNetwork::getInstruction(int id)
     }
     return FGATCInstruction();
 }
+
+// Note that this function is copied from simgear. for maintanance purposes, it's probabtl better to make a general function out of that.
+static void WorldCoordinate(osg::Matrix& obj_pos, double lat,
+                            double lon, double elev, double hdg)
+{
+    SGGeod geod = SGGeod::fromDegM(lon, lat, elev);
+    obj_pos = geod.makeZUpFrame();
+    // hdg is not a compass heading, but a counter-clockwise rotation
+    // around the Z axis
+    obj_pos.preMult(osg::Matrix::rotate(hdg * SGD_DEGREES_TO_RADIANS,
+                                        0.0, 0.0, 1.0));
+}
+
+
+
+
+void FGGroundNetwork::render()
+{
+
+    SGMaterialLib *matlib = globals->get_matlib();
+    if (group) {
+        //int nr = ;
+        globals->get_scenery()->get_scene_graph()->removeChild(group);
+        //while (group->getNumChildren()) {
+        //  cerr << "Number of children: " << group->getNumChildren() << endl;
+        simgear::EffectGeode* geode = (simgear::EffectGeode*) group->getChild(0);
+          //osg::MatrixTransform *obj_trans = (osg::MatrixTransform*) group->getChild(0);
+           //geode->releaseGLObjects();
+           //group->removeChild(geode);
+           //delete geode;
+    }
+    group = new osg::Group;
+
+    //for ( FGTaxiSegmentVectorIterator i = segments.begin(); i != segments.end(); i++) {
+    double dx = 0;
+    for   (TrafficVectorIterator i = activeTraffic.begin(); i != activeTraffic.end(); i++) {
+        // Handle start point
+        int pos = i->getCurrentPosition() - 1;
+        if (pos >= 0) {
+            
+            SGGeod start(SGGeod::fromDeg((i->getLongitude()), (i->getLatitude())));
+            SGGeod end  (SGGeod::fromDeg(segments[pos]->getEnd()->getLongitude(), segments[pos]->getEnd()->getLatitude()));
+
+            double length = SGGeodesy::distanceM(start, end);
+            //heading = SGGeodesy::headingDeg(start->getGeod(), end->getGeod());
+
+            double az2, heading; //, distanceM;
+            SGGeodesy::inverse(start, end, heading, az2, length);
+            double coveredDistance = length * 0.5;
+            SGGeod center;
+            SGGeodesy::direct(start, heading, coveredDistance, center, az2);
+            //cerr << "Active Aircraft : Centerpoint = (" << center.getLatitudeDeg() << ", " << center.getLongitudeDeg() << "). Heading = " << heading << endl;
+            ///////////////////////////////////////////////////////////////////////////////
+            // Make a helper function out of this
+            osg::Matrix obj_pos;
+                osg::MatrixTransform *obj_trans = new osg::MatrixTransform;
+                obj_trans->setDataVariance(osg::Object::STATIC);
+
+                WorldCoordinate( obj_pos, center.getLatitudeDeg(), center.getLongitudeDeg(), parent->elevation()+8+dx, -(heading) );
+
+                obj_trans->setMatrix( obj_pos );
+                //osg::Vec3 center(0, 0, 0)
+
+                float width = length /2.0;
+                osg::Vec3 corner(-width, 0, 0.25f);
+                osg::Vec3 widthVec(2*width + 1, 0, 0);
+                osg::Vec3 heightVec(0, 1, 0);
+                osg::Geometry* geometry;
+                geometry = osg::createTexturedQuadGeometry(corner, widthVec, heightVec);
+                simgear::EffectGeode* geode = new simgear::EffectGeode;
+                geode->setName("test");
+                geode->addDrawable(geometry);
+                //osg::Node *custom_obj;
+                SGMaterial *mat = matlib->find("UnidirectionalTaper");
+                if (mat)
+                    geode->setEffect(mat->get_effect());
+                obj_trans->addChild(geode);
+                // wire as much of the scene graph together as we can
+                //->addChild( obj_trans );
+                group->addChild( obj_trans );
+        /////////////////////////////////////////////////////////////////////
+        } else {
+             cerr << "BIG FAT WARNING: current position is here : " << pos << endl;
+        }
+        for(intVecIterator j = (i)->getIntentions().begin(); j != (i)->getIntentions().end(); j++) {
+             osg::Matrix obj_pos;
+            int k = (*j)-1;
+            if (k >= 0) {
+                osg::MatrixTransform *obj_trans = new osg::MatrixTransform;
+                obj_trans->setDataVariance(osg::Object::STATIC);
+
+                WorldCoordinate( obj_pos, segments[k]->getLatitude(), segments[k]->getLongitude(), parent->elevation()+8+dx, -(segments[k]->getHeading()) );
+
+                obj_trans->setMatrix( obj_pos );
+                //osg::Vec3 center(0, 0, 0)
+
+                float width = segments[k]->getLength() /2.0;
+                osg::Vec3 corner(-width, 0, 0.25f);
+                osg::Vec3 widthVec(2*width + 1, 0, 0);
+                osg::Vec3 heightVec(0, 1, 0);
+                osg::Geometry* geometry;
+                geometry = osg::createTexturedQuadGeometry(corner, widthVec, heightVec);
+                simgear::EffectGeode* geode = new simgear::EffectGeode;
+                geode->setName("test");
+                geode->addDrawable(geometry);
+                //osg::Node *custom_obj;
+                SGMaterial *mat = matlib->find("UnidirectionalTaper");
+                if (mat)
+                    geode->setEffect(mat->get_effect());
+                obj_trans->addChild(geode);
+                // wire as much of the scene graph together as we can
+                //->addChild( obj_trans );
+                group->addChild( obj_trans );
+            }
+        }
+        //dx += 0.1;
+    }
+    globals->get_scenery()->get_scene_graph()->addChild(group);
+}
\ No newline at end of file
index fe83d4df25cd51b4db5e2b4fcac2001b9836628d..bc51fd85731560f71ca49eca76514b86889ce8e8 100644 (file)
 #ifndef _GROUNDNETWORK_HXX_
 #define _GROUNDNETWORK_HXX_
 
+#include <osg/Geode>
+#include <osg/Geometry>
+#include <osg/MatrixTransform>
+#include <osg/Shape>
+
+
 #include <simgear/compiler.h>
 #include <simgear/route/waypoint.hxx>
 
@@ -37,6 +43,7 @@ using std::vector;
 #include "parking.hxx"
 #include <ATC/trafficcontrol.hxx>
 
+
 class FGTaxiSegment; // forward reference
 class FGAIFlightPlan; // forward reference
 class FGAirport;      // forward reference
@@ -56,8 +63,8 @@ private:
   int startNode;
   int endNode;
   double length;
-  double course;
-  double headingDiff;
+  double heading;
+  SGGeod center;
   bool isActive;
   bool isPushBackRoute;
   FGTaxiNode *start;
@@ -72,8 +79,7 @@ public:
       startNode(0),
       endNode(0),
       length(0),
-      course(0),
-      headingDiff(0),
+      heading(0),
       isActive(0),
       isPushBackRoute(0),
       start(0),
@@ -87,8 +93,8 @@ public:
       startNode         (other.startNode),
       endNode           (other.endNode),
       length            (other.length),
-      course            (other.course),
-      headingDiff       (other.headingDiff),
+      heading           (other.heading),
+      center            (other.center),
       isActive          (other.isActive),
       isPushBackRoute   (other.isPushBackRoute),
       start             (other.start),
@@ -103,8 +109,8 @@ public:
       startNode          = other.startNode;
       endNode            = other.endNode;
       length             = other.length;
-      course             = other.course;
-      headingDiff        = other.headingDiff;
+      heading            = other.heading;
+      center             = other.center;
       isActive           = other.isActive;
       isPushBackRoute    = other.isPushBackRoute;
       start              = other.start;
@@ -123,13 +129,15 @@ public:
   void setStart(FGTaxiNodeVector *nodes);
   void setEnd  (FGTaxiNodeVector *nodes);
   void setPushBackType(bool val) { isPushBackRoute = val; };
-  void setTrackDistance();
+  void setDimensions(double elevation);
 
   FGTaxiNode * getEnd() { return end;};
   FGTaxiNode * getStart() { return start; };
   double getLength() { return length; };
   int getIndex() { return index; };
-  
+  double getLatitude()  { return center.getLatitudeDeg();  };
+  double getLongitude() { return center.getLongitudeDeg(); };
+  double getHeading()   { return heading; }; 
   bool isPushBack() { return isPushBackRoute; };
 
   int getPenalty(int nGates);
@@ -137,7 +145,7 @@ public:
   FGTaxiSegment *getAddress() { return this;};
 
   bool operator<(const FGTaxiSegment &other) const { return index < other.index; };
-  bool hasSmallerHeadingDiff (const FGTaxiSegment &other) const { return headingDiff < other.headingDiff; };
+  //bool hasSmallerHeadingDiff (const FGTaxiSegment &other) const { return headingDiff < other.headingDiff; };
   FGTaxiSegment *opposite() { return oppositeDirection; };
   void setCourseDiff(double crse);
 
@@ -173,6 +181,7 @@ public:
     routes = rts;
     distance = dist; 
     currNode = nodes.begin();
+    currRoute = routes.begin();
 //    depth = dpth;
   };
 
@@ -241,6 +250,8 @@ private:
   void checkHoldPosition(int id, double lat, double lon, 
                         double heading, double speed, double alt);
 
+
+
 public:
   FGGroundNetwork();
   ~FGGroundNetwork();
@@ -269,11 +280,15 @@ public:
                                double lat, double lon, double hdg, double spd, double alt, 
                                double radius, int leg, FGAIAircraft *aircraft);
   virtual void signOff(int id);
-  virtual void update(int id, double lat, double lon, double heading, double speed, double alt, double dt);
+  virtual void updateAircraftInformation(int id, double lat, double lon, double heading, double speed, double alt, double dt);
   virtual bool hasInstruction(int id);
   virtual FGATCInstruction getInstruction(int id);
 
+  bool checkTransmissionState(int minState, int MaxState, TrafficVectorIterator i, time_t now, AtcMsgId msgId,
+                               AtcMsgDir msgDir);
   bool checkForCircularWaits(int id);
+  virtual void render();
+
 };
 
 
index cc62744cd8c32c3b364d69549aae701a1f93d89d..52a88efdfc1da92b03ab2b25490ea038d805a6e0 100644 (file)
@@ -76,6 +76,7 @@
 #include <AIModel/AIManager.hxx>
 
 #include <ATCDCL/ATCmgr.hxx>
+#include <ATC/atc_mgr.hxx>
 
 #include <Autopilot/route_mgr.hxx>
 #include <Autopilot/autopilotgroup.hxx>
@@ -1430,12 +1431,26 @@ bool fgInitSubsystems() {
 
     ////////////////////////////////////////////////////////////////////
     // Initialise the ATC Manager
+    // Note that this is old stuff, but might be necessesary for the 
+    // current ATIS implementation. Therefore, leave it in here
+    // until the ATIS system is ported over to make use of the ATIS 
+    // sub system infrastructure.
     ////////////////////////////////////////////////////////////////////
 
     SG_LOG(SG_GENERAL, SG_INFO, "  ATC Manager");
     globals->set_ATC_mgr(new FGATCMgr);
     globals->get_ATC_mgr()->init(); 
 
+    ////////////////////////////////////////////////////////////////////
+   // Initialize the ATC subsystem
+    ////////////////////////////////////////////////////////////////////
+    globals->add_subsystem("ATC", new FGATCManager, SGSubsystemMgr::POST_FDM);
+    ////////////////////////////////////////////////////////////////////
+    // Initialise the ATIS Subsystem
+    ////////////////////////////////////////////////////////////////////
+    //globals->add_subsystem("atis", new FGAtisManager, SGSubsystemMgr::POST_FDM);
+
+
     ////////////////////////////////////////////////////////////////////
     // Initialize multiplayer subsystem
     ////////////////////////////////////////////////////////////////////
index 6eeb706679077d70b36065859b277f8e9ecf7c13..b7f94ca0875cfa78e0c247a979fa84bd3769f935 100644 (file)
@@ -168,6 +168,7 @@ bool FGTileMgr::sched_tile( const SGBucket& b, double priority, bool current_vie
         if ( tile_cache.insert_tile( t ) )
         {
             // Attach to scene graph
+
             t->addToSceneGraph(globals->get_scenery()->get_terrain_branch());
         } else
         {
index 8b5b6ee68e4dfc5bec3fe97a70859cade54d76c4..5339a292ff0231f0853153d3e34d21310893a984 100644 (file)
 
 FGScheduledFlight::FGScheduledFlight()
 {
-   initialized = false;
-   available = true;
+    departureTime  = 0;
+    arrivalTime    = 0;
+    cruiseAltitude = 0;
+    repeatPeriod   = 0;
+    initialized = false;
+    available = true;
 }
   
 FGScheduledFlight::FGScheduledFlight(const FGScheduledFlight &other)
index 0ee3eb6bd1f9c5b3056daa27b0488810ec53c59b..0567102fb89930307b107ca4a2a5ccfb269f4c0d 100644 (file)
@@ -90,6 +90,8 @@ public:
   time_t getDepartureTime() { return departureTime; };
   time_t getArrivalTime  () { return arrivalTime;   };
   
+  void setDepartureAirport(string port) { depId = port; };
+  void setArrivalAirport  (string port) { arrId = port; };
   FGAirport *getDepartureAirport();
   FGAirport *getArrivalAirport  ();
 
@@ -109,6 +111,9 @@ public:
   void release() { available = true; };
 
   bool isAvailable() { return available; };
+
+  void setCallSign(string val)    { callsign = val; };
+  void setFlightRules(string val) { fltRules = val; };
 };
 
 typedef vector<FGScheduledFlight*>           FGScheduledFlightVec;
index 20d30609cf9e1b57a0f4c735e278ca24f56dc45c..0306fc4cd010edc8dd2b24de1c36be07eecbed0c 100644 (file)
@@ -68,6 +68,7 @@ FGAISchedule::FGAISchedule()
   radius = 0;
   groundOffset = 0;
   distanceToUser = 0;
+  valid = true;
   //score = 0;
 }
 
@@ -120,6 +121,7 @@ FGAISchedule::FGAISchedule(string model,
   runCount         = 0;
   hits             = 0;
   initialized      = false;
+  valid            = true;
 }
 
 FGAISchedule::FGAISchedule(const FGAISchedule &other)
@@ -146,6 +148,7 @@ FGAISchedule::FGAISchedule(const FGAISchedule &other)
   runCount           = other.runCount;
   hits               = other.hits;
   initialized        = other.initialized;
+  valid              = other.valid;
 }
 
 
@@ -192,9 +195,12 @@ bool FGAISchedule::update(time_t now, const SGVec3d& userCart)
     elapsedTimeEnroute,
     remainingTimeEnroute, 
     deptime = 0;
-  
+  if (!valid) {
+    return false;
+  }
   scheduleFlights();
   if (flights.empty()) { // No flights available for this aircraft
+      valid = false;
       return false;
   }
   
@@ -211,7 +217,7 @@ bool FGAISchedule::update(time_t now, const SGVec3d& userCart)
      firstRun = false;
   }
   
-  FGScheduledFlight* flight = flights.front();
+    FGScheduledFlight* flight = flights.front();
   if (!deptime) {
     deptime = flight->getDepartureTime();
     //cerr << "Settiing departure time " << deptime << endl;
@@ -329,19 +335,35 @@ bool FGAISchedule::createAIAircraft(FGScheduledFlight* flight, double speedKnots
   aircraft->setBank(0);
       
   courseToDest = SGGeodesy::courseDeg(position, arr->geod());
-  aircraft->SetFlightPlan(new FGAIFlightPlan(aircraft, flightPlanName, courseToDest, deptime, 
-                                                            dep, arr, true, radius, 
-                                                            flight->getCruiseAlt()*100, 
-                                                            position.getLatitudeDeg(), 
-                   position.getLongitudeDeg(), 
-                   speedKnots, flightType, acType, 
-                                                            airline));
-                   
-    
-  FGAIManager* aimgr = (FGAIManager *) globals-> get_subsystem("ai_model");
-  aimgr->attach(aircraft);
-  AIManagerRef = aircraft->getID();
-  return true;
+    FGAIFlightPlan *fp = new FGAIFlightPlan(aircraft, flightPlanName, courseToDest, deptime, 
+                                            dep, arr, true, radius, 
+                                            flight->getCruiseAlt()*100, 
+                                            position.getLatitudeDeg(), 
+                                            position.getLongitudeDeg(), 
+                                            speedKnots, flightType, acType, 
+                                            airline);
+  if (fp->isValidPlan()) {
+        aircraft->SetFlightPlan(fp);
+        FGAIManager* aimgr = (FGAIManager *) globals-> get_subsystem("ai_model");
+        aimgr->attach(aircraft);
+        AIManagerRef = aircraft->getID();
+        return true;
+  } else {
+        delete aircraft;
+        delete fp;
+        //hand back the flights that had already been scheduled
+        while (!flights.empty()) {
+            flights.front()->release();
+            flights.erase(flights.begin());
+        }
+        return false;
+  }
+}
+
+// Create an initial heading for user controlled aircraft.
+void FGAISchedule::setHeading()  
+{ 
+    courseToDest = SGGeodesy::courseDeg((*flights.begin())->getDepartureAirport()->geod(), (*flights.begin())->getArrivalAirport()->geod());
 }
 
 void FGAISchedule::scheduleFlights()
index cc80e40805a2a9d9878525302d514b4f37b6bd11..1f508271bb78a5c8ff6f3c13a59da61b7744c704 100644 (file)
@@ -59,6 +59,7 @@ class FGAISchedule
   bool firstRun;
   double courseToDest;
   bool initialized;
+  bool valid;
 
   void scheduleFlights();
   
@@ -117,10 +118,14 @@ class FGAISchedule
   void         setHits    (unsigned int count) { hits     = count; };
   void         setScore   ();
   double       getScore   () { return score; };
+  void         setHeading (); 
+  void         assign         (FGScheduledFlight *ref) { flights.push_back(ref); };
+  void         setFlightType  (string val            ) { flightType = val; };
   FGScheduledFlight*findAvailableFlight (const string &currentDestination, const string &req);
   // used to sort in decending order of score: I've probably found a better way to
   // decending order sorting, but still need to test that.
   bool operator< (const FGAISchedule &other) const { return (score > other.score); };
+    void taint() { valid = false; };
   //void * getAiRef                 () { return AIManagerRef; };
   //FGAISchedule* getAddress        () { return this;};
 
index 4abbc1a20a8673618d06d28644c19708f92aef8d..9ebf78c1c7c063e80ba68352d1d4073131d4a3a8 100644 (file)
@@ -258,6 +258,7 @@ void FGTrafficManager::update(double /*dt */ )
     }
     //cerr << "Processing << " << (*currAircraft)->getRegistration() << " with score " << (*currAircraft)->getScore() << endl;
     if (!((*currAircraft)->update(now, userCart))) {
+        (*currAircraft)->taint();
         // NOTE: With traffic manager II, this statement below is no longer true
         // after proper initialization, we shouldnt get here.
         // But let's make sure