1 /** 2 * NavDataCache.hxx - defines a unified binary cache for navigation 3 * data, parsed from various text / XML sources. 4 */ 5 6 // Written by James Turner, started 2012. 7 // 8 // Copyright (C) 2012 James Turner 9 // 10 // This program is free software; you can redistribute it and/or 11 // modify it under the terms of the GNU General Public License as 12 // published by the Free Software Foundation; either version 2 of the 13 // License, or (at your option) any later version. 14 // 15 // This program is distributed in the hope that it will be useful, but 16 // WITHOUT ANY WARRANTY; without even the implied warranty of 17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 // General Public License for more details. 19 // 20 // You should have received a copy of the GNU General Public License 21 // along with this program; if not, write to the Free Software 22 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 23 24 #ifndef FG_NAVDATACACHE_HXX 25 #define FG_NAVDATACACHE_HXX 26 27 #include <memory> 28 #include <cstddef> // for std::size_t 29 #include <functional> 30 31 #include <simgear/misc/strutils.hxx> // for string_list 32 #include <Navaids/positioned.hxx> 33 #include <Main/globals.hxx> // for PathList 34 35 class SGPath; 36 class FGRunway; 37 38 namespace flightgear 39 { 40 41 /// a pair of airport ID, runway ID 42 typedef std::pair<PositionedID, PositionedID> AirportRunwayPair; 43 44 typedef std::pair<FGPositioned::Type, PositionedID> TypedPositioned; 45 typedef std::vector<TypedPositioned> TypedPositionedVec; 46 47 // pair of airway ID, destination node ID 48 typedef std::pair<int, PositionedID> AirwayEdge; 49 typedef std::vector<AirwayEdge> AirwayEdgeVec; 50 51 namespace Octree { 52 class Node; 53 class Branch; 54 } 55 56 class Airway; 57 using AirwayRef = SGSharedPtr<Airway>; 58 59 class NavDataCache 60 { 61 public: 62 ~NavDataCache(); 63 64 // singleton accessor 65 static NavDataCache* instance(); 66 67 // static creator 68 static NavDataCache* createInstance(); 69 70 static void shutdown(); 71 72 SGPath path() const; 73 74 enum DatFileType { 75 DATFILETYPE_APT = 0, 76 DATFILETYPE_METAR, 77 DATFILETYPE_AWY, 78 DATFILETYPE_NAV, 79 DATFILETYPE_FIX, 80 DATFILETYPE_POI, 81 DATFILETYPE_CARRIER, 82 DATFILETYPE_TACAN_FREQ, 83 DATFILETYPE_LAST 84 }; 85 86 struct DatFilesGroupInfo { 87 DatFileType datFileType; // for instance, DATFILETYPE_APT 88 PathList paths; // SGPath instances 89 std::size_t totalSize; // total size of all these files, in bytes 90 }; 91 92 // datTypeStr[DATFILETYPE_APT] = std::string("apt"), etc. This gives, 93 // among other things, the subdirectory of $scenery_path/NavData where 94 // each type of dat file is looked for. 95 static const std::string datTypeStr[]; 96 // defaultDatFile[DATFILETYPE_APT] = std::string("Airports/apt.dat.gz"), 97 // etc. This tells where to find the historical dat files: those under 98 // $FG_ROOT. 99 static const std::string defaultDatFile[]; 100 101 // Update d->datFilesInfo and legacy d->metarDatPath, d->poiDatPath, 102 // etc. by looking into $scenery_path/NavData for each scenery path. 103 void updateListsOfDatFiles(); 104 // Returns datFilesInfo for the given type. 105 const DatFilesGroupInfo& getDatFilesInfo(DatFileType datFileType) const; 106 107 /** 108 * predicate - check if the cache needs to be rebuilt. 109 * This can happen is the cache file is missing or damaged, or one of the 110 ** global input files is changed. 111 */ 112 bool isRebuildRequired(); 113 114 static bool isAnotherProcessRebuilding(); 115 116 enum RebuildPhase 117 { 118 REBUILD_UNKNOWN = 0, 119 REBUILD_READING_APT_DAT_FILES, 120 REBUILD_LOADING_AIRPORTS, 121 REBUILD_NAVAIDS, 122 REBUILD_FIXES, 123 REBUILD_POIS, 124 REBUILD_DONE 125 }; 126 127 /** 128 * run the cache rebuild - returns the current phase or 'done' 129 */ 130 RebuildPhase rebuild(); 131 132 unsigned int rebuildPhaseCompletionPercentage() const; 133 void setRebuildPhaseProgress(RebuildPhase ph, unsigned int percent = 0); 134 135 bool isCachedFileModified(const SGPath& path) const; 136 void stampCacheFile(const SGPath& path); 137 138 int readIntProperty(const std::string& key); 139 double readDoubleProperty(const std::string& key); 140 std::string readStringProperty(const std::string& key); 141 142 void writeIntProperty(const std::string& key, int value); 143 void writeStringProperty(const std::string& key, const std::string& value); 144 void writeDoubleProperty(const std::string& key, const double& value); 145 146 // Warning: order is not necessarily preserved upon write-read cycles! 147 string_list readStringListProperty(const std::string& key); 148 void writeStringListProperty(const std::string& key, const string_list& values); 149 150 // These ones guarantee the same order after each write-read cycle. 151 string_list readOrderedStringListProperty(const std::string& key, 152 const char* separator); 153 void writeOrderedStringListProperty(const std::string& key, 154 const string_list& values, 155 const char* separator); 156 157 /** 158 * retrieve an FGPositioned from the cache. 159 * This may be trivial if the object is previously loaded, or require actual 160 * disk IO. 161 */ 162 FGPositionedRef loadById(PositionedID guid); 163 164 PositionedID insertAirport(FGPositioned::Type ty, const std::string& ident, 165 const std::string& name); 166 void insertTower(PositionedID airportId, const SGGeod& pos); 167 PositionedID insertRunway(FGPositioned::Type ty, const std::string& ident, 168 const SGGeod& pos, PositionedID apt, 169 double heading, double length, double width, double displacedThreshold, 170 double stopway, int surfaceCode); 171 void setRunwayReciprocal(PositionedID runway, PositionedID recip); 172 void setRunwayILS(PositionedID runway, PositionedID ils); 173 174 PositionedID insertNavaid(FGPositioned::Type ty, const std::string& ident, 175 const std::string& name, const SGGeod& pos, int freq, int range, double multiuse, 176 PositionedID apt, PositionedID runway); 177 178 // Assign colocated DME to a navaid 179 void setNavaidColocated(PositionedID navaid, PositionedID colocatedDME); 180 181 PositionedID insertCommStation(FGPositioned::Type ty, 182 const std::string& name, const SGGeod& pos, int freq, int range, 183 PositionedID apt); 184 PositionedID insertFix(const std::string& ident, const SGGeod& aPos); 185 186 PositionedID createPOI(FGPositioned::Type ty, const std::string& ident, const SGGeod& aPos); 187 188 bool removePOI(FGPositioned::Type ty, const std::string& aIdent); 189 190 /// update the metar flag associated with an airport 191 void setAirportMetar(const std::string& icao, bool hasMetar); 192 193 /** 194 * Modify the position of an existing item. 195 */ 196 void updatePosition(PositionedID item, const SGGeod &pos); 197 198 FGPositionedList findAllWithIdent( const std::string& ident, 199 FGPositioned::Filter* filter, 200 bool exact ); 201 FGPositionedList findAllWithName( const std::string& ident, 202 FGPositioned::Filter* filter, 203 bool exact ); 204 205 FGPositionedRef findClosestWithIdent( const std::string& aIdent, 206 const SGGeod& aPos, 207 FGPositioned::Filter* aFilter ); 208 209 210 /** 211 * Helper to implement the AirportSearch widget. Optimised text search of 212 * airport names and idents, returning a list suitable for passing directly 213 * to PLIB. 214 */ 215 char** searchAirportNamesAndIdents(const std::string& aFilter); 216 217 /** 218 * Find the closest matching comm-station on a frequency, to a position. 219 * The filter with be used for both type ranging and to validate the result 220 * candidates. 221 */ 222 FGPositionedRef findCommByFreq(int freqKhz, const SGGeod& pos, FGPositioned::Filter* filt); 223 224 /** 225 * find all items of a specified type (or range of types) at an airport 226 */ 227 PositionedIDVec airportItemsOfType(PositionedID apt, FGPositioned::Type ty, 228 FGPositioned::Type maxTy = FGPositioned::INVALID); 229 230 /** 231 * find the first match item of the specified type and ident, at an airport 232 */ 233 PositionedID airportItemWithIdent(PositionedID apt, FGPositioned::Type ty, const std::string& ident); 234 235 /** 236 * Find all navaids matching a particular frequency, sorted by range from the 237 * supplied position. Type-range will be determined from the filter 238 */ 239 PositionedIDVec findNavaidsByFreq(int freqKhz, const SGGeod& pos, FGPositioned::Filter* filt); 240 241 /// overload version of the above that does not consider positioned when 242 /// returning results. Only used by TACAN carrier search 243 PositionedIDVec findNavaidsByFreq(int freqKhz, FGPositioned::Filter* filt); 244 245 /** 246 * Given a runway and type, find the corresponding navaid (ILS / GS / OM) 247 */ 248 PositionedID findNavaidForRunway(PositionedID runway, FGPositioned::Type ty); 249 250 /** 251 * given a navaid name (or similar) from apt.dat / nav.dat, find the 252 * corresponding airport and runway IDs. 253 * Such names look like: 'LHBP 31L DME-ILS' or 'UEEE 23L MM' 254 */ 255 AirportRunwayPair findAirportRunway(const std::string& name); 256 257 /** 258 * Given an aiport, and runway and ILS identifier, find the corresponding cache 259 * entry. This matches the data we get in the ils.xml files for airports. 260 */ 261 PositionedID findILS(PositionedID airport, const std::string& runway, const std::string& navIdent); 262 263 /** 264 * Given an Octree node ID, return a bit-mask defining which of the child 265 * nodes exist. In practice this means an 8-bit value be sufficent, but 266 * an int works fine too. 267 */ 268 int getOctreeBranchChildren(int64_t octreeNodeId); 269 270 void defineOctreeNode(Octree::Branch* pr, Octree::Node* nd); 271 272 /** 273 * given an octree leaf, return all its child positioned items and their types 274 */ 275 TypedPositionedVec getOctreeLeafChildren(int64_t octreeNodeId); 276 277 // airways 278 int findAirway(int network, const std::string& aName, bool create); 279 280 int findAirway(const std::string& aName); 281 282 /** 283 * insert an edge between two positioned nodes, into the network. 284 * The airway identifier will be set accordingly. No reverse edge is created 285 * by this method - edges are directional so a reverses must be explicitly 286 * created. 287 */ 288 void insertEdge(int network, int airwayID, PositionedID from, PositionedID to); 289 290 /// is the specified positioned a node on the network? 291 bool isInAirwayNetwork(int network, PositionedID pos); 292 293 /** 294 * retrive all the destination points reachable from a positioned 295 * in an airway 296 */ 297 AirwayEdgeVec airwayEdgesFrom(int network, PositionedID pos); 298 299 AirwayRef loadAirway(int airwayID); 300 301 /** 302 * Waypoints on the airway 303 */ 304 PositionedIDVec airwayWaypts(int id); 305 306 class Transaction 307 { 308 public: 309 Transaction(NavDataCache* cache); 310 ~Transaction(); 311 312 void commit(); 313 private: 314 NavDataCache* _instance; 315 bool _committed; 316 }; 317 318 bool isReadOnly() const; 319 320 class ThreadedGUISearch 321 { 322 public: 323 ThreadedGUISearch(const std::string& term, bool onlyAirports); 324 ~ThreadedGUISearch(); 325 326 PositionedIDVec results() const; 327 328 bool isComplete() const; 329 private: 330 class ThreadedGUISearchPrivate; 331 std::unique_ptr<ThreadedGUISearchPrivate> d; 332 }; 333 334 void clearDynamicPositioneds(); 335 336 private: 337 NavDataCache(); 338 339 friend class RebuildThread; 340 341 // A generic function for loading all navigation data files of the 342 // specified type (apt/fix/nav etc.) using the passed type-specific loader. 343 void loadDatFiles(DatFileType type, 344 std::function<void(const SGPath&, std::size_t, std::size_t)> loader); 345 346 void doRebuild(); 347 348 friend class Transaction; 349 350 void beginTransaction(); 351 void commitTransaction(); 352 void abortTransaction(); 353 354 class NavDataCachePrivate; 355 std::unique_ptr<NavDataCachePrivate> d; 356 357 bool rebuildInProgress = false; 358 }; 359 360 } // of namespace flightgear 361 362 #endif // of FG_NAVDATACACHE_HXX 363