1 /** 2 * FlightPlan.hxx - defines a full flight-plan object, including 3 * departure, cruise, arrival information and waypoints 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_FLIGHTPLAN_HXX 25 #define FG_FLIGHTPLAN_HXX 26 27 #include <functional> 28 29 #include <Navaids/route.hxx> 30 #include <Airports/airport.hxx> 31 32 namespace flightgear 33 { 34 35 class Transition; 36 class FlightPlan; 37 38 typedef SGSharedPtr<FlightPlan> FlightPlanRef; 39 40 enum class ICAOFlightRules 41 { 42 VFR = 0, 43 IFR, 44 IFR_VFR, // type Y 45 VFR_IFR // type Z 46 }; 47 48 enum class ICAOFlightType 49 { 50 Scheduled = 0, 51 NonScheduled, 52 GeneralAviation, 53 Military, 54 Other // type X 55 }; 56 57 class FlightPlan : public RouteBase 58 { 59 public: 60 FlightPlan(); 61 virtual ~FlightPlan(); 62 63 virtual std::string ident() const; 64 void setIdent(const std::string& s); 65 66 // propogate the GPS/FMS setting for this through to the RoutePath 67 void setFollowLegTrackToFixes(bool tf); 68 bool followLegTrackToFixes() const; 69 70 // aircraft approach category as per CFR 97.3, etc 71 // http://www.flightsimaviation.com/data/FARS/part_97-3.html 72 std::string icaoAircraftCategory() const; 73 void setIcaoAircraftCategory(const std::string& cat); 74 icaoAircraftType() const75 std::string icaoAircraftType() const 76 { return _aircraftType; } 77 78 void setIcaoAircraftType(const std::string& ty); 79 80 FlightPlan* clone(const std::string& newIdent = std::string()) const; 81 82 /** 83 * flight-plan leg encapsulation 84 */ 85 class Leg : public SGReferenced 86 { 87 public: owner() const88 FlightPlan* owner() const 89 { return const_cast<FlightPlan*>(_parent); } 90 waypoint() const91 Waypt* waypoint() const 92 { return _waypt; } 93 94 // return the next leg after this one 95 Leg* nextLeg() const; 96 97 /** 98 * requesting holding at the waypoint upon reaching it. This will 99 * convert the waypt to a Hold if not already defined as one, but 100 * with default hold data. 101 * 102 * If the waypt is not of a type suitable for holding at, returns false 103 * (eg a runway or dynamic waypoint) 104 */ 105 bool setHoldCount(int count); 106 107 int holdCount() const; 108 109 110 bool convertWaypointToHold(); 111 112 unsigned int index() const; 113 114 int altitudeFt() const; 115 int speed() const; 116 117 int speedKts() const; 118 double speedMach() const; 119 120 RouteRestriction altitudeRestriction() const; 121 RouteRestriction speedRestriction() const; 122 123 void setSpeed(RouteRestriction ty, double speed); 124 void setAltitude(RouteRestriction ty, int altFt); 125 126 double courseDeg() const; 127 double distanceNm() const; 128 double distanceAlongRoute() const; 129 130 /** 131 * helper function, if the waypoint is modified in some way, to 132 * notify the flightplan owning this leg, and hence any delegates 133 * obsering us 134 */ 135 void markWaypointDirty(); 136 private: 137 friend class FlightPlan; 138 139 Leg(FlightPlan* owner, WayptRef wpt); 140 141 Leg* cloneFor(FlightPlan* owner) const; 142 143 void writeToProperties(SGPropertyNode* node) const; 144 145 const FlightPlan* _parent; 146 RouteRestriction _speedRestrict = RESTRICT_NONE, 147 _altRestrict = RESTRICT_NONE; 148 int _speed = 0; 149 int _altitudeFt = 0; 150 151 // if > 0, we will hold at the waypoint using 152 // the published hold side/course 153 // This only works if _waypt is a Hold, either defined by a procedure 154 // or modified to become one 155 int _holdCount = 0; 156 157 WayptRef _waypt; 158 /// length of this leg following the flown path 159 mutable double _pathDistance = -1.0; 160 mutable double _courseDeg = -1.0; 161 /// total distance of this leg from departure point 162 mutable double _distanceAlongPath = 11.0; 163 }; 164 165 using LegRef = SGSharedPtr<Leg>; 166 167 class DelegateFactory; 168 using DelegateFactoryRef = std::shared_ptr<DelegateFactory>; 169 170 class Delegate 171 { 172 public: 173 virtual ~Delegate(); 174 departureChanged()175 virtual void departureChanged() { } arrivalChanged()176 virtual void arrivalChanged() { } waypointsChanged()177 virtual void waypointsChanged() { } cruiseChanged()178 virtual void cruiseChanged() { } cleared()179 virtual void cleared() { } activated()180 virtual void activated() { } 181 182 /** 183 * Invoked when the C++ code determines the active leg is done / next 184 * leg should be sequenced. The default route-manager delegate will 185 * advance to the next waypoint when handling this. 186 * 187 * If multiple delegates are installed, take special care not to sequence 188 * the waypoint twice. 189 */ sequence()190 virtual void sequence() { } 191 currentWaypointChanged()192 virtual void currentWaypointChanged() { } endOfFlightPlan()193 virtual void endOfFlightPlan() { } 194 loaded()195 virtual void loaded() { } 196 protected: 197 Delegate(); 198 199 private: 200 friend class FlightPlan; 201 202 // record the factory which created us, so we have the option to clean up 203 DelegateFactoryRef _factory; 204 }; 205 206 LegRef insertWayptAtIndex(Waypt* aWpt, int aIndex); 207 void insertWayptsAtIndex(const WayptVec& wps, int aIndex); 208 209 void deleteIndex(int index); 210 void clearAll(); 211 void clearLegs(); 212 int clearWayptsWithFlag(WayptFlag flag); 213 currentIndex() const214 int currentIndex() const 215 { return _currentIndex; } 216 217 void sequence(); 218 219 void setCurrentIndex(int index); 220 221 void activate(); 222 223 void finish(); 224 225 bool isActive() const; 226 227 LegRef currentLeg() const; 228 LegRef nextLeg() const; 229 LegRef previousLeg() const; 230 numLegs() const231 int numLegs() const 232 { return static_cast<int>(_legs.size()); } 233 234 LegRef legAtIndex(int index) const; 235 236 int findWayptIndex(const SGGeod& aPos) const; 237 int findWayptIndex(const FGPositionedRef aPos) const; 238 239 int indexOfFirstNonDepartureWaypoint() const; 240 int indexOfFirstArrivalWaypoint() const; 241 int indexOfFirstApproachWaypoint() const; 242 int indexOfDestinationRunwayWaypoint() const; 243 244 bool load(const SGPath& p); 245 bool save(const SGPath& p) const; 246 247 bool save(std::ostream& stream) const; 248 bool load(std::istream& stream); 249 departureAirport() const250 FGAirportRef departureAirport() const 251 { return _departure; } 252 destinationAirport() const253 FGAirportRef destinationAirport() const 254 { return _destination; } 255 departureRunway() const256 FGRunway* departureRunway() const 257 { return _departureRunway; } 258 destinationRunway() const259 FGRunway* destinationRunway() const 260 { return _destinationRunway; } 261 approach() const262 Approach* approach() const 263 { return _approach; } 264 265 void setDeparture(FGAirport* apt); 266 void setDeparture(FGRunway* rwy); 267 268 void clearDeparture(); 269 sid() const270 SID* sid() const 271 { return _sid; } 272 273 Transition* sidTransition() const; 274 275 void setSID(SID* sid, const std::string& transition = std::string()); 276 277 void setSID(Transition* sidWithTrans); 278 279 void clearSID(); 280 281 void setDestination(FGAirport* apt); 282 void setDestination(FGRunway* rwy); 283 284 void clearDestination(); 285 286 FGAirportRef alternate() const; 287 void setAlternate(FGAirportRef alt); 288 289 /** 290 * note setting an approach will implicitly update the destination 291 * airport and runway to match 292 */ 293 void setApproach(Approach* app, const std::string& transition = {}); 294 295 void setApproach(Transition* approachWithTrans); 296 297 298 Transition* approachTransition() const; 299 star() const300 STAR* star() const 301 { return _star; } 302 303 Transition* starTransition() const; 304 305 void setSTAR(STAR* star, const std::string& transition = std::string()); 306 307 void setSTAR(Transition* starWithTrans); 308 309 void clearSTAR(); 310 totalDistanceNm() const311 double totalDistanceNm() const 312 { return _totalDistance; } 313 estimatedDurationMinutes() const314 int estimatedDurationMinutes() const 315 { return _estimatedDuration; } 316 317 void setEstimatedDurationMinutes(int minutes); 318 319 /** 320 * @brief computeDurationMinutes - use performance data and cruise data 321 * to estimate enroute time 322 */ 323 void computeDurationMinutes(); 324 325 /** 326 * given a waypoint index, and an offset in NM, find the geodetic 327 * position on the route path. I.e the point 10nm before or after 328 * a particular waypoint. 329 */ 330 SGGeod pointAlongRoute(int aIndex, double aOffsetNm) const; 331 332 /** 333 given a waypoint index, find a point at a normalised offset, which must be [-1 .. 1] 334 eg an offset of -0.5 will be half-way between aIndex and the preceeding waypoint, 335 and an offset of 0.3 will be 30% of the distance from aIndex to the next waypoint. 336 */ 337 SGGeod pointAlongRouteNorm(int aIndex, double aOffsetNorm) const; 338 339 /** 340 * Create a WayPoint from a string in the following format: 341 * - simple identifier 342 * - decimal-lon,decimal-lat 343 * - airport-id/runway-id 344 * - navaid/radial-deg/offset-nm 345 */ 346 WayptRef waypointFromString(const std::string& target); 347 348 /** 349 * attempt to replace the route waypoints (and potentially the SID and 350 * STAR) based on an ICAO standard route string, i.e item 15. 351 * Returns true if the rotue was parsed successfully (and this flight 352 * plan modified accordingly) or false if the string could not be 353 * parsed. 354 */ 355 bool parseICAORouteString(const std::string& routeData); 356 357 std::string asICAORouteString() const; 358 359 // ICAO flight-plan data 360 void setFlightRules(ICAOFlightRules rules); 361 ICAOFlightRules flightRules() const; 362 363 void setFlightType(ICAOFlightType type); 364 ICAOFlightType flightType() const; 365 366 void setCallsign(const std::string& callsign); callsign() const367 std::string callsign() const 368 { return _callsign; } 369 370 void setRemarks(const std::string& remarks); remarks() const371 std::string remarks() const 372 { return _remarks; } 373 374 // cruise data 375 void setCruiseSpeedKnots(int kts); 376 int cruiseSpeedKnots() const; 377 378 void setCruiseSpeedMach(double mach); 379 double cruiseSpeedMach() const; 380 381 void setCruiseFlightLevel(int flightLevel); 382 int cruiseFlightLevel() const; 383 384 void setCruiseAltitudeFt(int altFt); 385 int cruiseAltitudeFt() const; 386 387 /** 388 * abstract interface for creating delegates automatically when a 389 * flight-plan is created or loaded 390 */ 391 class DelegateFactory 392 { 393 public: 394 virtual Delegate* createFlightPlanDelegate(FlightPlan* fp) = 0; 395 virtual void destroyFlightPlanDelegate(FlightPlan* fp, Delegate* d); 396 }; 397 398 static void registerDelegateFactory(DelegateFactoryRef df); 399 static void unregisterDelegateFactory(DelegateFactoryRef df); 400 401 void addDelegate(Delegate* d); 402 void removeDelegate(Delegate* d); 403 404 using LegVisitor = std::function<void(Leg*)>; 405 void forEachLeg(const LegVisitor& lv); 406 private: 407 friend class Leg; 408 409 int findLegIndex(const Leg* l) const; 410 411 void lockDelegates(); 412 void unlockDelegates(); 413 414 void notifyCleared(); 415 416 unsigned int _delegateLock = 0; 417 bool _arrivalChanged = false, 418 _departureChanged = false, 419 _waypointsChanged = false, 420 _currentWaypointChanged = false, 421 _cruiseDataChanged = false; 422 bool _didLoadFP = false; 423 424 void saveToProperties(SGPropertyNode* d) const; 425 426 bool loadXmlFormat(const SGPath& path); 427 bool loadGpxFormat(const SGPath& path); 428 bool loadPlainTextFormat(const SGPath& path); 429 430 bool loadVersion1XMLRoute(SGPropertyNode_ptr routeData); 431 bool loadVersion2XMLRoute(SGPropertyNode_ptr routeData); 432 void loadXMLRouteHeader(SGPropertyNode_ptr routeData); 433 WayptRef parseVersion1XMLWaypt(SGPropertyNode* aWP); 434 435 double magvarDegAt(const SGGeod& pos) const; 436 bool parseICAOLatLon(const std::string &s, SGGeod &p); 437 438 std::string _ident; 439 std::string _callsign; 440 std::string _remarks; 441 std::string _aircraftType; 442 443 int _currentIndex; 444 bool _followLegTrackToFix; 445 char _aircraftCategory; 446 ICAOFlightType _flightType = ICAOFlightType::Other; 447 ICAOFlightRules _flightRules = ICAOFlightRules::VFR; 448 int _cruiseAirspeedKnots = 0; 449 double _cruiseAirspeedMach = 0.0; 450 int _cruiseFlightLevel = 0; 451 int _cruiseAltitudeFt = 0; 452 int _estimatedDuration = 0; 453 454 FGAirportRef _departure, _destination; 455 FGAirportRef _alternate; 456 FGRunway* _departureRunway, *_destinationRunway; 457 SGSharedPtr<SID> _sid; 458 SGSharedPtr<STAR> _star; 459 SGSharedPtr<Approach> _approach; 460 std::string _sidTransition, _starTransition, _approachTransition; 461 462 double _totalDistance; 463 void rebuildLegData(); 464 465 using LegVec = std::vector<LegRef>; 466 LegVec _legs; 467 468 std::vector<Delegate*> _delegates; 469 }; 470 471 } // of namespace flightgear 472 473 #endif // of FG_FLIGHTPLAN_HXX 474