1
0
Fork 0

Create a real FlightPlan (and Leg) class

Convert the route-manager to use a flight-plan internally, and expose
flightplan, leg and procedure data to Nasal. Move the Level-D parser
into its own file.
This commit is contained in:
James Turner 2012-04-24 22:55:30 +01:00
parent 563ed19f97
commit 1b7b69b498
24 changed files with 3111 additions and 1666 deletions

View file

@ -172,7 +172,7 @@ void FGRunway::setReciprocalRunway(FGRunway* other)
_reciprocal = other;
}
std::vector<flightgear::SID*> FGRunway::getSIDs()
std::vector<flightgear::SID*> FGRunway::getSIDs() const
{
std::vector<flightgear::SID*> result;
for (unsigned int i=0; i<_airport->numSIDs(); ++i) {
@ -185,7 +185,7 @@ std::vector<flightgear::SID*> FGRunway::getSIDs()
return result;
}
std::vector<flightgear::STAR*> FGRunway::getSTARs()
std::vector<flightgear::STAR*> FGRunway::getSTARs() const
{
std::vector<flightgear::STAR*> result;
for (unsigned int i=0; i<_airport->numSTARs(); ++i) {
@ -198,3 +198,16 @@ std::vector<flightgear::STAR*> FGRunway::getSTARs()
return result;
}
std::vector<flightgear::Approach*> FGRunway::getApproaches() const
{
std::vector<flightgear::Approach*> result;
for (unsigned int i=0; i<_airport->numApproaches(); ++i) {
flightgear::Approach* s = _airport->getApproachByIndex(i);
if (s->runway() == this) {
result.push_back(s);
}
} // of approaches at the airport iteration
return result;
}

View file

@ -36,6 +36,7 @@ class SGPropertyNode;
namespace flightgear {
class SID;
class STAR;
class Approach;
}
class FGRunway : public FGRunwayBase
@ -124,12 +125,15 @@ public:
/**
* Get SIDs (DPs) associated with this runway
*/
std::vector<flightgear::SID*> getSIDs();
std::vector<flightgear::SID*> getSIDs() const;
/**
* Get STARs associared with this runway
*/
std::vector<flightgear::STAR*> getSTARs();
std::vector<flightgear::STAR*> getSTARs() const;
std::vector<flightgear::Approach*> getApproaches() const;
};

View file

@ -406,7 +406,7 @@ void FGAirport::loadProcedures() const
}
SG_LOG(SG_GENERAL, SG_INFO, ident() << ": loading procedures from " << path.str());
Route::loadAirportProcedures(path, const_cast<FGAirport*>(this));
RouteBase::loadAirportProcedures(path, const_cast<FGAirport*>(this));
}
void FGAirport::loadSceneryDefinitions() const
@ -469,128 +469,6 @@ void FGAirport::readTowerData(SGPropertyNode* aRoot)
_tower_location = SGGeod::fromDegM(lon, lat, fieldElevationM + elevM);
}
bool FGAirport::buildApproach(Waypt* aEnroute, STAR* aSTAR, FGRunway* aRwy, WayptVec& aRoute)
{
loadProcedures();
if ((aRwy && (aRwy->airport() != this))) {
throw sg_exception("invalid parameters", "FGAirport::buildApproach");
}
if (aSTAR) {
bool ok = aSTAR->route(aRwy, aEnroute, aRoute);
if (!ok) {
SG_LOG(SG_GENERAL, SG_WARN, ident() << ": build approach, STAR " << aSTAR->ident()
<< " failed to route from transition " << aEnroute->ident());
return false;
}
} else if (aEnroute) {
// no a STAR specified, just use enroute point directly
aRoute.push_back(aEnroute);
}
if (!aRwy) {
// no runway selected yet, but we loaded the STAR, so that's fine, we're done
return true;
}
// build the approach (possibly including transition), and including the missed segment
vector<Approach*> aps;
for (unsigned int j=0; j<mApproaches.size();++j) {
if (mApproaches[j]->runway() == aRwy) {
aps.push_back(mApproaches[j]);
}
} // of approach filter by runway
if (aps.empty()) {
SG_LOG(SG_GENERAL, SG_INFO, ident() << "; no approaches defined for runway " << aRwy->ident());
// could build a fallback approach here
return false;
}
for (unsigned int k=0; k<aps.size(); ++k) {
if (aps[k]->route(aRoute.back(), aRoute)) {
return true;
}
} // of initial approach iteration
SG_LOG(SG_GENERAL, SG_INFO, ident() << ": unable to find transition to runway "
<< aRwy->ident() << ", assume vectors");
WayptRef v(new ATCVectors(NULL, this));
aRoute.push_back(v);
return aps.front()->routeFromVectors(aRoute);
}
pair<flightgear::SID*, WayptRef>
FGAirport::selectSID(const SGGeod& aDest, FGRunway* aRwy)
{
loadProcedures();
WayptRef enroute;
flightgear::SID* sid = NULL;
double d = 1e9;
for (unsigned int i=0; i<mSIDs.size(); ++i) {
if (aRwy && !mSIDs[i]->isForRunway(aRwy)) {
continue;
}
WayptRef e = mSIDs[i]->findBestTransition(aDest);
if (!e) {
continue; // strange, but let's not worry about it
}
// assert(e->isFixedPosition());
double ed = SGGeodesy::distanceM(aDest, e->position());
if (ed < d) { // new best match
enroute = e;
d = ed;
sid = mSIDs[i];
}
} // of SID iteration
if (!mSIDs.empty() && !sid) {
SG_LOG(SG_GENERAL, SG_INFO, ident() << "selectSID, no SID found (runway="
<< (aRwy ? aRwy->ident() : "no runway preference"));
}
return std::make_pair(sid, enroute);
}
pair<STAR*, WayptRef>
FGAirport::selectSTAR(const SGGeod& aOrigin, FGRunway* aRwy)
{
loadProcedures();
WayptRef enroute;
STAR* star = NULL;
double d = 1e9;
for (unsigned int i=0; i<mSTARs.size(); ++i) {
if (!mSTARs[i]->isForRunway(aRwy)) {
continue;
}
SG_LOG(SG_GENERAL, SG_INFO, "STAR " << mSTARs[i]->ident() << " is valid for runway");
WayptRef e = mSTARs[i]->findBestTransition(aOrigin);
if (!e) {
continue; // strange, but let's not worry about it
}
// assert(e->isFixedPosition());
double ed = SGGeodesy::distanceM(aOrigin, e->position());
if (ed < d) { // new best match
enroute = e;
d = ed;
star = mSTARs[i];
}
} // of STAR iteration
return std::make_pair(star, enroute);
}
void FGAirport::addSID(flightgear::SID* aSid)
{
mSIDs.push_back(aSid);
@ -666,6 +544,18 @@ Approach* FGAirport::getApproachByIndex(unsigned int aIndex) const
return mApproaches[aIndex];
}
Approach* FGAirport::findApproachWithIdent(const std::string& aIdent) const
{
loadProcedures();
for (unsigned int i=0; i<mApproaches.size(); ++i) {
if (mApproaches[i]->ident() == aIdent) {
return mApproaches[i];
}
}
return NULL;
}
void FGAirport::setCommStations(CommStationList& comms)
{
mCommStations.swap(comms);

View file

@ -188,7 +188,8 @@ public:
unsigned int numApproaches() const;
flightgear::Approach* getApproachByIndex(unsigned int aIndex) const;
flightgear::Approach* findApproachWithIdent(const std::string& aIdent) const;
/**
* Syntactic wrapper around FGPositioned::findClosest - find the closest
* match for filter, and return it cast to FGAirport. The default filter
@ -216,22 +217,6 @@ public:
*/
static char** searchNamesAndIdents(const std::string& aFilter);
bool buildApproach(flightgear::Waypt* aEnroute, flightgear::STAR* aSTAR,
FGRunway* aRwy, flightgear::WayptVec& aRoute);
/**
* Given a destiation point, select the best SID and transition waypt from
* this airport. Returns (NULL,NULL) is no SIDs are defined, otherwise the
* best SID/transition is that which is closest to the destination point.
*/
std::pair<flightgear::SID*, flightgear::WayptRef> selectSID(const SGGeod& aDest, FGRunway* aRwy);
/**
* Select a STAR and enroute transition waypt, given an origin (departure) position.
* returns (NULL, NULL) is no suitable STAR is exists
*/
std::pair<flightgear::STAR*, flightgear::WayptRef> selectSTAR(const SGGeod& aOrigin, FGRunway* aRwy);
void setCommStations(flightgear::CommStationList& comms);
flightgear::CommStationList commStationsOfType(FGPositioned::Type aTy) const;

File diff suppressed because it is too large Load diff

View file

@ -44,7 +44,8 @@ typedef SGSharedPtr<FGAirport> FGAirportRef;
*
*/
class FGRouteMgr : public SGSubsystem
class FGRouteMgr : public SGSubsystem,
public flightgear::FlightPlan::Delegate
{
public:
FGRouteMgr();
@ -55,11 +56,6 @@ public:
void bind ();
void unbind ();
void update (double dt);
void insertWayptAtIndex(flightgear::Waypt* aWpt, int aIndex);
flightgear::WayptRef removeWayptAtIndex(int index);
void clearRoute();
typedef enum {
ROUTE_HIGH_AIRWAYS, ///< high-level airways routing
@ -74,34 +70,31 @@ public:
* used as the final waypoint.
*/
bool routeToIndex(int index, RouteType aRouteType);
void autoRoute();
bool isRouteActive() const;
int currentIndex() const
{ return _currentIndex; }
int currentIndex() const;
void setFlightPlan(flightgear::FlightPlan* plan);
flightgear::FlightPlan* flightPlan() const;
void clearRoute();
flightgear::Waypt* currentWaypt() const;
flightgear::Waypt* nextWaypt() const;
flightgear::Waypt* previousWaypt() const;
const flightgear::WayptVec& waypts() const
{ return _route; }
int numLegs() const;
// deprecated
int numWaypts() const
{ return _route.size(); }
{ return numLegs(); }
// deprecated
flightgear::Waypt* wayptAtIndex(int index) const;
SGPropertyNode_ptr wayptNodeAtIndex(int index) const;
/**
* Find a waypoint in the route, by position, and return its index, or
* -1 if no matching waypoint was found in the route.
*/
int findWayptIndex(const SGGeod& aPos) const;
void removeLegAtIndex(int aIndex);
/**
* Activate a built route. This checks for various mandatory pieces of
* data, such as departure and destination airports, and creates waypoints
@ -125,38 +118,20 @@ public:
bool saveRoute(const SGPath& p);
bool loadRoute(const SGPath& p);
flightgear::WayptRef waypointFromString(const std::string& target);
/**
* Helper command to setup current airport/runway if necessary
*/
void initAtPosition();
/**
* Create a WayPoint from a string in the following format:
* - simple identifier
* - decimal-lon,decimal-lat
* - airport-id/runway-id
* - navaid/radial-deg/offset-nm
*/
flightgear::WayptRef waypointFromString(const std::string& target);
FGAirportRef departureAirport() const;
FGAirportRef destinationAirport() const;
FGRunway* departureRunway() const;
FGRunway* destinationRunway() const;
private:
flightgear::WayptVec _route;
int _currentIndex;
flightgear::FlightPlan* _plan;
time_t _takeoffTime;
time_t _touchdownTime;
FGAirportRef _departure;
FGAirportRef _destination;
// automatic inputs
SGPropertyNode_ptr lon;
SGPropertyNode_ptr lat;
SGPropertyNode_ptr alt;
SGPropertyNode_ptr magvar;
// automatic outputs
@ -215,11 +190,11 @@ private:
InputListener *listener;
SGPropertyNode_ptr mirror;
void departureChanged();
virtual void departureChanged();
void buildDeparture(flightgear::WayptRef enroute, flightgear::WayptVec& wps);
void arrivalChanged();
virtual void arrivalChanged();
void buildArrival(flightgear::WayptRef enroute, flightgear::WayptVec& wps);
/**
@ -227,16 +202,11 @@ private:
* modified (waypoints added, inserted, removed). Notably, this fires the
* 'edited' signal.
*/
void waypointsChanged();
virtual void waypointsChanged();
void update_mirror();
void currentWaypointChanged();
/**
* Parse a route/wp node (from a saved, property-lsit formatted route)
*/
void parseRouteWaypoint(SGPropertyNode* aWP);
virtual void currentWaypointChanged();
/**
* Check if we've reached the final waypoint.
@ -244,14 +214,6 @@ private:
*/
bool checkFinished();
bool loadPlainTextRoute(const SGPath& path);
void loadVersion1XMLRoute(SGPropertyNode_ptr routeData);
void loadVersion2XMLRoute(SGPropertyNode_ptr routeData);
void loadXMLRouteHeader(SGPropertyNode_ptr routeData);
flightgear::WayptRef parseVersion1XMLWaypt(SGPropertyNode* aWP);
/**
* Predicate for helping the UI - test if at least one waypoint was
* entered by the user (as opposed to being generated by the route-manager)
@ -263,12 +225,27 @@ private:
const char* getDepartureName() const;
void setDepartureICAO(const char* aIdent);
const char* getDepartureRunway() const;
void setDepartureRunway(const char* aIdent);
const char* getSID() const;
void setSID(const char* aIdent);
const char* getDestinationICAO() const;
const char* getDestinationName() const;
void setDestinationICAO(const char* aIdent);
PropertyWatcher* _departureWatcher;
PropertyWatcher* _arrivalWatcher;
const char* getDestinationRunway() const;
void setDestinationRunway(const char* aIdent);
const char* getApproach() const;
void setApproach(const char* aIdent);
const char* getSTAR() const;
void setSTAR(const char* aIdent);
double getDepartureFieldElevation() const;
double getDestinationFieldElevation() const;
};

View file

@ -682,7 +682,7 @@ void MapWidget::paintRoute()
return;
}
RoutePath path(_route->waypts());
RoutePath path(_route->flightPlan());
// first pass, draw the actual lines
glLineWidth(2.0);

View file

@ -37,20 +37,19 @@ enum {
static const double BLINK_TIME = 0.3;
static const int DRAG_START_DISTANCE_PX = 5;
class RouteManagerWaypointModel :
class FlightPlanWaypointModel :
public WaypointList::Model,
public SGPropertyChangeListener
{
public:
RouteManagerWaypointModel()
{
_rm = static_cast<FGRouteMgr*>(globals->get_subsystem("route-manager"));
FlightPlanWaypointModel(flightgear::FlightPlan* fp) :
_fp(fp)
{
SGPropertyNode* routeEdited = fgGetNode("/autopilot/route-manager/signals/edited", true);
routeEdited->addChangeListener(this);
}
virtual ~RouteManagerWaypointModel()
~FlightPlanWaypointModel()
{
SGPropertyNode* routeEdited = fgGetNode("/autopilot/route-manager/signals/edited", true);
routeEdited->removeChangeListener(this);
@ -59,12 +58,12 @@ public:
// implement WaypointList::Model
virtual unsigned int numWaypoints() const
{
return _rm->numWaypts();
return _fp->numLegs();
}
virtual int currentWaypoint() const
{
return _rm->currentIndex();
return _fp->currentIndex();
}
virtual flightgear::Waypt* waypointAt(unsigned int index) const
@ -73,12 +72,12 @@ public:
return NULL;
}
return _rm->wayptAtIndex(index);
return _fp->legAtIndex(index)->waypoint();
}
virtual void deleteAt(unsigned int index)
{
_rm->removeWayptAtIndex(index);
_fp->deleteIndex(index);
}
virtual void moveWaypointToIndex(unsigned int srcIndex, unsigned int destIndex)
@ -89,13 +88,15 @@ public:
}
unsigned int currentWpIndex = currentWaypoint();
WayptRef w(_rm->removeWayptAtIndex(srcIndex));
WayptRef w(waypointAt(currentWpIndex));
_fp->deleteIndex(currentWpIndex);
SG_LOG(SG_GENERAL, SG_INFO, "wpt:" << w->ident());
_rm->insertWayptAtIndex(w, destIndex);
_fp->insertWayptAtIndex(w, destIndex);
if (srcIndex == currentWpIndex) {
// current waypoint was moved
_rm->jumpToIndex(destIndex);
_fp->setCurrentIndex(destIndex);
}
}
@ -112,7 +113,7 @@ public:
}
}
private:
FGRouteMgr* _rm;
flightgear::FlightPlan* _fp;
SGCallback* _cb;
};
@ -152,7 +153,9 @@ WaypointList::WaypointList(int x, int y, int width, int height) :
{
// pretend to be a list, so fgPopup doesn't mess with our mouse events
type |= PUCLASS_LIST;
setModel(new RouteManagerWaypointModel());
flightgear::FlightPlan* fp =
static_cast<FGRouteMgr*>(globals->get_subsystem("route-manager"))->flightPlan();
setModel(new FlightPlanWaypointModel(fp));
setSize(width, height);
setValue(-1);

View file

@ -159,7 +159,6 @@ public:
virtual void valueChanged (SGPropertyNode * prop)
{
_nd->invalidatePositionedCache();
SG_LOG(SG_INSTR, SG_INFO, "invalidating NavDisplay cache");
}
private:
NavDisplay* _nd;
@ -174,7 +173,6 @@ public:
virtual void valueChanged (SGPropertyNode * prop)
{
SG_LOG(SG_INSTR, SG_INFO, "forcing NavDisplay update");
_nd->forceUpdate();
}
private:
@ -683,9 +681,6 @@ NavDisplay::update (double delta_time_sec)
SGVec3d cartNow(SGVec3d::fromGeod(_pos));
double movedNm = dist(_cachedPos, cartNow) * SG_METER_TO_NM;
_cachedItemsValid = (movedNm < 1.0);
if (!_cachedItemsValid) {
SG_LOG(SG_INSTR, SG_INFO, "invalidating NavDisplay cache due to moving: " << movedNm);
}
}
_vertices->clear();
@ -951,7 +946,6 @@ public:
void NavDisplay::findItems()
{
if (!_cachedItemsValid) {
SG_LOG(SG_INSTR, SG_INFO, "re-validating NavDisplay cache");
Filter filt;
filt.minRunwayLengthFt = 2000;
_itemsInRange = FGPositioned::findWithinRange(_pos, _rangeNm, &filt);
@ -967,29 +961,31 @@ void NavDisplay::findItems()
void NavDisplay::processRoute()
{
_routeSources.clear();
RoutePath path(_route->waypts());
flightgear::FlightPlan* fp = _route->flightPlan();
RoutePath path(fp);
int current = _route->currentIndex();
for (int w=0; w<_route->numWaypts(); ++w) {
flightgear::WayptRef wpt(_route->wayptAtIndex(w));
for (int l=0; l<fp->numLegs(); ++l) {
flightgear::FlightPlan::Leg* leg = fp->legAtIndex(l);
flightgear::WayptRef wpt(leg->waypoint());
_routeSources.insert(wpt->source());
string_set state;
state.insert("on-active-route");
if (w < current) {
if (l < current) {
state.insert("passed");
}
if (w == current) {
if (l == current) {
state.insert("current-wp");
}
if (w > current) {
if (l > current) {
state.insert("future");
}
if (w == (current + 1)) {
if (l == (current + 1)) {
state.insert("next-wp");
}
@ -999,8 +995,12 @@ void NavDisplay::processRoute()
return; // no rules matched, we can skip this item
}
SGGeod g = path.positionForIndex(w);
SGPropertyNode* vars = _route->wayptNodeAtIndex(w);
SGGeod g = path.positionForIndex(l);
SGPropertyNode* vars = _route->wayptNodeAtIndex(l);
if (!vars) {
continue; // shouldn't happen, but let's guard against it
}
double heading;
computeWayptPropsAndHeading(wpt, g, vars, heading);
@ -1009,7 +1009,7 @@ void NavDisplay::processRoute()
addSymbolInstance(projected, heading, r->getDefinition(), vars);
if (r->getDefinition()->drawRouteLeg) {
SGGeodVec gv(path.pathForIndex(w));
SGGeodVec gv(path.pathForIndex(l));
if (!gv.empty()) {
osg::Vec2 pr = projectGeod(gv[0]);
for (unsigned int i=1; i<gv.size(); ++i) {
@ -1189,6 +1189,7 @@ void NavDisplay::computePositionedState(FGPositioned* pos, string_set& states)
states.insert("on-active-route");
}
flightgear::FlightPlan* fp = _route->flightPlan();
switch (pos->type()) {
case FGPositioned::VOR:
case FGPositioned::LOC:
@ -1209,21 +1210,21 @@ void NavDisplay::computePositionedState(FGPositioned* pos, string_set& states)
// mark alternates!
// once the FMS system has some way to tell us about them, of course
if (pos == _route->departureAirport()) {
if (pos == fp->departureAirport()) {
states.insert("departure");
}
if (pos == _route->destinationAirport()) {
if (pos == fp->destinationAirport()) {
states.insert("destination");
}
break;
case FGPositioned::RUNWAY:
if (pos == _route->departureRunway()) {
if (pos == fp->departureRunway()) {
states.insert("departure");
}
if (pos == _route->destinationRunway()) {
if (pos == fp->destinationRunway()) {
states.insert("destination");
}
break;

View file

@ -724,7 +724,7 @@ void GPS::routeManagerSequenced()
SG_LOG(SG_INSTR, SG_INFO, "GPS waypoint index is now " << index);
if (index > 0) {
_prevWaypt = _routeMgr->previousWaypt();
_prevWaypt = _routeMgr->wayptAtIndex(index - 1);
if (_prevWaypt->flag(WPT_DYNAMIC)) {
_wp0_position = _indicated_pos;
} else {
@ -829,7 +829,7 @@ void GPS::updateOverflight()
// check for wp1 being on active route - resume leg mode
if (_routeMgr->isRouteActive()) {
int index = _routeMgr->findWayptIndex(_currentWaypt->position());
int index = _routeMgr->flightPlan()->findWayptIndex(_currentWaypt->position());
if (index >= 0) {
SG_LOG(SG_INSTR, SG_INFO, "GPS DTO, resuming LEG mode at wp:" << index);
_mode = "leg";
@ -881,7 +881,7 @@ void GPS::computeTurnData()
return;
}
WayptRef next = _routeMgr->nextWaypt();
WayptRef next = _routeMgr->wayptAtIndex(_routeMgr->currentIndex() + 1);
if (!next || next->flag(WPT_DYNAMIC)) {
_anticipateTurn = false;
return;
@ -1684,7 +1684,7 @@ void GPS::insertWaypointAtIndex(int aIndex)
string ident = _scratchNode->getStringValue("ident");
WayptRef wpt = new BasicWaypt(_scratchPos, ident, NULL);
_routeMgr->insertWayptAtIndex(wpt, aIndex);
_routeMgr->flightPlan()->insertWayptAtIndex(wpt, aIndex);
}
void GPS::removeWaypointAtIndex(int aIndex)
@ -1693,7 +1693,7 @@ void GPS::removeWaypointAtIndex(int aIndex)
throw sg_range_exception("GPS::removeWaypointAtIndex: index out of bounds");
}
_routeMgr->removeWayptAtIndex(aIndex);
_routeMgr->removeLegAtIndex(aIndex);
}
void GPS::tieSGGeod(SGPropertyNode* aNode, SGGeod& aRef,

View file

@ -317,7 +317,9 @@ public:
double curAlt = _rnav->position().getElevationFt();
switch (_waypt->altitudeRestriction()) {
case RESTRICT_AT: {
case RESTRICT_AT:
case RESTRICT_COMPUTED:
{
double d = curAlt - _waypt->altitudeFt();
if (fabs(d) < 50.0) {
SG_LOG(SG_INSTR, SG_INFO, "ConstHdgToAltCtl, reached target altitude " << _waypt->altitudeFt());
@ -339,11 +341,7 @@ public:
}
break;
case RESTRICT_NONE:
assert(false);
break;
case SPEED_RESTRICT_MACH:
assert(false);
default:
break;
}
}

View file

@ -12,7 +12,8 @@ set(SOURCES
route.cxx
routePath.cxx
waypoint.cxx
)
LevelDXML.cxx
)
set(HEADERS
airways.hxx
@ -26,6 +27,7 @@ set(HEADERS
route.hxx
routePath.hxx
waypoint.hxx
)
LevelDXML.hxx
)
flightgear_component(Navaids "${SOURCES}" "${HEADERS}")

337
src/Navaids/LevelDXML.cxx Normal file
View file

@ -0,0 +1,337 @@
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "LevelDXML.hxx"
#include <boost/algorithm/string.hpp>
#include <simgear/structure/exception.hxx>
#include <simgear/misc/sg_path.hxx>
#include <Navaids/waypoint.hxx>
#include <Airports/simple.hxx>
using std::string;
using std::vector;
namespace flightgear
{
NavdataVisitor::NavdataVisitor(FGAirport* aApt, const SGPath& aPath):
_airport(aApt),
_path(aPath),
_sid(NULL),
_star(NULL),
_approach(NULL),
_transition(NULL),
_procedure(NULL)
{
}
void NavdataVisitor::startXML()
{
}
void NavdataVisitor::endXML()
{
}
void NavdataVisitor::startElement(const char* name, const XMLAttributes &atts)
{
_text.clear();
string tag(name);
if (tag == "Airport") {
string icao(atts.getValue("ICAOcode"));
if (_airport->ident() != icao) {
throw sg_format_exception("Airport and ICAO mismatch", icao, _path.str());
}
} else if (tag == "Sid") {
string ident(atts.getValue("Name"));
_sid = new SID(ident, _airport);
_procedure = _sid;
_waypoints.clear();
processRunways(_sid, atts);
} else if (tag == "Star") {
string ident(atts.getValue("Name"));
_star = new STAR(ident, _airport);
_procedure = _star;
_waypoints.clear();
processRunways(_star, atts);
} else if ((tag == "Sid_Waypoint") ||
(tag == "App_Waypoint") ||
(tag == "Star_Waypoint") ||
(tag == "AppTr_Waypoint") ||
(tag == "SidTr_Waypoint") ||
(tag == "RwyTr_Waypoint"))
{
// reset waypoint data
_speed = 0.0;
_altRestrict = RESTRICT_NONE;
_altitude = 0.0;
} else if (tag == "Approach") {
_ident = atts.getValue("Name");
_waypoints.clear();
ProcedureType ty = PROCEDURE_APPROACH_RNAV;
_approach = new Approach(_ident, ty);
_procedure = _approach;
} else if ((tag == "Sid_Transition") ||
(tag == "App_Transition") ||
(tag == "Star_Transition")) {
_transIdent = atts.getValue("Name");
_transition = new Transition(_transIdent, PROCEDURE_TRANSITION, _procedure);
_transWaypts.clear();
} else if (tag == "RunwayTransition") {
_transIdent = atts.getValue("Runway");
_transition = new Transition(_transIdent, PROCEDURE_RUNWAY_TRANSITION, _procedure);
_transWaypts.clear();
} else {
}
}
void NavdataVisitor::processRunways(ArrivalDeparture* aProc, const XMLAttributes &atts)
{
string v("All");
if (atts.hasAttribute("Runways")) {
v = atts.getValue("Runways");
}
if (v == "All") {
for (unsigned int r=0; r<_airport->numRunways(); ++r) {
aProc->addRunway(_airport->getRunwayByIndex(r));
}
return;
}
vector<string> rwys;
boost::split(rwys, v, boost::is_any_of(" ,"));
for (unsigned int r=0; r<rwys.size(); ++r) {
FGRunway* rwy = _airport->getRunwayByIdent(rwys[r]);
aProc->addRunway(rwy);
}
}
void NavdataVisitor::endElement(const char* name)
{
string tag(name);
if ((tag == "Sid_Waypoint") ||
(tag == "App_Waypoint") ||
(tag == "Star_Waypoint"))
{
_waypoints.push_back(buildWaypoint(_procedure));
} else if ((tag == "AppTr_Waypoint") ||
(tag == "SidTr_Waypoint") ||
(tag == "RwyTr_Waypoint") ||
(tag == "StarTr_Waypoint"))
{
_transWaypts.push_back(buildWaypoint(_transition));
} else if (tag == "Sid_Transition") {
assert(_sid);
// SID waypoints are stored backwards, to share code with STARs
std::reverse(_transWaypts.begin(), _transWaypts.end());
_transition->setPrimary(_transWaypts);
_sid->addTransition(_transition);
} else if (tag == "Star_Transition") {
assert(_star);
_transition->setPrimary(_transWaypts);
_star->addTransition(_transition);
} else if (tag == "App_Transition") {
assert(_approach);
_transition->setPrimary(_transWaypts);
_approach->addTransition(_transition);
} else if (tag == "RunwayTransition") {
ArrivalDeparture* ad;
if (_sid) {
// SID waypoints are stored backwards, to share code with STARs
std::reverse(_transWaypts.begin(), _transWaypts.end());
ad = _sid;
} else {
ad = _star;
}
_transition->setPrimary(_transWaypts);
FGRunwayRef rwy = _airport->getRunwayByIdent(_transIdent);
ad->addRunwayTransition(rwy, _transition);
} else if (tag == "Approach") {
finishApproach();
} else if (tag == "Sid") {
finishSid();
} else if (tag == "Star") {
finishStar();
} else if (tag == "Longitude") {
_longitude = atof(_text.c_str());
} else if (tag == "Latitude") {
_latitude = atof(_text.c_str());
} else if (tag == "Name") {
_wayptName = _text;
} else if (tag == "Type") {
_wayptType = _text;
} else if (tag == "Speed") {
_speed = atoi(_text.c_str());
} else if (tag == "Altitude") {
_altitude = atof(_text.c_str());
} else if (tag == "AltitudeRestriction") {
if (_text == "at") {
_altRestrict = RESTRICT_AT;
} else if (_text == "above") {
_altRestrict = RESTRICT_ABOVE;
} else if (_text == "below") {
_altRestrict = RESTRICT_BELOW;
} else {
throw sg_format_exception("Unrecognized altitude restriction", _text);
}
} else if (tag == "Hld_Rad_or_Inbd") {
if (_text == "Inbd") {
_holdRadial = -1.0;
}
} else if (tag == "Hld_Time_or_Dist") {
_holdDistance = (_text == "Dist");
} else if (tag == "Hld_Rad_value") {
_holdRadial = atof(_text.c_str());
} else if (tag == "Hld_Turn") {
_holdRighthanded = (_text == "Right");
} else if (tag == "Hld_td_value") {
_holdTD = atof(_text.c_str());
} else if (tag == "Hdg_Crs_value") {
_course = atof(_text.c_str());
} else if (tag == "DMEtoIntercept") {
_dmeDistance = atof(_text.c_str());
} else if (tag == "RadialtoIntercept") {
_radial = atof(_text.c_str());
} else {
}
}
Waypt* NavdataVisitor::buildWaypoint(RouteBase* owner)
{
Waypt* wp = NULL;
if (_wayptType == "Normal") {
// new LatLonWaypoint
SGGeod pos(SGGeod::fromDeg(_longitude, _latitude));
wp = new BasicWaypt(pos, _wayptName, owner);
} else if (_wayptType == "Runway") {
string ident = _wayptName.substr(2);
FGRunwayRef rwy = _airport->getRunwayByIdent(ident);
wp = new RunwayWaypt(rwy, owner);
} else if (_wayptType == "Hold") {
SGGeod pos(SGGeod::fromDeg(_longitude, _latitude));
Hold* h = new Hold(pos, _wayptName, owner);
wp = h;
if (_holdRighthanded) {
h->setRightHanded();
} else {
h->setLeftHanded();
}
if (_holdDistance) {
h->setHoldDistance(_holdTD);
} else {
h->setHoldTime(_holdTD * 60.0);
}
if (_holdRadial >= 0.0) {
h->setHoldRadial(_holdRadial);
}
} else if (_wayptType == "Vectors") {
wp = new ATCVectors(owner, _airport);
} else if ((_wayptType == "Intc") || (_wayptType == "VorRadialIntc")) {
SGGeod pos(SGGeod::fromDeg(_longitude, _latitude));
wp = new RadialIntercept(owner, _wayptName, pos, _course, _radial);
} else if (_wayptType == "DmeIntc") {
SGGeod pos(SGGeod::fromDeg(_longitude, _latitude));
wp = new DMEIntercept(owner, _wayptName, pos, _course, _dmeDistance);
} else if (_wayptType == "ConstHdgtoAlt") {
wp = new HeadingToAltitude(owner, _wayptName, _course);
} else if (_wayptType == "PBD") {
SGGeod pos(SGGeod::fromDeg(_longitude, _latitude)), pos2;
double az2;
SGGeodesy::direct(pos, _course, _dmeDistance, pos2, az2);
wp = new BasicWaypt(pos2, _wayptName, owner);
} else {
SG_LOG(SG_GENERAL, SG_ALERT, "implement waypoint type:" << _wayptType);
throw sg_format_exception("Unrecognized waypt type", _wayptType);
}
assert(wp);
if ((_altitude > 0.0) && (_altRestrict != RESTRICT_NONE)) {
wp->setAltitude(_altitude,_altRestrict);
}
if (_speed > 0.0) {
wp->setSpeed(_speed, RESTRICT_AT); // or _BELOW?
}
return wp;
}
void NavdataVisitor::finishApproach()
{
WayptVec::iterator it;
FGRunwayRef rwy;
// find the runway node
for (it = _waypoints.begin(); it != _waypoints.end(); ++it) {
FGPositionedRef navid = (*it)->source();
if (!navid) {
continue;
}
if (navid->type() == FGPositioned::RUNWAY) {
rwy = (FGRunway*) navid.get();
break;
}
}
if (!rwy) {
throw sg_format_exception("Malformed approach, no runway waypt", _ident);
}
WayptVec primary(_waypoints.begin(), it);
// erase all points up to and including the runway, to leave only the
// missed segments
_waypoints.erase(_waypoints.begin(), ++it);
_approach->setRunway(rwy);
_approach->setPrimaryAndMissed(primary, _waypoints);
_airport->addApproach(_approach);
_approach = NULL;
}
void NavdataVisitor::finishSid()
{
// reverse order, because that's how we deal with commonality between
// STARs and SIDs. SID::route undoes this
std::reverse(_waypoints.begin(), _waypoints.end());
_sid->setCommon(_waypoints);
_airport->addSID(_sid);
_sid = NULL;
}
void NavdataVisitor::finishStar()
{
_star->setCommon(_waypoints);
_airport->addSTAR(_star);
_star = NULL;
}
void NavdataVisitor::data (const char * s, int len)
{
_text += string(s, len);
}
void NavdataVisitor::pi (const char * target, const char * data) {
//cout << "Processing instruction " << target << ' ' << data << endl;
}
void NavdataVisitor::warning (const char * message, int line, int column) {
SG_LOG(SG_IO, SG_WARN, "Warning: " << message << " (" << line << ',' << column << ')');
}
void NavdataVisitor::error (const char * message, int line, int column) {
SG_LOG(SG_IO, SG_ALERT, "Error: " << message << " (" << line << ',' << column << ')');
}
}

66
src/Navaids/LevelDXML.hxx Normal file
View file

@ -0,0 +1,66 @@
#ifndef FG_NAV_LEVELDXML_HXX
#define FG_NAV_LEVELDXML_HXX
class FGAirport;
class SGPath;
#include <simgear/xml/easyxml.hxx>
#include <simgear/misc/sg_path.hxx>
#include <Navaids/procedure.hxx>
namespace flightgear
{
class NavdataVisitor : public XMLVisitor {
public:
NavdataVisitor(FGAirport* aApt, const SGPath& aPath);
protected:
virtual void startXML ();
virtual void endXML ();
virtual void startElement (const char * name, const XMLAttributes &atts);
virtual void endElement (const char * name);
virtual void data (const char * s, int len);
virtual void pi (const char * target, const char * data);
virtual void warning (const char * message, int line, int column);
virtual void error (const char * message, int line, int column);
private:
Waypt* buildWaypoint(RouteBase* owner);
void processRunways(ArrivalDeparture* aProc, const XMLAttributes &atts);
void finishApproach();
void finishSid();
void finishStar();
FGAirport* _airport;
SGPath _path;
std::string _text; ///< last element text value
SID* _sid;
STAR* _star;
Approach* _approach;
Transition* _transition;
Procedure* _procedure;
WayptVec _waypoints; ///< waypoint list for current approach/sid/star
WayptVec _transWaypts; ///< waypoint list for current transition
std::string _wayptName;
std::string _wayptType;
std::string _ident; // id of segment under construction
std::string _transIdent;
double _longitude, _latitude, _altitude, _speed;
RouteRestriction _altRestrict;
double _holdRadial; // inbound hold radial, or -1 if radial is 'inbound'
double _holdTD; ///< hold time (seconds) or distance (nm), based on flag below
bool _holdRighthanded;
bool _holdDistance; // true, TD is distance in nm; false, TD is time in seconds
double _course, _radial, _dmeDistance;
};
}
#endif

View file

@ -35,7 +35,7 @@ struct SearchContext;
class AdjacentWaypoint;
class InAirwayFilter;
class Airway : public Route
class Airway : public RouteBase
{
public:
virtual std::string ident() const

View file

@ -30,14 +30,22 @@ using std::string;
namespace flightgear
{
static void markWaypoints(WayptVec& wps, WayptFlag f)
{
for (unsigned int i=0; i<wps.size(); ++i) {
wps[i]->setFlag(f, true);
}
}
Procedure::Procedure(const string& aIdent) :
_ident(aIdent)
{
}
Approach::Approach(const string& aIdent) :
Procedure(aIdent)
Approach::Approach(const string& aIdent, ProcedureType ty) :
Procedure(aIdent),
_type(ty)
{
}
@ -47,22 +55,32 @@ void Approach::setRunway(FGRunwayRef aRwy)
_runway = aRwy;
}
FGAirport* Approach::airport() const
{
return _runway->airport();
}
RunwayVec Approach::runways() const
{
RunwayVec r;
r.push_back(_runway);
return r;
}
void Approach::setPrimaryAndMissed(const WayptVec& aPrimary, const WayptVec& aMissed)
{
_primary = aPrimary;
_primary[0]->setFlag(WPT_IAF, true);
_primary[_primary.size()-1]->setFlag(WPT_FAF, true);
markWaypoints(_primary, WPT_APPROACH);
_missed = aMissed;
if (!_missed.empty()) {
// mark the first point as the published missed-approach point
_missed[0]->setFlag(WPT_MAP, true);
// mark all the points as being on the missed approach route
for (unsigned int i=0; i<_missed.size(); ++i) {
_missed[i]->setFlag(WPT_MISS, true);
}
markWaypoints(_missed, WPT_MISS);
markWaypoints(_missed, WPT_APPROACH);
}
}
@ -70,6 +88,7 @@ void Approach::addTransition(Transition* aTrans)
{
WayptRef entry = aTrans->enroute();
_transitions[entry] = aTrans;
aTrans->mark(WPT_APPROACH);
}
bool Approach::route(WayptRef aIAF, WayptVec& aWps)
@ -78,8 +97,9 @@ bool Approach::route(WayptRef aIAF, WayptVec& aWps)
bool haveTrans = false;
for (it = _transitions.begin(); it != _transitions.end(); ++it) {
Transition* t= it->second;
if (t->route(aIAF, aWps)) {
haveTrans = true;
if (t->enroute()->matches(aIAF)) {
t->route(aWps);
haveTrans = true;
break;
}
} // of transitions iteration
@ -90,10 +110,7 @@ bool Approach::route(WayptRef aIAF, WayptVec& aWps)
return false;
}
aWps.insert(aWps.end(), _primary.begin(), _primary.end());
aWps.push_back(new RunwayWaypt(_runway, NULL));
aWps.insert(aWps.end(), _missed.begin(), _missed.end());
return true;
return routeFromVectors(aWps);
}
bool Approach::routeFromVectors(WayptVec& aWps)
@ -104,34 +121,64 @@ bool Approach::routeFromVectors(WayptVec& aWps)
return true;
}
bool Approach::isApproach(ProcedureType ty)
{
return (ty >= PROCEDURE_APPROACH_ILS) && (ty <= PROCEDURE_APPROACH_RNAV);
}
//////////////////////////////////////////////////////////////////////////////
ArrivalDeparture::ArrivalDeparture(const string& aIdent) :
Procedure(aIdent)
ArrivalDeparture::ArrivalDeparture(const string& aIdent, FGAirport* apt) :
Procedure(aIdent),
_airport(apt)
{
}
void ArrivalDeparture::addRunway(FGRunwayRef aWay)
{
assert(aWay->airport() == _airport);
_runways[aWay] = NULL;
}
bool ArrivalDeparture::isForRunway(FGRunwayRef aWay) const
bool ArrivalDeparture::isForRunway(const FGRunway* aWay) const
{
// null runway always passes
if (!aWay) {
return true;
}
return (_runways.count(aWay));
FGRunwayRef r(const_cast<FGRunway*>(aWay));
return (_runways.count(r));
}
RunwayVec ArrivalDeparture::runways() const
{
RunwayVec r;
RunwayTransitionMap::const_iterator it = _runways.begin();
for (; it != _runways.end(); ++it) {
r.push_back(it->first);
}
return r;
}
void ArrivalDeparture::addTransition(Transition* aTrans)
{
WayptRef entry = aTrans->enroute();
aTrans->mark(flagType());
_enrouteTransitions[entry] = aTrans;
}
string_list ArrivalDeparture::transitionIdents() const
{
string_list r;
WptTransitionMap::const_iterator eit;
for (eit = _enrouteTransitions.begin(); eit != _enrouteTransitions.end(); ++eit) {
r.push_back(eit->second->ident());
}
return r;
}
void ArrivalDeparture::addRunwayTransition(FGRunwayRef aWay, Transition* aTrans)
{
assert(aWay->ident() == aTrans->ident());
@ -139,23 +186,24 @@ void ArrivalDeparture::addRunwayTransition(FGRunwayRef aWay, Transition* aTrans)
throw sg_io_exception("adding transition for unspecified runway:" + aWay->ident(), ident());
}
aTrans->mark(flagType());
_runways[aWay] = aTrans;
}
void ArrivalDeparture::setCommon(const WayptVec& aWps)
{
_common = aWps;
markWaypoints(_common, flagType());
}
bool ArrivalDeparture::commonRoute(Waypt* aEnroute, WayptVec& aPath, FGRunwayRef aRwy)
bool ArrivalDeparture::commonRoute(Transition* t, WayptVec& aPath, FGRunwayRef aRwy)
{
// assume we're routing from enroute, to the runway.
// for departures, we'll flip the result points
Transition* t = findTransitionByEnroute(aEnroute);
WayptVec::iterator firstCommon = _common.begin();
if (t) {
t->route(aEnroute, aPath);
t->route(aPath);
Waypt* transEnd = t->procedureEnd();
for (; firstCommon != _common.end(); ++firstCommon) {
@ -170,9 +218,7 @@ bool ArrivalDeparture::commonRoute(Waypt* aEnroute, WayptVec& aPath, FGRunwayRef
// common section after the transition.
firstCommon = _common.begin();
} else {
if (aEnroute && !(*firstCommon)->matches(aEnroute)) {
return false;
}
// no tranasition
} // of not using a transition
// append (some) common points
@ -193,7 +239,7 @@ bool ArrivalDeparture::commonRoute(Waypt* aEnroute, WayptVec& aPath, FGRunwayRef
}
SG_LOG(SG_GENERAL, SG_INFO, ident() << " using runway transition for " << r->first->ident());
r->second->route(NULL, aPath);
r->second->route(aPath);
return true;
}
@ -241,13 +287,12 @@ WayptRef ArrivalDeparture::findBestTransition(const SGGeod& aPos) const
return w;
}
WayptRef ArrivalDeparture::findTransitionByName(const string& aIdent) const
Transition* ArrivalDeparture::findTransitionByName(const string& aIdent) const
{
WptTransitionMap::const_iterator eit;
for (eit = _enrouteTransitions.begin(); eit != _enrouteTransitions.end(); ++eit) {
WayptRef c = eit->second->enroute();
if (c->ident() == aIdent) {
return c;
if (eit->second->ident() == aIdent) {
return eit->second;
}
}
@ -256,12 +301,12 @@ WayptRef ArrivalDeparture::findTransitionByName(const string& aIdent) const
////////////////////////////////////////////////////////////////////////////
SID::SID(const string& aIdent) :
ArrivalDeparture(aIdent)
SID::SID(const string& aIdent, FGAirport* apt) :
ArrivalDeparture(aIdent, apt)
{
}
bool SID::route(FGRunwayRef aWay, Waypt* aEnroute, WayptVec& aPath)
bool SID::route(FGRunwayRef aWay, Transition* trans, WayptVec& aPath)
{
if (!isForRunway(aWay)) {
SG_LOG(SG_GENERAL, SG_WARN, "SID " << ident() << " not for runway " << aWay->ident());
@ -269,7 +314,7 @@ bool SID::route(FGRunwayRef aWay, Waypt* aEnroute, WayptVec& aPath)
}
WayptVec path;
if (!commonRoute(aEnroute, path, aWay)) {
if (!commonRoute(trans, path, aWay)) {
return false;
}
@ -283,24 +328,25 @@ bool SID::route(FGRunwayRef aWay, Waypt* aEnroute, WayptVec& aPath)
////////////////////////////////////////////////////////////////////////////
STAR::STAR(const string& aIdent) :
ArrivalDeparture(aIdent)
STAR::STAR(const string& aIdent, FGAirport* apt) :
ArrivalDeparture(aIdent, apt)
{
}
bool STAR::route(FGRunwayRef aWay, Waypt* aEnroute, WayptVec& aPath)
bool STAR::route(FGRunwayRef aWay, Transition* trans, WayptVec& aPath)
{
if (aWay && !isForRunway(aWay)) {
return false;
}
return commonRoute(aEnroute, aPath, aWay);
return commonRoute(trans, aPath, aWay);
}
/////////////////////////////////////////////////////////////////////////////
Transition::Transition(const std::string& aIdent, Procedure* aPr) :
_ident(aIdent),
Transition::Transition(const std::string& aIdent, ProcedureType ty, Procedure* aPr) :
Procedure(aIdent),
_type(ty),
_parent(aPr)
{
assert(aPr);
@ -325,14 +371,20 @@ WayptRef Transition::procedureEnd() const
return _primary[_primary.size() - 1];
}
bool Transition::route(Waypt* aEnroute, WayptVec& aPath)
bool Transition::route(WayptVec& aPath)
{
if (aEnroute && !enroute()->matches(aEnroute)) {
return false;
}
aPath.insert(aPath.end(), _primary.begin(), _primary.end());
return true;
}
FGAirport* Transition::airport() const
{
return _parent->airport();
}
void Transition::mark(WayptFlag f)
{
markWaypoints(_primary, f);
}
} // of namespace

View file

@ -22,6 +22,8 @@
#include <set>
#include <simgear/math/sg_types.hxx> // for string_list
#include <Navaids/route.hxx>
#include <Airports/runways.hxx>
@ -32,12 +34,32 @@ namespace flightgear {
// forward decls
class NavdataVisitor;
class Procedure : public Route
typedef std::vector<FGRunwayRef> RunwayVec;
typedef enum {
PROCEDURE_INVALID,
PROCEDURE_APPROACH_ILS,
PROCEDURE_APPROACH_VOR,
PROCEDURE_APPROACH_NDB,
PROCEDURE_APPROACH_RNAV,
PROCEDURE_SID,
PROCEDURE_STAR,
PROCEDURE_TRANSITION,
PROCEDURE_RUNWAY_TRANSITION
} ProcedureType;
class Procedure : public RouteBase
{
public:
public:
virtual ProcedureType type() const = 0;
virtual std::string ident() const
{ return _ident; }
virtual FGAirport* airport() const = 0;
virtual RunwayVec runways() const
{ return RunwayVec(); }
protected:
Procedure(const std::string& aIdent);
@ -47,14 +69,16 @@ protected:
/**
* Encapsulate a transition segment
*/
class Transition : public Route
class Transition : public Procedure
{
public:
bool route(Waypt* aEnroute, WayptVec& aPath);
bool route(WayptVec& aPath);
Procedure* parent() const
{ return _parent; }
virtual FGAirport* airport() const;
/**
* Return the enroute end of the transition
*/
@ -65,16 +89,19 @@ public:
*/
WayptRef procedureEnd() const;
virtual std::string ident() const
{ return _ident; }
virtual ProcedureType type() const
{ return _type; }
void mark(WayptFlag f);
private:
friend class NavdataVisitor;
Transition(const std::string& aIdent, Procedure* aPr);
Transition(const std::string& aIdent, ProcedureType ty, Procedure* aPr);
void setPrimary(const WayptVec& aWps);
std::string _ident;
ProcedureType _type;
Procedure* _parent;
WayptVec _primary;
};
@ -89,6 +116,12 @@ public:
FGRunwayRef runway()
{ return _runway; }
static bool isApproach(ProcedureType ty);
virtual FGAirport* airport() const;
virtual RunwayVec runways() const;
/**
* Build a route from a valid IAF to the runway, including the missed
* segment. Return false if no valid transition from the specified IAF
@ -108,16 +141,19 @@ public:
const WayptVec& missed() const
{ return _missed; }
virtual ProcedureType type() const
{ return _type; }
private:
friend class NavdataVisitor;
Approach(const std::string& aIdent);
Approach(const std::string& aIdent, ProcedureType ty);
void setRunway(FGRunwayRef aRwy);
void setPrimaryAndMissed(const WayptVec& aPrimary, const WayptVec& aMissed);
void addTransition(Transition* aTrans);
FGRunwayRef _runway;
ProcedureType _type;
typedef std::map<WayptRef, Transition*> WptTransitionMap;
WptTransitionMap _transitions;
@ -129,20 +165,27 @@ private:
class ArrivalDeparture : public Procedure
{
public:
virtual FGAirport* airport() const
{ return _airport; }
/**
* Predicate, test if this procedure applies to the requested runway
*/
virtual bool isForRunway(FGRunwayRef aWay) const;
virtual bool isForRunway(const FGRunway* aWay) const;
virtual RunwayVec runways() const;
/**
* Find a path between the runway and enroute structure. Waypoints
* corresponding to the appropriate transitions and segments will be created.
*/
virtual bool route(FGRunwayRef aWay, Waypt* aEnroute, WayptVec& aPath) = 0;
virtual bool route(FGRunwayRef aWay, Transition* trans, WayptVec& aPath) = 0;
const WayptVec& common() const
{ return _common; }
string_list transitionIdents() const;
/**
* Given an enroute location, find the best enroute transition point for
* this arrival/departure. Best is currently determined as 'closest to the
@ -155,14 +198,14 @@ public:
* for the route-manager and similar code that that needs to talk about
* transitions in a human-meaningful way (including persistence).
*/
WayptRef findTransitionByName(const std::string& aIdent) const;
Transition* findTransitionByName(const std::string& aIdent) const;
Transition* findTransitionByEnroute(Waypt* aEnroute) const;
protected:
bool commonRoute(Waypt* aEnroute, WayptVec& aPath, FGRunwayRef aRwy);
bool commonRoute(Transition* t, WayptVec& aPath, FGRunwayRef aRwy);
ArrivalDeparture(const std::string& aIdent);
ArrivalDeparture(const std::string& aIdent, FGAirport* apt);
void addRunway(FGRunwayRef aRwy);
@ -170,6 +213,7 @@ protected:
typedef std::map<FGRunwayRef, Transition*> RunwayTransitionMap;
RunwayTransitionMap _runways;
virtual WayptFlag flagType() const = 0;
private:
friend class NavdataVisitor;
@ -179,6 +223,7 @@ private:
void addRunwayTransition(FGRunwayRef aRwy, Transition* aTrans);
FGAirport* _airport;
WayptVec _common;
typedef std::map<WayptRef, Transition*> WptTransitionMap;
@ -190,23 +235,37 @@ private:
class SID : public ArrivalDeparture
{
public:
virtual bool route(FGRunwayRef aWay, Waypt* aEnroute, WayptVec& aPath);
virtual bool route(FGRunwayRef aWay, Transition* aTrans, WayptVec& aPath);
virtual ProcedureType type() const
{ return PROCEDURE_SID; }
protected:
virtual WayptFlag flagType() const
{ return WPT_DEPARTURE; }
private:
friend class NavdataVisitor;
SID(const std::string& aIdent);
SID(const std::string& aIdent, FGAirport* apt);
};
class STAR : public ArrivalDeparture
{
public:
virtual bool route(FGRunwayRef aWay, Waypt* aEnroute, WayptVec& aPath);
virtual bool route(FGRunwayRef aWay, Transition* aTrans, WayptVec& aPath);
virtual ProcedureType type() const
{ return PROCEDURE_STAR; }
protected:
virtual WayptFlag flagType() const
{ return WPT_ARRIVAL; }
private:
friend class NavdataVisitor;
STAR(const std::string& aIdent);
STAR(const std::string& aIdent, FGAirport* apt);
};
} // of namespace

File diff suppressed because it is too large Load diff

View file

@ -39,16 +39,22 @@
// forward decls
class FGPositioned;
class SGPath;
class FGAirport;
class FGRunway;
#include <Airports/simple.hxx>
typedef SGSharedPtr<FGAirport> FGAirportRef;
namespace flightgear
{
// forward decls
class Route;
class RouteBase;
class Waypt;
class NavdataVisitor;
class SID;
class STAR;
class Transition;
typedef SGSharedPtr<Waypt> WayptRef;
typedef enum {
@ -66,7 +72,12 @@ typedef enum {
WPT_GENERATED = 1 << 7,
WPT_DEPARTURE = 1 << 8,
WPT_ARRIVAL = 1 << 9
WPT_ARRIVAL = 1 << 9,
/// waypoint generated by VNAV / speed management profile,
/// for step climbs or top of descent
WPT_PSEUDO = 1 << 10,
WPT_APPROACH = 1 << 11
} WayptFlag;
typedef enum {
@ -74,9 +85,14 @@ typedef enum {
RESTRICT_AT,
RESTRICT_ABOVE,
RESTRICT_BELOW,
SPEED_RESTRICT_MACH
SPEED_RESTRICT_MACH, ///< encode an 'AT' restriction in Mach, not IAS
RESTRICT_DELETE, ///< ignore underlying restriction (on a leg)
RESTRICT_COMPUTED, ///< data is computed, not a real restriction
SPEED_COMPUTED_MACH ///< variant on above to encode a Mach value
} RouteRestriction;
bool isMachRestrict(RouteRestriction rr);
/**
* Abstract base class for waypoints (and things that are treated similarly
* by navigation systems)
@ -86,7 +102,7 @@ class Waypt : public SGReferenced
public:
virtual ~Waypt();
Route* owner() const
RouteBase* owner() const
{ return _owner; }
/**
@ -140,7 +156,7 @@ public:
/**
* Factory method
*/
static WayptRef createFromProperties(Route* aOwner, SGPropertyNode_ptr aProp);
static WayptRef createFromProperties(RouteBase* aOwner, SGPropertyNode_ptr aProp);
void saveAsNode(SGPropertyNode* node) const;
@ -173,7 +189,7 @@ public:
protected:
friend class NavdataVisitor;
Waypt(Route* aOwner);
Waypt(RouteBase* aOwner);
/**
* Persistence helper - read node properties from a file
@ -185,7 +201,7 @@ protected:
*/
virtual void writeToProperties(SGPropertyNode_ptr aProp) const;
typedef Waypt* (FactoryFunction)(Route* aOwner) ;
typedef Waypt* (FactoryFunction)(RouteBase* aOwner) ;
static void registerFactory(const std::string aNodeType, FactoryFunction* aFactory);
double _altitudeFt;
@ -197,16 +213,16 @@ private:
/**
* Create an instance of a concrete subclass, or throw an exception
*/
static Waypt* createInstance(Route* aOwner, const std::string& aTypeName);
static Waypt* createInstance(RouteBase* aOwner, const std::string& aTypeName);
Route* _owner;
RouteBase* _owner;
unsigned short _flags;
mutable double _magVarDeg;
};
typedef std::vector<WayptRef> WayptVec;
class Route
class RouteBase
{
public:
/**
@ -216,14 +232,219 @@ public:
static void loadAirportProcedures(const SGPath& aPath, FGAirport* aApt);
static void dumpRouteToFile(const WayptVec& aRoute, const std::string& aName);
static void dumpRouteToKML(const WayptVec& aRoute, const std::string& aName);
static void dumpRouteToLineString(const std::string& aIdent,
static void dumpRouteToKMLLineString(const std::string& aIdent,
const WayptVec& aRoute, std::ostream& aStream);
private:
};
class FlightPlan : public RouteBase
{
public:
FlightPlan();
virtual ~FlightPlan();
virtual std::string ident() const;
void setIdent(const std::string& s);
FlightPlan* clone(const std::string& newIdent = std::string()) const;
/**
* flight-plan leg encapsulation
*/
class Leg
{
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 speed() const;
int speedKts() const;
double speedMach() 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;
int _altitudeFt;
WayptRef _waypt;
/// length of this leg following the flown path
mutable double _pathDistance;
mutable double _courseDeg;
/// total distance of this leg from departure point
mutable double _distanceAlongPath;
};
class Delegate
{
public:
virtual ~Delegate();
virtual void departureChanged() { }
virtual void arrivalChanged() { }
virtual void waypointsChanged() { }
virtual void currentWaypointChanged() { }
protected:
Delegate();
private:
void removeInner(Delegate* d);
void runDepartureChanged();
void runArrivalChanged();
void runWaypointsChanged();
void runCurrentWaypointChanged();
friend class FlightPlan;
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);
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;
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; }
/**
* Create a WayPoint from a string in the following format:
* - simple identifier
* - decimal-lon,decimal-lat
* - airport-id/runway-id
* - navaid/radial-deg/offset-nm
*/
WayptRef waypointFromString(const std::string& target);
void setDelegate(Delegate* d);
void removeDelegate(Delegate* d);
private:
bool loadPlainTextRoute(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;
FGAirportRef _departure, _destination;
FGRunway* _departureRunway, *_destinationRunway;
SID* _sid;
STAR* _star;
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_ROUTE_HXX

View file

@ -53,11 +53,24 @@ double pointsKnownDistanceFromGC(const SGGeoc& a, const SGGeoc&b, const SGGeoc&
RoutePath::RoutePath(const flightgear::WayptVec& wpts) :
_waypts(wpts)
{
commonInit();
}
RoutePath::RoutePath(const flightgear::FlightPlan* fp)
{
for (int l=0; l<fp->numLegs(); ++l) {
_waypts.push_back(fp->legAtIndex(l)->waypoint());
}
commonInit();
}
void RoutePath::commonInit()
{
_pathClimbFPM = 1200;
_pathDescentFPM = 800;
_pathIAS = 190;
_pathTurnRate = 3.0; // 3 deg/sec = 180def/min = standard rate turn
_pathTurnRate = 3.0; // 3 deg/sec = 180def/min = standard rate turn
}
SGGeodVec RoutePath::pathForIndex(int index) const

View file

@ -37,12 +37,15 @@ class RoutePath
{
public:
RoutePath(const flightgear::WayptVec& wpts);
RoutePath(const flightgear::FlightPlan* fp);
SGGeodVec pathForIndex(int index) const;
SGGeod positionForIndex(int index) const;
private:
void commonInit();
class PathCtx;
SGGeodVec pathForHold(flightgear::Hold* hold) const;

View file

@ -34,7 +34,7 @@ using std::string;
namespace flightgear
{
BasicWaypt::BasicWaypt(const SGGeod& aPos, const string& aIdent, Route* aOwner) :
BasicWaypt::BasicWaypt(const SGGeod& aPos, const string& aIdent, RouteBase* aOwner) :
Waypt(aOwner),
_pos(aPos),
_ident(aIdent)
@ -44,14 +44,14 @@ BasicWaypt::BasicWaypt(const SGGeod& aPos, const string& aIdent, Route* aOwner)
}
}
BasicWaypt::BasicWaypt(const SGWayPoint& aWP, Route* aOwner) :
BasicWaypt::BasicWaypt(const SGWayPoint& aWP, RouteBase* aOwner) :
Waypt(aOwner),
_pos(aWP.get_target()),
_ident(aWP.get_id())
{
}
BasicWaypt::BasicWaypt(Route* aOwner) :
BasicWaypt::BasicWaypt(RouteBase* aOwner) :
Waypt(aOwner)
{
}
@ -81,7 +81,7 @@ void BasicWaypt::writeToProperties(SGPropertyNode_ptr aProp) const
//////////////////////////////////////////////////////////////////////////////
NavaidWaypoint::NavaidWaypoint(FGPositioned* aPos, Route* aOwner) :
NavaidWaypoint::NavaidWaypoint(FGPositioned* aPos, RouteBase* aOwner) :
Waypt(aOwner),
_navaid(aPos)
{
@ -90,7 +90,7 @@ NavaidWaypoint::NavaidWaypoint(FGPositioned* aPos, Route* aOwner) :
}
}
NavaidWaypoint::NavaidWaypoint(Route* aOwner) :
NavaidWaypoint::NavaidWaypoint(RouteBase* aOwner) :
Waypt(aOwner)
{
}
@ -142,7 +142,7 @@ void NavaidWaypoint::writeToProperties(SGPropertyNode_ptr aProp) const
aProp->setDoubleValue("lat", _navaid->geod().getLatitudeDeg());
}
OffsetNavaidWaypoint::OffsetNavaidWaypoint(FGPositioned* aPos, Route* aOwner,
OffsetNavaidWaypoint::OffsetNavaidWaypoint(FGPositioned* aPos, RouteBase* aOwner,
double aRadial, double aDistNm) :
NavaidWaypoint(aPos, aOwner),
_radial(aRadial),
@ -151,7 +151,7 @@ OffsetNavaidWaypoint::OffsetNavaidWaypoint(FGPositioned* aPos, Route* aOwner,
init();
}
OffsetNavaidWaypoint::OffsetNavaidWaypoint(Route* aOwner) :
OffsetNavaidWaypoint::OffsetNavaidWaypoint(RouteBase* aOwner) :
NavaidWaypoint(aOwner)
{
}
@ -186,13 +186,13 @@ void OffsetNavaidWaypoint::writeToProperties(SGPropertyNode_ptr aProp) const
/////////////////////////////////////////////////////////////////////////////
RunwayWaypt::RunwayWaypt(FGRunway* aPos, Route* aOwner) :
RunwayWaypt::RunwayWaypt(FGRunway* aPos, RouteBase* aOwner) :
Waypt(aOwner),
_runway(aPos)
{
}
RunwayWaypt::RunwayWaypt(Route* aOwner) :
RunwayWaypt::RunwayWaypt(RouteBase* aOwner) :
Waypt(aOwner)
{
}
@ -239,7 +239,7 @@ void RunwayWaypt::writeToProperties(SGPropertyNode_ptr aProp) const
/////////////////////////////////////////////////////////////////////////////
Hold::Hold(const SGGeod& aPos, const string& aIdent, Route* aOwner) :
Hold::Hold(const SGGeod& aPos, const string& aIdent, RouteBase* aOwner) :
BasicWaypt(aPos, aIdent, aOwner),
_righthanded(true),
_isDistance(false)
@ -247,7 +247,7 @@ Hold::Hold(const SGGeod& aPos, const string& aIdent, Route* aOwner) :
setFlag(WPT_DYNAMIC);
}
Hold::Hold(Route* aOwner) :
Hold::Hold(RouteBase* aOwner) :
BasicWaypt(aOwner),
_righthanded(true),
_isDistance(false)
@ -308,7 +308,7 @@ void Hold::writeToProperties(SGPropertyNode_ptr aProp) const
/////////////////////////////////////////////////////////////////////////////
HeadingToAltitude::HeadingToAltitude(Route* aOwner, const string& aIdent,
HeadingToAltitude::HeadingToAltitude(RouteBase* aOwner, const string& aIdent,
double aMagHdg) :
Waypt(aOwner),
_ident(aIdent),
@ -317,7 +317,7 @@ HeadingToAltitude::HeadingToAltitude(Route* aOwner, const string& aIdent,
setFlag(WPT_DYNAMIC);
}
HeadingToAltitude::HeadingToAltitude(Route* aOwner) :
HeadingToAltitude::HeadingToAltitude(RouteBase* aOwner) :
Waypt(aOwner)
{
}
@ -343,7 +343,7 @@ void HeadingToAltitude::writeToProperties(SGPropertyNode_ptr aProp) const
/////////////////////////////////////////////////////////////////////////////
DMEIntercept::DMEIntercept(Route* aOwner, const string& aIdent, const SGGeod& aPos,
DMEIntercept::DMEIntercept(RouteBase* aOwner, const string& aIdent, const SGGeod& aPos,
double aCourseDeg, double aDistanceNm) :
Waypt(aOwner),
_ident(aIdent),
@ -354,7 +354,7 @@ DMEIntercept::DMEIntercept(Route* aOwner, const string& aIdent, const SGGeod& aP
setFlag(WPT_DYNAMIC);
}
DMEIntercept::DMEIntercept(Route* aOwner) :
DMEIntercept::DMEIntercept(RouteBase* aOwner) :
Waypt(aOwner)
{
}
@ -388,7 +388,7 @@ void DMEIntercept::writeToProperties(SGPropertyNode_ptr aProp) const
/////////////////////////////////////////////////////////////////////////////
RadialIntercept::RadialIntercept(Route* aOwner, const string& aIdent, const SGGeod& aPos,
RadialIntercept::RadialIntercept(RouteBase* aOwner, const string& aIdent, const SGGeod& aPos,
double aCourseDeg, double aRadial) :
Waypt(aOwner),
_ident(aIdent),
@ -399,7 +399,7 @@ RadialIntercept::RadialIntercept(Route* aOwner, const string& aIdent, const SGGe
setFlag(WPT_DYNAMIC);
}
RadialIntercept::RadialIntercept(Route* aOwner) :
RadialIntercept::RadialIntercept(RouteBase* aOwner) :
Waypt(aOwner)
{
}
@ -433,7 +433,7 @@ void RadialIntercept::writeToProperties(SGPropertyNode_ptr aProp) const
/////////////////////////////////////////////////////////////////////////////
ATCVectors::ATCVectors(Route* aOwner, FGAirport* aFacility) :
ATCVectors::ATCVectors(RouteBase* aOwner, FGAirport* aFacility) :
Waypt(aOwner),
_facility(aFacility)
{
@ -444,7 +444,7 @@ ATCVectors::~ATCVectors()
{
}
ATCVectors::ATCVectors(Route* aOwner) :
ATCVectors::ATCVectors(RouteBase* aOwner) :
Waypt(aOwner)
{
}

View file

@ -36,11 +36,11 @@ class BasicWaypt : public Waypt
{
public:
BasicWaypt(const SGGeod& aPos, const std::string& aIdent, Route* aOwner);
BasicWaypt(const SGGeod& aPos, const std::string& aIdent, RouteBase* aOwner);
BasicWaypt(const SGWayPoint& aWP, Route* aOwner);
BasicWaypt(const SGWayPoint& aWP, RouteBase* aOwner);
BasicWaypt(Route* aOwner);
BasicWaypt(RouteBase* aOwner);
virtual SGGeod position() const
{ return _pos; }
@ -67,9 +67,9 @@ protected:
class NavaidWaypoint : public Waypt
{
public:
NavaidWaypoint(FGPositioned* aPos, Route* aOwner);
NavaidWaypoint(FGPositioned* aPos, RouteBase* aOwner);
NavaidWaypoint(Route* aOwner);
NavaidWaypoint(RouteBase* aOwner);
virtual SGGeod position() const;
@ -90,9 +90,9 @@ protected:
class OffsetNavaidWaypoint : public NavaidWaypoint
{
public:
OffsetNavaidWaypoint(FGPositioned* aPos, Route* aOwner, double aRadial, double aDistNm);
OffsetNavaidWaypoint(FGPositioned* aPos, RouteBase* aOwner, double aRadial, double aDistNm);
OffsetNavaidWaypoint(Route* aOwner);
OffsetNavaidWaypoint(RouteBase* aOwner);
virtual SGGeod position() const
{ return _geod; }
@ -120,9 +120,9 @@ private:
class RunwayWaypt : public Waypt
{
public:
RunwayWaypt(FGRunway* aPos, Route* aOwner);
RunwayWaypt(FGRunway* aPos, RouteBase* aOwner);
RunwayWaypt(Route* aOwner);
RunwayWaypt(RouteBase* aOwner);
virtual SGGeod position() const;
@ -148,9 +148,9 @@ private:
class Hold : public BasicWaypt
{
public:
Hold(const SGGeod& aPos, const std::string& aIdent, Route* aOwner);
Hold(const SGGeod& aPos, const std::string& aIdent, RouteBase* aOwner);
Hold(Route* aOwner);
Hold(RouteBase* aOwner);
void setHoldRadial(double aInboundRadial);
void setHoldDistance(double aDistanceNm);
@ -190,9 +190,9 @@ private:
class HeadingToAltitude : public Waypt
{
public:
HeadingToAltitude(Route* aOwner, const std::string& aIdent, double aMagHdg);
HeadingToAltitude(RouteBase* aOwner, const std::string& aIdent, double aMagHdg);
HeadingToAltitude(Route* aOwner);
HeadingToAltitude(RouteBase* aOwner);
virtual void initFromProperties(SGPropertyNode_ptr aProp);
virtual void writeToProperties(SGPropertyNode_ptr aProp) const;
@ -222,10 +222,10 @@ private:
class DMEIntercept : public Waypt
{
public:
DMEIntercept(Route* aOwner, const std::string& aIdent, const SGGeod& aPos,
DMEIntercept(RouteBase* aOwner, const std::string& aIdent, const SGGeod& aPos,
double aCourseDeg, double aDistanceNm);
DMEIntercept(Route* aOwner);
DMEIntercept(RouteBase* aOwner);
virtual void initFromProperties(SGPropertyNode_ptr aProp);
virtual void writeToProperties(SGPropertyNode_ptr aProp) const;
@ -257,10 +257,10 @@ private:
class RadialIntercept : public Waypt
{
public:
RadialIntercept(Route* aOwner, const std::string& aIdent, const SGGeod& aPos,
RadialIntercept(RouteBase* aOwner, const std::string& aIdent, const SGGeod& aPos,
double aCourseDeg, double aRadialDeg);
RadialIntercept(Route* aOwner);
RadialIntercept(RouteBase* aOwner);
virtual void initFromProperties(SGPropertyNode_ptr aProp);
virtual void writeToProperties(SGPropertyNode_ptr aProp) const;
@ -295,10 +295,10 @@ private:
class ATCVectors : public Waypt
{
public:
ATCVectors(Route* aOwner, FGAirport* aFacility);
ATCVectors(RouteBase* aOwner, FGAirport* aFacility);
virtual ~ATCVectors();
ATCVectors(Route* aOwner);
ATCVectors(RouteBase* aOwner);
virtual void initFromProperties(SGPropertyNode_ptr aProp);
virtual void writeToProperties(SGPropertyNode_ptr aProp) const;

View file

@ -27,6 +27,7 @@
#include "NasalPositioned.hxx"
#include <boost/foreach.hpp>
#include <boost/algorithm/string/case_conv.hpp>
#include <simgear/sg_inlines.h>
#include <simgear/scene/material/mat.hxx>
@ -48,8 +49,13 @@
#include <Autopilot/route_mgr.hxx>
#include <Navaids/procedure.hxx>
using namespace flightgear;
static void positionedGhostDestroy(void* g);
static void wayptGhostDestroy(void* g);
static void legGhostDestroy(void* g);
static void routeBaseGhostDestroy(void* g);
naGhostType PositionedGhostType = { positionedGhostDestroy, "positioned" };
static const char* airportGhostGetMember(naContext c, void* g, naRef field, naRef* out);
@ -62,12 +68,32 @@ static const char* runwayGhostGetMember(naContext c, void* g, naRef field, naRef
naGhostType RunwayGhostType = { positionedGhostDestroy, "runway", runwayGhostGetMember, 0 };
static const char* wayptGhostGetMember(naContext c, void* g, naRef field, naRef* out);
naGhostType WayptGhostType = { wayptGhostDestroy,
"waypoint",
wayptGhostGetMember,
0};
static const char* legGhostGetMember(naContext c, void* g, naRef field, naRef* out);
naGhostType FPLegGhostType = { legGhostDestroy,
"flightplan-leg",
legGhostGetMember,
0};
static const char* flightplanGhostGetMember(naContext c, void* g, naRef field, naRef* out);
static void flightplanGhostSetMember(naContext c, void* g, naRef field, naRef value);
naGhostType FlightPlanGhostType = { routeBaseGhostDestroy,
"flightplan",
flightplanGhostGetMember,
flightplanGhostSetMember
};
static const char* procedureGhostGetMember(naContext c, void* g, naRef field, naRef* out);
naGhostType ProcedureGhostType = { routeBaseGhostDestroy,
"procedure",
procedureGhostGetMember,
0};
static void hashset(naContext c, naRef hash, const char* key, naRef val)
{
naRef s = naNewString(c);
@ -117,24 +143,58 @@ static void positionedGhostDestroy(void* g)
delete pos;
}
static flightgear::Waypt* wayptGhost(naRef r)
static Waypt* wayptGhost(naRef r)
{
if (naGhost_type(r) == &WayptGhostType)
return (flightgear::Waypt*) naGhost_ptr(r);
return (Waypt*) naGhost_ptr(r);
return 0;
}
static void wayptGhostDestroy(void* g)
{
flightgear::Waypt* wpt = (flightgear::Waypt*)g;
if (!flightgear::Waypt::put(wpt)) // unref
Waypt* wpt = (Waypt*)g;
if (!Waypt::put(wpt)) // unref
delete wpt;
}
static void legGhostDestroy(void* g)
{
// nothing for now
}
static FlightPlan::Leg* fpLegGhost(naRef r)
{
if (naGhost_type(r) == &FPLegGhostType)
return (FlightPlan::Leg*) naGhost_ptr(r);
return 0;
}
static Procedure* procedureGhost(naRef r)
{
if (naGhost_type(r) == &ProcedureGhostType)
return (Procedure*) naGhost_ptr(r);
return 0;
}
static FlightPlan* flightplanGhost(naRef r)
{
if (naGhost_type(r) == &FlightPlanGhostType)
return (FlightPlan*) naGhost_ptr(r);
return 0;
}
static void routeBaseGhostDestroy(void* g)
{
// nothing for now
}
static naRef airportPrototype;
static naRef routePrototype;
static naRef flightplanPrototype;
static naRef waypointPrototype;
static naRef geoCoordClass;
static naRef fpLegPrototype;
static naRef procedurePrototype;
naRef ghostForPositioned(naContext c, const FGPositioned* pos)
{
@ -176,16 +236,43 @@ naRef ghostForRunway(naContext c, const FGRunway* r)
return naNewGhost2(c, &RunwayGhostType, (void*) r);
}
naRef ghostForWaypt(naContext c, const flightgear::Waypt* wpt)
naRef ghostForWaypt(naContext c, const Waypt* wpt)
{
if (!wpt) {
return naNil();
}
flightgear::Waypt::get(wpt); // take a ref
Waypt::get(wpt); // take a ref
return naNewGhost2(c, &WayptGhostType, (void*) wpt);
}
naRef ghostForLeg(naContext c, const FlightPlan::Leg* leg)
{
if (!leg) {
return naNil();
}
return naNewGhost2(c, &FPLegGhostType, (void*) leg);
}
naRef ghostForFlightPlan(naContext c, const FlightPlan* fp)
{
if (!fp) {
return naNil();
}
return naNewGhost2(c, &FlightPlanGhostType, (void*) fp);
}
naRef ghostForProcedure(naContext c, const Procedure* proc)
{
if (!proc) {
return naNil();
}
return naNewGhost2(c, &ProcedureGhostType, (void*) proc);
}
static const char* airportGhostGetMember(naContext c, void* g, naRef field, naRef* out)
{
const char* fieldName = naStr_data(field);
@ -218,43 +305,299 @@ static const char* airportGhostGetMember(naContext c, void* g, naRef field, naRe
return "";
}
static const char* wayptGhostGetMember(naContext c, void* g, naRef field, naRef* out)
static const char* waypointCommonGetMember(naContext c, Waypt* wpt, const char* fieldName, naRef* out)
{
const char* fieldName = naStr_data(field);
flightgear::Waypt* wpt = (flightgear::Waypt*) g;
if (!strcmp(fieldName, "parents")) {
*out = naNewVector(c);
naVec_append(*out, waypointPrototype);
} else if (!strcmp(fieldName, "wp_name")) *out =stringToNasal(c, wpt->ident());
if (!strcmp(fieldName, "wp_name")) *out = stringToNasal(c, wpt->ident());
else if (!strcmp(fieldName, "wp_type")) *out = stringToNasal(c, wpt->type());
else if (!strcmp(fieldName, "wp_lat")) *out = naNum(wpt->position().getLatitudeDeg());
else if (!strcmp(fieldName, "wp_lon")) *out = naNum(wpt->position().getLongitudeDeg());
else if (!strcmp(fieldName, "wp_parent_name")) {
flightgear::Procedure* proc = dynamic_cast<flightgear::Procedure*>(wpt->owner());
Procedure* proc = dynamic_cast<Procedure*>(wpt->owner());
*out = proc ? stringToNasal(c, proc->ident()) : naNil();
} else if (!strcmp(fieldName, "wp_parent")) {
Procedure* proc = dynamic_cast<Procedure*>(wpt->owner());
*out = ghostForProcedure(c, proc);
} else if (!strcmp(fieldName, "fly_type")) {
if (wpt->type() == "hold") {
*out = stringToNasal(c, "Hold");
} else {
*out = stringToNasal(c, wpt->flag(flightgear::WPT_OVERFLIGHT) ? "flyOver" : "flyBy");
*out = stringToNasal(c, wpt->flag(WPT_OVERFLIGHT) ? "flyOver" : "flyBy");
}
} else if (!strcmp(fieldName, "alt_cstr")) *out = naNum(wpt->altitudeFt());
else if (!strcmp(fieldName, "speed_cstr")) {
double s = (wpt->speedRestriction() == flightgear::SPEED_RESTRICT_MACH)
? wpt->speedMach() : wpt->speedKts();
*out = naNum(s);
} else if (!strcmp(fieldName, "leg_distance")) {
return "please implement me";
} else if (!strcmp(fieldName, "leg_bearing")) {
return "please implement me";
} else {
return NULL; // member not found
}
return "";
}
static const char* wayptGhostGetMember(naContext c, void* g, naRef field, naRef* out)
{
const char* fieldName = naStr_data(field);
Waypt* wpt = (flightgear::Waypt*) g;
return waypointCommonGetMember(c, wpt, fieldName, out);
}
static RouteRestriction routeRestrictionFromString(const char* s)
{
string u(s);
boost::to_lower(u);
if (u == "computed") return RESTRICT_COMPUTED;
if (u == "at") return RESTRICT_AT;
if (u == "mach") return SPEED_RESTRICT_MACH;
if (u == "computed-mach") return SPEED_COMPUTED_MACH;
if (u == "delete") return RESTRICT_DELETE;
return RESTRICT_NONE;
};
naRef routeRestrictionToNasal(naContext c, RouteRestriction rr)
{
switch (rr) {
case RESTRICT_NONE: return naNil();
case RESTRICT_AT: return stringToNasal(c, "at");
case RESTRICT_ABOVE: return stringToNasal(c, "above");
case RESTRICT_BELOW: return stringToNasal(c, "below");
case SPEED_RESTRICT_MACH: return stringToNasal(c, "mach");
case RESTRICT_COMPUTED: return stringToNasal(c, "computed");
case SPEED_COMPUTED_MACH: return stringToNasal(c, "computed-mach");
case RESTRICT_DELETE: return stringToNasal(c, "delete");
}
return naNil();
}
static const char* legGhostGetMember(naContext c, void* g, naRef field, naRef* out)
{
const char* fieldName = naStr_data(field);
FlightPlan::Leg* leg = (FlightPlan::Leg*) g;
Waypt* wpt = leg->waypoint();
if (!strcmp(fieldName, "parents")) {
*out = naNewVector(c);
naVec_append(*out, fpLegPrototype);
} else if (!strcmp(fieldName, "alt_cstr")) {
*out = naNum(leg->altitudeFt());
} else if (!strcmp(fieldName, "alt_cstr_type")) {
*out = routeRestrictionToNasal(c, leg->altitudeRestriction());
} else if (!strcmp(fieldName, "speed_cstr")) {
double s = isMachRestrict(leg->speedRestriction()) ? leg->speedMach() : leg->speedKts();
*out = naNum(s);
} else if (!strcmp(fieldName, "speed_cstr_type")) {
*out = routeRestrictionToNasal(c, leg->speedRestriction());
} else if (!strcmp(fieldName, "leg_distance")) {
*out = naNum(leg->distanceNm());
} else if (!strcmp(fieldName, "leg_bearing")) {
*out = naNum(leg->courseDeg());
} else if (!strcmp(fieldName, "distance_along_route")) {
*out = naNum(leg->distanceAlongRoute());
} else { // check for fields defined on the underlying waypoint
return waypointCommonGetMember(c, wpt, fieldName, out);
}
return ""; // success
}
static const char* flightplanGhostGetMember(naContext c, void* g, naRef field, naRef* out)
{
const char* fieldName = naStr_data(field);
FlightPlan* fp = (FlightPlan*) g;
if (!strcmp(fieldName, "parents")) {
*out = naNewVector(c);
naVec_append(*out, flightplanPrototype);
} else if (!strcmp(fieldName, "id")) *out = stringToNasal(c, fp->ident());
else if (!strcmp(fieldName, "departure")) *out = ghostForAirport(c, fp->departureAirport());
else if (!strcmp(fieldName, "destination")) *out = ghostForAirport(c, fp->destinationAirport());
else if (!strcmp(fieldName, "departure_runway")) *out = ghostForRunway(c, fp->departureRunway());
else if (!strcmp(fieldName, "destination_runway")) *out = ghostForRunway(c, fp->destinationRunway());
else if (!strcmp(fieldName, "sid")) *out = ghostForProcedure(c, fp->sid());
else if (!strcmp(fieldName, "sid_trans")) *out = ghostForProcedure(c, fp->sidTransition());
else if (!strcmp(fieldName, "star")) *out = ghostForProcedure(c, fp->star());
else if (!strcmp(fieldName, "star_trans")) *out = ghostForProcedure(c, fp->starTransition());
else if (!strcmp(fieldName, "approach")) *out = ghostForProcedure(c, fp->approach());
else if (!strcmp(fieldName, "current")) *out = naNum(fp->currentIndex());
else {
return 0;
}
return "";
}
static void flightplanGhostSetMember(naContext c, void* g, naRef field, naRef value)
{
const char* fieldName = naStr_data(field);
FlightPlan* fp = (FlightPlan*) g;
if (!strcmp(fieldName, "id")) {
if (!naIsString(value)) naRuntimeError(c, "flightplan.id must be a string");
fp->setIdent(naStr_data(value));
} else if (!strcmp(fieldName, "current")) {
int index = value.num;
if ((index < 0) || (index >= fp->numLegs())) {
return;
}
fp->setCurrentIndex(index);
} else if (!strcmp(fieldName, "departure")) {
FGAirport* apt = airportGhost(value);
if (apt) {
fp->setDeparture(apt);
return;
}
FGRunway* rwy = runwayGhost(value);
if (rwy){
fp->setDeparture(rwy);
return;
}
naRuntimeError(c, "bad argument type setting departure");
} else if (!strcmp(fieldName, "destination")) {
FGAirport* apt = airportGhost(value);
if (apt) {
fp->setDestination(apt);
return;
}
FGRunway* rwy = runwayGhost(value);
if (rwy){
fp->setDestination(rwy);
return;
}
naRuntimeError(c, "bad argument type setting destination");
} else if (!strcmp(fieldName, "departure_runway")) {
FGRunway* rwy = runwayGhost(value);
if (rwy){
fp->setDeparture(rwy);
return;
}
naRuntimeError(c, "bad argument type setting departure");
} else if (!strcmp(fieldName, "destination_runway")) {
FGRunway* rwy = runwayGhost(value);
if (rwy){
fp->setDestination(rwy);
return;
}
naRuntimeError(c, "bad argument type setting departure");
} else if (!strcmp(fieldName, "sid")) {
Procedure* proc = procedureGhost(value);
if (proc && (proc->type() == PROCEDURE_SID)) {
fp->setSID((SID*) proc);
return;
}
// allow a SID transition to be set, implicitly include the SID itself
if (proc && (proc->type() == PROCEDURE_TRANSITION)) {
fp->setSID((Transition*) proc);
return;
}
if (naIsString(value)) {
FGAirport* apt = fp->departureAirport();
fp->setSID(apt->findSIDWithIdent(naStr_data(value)));
return;
}
naRuntimeError(c, "bad argument type setting SID");
} else if (!strcmp(fieldName, "star")) {
Procedure* proc = procedureGhost(value);
if (proc && (proc->type() == PROCEDURE_STAR)) {
fp->setSTAR((STAR*) proc);
return;
}
if (proc && (proc->type() == PROCEDURE_TRANSITION)) {
fp->setSTAR((Transition*) proc);
return;
}
if (naIsString(value)) {
FGAirport* apt = fp->destinationAirport();
fp->setSTAR(apt->findSTARWithIdent(naStr_data(value)));
return;
}
naRuntimeError(c, "bad argument type setting STAR");
} else if (!strcmp(fieldName, "approach")) {
Procedure* proc = procedureGhost(value);
if (proc && Approach::isApproach(proc->type())) {
fp->setApproach((Approach*) proc);
return;
}
if (naIsString(value)) {
FGAirport* apt = fp->destinationAirport();
fp->setApproach(apt->findApproachWithIdent(naStr_data(value)));
return;
}
naRuntimeError(c, "bad argument type setting approach");
}
}
static naRef procedureTpType(naContext c, ProcedureType ty)
{
switch (ty) {
case PROCEDURE_SID: return stringToNasal(c, "sid");
case PROCEDURE_STAR: return stringToNasal(c, "star");
case PROCEDURE_APPROACH_VOR:
case PROCEDURE_APPROACH_ILS:
case PROCEDURE_APPROACH_RNAV:
case PROCEDURE_APPROACH_NDB:
return stringToNasal(c, "IAP");
default:
return naNil();
}
}
static naRef procedureRadioType(naContext c, ProcedureType ty)
{
switch (ty) {
case PROCEDURE_APPROACH_VOR: return stringToNasal(c, "VOR");
case PROCEDURE_APPROACH_ILS: return stringToNasal(c, "ILS");
case PROCEDURE_APPROACH_RNAV: return stringToNasal(c, "RNAV");
case PROCEDURE_APPROACH_NDB: return stringToNasal(c, "NDB");
default:
return naNil();
}
}
static const char* procedureGhostGetMember(naContext c, void* g, naRef field, naRef* out)
{
const char* fieldName = naStr_data(field);
Procedure* proc = (Procedure*) g;
if (!strcmp(fieldName, "parents")) {
*out = naNewVector(c);
naVec_append(*out, procedurePrototype);
} else if (!strcmp(fieldName, "id")) *out = stringToNasal(c, proc->ident());
else if (!strcmp(fieldName, "airport")) *out = ghostForAirport(c, proc->airport());
else if (!strcmp(fieldName, "tp_type")) *out = procedureTpType(c, proc->type());
else if (!strcmp(fieldName, "radio")) *out = procedureRadioType(c, proc->type());
else if (!strcmp(fieldName, "runways")) {
*out = naNewVector(c);
BOOST_FOREACH(FGRunwayPtr rwy, proc->runways()) {
naVec_append(*out, stringToNasal(c, rwy->ident()));
}
} else if (!strcmp(fieldName, "transitions")) {
if ((proc->type() != PROCEDURE_SID) && (proc->type() != PROCEDURE_STAR)) {
*out = naNil();
return "";
}
ArrivalDeparture* ad = static_cast<ArrivalDeparture*>(proc);
*out = naNewVector(c);
BOOST_FOREACH(string id, ad->transitionIdents()) {
naVec_append(*out, stringToNasal(c, id));
}
} else {
return 0;
}
return "";
}
static const char* runwayGhostGetMember(naContext c, void* g, naRef field, naRef* out)
{
const char* fieldName = naStr_data(field);
@ -664,6 +1007,7 @@ static naRef f_airport_runway(naContext c, naRef me, int argc, naRef* args)
}
std::string ident(naStr_data(args[0]));
boost::to_upper(ident);
if (!apt->hasRunwayWithIdent(ident)) {
return naNil();
}
@ -680,12 +1024,18 @@ static naRef f_airport_sids(naContext c, naRef me, int argc, naRef* args)
naRef sids = naNewVector(c);
FGRunway* rwy = NULL;
if (argc > 0 && naIsString(args[0])) {
if (!apt->hasRunwayWithIdent(naStr_data(args[0]))) {
return naNil();
}
FGRunway* rwy = apt->getRunwayByIdent(naStr_data(args[0]));
rwy = apt->getRunwayByIdent(naStr_data(args[0]));
} else if (argc > 0) {
rwy = runwayGhost(args[0]);
}
if (rwy) {
BOOST_FOREACH(flightgear::SID* sid, rwy->getSIDs()) {
naRef procId = stringToNasal(c, sid->ident());
naVec_append(sids, procId);
@ -710,12 +1060,18 @@ static naRef f_airport_stars(naContext c, naRef me, int argc, naRef* args)
naRef stars = naNewVector(c);
FGRunway* rwy = NULL;
if (argc > 0 && naIsString(args[0])) {
if (!apt->hasRunwayWithIdent(naStr_data(args[0]))) {
return naNil();
}
FGRunway* rwy = apt->getRunwayByIdent(naStr_data(args[0]));
rwy = apt->getRunwayByIdent(naStr_data(args[0]));
} else if (argc > 0) {
rwy = runwayGhost(args[0]);
}
if (rwy) {
BOOST_FOREACH(flightgear::STAR* s, rwy->getSTARs()) {
naRef procId = stringToNasal(c, s->ident());
naVec_append(stars, procId);
@ -731,6 +1087,61 @@ static naRef f_airport_stars(naContext c, naRef me, int argc, naRef* args)
return stars;
}
static naRef f_airport_approaches(naContext c, naRef me, int argc, naRef* args)
{
FGAirport* apt = airportGhost(me);
if (!apt) {
naRuntimeError(c, "airport.getApproachList called on non-airport object");
}
naRef approaches = naNewVector(c);
ProcedureType ty = PROCEDURE_INVALID;
if ((argc > 1) && naIsString(args[1])) {
std::string u(naStr_data(args[1]));
boost::to_upper(u);
if (u == "NDB") ty = PROCEDURE_APPROACH_NDB;
if (u == "VOR") ty = PROCEDURE_APPROACH_VOR;
if (u == "ILS") ty = PROCEDURE_APPROACH_ILS;
if (u == "RNAV") ty = PROCEDURE_APPROACH_RNAV;
}
FGRunway* rwy = NULL;
if (argc > 0 && (rwy = runwayGhost(args[0]))) {
// ok
} else if (argc > 0 && naIsString(args[0])) {
if (!apt->hasRunwayWithIdent(naStr_data(args[0]))) {
return naNil();
}
rwy = apt->getRunwayByIdent(naStr_data(args[0]));
}
if (rwy) {
BOOST_FOREACH(Approach* s, rwy->getApproaches()) {
if ((ty != PROCEDURE_INVALID) && (s->type() != ty)) {
continue;
}
naRef procId = stringToNasal(c, s->ident());
naVec_append(approaches, procId);
}
} else {
// no runway specified, report them all
for (unsigned int s=0; s<apt->numApproaches(); ++s) {
Approach* app = apt->getApproachByIndex(s);
if ((ty != PROCEDURE_INVALID) && (app->type() != ty)) {
continue;
}
naRef procId = stringToNasal(c, app->ident());
naVec_append(approaches, procId);
}
}
return approaches;
}
static naRef f_airport_parking(naContext c, naRef me, int argc, naRef* args)
{
FGAirport* apt = airportGhost(me);
@ -769,6 +1180,51 @@ static naRef f_airport_parking(naContext c, naRef me, int argc, naRef* args)
return r;
}
static naRef f_airport_getSid(naContext c, naRef me, int argc, naRef* args)
{
FGAirport* apt = airportGhost(me);
if (!apt) {
naRuntimeError(c, "airport.getSid called on non-airport object");
}
if ((argc != 1) || !naIsString(args[0])) {
naRuntimeError(c, "airport.getSid passed invalid argument");
}
string ident = naStr_data(args[0]);
return ghostForProcedure(c, apt->findSIDWithIdent(ident));
}
static naRef f_airport_getStar(naContext c, naRef me, int argc, naRef* args)
{
FGAirport* apt = airportGhost(me);
if (!apt) {
naRuntimeError(c, "airport.getStar called on non-airport object");
}
if ((argc != 1) || !naIsString(args[0])) {
naRuntimeError(c, "airport.getStar passed invalid argument");
}
string ident = naStr_data(args[0]);
return ghostForProcedure(c, apt->findSTARWithIdent(ident));
}
static naRef f_airport_getApproach(naContext c, naRef me, int argc, naRef* args)
{
FGAirport* apt = airportGhost(me);
if (!apt) {
naRuntimeError(c, "airport.getIAP called on non-airport object");
}
if ((argc != 1) || !naIsString(args[0])) {
naRuntimeError(c, "airport.getIAP passed invalid argument");
}
string ident = naStr_data(args[0]);
return ghostForProcedure(c, apt->findApproachWithIdent(ident));
}
// Returns vector of data hash for navaid of a <type>, nil on error
// navaids sorted by ascending distance
// navinfo([<lat>,<lon>],[<type>],[<id>])
@ -1030,62 +1486,233 @@ static naRef f_tileIndex(naContext c, naRef me, int argc, naRef* args)
static naRef f_route(naContext c, naRef me, int argc, naRef* args)
{
naRef route = naNewHash(c);
if (argc == 0) {
FGRouteMgr* rm = static_cast<FGRouteMgr*>(globals->get_subsystem("route-manager"));
return ghostForFlightPlan(c, rm->flightPlan());
}
// return active route hash by default,
// other routes in the future
if ((argc > 0) && naIsString(args[0])) {
flightgear::FlightPlan* fp = new flightgear::FlightPlan;
SGPath path(naStr_data(args[0]));
if (!path.exists()) {
naRuntimeError(c, "flightplan, no file at path %s", path.c_str());
}
if (!fp->load(path)) {
SG_LOG(SG_NASAL, SG_WARN, "failed to load flight-plan from " << path);
delete fp;
return naNil();
}
return ghostForFlightPlan(c, fp);
}
naRef parents = naNewVector(c);
naVec_append(parents, routePrototype);
hashset(c, route, "parents", parents);
return route;
naRuntimeError(c, "bad arguments to flightplan()");
return naNil();
}
static naRef f_route_getWP(naContext c, naRef me, int argc, naRef* args)
static naRef f_flightplan_getWP(naContext c, naRef me, int argc, naRef* args)
{
FGRouteMgr* rm = static_cast<FGRouteMgr*>(globals->get_subsystem("route-manager"));
FlightPlan* fp = flightplanGhost(me);
if (!fp) {
naRuntimeError(c, "flightplan.getWP called on non-flightplan object");
}
int index;
if (argc == 0) {
index = rm->currentIndex();
index = fp->currentIndex();
} else {
index = (int) naNumValue(args[0]).num;
}
if ((index < 0) || (index >= rm->numWaypts())) {
if ((index < 0) || (index >= fp->numLegs())) {
return naNil();
}
return ghostForWaypt(c, rm->wayptAtIndex(index));
return ghostForLeg(c, fp->legAtIndex(index));
}
static naRef f_route_currentWP(naContext c, naRef me, int argc, naRef* args)
static naRef f_flightplan_currentWP(naContext c, naRef me, int argc, naRef* args)
{
FGRouteMgr* rm = static_cast<FGRouteMgr*>(globals->get_subsystem("route-manager"));
return ghostForWaypt(c, rm->currentWaypt());
}
static naRef f_route_nextWP(naContext c, naRef me, int argc, naRef* args)
{
FGRouteMgr* rm = static_cast<FGRouteMgr*>(globals->get_subsystem("route-manager"));
flightgear::WayptRef wp = rm->nextWaypt();
if (!wp) {
return naNil();
FlightPlan* fp = flightplanGhost(me);
if (!fp) {
naRuntimeError(c, "flightplan.currentWP called on non-flightplan object");
}
return ghostForWaypt(c, wp);
return ghostForLeg(c, fp->currentLeg());
}
static naRef f_route_currentIndex(naContext c, naRef me, int argc, naRef* args)
static naRef f_flightplan_nextWP(naContext c, naRef me, int argc, naRef* args)
{
FGRouteMgr* rm = static_cast<FGRouteMgr*>(globals->get_subsystem("route-manager"));
return naNum(rm->currentIndex());
FlightPlan* fp = flightplanGhost(me);
if (!fp) {
naRuntimeError(c, "flightplan.nextWP called on non-flightplan object");
}
return ghostForLeg(c, fp->nextLeg());
}
static naRef f_route_numWaypoints(naContext c, naRef me, int argc, naRef* args)
static naRef f_flightplan_numWaypoints(naContext c, naRef me, int argc, naRef* args)
{
FGRouteMgr* rm = static_cast<FGRouteMgr*>(globals->get_subsystem("route-manager"));
return naNum(rm->numWaypts());
FlightPlan* fp = flightplanGhost(me);
if (!fp) {
naRuntimeError(c, "flightplan.numWaypoints called on non-flightplan object");
}
return naNum(fp->numLegs());
}
static naRef f_flightplan_appendWP(naContext c, naRef me, int argc, naRef* args)
{
FlightPlan* fp = flightplanGhost(me);
if (!fp) {
naRuntimeError(c, "flightplan.appendWP called on non-flightplan object");
}
WayptRef wp = wayptGhost(args[0]);
int index = fp->numLegs();
fp->insertWayptAtIndex(wp.get(), index);
return naNum(index);
}
static naRef f_flightplan_insertWP(naContext c, naRef me, int argc, naRef* args)
{
FlightPlan* fp = flightplanGhost(me);
if (!fp) {
naRuntimeError(c, "flightplan.insertWP called on non-flightplan object");
}
WayptRef wp = wayptGhost(args[0]);
int index = -1; // append
if ((argc > 1) && naIsNum(args[1])) {
index = (int) args[1].num;
}
fp->insertWayptAtIndex(wp.get(), index);
return naNil();
}
static naRef f_flightplan_insertWPAfter(naContext c, naRef me, int argc, naRef* args)
{
FlightPlan* fp = flightplanGhost(me);
if (!fp) {
naRuntimeError(c, "flightplan.insertWPAfter called on non-flightplan object");
}
WayptRef wp = wayptGhost(args[0]);
int index = -1; // append
if ((argc > 1) && naIsNum(args[1])) {
index = (int) args[1].num;
}
fp->insertWayptAtIndex(wp.get(), index + 1);
return naNil();
}
static naRef f_flightplan_insertWaypoints(naContext c, naRef me, int argc, naRef* args)
{
FlightPlan* fp = flightplanGhost(me);
if (!fp) {
naRuntimeError(c, "flightplan.insertWaypoints called on non-flightplan object");
}
WayptVec wps;
if (!naIsVector(args[0])) {
naRuntimeError(c, "flightplan.insertWaypoints expects vector as first arg");
}
int count = naVec_size(args[0]);
for (int i=0; i<count; ++i) {
Waypt* wp = wayptGhost(naVec_get(args[0], i));
if (wp) {
wps.push_back(wp);
}
}
int index = -1; // append
if ((argc > 1) && naIsNum(args[1])) {
index = (int) args[1].num;
}
fp->insertWayptsAtIndex(wps, index);
return naNil();
}
static naRef f_flightplan_clearPlan(naContext c, naRef me, int argc, naRef* args)
{
FlightPlan* fp = flightplanGhost(me);
if (!fp) {
naRuntimeError(c, "flightplan.clearPlan called on non-flightplan object");
}
fp->clear();
return naNil();
}
static WayptFlag wayptFlagFromString(const char* s)
{
if (!strcmp(s, "sid")) return WPT_DEPARTURE;
if (!strcmp(s, "star")) return WPT_ARRIVAL;
if (!strcmp(s, "approach")) return WPT_APPROACH;
if (!strcmp(s, "missed")) return WPT_MISS;
if (!strcmp(s, "pseudo")) return WPT_PSEUDO;
return (WayptFlag) 0;
}
static naRef f_flightplan_clearWPType(naContext c, naRef me, int argc, naRef* args)
{
FlightPlan* fp = flightplanGhost(me);
if (!fp) {
naRuntimeError(c, "flightplan.clearWPType called on non-flightplan object");
}
if (argc < 1) {
naRuntimeError(c, "insufficent args to flightplan.clearWPType");
}
WayptFlag flag = wayptFlagFromString(naStr_data(args[0]));
fp->clearWayptsWithFlag(flag);
return naNil();
}
static naRef f_flightplan_clone(naContext c, naRef me, int argc, naRef* args)
{
FlightPlan* fp = flightplanGhost(me);
if (!fp) {
naRuntimeError(c, "flightplan.clone called on non-flightplan object");
}
return ghostForFlightPlan(c, fp->clone());
}
static naRef f_leg_setSpeed(naContext c, naRef me, int argc, naRef* args)
{
FlightPlan::Leg* leg = fpLegGhost(me);
if (!leg) {
naRuntimeError(c, "leg.setSpeed called on non-flightplan-leg object");
}
if (argc < 2) {
naRuntimeError(c, "bad arguments to leg.setSpeed");
}
RouteRestriction rr = routeRestrictionFromString(naStr_data(args[1]));
leg->setSpeed(rr, args[0].num);
return naNil();
}
static naRef f_leg_setAltitude(naContext c, naRef me, int argc, naRef* args)
{
FlightPlan::Leg* leg = fpLegGhost(me);
if (!leg) {
naRuntimeError(c, "leg.setAltitude called on non-flightplan-leg object");
}
if (argc < 2) {
naRuntimeError(c, "bad arguments to leg.setAltitude");
}
RouteRestriction rr = routeRestrictionFromString(naStr_data(args[1]));
leg->setAltitude(rr, args[0].num);
return naNil();
}
static naRef f_waypoint_navaid(naContext c, naRef me, int argc, naRef* args)
@ -1147,6 +1774,23 @@ static naRef f_waypoint_runway(naContext c, naRef me, int argc, naRef* args)
return ghostForRunway(c, (FGRunway*) pos);
}
static naRef f_procedure_transition(naContext c, naRef me, int argc, naRef* args)
{
Procedure* proc = procedureGhost(me);
if (!proc) {
naRuntimeError(c, "procedure.transition called on non-procedure object");
}
if ((proc->type() != PROCEDURE_SID) && (proc->type() != PROCEDURE_STAR)) {
naRuntimeError(c, "procedure.transition called on non-SID or -STAR");
}
ArrivalDeparture* ad = (ArrivalDeparture*) proc;
Transition* trans = ad->findTransitionByName(naStr_data(args[0]));
return ghostForProcedure(c, trans);
}
// Table of extension functions. Terminate with zeros.
static struct { const char* name; naCFunction func; } funcs[] = {
{ "carttogeod", f_carttogeod },
@ -1160,7 +1804,7 @@ static struct { const char* name; naCFunction func; } funcs[] = {
{ "findNavaidByFrequency", f_findNavaidByFrequency },
{ "findNavaidsByFrequency", f_findNavaidsByFrequency },
{ "findNavaidsByID", f_findNavaidsByIdent },
{ "route", f_route },
{ "flightplan", f_route },
{ "magvar", f_magvar },
{ "courseAndDistance", f_courseAndDistance },
{ "greatCircleMove", f_greatCircleMove },
@ -1180,17 +1824,27 @@ naRef initNasalPositioned(naRef globals, naContext c, naRef gcSave)
hashset(c, airportPrototype, "comms", naNewFunc(c, naNewCCode(c, f_airport_comms)));
hashset(c, airportPrototype, "sids", naNewFunc(c, naNewCCode(c, f_airport_sids)));
hashset(c, airportPrototype, "stars", naNewFunc(c, naNewCCode(c, f_airport_stars)));
hashset(c, airportPrototype, "getApproachList", naNewFunc(c, naNewCCode(c, f_airport_approaches)));
hashset(c, airportPrototype, "parking", naNewFunc(c, naNewCCode(c, f_airport_parking)));
hashset(c, airportPrototype, "getSid", naNewFunc(c, naNewCCode(c, f_airport_getSid)));
hashset(c, airportPrototype, "getStar", naNewFunc(c, naNewCCode(c, f_airport_getStar)));
hashset(c, airportPrototype, "getIAP", naNewFunc(c, naNewCCode(c, f_airport_getApproach)));
routePrototype = naNewHash(c);
hashset(c, gcSave, "routeProto", routePrototype);
flightplanPrototype = naNewHash(c);
hashset(c, gcSave, "flightplanProto", flightplanPrototype);
hashset(c, routePrototype, "getWP", naNewFunc(c, naNewCCode(c, f_route_getWP)));
hashset(c, routePrototype, "currentWP", naNewFunc(c, naNewCCode(c, f_route_currentWP)));
hashset(c, routePrototype, "nextWP", naNewFunc(c, naNewCCode(c, f_route_nextWP)));
hashset(c, routePrototype, "currentIndex", naNewFunc(c, naNewCCode(c, f_route_currentIndex)));
hashset(c, routePrototype, "getPlanSize", naNewFunc(c, naNewCCode(c, f_route_numWaypoints)));
hashset(c, flightplanPrototype, "getWP", naNewFunc(c, naNewCCode(c, f_flightplan_getWP)));
hashset(c, flightplanPrototype, "currentWP", naNewFunc(c, naNewCCode(c, f_flightplan_currentWP)));
hashset(c, flightplanPrototype, "nextWP", naNewFunc(c, naNewCCode(c, f_flightplan_nextWP)));
hashset(c, flightplanPrototype, "getPlanSize", naNewFunc(c, naNewCCode(c, f_flightplan_numWaypoints)));
hashset(c, flightplanPrototype, "appendWP", naNewFunc(c, naNewCCode(c, f_flightplan_appendWP)));
hashset(c, flightplanPrototype, "insertWP", naNewFunc(c, naNewCCode(c, f_flightplan_insertWP)));
hashset(c, flightplanPrototype, "insertWPAfter", naNewFunc(c, naNewCCode(c, f_flightplan_insertWPAfter)));
hashset(c, flightplanPrototype, "insertWaypoints", naNewFunc(c, naNewCCode(c, f_flightplan_insertWaypoints)));
hashset(c, flightplanPrototype, "cleanPlan", naNewFunc(c, naNewCCode(c, f_flightplan_clearPlan)));
hashset(c, flightplanPrototype, "clearWPType", naNewFunc(c, naNewCCode(c, f_flightplan_clearWPType)));
hashset(c, flightplanPrototype, "clone", naNewFunc(c, naNewCCode(c, f_flightplan_clone)));
waypointPrototype = naNewHash(c);
hashset(c, gcSave, "wayptProto", waypointPrototype);
@ -1198,6 +1852,17 @@ naRef initNasalPositioned(naRef globals, naContext c, naRef gcSave)
hashset(c, waypointPrototype, "runway", naNewFunc(c, naNewCCode(c, f_waypoint_runway)));
hashset(c, waypointPrototype, "airport", naNewFunc(c, naNewCCode(c, f_waypoint_airport)));
procedurePrototype = naNewHash(c);
hashset(c, gcSave, "procedureProto", procedurePrototype);
// hashset(c, procedurePrototype, "runwayTransition", naNewFunc(c, naNewCCode(c, f_procedure_runwayTransition)));
hashset(c, procedurePrototype, "transition", naNewFunc(c, naNewCCode(c, f_procedure_transition)));
// hashset(c, procedurePrototype, "buildPath", naNewFunc(c, naNewCCode(c, f_procedure_build)));
fpLegPrototype = naNewHash(c);
hashset(c, gcSave, "fpLegProto", fpLegPrototype);
hashset(c, fpLegPrototype, "setSpeed", naNewFunc(c, naNewCCode(c, f_leg_setSpeed)));
hashset(c, fpLegPrototype, "setAltitude", naNewFunc(c, naNewCCode(c, f_leg_setAltitude)));
for(int i=0; funcs[i].name; i++) {
hashset(c, globals, funcs[i].name,
naNewFunc(c, naNewCCode(c, funcs[i].func)));