diff --git a/src/Airports/GenAirports850/airport.cxx b/src/Airports/GenAirports850/airport.cxx index 31b370c9..9f11902b 100644 --- a/src/Airports/GenAirports850/airport.cxx +++ b/src/Airports/GenAirports850/airport.cxx @@ -29,18 +29,54 @@ Airport::Airport( int c, char* def) { int numParams; - char d[100]; - char tmp[16]; + char* tok; int x, y; code = c; - numParams = sscanf(def, "%d %d %d %s %ls", &altitude, &x, &y, tmp, d); + // we need to tokenize airports, since we can't scanf two strings next to each other... + numParams = 0; + bool done = false; + + while (!done) + { + // trim leading whitespace + while(isspace(*def)) def++; + + tok = strtok(def, " \t\r\n"); + + if (tok) + { + def += strlen(tok)+1; + + switch( numParams ) + { + case 0: + altitude = atoi(tok); + break; + + case 1: + x = atoi(tok); + break; + + case 2: + y = atoi(tok); + break; + + case 3: + icao = tok; + description = def; + done = true; + break; + } + } + numParams++; + } altitude *= SG_FEET_TO_METER; - icao = tmp; - description = d; boundary = NULL; + + SG_LOG( SG_GENERAL, SG_DEBUG, "Created airport with icao " << icao << " and description " << description ); } // TODO: fix OSG - it was nice, but unnecesary... diff --git a/src/Airports/GenAirports850/airport.hxx b/src/Airports/GenAirports850/airport.hxx index 86371b09..0e57db24 100644 --- a/src/Airports/GenAirports850/airport.hxx +++ b/src/Airports/GenAirports850/airport.hxx @@ -77,6 +77,11 @@ public: signs.push_back( sign ); } + string GetIcao( ) + { + return icao; + } + void BuildOsg( osg::Group* airport ); void BuildBtg( const string& root, const string_list& elev_src ); diff --git a/src/Airports/GenAirports850/linearfeature.cxx b/src/Airports/GenAirports850/linearfeature.cxx index 88154086..fc566181 100644 --- a/src/Airports/GenAirports850/linearfeature.cxx +++ b/src/Airports/GenAirports850/linearfeature.cxx @@ -302,14 +302,14 @@ Point3D LinearFeature::OffsetPointMiddle( Point3D *prev, Point3D *cur, Point3D * // check the turn direction SGVec3d cp = cross( dir1, dir2 ); - SG_LOG(SG_GENERAL, SG_ALERT, "\tcross product of dir1: " << dir1 << " and dir2: " << dir2 << " is " << cp ); + SG_LOG(SG_GENERAL, SG_DEBUG, "\tcross product of dir1: " << dir1 << " and dir2: " << dir2 << " is " << cp ); // calculate the angle between cur->prev and cur->next theta = SGMiscd::rad2deg(CalculateTheta(*prev, *cur, *next)); if ( abs(theta - 180.0) < 0.1 ) { - SG_LOG(SG_GENERAL, SG_ALERT, "\nLinearFeature: (theta close to 180) " << description << ": theta is " << theta ); + SG_LOG(SG_GENERAL, SG_DEBUG, "\nLinearFeature: (theta close to 180) " << description << ": theta is " << theta ); // find the direction to the next point geo_inverse_wgs_84( cur->y(), cur->x(), next->y(), next->x(), &next_dir, &az2, &dist); @@ -325,7 +325,7 @@ Point3D LinearFeature::OffsetPointMiddle( Point3D *prev, Point3D *cur, Point3D * } else if ( abs(theta) < 0.1 ) { - SG_LOG(SG_GENERAL, SG_ALERT, "\nLinearFeature: (theta close to 0) " << description << ": theta is " << theta ); + SG_LOG(SG_GENERAL, SG_DEBUG, "\nLinearFeature: (theta close to 0) " << description << ": theta is " << theta ); // find the direction to the next point geo_inverse_wgs_84( cur->y(), cur->x(), next->y(), next->x(), &next_dir, &az2, &dist); @@ -341,7 +341,7 @@ Point3D LinearFeature::OffsetPointMiddle( Point3D *prev, Point3D *cur, Point3D * } else { - SG_LOG(SG_GENERAL, SG_ALERT, "\nLinearFeature: (theta NOT close to 180) " << description << ": theta is " << theta ); + SG_LOG(SG_GENERAL, SG_DEBUG, "\nLinearFeature: (theta NOT close to 180) " << description << ": theta is " << theta ); // find the offset angle geo_inverse_wgs_84( avg.y(), avg.x(), 0.0f, 0.0f, &offset_dir, &az2, &dist); @@ -363,12 +363,12 @@ Point3D LinearFeature::OffsetPointMiddle( Point3D *prev, Point3D *cur, Point3D * dist = (offset_by)/sin(SGMiscd::deg2rad(next_dir-offset_dir)); } - SG_LOG(SG_GENERAL, SG_ALERT, "\theading is " << offset_dir << " distance is " << dist ); + SG_LOG(SG_GENERAL, SG_DEBUG, "\theading is " << offset_dir << " distance is " << dist ); // calculate the point from cur geo_direct_wgs_84( cur->y(), cur->x(), offset_dir, dist, &pt_y, &pt_x, &az2 ); - SG_LOG(SG_GENERAL, SG_ALERT, "\tpoint is (" << pt_x << "," << pt_y << ")" ); + SG_LOG(SG_GENERAL, SG_DEBUG, "\tpoint is (" << pt_x << "," << pt_y << ")" ); return Point3D(pt_x, pt_y, 0.0f); } diff --git a/src/Airports/GenAirports850/main.cxx b/src/Airports/GenAirports850/main.cxx index c081dae2..ac170b7f 100644 --- a/src/Airports/GenAirports850/main.cxx +++ b/src/Airports/GenAirports850/main.cxx @@ -58,17 +58,19 @@ #include #include - #include -//#include #include +#include #include "beznode.hxx" #include "closedpoly.hxx" #include "linearfeature.hxx" #include "parser.hxx" +using namespace std; + + // TODO : Modularize this function // IDEAS // 1) Start / Stop MarkStyle @@ -105,6 +107,42 @@ void setup_default_elevation_sources(string_list& elev_src) { elev_src.push_back( "SRTM-30" ); } +// Display help and usage +static void help( int argc, char **argv, const string_list& elev_src ) { + cout << "genapts generates airports for use in generating scenery for the FlightGear flight simulator. \n"; + cout << "Airport, runway, and taxiway vector data and attributes are input, and generated 3D airports \n"; + cout << "are output for further processing by the TerraGear scenery creation tools. \n"; + cout << "\n\n"; + cout << "The standard input file is runways.dat.gz which is found in $FG_ROOT/Airports. \n"; + cout << "This file is periodically generated for the FlightGear project by Robin Peel, who \n"; + cout << "maintains an airport database for both the X-Plane and FlightGear simulators. \n"; + cout << "The format of this file is documented on the FlightGear web site. \n"; + cout << "Any other input file corresponding to this format may be used as input to genapts. \n"; + cout << "Input files may be gzipped or left as plain text as required. \n"; + cout << "\n\n"; + cout << "Processing all the world's airports takes a *long* time. To cut down processing time \n"; + cout << "when only some airports are required, you may refine the input selection either by airport \n"; + cout << "or by area. By airport, either one airport can be specified using --airport=abcd, where abcd is \n"; + cout << "a valid airport code eg. --airport-id=KORD, or a starting airport can be specified using --start-id=abcd \n"; + cout << "where once again abcd is a valid airport code. In this case, all airports in the file subsequent to the \n"; + cout << "start-id are done. This is convienient when re-starting after a previous error. \n"; + cout << "\nAn input area may be specified by lat and lon extent using min and max lat and lon. \n"; + cout << "Alternatively, you may specify a chunk (10 x 10 degrees) or tile (1 x 1 degree) using a string \n"; + cout << "such as eg. w080n40, e000s27. \n"; + cout << "\nAn input file containing only a subset of the world's \n"; + cout << "airports may of course be used.\n"; + cout << "\n\n"; + cout << "It is necessary to generate the elevation data for the area of interest PRIOR TO GENERATING THE AIRPORTS. \n"; + cout << "Failure to do this will result in airports being generated with an elevation of zero. \n"; + cout << "The following subdirectories of the work-dir will be searched for elevation files:\n\n"; + + string_list::const_iterator elev_src_it; + for (elev_src_it = elev_src.begin(); elev_src_it != elev_src.end(); elev_src_it++) { + cout << *elev_src_it << "\n"; + } + cout << "\n"; + usage( argc, argv ); +} // TODO: where do these belong int nudge = 10; @@ -116,7 +154,6 @@ int main(int argc, char **argv) float max_lon = 180; float min_lat = -90; float max_lat = 90; - bool ready_to_go = true; bool view_osg = false; string_list elev_src; @@ -154,7 +191,6 @@ int main(int argc, char **argv) else if ( arg.find("--start-id=") == 0 ) { start_id = arg.substr(11); - ready_to_go = false; } else if ( arg.find("--nudge=") == 0 ) { @@ -176,7 +212,6 @@ int main(int argc, char **argv) { max_lat = atof( arg.substr(10).c_str() ); } -#if 0 else if ( arg.find("--chunk=") == 0 ) { tg::Rectangle rectangle = tg::parseChunk(arg.substr(8).c_str(), 10.0); @@ -193,11 +228,9 @@ int main(int argc, char **argv) max_lon = rectangle.getMax().x(); max_lat = rectangle.getMax().y(); } -#endif else if ( arg.find("--airport=") == 0 ) { airport_id = arg.substr(10).c_str(); - ready_to_go = false; } else if ( arg == "--clear-dem-path" ) { @@ -220,13 +253,11 @@ int main(int argc, char **argv) { slope_max = atof( arg.substr(12).c_str() ); } -#if 0 else if ( (arg.find("--help") == 0) || (arg.find("-h") == 0) ) { help( argc, argv, elev_src ); exit(-1); } -#endif else { usage( argc, argv ); @@ -290,48 +321,40 @@ int main(int argc, char **argv) SG_LOG(SG_GENERAL, SG_INFO, "Creating parser"); // Create the parser... - Parser* parser = new Parser(input_file); + Parser* parser = new Parser(input_file, work_dir, elev_src); - SG_LOG(SG_GENERAL, SG_INFO, "Parse katl"); - parser->Parse((char*)"edfe"); - - if (view_osg) + // just one airport + if ( airport_id != "" ) { - // just view in OSG - osg::Group* airportNode; + // just find and add the one airport + parser->AddAirport( airport_id ); - SG_LOG(SG_GENERAL, SG_INFO, "View OSG"); - airportNode = parser->CreateOsgGroup(); + SG_LOG(SG_GENERAL, SG_INFO, "Finished Adding airport - now parse"); + + // and start the parser + parser->Parse(); + } +#if 0 + else if ( start_id != "" ) + { + // scroll forward in datafile + parser->FindAirport( start_id ); - // construct the viewer. - osgViewer::Viewer viewer; + // add remaining airports within boundary + parser->AddAirports( min_lat, min_lon, max_lat, max_lon ); - // add the thread model handler - viewer.addEventHandler(new osgViewer::ThreadingHandler); - - // add the window size toggle handler - viewer.addEventHandler(new osgViewer::WindowSizeHandler); - - // add model to viewer. - viewer.setSceneData( airportNode ); - viewer.setUpViewAcrossAllScreens(); - - // create the windows and run the threads. - viewer.realize(); - - viewer.setCameraManipulator(new osgGA::TrackballManipulator()); - - osgUtil::Optimizer optimzer; - optimzer.optimize(airportNode); - - viewer.run(); + // parse all the airports that were found + parser->Parse(); } else { - // write a .btg file.... - SG_LOG(SG_GENERAL, SG_INFO, "Write BTG"); - parser->WriteBtg(work_dir, elev_src); + // find all airports within given boundary + parser->AddAirports( min_lat, min_lon, max_lat, max_lon ); + + // and parser them + parser->Parse(); } +#endif SG_LOG(SG_GENERAL, SG_INFO, "Done"); diff --git a/src/Airports/GenAirports850/parser.cxx b/src/Airports/GenAirports850/parser.cxx index 5eac64e7..f5591762 100644 --- a/src/Airports/GenAirports850/parser.cxx +++ b/src/Airports/GenAirports850/parser.cxx @@ -3,35 +3,140 @@ #include "parser.hxx" -#if 0 -int Parser::ParseBoundry(char* line) -{ - return 0; -} -#endif -int Parser::Parse( char* icao ) +bool Parser::IsAirportDefinition( char* line, string icao ) { - string line; - char tmp[2048]; + char* tok; + int code; + Airport* airport = NULL; + bool match = false; + + // Get the number code + tok = strtok(line, " \t\r\n"); - sg_gzifstream in( filename ); + if (tok) + { + line += strlen(tok)+1; + code = atoi(tok); + + switch(code) + { + case LAND_AIRPORT_CODE: + case SEA_AIRPORT_CODE: + airport = new Airport( code, line ); + if ( airport->GetIcao() == icao ) + { + + match = true; + } + break; + + case HELIPORT_CODE: + case LAND_RUNWAY_CODE: + case WATER_RUNWAY_CODE: + case HELIPAD_CODE: + case PAVEMENT_CODE: + case LINEAR_FEATURE_CODE: + case BOUNDRY_CODE: + case NODE_CODE: + case BEZIER_NODE_CODE: + case CLOSE_NODE_CODE: + case CLOSE_BEZIER_NODE_CODE: + case TERM_NODE_CODE: + case TERM_BEZIER_NODE_CODE: + case AIRPORT_VIEWPOINT_CODE: + case AIRPLANE_STARTUP_LOCATION_CODE: + case LIGHT_BEACON_CODE: + case WINDSOCK_CODE: + case TAXIWAY_SIGN: + case LIGHTING_OBJECT: + case COMM_FREQ1_CODE: + case COMM_FREQ2_CODE: + case COMM_FREQ3_CODE: + case COMM_FREQ4_CODE: + case COMM_FREQ5_CODE: + case COMM_FREQ6_CODE: + case COMM_FREQ7_CODE: + case END_OF_FILE : + break; + } + } + + return match; +} + +void Parser::AddAirport( string icao ) +{ + char line[2048]; + long cur_pos; + bool found = false; + + ifstream in( filename.c_str() ); if ( !in.is_open() ) { SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << filename ); exit(-1); } - while ( !in.eof() ) + SG_LOG( SG_GENERAL, SG_ALERT, "Adding airport " << icao << " to parse list"); + while ( !in.eof() && !found ) { - in.getline(tmp, 2048); - line = tmp; + // remember the position of this line + cur_pos = in.tellg(); - // Parse the line - ParseLine(tmp); + // get a line + in.getline(line, 2048); + + // this is and airport definition - remember it + if ( IsAirportDefinition( line, icao ) ) + { + SG_LOG( SG_GENERAL, SG_ALERT, "Found airport " << line << " at " << cur_pos ); + parse_positions.push_back( cur_pos ); + found = true; + } + } +} + +void Parser::Parse() +{ + char tmp[2048]; + bool done = false; + int i; + + ifstream in( filename.c_str() ); + if ( !in.is_open() ) + { + SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << filename ); + exit(-1); } - return 1; + // for each position in parse_positions, parse an airport + for (i=0; iBuildBtg( work_dir, elevation ); + + delete cur_airport; + cur_airport = NULL; + } + } } BezNode* Parser::ParseNode( int type, char* line, BezNode* prevNode ) @@ -183,7 +288,7 @@ LinearFeature* Parser::ParseFeature( char* line ) feature = new LinearFeature(NULL, 0.0f); } - SG_LOG(SG_GENERAL, SG_ALERT, "Creating Linear Feature with desription \"" << line << "\""); + SG_LOG(SG_GENERAL, SG_DEBUG, "Creating Linear Feature with desription \"" << line << "\""); return feature; } @@ -226,7 +331,7 @@ ClosedPoly* Parser::ParseBoundary( char* line ) } else { - d = "none"; + d = (char *)"none"; } SG_LOG(SG_GENERAL, SG_DEBUG, "Creating Closed Poly for airport boundary : " << d); @@ -278,10 +383,16 @@ int Parser::ParseLine(char* line) { case LAND_AIRPORT_CODE: case SEA_AIRPORT_CODE: - SetState( STATE_PARSE_SIMPLE ); - SG_LOG(SG_GENERAL, SG_DEBUG, "Parsing land airport: " << line); - cur_airport = new Airport( code, line ); - airports.push_back( cur_airport ); + if (cur_state == STATE_NONE) + { + SetState( STATE_PARSE_SIMPLE ); + SG_LOG(SG_GENERAL, SG_DEBUG, "Parsing land airport: " << line); + cur_airport = new Airport( code, line ); + } + else + { + SetState( STATE_DONE ); + } break; case HELIPORT_CODE: SetState( STATE_PARSE_SIMPLE ); @@ -504,19 +615,10 @@ int Parser::ParseLine(char* line) } } - return 0; -} - -void Parser::WriteBtg( const string& root, const string_list& elev_src ) -{ - int i; - - for (i=0; iBuildBtg( root, elev_src ); - } + return cur_state; } +#if 0 osg::Group* Parser::CreateOsgGroup( void ) { osg::Group* airportNode = new osg::Group(); @@ -530,4 +632,5 @@ osg::Group* Parser::CreateOsgGroup( void ) return airportNode; } +#endif diff --git a/src/Airports/GenAirports850/parser.hxx b/src/Airports/GenAirports850/parser.hxx index 0932b326..29fcaa18 100644 --- a/src/Airports/GenAirports850/parser.hxx +++ b/src/Airports/GenAirports850/parser.hxx @@ -1,6 +1,9 @@ #ifndef _PARSER_H_ #define _PARSER_H_ +#include +#include + #include "beznode.hxx" #include "closedpoly.hxx" #include "linearfeature.hxx" @@ -52,12 +55,20 @@ #define END_OF_FILE (99) +using namespace std; + + +typedef std::vector ParseList; + class Parser { public: - Parser(string& f) + Parser(string& datafile, const string& root, const string_list& elev_src) { - filename = f; + filename = datafile; + work_dir = root; + elevation = elev_src; + cur_airport = NULL; cur_runway = NULL; cur_waterrunway = NULL; @@ -73,11 +84,18 @@ public: cur_state = STATE_NONE; } - int Parse( char* icao ); - void WriteBtg( const string& root, const string_list& elev_src ); - osg::Group* CreateOsgGroup( void ); +// int Parse( char* icao ); + void FindAirport( string icao ); + void AddAirport( string icao ); + void AddAirports( float min_lat, float min_lon, float max_lat, float max_lon ); + void Parse( void ); + +// osg::Group* CreateOsgGroup( void ); + private: + bool IsAirportDefinition( char* line, string icao ); + int SetState( int state ); BezNode* ParseNode( int type, char* line, BezNode* prevNode ); @@ -91,6 +109,8 @@ private: BezNode* prev_node; int cur_state; string filename; + string_list elevation; + string work_dir; // a polygon conists of an array of contours // (first is outside boundry, remaining are holes) @@ -106,7 +126,8 @@ private: Beacon* cur_beacon; Sign* cur_sign; - AirportList airports; + // List of positions in database file to parse + ParseList parse_positions; }; #endif