]> git.mxchange.org Git - flightgear.git/blob - src/Navaids/positioned.cxx
Implement a persistent cache for navigation data.
[flightgear.git] / src / Navaids / positioned.cxx
1 // positioned.cxx - 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 #ifdef HAVE_CONFIG_H
22 #  include "config.h"
23 #endif
24
25 #include "positioned.hxx"
26
27 #include <map>
28 #include <set>
29 #include <algorithm> // for sort
30 #include <queue>
31 #include <memory>
32
33 #include <boost/algorithm/string/case_conv.hpp>
34 #include <boost/algorithm/string/predicate.hpp>
35
36 #include <osg/Math> // for osg::isNaN
37
38 #include <simgear/timing/timestamp.hxx>
39 #include <simgear/debug/logstream.hxx>
40 #include <simgear/structure/exception.hxx>
41 #include <simgear/math/SGGeometry.hxx>
42 #include <simgear/sg_inlines.h>
43
44 #include "Navaids/PositionedOctree.hxx"
45
46 using std::string;
47 using namespace flightgear;
48
49 static void validateSGGeod(const SGGeod& geod)
50 {
51   if (osg::isNaN(geod.getLatitudeDeg()) ||
52       osg::isNaN(geod.getLongitudeDeg()))
53   {
54     throw sg_range_exception("position is invalid, NaNs");
55   }
56 }
57
58
59 ///////////////////////////////////////////////////////////////////////////////
60
61 FGPositioned::FGPositioned(PositionedID aGuid, Type ty, const std::string& aIdent, const SGGeod& aPos) :
62   mGuid(aGuid),
63   mPosition(aPos),
64   mCart(SGVec3d::fromGeod(mPosition)),
65   mType(ty),
66   mIdent(aIdent)
67 {  
68 }
69
70 FGPositioned::~FGPositioned()
71 {
72 //  std::cout << "destroying:" << mIdent << "/" << nameForType(mType) << std::endl;
73 }
74
75 FGPositioned*
76 FGPositioned::createUserWaypoint(const std::string& aIdent, const SGGeod& aPos)
77 {
78   PositionedID id = NavDataCache::instance()->createUserWaypoint(aIdent, aPos);
79   return NavDataCache::instance()->loadById(id);
80 }
81
82 const SGVec3d&
83 FGPositioned::cart() const
84 {
85   return mCart;
86 }
87
88 FGPositioned::Type FGPositioned::typeFromName(const std::string& aName)
89 {
90   if (aName.empty() || (aName == "")) {
91     return INVALID;
92   }
93
94   typedef struct {
95     const char* _name;
96     Type _ty;
97   } NameTypeEntry;
98   
99   const NameTypeEntry names[] = {
100     {"airport", AIRPORT},
101     {"vor", VOR},
102     {"loc", LOC},
103     {"ils", ILS},
104     {"gs", GS},
105     {"ndb", NDB},
106     {"wpt", WAYPOINT},
107     {"fix", FIX},
108     {"tacan", TACAN},
109     {"dme", DME},
110     {"atis", FREQ_ATIS},
111     {"awos", FREQ_AWOS},
112     {"tower", FREQ_TOWER},
113     {"ground", FREQ_GROUND},
114     {"approach", FREQ_APP_DEP},
115     {"departure", FREQ_APP_DEP},
116   // aliases
117     {"gnd", FREQ_GROUND},
118     {"twr", FREQ_TOWER},
119     {"waypoint", WAYPOINT},
120     {"apt", AIRPORT},
121     {"arpt", AIRPORT},
122     {"any", INVALID},
123     {"all", INVALID},
124     
125     {NULL, INVALID}
126   };
127   
128   std::string lowerName(boost::to_lower_copy(aName));
129   
130   for (const NameTypeEntry* n = names; (n->_name != NULL); ++n) {
131     if (::strcmp(n->_name, lowerName.c_str()) == 0) {
132       return n->_ty;
133     }
134   }
135   
136   SG_LOG(SG_GENERAL, SG_WARN, "FGPositioned::typeFromName: couldn't match:" << aName);
137   return INVALID;
138 }
139
140 const char* FGPositioned::nameForType(Type aTy)
141 {
142  switch (aTy) {
143  case RUNWAY: return "runway";
144  case TAXIWAY: return "taxiway";
145  case PAVEMENT: return "pavement";
146  case PARK_STAND: return "parking stand";
147  case FIX: return "fix";
148  case VOR: return "VOR";
149  case NDB: return "NDB";
150  case ILS: return "ILS";
151  case LOC: return "localiser";
152  case GS: return "glideslope";
153  case OM: return "outer-marker";
154  case MM: return "middle-marker";
155  case IM: return "inner-marker";
156  case AIRPORT: return "airport";
157  case HELIPORT: return "heliport";
158  case SEAPORT: return "seaport";
159  case WAYPOINT: return "waypoint";
160  case DME: return "dme";
161  case TACAN: return "tacan";
162  case FREQ_TOWER: return "tower";
163  case FREQ_ATIS: return "atis";
164  case FREQ_AWOS: return "awos";
165  case FREQ_GROUND: return "ground";
166  case FREQ_CLEARANCE: return "clearance";
167  case FREQ_UNICOM: return "unicom";
168  case FREQ_APP_DEP: return "approach-departure";
169  default:
170   return "unknown";
171  }
172 }
173
174 ///////////////////////////////////////////////////////////////////////////////
175 // search / query functions
176
177 FGPositionedRef
178 FGPositioned::findClosestWithIdent(const std::string& aIdent, const SGGeod& aPos, Filter* aFilter)
179 {
180   validateSGGeod(aPos);  
181   return NavDataCache::instance()->findClosestWithIdent(aIdent, aPos, aFilter);
182 }
183
184 FGPositionedRef
185 FGPositioned::findFirstWithIdent(const std::string& aIdent, Filter* aFilter)
186 {
187   if (aIdent.empty()) {
188     return NULL;
189   }
190   
191   List r = NavDataCache::instance()->findAllWithIdent(aIdent, aFilter, true);
192   if (r.empty()) {
193     return NULL;
194   }
195   
196   return r.front();
197 }
198
199 FGPositioned::List
200 FGPositioned::findWithinRange(const SGGeod& aPos, double aRangeNm, Filter* aFilter)
201 {
202   validateSGGeod(aPos);
203
204   List result;
205   Octree::findAllWithinRange(SGVec3d::fromGeod(aPos), 
206     aRangeNm * SG_NM_TO_METER, aFilter, result);
207   return result;
208 }
209
210 FGPositioned::List
211 FGPositioned::findAllWithIdent(const std::string& aIdent, Filter* aFilter, bool aExact)
212 {
213   return NavDataCache::instance()->findAllWithIdent(aIdent, aFilter, aExact);
214 }
215
216 FGPositioned::List
217 FGPositioned::findAllWithName(const std::string& aName, Filter* aFilter, bool aExact)
218 {
219   return NavDataCache::instance()->findAllWithName(aName, aFilter, aExact);
220 }
221
222 FGPositionedRef
223 FGPositioned::findClosest(const SGGeod& aPos, double aCutoffNm, Filter* aFilter)
224 {
225   validateSGGeod(aPos);
226   
227   List l(findClosestN(aPos, 1, aCutoffNm, aFilter));
228   if (l.empty()) {
229     return NULL;
230   }
231
232   assert(l.size() == 1);
233   return l.front();
234 }
235
236 FGPositioned::List
237 FGPositioned::findClosestN(const SGGeod& aPos, unsigned int aN, double aCutoffNm, Filter* aFilter)
238 {
239   validateSGGeod(aPos);
240   
241   List result;
242   Octree::findNearestN(SGVec3d::fromGeod(aPos), aN, aCutoffNm * SG_NM_TO_METER, aFilter, result);
243   return result;
244 }
245  
246 void
247 FGPositioned::sortByRange(List& aResult, const SGGeod& aPos)
248 {
249   validateSGGeod(aPos);
250   
251   SGVec3d cartPos(SGVec3d::fromGeod(aPos));
252 // computer ordering values
253   Octree::FindNearestResults r;
254   List::iterator it = aResult.begin(), lend = aResult.end();
255   for (; it != lend; ++it) {
256     double d2 = distSqr((*it)->cart(), cartPos);
257     r.push_back(Octree::OrderedPositioned(*it, d2));
258   }
259   
260 // sort
261   std::sort(r.begin(), r.end());
262   
263 // convert to a plain list
264   unsigned int count = aResult.size();
265   for (unsigned int i=0; i<count; ++i) {
266     aResult[i] = r[i].get();
267   }
268 }
269
270 void FGPositioned::modifyPosition(const SGGeod& newPos)
271 {
272   const_cast<SGGeod&>(mPosition) = newPos;
273   const_cast<SGVec3d&>(mCart) = SGVec3d::fromGeod(newPos);
274 }
275
276 FGPositioned::TypeFilter::TypeFilter(Type aTy) :
277   mMinType(aTy),
278   mMaxType(aTy)
279 {
280   addType(aTy);
281 }
282
283 void FGPositioned::TypeFilter::addType(Type aTy)
284 {
285   if (aTy == INVALID) {
286     return;
287   }
288   
289   types.push_back(aTy);
290   mMinType = std::min(mMinType, aTy);
291   mMaxType = std::max(mMaxType, aTy);
292 }
293
294 bool
295 FGPositioned::TypeFilter::pass(FGPositioned* aPos) const
296 {
297   if (types.empty()) {
298     return true;
299   }
300   
301     std::vector<Type>::const_iterator it = types.begin(),
302         end = types.end();
303     for (; it != end; ++it) {
304         return aPos->type() == *it;
305     }
306     
307     return false;
308 }
309