]> git.mxchange.org Git - flightgear.git/commitdiff
X-Plane 850 airport file format parsing. 810 is still supported and may be mixed...
authorfredb <fredb>
Sun, 14 Jun 2009 11:08:21 +0000 (11:08 +0000)
committerTim Moore <timoore@redhat.com>
Mon, 15 Jun 2009 08:29:45 +0000 (10:29 +0200)
Ground radar updated to display new pavements.

projects/VC7.1/FlightGear.vcproj
src/Airports/Makefile.am
src/Airports/apt_loader.cxx
src/Airports/pavement.cxx [new file with mode: 0755]
src/Airports/pavement.hxx [new file with mode: 0755]
src/Airports/simple.cxx
src/Airports/simple.hxx
src/Instrumentation/groundradar.cxx
src/Instrumentation/groundradar.hxx

index 8d350296c06cf657b1612157066de19969fb9251..fbc25328f4bf9de8b832859e1fba8025730e9186 100755 (executable)
                        <File
                                RelativePath="..\..\src\Airports\parking.hxx">
                        </File>
+                       <File
+                               RelativePath="..\..\src\Airports\pavement.cxx">
+                       </File>
+                       <File
+                               RelativePath="..\..\src\Airports\pavement.hxx">
+                       </File>
                        <File
                                RelativePath="..\..\src\Airports\runwaybase.cxx">
                        </File>
index e78463b4ba2b498328763422dc47044b0d7f1a53..fa982678f39bd01a51e1ae660a288396b8b72995 100644 (file)
@@ -15,7 +15,8 @@ libAirports_a_SOURCES = \
        sidstar.cxx sidstar.hxx \
        runwayprefloader.cxx runwayprefloader.hxx \
        xmlloader.cxx xmlloader.hxx \
-       runwaybase.cxx runwaybase.hxx
+       runwaybase.cxx runwaybase.hxx \
+       pavement.cxx pavement.hxx
        
 calc_loc_SOURCES = calc_loc.cxx
 calc_loc_LDADD = -lsgmath -lsgdebug -lsgmisc -lsgstructure -lz $(base_LIBS)
index b12d062321091d3875ab8ad6f03f0a40d1b93b07..36eeabb643e40ab1e9c28df98670811704d86be1 100644 (file)
@@ -42,6 +42,7 @@
 
 #include "simple.hxx"
 #include "runways.hxx"
+#include "pavement.hxx"
 
 #include "apt_loader.hxx"
 
@@ -105,12 +106,18 @@ public:
               *p = 0;
         }
         SG_LOG( SG_GENERAL, SG_INFO, "Data file version = " << tmp );
-           } else if ( line_id == 1 /* Airport */ ||
+      } else if ( line_id == 1 /* Airport */ ||
                     line_id == 16 /* Seaplane base */ ||
                     line_id == 17 /* Heliport */ ) {
         parseAirportLine(simgear::strutils::split(line));
-      } else if ( line_id == 10 ) {
-        parseRunwayLine(simgear::strutils::split(line));
+      } else if ( line_id == 10 ) { // Runway v810
+        parseRunwayLine810(simgear::strutils::split(line));
+      } else if ( line_id == 100 ) { // Runway v850
+        parseRunwayLine850(simgear::strutils::split(line));
+      } else if ( line_id == 101 ) { // Water Runway v850
+        parseWaterRunwayLine850(simgear::strutils::split(line));
+      } else if ( line_id == 102 ) { // Helipad v850
+        parseHelipadLine850(simgear::strutils::split(line));
       } else if ( line_id == 18 ) {
             // beacon entry (ignore)
       } else if ( line_id == 14 ) {
@@ -124,18 +131,34 @@ public:
         got_tower = true;
       } else if ( line_id == 19 ) {
           // windsock entry (ignore)
+      } else if ( line_id == 20 ) {
+          // Taxiway sign (ignore)
+      } else if ( line_id == 21 ) {
+          // lighting objects (ignore)
       } else if ( line_id == 15 ) {
           // custom startup locations (ignore)
       } else if ( line_id == 0 ) {
           // ??
       } else if ( line_id >= 50 && line_id <= 56 ) {
           // frequency entries (ignore)
+      } else if ( line_id == 110 ) {
+        pavement = true;
+        parsePavementLine850(simgear::strutils::split(line));
+      } else if ( line_id >= 111 && line_id <= 114 ) {
+        if ( pavement )
+          parsePavementNodeLine850(line_id, simgear::strutils::split(line));
+      } else if ( line_id >= 115 && line_id <= 116 ) {
+          // other pavement nodes (ignore)
+      } else if ( line_id == 120 ) {
+        pavement = false;
+      } else if ( line_id == 130 ) {
+        pavement = false;
       } else if ( line_id == 99 ) {
           SG_LOG( SG_GENERAL, SG_DEBUG, "End of file reached" );
       } else {
           SG_LOG( SG_GENERAL, SG_ALERT, 
                   "Unknown line(#" << line_num << ") in file: " << line );
-          exit(-1);
+          exit( -1 );
       }
     }
 
@@ -153,9 +176,12 @@ private:
   double last_apt_elev;
   SGGeod tower;
   int last_apt_type;
+  string pavement_ident;
+  bool pavement;
   
   vector<FGRunwayPtr> runways;
   vector<FGTaxiwayPtr> taxiways;
+  vector<FGPavementPtr> pavements;
   
   void addAirport()
   {  
@@ -185,7 +211,7 @@ private:
     FGAirport* apt = new FGAirport(last_apt_id, pos, tower, last_apt_name, false,
         fptypeFromRobinType(last_apt_type));
         
-    apt->setRunwaysAndTaxiways(runways, taxiways);
+    apt->setRunwaysAndTaxiways(runways, taxiways, pavements);
   }
   
   void parseAirportLine(const vector<string>& token)
@@ -214,7 +240,7 @@ private:
     rwy_count = 0;
   }
   
-  void parseRunwayLine(const vector<string>& token)
+  void parseRunwayLine810(const vector<string>& token)
   {
     double lat = atof( token[1].c_str() );
     double lon = atof( token[2].c_str() );
@@ -254,14 +280,157 @@ private:
       FGRunway* rwy = new FGRunway(NULL, rwy_no, pos, heading, length,
                             width, displ_thresh1, stopway1, surface_code, false);
       runways.push_back(rwy);
-      
+
       FGRunway* reciprocal = new FGRunway(NULL, FGRunway::reverseIdent(rwy_no), 
                 pos, heading + 180.0, length, width, 
                 displ_thresh2, stopway2, surface_code, true);
-              
+
       runways.push_back(reciprocal);
     }
   }
+
+  void parseRunwayLine850(const vector<string>& token)
+  {
+    double width = atof( token[1].c_str() ) * SG_METER_TO_FEET;
+    int surface_code = atoi( token[2].c_str() );
+
+    double lat_1 = atof( token[9].c_str() );
+    double lon_1 = atof( token[10].c_str() );
+    SGGeod pos_1(SGGeod::fromDegFt(lon_1, lat_1, 0.0));
+    rwy_lat_accum += lat_1;
+    rwy_lon_accum += lon_1;
+    rwy_count++;
+
+    double lat_2 = atof( token[18].c_str() );
+    double lon_2 = atof( token[19].c_str() );
+    SGGeod pos_2(SGGeod::fromDegFt(lon_2, lat_2, 0.0));
+    rwy_lat_accum += lat_2;
+    rwy_lon_accum += lon_2;
+    rwy_count++;
+
+    double length, heading_1, heading_2, dummy;
+    SGGeodesy::inverse( pos_1, pos_2, heading_1, heading_2, length );
+    SGGeod pos;
+    SGGeodesy::direct( pos_1, heading_1, length / 2.0, pos, dummy );
+    length *= SG_METER_TO_FEET;
+
+    last_rwy_heading = heading_1;
+
+    const string& rwy_no_1(token[8]);
+    const string& rwy_no_2(token[17]);
+    if ( rwy_no_1.size() == 0 || rwy_no_2.size() == 0 )
+        return;
+
+    double displ_thresh1 = atof( token[11].c_str() );
+    double displ_thresh2 = atof( token[20].c_str() );
+
+    double stopway1 = atof( token[12].c_str() );
+    double stopway2 = atof( token[21].c_str() );
+
+    FGRunway* rwy = new FGRunway(NULL, rwy_no_1, pos, heading_1, length,
+                          width, displ_thresh1, stopway1, surface_code, false);
+    runways.push_back(rwy);
+
+    FGRunway* reciprocal = new FGRunway(NULL, rwy_no_2, 
+              pos, heading_2, length, width, 
+              displ_thresh2, stopway2, surface_code, true);
+    runways.push_back(reciprocal);
+  }
+
+  void parseWaterRunwayLine850(const vector<string>& token)
+  {
+    double width = atof( token[1].c_str() ) * SG_METER_TO_FEET;
+
+    double lat_1 = atof( token[4].c_str() );
+    double lon_1 = atof( token[5].c_str() );
+    SGGeod pos_1(SGGeod::fromDegFt(lon_1, lat_1, 0.0));
+    rwy_lat_accum += lat_1;
+    rwy_lon_accum += lon_1;
+    rwy_count++;
+
+    double lat_2 = atof( token[7].c_str() );
+    double lon_2 = atof( token[8].c_str() );
+    SGGeod pos_2(SGGeod::fromDegFt(lon_2, lat_2, 0.0));
+    rwy_lat_accum += lat_2;
+    rwy_lon_accum += lon_2;
+    rwy_count++;
+
+    double length, heading_1, heading_2, dummy;
+    SGGeodesy::inverse( pos_1, pos_2, heading_1, heading_2, length );
+    SGGeod pos;
+    SGGeodesy::direct( pos_1, heading_1, length / 2.0, pos, dummy );
+
+    last_rwy_heading = heading_1;
+
+    const string& rwy_no_1(token[3]);
+    const string& rwy_no_2(token[6]);
+
+    FGRunway* rwy = new FGRunway(NULL, rwy_no_1, pos, heading_1, length,
+                          width, 0.0, 0.0, 13, false);
+    runways.push_back(rwy);
+
+    FGRunway* reciprocal = new FGRunway(NULL, rwy_no_2, 
+              pos, heading_2, length, width, 
+              0.0, 0.0, 13, true);
+    runways.push_back(reciprocal);
+  }
+
+  void parseHelipadLine850(const vector<string>& token)
+  {
+    double length = atof( token[5].c_str() ) * SG_METER_TO_FEET;
+    double width = atof( token[6].c_str() ) * SG_METER_TO_FEET;
+
+    double lat = atof( token[2].c_str() );
+    double lon = atof( token[3].c_str() );
+    SGGeod pos(SGGeod::fromDegFt(lon, lat, 0.0));
+    rwy_lat_accum += lat;
+    rwy_lon_accum += lon;
+    rwy_count++;
+
+    double heading = atof( token[4].c_str() );
+
+    last_rwy_heading = heading;
+
+    const string& rwy_no(token[1]);
+    int surface_code = atoi( token[7].c_str() );
+
+    FGRunway* rwy = new FGRunway(NULL, rwy_no, pos, heading, length,
+                          width, 0.0, 0.0, surface_code, false);
+    runways.push_back(rwy);
+  }
+
+  void parsePavementLine850(const vector<string>& token)
+  {
+    if ( token.size() >= 5 ) {
+      pavement_ident = token[4];
+    } else {
+      pavement_ident = "xx";
+    }
+  }
+
+  void parsePavementNodeLine850(int num, const vector<string>& token)
+  {
+    double lat = atof( token[1].c_str() );
+    double lon = atof( token[2].c_str() );
+    SGGeod pos(SGGeod::fromDegFt(lon, lat, 0.0));
+
+    FGPavement* pvt = 0;
+    if ( !pavement_ident.empty() ) {
+      pvt = new FGPavement( pavement_ident, pos );
+      pavements.push_back( pvt );
+      pavement_ident = "";
+    } else {
+      pvt = pavements.back();
+    }
+    if ( num == 112 || num == 114 ) {
+      double lat_b = atof( token[3].c_str() );
+      double lon_b = atof( token[4].c_str() );
+      SGGeod pos_b(SGGeod::fromDegFt(lon_b, lat_b, 0.0));
+      pvt->addBezierNode(pos, pos_b, num == 114);
+    } else {
+      pvt->addNode(pos, num == 113);
+    }
+  }
 };
 
 // Load the airport data base from the specified aptdb file.  The
diff --git a/src/Airports/pavement.cxx b/src/Airports/pavement.cxx
new file mode 100755 (executable)
index 0000000..e89d5ad
--- /dev/null
@@ -0,0 +1,40 @@
+// pavement.cxx - class to represent complex taxiway specified in v850 apt.dat 
+//
+// Copyright (C) 2009 Frederic Bouvier
+//
+// 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// $Id$
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include "pavement.hxx"
+
+FGPavement::FGPavement(const std::string& aIdent, const SGGeod& aPos) :
+  FGPositioned(TAXIWAY, aIdent, aPos, false)
+{
+}
+
+void FGPavement::addNode(const SGGeod &aPos, bool aClose)
+{
+  mNodes.push_back(new SimpleNode(aPos, aClose));
+}
+
+void FGPavement::addBezierNode(const SGGeod &aPos, const SGGeod &aCtrlPt, bool aClose)
+{
+  mNodes.push_back(new BezierNode(aPos, aCtrlPt, aClose));
+}
diff --git a/src/Airports/pavement.hxx b/src/Airports/pavement.hxx
new file mode 100755 (executable)
index 0000000..9137cfc
--- /dev/null
@@ -0,0 +1,74 @@
+// pavement.hxx - class to represent complex taxiway specified in v850 apt.dat 
+//
+// Copyright (C) 2009 Frederic Bouvier
+//
+// 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// $Id$
+
+#ifndef FG_PAVEMENT_HXX
+#define FG_PAVEMENT_HXX
+
+#include <Navaids/positioned.hxx>
+
+class FGPavement : public FGPositioned
+{
+public:
+  /*
+   * 111 = Node (simple point).
+   * 112 = Node with Bezier control point.
+   * 113 = Node (close loop) point (to close a pavement boundary).
+   * 114 = Node (close loop) point with Bezier control point (to close a pavement boundary).
+   * 115 = Node (end) point to terminate a linear feature (so has no descriptive codes).
+   * 116 = Node (end) point with Bezier control point, to terminate a linear feature (so has no descriptive codes).
+   */
+  struct NodeBase : public SGReferenced
+  {
+    SGGeod mPos;
+    bool mClose;
+    virtual ~NodeBase(){} // To enable RTTI
+  };
+  struct SimpleNode : public NodeBase //111,113
+  {
+    SimpleNode(const SGGeod &aPos, bool aClose) {
+      mPos = aPos;
+      mClose = aClose;
+    }
+  };
+  struct BezierNode : public NodeBase //112,114
+  {
+    BezierNode(const SGGeod &aPos, const SGGeod &aCtrlPt, bool aClose) {
+      mPos = aPos;
+      mClose = aClose;
+      mControl = aCtrlPt;
+    }
+    SGGeod mControl;
+  };
+  typedef std::vector<SGSharedPtr<NodeBase> > NodeList;
+
+
+  FGPavement(const std::string& aIdent, const SGGeod& aPos);
+
+  void addNode(const SGGeod &aPos, bool aClose = false);
+  void addBezierNode(const SGGeod &aPos, const SGGeod &aCtrlPt, bool aClose = false);
+
+  const NodeList &getNodeList() const { return mNodes; }
+
+
+private:
+  NodeList mNodes;
+};
+
+#endif // of FG_PAVEMENT_HXX
index 6a1334cc10f40f53c30f4e31f01655f436a4446c..04dec38b8d4286a29b3ec740298bda969fb28efe 100644 (file)
@@ -39,6 +39,7 @@
 #include <Environment/environment.hxx>
 #include <Main/fg_props.hxx>
 #include <Airports/runways.hxx>
+#include <Airports/pavement.hxx>
 #include <Airports/dynamics.hxx>
 #include <Airports/xmlloader.hxx>
 
@@ -201,16 +202,29 @@ FGTaxiway* FGAirport::getTaxiwayByIndex(unsigned int aIndex) const
   return mTaxiways[aIndex];
 }
 
+unsigned int FGAirport::numPavements() const
+{
+  return mPavements.size();
+}
+
+FGPavement* FGAirport::getPavementByIndex(unsigned int aIndex) const
+{
+  assert(aIndex >= 0 && aIndex < mPavements.size());
+  return mPavements[aIndex];
+}
+
 void FGAirport::setRunwaysAndTaxiways(vector<FGRunwayPtr>& rwys,
-       vector<FGTaxiwayPtr>& txwys)
+       vector<FGTaxiwayPtr>& txwys,
+       vector<FGPavementPtr>& pvts)
 {
   mRunways.swap(rwys);
   Runway_iterator it = mRunways.begin();
   for (; it != mRunways.end(); ++it) {
     (*it)->setAirport(this);
   }
-  
+
   mTaxiways.swap(txwys);
+  mPavements.swap(pvts);
 }
 
 FGRunway* FGAirport::getActiveRunwayForUsage() const
index 80b690e0df70a2743daf276e5f04b2a693c5be3d..71fb97fb8b8cf4b4797607c1ff0e2ce2c7054dc4 100644 (file)
 class FGAirportDynamics;
 class FGRunway;
 class FGTaxiway;
+class FGPavement;
 
 typedef SGSharedPtr<FGRunway> FGRunwayPtr;
 typedef SGSharedPtr<FGTaxiway> FGTaxiwayPtr;
+typedef SGSharedPtr<FGPavement> FGPavementPtr;
 
 /***************************************************************************************
  *
@@ -93,12 +95,16 @@ public:
      * aiport has a hard-surfaced runway of at least the specified length.
      */
     bool hasHardRunwayOfLengthFt(double aLengthFt) const;
-    
+
     unsigned int numTaxiways() const;
     FGTaxiway* getTaxiwayByIndex(unsigned int aIndex) const;
-    
+
+    unsigned int numPavements() const;
+    FGPavement* getPavementByIndex(unsigned int aIndex) const;
+
     void setRunwaysAndTaxiways(std::vector<FGRunwayPtr>& rwys,
-      std::vector<FGTaxiwayPtr>& txwys);
+      std::vector<FGTaxiwayPtr>& txwys,
+      std::vector<FGPavementPtr>& pvts);
     
     class AirportFilter : public Filter
      {
@@ -172,6 +178,7 @@ private:
     
     std::vector<FGRunwayPtr> mRunways;
     std::vector<FGTaxiwayPtr> mTaxiways;
+    std::vector<FGPavementPtr> mPavements;
 };
 
 // find basic airport location info from airport database
index 3b74bea9e744b7dce69f198491d17b33717b5944..937fa2614b4858758c068307b31055a4185c5d81 100644 (file)
@@ -30,6 +30,7 @@
 #include <osgText/Text>
 #include <osgDB/Registry>
 #include <osgDB/ReaderWriter>
+#include <osgUtil/Tessellator>
 
 #include <Main/fg_props.hxx>
 #include <Main/globals.hxx>
@@ -37,7 +38,9 @@
 #include <Cockpit/panel.hxx>
 #include <Airports/simple.hxx>
 #include <Airports/runways.hxx>
+#include <Airports/pavement.hxx>
 #include <simgear/math/sg_geodesy.hxx>
+#include <simgear/math/beziercurve.hxx>
 
 #include "groundradar.hxx"
 
@@ -84,27 +87,39 @@ inline static osg::Vec3 fromPolar(double fi, double r)
 
 void GroundRadar::createTexture(const char* texture_name)
 {
-    setSize(512);
+    setSize(TextureHalfSize + TextureHalfSize);
     allocRT();
 
-    osg::Vec4Array* colors = new osg::Vec4Array;
-    colors->push_back(osg::Vec4(0.0f, 0.5f, 0.0f, 1.0f));
-    colors->push_back(osg::Vec4(0.0f, 0.5f, 0.5f, 1.0f));
+    _geode = new osg::Geode();
+    osg::StateSet* stateset = _geode->getOrCreateStateSet();
+    stateset->setMode(GL_BLEND, osg::StateAttribute::OFF);
 
-    _geom = new osg::Geometry();
-    _geom->setColorArray(colors);
-    _geom->setColorBinding(osg::Geometry::BIND_PER_PRIMITIVE_SET);
-    _geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, 0));
-    _geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, 0));
+    osg::Vec4Array* taxi_color = new osg::Vec4Array;
+    taxi_color->push_back(osg::Vec4(0.0f, 0.5f, 0.0f, 1.0f));
+    osg::Vec4Array* rwy_color = new osg::Vec4Array;
+    rwy_color->push_back(osg::Vec4(0.0f, 0.5f, 0.5f, 1.0f));
 
-    osg::Geode* geode = new osg::Geode();
-    osg::StateSet* stateset = geode->getOrCreateStateSet();
-    stateset->setMode(GL_BLEND, osg::StateAttribute::OFF);
-    geode->addDrawable(_geom.get());
+    osg::Geometry *taxi_geom = new osg::Geometry();
+    taxi_geom->setColorArray(taxi_color);
+    taxi_geom->setColorBinding(osg::Geometry::BIND_OVERALL);
+    taxi_geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, 0)); // Taxiways
+    _geode->addDrawable(taxi_geom);
+
+    osg::Geometry *pvt_geom = new osg::Geometry();
+    pvt_geom->setColorArray(taxi_color);
+    pvt_geom->setColorBinding(osg::Geometry::BIND_OVERALL);
+    // no primitive set for the moment. It needs tessellation
+    _geode->addDrawable(pvt_geom);
+
+    osg::Geometry *rwy_geom = new osg::Geometry();
+    rwy_geom->setColorArray(rwy_color);
+    rwy_geom->setColorBinding(osg::Geometry::BIND_OVERALL);
+    rwy_geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, 0)); // Runways
+    _geode->addDrawable(rwy_geom);
 
     osg::Camera* camera = getCamera();
     camera->setPostDrawCallback(new SingleFrameCallback());
-    camera->addChild(geode);
+    camera->addChild(_geode.get());
     camera->setNodeMask(0);
     camera->setProjectionMatrixAsOrtho2D(0, getTexture()->getTextureWidth(), 0, getTexture()->getTextureHeight());
 
@@ -117,7 +132,7 @@ void GroundRadar::addRunwayVertices(const FGRunwayBase* aRunway, double aTowerLa
   double az1, az2, dist_m;
   geo_inverse_wgs_84(aTowerLat, aTowerLon, aRunway->latitude(), aRunway->longitude(), &az1, &az2, &dist_m);
 
-  osg::Vec3 center = fromPolar(az1, dist_m * aScale) + osg::Vec3(256, 256, 0);
+  osg::Vec3 center = fromPolar(az1, dist_m * aScale) + osg::Vec3(TextureHalfSize, TextureHalfSize, 0);
   osg::Vec3 leftcenter = fromPolar(aRunway->headingDeg(), aRunway->lengthM() * aScale / 2) + center;
   osg::Vec3 lefttop = fromPolar(aRunway->headingDeg() - 90, aRunway->widthM() * aScale / 2) + leftcenter;
   osg::Vec3 leftbottom = leftcenter * 2 - lefttop;
@@ -130,10 +145,74 @@ void GroundRadar::addRunwayVertices(const FGRunwayBase* aRunway, double aTowerLa
   aVertices->push_back(righttop);
 }
 
+osg::Geometry *GroundRadar::addPavementGeometry(const FGPavement* aPavement, double aTowerLat, double aTowerLon, double aScale)
+{
+
+  osg::ref_ptr<osgUtil::Tessellator> tess = new osgUtil::Tessellator;
+  osg::ref_ptr<osg::Geometry> polygon = new osg::Geometry;
+  osg::ref_ptr<osg::Vec3Array> pts = new osg::Vec3Array;
+
+  double az1, az2, dist_m;
+  const FGPavement::NodeList &nodeLst = aPavement->getNodeList();
+  FGPavement::NodeList::const_iterator it = nodeLst.begin(),
+                                        loopBegin = it;
+  while ( it != nodeLst.end() )
+  {
+    bool close = (*it)->mClose;
+    geo_inverse_wgs_84(aTowerLat, aTowerLon, (*it)->mPos.getLatitudeDeg(), (*it)->mPos.getLongitudeDeg(), &az1, &az2, &dist_m);
+    osg::Vec3 p1 = fromPolar(az1, dist_m * aScale) + osg::Vec3(TextureHalfSize, TextureHalfSize, 0);
+    const FGPavement::BezierNode *bn = dynamic_cast<const FGPavement::BezierNode *>( it->ptr() );
+    if ( bn != 0 )
+    {
+      geo_inverse_wgs_84(aTowerLat, aTowerLon, bn->mControl.getLatitudeDeg(), bn->mControl.getLongitudeDeg(), &az1, &az2, &dist_m);
+      osg::Vec3 p2 = fromPolar(az1, dist_m * aScale) + osg::Vec3(TextureHalfSize, TextureHalfSize, 0),
+                p3;
+      ++it;
+      if ( it == nodeLst.end() || close )
+      {
+        geo_inverse_wgs_84(aTowerLat, aTowerLon, (*loopBegin)->mPos.getLatitudeDeg(), (*loopBegin)->mPos.getLongitudeDeg(), &az1, &az2, &dist_m);
+      }
+      else
+      {
+        geo_inverse_wgs_84(aTowerLat, aTowerLon, (*it)->mPos.getLatitudeDeg(), (*it)->mPos.getLongitudeDeg(), &az1, &az2, &dist_m);
+      }
+      p3 = fromPolar(az1, dist_m * aScale) + osg::Vec3(TextureHalfSize, TextureHalfSize, 0);
+      simgear::BezierCurve<osg::Vec3> bCurv( p1, p2, p3 );
+      simgear::BezierCurve<osg::Vec3>::PointList &ptList = bCurv.pointList();
+      for ( simgear::BezierCurve<osg::Vec3>::PointList::iterator ii = ptList.begin(); ii != ptList.end(); ++ii )
+      {
+        pts->push_back( *ii );
+      }
+      pts->pop_back(); // Last point belongs to next segment
+    }
+    else
+    {
+      pts->push_back( p1 );
+      ++it;
+    }
+
+    if ( close ) // One loop for the moment
+      break;
+  }
+  geo_inverse_wgs_84(aTowerLat, aTowerLon, (*loopBegin)->mPos.getLatitudeDeg(), (*loopBegin)->mPos.getLongitudeDeg(), &az1, &az2, &dist_m);
+  osg::Vec3 p1 = fromPolar(az1, dist_m * aScale) + osg::Vec3(TextureHalfSize, TextureHalfSize, 0);
+  pts->push_back( p1 );
+  polygon->setVertexArray( pts );
+
+  polygon->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::POLYGON, 0, pts->size() ) );
+
+  tess->setTessellationType( osgUtil::Tessellator::TESS_TYPE_GEOMETRY );
+  tess->setBoundaryOnly( false );
+  tess->setWindingType( osgUtil::Tessellator::TESS_WINDING_ODD );
+  tess->retessellatePolygons( *polygon );
+  return polygon.release();
+}
+
 void GroundRadar::updateTexture()
 {
     osg::ref_ptr<osg::Vec3Array> rwy_vertices = new osg::Vec3Array;
     osg::ref_ptr<osg::Vec3Array> taxi_vertices = new osg::Vec3Array;
+    osg::ref_ptr<osg::Vec3Array> pvt_vertices = new osg::Vec3Array;
 
     const string airport_name = _airport_node->getStringValue();
 
@@ -149,6 +228,107 @@ void GroundRadar::updateTexture()
     const FGAirport* apt = fgFindAirportID(airport_name);
     assert(apt);
 
+    for (unsigned int i=0; i<apt->numTaxiways(); ++i)
+    {
+      FGTaxiway* txwy(apt->getTaxiwayByIndex(i));
+      addRunwayVertices(txwy, tower_lat, tower_lon, scale, taxi_vertices.get());
+    }
+    osg::Geometry *taxi_geom = dynamic_cast<osg::Geometry *>(_geode->getDrawable(0));
+    taxi_geom->setVertexArray(taxi_vertices.get());
+    osg::DrawArrays* taxi = dynamic_cast<osg::DrawArrays*>(taxi_geom->getPrimitiveSet(0));
+    taxi->setCount(taxi_vertices->size());
+
+    osg::Geometry *pvt_geom = dynamic_cast<osg::Geometry *>(_geode->getDrawable(1));
+    osg::Geometry::PrimitiveSetList &pvt_prim_list = pvt_geom->getPrimitiveSetList();
+    pvt_prim_list.clear();
+    for (unsigned int i=0; i<apt->numPavements(); ++i)
+    {
+      FGPavement* pvt(apt->getPavementByIndex(i));
+      osg::ref_ptr<osg::Geometry> geom = addPavementGeometry(pvt, tower_lat, tower_lon, scale);
+      osg::Geometry::PrimitiveSetList &prim_list = geom->getPrimitiveSetList();
+      osg::Vec3Array *vertices = dynamic_cast<osg::Vec3Array *>(geom->getVertexArray());
+      size_t before = pvt_vertices->size(),
+            count = vertices->size();
+      for (size_t i = 0; i < count; ++i )
+      {
+        pvt_vertices->push_back( (*vertices)[i] );
+      }
+      for (osg::Geometry::PrimitiveSetList::iterator ii = prim_list.begin(); ii != prim_list.end(); ++ii )
+      {
+        osg::DrawArrays *da;
+        osg::DrawElementsUByte *de1;
+        osg::DrawElementsUShort *de2;
+        osg::DrawElementsUInt *de3;
+        if ((da = dynamic_cast<osg::DrawArrays *>(ii->get())) != 0)
+        {
+          osg::DrawArrays *ps = new osg::DrawArrays(*da);
+          ps->setFirst(da->getFirst() + before);
+          pvt_prim_list.push_back(ps);
+        }
+        else if ((de1 = dynamic_cast<osg::DrawElementsUByte *>(ii->get())) != 0)
+        {
+          if (before + count <= 255)
+          {
+            osg::DrawElementsUByte *ps = new osg::DrawElementsUByte(*de1);
+            for (size_t j = 0; j < ps->size(); ++j)
+            {
+              (*ps)[j] += before;
+            }
+            pvt_prim_list.push_back(ps);
+          }
+          else if (before + count <= 65535)
+          {
+            osg::DrawElementsUShort *ps = new osg::DrawElementsUShort(de1->getMode(), de1->begin(), de1->end());
+            for (size_t j = 0; j < ps->size(); ++j)
+            {
+              (*ps)[j] += before;
+            }
+            pvt_prim_list.push_back(ps);
+          }
+          else
+          {
+            osg::DrawElementsUInt *ps = new osg::DrawElementsUInt(de1->getMode(), de1->begin(), de1->end());
+            for (size_t j = 0; j < ps->size(); ++j)
+            {
+              (*ps)[j] += before;
+            }
+            pvt_prim_list.push_back(ps);
+          }
+        }
+        else if ((de2 = dynamic_cast<osg::DrawElementsUShort *>(ii->get())) != 0)
+        {
+          if (before + count <= 65535)
+          {
+            osg::DrawElementsUShort *ps = new osg::DrawElementsUShort(*de2);
+            for (size_t j = 0; j < ps->size(); ++j)
+            {
+              (*ps)[j] += before;
+            }
+            pvt_prim_list.push_back(ps);
+          }
+          else
+          {
+            osg::DrawElementsUInt *ps = new osg::DrawElementsUInt(de2->getMode(), de2->begin(), de2->end());
+            for (size_t j = 0; j < ps->size(); ++j)
+            {
+              (*ps)[j] += before;
+            }
+            pvt_prim_list.push_back(ps);
+          }
+        }
+        else if ((de3 = dynamic_cast<osg::DrawElementsUInt *>(ii->get())) != 0)
+        {
+          osg::DrawElementsUInt *ps = new osg::DrawElementsUInt(*de3);
+          for (size_t j = 0; j < ps->size(); ++j)
+          {
+            (*ps)[j] += before;
+          }
+          pvt_prim_list.push_back(ps);
+        }
+      }
+    }
+    pvt_geom->setVertexArray(pvt_vertices.get());
+
     for (unsigned int i=0; i<apt->numRunways(); ++i)
     {
       FGRunway* runway(apt->getRunwayByIndex(i));
@@ -156,20 +336,9 @@ void GroundRadar::updateTexture()
       
       addRunwayVertices(runway, tower_lat, tower_lon, scale, rwy_vertices.get());
     }
-    
-    for (unsigned int i=0; i<apt->numTaxiways(); ++i)
-    {
-      FGTaxiway* txwy(apt->getTaxiwayByIndex(i));
-      addRunwayVertices(txwy, tower_lat, tower_lon, scale, taxi_vertices.get());
-    }
-    
-    osg::Vec3Array* vertices = new osg::Vec3Array(*taxi_vertices.get());
-    vertices->insert(vertices->end(), rwy_vertices->begin(), rwy_vertices->end());
-    _geom->setVertexArray(vertices);
-    osg::DrawArrays* taxi = dynamic_cast<osg::DrawArrays*>(_geom->getPrimitiveSet(0));
-    osg::DrawArrays* rwy = dynamic_cast<osg::DrawArrays*>(_geom->getPrimitiveSet(1));
-    taxi->setCount(taxi_vertices->size());
-    rwy->setFirst(taxi_vertices->size());
+    osg::Geometry *rwy_geom = dynamic_cast<osg::Geometry *>(_geode->getDrawable(2));
+    rwy_geom->setVertexArray(rwy_vertices.get());
+    osg::DrawArrays* rwy = dynamic_cast<osg::DrawArrays*>(rwy_geom->getPrimitiveSet(0));
     rwy->setCount(rwy_vertices->size());
 
     getCamera()->setNodeMask(0xffffffff);
index 64cbd04a6fe5b90022eb8533e1a25b0c07597f51..dc653f2c4d3666b47ec88b9db375bf0d707b1de9 100644 (file)
@@ -35,6 +35,7 @@ class FGRunwayBase;
 class GroundRadar : public SGPropertyChangeListener, public FGODGauge
 {
 public:
+    static const int TextureHalfSize = 256;
     GroundRadar(SGPropertyNode* node);
     virtual ~GroundRadar();
     void updateTexture();
@@ -44,8 +45,9 @@ protected:
     void createTexture(const char* texture_name);
     
     void addRunwayVertices(const FGRunwayBase* aRunway, double aTowerLat, double aTowerLon, double aScale, osg::Vec3Array* aVertices);
+    osg::Geometry *addPavementGeometry(const FGPavement* aPavement, double aTowerLat, double aTowerLon, double aScale);
     
-    osg::ref_ptr<osg::Geometry> _geom;
+    osg::ref_ptr<osg::Geode> _geode;
     SGPropertyNode_ptr _airport_node;
     SGPropertyNode_ptr _range_node;
 };