Work on FlightPlan VIA / discontinuity support.
Needed for realistic FMS route support.
This commit is contained in:
parent
a55c939c5e
commit
eaa147e3c2
9 changed files with 905 additions and 471 deletions
|
@ -50,6 +50,7 @@
|
|||
#include <Navaids/procedure.hxx>
|
||||
#include <Navaids/waypoint.hxx>
|
||||
#include <Navaids/routePath.hxx>
|
||||
#include <Navaids/airways.hxx>
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
@ -334,20 +335,6 @@ void FlightPlan::setCurrentIndex(int index)
|
|||
unlockDelegate();
|
||||
}
|
||||
|
||||
void FlightPlan::activate()
|
||||
{
|
||||
lockDelegate();
|
||||
|
||||
_currentIndex = 0;
|
||||
_currentWaypointChanged = true;
|
||||
|
||||
if (_delegate) {
|
||||
_delegate->runActivated();
|
||||
}
|
||||
|
||||
unlockDelegate();
|
||||
}
|
||||
|
||||
void FlightPlan::finish()
|
||||
{
|
||||
if (_currentIndex == -1) {
|
||||
|
@ -976,11 +963,88 @@ double FlightPlan::magvarDegAt(const SGGeod& pos) const
|
|||
return sgGetMagVar(pos, jd) * SG_RADIANS_TO_DEGREES;
|
||||
}
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
WayptRef intersectionFromString(FGPositionedRef p1,
|
||||
const SGGeod& basePosition,
|
||||
const double magvar,
|
||||
const string_list& pieces)
|
||||
{
|
||||
assert(pieces.size() == 4);
|
||||
// navid/radial/navid/radial notation
|
||||
FGPositionedRef p2 = FGPositioned::findClosestWithIdent(pieces[2], basePosition);
|
||||
if (!p2) {
|
||||
SG_LOG( SG_NAVAID, SG_INFO, "Unable to find FGPositioned with ident:" << pieces[2]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
double r1 = atof(pieces[1].c_str()),
|
||||
r2 = atof(pieces[3].c_str());
|
||||
r1 += magvar;
|
||||
r2 += magvar;
|
||||
|
||||
SGGeod intersection;
|
||||
bool ok = SGGeodesy::radialIntersection(p1->geod(), r1, p2->geod(), r2, intersection);
|
||||
if (!ok) {
|
||||
SG_LOG(SG_NAVAID, SG_INFO, "no valid intersection for:" << pieces[0]
|
||||
<< "/" << pieces[2]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
std::string name = p1->ident() + "-" + p2->ident();
|
||||
return new BasicWaypt(intersection, name, NULL);
|
||||
}
|
||||
|
||||
WayptRef wayptFromLonLatString(const std::string& target)
|
||||
{
|
||||
size_t pos = target.find( ',' );
|
||||
if ( pos == string::npos )
|
||||
return WayptRef();
|
||||
|
||||
double lon = atof( target.substr(0, pos).c_str());
|
||||
double lat = atof( target.c_str() + pos + 1);
|
||||
char buf[32];
|
||||
char ew = (lon < 0.0) ? 'W' : 'E';
|
||||
char ns = (lat < 0.0) ? 'S' : 'N';
|
||||
snprintf(buf, 32, "%c%03d%c%03d", ew, (int) fabs(lon), ns, (int)fabs(lat));
|
||||
|
||||
return new BasicWaypt(SGGeod::fromDeg(lon, lat), buf, NULL);
|
||||
}
|
||||
|
||||
WayptRef viaFromString(const SGGeod& basePosition, const std::string& target)
|
||||
{
|
||||
assert(target.find("VIA ") == 0);
|
||||
string_list pieces(simgear::strutils::split(target, "/"));
|
||||
if ((pieces.size() != 4) || (pieces[2] != "TO")) {
|
||||
SG_LOG( SG_NAVAID, SG_WARN, "Malformed VIA specification string:" << target);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// airway ident is pieces[1]
|
||||
Airway* airway = Airway::findByIdent(pieces[1]);
|
||||
if (airway == NULL) {
|
||||
SG_LOG( SG_NAVAID, SG_WARN, "Unknown airway:" << pieces[1]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// TO navaid is pieces[3]
|
||||
FGPositionedRef nav = FGPositioned::findClosestWithIdent(pieces[3], basePosition, NULL);
|
||||
if (!nav || !airway->containsNavaid(nav)) {
|
||||
SG_LOG( SG_NAVAID, SG_WARN, "TO navaid:" << pieces[3] << " unknown or not on airway");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Via* via = new Via(NULL, pieces[1], nav);
|
||||
return via;
|
||||
}
|
||||
|
||||
} // of anonymous namespace
|
||||
|
||||
WayptRef FlightPlan::waypointFromString(const string& tgt )
|
||||
{
|
||||
string target(boost::to_upper_copy(tgt));
|
||||
WayptRef wpt;
|
||||
|
||||
string target(boost::to_upper_copy(tgt));
|
||||
// extract altitude
|
||||
double altFt = 0.0;
|
||||
RouteRestriction altSetting = RESTRICT_NONE;
|
||||
|
@ -995,22 +1059,8 @@ WayptRef FlightPlan::waypointFromString(const string& tgt )
|
|||
}
|
||||
|
||||
// check for lon,lat
|
||||
pos = target.find( ',' );
|
||||
if ( pos != string::npos ) {
|
||||
double lon = atof( target.substr(0, pos).c_str());
|
||||
double lat = atof( target.c_str() + pos + 1);
|
||||
char buf[32];
|
||||
char ew = (lon < 0.0) ? 'W' : 'E';
|
||||
char ns = (lat < 0.0) ? 'S' : 'N';
|
||||
snprintf(buf, 32, "%c%03d%c%03d", ew, (int) fabs(lon), ns, (int)fabs(lat));
|
||||
|
||||
wpt = new BasicWaypt(SGGeod::fromDeg(lon, lat), buf, NULL);
|
||||
if (altSetting != RESTRICT_NONE) {
|
||||
wpt->setAltitude(altFt, altSetting);
|
||||
}
|
||||
return wpt;
|
||||
}
|
||||
|
||||
WayptRef wpt = wayptFromLonLatString(target);
|
||||
|
||||
SGGeod basePosition;
|
||||
if (_legs.empty()) {
|
||||
// route is empty, use current position
|
||||
|
@ -1019,59 +1069,45 @@ WayptRef FlightPlan::waypointFromString(const string& tgt )
|
|||
basePosition = _legs.back()->waypoint()->position();
|
||||
}
|
||||
|
||||
string_list pieces(simgear::strutils::split(target, "/"));
|
||||
FGPositionedRef p = FGPositioned::findClosestWithIdent(pieces.front(), basePosition);
|
||||
if (!p) {
|
||||
SG_LOG( SG_NAVAID, SG_INFO, "Unable to find FGPositioned with ident:" << pieces.front());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
double magvar = magvarDegAt(basePosition);
|
||||
|
||||
if (pieces.size() == 1) {
|
||||
wpt = new NavaidWaypoint(p, NULL);
|
||||
} else if (pieces.size() == 3) {
|
||||
// navaid/radial/distance-nm notation
|
||||
double radial = atof(pieces[1].c_str()),
|
||||
distanceNm = atof(pieces[2].c_str());
|
||||
radial += magvar;
|
||||
wpt = new OffsetNavaidWaypoint(p, NULL, radial, distanceNm);
|
||||
} else if (pieces.size() == 2) {
|
||||
FGAirport* apt = dynamic_cast<FGAirport*>(p.ptr());
|
||||
if (!apt) {
|
||||
SG_LOG(SG_NAVAID, SG_INFO, "Waypoint is not an airport:" << pieces.front());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!apt->hasRunwayWithIdent(pieces[1])) {
|
||||
SG_LOG(SG_NAVAID, SG_INFO, "No runway: " << pieces[1] << " at " << pieces[0]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FGRunway* runway = apt->getRunwayByIdent(pieces[1]);
|
||||
wpt = new NavaidWaypoint(runway, NULL);
|
||||
} else if (pieces.size() == 4) {
|
||||
// navid/radial/navid/radial notation
|
||||
FGPositionedRef p2 = FGPositioned::findClosestWithIdent(pieces[2], basePosition);
|
||||
if (!p2) {
|
||||
SG_LOG( SG_NAVAID, SG_INFO, "Unable to find FGPositioned with ident:" << pieces[2]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
double r1 = atof(pieces[1].c_str()),
|
||||
r2 = atof(pieces[3].c_str());
|
||||
r1 += magvar;
|
||||
r2 += magvar;
|
||||
|
||||
SGGeod intersection;
|
||||
bool ok = SGGeodesy::radialIntersection(p->geod(), r1, p2->geod(), r2, intersection);
|
||||
if (!ok) {
|
||||
SG_LOG(SG_NAVAID, SG_INFO, "no valid intersection for:" << target);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
std::string name = p->ident() + "-" + p2->ident();
|
||||
wpt = new BasicWaypt(intersection, name, NULL);
|
||||
const double magvar = magvarDegAt(basePosition);
|
||||
|
||||
if (wpt) {
|
||||
// already handled in the lat/lon test above
|
||||
} else if (target.find("VIA ") == 0) {
|
||||
wpt = viaFromString(basePosition, target);
|
||||
} else {
|
||||
string_list pieces(simgear::strutils::split(target, "/"));
|
||||
FGPositionedRef p = FGPositioned::findClosestWithIdent(pieces.front(), basePosition);
|
||||
if (!p) {
|
||||
SG_LOG( SG_NAVAID, SG_INFO, "Unable to find FGPositioned with ident:" << pieces.front());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pieces.size() == 1) {
|
||||
wpt = new NavaidWaypoint(p, NULL);
|
||||
} else if (pieces.size() == 3) {
|
||||
// navaid/radial/distance-nm notation
|
||||
double radial = atof(pieces[1].c_str()),
|
||||
distanceNm = atof(pieces[2].c_str());
|
||||
radial += magvar;
|
||||
wpt = new OffsetNavaidWaypoint(p, NULL, radial, distanceNm);
|
||||
} else if (pieces.size() == 2) {
|
||||
FGAirport* apt = dynamic_cast<FGAirport*>(p.ptr());
|
||||
if (!apt) {
|
||||
SG_LOG(SG_NAVAID, SG_INFO, "Waypoint is not an airport:" << pieces.front());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!apt->hasRunwayWithIdent(pieces[1])) {
|
||||
SG_LOG(SG_NAVAID, SG_INFO, "No runway: " << pieces[1] << " at " << pieces[0]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FGRunway* runway = apt->getRunwayByIdent(pieces[1]);
|
||||
wpt = new NavaidWaypoint(runway, NULL);
|
||||
} else if (pieces.size() == 4) {
|
||||
wpt = intersectionFromString(p, basePosition, magvar, pieces);
|
||||
}
|
||||
}
|
||||
|
||||
if (!wpt) {
|
||||
|
@ -1084,7 +1120,51 @@ WayptRef FlightPlan::waypointFromString(const string& tgt )
|
|||
}
|
||||
return wpt;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void FlightPlan::activate()
|
||||
{
|
||||
lockDelegate();
|
||||
|
||||
_currentIndex = 0;
|
||||
_currentWaypointChanged = true;
|
||||
|
||||
for (unsigned int i=0; i < _legs.size(); ) {
|
||||
if (_legs[i]->waypoint()->type() == "via") {
|
||||
WayptRef preceeding = _legs[i - 1]->waypoint();
|
||||
Via* via = static_cast<Via*>(_legs[i]->waypoint());
|
||||
WayptVec wps = via->expandToWaypoints(preceeding);
|
||||
|
||||
// delete the VIA leg
|
||||
LegVec::iterator it = _legs.begin();
|
||||
it += i;
|
||||
Leg* l = *it;
|
||||
_legs.erase(it);
|
||||
delete l;
|
||||
|
||||
// create new lefs and insert
|
||||
it = _legs.begin();
|
||||
it += i;
|
||||
|
||||
LegVec newLegs;
|
||||
BOOST_FOREACH(WayptRef wp, wps) {
|
||||
newLegs.push_back(new Leg(this, wp));
|
||||
}
|
||||
|
||||
_waypointsChanged = true;
|
||||
_legs.insert(it, newLegs.begin(), newLegs.end());
|
||||
} else {
|
||||
++i; // normal case, no expansion
|
||||
}
|
||||
}
|
||||
|
||||
if (_delegate) {
|
||||
_delegate->runActivated();
|
||||
}
|
||||
|
||||
unlockDelegate();
|
||||
}
|
||||
|
||||
FlightPlan::Leg::Leg(FlightPlan* owner, WayptRef wpt) :
|
||||
_parent(owner),
|
||||
_speedRestrict(RESTRICT_NONE),
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* FlightPlan.hxx - defines a full flight-plan object, including
|
||||
* departure, cruise, arrival information and waypoints
|
||||
*/
|
||||
|
||||
|
||||
// Written by James Turner, started 2012.
|
||||
//
|
||||
// Copyright (C) 2012 James Turner
|
||||
|
@ -32,7 +32,7 @@ namespace flightgear
|
|||
|
||||
class Transition;
|
||||
class FlightPlan;
|
||||
|
||||
|
||||
typedef SGSharedPtr<FlightPlan> FlightPlanRef;
|
||||
|
||||
const char ICAO_AIRCRAFT_CATEGORY_A = 'A';
|
||||
|
@ -46,7 +46,7 @@ class FlightPlan : public RouteBase
|
|||
public:
|
||||
FlightPlan();
|
||||
virtual ~FlightPlan();
|
||||
|
||||
|
||||
virtual std::string ident() const;
|
||||
void setIdent(const std::string& s);
|
||||
|
||||
|
@ -60,7 +60,7 @@ public:
|
|||
void setIcaoAircraftCategory(const std::string& cat);
|
||||
|
||||
FlightPlan* clone(const std::string& newIdent = std::string()) const;
|
||||
|
||||
|
||||
/**
|
||||
* flight-plan leg encapsulation
|
||||
*/
|
||||
|
@ -69,37 +69,37 @@ public:
|
|||
public:
|
||||
FlightPlan* owner() const
|
||||
{ return _parent; }
|
||||
|
||||
|
||||
Waypt* waypoint() const
|
||||
{ return _waypt; }
|
||||
|
||||
|
||||
// reutrn the next leg after this one
|
||||
Leg* nextLeg() const;
|
||||
|
||||
|
||||
unsigned int index() const;
|
||||
|
||||
int altitudeFt() const;
|
||||
|
||||
int altitudeFt() const;
|
||||
int speed() const;
|
||||
|
||||
|
||||
int speedKts() const;
|
||||
double speedMach() const;
|
||||
|
||||
RouteRestriction altitudeRestriction() const;
|
||||
|
||||
RouteRestriction altitudeRestriction() const;
|
||||
RouteRestriction speedRestriction() const;
|
||||
|
||||
|
||||
void setSpeed(RouteRestriction ty, double speed);
|
||||
void setAltitude(RouteRestriction ty, int altFt);
|
||||
|
||||
|
||||
double courseDeg() const;
|
||||
double distanceNm() const;
|
||||
double distanceAlongRoute() const;
|
||||
private:
|
||||
friend class FlightPlan;
|
||||
|
||||
|
||||
Leg(FlightPlan* owner, WayptRef wpt);
|
||||
|
||||
|
||||
Leg* cloneFor(FlightPlan* owner) const;
|
||||
|
||||
|
||||
FlightPlan* _parent;
|
||||
RouteRestriction _speedRestrict, _altRestrict;
|
||||
int _speed;
|
||||
|
@ -109,14 +109,14 @@ public:
|
|||
mutable double _pathDistance;
|
||||
mutable double _courseDeg;
|
||||
/// total distance of this leg from departure point
|
||||
mutable double _distanceAlongPath;
|
||||
mutable double _distanceAlongPath;
|
||||
};
|
||||
|
||||
|
||||
class Delegate
|
||||
{
|
||||
public:
|
||||
virtual ~Delegate();
|
||||
|
||||
|
||||
virtual void departureChanged() { }
|
||||
virtual void arrivalChanged() { }
|
||||
virtual void waypointsChanged() { }
|
||||
|
@ -126,10 +126,10 @@ public:
|
|||
virtual void endOfFlightPlan() { }
|
||||
protected:
|
||||
Delegate();
|
||||
|
||||
|
||||
private:
|
||||
void removeInner(Delegate* d);
|
||||
|
||||
|
||||
void runDepartureChanged();
|
||||
void runArrivalChanged();
|
||||
void runWaypointsChanged();
|
||||
|
@ -139,98 +139,98 @@ public:
|
|||
void runActivated();
|
||||
|
||||
friend class FlightPlan;
|
||||
|
||||
|
||||
bool _deleteWithPlan;
|
||||
Delegate* _inner;
|
||||
};
|
||||
|
||||
|
||||
Leg* insertWayptAtIndex(Waypt* aWpt, int aIndex);
|
||||
void insertWayptsAtIndex(const WayptVec& wps, int aIndex);
|
||||
|
||||
|
||||
void deleteIndex(int index);
|
||||
void clear();
|
||||
int clearWayptsWithFlag(WayptFlag flag);
|
||||
|
||||
|
||||
int currentIndex() const
|
||||
{ return _currentIndex; }
|
||||
|
||||
|
||||
void setCurrentIndex(int index);
|
||||
|
||||
void activate();
|
||||
|
||||
void finish();
|
||||
|
||||
|
||||
Leg* currentLeg() const;
|
||||
Leg* nextLeg() const;
|
||||
Leg* previousLeg() const;
|
||||
|
||||
|
||||
int numLegs() const
|
||||
{ return _legs.size(); }
|
||||
|
||||
|
||||
Leg* legAtIndex(int index) const;
|
||||
int findLegIndex(const Leg* l) const;
|
||||
|
||||
|
||||
int findWayptIndex(const SGGeod& aPos) const;
|
||||
int findWayptIndex(const FGPositionedRef aPos) const;
|
||||
|
||||
|
||||
bool load(const SGPath& p);
|
||||
bool save(const SGPath& p);
|
||||
|
||||
|
||||
FGAirportRef departureAirport() const
|
||||
{ return _departure; }
|
||||
|
||||
|
||||
FGAirportRef destinationAirport() const
|
||||
{ return _destination; }
|
||||
|
||||
|
||||
FGRunway* departureRunway() const
|
||||
{ return _departureRunway; }
|
||||
|
||||
|
||||
FGRunway* destinationRunway() const
|
||||
{ return _destinationRunway; }
|
||||
|
||||
|
||||
Approach* approach() const
|
||||
{ return _approach; }
|
||||
|
||||
|
||||
void setDeparture(FGAirport* apt);
|
||||
void setDeparture(FGRunway* rwy);
|
||||
|
||||
|
||||
SID* sid() const
|
||||
{ return _sid; }
|
||||
|
||||
|
||||
Transition* sidTransition() const;
|
||||
|
||||
|
||||
void setSID(SID* sid, const std::string& transition = std::string());
|
||||
|
||||
|
||||
void setSID(Transition* sidWithTrans);
|
||||
|
||||
|
||||
void setDestination(FGAirport* apt);
|
||||
void setDestination(FGRunway* rwy);
|
||||
|
||||
|
||||
/**
|
||||
* note setting an approach will implicitly update the destination
|
||||
* airport and runway to match
|
||||
*/
|
||||
void setApproach(Approach* app);
|
||||
|
||||
|
||||
STAR* star() const
|
||||
{ return _star; }
|
||||
|
||||
|
||||
Transition* starTransition() const;
|
||||
|
||||
|
||||
void setSTAR(STAR* star, const std::string& transition = std::string());
|
||||
|
||||
|
||||
void setSTAR(Transition* starWithTrans);
|
||||
|
||||
|
||||
double totalDistanceNm() const
|
||||
{ return _totalDistance; }
|
||||
|
||||
|
||||
/**
|
||||
* given a waypoint index, and an offset in NM, find the geodetic
|
||||
* position on the route path. I.e the point 10nm before or after
|
||||
* a particular waypoint.
|
||||
*/
|
||||
SGGeod pointAlongRoute(int aIndex, double aOffsetNm) const;
|
||||
|
||||
|
||||
/**
|
||||
* Create a WayPoint from a string in the following format:
|
||||
* - simple identifier
|
||||
|
@ -239,7 +239,7 @@ public:
|
|||
* - navaid/radial-deg/offset-nm
|
||||
*/
|
||||
WayptRef waypointFromString(const std::string& target);
|
||||
|
||||
|
||||
/**
|
||||
* abstract interface for creating delegates automatically when a
|
||||
* flight-plan is created or loaded
|
||||
|
@ -249,33 +249,33 @@ public:
|
|||
public:
|
||||
virtual Delegate* createFlightPlanDelegate(FlightPlan* fp) = 0;
|
||||
};
|
||||
|
||||
|
||||
static void registerDelegateFactory(DelegateFactory* df);
|
||||
static void unregisterDelegateFactory(DelegateFactory* df);
|
||||
|
||||
|
||||
void addDelegate(Delegate* d);
|
||||
void removeDelegate(Delegate* d);
|
||||
private:
|
||||
void lockDelegate();
|
||||
void unlockDelegate();
|
||||
|
||||
|
||||
int _delegateLock;
|
||||
bool _arrivalChanged,
|
||||
_departureChanged,
|
||||
_waypointsChanged,
|
||||
bool _arrivalChanged,
|
||||
_departureChanged,
|
||||
_waypointsChanged,
|
||||
_currentWaypointChanged;
|
||||
|
||||
|
||||
bool loadXmlFormat(const SGPath& path);
|
||||
bool loadGpxFormat(const SGPath& path);
|
||||
bool loadPlainTextFormat(const SGPath& path);
|
||||
|
||||
|
||||
void loadVersion1XMLRoute(SGPropertyNode_ptr routeData);
|
||||
void loadVersion2XMLRoute(SGPropertyNode_ptr routeData);
|
||||
void loadXMLRouteHeader(SGPropertyNode_ptr routeData);
|
||||
WayptRef parseVersion1XMLWaypt(SGPropertyNode* aWP);
|
||||
|
||||
|
||||
double magvarDegAt(const SGGeod& pos) const;
|
||||
|
||||
|
||||
std::string _ident;
|
||||
int _currentIndex;
|
||||
bool _followLegTrackToFix;
|
||||
|
@ -287,16 +287,16 @@ private:
|
|||
SGSharedPtr<STAR> _star;
|
||||
SGSharedPtr<Approach> _approach;
|
||||
std::string _sidTransition, _starTransition;
|
||||
|
||||
|
||||
double _totalDistance;
|
||||
void rebuildLegData();
|
||||
|
||||
|
||||
typedef std::vector<Leg*> LegVec;
|
||||
LegVec _legs;
|
||||
|
||||
|
||||
Delegate* _delegate;
|
||||
};
|
||||
|
||||
|
||||
} // of namespace flightgear
|
||||
|
||||
#endif // of FG_FLIGHTPLAN_HXX
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -2,7 +2,7 @@
|
|||
* NavDataCache.hxx - defines a unified binary cache for navigation
|
||||
* data, parsed from various text / XML sources.
|
||||
*/
|
||||
|
||||
|
||||
// Written by James Turner, started 2012.
|
||||
//
|
||||
// Copyright (C) 2012 James Turner
|
||||
|
@ -28,33 +28,33 @@
|
|||
|
||||
#include <simgear/misc/strutils.hxx> // for string_list
|
||||
#include <Navaids/positioned.hxx>
|
||||
|
||||
|
||||
class SGPath;
|
||||
class FGRunway;
|
||||
|
||||
namespace flightgear
|
||||
{
|
||||
|
||||
|
||||
/// a pair of airport ID, runway ID
|
||||
typedef std::pair<PositionedID, PositionedID> AirportRunwayPair;
|
||||
|
||||
|
||||
typedef std::pair<FGPositioned::Type, PositionedID> TypedPositioned;
|
||||
typedef std::vector<TypedPositioned> TypedPositionedVec;
|
||||
|
||||
// pair of airway ID, destination node ID
|
||||
typedef std::pair<int, PositionedID> AirwayEdge;
|
||||
typedef std::vector<AirwayEdge> AirwayEdgeVec;
|
||||
|
||||
|
||||
namespace Octree {
|
||||
class Node;
|
||||
class Branch;
|
||||
}
|
||||
|
||||
|
||||
class NavDataCache
|
||||
{
|
||||
public:
|
||||
~NavDataCache();
|
||||
|
||||
|
||||
// singleton accessor
|
||||
static NavDataCache* instance();
|
||||
|
||||
|
@ -62,7 +62,7 @@ public:
|
|||
static NavDataCache* createInstance();
|
||||
|
||||
SGPath path() const;
|
||||
|
||||
|
||||
/**
|
||||
* predicate - check if the cache needs to be rebuilt.
|
||||
* This can happen is the cache file is missing or damaged, or one of the
|
||||
|
@ -90,25 +90,25 @@ public:
|
|||
|
||||
bool isCachedFileModified(const SGPath& path) const;
|
||||
void stampCacheFile(const SGPath& path);
|
||||
|
||||
|
||||
int readIntProperty(const std::string& key);
|
||||
double readDoubleProperty(const std::string& key);
|
||||
std::string readStringProperty(const std::string& key);
|
||||
|
||||
|
||||
void writeIntProperty(const std::string& key, int value);
|
||||
void writeStringProperty(const std::string& key, const std::string& value);
|
||||
void writeDoubleProperty(const std::string& key, const double& value);
|
||||
|
||||
|
||||
string_list readStringListProperty(const std::string& key);
|
||||
void writeStringListProperty(const std::string& key, const string_list& values);
|
||||
|
||||
|
||||
/**
|
||||
* retrieve an FGPositioned from the cache.
|
||||
* This may be trivial if the object is previously loaded, or require actual
|
||||
* disk IO.
|
||||
*/
|
||||
FGPositionedRef loadById(PositionedID guid);
|
||||
|
||||
|
||||
PositionedID insertAirport(FGPositioned::Type ty, const std::string& ident,
|
||||
const std::string& name);
|
||||
void insertTower(PositionedID airportId, const SGGeod& pos);
|
||||
|
@ -118,42 +118,42 @@ public:
|
|||
double stopway, int surfaceCode);
|
||||
void setRunwayReciprocal(PositionedID runway, PositionedID recip);
|
||||
void setRunwayILS(PositionedID runway, PositionedID ils);
|
||||
|
||||
|
||||
PositionedID insertNavaid(FGPositioned::Type ty, const std::string& ident,
|
||||
const std::string& name, const SGGeod& pos, int freq, int range, double multiuse,
|
||||
PositionedID apt, PositionedID runway);
|
||||
|
||||
// Assign colocated DME to a navaid
|
||||
void setNavaidColocated(PositionedID navaid, PositionedID colocatedDME);
|
||||
|
||||
|
||||
PositionedID insertCommStation(FGPositioned::Type ty,
|
||||
const std::string& name, const SGGeod& pos, int freq, int range,
|
||||
PositionedID apt);
|
||||
PositionedID insertFix(const std::string& ident, const SGGeod& aPos);
|
||||
|
||||
|
||||
PositionedID createPOI(FGPositioned::Type ty, const std::string& ident, const SGGeod& aPos);
|
||||
|
||||
|
||||
bool removePOI(FGPositioned::Type ty, const std::string& aIdent);
|
||||
|
||||
|
||||
/// update the metar flag associated with an airport
|
||||
void setAirportMetar(const std::string& icao, bool hasMetar);
|
||||
|
||||
|
||||
/**
|
||||
* Modify the position of an existing item.
|
||||
*/
|
||||
void updatePosition(PositionedID item, const SGGeod &pos);
|
||||
|
||||
|
||||
FGPositionedList findAllWithIdent( const std::string& ident,
|
||||
FGPositioned::Filter* filter,
|
||||
bool exact );
|
||||
FGPositionedList findAllWithName( const std::string& ident,
|
||||
FGPositioned::Filter* filter,
|
||||
bool exact );
|
||||
|
||||
|
||||
FGPositionedRef findClosestWithIdent( const std::string& aIdent,
|
||||
const SGGeod& aPos,
|
||||
FGPositioned::Filter* aFilter );
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Helper to implement the AirportSearch widget. Optimised text search of
|
||||
|
@ -161,35 +161,35 @@ public:
|
|||
* to PLIB.
|
||||
*/
|
||||
char** searchAirportNamesAndIdents(const std::string& aFilter);
|
||||
|
||||
|
||||
/**
|
||||
* Find the closest matching comm-station on a frequency, to a position.
|
||||
* The filter with be used for both type ranging and to validate the result
|
||||
* candidates.
|
||||
*/
|
||||
FGPositionedRef findCommByFreq(int freqKhz, const SGGeod& pos, FGPositioned::Filter* filt);
|
||||
|
||||
|
||||
/**
|
||||
* find all items of a specified type (or range of types) at an airport
|
||||
*/
|
||||
PositionedIDVec airportItemsOfType(PositionedID apt, FGPositioned::Type ty,
|
||||
FGPositioned::Type maxTy = FGPositioned::INVALID);
|
||||
|
||||
|
||||
/**
|
||||
* find the first match item of the specified type and ident, at an airport
|
||||
*/
|
||||
PositionedID airportItemWithIdent(PositionedID apt, FGPositioned::Type ty, const std::string& ident);
|
||||
|
||||
|
||||
/**
|
||||
* Find all navaids matching a particular frequency, sorted by range from the
|
||||
* supplied position. Type-range will be determined from the filter
|
||||
*/
|
||||
PositionedIDVec findNavaidsByFreq(int freqKhz, const SGGeod& pos, FGPositioned::Filter* filt);
|
||||
|
||||
|
||||
/// overload version of the above that does not consider positioned when
|
||||
/// returning results. Only used by TACAN carrier search
|
||||
PositionedIDVec findNavaidsByFreq(int freqKhz, FGPositioned::Filter* filt);
|
||||
|
||||
|
||||
/**
|
||||
* Given a runway and type, find the corresponding navaid (ILS / GS / OM)
|
||||
*/
|
||||
|
@ -201,30 +201,30 @@ public:
|
|||
* Such names look like: 'LHBP 31L DME-ILS' or 'UEEE 23L MM'
|
||||
*/
|
||||
AirportRunwayPair findAirportRunway(const std::string& name);
|
||||
|
||||
|
||||
/**
|
||||
* Given an aiport, and runway and ILS identifier, find the corresponding cache
|
||||
* entry. This matches the data we get in the ils.xml files for airports.
|
||||
*/
|
||||
PositionedID findILS(PositionedID airport, const std::string& runway, const std::string& navIdent);
|
||||
|
||||
|
||||
/**
|
||||
* Given an Octree node ID, return a bit-mask defining which of the child
|
||||
* nodes exist. In practice this means an 8-bit value be sufficent, but
|
||||
* an int works fine too.
|
||||
*/
|
||||
int getOctreeBranchChildren(int64_t octreeNodeId);
|
||||
|
||||
|
||||
void defineOctreeNode(Octree::Branch* pr, Octree::Node* nd);
|
||||
|
||||
|
||||
/**
|
||||
* given an octree leaf, return all its child positioned items and their types
|
||||
*/
|
||||
TypedPositionedVec getOctreeLeafChildren(int64_t octreeNodeId);
|
||||
|
||||
|
||||
// airways
|
||||
int findAirway(int network, const std::string& aName);
|
||||
|
||||
|
||||
/**
|
||||
* insert an edge between two positioned nodes, into the network.
|
||||
* The airway identifier will be set accordingly. No reverse edge is created
|
||||
|
@ -232,28 +232,33 @@ public:
|
|||
* created.
|
||||
*/
|
||||
void insertEdge(int network, int airwayID, PositionedID from, PositionedID to);
|
||||
|
||||
|
||||
/// is the specified positioned a node on the network?
|
||||
bool isInAirwayNetwork(int network, PositionedID pos);
|
||||
|
||||
|
||||
/**
|
||||
* retrive all the destination points reachcable from a positioned
|
||||
* in an airway
|
||||
*/
|
||||
AirwayEdgeVec airwayEdgesFrom(int network, PositionedID pos);
|
||||
|
||||
|
||||
/**
|
||||
* Waypoints on the airway
|
||||
*/
|
||||
PositionedIDVec airwayWaypts(int id);
|
||||
|
||||
class Transaction
|
||||
{
|
||||
public:
|
||||
Transaction(NavDataCache* cache);
|
||||
~Transaction();
|
||||
|
||||
|
||||
void commit();
|
||||
private:
|
||||
NavDataCache* _instance;
|
||||
bool _committed;
|
||||
};
|
||||
|
||||
|
||||
bool isReadOnly() const;
|
||||
|
||||
class ThreadedGUISearch
|
||||
|
@ -261,7 +266,7 @@ public:
|
|||
public:
|
||||
ThreadedGUISearch(const std::string& term);
|
||||
~ThreadedGUISearch();
|
||||
|
||||
|
||||
PositionedIDVec results() const;
|
||||
|
||||
bool isComplete() const;
|
||||
|
@ -271,21 +276,20 @@ public:
|
|||
};
|
||||
private:
|
||||
NavDataCache();
|
||||
|
||||
|
||||
friend class RebuildThread;
|
||||
void doRebuild();
|
||||
|
||||
|
||||
friend class Transaction;
|
||||
|
||||
|
||||
void beginTransaction();
|
||||
void commitTransaction();
|
||||
void abortTransaction();
|
||||
|
||||
|
||||
class NavDataCachePrivate;
|
||||
std::auto_ptr<NavDataCachePrivate> d;
|
||||
std::auto_ptr<NavDataCachePrivate> d;
|
||||
};
|
||||
|
||||
|
||||
} // of namespace flightgear
|
||||
|
||||
#endif // of FG_NAVDATACACHE_HXX
|
||||
|
||||
|
|
|
@ -161,11 +161,106 @@ void Airway::load(const SGPath& path)
|
|||
} // of file line iteration
|
||||
}
|
||||
|
||||
WayptVec::const_iterator Airway::find(WayptRef wpt) const
|
||||
{
|
||||
WayptVec::const_iterator it;
|
||||
for (it = _elements.begin(); it != _elements.end(); ++it) {
|
||||
if (wpt->matches(*it)) {
|
||||
return it;
|
||||
}
|
||||
}
|
||||
|
||||
return it;
|
||||
}
|
||||
|
||||
bool Airway::canVia(const WayptRef& from, const WayptRef& to) const
|
||||
{
|
||||
WayptVec::const_iterator fit = find(from);
|
||||
WayptVec::const_iterator tit = find(to);
|
||||
|
||||
if ((fit == _elements.end()) || (tit == _elements.end())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
WayptVec Airway::via(const WayptRef& from, const WayptRef& to) const
|
||||
{
|
||||
WayptVec v;
|
||||
WayptVec::const_iterator fit = find(from);
|
||||
WayptVec::const_iterator tit = find(to);
|
||||
|
||||
if ((fit == _elements.end()) || (tit == _elements.end())) {
|
||||
throw sg_exception("bad VIA transition points");
|
||||
}
|
||||
|
||||
if (fit == tit) {
|
||||
// will cause duplicate point but that seems better than
|
||||
// return an empty
|
||||
v.push_back(*tit);
|
||||
return v;
|
||||
}
|
||||
|
||||
// establish the ordering of the transitions, i.e are we moving forward or
|
||||
// backard along the airway.
|
||||
if (fit < tit) {
|
||||
// forward progression
|
||||
for (++fit; fit != tit; ++fit) {
|
||||
v.push_back(*fit);
|
||||
}
|
||||
} else {
|
||||
// reverse progression
|
||||
for (--fit; fit != tit; --fit) {
|
||||
v.push_back(*fit);
|
||||
}
|
||||
}
|
||||
|
||||
v.push_back(*tit);
|
||||
return v;
|
||||
}
|
||||
|
||||
bool Airway::containsNavaid(const FGPositionedRef &navaid) const
|
||||
{
|
||||
return find(new NavaidWaypoint(navaid, NULL)) != _elements.end();
|
||||
}
|
||||
|
||||
int Airway::Network::findAirway(const std::string& aName, double aTop, double aBase)
|
||||
{
|
||||
return NavDataCache::instance()->findAirway(_networkID, aName);
|
||||
}
|
||||
|
||||
Airway* Airway::findByIdent(const std::string& aIdent)
|
||||
{
|
||||
NavDataCache* ndc = NavDataCache::instance();
|
||||
|
||||
int id = ndc->findAirway(0, aIdent);
|
||||
|
||||
PositionedIDVec pts = ndc->airwayWaypts(id);
|
||||
Airway* awy = new Airway(aIdent, 0, 0);
|
||||
|
||||
PositionedIDVec::const_iterator it;
|
||||
for (it = pts.begin(); it != pts.end(); ++it) {
|
||||
FGPositionedRef pos = ndc->loadById(*it);
|
||||
WayptRef w = new NavaidWaypoint(pos, NULL);
|
||||
awy->_elements.push_back(w);
|
||||
}
|
||||
|
||||
return awy;
|
||||
}
|
||||
|
||||
WayptRef Airway::findEnroute(const std::string &aIdent) const
|
||||
{
|
||||
WayptVec::const_iterator it;
|
||||
for (it = _elements.begin(); it != _elements.end(); ++it) {
|
||||
if ((*it)->ident() == aIdent) {
|
||||
return *it;
|
||||
}
|
||||
}
|
||||
|
||||
return WayptRef();
|
||||
}
|
||||
|
||||
void Airway::Network::addEdge(int aWay, const SGGeod& aStartPos,
|
||||
const std::string& aStartIdent,
|
||||
const SGGeod& aEndPos, const std::string& aEndIdent)
|
||||
|
|
|
@ -49,7 +49,17 @@ public:
|
|||
|
||||
double bottomAltitudeFt() const
|
||||
{ return _bottomAltitudeFt; }
|
||||
|
||||
|
||||
static Airway* findByIdent(const std::string& aIdent);
|
||||
|
||||
WayptRef findEnroute(const std::string& aIdent) const;
|
||||
|
||||
bool canVia(const WayptRef& from, const WayptRef& to) const;
|
||||
|
||||
WayptVec via(const WayptRef& from, const WayptRef& to) const;
|
||||
|
||||
bool containsNavaid(const FGPositionedRef& navaid) const;
|
||||
|
||||
/**
|
||||
* Track a network of airways
|
||||
*
|
||||
|
@ -70,6 +80,8 @@ public:
|
|||
* Returns true if a route could be found, or false otherwise.
|
||||
*/
|
||||
bool route(WayptRef aFrom, WayptRef aTo, WayptVec& aPath);
|
||||
|
||||
|
||||
private:
|
||||
void addEdge(int aWay, const SGGeod& aStartPos,
|
||||
const std::string& aStartIdent,
|
||||
|
@ -123,6 +135,8 @@ public:
|
|||
private:
|
||||
Airway(const std::string& aIdent, double aTop, double aBottom);
|
||||
|
||||
WayptVec::const_iterator find(WayptRef wpt) const;
|
||||
|
||||
friend class Network;
|
||||
|
||||
std::string _ident;
|
||||
|
|
|
@ -212,7 +212,11 @@ Waypt* Waypt::createInstance(RouteBase* aOwner, const std::string& aTypeName)
|
|||
r = new RadialIntercept(aOwner);
|
||||
} else if (aTypeName == "vectors") {
|
||||
r = new ATCVectors(aOwner);
|
||||
}
|
||||
} else if (aTypeName == "discontinuity") {
|
||||
r = new Discontinuity(aOwner);
|
||||
} else if (aTypeName == "via") {
|
||||
r = new Via(aOwner);
|
||||
}
|
||||
|
||||
if (!r || (r->type() != aTypeName)) {
|
||||
throw sg_exception("broken factory method for type:" + aTypeName,
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
#include <Airports/airport.hxx>
|
||||
#include <Airports/runways.hxx>
|
||||
#include <Navaids/airways.hxx>
|
||||
|
||||
using std::string;
|
||||
|
||||
|
@ -465,4 +466,121 @@ void ATCVectors::writeToProperties(SGPropertyNode_ptr aProp) const
|
|||
aProp->setStringValue("icao", _facility->ident());
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Discontinuity::Discontinuity(RouteBase* aOwner) :
|
||||
Waypt(aOwner)
|
||||
{
|
||||
setFlag(WPT_DYNAMIC);
|
||||
setFlag(WPT_GENERATED); // prevent drag, delete, etc
|
||||
}
|
||||
|
||||
Discontinuity::~Discontinuity()
|
||||
{
|
||||
}
|
||||
|
||||
SGGeod Discontinuity::position() const
|
||||
{
|
||||
return SGGeod(); // deliberately invalid of course
|
||||
}
|
||||
|
||||
string Discontinuity::ident() const
|
||||
{
|
||||
return "DISCONTINUITY";
|
||||
}
|
||||
|
||||
void Discontinuity::initFromProperties(SGPropertyNode_ptr aProp)
|
||||
{
|
||||
}
|
||||
|
||||
void Discontinuity::writeToProperties(SGPropertyNode_ptr aProp) const
|
||||
{
|
||||
Waypt::writeToProperties(aProp);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SGGeod Via::position() const
|
||||
{
|
||||
return _to->geod();
|
||||
}
|
||||
|
||||
string Via::ident() const
|
||||
{
|
||||
return "VIA " + _airway + " TO " + _to->ident();
|
||||
}
|
||||
|
||||
Via::Via(RouteBase *aOwner) :
|
||||
Waypt(aOwner)
|
||||
{
|
||||
}
|
||||
|
||||
Via::Via(RouteBase *aOwner, const std::string &airwayName, FGPositioned *to) :
|
||||
Waypt(aOwner),
|
||||
_airway(airwayName),
|
||||
_to(to)
|
||||
{
|
||||
}
|
||||
|
||||
Via::~Via()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Via::initFromProperties(SGPropertyNode_ptr aProp)
|
||||
{
|
||||
if (!aProp->hasChild("airway") || !aProp->hasChild("to")) {
|
||||
throw sg_io_exception("missing airway/to propertie",
|
||||
"Via::initFromProperties");
|
||||
}
|
||||
|
||||
Waypt::initFromProperties(aProp);
|
||||
|
||||
_airway = aProp->getStringValue("airway");
|
||||
Airway* way = Airway::findByIdent(_airway);
|
||||
if (!way) {
|
||||
throw sg_io_exception("unknown airway idnet: '" + _airway + "'",
|
||||
"Via::initFromProperties");
|
||||
}
|
||||
|
||||
std::string idn(aProp->getStringValue("to"));
|
||||
SGGeod p;
|
||||
if (aProp->hasChild("lon")) {
|
||||
p = SGGeod::fromDeg(aProp->getDoubleValue("lon"),
|
||||
aProp->getDoubleValue("lat"));
|
||||
}
|
||||
|
||||
FGPositionedRef nav = FGPositioned::findClosestWithIdent(idn, p, NULL);
|
||||
if (!nav) {
|
||||
throw sg_io_exception("unknown navaid ident:" + idn,
|
||||
"Via::initFromProperties");
|
||||
}
|
||||
|
||||
_to = nav;
|
||||
}
|
||||
|
||||
void Via::writeToProperties(SGPropertyNode_ptr aProp) const
|
||||
{
|
||||
Waypt::writeToProperties(aProp);
|
||||
aProp->setStringValue("airway", _airway);
|
||||
aProp->setStringValue("to", _to->ident());
|
||||
// write lon/lat to disambiguate
|
||||
aProp->setDoubleValue("lon", _to->geod().getLongitudeDeg());
|
||||
aProp->setDoubleValue("lat", _to->geod().getLatitudeDeg());
|
||||
}
|
||||
|
||||
WayptVec Via::expandToWaypoints(WayptRef aPreceeding) const
|
||||
{
|
||||
if (!aPreceeding) {
|
||||
throw sg_exception("invalid preceeding waypoint");
|
||||
}
|
||||
|
||||
Airway* way = Airway::findByIdent(_airway);
|
||||
if (!way) {
|
||||
throw sg_exception("invalid airway");
|
||||
}
|
||||
|
||||
return way->via(aPreceeding, new NavaidWaypoint(_to, owner()));
|
||||
}
|
||||
|
||||
} // of namespace
|
||||
|
|
|
@ -312,7 +312,55 @@ private:
|
|||
* suffices until we have a proper facility representation
|
||||
*/
|
||||
FGAirportRef _facility;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Represent a route discontinuity. These can occur while editing
|
||||
* plans via certain interfaces (such as CDUs)
|
||||
*/
|
||||
class Discontinuity : public Waypt
|
||||
{
|
||||
public:
|
||||
virtual ~Discontinuity();
|
||||
Discontinuity(RouteBase* aOwner);
|
||||
|
||||
virtual void initFromProperties(SGPropertyNode_ptr aProp);
|
||||
virtual void writeToProperties(SGPropertyNode_ptr aProp) const;
|
||||
|
||||
virtual std::string type() const
|
||||
{ return "discontinuity"; }
|
||||
|
||||
virtual SGGeod position() const;
|
||||
|
||||
virtual std::string ident() const;
|
||||
|
||||
virtual double magvarDeg() const
|
||||
{ return 0.0; }
|
||||
private:
|
||||
};
|
||||
|
||||
class Via : public Waypt
|
||||
{
|
||||
public:
|
||||
Via(RouteBase* aOwner);
|
||||
Via(RouteBase* aOwner, const std::string& airwayName, FGPositioned* to);
|
||||
virtual ~Via();
|
||||
|
||||
virtual void initFromProperties(SGPropertyNode_ptr aProp);
|
||||
virtual void writeToProperties(SGPropertyNode_ptr aProp) const;
|
||||
|
||||
virtual std::string type() const
|
||||
{ return "via"; }
|
||||
|
||||
virtual SGGeod position() const;
|
||||
|
||||
virtual std::string ident() const;
|
||||
|
||||
WayptVec expandToWaypoints(WayptRef aPreceeding) const;
|
||||
private:
|
||||
std::string _airway;
|
||||
FGPositionedRef _to;
|
||||
};
|
||||
|
||||
} // of namespace flighgear
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue