]> git.mxchange.org Git - flightgear.git/commitdiff
Initial commit of code that reads and parses Robin Peel's awy.dat airway
authordurk <durk>
Thu, 27 Jul 2006 14:44:09 +0000 (14:44 +0000)
committerdurk <durk>
Thu, 27 Jul 2006 14:44:09 +0000 (14:44 +0000)
files.

src/Navaids/Makefile.am
src/Navaids/awynet.cxx [new file with mode: 0755]
src/Navaids/awynet.hxx [new file with mode: 0755]

index b54fc97de07ad34a5afbe3db634cfb70764335b7..7810dd4e5285003b43f925f9b7cdc39b9f098fc6 100644 (file)
@@ -5,6 +5,7 @@ noinst_LIBRARIES = libNavaids.a
 libNavaids_a_SOURCES = \
        navdb.hxx navdb.cxx \
        fix.hxx fixlist.hxx fixlist.cxx \
+       awynet.hxx awynet.cxx \
        navrecord.hxx navlist.hxx navlist.cxx
 
 #      ils.hxx ilslist.hxx ilslist.cxx \
diff --git a/src/Navaids/awynet.cxx b/src/Navaids/awynet.cxx
new file mode 100755 (executable)
index 0000000..5a76a52
--- /dev/null
@@ -0,0 +1,496 @@
+// awynet.cxx
+// by Durk Talsma, started June 2005.
+//
+// Copyright (C) 2004 Durk Talsma.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+// $Id$
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#ifdef _MSC_VER
+#  define _USE_MATH_DEFINES
+#endif
+#include <math.h>
+#include <algorithm>
+
+#include <simgear/compiler.h>
+
+//#include <plib/sg.h>
+//#include <plib/ul.h>
+
+//#include <Environment/environment_mgr.hxx>
+//#include <Environment/environment.hxx>
+//#include <simgear/misc/sg_path.hxx>
+//#include <simgear/props/props.hxx>
+//#include <simgear/structure/subsystem_mgr.hxx>
+#include <simgear/debug/logstream.hxx>
+#include <simgear/misc/sgstream.hxx>
+#include <simgear/route/waypoint.hxx>
+//#include <Main/globals.hxx>
+//#include <Main/fg_props.hxx>
+//#include <Airports/runways.hxx>
+
+//#include STL_STRING
+
+#include "awynet.hxx"
+
+SG_USING_STD(sort);
+
+/**************************************************************************
+ * FGNode
+ *************************************************************************/
+FGNode::FGNode()
+{
+}
+
+bool FGNode::matches(string id, double lt, double ln)
+{
+  if ((ident == id) &&
+      (fabs(lt - lat) < 1.0) &&
+      (fabs(ln - lon) < 1.0))
+    return true;
+  else
+    return false;
+}
+
+/***************************************************************************
+ * FGAirway
+ **************************************************************************/
+FGAirway::FGAirway()
+{
+  length = 0;
+}
+
+void FGAirway::setStart(node_map *nodes)
+{
+  node_map_iterator itr = nodes->find(startNode);
+  if (itr == nodes->end()) {
+    cerr << "Couldn't find node: " << startNode << endl;
+  }
+  else {
+    start = itr->second->getAddress();
+    itr->second->addAirway(this);
+  }
+}
+
+void FGAirway::setEnd(node_map *nodes)
+{
+ node_map_iterator itr = nodes->find(endNode);
+  if (itr == nodes->end()) {
+    cerr << "Couldn't find node: " << endNode << endl;
+  }
+  else {
+    end = itr->second->getAddress();
+  }
+}
+
+// There is probably a computationally cheaper way of
+// doing this.
+void FGAirway::setTrackDistance()
+{
+  double course;
+  SGWayPoint first  (start->getLongitude(),
+                    start->getLatitude(),
+                    0);
+  SGWayPoint second (end->getLongitude(),
+                    end->getLatitude(),
+                    0);
+  first.CourseAndDistance(second, &course, &length);
+
+}
+
+/***************************************************************************
+ * FGAirRoute()
+ **************************************************************************/
+
+
+bool FGAirRoute::next(int *val)
+{
+  //for (intVecIterator i = nodes.begin(); i != nodes.end(); i++)
+  //  cerr << "FGTaxiRoute contains : " << *(i) << endl;
+  //cerr << "Offset from end: " << nodes.end() - currNode << endl;
+  //if (currNode != nodes.end())
+  //  cerr << "true" << endl;
+  //else
+  //  cerr << "false" << endl;
+
+  if (currNode == nodes.end())
+    return false;
+  *val = *(currNode);
+  currNode++;
+  return true;
+};
+
+void FGAirRoute::add(const FGAirRoute &other) {
+  for (constIntVecIterator i = other.nodes.begin() ;
+       i != other.nodes.end(); i++)
+    {
+      nodes.push_back((*i));
+    }
+  distance += other.distance;
+}
+/***************************************************************************
+ * FGAirwayNetwork()
+ **************************************************************************/
+
+FGAirwayNetwork::FGAirwayNetwork()
+{
+  hasNetwork = false;
+  foundRoute = false;
+  totalDistance = 0;
+  maxDistance = 0;
+}
+
+void FGAirwayNetwork::addAirway(const FGAirway &seg)
+{
+  segments.push_back(seg);
+}
+
+//void FGAirwayNetwork::addNode(const FGNode &node)
+//{
+//  nodes.push_back(node);
+//}
+
+/*
+  void FGAirwayNetwork::addNodes(FGParkingVec *parkings)
+  {
+  FGTaxiNode n;
+  FGParkingVecIterator i = parkings->begin();
+  while (i != parkings->end())
+  {
+  n.setIndex(i->getIndex());
+  n.setLatitude(i->getLatitude());
+  n.setLongitude(i->getLongitude());
+  nodes.push_back(n);
+
+  i++;
+  }
+  }
+*/
+
+
+void FGAirwayNetwork::init()
+{
+  hasNetwork = true;
+  FGAirwayVectorIterator i = segments.begin();
+  while(i != segments.end()) {
+    //cerr << "initializing Airway " << i->getIndex() << endl;
+    i->setStart(&nodesMap);
+    i->setEnd  (&nodesMap);
+    //i->setTrackDistance();
+    //cerr << "Track distance = " << i->getLength() << endl;
+    //cerr << "Track ends at"      << i->getEnd()->getIndex() << endl;
+    i++;
+  }
+  //exit(1);
+}
+
+
+void FGAirwayNetwork::load(SGPath path)
+{
+  string identStart, identEnd, token, name;
+  double latStart, lonStart, latEnd, lonEnd;
+  int type, base, top;
+  int airwayIndex = 0;
+  FGNode *n;
+
+  sg_gzifstream in( path.str() );
+  if ( !in.is_open() ) {
+    SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << path.str() );
+    exit(-1);
+  }
+  // toss the first two lines of the file
+  in >> skipeol;
+  in >> skipeol;
+
+  // read in each remaining line of the file
+
+#ifdef __MWERKS__
+  char c = 0;
+  while ( in.get(c) && c != '\0' ) {
+    in.putback(c);
+#else
+    while ( ! in.eof() ) {
+#endif
+      string token;
+      in >> token;
+
+      if ( token == "99" ) {
+       return; //in >> skipeol;
+      }
+      // Read each line from the database
+      identStart = token;
+      in >> latStart >> lonStart >> identEnd >> latEnd >> lonEnd >> type >> base >> top >> name;
+      /*out << identStart << " "
+       << latStart   << " "
+       << lonStart   << " "
+       << identEnd   << " "
+       << latEnd     << " "
+       << lonEnd     << " "
+       << type       << " "
+       << base       << " "
+       << top        << " "
+       << name       << " "
+       << endl;*/
+      //first determine whether the start and end reference database already exist
+      //if not we should create them
+      int startIndex = 0, endIndex=0;
+      //     FGNodeVectorIterator i = nodes.begin();
+  //     while (i != nodes.end() && (!(i->matches(identStart,latStart, lonStart))))
+//     {
+//       i++;
+//       startIndex++;
+//     }
+//       if (i == nodes.end())
+//     {
+//       nodes.push_back(FGNode(latStart, lonStart, startIndex, identStart));
+//     //cout << "Adding node: " << identStart << endl;
+//     }
+
+//       i = nodes.begin();
+//       while (i != nodes.end() && (!(i->matches(identEnd,latEnd, lonEnd)))) {
+//     i++;
+//     endIndex++;
+//       }
+//       if (i == nodes.end()) {
+//     nodes.push_back(FGNode(latEnd, lonEnd, endIndex, identEnd));
+//     //cout << "Adding node: " << identEnd << endl;
+//       }
+      // generate unique IDs for the nodes, consisting of a combination
+      // of the Navaid identifier + the integer value of the lat/lon position.
+      // identifier alone will not suffice, because they might not be globally unique.
+      char buffer[32];
+      string startNode, endNode;
+      // Start
+      snprintf(buffer, 32, "%s%d%d", identStart.c_str(), (int) latStart, (int) lonStart);
+      startNode = buffer;
+
+      node_map_iterator itr = nodesMap.find(string(buffer));
+      if (itr == nodesMap.end()) {
+       startIndex = nodes.size();
+       n = new FGNode(latStart, lonStart, startIndex, identStart);
+       nodesMap[string(buffer)] = n;
+       nodes.push_back(n);
+       //cout << "Adding node: " << identStart << endl;
+      }
+      else {
+       startIndex = itr->second->getIndex();
+      }
+      // Start
+      snprintf(buffer, 32, "%s%d%d", identEnd.c_str(), (int) latEnd, (int) lonEnd);
+      endNode = buffer;
+
+      itr = nodesMap.find(string(buffer));
+      if (itr == nodesMap.end()) {
+       endIndex = nodes.size();
+       n = new FGNode(latEnd, lonEnd, endIndex, identEnd);
+       nodesMap[string(buffer)] = n;
+       nodes.push_back(n);
+       //cout << "Adding node: " << identEnd << endl;
+      }
+      else {
+       endIndex = itr->second->getIndex();
+      }
+
+
+      FGAirway airway;
+      airway.setIndex        ( airwayIndex++ );
+      airway.setStartNodeRef ( startNode     );
+      airway.setEndNodeRef   ( endNode       );
+      airway.setType         ( type          );
+      airway.setBase         ( base          );
+      airway.setTop          ( top           );
+      airway.setName         ( name          );
+      segments.push_back(airway);
+      //cout << "    Adding Airway: " << name << " " << startIndex << " " << endIndex << endl;
+    }
+  }
+
+  int FGAirwayNetwork::findNearestNode(double lat, double lon)
+{
+  double minDist = HUGE_VAL;
+  double distsqrt, lat2, lon2;
+  int index;
+  SGWayPoint first  (lon,
+                    lat,
+                    0);
+  //cerr << "Lat " << lat << " lon " << lon << endl;
+  for (FGNodeVectorIterator
+        itr = nodes.begin();
+       itr != nodes.end(); itr++)
+    {
+      //double course;
+      //if ((fabs(lat - ((*itr)->getLatitude())) < 0.001) &&
+      //  (fabs(lon - ((*itr)->getLongitude()) < 0.001)))
+      //cerr << "Warning: nodes are near" << endl;
+      //SGWayPoint second ((*itr)->getLongitude(),
+      //                (*itr)->getLatitude(),
+      //                0);
+      //first.CourseAndDistance(second, &course, &dist);
+      lat2 = (*itr)->getLatitude();
+      lon2 = (*itr)->getLongitude();
+      // Note: This equation should adjust for decreasing distance per longitude
+      // with increasing lat.
+      distsqrt =
+       (lat-lat2)*(lat-lat2) +
+       (lon-lon2)*(lon-lon2);
+
+      if (distsqrt < minDist)
+       {
+         minDist = distsqrt;
+         //cerr << "Test" << endl;
+         index = (*itr)->getIndex();
+         //cerr << "Minimum distance of " << minDist << " for index " << index << endl;
+         //cerr << (*itr)->getLatitude() << " " << (*itr)->getLongitude() << endl;
+       }
+      //cerr << (*itr)->getIndex() << endl;
+    }
+  //cerr << " returning  " << index << endl;
+  return index;
+}
+
+FGNode *FGAirwayNetwork::findNode(int idx)
+{
+  for (FGNodeVectorIterator
+        itr = nodes.begin();
+       itr != nodes.end(); itr++)
+    {
+      if ((*itr)->getIndex() == idx)
+       return (*itr)->getAddress();
+    }
+  return 0;
+}
+
+FGAirRoute FGAirwayNetwork::findShortestRoute(int start, int end)
+{
+  foundRoute = false;
+  totalDistance = 0;
+  FGNode *firstNode = findNode(start);
+  FGNode *lastNode  = findNode(end);
+  //prevNode = prevPrevNode = -1;
+  //prevNode = start;
+  routes.clear();
+  traceStack.clear();
+  trace(firstNode, end, 0, 0);
+  FGAirRoute empty;
+
+  if (!foundRoute)
+    {
+      SG_LOG( SG_GENERAL, SG_INFO, "Failed to find route from waypoint " << start << " to " << end );
+      cerr << "Failed to find route from waypoint " << start << " to " << end << endl;
+      //exit(1);
+    }
+  sort(routes.begin(), routes.end());
+  //for (intVecIterator i = route.begin(); i != route.end(); i++)
+  //  {
+  //    rte->push_back(*i);
+  //  }
+
+  if (routes.begin() != routes.end())
+    return *(routes.begin());
+  else
+    return empty;
+}
+
+
+void FGAirwayNetwork::trace(FGNode *currNode, int end, int depth, double distance)
+{
+  traceStack.push_back(currNode->getIndex());
+  totalDistance += distance;
+  //cerr << depth << " ";
+  //cerr << "Starting trace " << depth << " total distance: " << totalDistance<< endl;
+  //<< currNode->getIndex() << endl;
+
+  // If the current route matches the required end point we found a valid route
+  // So we can add this to the routing table
+  if (currNode->getIndex() == end)
+    {
+      cerr << "Found route : " <<  totalDistance << "" << " " << *(traceStack.end()-1) << endl;
+      routes.push_back(FGAirRoute(traceStack,totalDistance));
+      traceStack.pop_back();
+      if (!(foundRoute))
+       maxDistance = totalDistance;
+      else
+       if (totalDistance < maxDistance)
+         maxDistance = totalDistance;
+      foundRoute = true;
+      totalDistance -= distance;
+      return;
+    }
+
+
+  // search if the currentNode has been encountered before
+  // if so, we should step back one level, because it is
+  // rather rediculous to proceed further from here.
+  // if the current node has not been encountered before,
+  // i should point to traceStack.end()-1; and we can continue
+  // if i is not traceStack.end, the previous node was found,
+  // and we should return.
+  // This only works at trace levels of 1 or higher though
+  if (depth > 0) {
+    intVecIterator i = traceStack.begin();
+    while ((*i) != currNode->getIndex()) {
+      //cerr << "Route so far : " << (*i) << endl;
+      i++;
+    }
+    if (i != traceStack.end()-1) {
+      traceStack.pop_back();
+      totalDistance -= distance;
+      return;
+    }
+    // If the total distance from start to the current waypoint
+    // is longer than that of a route we can also stop this trace
+    // and go back one level.
+    if ((totalDistance > maxDistance) && foundRoute)
+      {
+       cerr << "Stopping rediculously long trace: " << totalDistance << endl;
+       traceStack.pop_back();
+       totalDistance -= distance;
+       return;
+      }
+  }
+
+  //cerr << "2" << endl;
+  if (currNode->getBeginRoute() != currNode->getEndRoute())
+    {
+      //cerr << "l3l" << endl;
+      for (FGAirwayPointerVectorIterator
+            i = currNode->getBeginRoute();
+          i != currNode->getEndRoute();
+          i++)
+       {
+         //cerr << (*i)->getLenght() << endl;
+         trace((*i)->getEnd(), end, depth+1, (*i)->getLength());
+       //  {
+       //      // cerr << currNode -> getIndex() << " ";
+       //      route.push_back(currNode->getIndex());
+       //      return true;
+       //    }
+       }
+    }
+  else
+    {
+      //SG_LOG( SG_GENERAL, SG_DEBUG, "4" );
+      //cerr << "4" << endl;
+    }
+  traceStack.pop_back();
+  totalDistance -= distance;
+  return;
+}
+
diff --git a/src/Navaids/awynet.hxx b/src/Navaids/awynet.hxx
new file mode 100755 (executable)
index 0000000..a2f4dd6
--- /dev/null
@@ -0,0 +1,210 @@
+// airwaynet.hxx - A number of classes to handle taxiway
+// assignments by the AI code
+//
+// Written by Durk Talsma. Based upon the ground netword code, started June 2005.
+//
+// Copyright (C) 2004 Durk Talsma.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+// $Id$
+
+#ifndef _AIRWAYNETWORK_HXX_
+#define _AIRWAYNETWORK_HXX_
+
+#include STL_STRING
+#include <fstream>
+#include <set>
+#include <map>
+#include <vector>
+
+SG_USING_STD(string);
+SG_USING_STD(map);
+SG_USING_STD(set);
+SG_USING_STD(vector);
+SG_USING_STD(fstream);
+
+#include <simgear/misc/sg_path.hxx>
+#include <simgear/misc/sgstream.hxx>
+
+
+//#include "parking.hxx"
+
+class FGAirway; // forward reference
+
+typedef vector<FGAirway>  FGAirwayVector;
+typedef vector<FGAirway *> FGAirwayPointerVector;
+typedef vector<FGAirway>::iterator FGAirwayVectorIterator;
+typedef vector<FGAirway*>::iterator FGAirwayPointerVectorIterator;
+
+/**************************************************************************************
+ * class FGNode
+ *************************************************************************************/
+class FGNode
+{
+private:
+  string ident;
+  double lat;
+  double lon;
+  int index;
+  FGAirwayPointerVector next; // a vector to all the segments leaving from this node
+
+public:
+  FGNode();
+  FGNode(double lt, double ln, int idx, string id) { lat = lt; lon = ln; index = idx; ident = id;};
+
+  void setIndex(int idx)                  { index = idx;};
+  void setLatitude (double val)           { lat = val;};
+  void setLongitude(double val)           { lon = val;};
+  //void setLatitude (const string& val)           { lat = processPosition(val);  };
+  //void setLongitude(const string& val)           { lon = processPosition(val);  };
+  void addAirway(FGAirway *segment) { next.push_back(segment); };
+
+  double getLatitude() { return lat;};
+  double getLongitude(){ return lon;};
+
+  int getIndex() { return index; };
+  string getIdent() { return ident; };
+  FGNode *getAddress() { return this;};
+  FGAirwayPointerVectorIterator getBeginRoute() { return next.begin(); };
+  FGAirwayPointerVectorIterator getEndRoute()   { return next.end();   };
+
+  bool matches(string ident, double lat, double lon);
+};
+
+typedef vector<FGNode *> FGNodeVector;
+typedef vector<FGNode *>::iterator FGNodeVectorIterator;
+
+
+typedef map < string, FGNode *> node_map;
+typedef node_map::iterator node_map_iterator;
+typedef node_map::const_iterator const_node_map_iterator;
+
+
+/***************************************************************************************
+ * class FGAirway
+ **************************************************************************************/
+class FGAirway
+{
+private:
+  string startNode;
+  string endNode;
+  double length;
+  FGNode *start;
+  FGNode *end;
+  int index;
+  int type; // 1=low altitude; 2=high altitude airway
+  int base; // base altitude
+  int top;  // top altitude
+  string name;
+
+public:
+  FGAirway();
+  FGAirway(FGNode *, FGNode *, int);
+
+  void setIndex        (int val) { index     = val; };
+  void setStartNodeRef (string val) { startNode = val; };
+  void setEndNodeRef   (string val) { endNode   = val; };
+
+  void setStart(node_map *nodes);
+  void setEnd  (node_map *nodes);
+  void setType (int tp) { type = tp;};
+  void setBase (int val) { base = val;};
+  void setTop  (int val) { top  = val;};
+  void setName (string val) { name = val;};
+
+  void setTrackDistance();
+
+  FGNode * getEnd() { return end;};
+  double getLength() { if (length == 0) setTrackDistance(); return length; };
+  int getIndex() { return index; };
+  string getName() { return name; };
+
+
+};
+
+
+typedef vector<int> intVec;
+typedef vector<int>::iterator intVecIterator;
+typedef vector<int>::const_iterator constIntVecIterator;
+
+class FGAirRoute
+{
+private:
+  intVec nodes;
+  double distance;
+  intVecIterator currNode;
+
+public:
+  FGAirRoute() { distance = 0; currNode = nodes.begin(); };
+  FGAirRoute(intVec nds, double dist) { nodes = nds; distance = dist; currNode = nodes.begin();};
+  bool operator< (const FGAirRoute &other) const {return distance < other.distance; };
+  bool empty () { return nodes.begin() == nodes.end(); };
+  bool next(int *val);
+
+  void first() { currNode = nodes.begin(); };
+  void add(const FGAirRoute &other);
+  void add(int node) {nodes.push_back(node);};
+
+  friend istream& operator >> (istream& in, FGAirRoute& r);
+};
+
+inline istream& operator >> ( istream& in, FGAirRoute& r )
+{
+  int node;
+  in >> node;
+  r.nodes.push_back(node);
+  //getline( in, n.name );
+  return in;
+}
+
+typedef vector<FGAirRoute> AirRouteVector;
+typedef vector<FGAirRoute>::iterator AirRouteVectorIterator;
+
+/**************************************************************************************
+ * class FGAirwayNetwork
+ *************************************************************************************/
+class FGAirwayNetwork
+{
+private:
+  bool hasNetwork;
+  node_map        nodesMap;
+  FGNodeVector    nodes;
+  FGAirwayVector segments;
+  //intVec route;
+  intVec traceStack;
+  AirRouteVector routes;
+
+  bool foundRoute;
+  double totalDistance, maxDistance;
+
+public:
+  FGAirwayNetwork();
+
+  //void addNode   (const FGNode& node);
+  //void addNodes  (FGParkingVec *parkings);
+  void addAirway(const FGAirway& seg);
+
+  void init();
+  bool exists() { return hasNetwork; };
+  int findNearestNode(double lat, double lon);
+  FGNode *findNode(int idx);
+  FGAirRoute findShortestRoute(int start, int end);
+  void trace(FGNode *, int, int, double dist);
+
+  void load(SGPath path);
+};
+
+#endif