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