1
0
Fork 0

Work on FlightPlan VIA / discontinuity support.

Needed for realistic FMS route support.
This commit is contained in:
James Turner 2014-11-13 21:03:24 +00:00
parent a55c939c5e
commit eaa147e3c2
9 changed files with 905 additions and 471 deletions

View file

@ -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),

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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;

View file

@ -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,

View file

@ -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

View file

@ -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