#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>
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));
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;
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)
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;
}
response.Header["Content-Type"] = "application/json; charset=UTF-8";
bool indent = request.RequestVariables.get("i") == "y";
+
string query = request.RequestVariables.get("q");
FGPositionedList result;
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();
// 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.