1 // positioned.hxx - base class for objects which are positioned
2 //
3 // Copyright (C) 2008 James Turner
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License as
7 // published by the Free Software Foundation; either version 2 of the
8 // License, or (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful, but
11 // WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 // General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 //
19 // $Id$
20 
21 #ifndef FG_POSITIONED_HXX
22 #define FG_POSITIONED_HXX
23 
24 #include <cassert>
25 #include <string>
26 #include <vector>
27 #include <stdint.h>
28 
29 #include <simgear/sg_inlines.h>
30 #include <simgear/structure/SGSharedPtr.hxx>
31 #include <simgear/math/SGMath.hxx>
32 
33 class FGPositioned;
34 typedef SGSharedPtr<FGPositioned> FGPositionedRef;
35 typedef std::vector<FGPositionedRef> FGPositionedList;
36 
37 typedef int64_t PositionedID;
38 typedef std::vector<PositionedID> PositionedIDVec;
39 
40 namespace flightgear { class NavDataCache; }
41 
42 class FGPositioned : public SGReferenced
43 {
44 public:
45     static const PositionedID TRANSIENT_ID;
46 
47   typedef enum {
48     INVALID = 0,
49     AIRPORT,
50     HELIPORT,
51     SEAPORT,
52     RUNWAY,
53     HELIPAD,
54     TAXIWAY,
55     PAVEMENT,
56     WAYPOINT,
57     FIX,
58     NDB,
59     VOR,
60     ILS,
61     LOC,
62     GS,
63     OM,
64     MM,
65     IM,
66 /// important that DME & TACAN are adjacent to keep the TacanFilter
67 /// efficient - DMEs are proxies for TACAN/VORTAC stations
68     DME,
69     TACAN,
70     MOBILE_TACAN,
71     OBSTACLE,
72 /// an actual airport tower - not a radio comms facility!
73 /// some airports have multiple towers, eg EHAM, although our data source
74 /// doesn't necessarily include them
75     TOWER,
76     FREQ_GROUND,
77     FREQ_TOWER,
78     FREQ_ATIS,
79     FREQ_AWOS,
80     FREQ_APP_DEP,
81     FREQ_ENROUTE,
82     FREQ_CLEARANCE,
83     FREQ_UNICOM,
84 // groundnet items
85     PARKING,  ///< parking position - might be a gate, or stand
86     TAXI_NODE,
87 // POI items
88     COUNTRY,
89     CITY,
90     TOWN,
91     VILLAGE,
92 
93     LAST_TYPE
94   } Type;
95 
96   virtual ~FGPositioned();
97 
type() const98   Type type() const
99   { return mType; }
100 
101   // True for the following types: AIRPORT, HELIPORT, SEAPORT.
102   // False for other types, as well as if pos == nullptr.
103   static bool isAirportType(FGPositioned* pos);
104   // True for the following type: RUNWAY.
105   // False for other types, as well as if pos == nullptr.
106   static bool isRunwayType(FGPositioned* pos);
107   // True for the following types: NDB, VOR, ILS, LOC, GS, DME, TACAN.
108   // False for other types, as well as if pos == nullptr.
109   static bool isNavaidType(FGPositioned* pos);
110 
typeString() const111   const char* typeString() const
112   { return nameForType(mType); }
113 
ident() const114   const std::string& ident() const
115   { return mIdent; }
116 
117   /**
118    * Return the name of this positioned. By default this is the same as the
119    * ident, but for many derived classes it's more meaningful - the aiport or
120    * navaid name, for example.
121    */
name() const122   virtual const std::string& name() const
123   { return mIdent; }
124 
geod() const125   virtual const SGGeod& geod() const
126   { return mPosition; }
127 
guid() const128   PositionedID guid() const
129   { return mGuid; }
130 
131   /**
132    *  The cartesian position associated with this object
133    */
134   virtual const SGVec3d& cart() const;
135 
latitude() const136   double latitude() const
137   { return geod().getLatitudeDeg(); }
138 
longitude() const139   double longitude() const
140   { return geod().getLongitudeDeg(); }
141 
elevation() const142   double elevation() const
143   { return geod().getElevationFt(); }
144 
elevationM() const145   double elevationM() const
146   { return geod().getElevationM(); }
147 
148   /**
149    * Predicate class to support custom filtering of FGPositioned queries
150    * Default implementation of this passes any FGPositioned instance.
151    */
152   class Filter
153   {
154   public:
~Filter()155     virtual ~Filter() { ; }
156 
157     /**
158      * Over-rideable filter method. Default implementation returns true.
159      */
pass(FGPositioned * aPos) const160     virtual bool pass(FGPositioned* aPos) const
161     { return true; }
162 
minType() const163     virtual Type minType() const
164     { return INVALID; }
165 
maxType() const166     virtual Type maxType() const
167     { return INVALID; }
168 
169 
operator ()(FGPositioned * aPos) const170     bool operator()(FGPositioned* aPos) const
171     { return pass(aPos); }
172   };
173 
174   class TypeFilter : public Filter
175   {
176   public:
177     TypeFilter(Type aTy = INVALID);
178 
179     TypeFilter(std::initializer_list<Type> types);
180 
181     bool pass(FGPositioned* aPos) const override;
182 
minType() const183     Type minType() const override
184     { return mMinType; }
185 
maxType() const186     Type maxType() const override
187     { return mMaxType; }
188 
189     void addType(Type aTy);
190 
191     static TypeFilter fromString(const std::string& aFilterSpec);
192   private:
193 
194     std::vector<Type> types;
195     Type mMinType = LAST_TYPE,
196       mMaxType = INVALID;
197   };
198 
199   static FGPositionedList findWithinRange(const SGGeod& aPos, double aRangeNm, Filter* aFilter);
200 
201   static FGPositionedList findWithinRangePartial(const SGGeod& aPos, double aRangeNm, Filter* aFilter, bool& aPartial);
202 
203   static FGPositionedRef findClosestWithIdent(const std::string& aIdent, const SGGeod& aPos, Filter* aFilter = NULL);
204 
205   static FGPositionedRef findFirstWithIdent(const std::string& aIdent, Filter* aFilter);
206 
207   /**
208    * Find all items with the specified ident
209    * @param aFilter - optional filter on items
210    */
211   static FGPositionedList findAllWithIdent(const std::string& aIdent, Filter* aFilter = NULL, bool aExact = true);
212 
213   /**
214    * As above, but searches names instead of idents
215    */
216   static FGPositionedList findAllWithName(const std::string& aName, Filter* aFilter = NULL, bool aExact = true);
217 
218   /**
219    * Sort an FGPositionedList by distance from a position
220    */
221   static void sortByRange(FGPositionedList&, const SGGeod& aPos);
222 
223   /**
224    * Find the closest item to a position, which pass the specified filter
225    * A cutoff range in NM must be specified, to constrain the search acceptably.
226    * Very large cutoff values will make this slow.
227    *
228    * @result The closest item passing the filter, or NULL
229    * @param aCutoffNm - maximum distance to search within, in nautical miles
230    */
231   static FGPositionedRef findClosest(const SGGeod& aPos, double aCutoffNm, Filter* aFilter = NULL);
232 
233   /**
234    * Find the closest N items to a position, which pass the specified filter
235    * A cutoff range in NM must be specified, to constrain the search acceptably.
236    * Very large cutoff values will make this slow.
237    *
238    * @result The matches (possibly less than N, depending on the filter and cutoff),
239    *    sorted by distance from the search pos
240    * @param aN - number of matches to find
241    * @param aCutoffNm - maximum distance to search within, in nautical miles
242    */
243   static FGPositionedList findClosestN(const SGGeod& aPos, unsigned int aN, double aCutoffNm, Filter* aFilter = NULL);
244 
245   /**
246    * Same as above, but with a time-bound in msec too.
247    */
248   static FGPositionedList findClosestNPartial(const SGGeod& aPos, unsigned int aN, double aCutoffNm, Filter* aFilter,
249                            bool& aPartial);
250 
251   template<class T>
loadById(PositionedID id)252   static SGSharedPtr<T> loadById(PositionedID id)
253   {
254     return static_pointer_cast<T>( loadByIdImpl(id) );
255   }
256 
257   template<class T>
loadById(const PositionedIDVec & id_vec,size_t index)258   static SGSharedPtr<T> loadById(const PositionedIDVec& id_vec, size_t index)
259   {
260     assert(index >= 0 && index < id_vec.size());
261     return loadById<T>(id_vec[index]);
262   }
263 
264   template<class T>
loadAllById(const PositionedIDVec & id_vec)265   static std::vector<SGSharedPtr<T> > loadAllById(const PositionedIDVec& id_vec)
266   {
267     std::vector<SGSharedPtr<T> > vec(id_vec.size());
268 
269     for(size_t i = 0; i < id_vec.size(); ++i)
270       vec[i] = loadById<T>(id_vec[i]);
271 
272     return vec;
273   }
274 
275   /**
276    * Map a candidate type string to a real type. Returns INVALID if the string
277    * does not correspond to a defined type.
278    */
279   static Type typeFromName(const std::string& aName);
280 
281   /**
282    * Map a type to a human-readable string
283    */
284   static const char* nameForType(Type aTy);
285 
286   static FGPositionedRef createUserWaypoint(const std::string& aIdent, const SGGeod& aPos);
287   static bool deleteUserWaypoint(const std::string& aIdent);
288 protected:
289   friend class flightgear::NavDataCache;
290 
291   FGPositioned(PositionedID aGuid, Type ty, const std::string& aIdent, const SGGeod& aPos);
292 
293   void modifyPosition(const SGGeod& newPos);
294   void invalidatePosition();
295 
296   static FGPositionedRef loadByIdImpl(PositionedID id);
297 
298   const PositionedID mGuid;
299   const Type mType;
300   const std::string mIdent;
301 
302 private:
303   SG_DISABLE_COPY(FGPositioned);
304 
305   const SGGeod mPosition;
306   const SGVec3d mCart;
307 };
308 
309 template <class T>
fgpositioned_cast(FGPositioned * p)310 T* fgpositioned_cast(FGPositioned* p)
311 {
312     if (T::isType(p->type())) {
313         return static_cast<T*>(p);
314     }
315 
316     return nullptr;
317 }
318 
319 template <class T>
fgpositioned_cast(FGPositionedRef p)320 T* fgpositioned_cast(FGPositionedRef p)
321 {
322     if (!p) return nullptr;
323 
324     if (T::isType(p->type())) {
325         return static_cast<T*>(p.ptr());
326     }
327 
328     return nullptr;
329 }
330 
331 #endif // of FG_POSITIONED_HXX
332