diff --git a/src/Airports/apt_loader.cxx b/src/Airports/apt_loader.cxx index c23d491e7..c223890fc 100644 --- a/src/Airports/apt_loader.cxx +++ b/src/Airports/apt_loader.cxx @@ -436,7 +436,7 @@ private: const string& rwy_no(token[1]); int surface_code = atoi( token[7].c_str() ); - cache->insertRunway(FGPositioned::RUNWAY, rwy_no, pos, + cache->insertRunway(FGPositioned::HELIPAD, rwy_no, pos, currentAirportID, heading, length, width, 0.0, 0.0, surface_code); } diff --git a/src/Airports/runwaybase.cxx b/src/Airports/runwaybase.cxx index 9bcee4e42..83c838926 100644 --- a/src/Airports/runwaybase.cxx +++ b/src/Airports/runwaybase.cxx @@ -1,6 +1,6 @@ // runwaybase.cxx -- a base class for runways and taxiways // -// Written by James Turber, started December 2008. +// Written by James Turner, started December 2008. // // Copyright (C) 2000 Curtis L. Olson - http://www.flightgear.org/~curt // diff --git a/src/Airports/runways.cxx b/src/Airports/runways.cxx index 70a2ee1b8..753eaf0d5 100644 --- a/src/Airports/runways.cxx +++ b/src/Airports/runways.cxx @@ -202,3 +202,14 @@ std::vector FGRunway::getApproaches() const return result; } +FGHelipad::FGHelipad(PositionedID aGuid, + PositionedID aAirport, const string& aIdent, + const SGGeod& aGeod, + const double heading, const double length, + const double width, + const int surface_code) : + FGRunwayBase(aGuid, RUNWAY, aIdent, aGeod, + heading, length, width, surface_code), + _airport(aAirport) +{ +} diff --git a/src/Airports/runways.hxx b/src/Airports/runways.hxx index 36f342c00..0c4cd4e37 100644 --- a/src/Airports/runways.hxx +++ b/src/Airports/runways.hxx @@ -134,4 +134,17 @@ public: }; +class FGHelipad : public FGRunwayBase +{ + PositionedID _airport; +public: + FGHelipad(PositionedID aGuid, + PositionedID aAirport, const std::string& rwy_no, + const SGGeod& aGeod, + const double heading, const double length, + const double width, + const int surface_code); +}; + + #endif // _FG_RUNWAYS_HXX diff --git a/src/Airports/simple.cxx b/src/Airports/simple.cxx index 769e4abcc..1ed7e9934 100644 --- a/src/Airports/simple.cxx +++ b/src/Airports/simple.cxx @@ -131,6 +131,12 @@ unsigned int FGAirport::numRunways() const return mRunways.size(); } +unsigned int FGAirport::numHelipads() const +{ + loadHelipads(); + return mHelipads.size(); +} + FGRunway* FGAirport::getRunwayByIndex(unsigned int aIndex) const { loadRunways(); @@ -139,6 +145,14 @@ FGRunway* FGAirport::getRunwayByIndex(unsigned int aIndex) const return (FGRunway*) flightgear::NavDataCache::instance()->loadById(mRunways[aIndex]); } +FGHelipad* FGAirport::getHelipadByIndex(unsigned int aIndex) const +{ + loadHelipads(); + + assert(aIndex >= 0 && aIndex < mHelipads.size()); + return (FGHelipad*) flightgear::NavDataCache::instance()->loadById(mHelipads[aIndex]); +} + bool FGAirport::hasRunwayWithIdent(const string& aIdent) const { return flightgear::NavDataCache::instance()->airportItemWithIdent(guid(), FGPositioned::RUNWAY, aIdent) != 0; @@ -356,6 +370,18 @@ void FGAirport::loadRunways() const mRunways = flightgear::NavDataCache::instance()->airportItemsOfType(guid(), FGPositioned::RUNWAY); } +void FGAirport::loadHelipads() const +{ + if (mHelipadsLoaded) { + return; // already loaded, great + } + + loadSceneryDefinitions(); + + mHelipadsLoaded = true; + mHelipads = flightgear::NavDataCache::instance()->airportItemsOfType(guid(), FGPositioned::HELIPAD); +} + void FGAirport::loadTaxiways() const { if (mTaxiwaysLoaded) { diff --git a/src/Airports/simple.hxx b/src/Airports/simple.hxx index 86045277e..a628712b0 100644 --- a/src/Airports/simple.hxx +++ b/src/Airports/simple.hxx @@ -38,6 +38,7 @@ // forward decls class FGAirportDynamics; class FGRunway; +class FGHelipad; class FGTaxiway; class FGPavement; class SGPropertyNode; @@ -102,7 +103,9 @@ public: FGAirportDynamics *getDynamics(); unsigned int numRunways() const; + unsigned int numHelipads() const; FGRunway* getRunwayByIndex(unsigned int aIndex) const; + FGHelipad* getHelipadByIndex(unsigned int aIndex) const; bool hasRunwayWithIdent(const std::string& aIdent) const; FGRunway* getRunwayByIdent(const std::string& aIdent) const; @@ -245,7 +248,7 @@ private: void validateTowerData() const; /** - * Helper to parse property data loaded from an ICAO.twr.xml filke + * Helper to parse property data loaded from an ICAO.twr.xml file */ void readTowerData(SGPropertyNode* aRoot); @@ -254,16 +257,19 @@ private: FGAirportDynamics *_dynamics; void loadRunways() const; + void loadHelipads() const; void loadTaxiways() const; void loadProcedures() const; mutable bool mTowerDataLoaded; mutable bool mRunwaysLoaded; + mutable bool mHelipadsLoaded; mutable bool mTaxiwaysLoaded; mutable bool mProceduresLoaded; bool mILSDataLoaded; mutable PositionedIDVec mRunways; + mutable PositionedIDVec mHelipads; mutable PositionedIDVec mTaxiways; PositionedIDVec mPavements; diff --git a/src/GUI/MapWidget.cxx b/src/GUI/MapWidget.cxx index a161e822a..778cd72a7 100644 --- a/src/GUI/MapWidget.cxx +++ b/src/GUI/MapWidget.cxx @@ -1195,22 +1195,27 @@ void MapWidget::drawAirport(FGAirport* apt) } for (unsigned int r=0; rnumRunways(); ++r) { - FGRunway* rwy = apt->getRunwayByIndex(r); - if (!rwy->isReciprocal()) { - drawRunwayPre(rwy); - } + FGRunway* rwy = apt->getRunwayByIndex(r); + if (!rwy->isReciprocal()) { + drawRunwayPre(rwy); + } } - for (unsigned int r=0; rnumRunways(); ++r) { - FGRunway* rwy = apt->getRunwayByIndex(r); - if (!rwy->isReciprocal()) { - drawRunway(rwy); - } + for (unsigned int r=0; rnumRunways(); ++r) { + FGRunway* rwy = apt->getRunwayByIndex(r); + if (!rwy->isReciprocal()) { + drawRunway(rwy); + } - if (rwy->ILS()) { - drawILS(false, rwy); - } - } // of runway iteration + if (rwy->ILS()) { + drawILS(false, rwy); + } + } + + for (unsigned int r=0; rnumHelipads(); ++r) { + FGHelipad* hp = apt->getHelipadByIndex(r); + drawHelipad(hp); + } // of runway iteration } @@ -1392,6 +1397,32 @@ void MapWidget::drawTraffic() } // of ai/models iteration } +void MapWidget::drawHelipad(FGHelipad* hp) +{ + SGVec2d pos = project(hp->geod()); + glLineWidth(1.0); + glColor3f(1.0, 1.0, 1.0); + circleAt(pos, 16, 5.0); + + if (validDataForKey(hp)) { + setAnchorForKey(hp, pos); + return; + } + + char buffer[1024]; + ::snprintf(buffer, 1024, "%s\n%03d\n%.0f'", + hp->ident().c_str(), + displayHeading(hp->headingDeg()), + hp->lengthFt()); + + MapData* d = createDataForKey(hp); + d->setText(buffer); + d->setLabel(hp->ident()); + d->setPriority(40); + d->setOffset(MapData::HALIGN_CENTER | MapData::VALIGN_BOTTOM, 8); + d->setAnchor(pos); +} + void MapWidget::drawAIAircraft(const SGPropertyNode* model, const SGGeod& pos, double hdg) { diff --git a/src/GUI/MapWidget.hxx b/src/GUI/MapWidget.hxx index b759602bd..e855a2fce 100644 --- a/src/GUI/MapWidget.hxx +++ b/src/GUI/MapWidget.hxx @@ -13,6 +13,7 @@ // forward decls class FGRouteMgr; class FGRunway; +class FGHelipad; class FGAirport; class FGNavRecord; class FGFix; @@ -58,6 +59,7 @@ private: int scoreAirportRunways(FGAirport* apt); void drawRunwayPre(FGRunway* rwy); void drawRunway(FGRunway* rwy); + void drawHelipad(FGHelipad* hp); void drawILS(bool tuned, FGRunway* rwy); void drawNavaids(); diff --git a/src/Navaids/NavDataCache.cxx b/src/Navaids/NavDataCache.cxx index e4d681eec..3cc8a255e 100644 --- a/src/Navaids/NavDataCache.cxx +++ b/src/Navaids/NavDataCache.cxx @@ -71,7 +71,7 @@ using std::string; namespace { const int MAX_RETRIES = 10; -const int SCHEMA_VERSION = 6; +const int SCHEMA_VERSION = 7; const int CACHE_SIZE_KBYTES= 16000; // bind a std::string to a sqlite statement. The std::string must live the @@ -724,6 +724,9 @@ public: if (ty == FGPositioned::TAXIWAY) { reset(loadRunwayStmt); return new FGTaxiway(rowId, id, pos, heading, lengthM, widthM, surface); + } else if (ty == FGPositioned::HELIPAD) { + reset(loadRunwayStmt); + return new FGHelipad(rowId, apt, id, pos, heading, lengthM, widthM, surface); } else { double displacedThreshold = sqlite3_column_double(loadRunwayStmt, 4); double stopway = sqlite3_column_double(loadRunwayStmt, 5); @@ -1020,6 +1023,7 @@ FGPositioned* NavDataCache::NavDataCachePrivate::loadById(sqlite3_int64 rowid) return new AirportTower(rowid, aptId, ident, pos); case FGPositioned::RUNWAY: + case FGPositioned::HELIPAD: case FGPositioned::TAXIWAY: return loadRunway(rowid, ty, ident, pos, aptId); @@ -1516,7 +1520,7 @@ NavDataCache::insertRunway(FGPositioned::Type ty, const string& ident, { // only runways are spatially indexed; don't bother indexing taxiways // or pavements - bool spatialIndex = (ty == FGPositioned::RUNWAY); + bool spatialIndex = ( ty == FGPositioned::RUNWAY || ty == FGPositioned::HELIPAD); sqlite3_int64 rowId = d->insertPositioned(ty, cleanRunwayNo(ident), "", pos, apt, spatialIndex); diff --git a/src/Navaids/positioned.hxx b/src/Navaids/positioned.hxx index e978bb6d6..7aaaf22ad 100644 --- a/src/Navaids/positioned.hxx +++ b/src/Navaids/positioned.hxx @@ -47,6 +47,7 @@ public: HELIPORT, SEAPORT, RUNWAY, + HELIPAD, TAXIWAY, PAVEMENT, WAYPOINT,