* borderline reception.
*/
static double
-adjust_range (double transmitter_elevation_ft, double aircraft_altitude_ft,
- double max_range_nm)
+adjust_range( double station_elevation_ft,
+ double aircraft_altitude_ft,
+ double max_range_nm )
{
- 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);
- if (range_nm > max_range_nm)
- range_nm = max_range_nm;
- else if (range_nm < 20.0)
- range_nm = 20.0;
- double rand = sg_random();
- return range_nm + (range_nm * rand * rand);
+ // See http://en.wikipedia.org/wiki/Line-of-sight_propagation for approximate
+ // line-of-sight distance to the horizon
+
+ double range_nm = 0;
+ if( station_elevation_ft > 5 )
+ range_nm += 1.23 * sqrt(station_elevation_ft);
+
+ if( aircraft_altitude_ft > 5 )
+ range_nm += 1.23 * sqrt(aircraft_altitude_ft);
+
+ return std::max(20., std::min(range_nm, max_range_nm))
+ * (1 + SGMiscd::pow<2>(0.3 * sg_random()));
}
//------------------------------------------------------------------------------
_channel_in2_node->addChangeListener(this);
_channel_in3_node->addChangeListener(this);
_channel_in4_node->addChangeListener(this, true);
+
+ disabled(true);
}
//------------------------------------------------------------------------------
if( !_active_station || !_active_station->get_serviceable() )
return disabled();
+ const SGGeod& nav_pos = _active_station->geod();
+
// 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) )
+ if( !SGGeodesy::inverse(pos, nav_pos, bearing, az, distance) )
return disabled();
- double range_nm = adjust_range( _active_station->get_elev_ft(),
+ // Increase distance due to difference in altitude
+ distance =
+ sqrt( SGMiscd::pow<2>(distance)
+ + SGMiscd::pow<2>(pos.getElevationM() - nav_pos.getElevationM()) );
+ double distance_nm = distance * SG_METER_TO_NM;
+
+ double range_nm = adjust_range( nav_pos.getElevationFt(),
pos.getElevationFt(),
_active_station->get_range() );
- double distance_nm = distance * SG_METER_TO_NM;
-
if( distance_nm > range_nm )
return disabled();
}
//------------------------------------------------------------------------------
-void TACAN::disabled()
+void TACAN::disabled(bool force)
{
- if( _was_disabled )
+ if( _was_disabled && !force )
return;
_last_distance_nm = 0;
private:
- void disabled();
+ void disabled(bool force = false);
void search (double frequency, const SGGeod& pos);
double searchChannel (const std::string& channel);
if (isCachedFileModified(d->aptDatPath) ||
isCachedFileModified(d->metarDatPath) ||
isCachedFileModified(d->navDatPath) ||
+ isCachedFileModified(d->carrierDatPath) ||
isCachedFileModified(d->fixDatPath) ||
// since POI loading is disabled on Windows, don't check for it
// this caused: https://code.google.com/p/flightgear-bugs/issues/detail?id=1227
case FGPositioned::GS:
return FG_LOC_DEFAULT_RANGE;
- case FGPositioned::DME: return FG_DME_DEFAULT_RANGE;
- default: return FG_LOC_DEFAULT_RANGE;
+ case FGPositioned::DME:
+ return FG_DME_DEFAULT_RANGE;
+
+ case FGPositioned::TACAN:
+ case FGPositioned::MOBILE_TACAN:
+ return FG_TACAN_DEFAULT_RANGE;
+
+ default:
+ return FG_LOC_DEFAULT_RANGE;
}
}
int rawType;
aStream >> rawType;
- if (aStream.eof() || (rawType == 99)) {
+ if( aStream.eof() || (rawType == 99) || (rawType == 0) )
return 0; // happens with, eg, carrier_nav.dat
- }
double lat, lon, elev_ft, multiuse;
int freq, range;
SGGeod pos(SGGeod::fromDegFt(lon, lat, elev_ft));
name = simgear::strutils::strip(name);
-
+
// the type can be forced by our caller, but normally we use th value
// supplied in the .dat file
if (type == FGPositioned::INVALID) {
}
while ( ! incarrier.eof() ) {
+ incarrier >> skipcomment;
// force the type to be MOBILE_TACAN
readNavFromStream(incarrier, FGPositioned::MOBILE_TACAN);
- } // end while
+ }
return true;
}
: _vehicle_node->getDoubleValue("position/altitude-ft")
));
else
- // If no match was found set 'invalid' position (lat = lon = 0)
- modifyPosition(SGGeod());
+ invalidatePosition();
serviceable = _vehicle_node.valid();
}
const double FG_NAV_DEFAULT_RANGE = 50; // nm
const double FG_LOC_DEFAULT_RANGE = 18; // nm
const double FG_DME_DEFAULT_RANGE = 50; // nm
+const double FG_TACAN_DEFAULT_RANGE = 250; // nm
const double FG_NAV_MAX_RANGE = 300; // nm
class FGNavRecord : public FGPositioned
///////////////////////////////////////////////////////////////////////////////
-FGPositioned::FGPositioned(PositionedID aGuid, Type ty, const std::string& aIdent, const SGGeod& aPos) :
+FGPositioned::FGPositioned( PositionedID aGuid,
+ Type ty,
+ const std::string& aIdent,
+ const SGGeod& aPos ):
mGuid(aGuid),
- mPosition(aPos),
- mCart(SGVec3d::fromGeod(mPosition)),
mType(ty),
- mIdent(aIdent)
-{
+ mIdent(aIdent),
+ mPosition(aPos),
+ mCart(SGVec3d::fromGeod(mPosition))
+{
+
}
FGPositioned::~FGPositioned()
}
}
+//------------------------------------------------------------------------------
void FGPositioned::modifyPosition(const SGGeod& newPos)
{
const_cast<SGGeod&>(mPosition) = newPos;
const_cast<SGVec3d&>(mCart) = SGVec3d::fromGeod(newPos);
}
+//------------------------------------------------------------------------------
+void FGPositioned::invalidatePosition()
+{
+ const_cast<SGGeod&>(mPosition) = SGGeod::fromDeg(999,999);
+ const_cast<SGVec3d&>(mCart) = SGVec3d::zeros();
+}
+
//------------------------------------------------------------------------------
FGPositionedRef FGPositioned::loadByIdImpl(PositionedID id)
{
FGPositioned(PositionedID aGuid, Type ty, const std::string& aIdent, const SGGeod& aPos);
void modifyPosition(const SGGeod& newPos);
+ void invalidatePosition();
static FGPositionedRef loadByIdImpl(PositionedID id);