]> git.mxchange.org Git - flightgear.git/commitdiff
TACAN/mobile navaid cleanup and improvements.
authorThomas Geymayer <tomgey@gmail.com>
Sat, 1 Mar 2014 19:18:02 +0000 (20:18 +0100)
committerThomas Geymayer <tomgey@gmail.com>
Sat, 1 Mar 2014 19:19:06 +0000 (20:19 +0100)
src/Airports/airport.cxx
src/Airports/gnnode.cxx
src/Airports/runwaybase.cxx
src/Instrumentation/tacan.cxx
src/Instrumentation/tacan.hxx
src/Navaids/NavDataCache.cxx
src/Navaids/navlist.cxx
src/Navaids/navlist.hxx
src/Navaids/navrecord.cxx
src/Navaids/navrecord.hxx
src/Navaids/positioned.hxx

index 5a511eb996854c32042aed4b34eaa76ee73b1862..9d07d6b997ad2b78dcb60ab1147bcbf46a1c5b5b 100644 (file)
@@ -394,7 +394,7 @@ FGRunwayRef FGAirport::getActiveRunwayForUsage() const
   double hdg = 270;
   
   if (envMgr) {
-    FGEnvironment stationWeather(envMgr->getEnvironment(mPosition));
+    FGEnvironment stationWeather(envMgr->getEnvironment(geod()));
   
     double windSpeed = stationWeather.get_wind_speed_kt();
     if (windSpeed > 0.0) {
@@ -617,7 +617,7 @@ void FGAirport::processThreshold(SGPropertyNode* aThreshold)
   
   double lon = aThreshold->getDoubleValue("lon"),
   lat = aThreshold->getDoubleValue("lat");
-  SGGeod newThreshold(SGGeod::fromDegM(lon, lat, mPosition.getElevationM()));
+  SGGeod newThreshold(SGGeod::fromDegM(lon, lat, elevationM()));
   
   double newHeading = aThreshold->getDoubleValue("hdg-deg");
   double newDisplacedThreshold = aThreshold->getDoubleValue("displ-m");
@@ -685,7 +685,7 @@ void FGAirport::readTowerData(SGPropertyNode* aRoot)
 // tower elevation is AGL, not AMSL. Since we don't want to depend on the
 // scenery for a precise terrain elevation, we use the field elevation
 // (this is also what the apt.dat code does)
-  double fieldElevationM = geod().getElevationM();
+  double fieldElevationM = elevationM();
   SGGeod towerLocation(SGGeod::fromDegM(lon, lat, fieldElevationM + elevM));
   
   NavDataCache* cache = NavDataCache::instance();
index 5c61f89af15e6f6fb91618b7feb17804a16f5b71..619e2e115a231da0d8661637682de043a1ab90ed 100644 (file)
@@ -33,16 +33,18 @@ void FGTaxiNode::setElevation(double val)
 
 double FGTaxiNode::getElevationFt()
 {
-  if (mPosition.getElevationFt() == 0.0) {
-    SGGeod center2 = mPosition;
+  const SGGeod& pos = geod();
+  if( pos.getElevationFt() == 0.0)
+  {
+    SGGeod center2 = pos;
     FGScenery* local_scenery = globals->get_scenery();
     center2.setElevationM(SG_MAX_ELEVATION_M);
     double elevationEnd = -100;
-    if (local_scenery->get_elevation_m( center2, elevationEnd, NULL )) {
-      
-      SGGeod newPos = mPosition;
+    if (local_scenery->get_elevation_m( center2, elevationEnd, NULL ))
+    {
+      SGGeod newPos = pos;
       newPos.setElevationM(elevationEnd);
-    // this will call modifyPosition to update mPosition
+      // this will call modifyPosition to update mPosition
       NavDataCache* cache = NavDataCache::instance();
       NavDataCache::Transaction txn(cache);
       cache->updatePosition(guid(), newPos);
@@ -50,7 +52,7 @@ double FGTaxiNode::getElevationFt()
     }
   }
   
-  return mPosition.getElevationFt();
+  return pos.getElevationFt();
 }
 
 double FGTaxiNode::getElevationM()
index 0e07c1fa9c82caa1674ea345d8f774ac5601a2ea..4f60682a9a75b36ecaacee90276e70be39349fcd 100644 (file)
@@ -61,8 +61,8 @@ FGRunwayBase::FGRunwayBase(PositionedID aGuid, Type aTy, const string& aIdent,
 
 SGGeod FGRunwayBase::pointOnCenterline(double aOffset) const
 {
-  SGGeod result = SGGeodesy::direct(mPosition, _heading, aOffset);
-  result.setElevationM(mPosition.getElevationM());
+  SGGeod result = SGGeodesy::direct(geod(), _heading, aOffset);
+  result.setElevationM(geod().getElevationM());
     
   return result;
 }
@@ -73,8 +73,7 @@ SGGeod FGRunwayBase::pointOffCenterline(double aOffset, double lateralOffset) co
   SGGeod temp;
   double dummyAz2;
 
-  SGGeodesy::direct(mPosition, _heading, 
-    aOffset, temp, dummyAz2);
+  SGGeodesy::direct(geod(), _heading, aOffset, temp, dummyAz2);
 
   SGGeodesy::direct(temp, SGMiscd::normalizePeriodic(0, 360,_heading+90.0),
     lateralOffset,
index 5b1d358649a110a444cc8986ed762dc2b46b7021..f9b463f506bf4a8b13b90f6c068f06080bd26c9b 100644 (file)
@@ -17,9 +17,6 @@
 
 #include "tacan.hxx"
 
-using std::vector;
-using std::string;
-
 /**
  * Adjust the range.
  *
@@ -31,7 +28,7 @@ static double
 adjust_range (double transmitter_elevation_ft, double aircraft_altitude_ft,
               double max_range_nm)
 {
-    max_range_nm = 150;
+    max_range_nm = 150; // TODO why a fixed range?
     double delta_elevation_ft =
         fabs(aircraft_altitude_ft - transmitter_elevation_ft);
     double range_nm = 1.23 * sqrt(delta_elevation_ft);
@@ -43,32 +40,31 @@ adjust_range (double transmitter_elevation_ft, double aircraft_altitude_ft,
     return range_nm + (range_nm * rand * rand);
 }
 
-
-TACAN::TACAN ( SGPropertyNode *node ) :
-    _name(node->getStringValue("name", "tacan")),
-    _num(node->getIntValue("number", 0)),
-    _new_frequency(false),
-    _channel("0000"),
-    _last_distance_nm(0),
-    _frequency_mhz(-1),
-    _time_before_search_sec(0),
-    _mobile_valid(false),
-    _transmitter_valid(false),
-    _transmitter_pos(SGGeod::fromDeg(0, 0)),
-    _transmitter_range_nm(0),
-    _transmitter_bias(0.0),
-    _listener_active(0)
+//------------------------------------------------------------------------------
+TACAN::TACAN( SGPropertyNode *node ):
+  _name(node->getStringValue("name", "tacan")),
+  _num(node->getIntValue("number", 0)),
+  _was_disabled(true),
+  _new_frequency(false),
+  _channel("0000"),
+  _last_distance_nm(0),
+  _frequency_mhz(-1),
+  _time_before_search_sec(0),
+  _listener_active(0)
 {
+
 }
 
-TACAN::~TACAN ()
+//------------------------------------------------------------------------------
+TACAN::~TACAN()
 {
+
 }
 
-void
-TACAN::init ()
+//------------------------------------------------------------------------------
+void TACAN::init()
 {
-    string branch = "/instrumentation/" + _name;
+    std::string branch = "/instrumentation/" + _name;
 
     SGPropertyNode *node = fgGetNode(branch.c_str(), _num, true );
 
@@ -84,12 +80,6 @@ TACAN::init ()
     _channel_in3_node = fnode->getChild("selected-channel", 3, true);
     _channel_in4_node = fnode->getChild("selected-channel", 4, true);
 
-    _channel_in0_node->addChangeListener(this);
-    _channel_in1_node->addChangeListener(this);
-    _channel_in2_node->addChangeListener(this);
-    _channel_in3_node->addChangeListener(this);
-    _channel_in4_node->addChangeListener(this, true);
-
     _in_range_node = node->getChild("in-range", 0, true);
     _distance_node = node->getChild("indicated-distance-nm", 0, true);
     _speed_node = node->getChild("indicated-ground-speed-kt", 0, true);
@@ -100,298 +90,176 @@ TACAN::init ()
     SGPropertyNode *dnode = node->getChild("display", 0, true);
     _x_shift_node = dnode->getChild("x-shift", 0, true);
     _y_shift_node = dnode->getChild("y-shift", 0, true);
-    _rotation_node = dnode->getChild("rotation", 0, true);
     _channel_node = dnode->getChild("channel", 0, true);
 
-    SGPropertyNode *cnode = fgGetNode("/ai/models/carrier", _num, false );
-    _carrier_name_node = cnode ? cnode->getChild("name", 0, false) : 0;
-
-    SGPropertyNode *tnode = fgGetNode("/ai/models/aircraft", _num, false);
-    _tanker_callsign_node = tnode ? tnode->getChild("callsign", 0, false) : 0;
-
-    SGPropertyNode *mnode = fgGetNode("/ai/models/multiplayer", _num, false);
-    _mp_callsign_node = mnode ? mnode->getChild("callsign", 0, false) : 0;
-
     _heading_node = fgGetNode("/orientation/heading-deg", true);
     _electrical_node = fgGetNode("/systems/electrical/outputs/tacan", true);
+
+    // Add/trigger change listener after creating all nodes
+    _channel_in0_node->addChangeListener(this);
+    _channel_in1_node->addChangeListener(this);
+    _channel_in2_node->addChangeListener(this);
+    _channel_in3_node->addChangeListener(this);
+    _channel_in4_node->addChangeListener(this, true);
 }
 
-void
-TACAN::reinit ()
+//------------------------------------------------------------------------------
+void TACAN::reinit()
 {
-    _time_before_search_sec = 0;
+  _time_before_search_sec = 0;
 }
 
-void
-TACAN::update (double delta_time_sec)
+//------------------------------------------------------------------------------
+void TACAN::update(double delta_time_sec)
 {
-    // don't do anything when paused
-    if (delta_time_sec == 0) return;
-
-    if (!_serviceable_node->getBoolValue() || !_electrical_node->getBoolValue()) {
-        _last_distance_nm = 0;
-        _in_range_node->setBoolValue(false);
-        _distance_node->setDoubleValue(0);
-        _speed_node->setDoubleValue(0);
-        _time_node->setDoubleValue(0);
-        return;
-    }
+  // don't do anything when paused
+  if( delta_time_sec == 0 )
+    return;
 
-    SGGeod pos(globals->get_aircraft_position());
-                                // On timeout, scan again
-    _time_before_search_sec -= delta_time_sec;
-    if ((_time_before_search_sec < 0 || _new_frequency) && _frequency_mhz >= 0)
-        search(_frequency_mhz, pos);
-
-                                 // Calculate the distance to the transmitter
-
-    //calculate the bearing and range of the mobile from the aircraft
-    double mobile_az2 = 0;
-    double mobile_bearing = 0;
-    double mobile_distance = SGLimitsd::max();
-    if (_mobile_valid) {
-        geo_inverse_wgs_84(pos, _mobilePos,
-                       &mobile_bearing, &mobile_az2, &mobile_distance);
-    }
+  if(   !_serviceable_node->getBoolValue()
+     || !_electrical_node->getBoolValue() )
+    return disabled();
 
-    //calculate the bearing and range of the station from the aircraft
-    double az2 = 0;
-    double bearing = 0;
-    double distance = SGLimitsd::max();
-    if (_transmitter_valid) {
-        geo_inverse_wgs_84(pos, _transmitter_pos,
-                           &bearing, &az2, &distance);
-    }
-
-    //select the nearer
-    if ( mobile_distance <= distance && _mobile_valid) {
-        bearing = mobile_bearing;
-        distance = mobile_distance;
-        _transmitter_pos.setElevationFt(_mobilePos.getElevationFt());
-        _transmitter_range_nm = _mobile_range_nm;
-        _transmitter_bias = _mobile_bias;
-        _transmitter_name = _mobile_name;
-        _name_node->setStringValue(_transmitter_name.c_str());
-        _transmitter_ident = _mobile_ident;
-        _ident_node->setStringValue(_transmitter_ident.c_str());
-        _channel_node->setStringValue(_channel.c_str());
-    }
+  SGGeod pos(globals->get_aircraft_position());
 
-    //// calculate some values for boresight display
-    double distance_nm = distance * SG_METER_TO_NM;
+  // On timeout, scan again
+  _time_before_search_sec -= delta_time_sec;
+  if ((_time_before_search_sec < 0 || _new_frequency) && _frequency_mhz >= 0)
+      search(_frequency_mhz, pos);
 
-    //// calculate look left/right to target, without yaw correction
-    // double horiz_offset = bearing - heading;
-    //
-    // if (horiz_offset > 180.0) horiz_offset -= 360.0;
-    // if (horiz_offset < -180.0) horiz_offset += 360.0;
+  if( !_active_station || !_active_station->get_serviceable() )
+    return disabled();
 
-    //// now correct look left/right for yaw
-    // horiz_offset += yaw;
+  // Calculate the bearing and range of the station from the aircraft
+  double az = 0;
+  double bearing = 0;
+  double distance = SGLimitsd::max();
+  if( !SGGeodesy::inverse(pos, _active_station->geod(), bearing, az, distance) )
+    return disabled();
 
-    // use the bearing for a plan position indicator display
-
-    double horiz_offset = bearing;
+  double range_nm = adjust_range( _active_station->get_elev_ft(),
+                                  pos.getElevationFt(),
+                                  _active_station->get_range() );
 
-    // calculate values for radar display
-    double y_shift = distance_nm * cos( horiz_offset * SG_DEGREES_TO_RADIANS);
-    double x_shift = distance_nm * sin( horiz_offset * SG_DEGREES_TO_RADIANS);
+  double distance_nm = distance * SG_METER_TO_NM;
 
-    double rotation = 0;
+  if( distance_nm > range_nm )
+    return disabled();
 
-    double range_nm = adjust_range(_transmitter_pos.getElevationFt(),
-                                  pos.getElevationFt(),
-                                   _transmitter_range_nm);
+  //// calculate look left/right to target, without yaw correction
+  // double horiz_offset = bearing - heading;
+  //
+  // if (horiz_offset > 180.0) horiz_offset -= 360.0;
+  // if (horiz_offset < -180.0) horiz_offset += 360.0;
 
-    if (distance_nm <= range_nm) {
-        double speed_kt = (fabs(distance_nm - _last_distance_nm) *
-                           ((1 / delta_time_sec) * 3600.0));
-        _last_distance_nm = distance_nm;
+  //// now correct look left/right for yaw
+  // horiz_offset += yaw;
 
-        _in_range_node->setBoolValue(true);
-        double tmp_dist = distance_nm - _transmitter_bias;
-        if ( tmp_dist < 0.0 ) {
-            tmp_dist = 0.0;
-        }
-        _distance_node->setDoubleValue( tmp_dist );
-        _speed_node->setDoubleValue(speed_kt);
-        _time_node->setDoubleValue(speed_kt > 0 ? (distance_nm/speed_kt*60.0) : 0);
-        _bearing_node->setDoubleValue(bearing);
-        _x_shift_node->setDoubleValue(x_shift);
-        _y_shift_node->setDoubleValue(y_shift);
-        _rotation_node->setDoubleValue(rotation);
-    } else {
-        _last_distance_nm = 0;
-        _in_range_node->setBoolValue(false);
-        _distance_node->setDoubleValue(0);
-        _speed_node->setDoubleValue(0);
-        _time_node->setDoubleValue(0);
-        _bearing_node->setDoubleValue(0);
-        _x_shift_node->setDoubleValue(0);
-        _y_shift_node->setDoubleValue(0);
-        _rotation_node->setDoubleValue(0);
-    }
+  // use the bearing for a plan position indicator display
+  double horiz_offset = bearing;
 
-                                // If we can't find a valid station set everything to zero
-    if (!_transmitter_valid && !_mobile_valid ) {
-        _in_range_node->setBoolValue(false);
-        _distance_node->setDoubleValue(0);
-        _speed_node->setDoubleValue(0);
-        _time_node->setDoubleValue(0);
-        _bearing_node->setDoubleValue(0);
-        _x_shift_node->setDoubleValue(0);
-        _y_shift_node->setDoubleValue(0);
-        _rotation_node->setDoubleValue(0);
-        _transmitter_name = "";
-        _name_node->setStringValue(_transmitter_name.c_str());
-        _transmitter_ident = "";
-        _ident_node->setStringValue(_transmitter_ident.c_str());
-        _channel_node->setStringValue(_channel.c_str());
-        return;
-    }
-} // end function update
+  // calculate values for radar display
+  double y_shift = distance_nm * cos(horiz_offset * SG_DEGREES_TO_RADIANS);
+  double x_shift = distance_nm * sin(horiz_offset * SG_DEGREES_TO_RADIANS);
 
-void
-TACAN::search (double frequency_mhz,const SGGeod& pos)
-{
-    int number, i;
-    _mobile_valid = false;
-
-    // reset search time
-    _time_before_search_sec = 1.0;
-
-    //try any carriers first
-    FGNavRecord *mobile_tacan = FGNavList::findByFreq( frequency_mhz, FGNavList::carrierFilter() );
-    bool freq_valid = (mobile_tacan != NULL);
-
-    if ( freq_valid ) {
-
-        string str1( mobile_tacan->name() );
-
-        SGPropertyNode * branch = fgGetNode("ai/models", true);
-        vector<SGPropertyNode_ptr> carrier = branch->getChildren("carrier");
-
-        number = carrier.size();
-
-        for ( i = 0; i < number; ++i ) {
-            string str2 ( carrier[i]->getStringValue("name", ""));
-
-            string::size_type loc1= str1.find( str2, 0 );
-            if ( loc1 != string::npos && str2 != "" ) {
-                _mobilePos = SGGeod::fromDegFt(
-                             carrier[i]->getDoubleValue("position/longitude-deg"),
-                             carrier[i]->getDoubleValue("position/latitude-deg"),
-                             mobile_tacan->get_elev_ft());
-                _mobile_range_nm = mobile_tacan->get_range();
-                _mobile_bias = mobile_tacan->get_multiuse();
-                _mobile_name = mobile_tacan->name();
-                _mobile_ident = mobile_tacan->get_trans_ident();
-                _mobile_valid = true;
-                break;
-            } else {
-                _mobile_valid = false;
-            }
-        }
+  // TODO probably not the best way to do this (especially with mobile stations)
+  double speed_kt = fabs(distance_nm - _last_distance_nm)
+                  * (3600 / delta_time_sec);
+  _speed_node->setDoubleValue(speed_kt);
+  _last_distance_nm = distance_nm;
 
-        //try any AI tankers second
-        if ( !_mobile_valid) {
-        SGPropertyNode * branch = fgGetNode("ai/models", true);
-        vector<SGPropertyNode_ptr> tanker = branch->getChildren("tanker");
-
-        number = tanker.size();
-
-        for ( i = 0; i < number; ++i ) {
-            string str4 ( tanker[i]->getStringValue("callsign", ""));
-            string::size_type loc1= str1.find( str4, 0 );
-            if ( loc1 != string::npos && str4 != "" ) {
-                _mobilePos = SGGeod::fromDegFt(
-                                             tanker[i]->getDoubleValue("position/longitude-deg"),
-                                             tanker[i]->getDoubleValue("position/latitude-deg"),
-                                             tanker[i]->getDoubleValue("position/altitude-ft"));
-
-              
-                _mobile_range_nm = mobile_tacan->get_range();
-                _mobile_bias = mobile_tacan->get_multiuse();
-                _mobile_name = mobile_tacan->name();
-                _mobile_ident = mobile_tacan->get_trans_ident();
-                _mobile_valid = true;
-                break;
-            } else {
-                _mobile_valid = false;
-            }
-        }
-    }
+  double bias = _active_station->get_multiuse();
+  _distance_node->setDoubleValue( SGMiscd::max(0.0, distance_nm - bias) );
 
-    //try any mp tankers third, if we haven't found the tanker in the ai aircraft
-
-    if ( !_mobile_valid ) {
-        SGPropertyNode * branch = fgGetNode("ai/models", true);
-        vector<SGPropertyNode_ptr> mp_tanker = branch->getChildren("multiplayer");
-
-        number = mp_tanker.size();
-
-        if ( number > 0 ) {      // don't do this if there are no MP aircraft
-            for ( i = 0; i < number; ++i ) {
-                string str6 ( mp_tanker[i]->getStringValue("callsign", ""));
-                string::size_type loc1= str1.find( str6, 0 );
-                if ( loc1 != string::npos && str6 != "" ) {
-                  _mobilePos = SGGeod::fromDegFt(
-                                                 mp_tanker[i]->getDoubleValue("position/longitude-deg"),
-                                                 mp_tanker[i]->getDoubleValue("position/latitude-deg"),
-                                                 mp_tanker[i]->getDoubleValue("position/altitude-ft"));
-
-                  
-                    _mobile_range_nm = mobile_tacan->get_range();
-                    _mobile_bias = mobile_tacan->get_multiuse();
-                    _mobile_name = mobile_tacan->name();
-                    _mobile_ident = mobile_tacan->get_trans_ident();
-                    _mobile_valid = true;
-                    break;
-                } else {
-                    _mobile_valid = false;
-                }
-                }
-            }
-        }
-    } else {
-        _mobile_valid = false;
-    }
+  _time_node->setDoubleValue(speed_kt > 0 ? (distance_nm/speed_kt*60.0) : 0);
+  _bearing_node->setDoubleValue(bearing);
+  _x_shift_node->setDoubleValue(x_shift);
+  _y_shift_node->setDoubleValue(y_shift);
 
-    // try the TACAN/VORTAC list next
-    FGNavRecord *tacan = FGNavList::findByFreq( frequency_mhz, pos, FGNavList::tacanFilter() );
+  _name_node->setStringValue(_active_station->name());
+  _ident_node->setStringValue(_active_station->ident());
+  _in_range_node->setBoolValue(true);
 
-    _transmitter_valid = (tacan != NULL);
+  _was_disabled = false;
+}
 
-    if ( _transmitter_valid ) {
+//------------------------------------------------------------------------------
+void TACAN::disabled()
+{
+  if( _was_disabled )
+    return;
+
+  _last_distance_nm = 0;
+
+  _in_range_node->setBoolValue(false);
+  _distance_node->setDoubleValue(0);
+  _speed_node->setDoubleValue(0);
+  _time_node->setDoubleValue(0);
+  _bearing_node->setDoubleValue(0);
+  _x_shift_node->setDoubleValue(0);
+  _y_shift_node->setDoubleValue(0);
+  _name_node->setStringValue("");
+  _ident_node->setStringValue("");
+
+  _was_disabled = true;
+}
 
-        _transmitter_pos = tacan->geod();
-        _transmitter_range_nm = tacan->get_range();
-        _transmitter_bias = tacan->get_multiuse();
-        _transmitter_name = tacan->name();
-        _name_node->setStringValue(_transmitter_name.c_str());
-        _transmitter_ident = tacan->get_trans_ident();
-        _ident_node->setStringValue(_transmitter_ident.c_str());
-    }
+//------------------------------------------------------------------------------
+void TACAN::search (double frequency_mhz,const SGGeod& pos)
+{
+  // reset search time
+  _time_before_search_sec = 1.0;
+
+  // Get first matching mobile station (carriers/tankers/etc.)
+  // TODO do we need to check for mobile stations with same frequency? Currently
+  //      the distance is not taken into account.
+  FGNavRecordRef mobile_tacan =
+    FGNavList::findByFreq(frequency_mhz, FGNavList::mobileTacanFilter());
+
+  double mobile_dist = (mobile_tacan && mobile_tacan->get_serviceable())
+                     ? SGGeodesy::distanceM(pos, mobile_tacan->geod())
+                     : SGLimitsd::max();
+
+  // No get nearest TACAN/VORTAC
+  FGNavRecordRef tacan =
+    FGNavList::findByFreq(frequency_mhz, pos, FGNavList::tacanFilter());
+
+  double tacan_dist = tacan
+                    ? SGGeodesy::distanceM(pos, tacan->geod())
+                    : SGLimitsd::max();
+
+  // Select nearer station as active
+  // TODO do we need to take more care of stations with same frequency?
+  _active_station = mobile_dist < tacan_dist
+                  ? mobile_tacan
+                  : tacan;
 }
 
-double
-TACAN::searchChannel (const string& channel)
+//------------------------------------------------------------------------------
+double TACAN::searchChannel(const std::string& channel)
 {
-    double frequency_khz = 0;
-
-    FGTACANRecord *freq
-        = globals->get_channellist()->findByChannel( channel );
-    bool _freq_valid = (freq != NULL);
-    SG_LOG( SG_INSTR, SG_DEBUG, "freq valid " << _freq_valid );
-    if ( _freq_valid ) {
-        frequency_khz = freq->get_freq();
-        SG_LOG( SG_INSTR, SG_DEBUG, "freq output " << frequency_khz );
-        //check sanity
-        if (frequency_khz >= 9620 && frequency_khz <= 121300)
-            return frequency_khz/100;
-    }
-    return frequency_khz = 0;
-} // end TACAN::searchChannel
+  FGTACANRecord *freq = globals->get_channellist()->findByChannel(channel);
+  if( !freq )
+  {
+    SG_LOG(SG_INSTR, SG_DEBUG, "Invalid TACAN channel: " << channel);
+    return 0;
+  }
+
+  double frequency_khz = freq->get_freq();
+  if(frequency_khz < 9620 || frequency_khz > 121300)
+  {
+    SG_LOG
+    (
+      SG_INSTR,
+      SG_DEBUG,
+      "TACAN frequency out of range: " << channel
+                               << ": " << frequency_khz << "kHz"
+    );
+    return 0;
+  }
+
+  return frequency_khz/100;
+}
 
 /*
  * Listener callback. Maintains channel input properties,
@@ -406,7 +274,7 @@ TACAN::valueChanged(SGPropertyNode *prop)
     _listener_active++;
 
     int index = prop->getIndex();
-    string channel = _channel;
+    std::string channel = _channel;
 
     if (index) {  // channel digit or X/Y input
         int c;
@@ -451,6 +319,7 @@ TACAN::valueChanged(SGPropertyNode *prop)
         }
 
         _channel = channel;
+        _channel_node->setStringValue(_channel);
         _time_before_search_sec = 0;
     }
 
index b48057f4bd13dd806fd17dfd3e8333a4837cb45e..92f57c7d348748c1d97d0bd6efc81f8869cb6059 100644 (file)
 class TACAN : public SGSubsystem, public SGPropertyChangeListener
 {
 
-public:
+  public:
 
-    TACAN ( SGPropertyNode *node );
-    virtual ~TACAN ();
+    TACAN(SGPropertyNode *node);
+    virtual ~TACAN();
 
     virtual void init ();
     virtual void reinit ();
     virtual void update (double delta_time_sec);
 
-private:
+  private:
+
+    void disabled();
 
     void search (double frequency, const SGGeod& pos);
-  double searchChannel (const std::string& channel);
+    double searchChannel (const std::string& channel);
     void valueChanged (SGPropertyNode *);
 
     std::string _name;
@@ -59,7 +61,6 @@ private:
     SGPropertyNode_ptr _display_node;
     SGPropertyNode_ptr _x_shift_node;
     SGPropertyNode_ptr _y_shift_node;
-    SGPropertyNode_ptr _rotation_node;
 
     SGPropertyNode_ptr _in_range_node;
     SGPropertyNode_ptr _distance_node;
@@ -76,31 +77,14 @@ private:
     SGPropertyNode_ptr _channel_in3_node;
     SGPropertyNode_ptr _channel_in4_node;
 
-    SGPropertyNode_ptr _carrier_name_node;             // FIXME unused
-    SGPropertyNode_ptr _tanker_callsign_node;          // FIXME
-    SGPropertyNode_ptr _mp_callsign_node;              // FIXME
-
+    bool _was_disabled;
     bool _new_frequency;
     std::string _channel;
     double _last_distance_nm;
     double _frequency_mhz;
     double _time_before_search_sec;
 
-    bool _mobile_valid;
-    bool _transmitter_valid;
-
-    SGVec3d _transmitter;
-    SGGeod _transmitter_pos;
-    double _transmitter_range_nm;
-    double _transmitter_bias;
-    std::string _transmitter_name;
-    std::string _transmitter_ident;
-
-    SGGeod _mobilePos;
-    double _mobile_range_nm;
-    double _mobile_bias;
-    std::string _mobile_name;
-    std::string _mobile_ident;
+    FGNavRecordRef _active_station;
 
     int _listener_active;
 };
index 6a8dda5d0f7d397b77d3a5df5bf0fe9b18fe4cb0..bbd399032c1b3654a8cafc3b3e18f0bceabc673b 100644 (file)
@@ -716,10 +716,15 @@ public:
     PositionedID colocated = sqlite3_column_int64(loadNavaid, 4);
     reset(loadNavaid);
 
-    FGNavRecord* n = new FGNavRecord(rowId, ty, id, name, pos, freq, rangeNm, mulituse, runway);
-    if (colocated) {
-        n->setColocatedDME(colocated);
-    }
+    FGNavRecord* n =
+      (ty == FGPositioned::MOBILE_TACAN)
+      ? new FGMobileNavRecord
+            (rowId, ty, id, name, pos, freq, rangeNm, mulituse, runway)
+      : new FGNavRecord
+            (rowId, ty, id, name, pos, freq, rangeNm, mulituse, runway);
+
+    if (colocated)
+      n->setColocatedDME(colocated);
 
     return n;
   }
index 822391e04d79d38cd928566f07c4c023decce286..9b0c911dee50c44c274532495c78113a9252fb5d 100644 (file)
@@ -179,7 +179,7 @@ FGNavList::TypeFilter* FGNavList::tacanFilter()
   return &tf;
 }
 
-FGNavList::TypeFilter* FGNavList::carrierFilter()
+FGNavList::TypeFilter* FGNavList::mobileTacanFilter()
 {
   static TypeFilter tf(FGPositioned::MOBILE_TACAN);
   return &tf;
index d2db76cbf7d325803cb023836f758f8aaef5bbd3..c10b7e3b7d865079c5225436bdffe75073a8da2d 100644 (file)
@@ -86,7 +86,7 @@ public:
   static TypeFilter* tacanFilter();
   
   
-  static TypeFilter* carrierFilter();
+  static TypeFilter* mobileTacanFilter();
   
     /** Query the database for the specified station.  It is assumed
       * that there will be multiple stations with matching frequencies
index cb83fd02d189fbdb3794f8637ce338fdb152523a..bfc78f6326a2ce1453c7fafab8a53541f4dbc9c7 100644 (file)
@@ -109,6 +109,108 @@ void FGNavRecord::updateFromXML(const SGGeod& geod, double heading)
     multiuse = heading;
 }
 
+//------------------------------------------------------------------------------
+FGMobileNavRecord::FGMobileNavRecord( PositionedID aGuid,
+                                      Type type,
+                                      const std::string& ident,
+                                      const std::string& name,
+                                      const SGGeod& aPos,
+                                      int freq,
+                                      int range,
+                                      double multiuse,
+                                      PositionedID aRunway ):
+  FGNavRecord(aGuid, type, ident, name, aPos, freq, range, multiuse, aRunway)
+{
+
+}
+
+//------------------------------------------------------------------------------
+const SGGeod& FGMobileNavRecord::geod() const
+{
+  const_cast<FGMobileNavRecord*>(this)->updatePos();
+  return FGNavRecord::geod();
+}
+
+//------------------------------------------------------------------------------
+const SGVec3d& FGMobileNavRecord::cart() const
+{
+  const_cast<FGMobileNavRecord*>(this)->updatePos();
+  return FGNavRecord::cart();
+}
+
+//------------------------------------------------------------------------------
+void FGMobileNavRecord::updatePos()
+{
+  SGTimeStamp now = SGTimeStamp::now();
+  if( (now - _last_position_update).toSecs() < 1 )
+    return;
+  _last_position_update = now;
+
+  SGPropertyNode* ai_branch = fgGetNode("ai/models");
+  if( !ai_branch )
+  {
+    SG_LOG( SG_NAVAID,
+            SG_INFO,
+            "Can not update mobile navaid position (no ai/models branch)" );
+    return;
+  }
+
+  serviceable = true;
+  const std::string& nav_name = name();
+
+  // Try any aircraft carriers first
+  simgear::PropertyList carrier = ai_branch->getChildren("carrier");
+  for(size_t i = 0; i < carrier.size(); ++i)
+  {
+    const std::string carrier_name = carrier[i]->getStringValue("name");
+
+    if(    carrier_name.empty()
+        || nav_name.find(carrier_name) == std::string::npos )
+      continue;
+
+    modifyPosition(SGGeod::fromDegFt(
+      carrier[i]->getDoubleValue("position/longitude-deg"),
+      carrier[i]->getDoubleValue("position/latitude-deg"),
+      get_elev_ft()
+    ));
+    return;
+  }
+
+  // Now the tankers
+  const std::string tanker_branches[] = {
+    // AI tankers
+    "tanker",
+    // And finally mp tankers
+    "multiplayer"
+  };
+
+  for(size_t i = 0; i < sizeof(tanker_branches)/sizeof(tanker_branches[0]); ++i)
+  {
+    simgear::PropertyList tanker = ai_branch->getChildren(tanker_branches[i]);
+    for(size_t j = 0; j < tanker.size(); ++j)
+    {
+      const std::string callsign = tanker[j]->getStringValue("callsign");
+
+      if(    callsign.empty()
+          || nav_name.find(callsign) == std::string::npos )
+        continue;
+
+      modifyPosition(SGGeod::fromDegFt(
+        tanker[j]->getDoubleValue("position/longitude-deg"),
+        tanker[j]->getDoubleValue("position/latitude-deg"),
+        tanker[j]->getDoubleValue("position/altitude-ft")
+      ));
+      return;
+    }
+  }
+
+  // If no match was found set 'invalid' position (lat = lon = alt = 0)
+  modifyPosition(SGGeod());
+
+  // It's mobile but we do not know where it is...
+  serviceable = false;
+}
+
 FGTACANRecord::FGTACANRecord(void) :
     channel(""),
     freq(0)
index a96e171d85b1398a0135efac02f80886ba69d10c..f7400ba8f399c974774b30293fabfd747b9a0468 100644 (file)
@@ -30,6 +30,8 @@
 #include "positioned.hxx"
 #include <Airports/airports_fwd.hxx>
 
+#include <simgear/timing/timestamp.hxx>
+
 const double FG_NAV_DEFAULT_RANGE = 50; // nm
 const double FG_LOC_DEFAULT_RANGE = 18; // nm
 const double FG_DME_DEFAULT_RANGE = 50; // nm
@@ -44,18 +46,24 @@ class FGNavRecord : public FGPositioned
                                 // (degrees) or localizer heading
                                 // (degrees) or dme bias (nm)
 
-    std::string mName;                // verbose name in nav database
-    PositionedID mRunway;        // associated runway, if there is one
-    PositionedID mColocated;     // Colocated DME at a navaid (ILS, VOR, TACAN, NDB)
-    bool serviceable;          // for failure modeling
+    std::string mName;          // verbose name in nav database
+    PositionedID mRunway;       // associated runway, if there is one
+    PositionedID mColocated;    // Colocated DME at a navaid (ILS, VOR, TACAN, NDB)
+
+  protected:
+    mutable bool serviceable;   // for failure modeling
+
+  public:
+    FGNavRecord( PositionedID aGuid,
+                 Type type,
+                 const std::string& ident,
+                 const std::string& name,
+                 const SGGeod& aPos,
+                 int freq,
+                 int range,
+                 double multiuse,
+                 PositionedID aRunway );
 
-public:
-  FGNavRecord(PositionedID aGuid, Type type, const std::string& ident,
-              const std::string& name,
-              const SGGeod& aPos,
-              int freq, int range, double multiuse,
-              PositionedID aRunway);
-    
     inline double get_lon() const { return longitude(); } // degrees
     inline double get_lat() const { return latitude(); } // degrees
     inline double get_elev_ft() const { return elevation(); }
@@ -93,6 +101,33 @@ public:
     void updateFromXML(const SGGeod& geod, double heading);
 };
 
+/**
+ * A mobile navaid, aka. a navaid which can change its position (eg. a mobile
+ * TACAN)
+ */
+class FGMobileNavRecord:
+  public FGNavRecord
+{
+  public:
+    FGMobileNavRecord( PositionedID aGuid,
+                       Type type,
+                       const std::string& ident,
+                       const std::string& name,
+                       const SGGeod& aPos,
+                       int freq,
+                       int range,
+                       double multiuse,
+                       PositionedID aRunway );
+
+    virtual const SGGeod& geod() const;
+    virtual const SGVec3d& cart() const;
+
+    void updatePos();
+
+  protected:
+    SGTimeStamp _last_position_update;
+};
+
 class FGTACANRecord : public SGReferenced {
 
     std::string channel;               
index 8b4fb6a3f8c4b4c86e9816d9ed50677eb86efbb4..b0059c89bbba382f1e3f1fc6beab58af2b6c3944 100644 (file)
@@ -111,7 +111,7 @@ public:
   virtual const std::string& name() const
   { return mIdent; }
 
-  const SGGeod& geod() const
+  virtual const SGGeod& geod() const
   { return mPosition; }
   
   PositionedID guid() const
@@ -120,19 +120,19 @@ public:
   /**
    *  The cartesian position associated with this object
    */
-  const SGVec3d& cart() const;
+  virtual const SGVec3d& cart() const;
 
   double latitude() const
-  { return mPosition.getLatitudeDeg(); }
+  { return geod().getLatitudeDeg(); }
   
   double longitude() const
-  { return mPosition.getLongitudeDeg(); }
+  { return geod().getLongitudeDeg(); }
   
   double elevation() const
-  { return mPosition.getElevationFt(); }
+  { return geod().getElevationFt(); }
   
   double elevationM() const
-  { return mPosition.getElevationM(); }
+  { return geod().getElevationM(); }
 
   /**
    * Predicate class to support custom filtering of FGPositioned queries
@@ -280,13 +280,14 @@ protected:
   static FGPositionedRef loadByIdImpl(PositionedID id);
 
   const PositionedID mGuid;
-  const SGGeod mPosition;
-  const SGVec3d mCart;
   const Type mType;
   const std::string mIdent;
   
 private:
   SG_DISABLE_COPY(FGPositioned);
+
+  const SGGeod mPosition;
+  const SGVec3d mCart;
 };
 
 #endif // of FG_POSITIONED_HXX