]> git.mxchange.org Git - flightgear.git/commitdiff
httpd: provide more airport information in geojson
authorTorsten Dreyer <torsten@t3r.de>
Sun, 23 Mar 2014 20:19:04 +0000 (21:19 +0100)
committerTorsten Dreyer <torsten@t3r.de>
Sun, 23 Mar 2014 20:19:04 +0000 (21:19 +0100)
- provide runways as polygon geometry
- provide longest runway lenght, heading and surface type
- some code cleanup

src/Airports/runwaybase.cxx
src/Airports/runwaybase.hxx
src/Network/http/NavdbUriHandler.cxx

index 4f60682a9a75b36ecaacee90276e70be39349fcd..d5176c88b370db4ae83d9552519dd45b536c231a 100644 (file)
@@ -45,6 +45,22 @@ using std::string;
  * 9 - dirt helipad
  * 12 -  lakebed
  */
+const char * FGRunwayBase::surfaceName( int surface_code )
+{
+  switch( surface_code ) {
+    case 1: return "asphalt";
+    case 2: return "concrete";
+    case 3: return "turf";
+    case 4: return "dirt";
+    case 5: return "gravel";
+    case 6: return "asphalt helipad";
+    case 7: return "concrete helipad";
+    case 8: return "turf helipad";
+    case 9: return "dirt helipad";
+    case 12: return "lakebed";
+    default: return "unknown";
+  }
+}
 
 FGRunwayBase::FGRunwayBase(PositionedID aGuid, Type aTy, const string& aIdent,
                         const SGGeod& aGeod,
index e13101b19d99d418dbf721871157ffe37cdef828..c365f69e52fa425bdc39132d6b98cff1fa87df89 100644 (file)
@@ -82,6 +82,12 @@ public:
    */
   int surface() const 
   { return _surface_code; }
+
+  /**
+   * Retrieve runway surface name, as define in Robin Peel's data
+   */
+  static const char * surfaceName( int surface_code );
+  const char * surfaceName() { return surfaceName( _surface_code ); }
   
 protected:
     
index 7cc341d6a0ab458fd5c297bd4ab83513bc1a3487..2b568dc1c3895f5c996174e3d28a3e31d68709b8 100644 (file)
@@ -21,6 +21,7 @@
 #include "NavdbUriHandler.hxx"
 #include <simgear/debug/logstream.hxx>
 #include <Navaids/navrecord.hxx>
+#include <Airports/airport.hxx>
 #include <3rdparty/cjson/cJSON.h>
 #include <boost/lexical_cast.hpp>
 
@@ -29,9 +30,7 @@ using std::string;
 namespace flightgear {
 namespace http {
 
-//Ref: http://geojson.org/
-
-static cJSON * createPosition(double x, double y)
+static cJSON * createPositionArray(double x, double y)
 {
   cJSON * p = cJSON_CreateArray();
   cJSON_AddItemToArray(p, cJSON_CreateNumber(x));
@@ -39,45 +38,92 @@ static cJSON * createPosition(double x, double y)
   return p;
 }
 
-static cJSON * createGeometryFor(FGNavRecord * navRecord)
+static cJSON * createLOCGeometry(FGNavRecord * navRecord)
 {
-  if ( NULL == navRecord) return NULL;
+  assert( navRecord != NULL );
+
   cJSON * geometry = cJSON_CreateObject();
+  int range = navRecord->get_range();
 
-  if (navRecord->type() == FGPositioned::LOC || navRecord->type() == FGPositioned::ILS) {
-    int range = navRecord->get_range();
+  double width = navRecord->localizerWidth();
+  double course = navRecord->get_multiuse();
 
-    double width = navRecord->localizerWidth();
-    double course = navRecord->get_multiuse();
+  double px[4];
+  double py[4];
 
-    double px[4];
-    double py[4];
+  px[0] = navRecord->longitude();
+  py[0] = navRecord->latitude();
 
-    px[0] = navRecord->longitude();
-    py[0] = navRecord->latitude();
+  for (int i = -1; i <= +1; i++) {
+    double c = SGMiscd::normalizeAngle((course + 180 + i * width / 2) * SG_DEGREES_TO_RADIANS);
+    SGGeoc geoc = SGGeoc::fromGeod(navRecord->geod());
+    SGGeod p2 = SGGeod::fromGeoc(geoc.advanceRadM(c, range * SG_NM_TO_METER));
+    px[i + 2] = p2.getLongitudeDeg();
+    py[i + 2] = p2.getLatitudeDeg();
+  }
+  // Add three lines: centerline, left and right edge
+  cJSON_AddItemToObject(geometry, "type", cJSON_CreateString("MultiLineString"));
+  cJSON * coordinates = cJSON_CreateArray();
+  cJSON_AddItemToObject(geometry, "coordinates", coordinates);
+  for (int i = 1; i < 4; i++) {
+    cJSON * line = cJSON_CreateArray();
+    cJSON_AddItemToArray(coordinates, line);
+    cJSON_AddItemToArray(line, createPositionArray(px[0], py[0]));
+    cJSON_AddItemToArray(line, createPositionArray(px[i], py[i]));
+  }
 
-    for (int i = -1; i <= +1; i++) {
-      double c = SGMiscd::normalizeAngle((course + 180 + i*width/2 ) * SG_DEGREES_TO_RADIANS);
-      SGGeoc geoc = SGGeoc::fromGeod(navRecord->geod());
-      SGGeod p2 = SGGeod::fromGeoc(geoc.advanceRadM(c, range * SG_NM_TO_METER));
-      px[i+2] = p2.getLongitudeDeg();
-      py[i+2] = p2.getLatitudeDeg();
-    }
-    // Add three lines: centerline, left and right edge
-    cJSON_AddItemToObject(geometry, "type", cJSON_CreateString("MultiLineString"));
-    cJSON * coordinates = cJSON_CreateArray();
-    cJSON_AddItemToObject(geometry, "coordinates", coordinates);
-    for (int i = 1; i < 4; i++) {
-      cJSON * line = cJSON_CreateArray();
-      cJSON_AddItemToArray(coordinates, line);
-      cJSON_AddItemToArray(line, createPosition(px[0], py[0]));
-      cJSON_AddItemToArray(line, createPosition(px[i], py[i]));
-    }
+  return geometry;
+}
 
-  } else {
+static cJSON * createPointGeometry(FGPositionedRef positioned )
+{
+  cJSON * geometry = cJSON_CreateObject();
+  cJSON_AddItemToObject(geometry, "type", cJSON_CreateString("Point"));
+  cJSON_AddItemToObject(geometry, "coordinates", createPositionArray(positioned ->longitude(), positioned->latitude()));
+  return geometry;
+}
+
+static cJSON * createAirportGeometry(FGAirport * airport )
+{
+  assert( airport != NULL );
+  FGRunwayList runways = airport->getRunwaysWithoutReciprocals();
+
+  if( runways.empty() ) {
+    // no runways? Create a Point geometry
+    return createPointGeometry( airport );
+  }
 
-    cJSON_AddItemToObject(geometry, "type", cJSON_CreateString("Point"));
-    cJSON_AddItemToObject(geometry, "coordinates", createPosition(navRecord->longitude(), navRecord->latitude()));
+  cJSON * geometry = cJSON_CreateObject();
+
+  // if there are runways, create a geometry collection
+  cJSON_AddItemToObject(geometry, "type", cJSON_CreateString("GeometryCollection"));
+  cJSON * geometryCollection = cJSON_CreateArray();
+  cJSON_AddItemToObject(geometry, "geometries", geometryCollection);
+
+  // the first item is the aerodrome reference point
+  cJSON_AddItemToArray( geometryCollection, createPointGeometry(airport) );
+
+  // followed by the runway polygons
+  for( FGRunwayList::iterator it = runways.begin(); it != runways.end(); ++it ) {
+    cJSON * polygon = cJSON_CreateObject(); 
+    cJSON_AddItemToArray( geometryCollection, polygon );
+    cJSON_AddItemToObject(polygon, "type", cJSON_CreateString("Polygon"));
+    cJSON * coordinates = cJSON_CreateArray();
+    cJSON_AddItemToObject(polygon, "coordinates", coordinates );
+    cJSON * linearRing = cJSON_CreateArray();
+    cJSON_AddItemToArray( coordinates, linearRing );
+
+    // compute the four corners of the runway
+    SGGeod p1 = (*it)->pointOffCenterline( 0.0, (*it)->widthM()/2 );
+    SGGeod p2 = (*it)->pointOffCenterline( 0.0, -(*it)->widthM()/2 );
+    SGGeod p3 = (*it)->pointOffCenterline( (*it)->lengthM(), -(*it)->widthM()/2 );
+    SGGeod p4 = (*it)->pointOffCenterline( (*it)->lengthM(), (*it)->widthM()/2 );
+    cJSON_AddItemToArray( linearRing, createPositionArray(p1.getLongitudeDeg(), p1.getLatitudeDeg()) );
+    cJSON_AddItemToArray( linearRing, createPositionArray(p2.getLongitudeDeg(), p2.getLatitudeDeg()) );
+    cJSON_AddItemToArray( linearRing, createPositionArray(p3.getLongitudeDeg(), p3.getLatitudeDeg()) );
+    cJSON_AddItemToArray( linearRing, createPositionArray(p4.getLongitudeDeg(), p4.getLatitudeDeg()) );
+    // close the ring
+    cJSON_AddItemToArray( linearRing, createPositionArray(p1.getLongitudeDeg(), p1.getLatitudeDeg()) );
   }
 
   return geometry;
@@ -85,19 +131,57 @@ static cJSON * createGeometryFor(FGNavRecord * navRecord)
 
 static cJSON * createGeometryFor(FGPositionedRef positioned)
 {
-  cJSON * geometry = createGeometryFor(dynamic_cast<FGNavRecord*>(positioned.get()));
-  if ( NULL != geometry) return geometry;
+  switch( positioned->type() ) {
+    case FGPositioned::LOC:
+    case FGPositioned::ILS:
+      return createLOCGeometry( dynamic_cast<FGNavRecord*>(positioned.get()) );
 
-  geometry = cJSON_CreateObject();
-  cJSON_AddItemToObject(geometry, "type", cJSON_CreateString("Point"));
+    case FGPositioned::AIRPORT:
+      return createAirportGeometry( dynamic_cast<FGAirport*>(positioned.get()) );
 
-  cJSON * coordinates = cJSON_CreateArray();
-  cJSON_AddItemToObject(geometry, "coordinates", coordinates);
+    default:
+      return createPointGeometry( positioned );
+  }
+}
 
-  cJSON_AddItemToArray(coordinates, cJSON_CreateNumber(positioned->longitude()));
-  cJSON_AddItemToArray(coordinates, cJSON_CreateNumber(positioned->latitude()));
+static void addAirportProperties(cJSON * json, FGAirport * airport )
+{
+  if( NULL == airport ) return;
+  FGRunwayList runways = airport->getRunwaysWithoutReciprocals();
+  double longestRunwayLength = 0.0;
+  double longestRunwayHeading = 0.0;
+  const char * longestRunwaySurface = "";
+  for( FGRunwayList::iterator it = runways.begin(); it != runways.end(); ++it ) {
+    FGRunwayRef runway = *it;
+    if( runway->lengthM() > longestRunwayLength ) {
+      longestRunwayLength = runway->lengthM();
+      longestRunwayHeading = runway->headingDeg();
+      longestRunwaySurface = runway->surfaceName();
+    }
+  }
+  cJSON_AddItemToObject(json, "longestRwyLength_m", cJSON_CreateNumber(longestRunwayLength));
+  cJSON_AddItemToObject(json, "longestRwyHeading_deg", cJSON_CreateNumber(longestRunwayHeading));
+  cJSON_AddItemToObject(json, "longestRwySurface", cJSON_CreateString(longestRunwaySurface));
+}
 
-  return geometry;
+static void addNAVProperties(cJSON * json, FGNavRecord * navRecord )
+{
+  if( NULL == navRecord ) return;
+  cJSON_AddItemToObject(json, "range_nm", cJSON_CreateNumber(navRecord->get_range()));
+  cJSON_AddItemToObject(json, "frequency", cJSON_CreateNumber((double) navRecord->get_freq() / 100.0));
+  switch (navRecord->type()) {
+    case FGPositioned::ILS:
+    case FGPositioned::LOC:
+      cJSON_AddItemToObject(json, "localizer-course", cJSON_CreateNumber(navRecord->get_multiuse()));
+      break;
+
+    case FGPositioned::VOR:
+      cJSON_AddItemToObject(json, "variation", cJSON_CreateNumber(navRecord->get_multiuse()));
+      break;
+
+    default:
+      break;
+  }
 }
 
 static cJSON * createPropertiesFor(FGPositionedRef positioned)
@@ -107,24 +191,8 @@ static cJSON * createPropertiesFor(FGPositionedRef positioned)
   cJSON_AddItemToObject(properties, "name", cJSON_CreateString(positioned->name().c_str()));
   cJSON_AddItemToObject(properties, "type", cJSON_CreateString(positioned->typeString()));
   cJSON_AddItemToObject(properties, "elevation-m", cJSON_CreateNumber(positioned->elevationM()));
-  FGNavRecord * navRecord = dynamic_cast<FGNavRecord*>(positioned.get());
-  if ( NULL != navRecord) {
-    cJSON_AddItemToObject(properties, "range-nm", cJSON_CreateNumber(navRecord->get_range()));
-    cJSON_AddItemToObject(properties, "frequency", cJSON_CreateNumber((double) navRecord->get_freq() / 100.0));
-    switch (navRecord->type()) {
-      case FGPositioned::ILS:
-        cJSON_AddItemToObject(properties, "localizer-course", cJSON_CreateNumber(navRecord->get_multiuse()));
-        break;
-
-      case FGPositioned::VOR:
-        cJSON_AddItemToObject(properties, "variation", cJSON_CreateNumber(navRecord->get_multiuse()));
-        break;
-
-      default:
-        break;
-    }
-
-  }
+  addNAVProperties( properties, dynamic_cast<FGNavRecord*>(positioned.get()) );
+  addAirportProperties( properties, dynamic_cast<FGAirport*>(positioned.get()) );
   return properties;
 }
 
@@ -156,6 +224,7 @@ bool NavdbUriHandler::handleRequest(const HTTPRequest & request, HTTPResponse &
   response.Header["Content-Type"] = "application/json; charset=UTF-8";
 
   bool indent = request.RequestVariables.get("i") == "y";
+
   string query = request.RequestVariables.get("q");
   FGPositionedList result;
 
@@ -189,7 +258,7 @@ bool NavdbUriHandler::handleRequest(const HTTPRequest & request, HTTPResponse &
     goto fail;
   }
 
 { // create some GeoJSON from the result list
+ { // create some GeoJSON from the result list
     // GeoJSON always consists of a single object.
     cJSON * geoJSON = cJSON_CreateObject();
 
@@ -197,6 +266,7 @@ bool NavdbUriHandler::handleRequest(const HTTPRequest & request, HTTPResponse &
     // This member's value is a string that determines the type of the GeoJSON object.
     cJSON_AddItemToObject(geoJSON, "type", cJSON_CreateString("FeatureCollection"));
 
+    // we send zero to many features - let's make it a FeatureCollection
     // A GeoJSON object with the type "FeatureCollection" is a feature collection object.
     // An object of type "FeatureCollection" must have a member with the name "features".
     // The value corresponding to "features" is an array.