diff --git a/src/BuildTiles/Parallel/client.cxx b/src/BuildTiles/Parallel/client.cxx index 855ce6f6..46ea04b3 100644 --- a/src/BuildTiles/Parallel/client.cxx +++ b/src/BuildTiles/Parallel/client.cxx @@ -175,8 +175,8 @@ long int get_next_task( const string& host, int port, long int last_tile ) { // successfully bool construct_tile( const SGBucket& b, const string& result_file, - const string &cover ) { - double angle = 10.0; + const string &cover, + float angle ) { bool still_trying = true; while ( still_trying ) { @@ -216,6 +216,9 @@ bool construct_tile( const SGBucket& b, angle = 5.0; still_trying = true; } else if ( angle > 4.0 ) { + angle = 1.0; + still_trying = true; + } else if ( angle > 0.0 ) { angle = 0.0; still_trying = true; } @@ -257,6 +260,7 @@ int main(int argc, char *argv[]) { string cover; string host = "127.0.0.1"; int port=4001; + float angle = 10.0; // // Parse the command-line arguments. @@ -277,6 +281,8 @@ int main(int argc, char *argv[]) { rude = true; } else if (arg.find("--cover=") == 0) { cover = arg.substr(8); + } else if (arg.find("--min-angle=") == 0) { + angle = atof(arg.substr(12).c_str()); } else if (arg.find("--") == 0) { usage(argv[0]); } else { @@ -315,7 +321,7 @@ int main(int argc, char *argv[]) { check_master_switch(); while ( (tile = get_next_task( host, port, last_tile )) >= 0 ) { - result = construct_tile( SGBucket(tile), result_file, cover ); + result = construct_tile( SGBucket(tile), result_file, cover, angle ); if ( result ) { last_tile = tile; } else { diff --git a/src/Lib/Polygon/names.cxx b/src/Lib/Polygon/names.cxx index 41f8eb97..25832f3c 100644 --- a/src/Lib/Polygon/names.cxx +++ b/src/Lib/Polygon/names.cxx @@ -70,6 +70,7 @@ inline static void init () set_area("Reservoir", ReservoirArea); set_area("Reservoir Intermittent", IntReservoirArea); set_area("IntermittentReservoir", IntReservoirArea); + set_area("Freeway", FreewayArea); set_area("Road", RoadArea); set_area("Railroad", RailroadArea); set_area("Stream", StreamArea); diff --git a/src/Lib/Polygon/names.hxx b/src/Lib/Polygon/names.hxx index d623fc98..8fadfee6 100644 --- a/src/Lib/Polygon/names.hxx +++ b/src/Lib/Polygon/names.hxx @@ -44,6 +44,7 @@ enum AreaType { IntLakeArea, ReservoirArea, IntReservoirArea, + FreewayArea, RoadArea, RailroadArea, StreamArea, diff --git a/src/Lib/e00/Makefile.am b/src/Lib/e00/Makefile.am index 25e97f1e..d3b241bf 100644 --- a/src/Lib/e00/Makefile.am +++ b/src/Lib/e00/Makefile.am @@ -5,6 +5,8 @@ libe00_a_SOURCES = e00.cxx e00.hxx noinst_PROGRAMS = teste00 teste00_SOURCES = teste00.cxx -teste00_LDADD = libe00.a - +teste00_LDADD = libe00.a -lsgmisc -lz +INCLUDES += \ + -I$(top_srcdir)/src \ + -I$(top_srcdir)/src/Lib diff --git a/src/Lib/e00/e00.cxx b/src/Lib/e00/e00.cxx index cbf66ce4..2780d978 100644 --- a/src/Lib/e00/e00.cxx +++ b/src/Lib/e00/e00.cxx @@ -39,22 +39,25 @@ append (string &s, double f) } static void -skipWhitespace (istream &input) +skipNewlines (istream &input) { char c; input.get(c); - while (isspace(c)) { +// while (isspace(c)) { +// input.get(c); +// } + while (c == '\n' || c == '\r') { input.get(c); } input.putback(c); } static void -readStringItem (istream &input, string &line, int width) +readItem (istream &input, string &line, int width) { char c; - skipWhitespace(input); + skipNewlines(input); line.resize(0); for (int i = 0; i < width; i++) { @@ -89,6 +92,43 @@ checkZeros (istream &input) } +static void +expect (istream &input, int i) +{ + int in; + input >> in; + if (in != i) { + string message = "Expected "; + append(message, i); + throw E00Exception(message.c_str()); + } +} + +static void +expect (istream &input, double f) +{ + double in; + input >> in; + if (in != f) { + string message = "Expected "; + append(message, f); + throw E00Exception(message.c_str()); + } +} + +static void +expect (istream &input, const char *s) +{ + string in; + input >> in; + if (in != s) { + string message = "Expected "; + message += s; + throw E00Exception(message.c_str()); + } +} + + //////////////////////////////////////////////////////////////////////// // Implementation of E00 @@ -105,136 +145,6 @@ E00::~E00 () } -void -E00::expect (int i) -{ - int in; - *_input >> in; - if (in != i) { - string message = "Expected "; - append(message, i); - throw E00Exception(message.c_str()); - } -} - -void -E00::expect (double f) -{ - double in; - *_input >> in; - if (in != f) { - string message = "Expected "; - append(message, f); - throw E00Exception(message.c_str()); - } -} - -void -E00::expect (const char * s) -{ - string in; - *_input >> in; - if (in != s) { - string message = "Expected "; - message += s; - throw E00Exception(message.c_str()); - } -} - - - -//////////////////////////////////////////////////////////////////////// -// XML output. -//////////////////////////////////////////////////////////////////////// - -static void -writeVertex (ostream &output, double x, double y) -{ - output << "<v x=\"" << x << "\" y=\"" << y << "\"/>" << endl; -} - -void -E00::write (ostream &output) const -{ - int i, j, k; - - output << "<?xml version=\"1.0\"?>" << endl << endl; - output << "<GIS>" << endl << endl; - - if (arc_section.size() == 0) { - for (int i = 0; i < (int)lab_section.size(); i++) { - output << "<point>" << endl; - writeVertex(output, lab_section[i].coord.x, lab_section[i].coord.y); - output << "</point>" << endl << endl; - } - } - - for ( i = 0; i < (int)arc_section.size(); i++) { - const e00ARC &arc = arc_section[i]; - if (!arc.inPolygon) { - output << "<line>" << endl; - for ( j = 0; j < (int)arc.coordinates.size(); j++) { - writeVertex(output, arc.coordinates[j].x, arc.coordinates[j].y); - } - output << "</line>" << endl << endl;; - } - } - - // NB: skip enclosing poly - for ( i = 1; i < (int)pal_section.size(); i++) { - const e00PAL &pal = pal_section[i]; - output << "<polygon>" << endl; - for ( j = 0; j < pal.numArcs; j++) { - bool isReversed = false; - int arcNum = pal.arcs[j].arcNum; - if (arcNum < 0) { - arcNum = 0 - arcNum; - isReversed = true; - } - const e00ARC &arc = arc_section[arcNum]; - output << "<arc coverage=\"" << arc.coverageId << "\">" << endl; - if (isReversed) { - for ( k = arc.numberOfCoordinates - 1; k >= 0; k--) { - writeVertex(output, arc.coordinates[k].x, arc.coordinates[k].y); - } - } else { - for ( k = 0; k < arc.numberOfCoordinates; k++) { - writeVertex(output, arc.coordinates[k].x, arc.coordinates[k].y); - } - } - output << "</arc>" << endl; - } - output << "</polygon>" << endl << endl; - } - - output << "</GIS>" << endl; -} - - - - - -//////////////////////////////////////////////////////////////////////// -// Public query methods. -//////////////////////////////////////////////////////////////////////// - -int -E00::nPoints () const -{ - return lab_section.size(); -} - -int -E00::nLines () const -{ - return lineArcs.size(); -} - -int -E00::nPolygons () const -{ - return pal_section.size(); -} @@ -255,6 +165,7 @@ E00::readE00 (istream &input) *_input >> token; + cerr << "Reading " << token << " section" << endl; if (token == "ARC") { readARC(); } else if (token == "CNT") { @@ -273,6 +184,14 @@ E00::readE00 (istream &input) readTOL(); } else if (token == "IFO") { readIFO(); + } else if (token == "TX6") { + readTX6(); + } else if (token == "TX7") { + readTX7(); + } else if (token == "RXP") { + readRXP(); + } else if (token == "RPL") { + readRPL(); } else if (token == "EOS") { postProcess(); return; @@ -283,6 +202,7 @@ E00::readE00 (istream &input) } throw E00Exception("File ended without EOS line"); + _input = 0; } @@ -292,8 +212,8 @@ E00::readE00 (istream &input) void E00::readHeader () { - expect("EXP"); - expect(0); + expect(*_input, "EXP"); + expect(*_input, 0); *_input >> pathName; } @@ -304,14 +224,12 @@ E00::readHeader () void E00::readARC () { - e00ARC arc; - e00Coord coord; + ARC arc; + Coord coord; checkPrecision(*_input); - *_input >> arc.coverageNum; while (arc.coverageNum != -1) { - arc.inPolygon = false; *_input >> arc.coverageId; *_input >> arc.fromNode; *_input >> arc.toNode; @@ -324,6 +242,7 @@ E00::readARC () *_input >> coord.y; arc.coordinates.push_back(coord); } + arc.in_polygon = false; // we'll check later arc_section.push_back(arc); *_input >> arc.coverageNum; } @@ -338,14 +257,16 @@ E00::readARC () void E00::readCNT () { - e00CNT cnt; + int numLabels; int label; checkPrecision(*_input); - *_input >> cnt.numLabels; + *_input >> numLabels; - while (cnt.numLabels != -1) { + while (numLabels != -1) { + CNT cnt; + cnt.numLabels = numLabels; *_input >> cnt.centroid.x; *_input >> cnt.centroid.y; for (int i = 0; i < cnt.numLabels; i++) { @@ -353,7 +274,7 @@ E00::readCNT () cnt.labels.push_back(label); } cnt_section.push_back(cnt); - *_input >> cnt.numLabels; + *_input >> numLabels; } checkZeros(*_input); @@ -363,7 +284,7 @@ E00::readCNT () void E00::readLAB () { - e00LAB lab; + LAB lab; checkPrecision(*_input); *_input >> lab.coverageId; @@ -387,7 +308,7 @@ E00::readLAB () void E00::readLOG () { - e00LOG log; + LOG log; string line; checkPrecision(*_input); @@ -409,8 +330,9 @@ E00::readLOG () void E00::readPAL () { - e00PAL pal; - e00PAL::ARC arc; + PAL pal; + PAL::ARCref arc; + int count = 1; checkPrecision(*_input); *_input >> pal.numArcs; @@ -422,6 +344,19 @@ E00::readPAL () pal.arcs.resize(0); for (int i = 0; i < pal.numArcs; i++) { *_input >> arc.arcNum; + if (count > 1) { + if (arc.arcNum > 0) + _getARC(arc.arcNum).in_polygon = true; + else + _getARC(0-arc.arcNum).in_polygon = true; + } + int num = (arc.arcNum < 0 ? 0 - arc.arcNum : arc.arcNum); + if (num != 0 && + getARC(num).leftPolygon != count && + getARC(num).rightPolygon != count) { + cerr << "Polygon " << count << " includes arc " << num + << " which doesn't reference it" << endl; + } *_input >> arc.nodeNum; *_input >> arc.polygonNum; pal.arcs.push_back(arc); @@ -429,6 +364,7 @@ E00::readPAL () pal_section.push_back(pal); *_input >> pal.numArcs; + count++; } checkZeros(*_input); @@ -438,7 +374,7 @@ E00::readPAL () void E00::readPRJ () { - e00PRJ prj; + PRJ prj; string line; checkPrecision(*_input); @@ -472,7 +408,7 @@ E00::readSIN () void E00::readTOL () { - e00TOL tol; + TOL tol; checkPrecision(*_input); *_input >> tol.type; @@ -487,20 +423,68 @@ E00::readTOL () } +void +E00::readTX6 () +{ + string dummy; + *_input >> dummy; + // FIXME: will fail if "JABBERWOCKY" appears + // in the text annotation itself + while (dummy != "JABBERWOCKY") + *_input >> dummy; +} + + +void +E00::readTX7 () +{ + string dummy; + *_input >> dummy; + // FIXME: will fail if "JABBERWOCKY" appears + // in the text annotation itself + while (dummy != "JABBERWOCKY") + *_input >> dummy; +} + +void +E00::readRXP () +{ + string dummy; + *_input >> dummy; + // FIXME: will fail if "JABBERWOCKY" appears + // in the text annotation itself + while (dummy != "JABBERWOCKY") + *_input >> dummy; +} + +void +E00::readRPL () +{ + string dummy; + *_input >> dummy; + // FIXME: will fail if "JABBERWOCKY" appears + // in the text annotation itself + while (dummy != "JABBERWOCKY") + *_input >> dummy; +} + + void E00::readIFO () { - e00IFO ifo; - e00IFO::ItemDef def; - e00IFO::Entry entry; - string line; + string line = ""; int intval; double realval; checkPrecision(*_input); - *_input >> ifo.fileName; - while (ifo.fileName.find("EOI") != 0) { + while (line == "") + *_input >> line; + while (line != string("EOI")) { + + IFO ifo; + IFO::Entry entry; + ifo.fileName = line; // 'XX' may be absent *_input >> ifo.isArcInfo; @@ -517,19 +501,21 @@ E00::readIFO () // Read the item definitions ifo.defs.resize(0); for (int i = 0; i < ifo.numItems; i++) { + IFO::ItemDef def; + *_input >> def.itemName; *_input >> def.itemWidth; - expect(-1); + expect(*_input, -1); *_input >> def.itemStartPos; - expect(-1); + expect(*_input, -1); def.itemStartPos -= 4; def.itemStartPos /= 10; *_input >> def.itemOutputFormat[0]; *_input >> def.itemOutputFormat[1]; *_input >> def.itemType; - expect(-1); - expect(-1); - expect(-1); + expect(*_input, -1); + expect(*_input, -1); + expect(*_input, -1); *_input >> def.seqId; ifo.defs.push_back(def); getline(*_input, line); @@ -542,18 +528,51 @@ E00::readIFO () for (int j = 0; j < ifo.numItems; j++) { line.resize(0); string &type = ifo.defs[j].itemType; - if (type == "20-1") { // character field - readStringItem(*_input, line, ifo.defs[j].itemOutputFormat[0]); - } else if (type == "50-1") { // integer - *_input >> intval; - append(line, intval); - } else if (type == "60-1") { // real number - *_input >> realval; - append(line, realval); - } else { // assume integer - cerr << "Unknown IFO item type '30-1': assuming integer" << endl; - *_input >> intval; - append(line, intval); + + if (type == "10-1") { // date + readItem(*_input, line, 8); + } + + else if (type == "20-1") { // character field + readItem(*_input, line, ifo.defs[j].itemOutputFormat[0]); + } + + else if (type == "30-1") { // fixed-width integer + readItem(*_input, line, ifo.defs[j].itemOutputFormat[0]); + } + + else if (type == "40-1") { // single-precision float + readItem(*_input, line, 14); + } + + else if (type == "50-1") { // integer + if (ifo.defs[j].itemWidth == 2) { + readItem(*_input, line, 6); + } else if (ifo.defs[j].itemWidth == 4) { + readItem(*_input, line, 11); + } else { + cerr << "Unexpected width " << ifo.defs[j].itemWidth + << " for item of type 50-1" << endl; + exit(1); + } + } + + else if (type == "60-1") { // real number + if (ifo.defs[j].itemWidth == 4) { + readItem(*_input, line, 14); + } else if (ifo.defs[j].itemWidth == 8) { + readItem(*_input, line, 24); + } else { + cerr << "Unexpected width " << ifo.defs[j].itemWidth + << " for item of type 60-1" << endl; + exit(1); + } + } + + else { // assume integer + cerr << "Unknown IFO item type " << type + << " assuming integer" << endl; + exit(1); } entry.push_back(line); } @@ -561,7 +580,9 @@ E00::readIFO () } ifo_section.push_back(ifo); - *_input >> ifo.fileName; + line = ""; + while (line == "") + *_input >> line; } } @@ -580,31 +601,59 @@ E00::readUnknown () void E00::postProcess () { + // TODO +} - // Flag the arcs so that we know what is - // and isn't part of a polygon. - for (int i = 0; i < (int)pal_section.size(); i++) { - e00PAL &pal = pal_section[i]; - for (int j = 0; j < (int)pal.arcs.size(); j++) { - int arcNum = pal.arcs[j].arcNum; - if (arcNum >= (int)arc_section.size()) { - cerr << "Polygon includes non-existent arc " << arcNum << endl; - } else { - arc_section[arcNum].inPolygon = true; - } - } + + +//////////////////////////////////////////////////////////////////////// +// Other access methods. +//////////////////////////////////////////////////////////////////////// + +const E00::IFO * +E00::getIFO (const string &fileName) const +{ + for (int i = 0; i < ifo_section.size(); i++) { + if (ifo_section[i].fileName == fileName) + return &(ifo_section[i]); + } + return 0; +} + +const string * +E00::getIFOItem (const string &fileName, int entry, + const string &itemName) const +{ + const IFO * ifo = getIFO(fileName); + if (ifo == 0) + return 0; + + int pos = -1; + for (int i = 0; i < ifo->defs.size(); i++) { + if (ifo->defs[i].itemName == itemName) + pos = i; } - // Now, check which arcs aren't flagged - // and assign them to the appropriate - // lists. - for (int i = 0; i < (int)arc_section.size(); i++) { - e00ARC &arc = arc_section[i]; - if (!arc.inPolygon) { - lineArcs.push_back(&arc); - } + if (pos == -1) + return 0; + + return &(ifo->entries[entry-1][pos]); +} + +const string * +E00::getIFOItemType (const string &fileName, const string &itemName) const +{ + const IFO * ifo = getIFO(fileName); + if (ifo == 0) + return 0; + + int pos = -1; + for (int i = 0; i < ifo->defs.size(); i++) { + if (ifo->defs[i].itemName == itemName) + return &(ifo->defs[i].itemType); } + return 0; } // end of e00.cxx diff --git a/src/Lib/e00/e00.hxx b/src/Lib/e00/e00.hxx index a51005b2..273b093f 100644 --- a/src/Lib/e00/e00.hxx +++ b/src/Lib/e00/e00.hxx @@ -1,145 +1,170 @@ +// e00.hxx - declarations for E00 file processing. + +#ifndef __E00_HXX +#define __E00_HXX 1 + #include <simgear/compiler.h> #include <vector> -#include <map> -#include STL_STRING +#include <string> #include <iostream> -FG_USING_STD(vector); -FG_USING_STD(map); -FG_USING_STD(string); -FG_USING_STD(istream); -FG_USING_STD(ostream); +using std::vector; +using std::string; +using std::istream; -struct E00Exception + +// An exception reading an E00 file. + +class E00Exception { - E00Exception (const char * msg) : message(msg) {} - string message; +public: + E00Exception (const string &message) : _message(message) {} + virtual const string &getMessage () const { return _message; } +private: + string _message; }; -// A coordinate in two-dimensional space. - -struct e00Coord -{ - double x; - double y; -}; - - -// Arc Coordinates and Topology - -struct e00ARC -{ - bool inPolygon; - int coverageNum; - int coverageId; - int fromNode; - int toNode; - int leftPolygon; - int rightPolygon; - int numberOfCoordinates; - vector<e00Coord> coordinates; -}; - - -// Polygon Centroid Coordinates - -struct e00CNT -{ - int numLabels; - e00Coord centroid; - vector<int> labels; -}; - - -// Label Point Coordinates and Topology - -struct e00LAB -{ - int coverageId; - int enclosingPolygon; - e00Coord coord; - e00Coord box1; // obsolete - e00Coord box2; // obsolete -}; - - -// Coverage History - -struct e00LOG -{ - vector<string> lines; -}; - - -// Polygon Topology - -struct e00PAL -{ - struct ARC - { - int arcNum; - int nodeNum; - int polygonNum; - }; - int numArcs; - e00Coord min; - e00Coord max; - vector<ARC> arcs; -}; - - -// Projection Parameters - -struct e00PRJ -{ - vector<string> lines; -}; - - -// Tolerance Type - -struct e00TOL -{ - int type; - int status; - double value; -}; - - -// Info Files - -struct e00IFO -{ - struct ItemDef - { - string itemName; - int itemWidth; // followed by -1 - int itemStartPos; // followed by 4-1 - int itemOutputFormat[2]; - string itemType; - // -1 - // -1-1 - string seqId; - }; - typedef vector<string> Entry; - string fileName; - string isArcInfo; - int numItems; - int altNumItems; - int dataRecordLength; - int numDataRecords; - vector<ItemDef> defs; - vector<Entry> entries; -}; - // ARCInfo file class E00 { + public: + + ////////////////////////////////////////////////////////////////////// + // Data structures for internal use. + ////////////////////////////////////////////////////////////////////// + + + // A coordinate in two-dimensional space. + + struct Coord + { + virtual ~Coord () {} + double x; + double y; + }; + + + // Arc co-ordinates and topology. + + struct ARC + { + virtual ~ARC () {} + int coverageNum; + int coverageId; + int fromNode; + int toNode; + int leftPolygon; + int rightPolygon; + int numberOfCoordinates; + vector<Coord> coordinates; + bool in_polygon; + }; + + + // Polygon Centroid Coordinates + + struct CNT + { + virtual ~CNT () {} + int numLabels; + Coord centroid; + vector<int> labels; + }; + + + // Label Point Coordinates and Topology + + struct LAB + { + virtual ~LAB () {} + int coverageId; + int enclosingPolygon; + Coord coord; + Coord box1; // obsolete + Coord box2; // obsolete + }; + + + // Coverage History + + struct LOG + { + virtual ~LOG () {} + vector<string> lines; + }; + + + // Polygon Topology + + struct PAL + { + virtual ~PAL () {} + struct ARCref + { + int arcNum; + int nodeNum; + int polygonNum; + }; + int numArcs; + Coord min; + Coord max; + vector<ARCref> arcs; + }; + + + // Projection Parameters + + struct PRJ + { + virtual ~PRJ () {} + vector<string> lines; + }; + + + // Tolerance Type + + struct TOL + { + virtual ~TOL () {} + int type; + int status; + double value; + }; + + + // Info Files + + struct IFO + { + virtual ~IFO () {} + struct ItemDef + { + string itemName; + int itemWidth; // followed by -1 + int itemStartPos; // followed by 4-1 + int itemOutputFormat[2]; + string itemType; + // -1 + // -1-1 + string seqId; + }; + typedef vector<string> Entry; + string fileName; + string isArcInfo; + int numItems; + int altNumItems; + int dataRecordLength; + int numDataRecords; + vector<ItemDef> defs; + vector<Entry> entries; + }; + + E00 (); virtual ~E00 (); @@ -147,35 +172,37 @@ public: virtual string getPathName () const { return pathName; } - virtual int nPoints () const; - virtual int nLines () const; - virtual int nPolygons () const; + virtual int nPoints () const { return lab_section.size(); } + virtual int nLines () const { return arc_section.size(); } + virtual int nPolygons () const { return pal_section.size(); } + virtual int nInfoFiles () const { return ifo_section.size(); } - virtual const e00ARC * getPoint (int i) const { return pointArcs[i]; } - virtual const e00ARC * getLine (int i) const { return lineArcs[i]; } - - virtual void write (ostream &output) const; + virtual const ARC &getARC (int i) const { return arc_section[i-1]; } + virtual const LAB &getLAB (int i) const { return lab_section[i-1]; } + virtual const PAL &getPAL (int i) const { return pal_section[i-1]; } + virtual const IFO &getIFO (int i) const { return ifo_section[i-1]; } + virtual const IFO * getIFO (const string &name) const; + virtual const string * getIFOItem (const string &fileName, int entry, + const string &itemName) const; + virtual const string * getIFOItemType (const string &fileName, + const string &itemName) const; + private: - vector<const e00ARC *> pointArcs; - vector<const e00ARC *> lineArcs; + virtual ARC &_getARC (int i) { return arc_section[i-1]; } string pathName; - vector<e00ARC> arc_section; - vector<e00CNT> cnt_section; - vector<e00LAB> lab_section; - vector<e00LOG> log_section; - vector<e00PAL> pal_section; - vector<e00PRJ> prj_section; - vector<e00TOL> tol_section; - vector<e00IFO> ifo_section; + vector<ARC> arc_section; + vector<CNT> cnt_section; + vector<LAB> lab_section; + vector<LOG> log_section; + vector<PAL> pal_section; + vector<PRJ> prj_section; + vector<TOL> tol_section; + vector<IFO> ifo_section; - istream * _input; - - void expect (int i); - void expect (double f); - void expect (const char * s); + mutable istream * _input; void postProcess (); @@ -188,6 +215,15 @@ private: void readPRJ (); void readSIN (); void readTOL (); + void readTX6 (); + void readTX7 (); + void readRXP (); + void readRPL (); void readIFO (); void readUnknown (); + }; + +#endif __E00_HXX + +// end of e00.hxx diff --git a/src/Lib/e00/teste00.cxx b/src/Lib/e00/teste00.cxx index af13d7a4..f7f9e07b 100644 --- a/src/Lib/e00/teste00.cxx +++ b/src/Lib/e00/teste00.cxx @@ -1,20 +1,19 @@ +// teste00.cxx - test the E00 parsing routines and dump some results. -#include <fstream> +#include <simgear/misc/fgstream.hxx> #include "e00.hxx" -using std::ifstream; - int main (int ac, const char ** av) { for (int i = 1; i < ac; i++) { cerr << "Reading " << av[i] << endl; - ifstream input(av[i]); + fg_gzifstream input(av[i]); E00 data; try { data.readE00(input); } catch (E00Exception &e) { cerr << "Reading " << av[i] << " failed with exception " - << e.message << endl; + << e.getMessage() << endl; exit(1); } cerr << "Read " << av[i] << " successfully" << endl; @@ -23,8 +22,39 @@ int main (int ac, const char ** av) cerr << "Read " << data.nPolygons() << " polygon(s)" << endl; cerr << " (including enclosing polygon)" << endl; - data.write(cout); + for (int i = 1; i <= data.nInfoFiles(); i++) { + const E00::IFO &ifo = data.getIFO(i); + cout << "IFO file: " << ifo.fileName << endl; + for (int j = 0; j < ifo.numItems; j++) { + cout << " " << ifo.defs[j].itemName << endl; + } + } + +// for (int i = 2; i <= data.nPolygons(); i++) { +// const E00::PAL &pal = data.getPAL(i); +// for (int j = 0; j < pal.numArcs; j++) { +// int arcNum = pal.arcs[j].arcNum; +// if (arcNum == 0) { +// cout << endl; +// } else if (arcNum < 0) { +// const E00::ARC &arc = data.getARC(0-arcNum); +// for (int k = arc.numberOfCoordinates - 1; k >= 0; k--) { +// cout << arc.coordinates[k].x << '\t' +// << arc.coordinates[k].y << endl; +// } +// } else { +// const E00::ARC &arc = data.getARC(arcNum); +// for (int k = 0; k < arc.numberOfCoordinates; k++) { +// cout << arc.coordinates[k].x << '\t' +// << arc.coordinates[k].y << endl; +// } +// } +// cout << endl; +// } +// } } return 0; } + +// end of teste00.cxx diff --git a/src/Prep/E00Lines/Makefile.am b/src/Prep/E00Lines/Makefile.am index 09e7e34a..8caea46c 100644 --- a/src/Prep/E00Lines/Makefile.am +++ b/src/Prep/E00Lines/Makefile.am @@ -6,6 +6,6 @@ e00lines_LDADD = \ $(top_builddir)/src/Lib/Polygon/libPolygon.a \ $(top_builddir)/src/Lib/poly2tri/libpoly2tri.a \ $(top_builddir)/src/Lib/e00/libe00.a \ - -lsgdebug -lsgbucket -lsgmisc -lsgmath -lz -lgpc + -lsgdebug -lsgbucket -lsgmisc -lsgmath -lsgio -lz -lgpc INCLUDES += -I$(top_srcdir)/src/Lib diff --git a/src/Prep/E00Lines/main.cxx b/src/Prep/E00Lines/main.cxx index c9550384..85c7bf66 100644 --- a/src/Prep/E00Lines/main.cxx +++ b/src/Prep/E00Lines/main.cxx @@ -27,12 +27,16 @@ #include <simgear/constants.h> #include <simgear/math/sg_geodesy.hxx> #include <simgear/debug/logstream.hxx> +#include <simgear/misc/fgstream.hxx> +#include <iostream> #include <string> -#include <fstream> +#include <vector> -using std::string; -using std::ifstream; +FG_USING_STD(cerr); +FG_USING_STD(cout); +FG_USING_STD(string); +FG_USING_STD(vector); #include <Polygon/index.hxx> #include <Polygon/names.hxx> @@ -44,7 +48,14 @@ using std::ifstream; # include <Win32/mkdir.hpp> #endif -static inline double ANGLE (double a) + + +//////////////////////////////////////////////////////////////////////// +// Utility stuff. +//////////////////////////////////////////////////////////////////////// + +static inline double +ANGLE (double a) { while (a < 0.0) a += 360.0; @@ -54,69 +65,192 @@ static inline double ANGLE (double a) } -int -main (int argc, const char **argv) + + + + +//////////////////////////////////////////////////////////////////////// +// Areas. +//////////////////////////////////////////////////////////////////////// + +/** + * A rectangle (such as a bounding box). + */ +struct Rectangle { + Rectangle () : minX(0.0), minY(0.0), maxX(0.0), maxY(0.0) {} + Rectangle (double _minX, double _minY, double _maxX, double _maxY) + : minX(_minX), minY(_minY), maxX(_maxX), maxY(_maxY) {} + double minX; + double minY; + double maxX; + double maxY; + bool isInside (double x, double y) const + { + return (x >= minX && x <= maxX && y >= minY && y <= maxY); + } + bool isOverlapping (const Rectangle &rect) const + { + return (isInside(rect.minX, rect.minY) || + isInside(rect.minX, rect.maxY) || + isInside(rect.maxX, rect.minY) || + isInside(rect.maxX, rect.maxY)); + } +}; - // Enable logging. - fglog().setLogLevels( FG_ALL, FG_DEBUG ); +static ostream & +operator<< (ostream &output, const Rectangle &rect) { + output << '(' << rect.minX << ',' << rect.minY << "),(" + << rect.maxX << ',' << rect.maxY << ')'; +} + +/** + * Make a bounding box for a single ARC. + */ +static Rectangle +makeBounds (const E00::ARC &arc) +{ + Rectangle bounds; + for (int i = 0; i < arc.numberOfCoordinates; i++) { + double x = arc.coordinates[i].x; + double y = arc.coordinates[i].y; + if (i == 0) { + bounds.minX = bounds.maxX = x; + bounds.minY = bounds.maxY = y; + } else { + if (x < bounds.minX) bounds.minX = x; + if (y < bounds.minY) bounds.minY = y; + if (x > bounds.maxX) bounds.maxX = x; + if (y > bounds.maxY) bounds.maxY = y; + } + } + return bounds; +} + +/** + * Make a bounding box for a polygon. + */ +static Rectangle +makeBounds (const E00::PAL &pal) +{ + return Rectangle(pal.min.x, pal.min.y, pal.max.x, pal.max.y); +} + + + +//////////////////////////////////////////////////////////////////////// +// Processing methods. +//////////////////////////////////////////////////////////////////////// + +/** + * An attribute pattern. + */ +struct Attribute +{ + string file; + string item; + string value; +}; + + +/** + * Check whether an attribute pattern matches a shape. + */ +static bool +checkAttribute (const E00 &data, int index, const Attribute &att) +{ + const string * type = data.getIFOItemType(att.file, att.item); + if (type == 0) + return false; + const string * value = data.getIFOItem(att.file, index, att.item); + if (value == 0) + return false; + + if (*type == "10-1") { // date + return (*value == att.value); + } - // Check usage. - if ( argc != 5 ) { - FG_LOG( FG_GENERAL, FG_ALERT, "Usage: " << argv[0] - << " <e00_line_file> <width_meters> <area_type> <work_dir>" ); - exit(-1); + else if (*type == "20-1") { // string + return (*value == att.value); } - // Grab command-line arguments. - ifstream input(argv[1]); - if ( !input.good() ) { - FG_LOG( FG_GENERAL, FG_ALERT, "Cannot open file: " << argv[1]); - exit(-1); + else if (*type == "30-1" || *type == "50-1") { // integer + int val1 = atoi(value->c_str()); + int val2 = atoi(att.value.c_str()); + return (val1 == val2); } - int width = atoi(argv[2]); - if (width <= 0) { - FG_LOG(FG_GENERAL, FG_ALERT, "Bad width specified " << argv[2]); - exit(-1); + else if (*type == "40-1" || *type == "60-1") { // float + float val1 = atof(value->c_str()); + float val2 = atof(att.value.c_str()); + return (val1 == val2); } - AreaType area_type = get_area_type(argv[3]); - - string work_dir = argv[4]; -#ifdef _MSC_VER - fg_mkdir(work_dir.c_str()); -#else - string command = "mkdir -p " + work_dir; - system(command.c_str()); -#endif - - // Read the E00 file. - E00 data; - try { - data.readE00(input); - } catch (E00Exception &e) { - FG_LOG(FG_GENERAL, FG_ALERT, "Reading " << argv[1] - << " failed with exception " << e.message); + else { + cerr << "Unknown IFO field type " << *type << endl; exit(1); } - // Initialize the persistant polygon counter. - string counter_file = work_dir + "/../poly_counter"; - poly_index_init( counter_file ); + return (*value == att.value); +} + +/** + * Create polygons out of points. + */ +static void +processPoints (const E00 &data, const Rectangle &bounds, + AreaType areaType, const string &workDir, int width) +{ + cerr << "Points not yet supported" << endl; +} + + +/** + * Create polygons out of all loose line segments. + */ +static void +processLines (const E00 &data, const Rectangle &bounds, + AreaType areaType, const string &workDir, int width, + const vector<Attribute> &aat_list) +{ FGPolygon shape; - // Iterate through the lines. int nLines = data.nLines(); - for (int i = 0; i < nLines; i++) { - const e00ARC * line = data.getLine(i); - cout << "Line has " << line->numberOfCoordinates << " coordinates" << endl; - for (int j = 0; j < line->numberOfCoordinates - 1; j++) { - double lon1 = line->coordinates[j].x; - double lat1 = line->coordinates[j].y; - double lon2 = line->coordinates[j+1].x; - double lat2 = line->coordinates[j+1].y; + cout << "Processing " << nLines << " lines." << endl; + for (int i = 1; i <= nLines; i++) { + const E00::ARC &arc = data.getARC(i); + Rectangle arcBounds = makeBounds(arc); + if (!bounds.isOverlapping(arcBounds)) { + cout << "Arc " << i << " outside of area; skipping" << endl; + cout << "Arc bounds: " << arcBounds << endl; + continue; + } + + // If any arc attributes were specified, + // make sure at least one of them is + // present. + if (aat_list.size() > 0) { + bool status = false; + for (int j = 0; j < aat_list.size(); j++) { + if (checkAttribute(data, i, aat_list[j])) { + status = true; + break; + } + } + if (!status) { + cout << "Skipping line " << i << " (failed attribute tests)" << endl; + continue; + } + } + + // Make the line into a polygon. + cout << "Line has " << arc.numberOfCoordinates << " coordinates" << endl; + for (int j = 0; j < arc.numberOfCoordinates - 1; j++) { + double lon1 = arc.coordinates[j].x; + double lat1 = arc.coordinates[j].y; + double lon2 = arc.coordinates[j+1].x; + double lat2 = arc.coordinates[j+1].y; double angle1, angle2, dist; geo_inverse_wgs_84(0, lat1, lon1, lat2, lon2, &angle1, &angle2, &dist); cout << "angle1 = " << angle1 << endl; @@ -152,10 +286,358 @@ main (int argc, const char **argv) shape.add_node(0, Point3D(x, y, 0)); // Split into tiles - split_polygon(work_dir, area_type, shape); + split_polygon(workDir, areaType, shape); + } + } +} + + +/** + * Import all polygons. + */ +static void +processPolygons (const E00 &data, const Rectangle &bounds, + AreaType areaType, const string &workDir, + const vector<Attribute> pat_list) +{ + FGPolygon shape; + + int nPolygons = data.nPolygons(); + cout << "Processing " << nPolygons << " polygons" << endl; + + for (int i = 2; i <= nPolygons; i++) { + + // Test whether the polygon matches + // at least one of the attributes + // provided. + if (pat_list.size() > 0) { + bool status = false; + for (int j = 0; j < pat_list.size(); j++) { + if (checkAttribute(data, i, pat_list[j])) { + status = true; + break; + } + } + if (!status) { + cout << "Skipping polygon " << i << " (failed attribute tests)" + << endl; + continue; + } + } + + int contour = 0; + const E00::PAL &pal = data.getPAL(i); + Rectangle palBounds = makeBounds(pal); + if (!bounds.isOverlapping(palBounds)) { + cout << "Polygon " << i << " outside of area, skipping" << endl; + cout << "Polygon boundary is " << palBounds << endl; + continue; + } + shape.erase(); + for (int j = 0; j < pal.numArcs; j++) { + int arcNum = pal.arcs[j].arcNum; + // Starting a hole + if (arcNum == 0) { + contour++; + point_list contour; + contour.clear(); + shape.add_contour(contour, 1); + } else if (arcNum < 0) { + const E00::ARC &arc = data.getARC(0-arcNum); + for (int k = arc.numberOfCoordinates - 1; k >= 0; k--) + shape.add_node(contour, Point3D(arc.coordinates[k].x, + arc.coordinates[k].y, + 0.0)); + } else { + const E00::ARC &arc = data.getARC(arcNum); + for (int k = 0; k < arc.numberOfCoordinates; k++) + shape.add_node(contour, Point3D(arc.coordinates[k].x, + arc.coordinates[k].y, + 0.0)); + } + } + split_polygon(workDir, areaType, shape); + } +} + + + + +//////////////////////////////////////////////////////////////////////// +// Main program. +//////////////////////////////////////////////////////////////////////// + + +/** + * Print the command-line usage and exit. + */ +static void +usage (const char * prog) +{ + cerr << "Usage: " << prog << " [opts] e00file ..." << endl; + cerr << "Options:" << endl; + cerr << "--points=yes|no (default: no)" << endl; + cerr << "--lines=yes|no (default: yes)" << endl; + cerr << "--polygons=yes|no (default: yes)" << endl; + cerr << "--min-lon=<longitude> (default: -180.0)" << endl; + cerr << "--min-lat=<latitude> (default: -90.0)" << endl; + cerr << "--max-lon=<longitude> (default: 180.0)" << endl; + cerr << "--max-lat=<latitude> (default: 90.0)" << endl; + cerr << "--area=<area_type> (default: Default)" << endl; + cerr << "--point-width=<meters> (default: 500)" << endl; + cerr << "--line-width=<meters> (default: 50)" << endl; + cerr << "--work-dir=<dir> (default: .)" << endl; + cerr << "--aat=<infofile>:<item>:<value> (may be repeated)" << endl; + cerr << "--pat=<infofile>:<item>:<value> (may be repeated)" << endl; + exit(2); +} + + +/** + * Parse an attribute value specification from the command line. + */ +static void +parseAttribute (const char * prog, string arg, Attribute &att) +{ + int pos1 = arg.find(':'); + int pos2 = arg.rfind(':'); + if (pos1 == -1 || pos2 == -1 || pos2 <= pos1) { + cerr << "Bad attribute specification: " << arg << endl; + usage(prog); + } + + att.file = arg.substr(0, pos1); + att.item = arg.substr(pos1 + 1, pos2 - (pos1 + 1)); + att.value = arg.substr(pos2+1); +} + + +/** + * Main entry point. + */ +int +main (int argc, const char **argv) +{ + vector<Attribute> aat_list; + vector<Attribute> pat_list; + + // Enable logging. + fglog().setLogLevels( FG_ALL, FG_DEBUG ); + + + // Default values + Rectangle bounds(-180.0, -90.0, 180.0, 90.0); + AreaType areaType = DefaultArea; + int pointWidth = 500; + int lineWidth = 50; + string workDir = "."; + bool usePoints = false; + bool useLines = true; + bool usePolygons = true; + + // Command-line options + int argPos = 1; + while (argPos < argc) { + string arg = argv[argPos]; + + cout << "Trying argument " << arg << endl; + + if (arg.find("--points=") == 0) { + if (arg.substr(9) == "yes") + usePoints = true; + else if (arg.substr(9) == "no") + usePoints = false; + else { + cerr << "--points option needs 'yes' or 'no'" << endl; + usage(argv[0]); + } + argPos++; + } + + else if (arg.find("--lines=") == 0) { + if (arg.substr(9) == "yes") + useLines = true; + else if (arg.substr(9) == "no") + useLines = false; + else { + cerr << "--lines option needs 'yes' or 'no'" << endl; + usage(argv[0]); + } + argPos++; + } + + else if (arg.find("--polygons=") == 0) { + if (arg.substr(9) == "yes") + usePolygons = true; + else if (arg.substr(9) == "no") + usePolygons = false; + else { + cerr << "--polygons option needs 'yes' or 'no'" << endl; + usage(argv[0]); + } + argPos++; + } + + else if (arg.find("--min-lon=") == 0) { + bounds.minX = atof(arg.substr(10).c_str()); + argPos++; + } + + else if (arg.find("--min-lat=") == 0) { + bounds.minY = atof(arg.substr(10).c_str()); + argPos++; + } + + else if (arg.find("--max-lon=") == 0) { + bounds.maxX = atof(arg.substr(10).c_str()); + argPos++; + } + + else if (arg.find("--max-lat=") == 0) { + bounds.maxY = atof(arg.substr(10).c_str()); + argPos++; + } + + else if (arg.find("--area=") == 0) { + areaType = get_area_type(arg.substr(7).c_str()); + argPos++; + } + + else if (arg.find("--point-width=") == 0) { + pointWidth = atoi(arg.substr(14).c_str()); + argPos++; + } + + else if (arg.find("--line-width=") == 0) { + lineWidth = atoi(arg.substr(13).c_str()); + argPos++; + } + + else if (arg.find("--work-dir=") == 0) { + workDir = arg.substr(11); + argPos++; + } + + else if (arg.find("--aat=") == 0) { + Attribute att; + parseAttribute(argv[0], arg.substr(6), att); + aat_list.push_back(att); + cout << "Added polygon constraint for " << att.file << ": " + << att.item << '=' << att.value << endl; + argPos++; + } + + else if (arg.find("--pat=") == 0) { + Attribute att; + parseAttribute(argv[0], arg.substr(6), att); + pat_list.push_back(att); + cout << "Added polygon constraint for " << att.file << ": " + << att.item << '=' << att.value << endl; + argPos++; + } + + else if (arg == "--") { + argPos++; + break; + } + + else if (arg.find("-") == 0) { + cerr << "Unrecognized option: " << arg << endl; + usage(argv[0]); + } + + else { + break; } } + // Check for files to process + if (argPos >= argc) { + cerr << "No e00 files specified!!" << endl; + usage(argv[0]); + } + + cout << "Bounds are " << bounds << endl; + cout << "Area type is " << get_area_name(areaType) << endl;; + cout << "Working directory is " << workDir << endl; + if (usePoints) + cout << "Using points with width " << pointWidth << " meters" << endl; + else + cout << "Ignoring point coverage" << endl; + if (useLines) + cout << "Using lines with width " << lineWidth << " meters" << endl; + else + cout << "Ignoring line coverage" << endl; + if (usePolygons) + cout << "Using polygons" << endl; + else + cout << "Ignoring polygon coverage" << endl; + if (useLines && aat_list.size() > 0) { + cout << "Lines must match at least one of the following:" << endl; + for (int i = 0; i < aat_list.size(); i++) { + cout << aat_list[i].file << ' ' << aat_list[i].item << ' ' + << aat_list[i].value << endl; + } + } + if (usePolygons && pat_list.size() > 0) { + cout << "Polygons must match at least one of the following:" << endl; + for (int i = 0; i < pat_list.size(); i++) { + cout << pat_list[i].file << ' ' << pat_list[i].item << ' ' + << pat_list[i].value << endl; + } + } + + // Make sure the destination + // directory exists. +#ifdef _MSC_VER + fg_mkdir(workDir.c_str()); +#else + string command = "mkdir -p " + workDir; + system(command.c_str()); +#endif + + // Process all of the e00 files + // on the command line. + while (argPos < argc) { + + cout << "Processing " << argv[argPos] << endl; + + // Grab command-line arguments. + fg_gzifstream input(argv[argPos]); + if ( !input.good() ) { + FG_LOG( FG_GENERAL, FG_ALERT, "Cannot open file: " << argv[argPos]); + exit(-1); + } + + // Read the E00 file. + + E00 data; + try { + data.readE00(input); + } catch (E00Exception &e) { + FG_LOG(FG_GENERAL, FG_ALERT, "Reading " << argv[argPos] + << " failed with exception " << e.getMessage()); + exit(1); + } + + // Initialize the persistant polygon counter. + string counter_file = workDir + "/../poly_counter"; + poly_index_init( counter_file ); + + if (usePoints) + processPoints(data, bounds, areaType, workDir, pointWidth); + + if (useLines) + processLines(data, bounds, areaType, workDir, lineWidth, aat_list); + + if (usePolygons) + processPolygons(data, bounds, areaType, workDir, pat_list); + + cout << "Done processing " << argv[argPos] << endl; + argPos++; + } + + cout << "Done all processing." << endl; return 0; }