Changeset 13936

Show
Ignore:
Timestamp:
03/05/08 17:52:33 (4 months ago)
Author:
rouault
Message:

Update of X-Plane driver

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/gdal/ogr/ogrsf_frmts/xplane/GNUmakefile

    r13919 r13936  
    33include ../../../GDALmake.opt 
    44 
    5 OBJ     =       ogrxplanedriver.o ogrxplanedatasource.o ogrxplanelayer.o 
     5OBJ     =       ogrxplanedriver.o ogrxplanedatasource.o ogrxplanelayer.o ogr_xplane_geo_utils.o 
    66 
    77CPPFLAGS        :=      -I.. -I../.. $(GDAL_INCLUDE) $(CPPFLAGS) 
     
    1414$(O_OBJ):       ogr_xplane.h 
    1515 
     16test_geo_utils: test_geo_utils.o ogr_xplane_geo_utils.o 
     17        $(CXX) test_geo_utils.o ogr_xplane_geo_utils.o -o test_geo_utils -lm 
  • trunk/gdal/ogr/ogrsf_frmts/xplane/makefile.vc

    r13919 r13936  
    11 
    2 OBJ     =       ogrxplanedriver.obj ogrxplanedatasource.obj ogrxplanelayer.obj  
     2OBJ     =       ogrxplanedriver.obj ogrxplanedatasource.obj ogrxplanelayer.obj ogr_xplane_geo_utils.obj 
    33 
    44EXTRAFLAGS =    -I.. -I..\..  
  • trunk/gdal/ogr/ogrsf_frmts/xplane/ogr_xplane.h

    r13919 r13936  
    104104  public: 
    105105                        OGRXPlaneILSLayer(); 
    106     void                AddFeature(const char* pszNavaidID, 
     106    OGRFeature*         AddFeature(const char* pszNavaidID, 
    107107                                   const char* pszAptICAO, 
    108108                                   const char* pszRwyNum, 
     
    125125  public: 
    126126                        OGRXPlaneVORLayer(); 
    127     void                AddFeature(const char* pszNavaidID, 
     127    OGRFeature*         AddFeature(const char* pszNavaidID, 
    128128                                   const char* pszNavaidName, 
    129129                                   const char* pszSubType, 
     
    145145  public: 
    146146                        OGRXPlaneNDBLayer(); 
    147     void                AddFeature(const char* pszNavaidID, 
     147    OGRFeature*         AddFeature(const char* pszNavaidID, 
    148148                                   const char* pszNavaidName, 
    149149                                   const char* pszSubType, 
     
    164164  public: 
    165165                        OGRXPlaneGSLayer(); 
    166     void                AddFeature(const char* pszNavaidID, 
     166    OGRFeature*         AddFeature(const char* pszNavaidID, 
    167167                                   const char* pszAptICAO, 
    168168                                   const char* pszRwyNum, 
     
    185185  public: 
    186186                        OGRXPlaneMarkerLayer(); 
    187     void                AddFeature(const char* pszAptICAO, 
     187    OGRFeature*         AddFeature(const char* pszAptICAO, 
    188188                                   const char* pszRwyNum, 
    189189                                   const char* pszSubType, 
     
    203203  public: 
    204204                        OGRXPlaneDMEILSLayer(); 
    205     void                AddFeature(const char* pszNavaidID, 
     205    OGRFeature*         AddFeature(const char* pszNavaidID, 
    206206                                   const char* pszAptICAO, 
    207207                                   const char* pszRwyNum, 
     
    224224  public: 
    225225                        OGRXPlaneDMELayer(); 
    226     void                AddFeature(const char* pszNavaidID, 
     226    OGRFeature*         AddFeature(const char* pszNavaidID, 
    227227                                   const char* pszNavaidName, 
    228228                                   const char* pszSubType, 
     
    247247    /* If the airport has a tower, its coordinates are the tower coordinates */ 
    248248    /* If it has no tower, then we pick up the coordinates of the threshold of its first found runway */ 
    249     void                AddFeature(const char* pszAptICAO, 
     249    OGRFeature*         AddFeature(const char* pszAptICAO, 
    250250                                   const char* pszAptName, 
    251251                                   double dfElevation, 
     
    260260 
    261261/************************************************************************/ 
    262 /*                         OGRXPlaneRunwayLayer                         */ 
     262/*                OGRXPlaneRunwayThresholdLayerLayer                    */ 
    263263/************************************************************************/ 
    264264 
     
    313313{ 
    314314    { 0, "None" }, 
    315     { 1, "omni-directional" }, 
    316     { 2, "unidirectional" } 
     315    { 1, "Omni-directional" }, 
     316    { 2, "Unidirectional" } 
    317317}; 
    318318 
     
    324324 
    325325 
    326 class OGRXPlaneRunwayLayer : public OGRXPlaneLayer 
    327 { 
    328   public: 
    329                         OGRXPlaneRunwayLayer(); 
    330  
    331     void                AddFeature(const char* pszAptICAO, 
    332                                    const char* pszRunwayID
     326class OGRXPlaneRunwayThresholdLayer : public OGRXPlaneLayer 
     327{ 
     328  public: 
     329                        OGRXPlaneRunwayThresholdLayer(); 
     330 
     331    OGRFeature*         AddFeature(const char* pszAptICAO, 
     332                                   const char* pszRwyNum
    333333                                   double dfLat, 
    334334                                   double dfLon, 
     
    346346                                   int bHasTouchdownLights, 
    347347                                   const char* pszREIL); 
    348 }; 
    349  
     348 
     349    /* Set a few computed values */ 
     350    void                 SetRunwayLengthAndHeading(OGRFeature* poFeature, 
     351                                                   double dfLength, 
     352                                                   double dfHeading); 
     353}; 
     354 
     355/************************************************************************/ 
     356/*                          OGRXPlaneRunwayLayer                        */ 
     357/************************************************************************/ 
     358 
     359 
     360class OGRXPlaneRunwayLayer : public OGRXPlaneLayer 
     361
     362  public: 
     363                        OGRXPlaneRunwayLayer(); 
     364 
     365    OGRFeature*         AddFeature(const char* pszAptICAO, 
     366                                   const char* pszRwyNum1, 
     367                                   const char* pszRwyNum2, 
     368                                   double dfLat1, 
     369                                   double dfLon1, 
     370                                   double dfLat2, 
     371                                   double dfLon2, 
     372                                   double dfWidth, 
     373                                   const char* pszSurfaceType, 
     374                                   const char* pszShoulderType, 
     375                                   double dfSmoothness, 
     376                                   int bHasCenterLineLights, 
     377                                   int bHasMIRL, 
     378                                   int bHasDistanceRemainingSigns); 
     379}; 
     380 
     381 
     382/************************************************************************/ 
     383/*                   OGRXPlaneWaterRunwayThresholdLayer                 */ 
     384/************************************************************************/ 
     385 
     386 
     387class OGRXPlaneWaterRunwayThresholdLayer : public OGRXPlaneLayer 
     388
     389  public: 
     390                        OGRXPlaneWaterRunwayThresholdLayer(); 
     391 
     392    OGRFeature*         AddFeature(const char* pszAptICAO, 
     393                                   const char* pszRwyNum, 
     394                                   double dfLat, 
     395                                   double dfLon, 
     396                                   double dfWidth, 
     397                                   int bBuoys); 
     398 
     399    /* Set a few computed values */ 
     400    void                 SetRunwayLengthAndHeading(OGRFeature* poFeature, 
     401                                                   double dfLength, 
     402                                                   double dfHeading); 
     403}; 
     404 
     405 
     406/************************************************************************/ 
     407/*                         OGRXPlaneWaterRunwayLayer                    */ 
     408/************************************************************************/ 
     409 
     410/* Polygonal object */ 
     411 
     412class OGRXPlaneWaterRunwayLayer : public OGRXPlaneLayer 
     413
     414  public: 
     415                        OGRXPlaneWaterRunwayLayer(); 
     416 
     417    OGRFeature*         AddFeature(const char* pszAptICAO, 
     418                                   const char* pszRwyNum1, 
     419                                   const char* pszRwyNum2, 
     420                                   double dfLat1, 
     421                                   double dfLon1, 
     422                                   double dfLat2, 
     423                                   double dfLon2, 
     424                                   double dfWidth, 
     425                                   int bBuoys); 
     426}; 
     427 
     428 
     429/************************************************************************/ 
     430/*                        OGRXPlaneHelipadLayer                         */ 
     431/************************************************************************/ 
     432 
     433 
     434class OGRXPlaneHelipadLayer : public OGRXPlaneLayer 
     435
     436  public: 
     437                        OGRXPlaneHelipadLayer(); 
     438 
     439    OGRFeature*         AddFeature(const char* pszAptICAO, 
     440                                   const char* pszHelipadNum, 
     441                                   double dfLat, 
     442                                   double dfLon, 
     443                                   double dfTrueHeading, 
     444                                   double dfLength, 
     445                                   double dfWidth, 
     446                                   const char* pszSurfaceType, 
     447                                   const char* pszMarkings, 
     448                                   const char* pszShoulderType, 
     449                                   double dfSmoothness, 
     450                                   int bYellowEdgeLights); 
     451}; 
     452 
     453/************************************************************************/ 
     454/*                     OGRXPlaneHelipadPolygonLayer                     */ 
     455/************************************************************************/ 
     456 
     457 
     458class OGRXPlaneHelipadPolygonLayer : public OGRXPlaneLayer 
     459
     460  public: 
     461                        OGRXPlaneHelipadPolygonLayer(); 
     462 
     463    OGRFeature*         AddFeature(const char* pszAptICAO, 
     464                                   const char* pszHelipadNum, 
     465                                   double dfLat, 
     466                                   double dfLon, 
     467                                   double dfTrueHeading, 
     468                                   double dfLength, 
     469                                   double dfWidth, 
     470                                   const char* pszSurfaceType, 
     471                                   const char* pszMarkings, 
     472                                   const char* pszShoulderType, 
     473                                   double dfSmoothness, 
     474                                   int bYellowEdgeLights); 
     475}; 
    350476 
    351477/************************************************************************/ 
     
    358484                        OGRXPlaneATCFreqLayer(); 
    359485 
    360     void                AddFeature(const char* pszAptICAO, 
     486    OGRFeature*         AddFeature(const char* pszAptICAO, 
    361487                                   const char* pszATCType, 
    362488                                   const char* pszATCFreqName, 
    363                                    double dFrequency); 
     489                                   double dfFrequency); 
     490}; 
     491 
     492 
     493/************************************************************************/ 
     494/*                     OGRXPlaneStartupLocationLayer                    */ 
     495/************************************************************************/ 
     496 
     497class OGRXPlaneStartupLocationLayer : public OGRXPlaneLayer 
     498
     499  public: 
     500                        OGRXPlaneStartupLocationLayer(); 
     501 
     502    OGRFeature*         AddFeature(const char* pszAptICAO, 
     503                                   const char* pszName, 
     504                                   double dfLat, 
     505                                   double dfLon, 
     506                                   double dfTrueHeading); 
     507}; 
     508 
     509/************************************************************************/ 
     510/*                     OGRXPlaneAPTLightBeaconLayer                     */ 
     511/************************************************************************/ 
     512 
     513 
     514static const sEnumerationElement APTLightBeaconColorType[] = 
     515
     516    { 0, "None" }, 
     517    { 1, "White-green" },           /* land airport */ 
     518    { 2, "White-yellow" },          /* seaplane base */ 
     519    { 3, "Green-yellow-white" },    /* heliports */ 
     520    { 4, "White-white-green" }     /* military field */ 
     521}; 
     522 
     523DEFINE_XPLANE_ENUMERATION(APTLightBeaconColorEnumeration, APTLightBeaconColorType); 
     524 
     525class OGRXPlaneAPTLightBeaconLayer : public OGRXPlaneLayer 
     526
     527  public: 
     528                        OGRXPlaneAPTLightBeaconLayer(); 
     529 
     530    OGRFeature*         AddFeature(const char* pszAptICAO, 
     531                                   const char* pszName, 
     532                                   double dfLat, 
     533                                   double dfLon, 
     534                                   const char* pszColor); 
     535}; 
     536 
     537/************************************************************************/ 
     538/*                       OGRXPlaneAPTWindsockLayer                      */ 
     539/************************************************************************/ 
     540 
     541class OGRXPlaneAPTWindsockLayer : public OGRXPlaneLayer 
     542
     543  public: 
     544                        OGRXPlaneAPTWindsockLayer(); 
     545 
     546    OGRFeature*         AddFeature(const char* pszAptICAO, 
     547                                   const char* pszName, 
     548                                   double dfLat, 
     549                                   double dfLon, 
     550                                   int bIsIllumnited); 
     551}; 
     552 
     553 
     554/************************************************************************/ 
     555/*                       OGRXPlaneTaxiwaySignLayer                      */ 
     556/************************************************************************/ 
     557 
     558class OGRXPlaneTaxiwaySignLayer : public OGRXPlaneLayer 
     559
     560  public: 
     561                        OGRXPlaneTaxiwaySignLayer(); 
     562 
     563    OGRFeature*         AddFeature(const char* pszAptICAO, 
     564                                   const char* pszText, 
     565                                   double dfLat, 
     566                                   double dfLon, 
     567                                   double dfHeading, 
     568                                   int nSize); 
     569}; 
     570 
     571/************************************************************************/ 
     572/*                   OGRXPlane_VASI_PAPI_WIGWAG_Layer                   */ 
     573/************************************************************************/ 
     574 
     575static const sEnumerationElement VASI_PAPI_WIGWAG_Type[] = 
     576
     577    { 1, "VASI" }, 
     578    { 2, "PAPI Left" }, 
     579    { 3, "PAPI Right" }, 
     580    { 4, "Space Shuttle PAPI" }, 
     581    { 5, "Tri-colour VASI" }, 
     582    { 6, "Wig-Wag lights" } 
     583}; 
     584 
     585DEFINE_XPLANE_ENUMERATION(VASI_PAPI_WIGWAG_Enumeration, VASI_PAPI_WIGWAG_Type); 
     586 
     587class OGRXPlane_VASI_PAPI_WIGWAG_Layer : public OGRXPlaneLayer 
     588
     589  public: 
     590                        OGRXPlane_VASI_PAPI_WIGWAG_Layer(); 
     591 
     592    OGRFeature*         AddFeature(const char* pszAptICAO, 
     593                                   const char* pszRwyNum, 
     594                                   const char* pszObjectType, 
     595                                   double dfLat, 
     596                                   double dfLon, 
     597                                   double dfHeading, 
     598                                   double dfVisualGlidePathAngle); 
    364599}; 
    365600 
  • trunk/gdal/ogr/ogrsf_frmts/xplane/ogrxplanedatasource.cpp

    r13919 r13936  
    2828 ****************************************************************************/ 
    2929 
     30#include <math.h> 
     31 
    3032#include "ogr_xplane.h" 
    31 #include "cpl_conv.h" 
     33#include "ogr_xplane_geo_utils.h" 
    3234 
    3335#define FEET_TO_METER       0.30479999798832 
    3436#define NM_TO_KM            1.852 
     37 
    3538 
    3639/************************************************************************/ 
     
    129132 
    130133 
     134#define ASSERT_MIN_COL(nMinColNum) \ 
     135            if (nTokens < nMinColNum) \ 
     136            { \ 
     137                CPLDebug("XPlane", "Line %d : not enough columns : %d. %d is the minimum required", \ 
     138                        nLineNumber, nTokens, nMinColNum); \ 
     139                goto next_line; \ 
     140            } 
     141 
     142#define READ_STRING_UNTIL_END(osResult, iFirstIndice) \ 
     143            if (nTokens > iFirstIndice) \ 
     144            { \ 
     145                int _i; \ 
     146                int _nIDsToSum = nTokens - iFirstIndice; \ 
     147                osResult = papszTokens[iFirstIndice]; \ 
     148                for(_i=1;_i<_nIDsToSum;_i++) \ 
     149                { \ 
     150                    osResult += " "; \ 
     151                    osResult += papszTokens[iFirstIndice + _i]; \ 
     152                } \ 
     153            } 
     154 
    131155enum 
    132156{ 
     
    236260 
    237261        dfFrequency = READ_DOUBLE(4, "frequency"); 
     262        /* NDB frequencies are in kHz. Others must be divided by 100 */ 
     263        /* to get a frequency in MHz */ 
     264        if (nType != NAVAID_NDB) 
     265            dfFrequency /= 100.; 
    238266 
    239267        /* nautical miles to kilometer */ 
     
    244272        if (nType == NAVAID_NDB) 
    245273        { 
    246             int nIDsToSum = nTokens - 8; 
    247274            char* pszSubType = ""; 
    248275            CPLString osNavaidName; 
     
    252279            { 
    253280                pszSubType = papszTokens[nTokens-1]; 
    254                 nIDsToSum--; 
     281                nTokens--; 
    255282            } 
    256283            else 
     
    258285                CPLDebug("XPlane", "Unexpected NDB subtype : %s", papszTokens[nTokens-1]); 
    259286            } 
    260             osNavaidName = papszTokens[8]; 
    261             int i; 
    262             for(i=1;i<nIDsToSum;i++) 
    263             { 
    264                 osNavaidName += " "; 
    265                 osNavaidName += papszTokens[8 + i]; 
    266             } 
    267  
    268             /* NDB frequencies are in kHz. Others must be divided by 100 */ 
    269             /* to get a frequency in MHz */ 
    270             if (nType != NAVAID_NDB) 
    271                 dfFrequency /= 100; 
     287 
     288            READ_STRING_UNTIL_END(osNavaidName, 8); 
    272289 
    273290            poNDBLayer->AddFeature(pszNavaidId, osNavaidName, pszSubType, 
     
    277294        else if (nType == NAVAID_VOR) 
    278295        { 
    279             int nIDsToSum = nTokens - 8; 
    280296            char* pszSubType = ""; 
    281297            CPLString osNavaidName; 
     
    288304            { 
    289305                pszSubType = papszTokens[nTokens-1]; 
    290                 nIDsToSum--; 
     306                nTokens--; 
    291307            } 
    292308            else 
     
    294310                CPLDebug("XPlane", "Unexpected VOR subtype : %s", papszTokens[nTokens-1]); 
    295311            } 
    296             osNavaidName = papszTokens[8]; 
    297             int i; 
    298             for(i=1;i<nIDsToSum;i++) 
    299             { 
    300                 osNavaidName += " "; 
    301                 osNavaidName += papszTokens[8 + i]; 
    302             } 
     312 
     313            READ_STRING_UNTIL_END(osNavaidName, 8); 
     314 
    303315            poVORLayer->AddFeature(pszNavaidId, osNavaidName, pszSubType, 
    304316                                   dfLat, dfLon, 
     
    311323            dfTrueHeading = READ_DOUBLE_WITH_BOUNDS(6, "true heading", 0., 360.); 
    312324 
    313             if (nTokens != 11) 
    314             { 
    315                 CPLDebug("XPlane", "Line %d : not enough columns : %d", 
    316                         nLineNumber, nTokens); 
    317                 goto next_line; 
    318             } 
     325            ASSERT_MIN_COL(11); 
    319326 
    320327            pszAptICAO = papszTokens[8]; 
     
    327334                EQUAL(pszSubType, "LOC") || 
    328335                EQUAL(pszSubType, "LDA") || 
    329                 EQUAL(pszSubType, "SDF") ) 
     336                EQUAL(pszSubType, "SDF") || 
     337                EQUAL(pszSubType, "IGS") || 
     338                EQUAL(pszSubType, "LDA-GS")) 
    330339            { 
    331340                poILSLayer->AddFeature(pszNavaidId, pszAptICAO, pszRwyNum, pszSubType, 
     
    354363            } 
    355364 
    356             if (nTokens != 11) 
    357             { 
    358                 CPLDebug("XPlane", "Line %d : not enough columns : %d", 
    359                         nLineNumber, nTokens); 
    360                 goto next_line; 
    361             } 
     365            ASSERT_MIN_COL(11); 
    362366 
    363367            pszAptICAO = papszTokens[8]; 
     
    384388            dfTrueHeading = READ_DOUBLE_WITH_BOUNDS(6, "true heading", 0., 360.); 
    385389 
    386             if (nTokens != 11) 
    387             { 
    388                 CPLDebug("XPlane", "Line %d : not enough columns : %d", 
    389                         nLineNumber, nTokens); 
    390                 goto next_line; 
    391             } 
     390            ASSERT_MIN_COL(11); 
    392391 
    393392            pszAptICAO = papszTokens[8]; 
     
    412411        else if (nType == NAVAID_DME_COLOC || nType == NAVAID_DME_STANDALONE) 
    413412        { 
    414             int nIDsToSum = nTokens - 8; 
    415413            char* pszSubType = ""; 
    416414            CPLString osNavaidName; 
     
    440438                if (EQUAL(papszTokens[nTokens-1], "DME")) 
    441439                { 
    442                     nIDsToSum--; 
    443                     if (EQUAL(papszTokens[nTokens-2], "VORTAC") || 
    444                         EQUAL(papszTokens[nTokens-2], "VOR-DME") || 
    445                         EQUAL(papszTokens[nTokens-2], "TACAN") || 
    446                         EQUAL(papszTokens[nTokens-2], "NDB-DME")) 
     440                    nTokens--; 
     441                    if (EQUAL(papszTokens[nTokens-1], "VORTAC") || 
     442                        EQUAL(papszTokens[nTokens-1], "VOR-DME") || 
     443                        EQUAL(papszTokens[nTokens-1], "TACAN") || 
     444                        EQUAL(papszTokens[nTokens-1], "NDB-DME")) 
    447445                    { 
    448                         pszSubType = papszTokens[nTokens-2]; 
    449                         nIDsToSum--; 
     446                        pszSubType = papszTokens[nTokens-1]; 
     447                        nTokens--; 
    450448                    } 
    451449                } 
     
    455453                } 
    456454 
    457                 osNavaidName = papszTokens[8]; 
    458                 int i; 
    459                 for(i=1;i<nIDsToSum;i++) 
    460                 { 
    461                     osNavaidName += " "; 
    462                     osNavaidName += papszTokens[8 + i]; 
    463                 } 
     455                READ_STRING_UNTIL_END(osNavaidName, 8); 
     456 
    464457                poDMELayer->AddFeature(pszNavaidId, osNavaidName, pszSubType, 
    465458                                       dfLat, dfLon, 
     
    486479{ 
    487480    APT_AIRPORT_HEADER         = 1, 
     481    APT_RUNWAY_TAXIWAY_V_810   = 10, 
    488482    APT_RUNWAY                 = 100, 
    489483    APT_WATER_RUNWAY           = 101, 
     
    496490    APT_NODE_END               = 115, 
    497491    APT_NODE_END_WITH_BEZIER   = 116, 
    498     APT_LINEAR_FEATURE         = 120, 
    499     APT_LINEAR_FEATURE_2       = 130, 
     492    APT_LINEAR_HEADER          = 120, 
     493    APT_BOUNDARY_HEADER        = 130, 
    500494    APT_VASI_PAPI_WIGWAG       = 21, 
    501495    APT_TAXIWAY_SIGNS          = 20, 
     
    559553    OGRXPlaneAPTLayer* poAPTLayer = new OGRXPlaneAPTLayer(); 
    560554    OGRXPlaneRunwayLayer* poRunwayLayer = new OGRXPlaneRunwayLayer(); 
     555    OGRXPlaneRunwayThresholdLayer* poRunwayThresholdLayer = new OGRXPlaneRunwayThresholdLayer(); 
     556    OGRXPlaneWaterRunwayLayer* poWaterRunwayLayer = new OGRXPlaneWaterRunwayLayer(); 
     557    OGRXPlaneWaterRunwayThresholdLayer* poWaterRunwayThresholdLayer = new OGRXPlaneWaterRunwayThresholdLayer(); 
     558    OGRXPlaneHelipadLayer* poHelipadLayer = new OGRXPlaneHelipadLayer(); 
     559    OGRXPlaneHelipadPolygonLayer* poHelipadPolygonLayer = new OGRXPlaneHelipadPolygonLayer(); 
    561560    OGRXPlaneATCFreqLayer* poATCFreqLayer = new OGRXPlaneATCFreqLayer(); 
     561    OGRXPlaneStartupLocationLayer* poStartupLocationLayer = new OGRXPlaneStartupLocationLayer(); 
     562    OGRXPlaneAPTLightBeaconLayer* poAPTLightBeaconLayer = new OGRXPlaneAPTLightBeaconLayer(); 
     563    OGRXPlaneAPTWindsockLayer* poAPTWindsockLayer = new OGRXPlaneAPTWindsockLayer(); 
     564    OGRXPlaneTaxiwaySignLayer* poTaxiwaySignLayer = new OGRXPlaneTaxiwaySignLayer(); 
     565    OGRXPlane_VASI_PAPI_WIGWAG_Layer* poVASI_PAPI_WIGWAG_Layer = new OGRXPlane_VASI_PAPI_WIGWAG_Layer(); 
    562566 
    563567    RegisterLayer(poAPTLayer); 
    564568    RegisterLayer(poRunwayLayer); 
     569    RegisterLayer(poRunwayThresholdLayer); 
     570    RegisterLayer(poWaterRunwayLayer); 
     571    RegisterLayer(poWaterRunwayThresholdLayer); 
     572    RegisterLayer(poHelipadLayer); 
     573    RegisterLayer(poHelipadPolygonLayer); 
    565574    RegisterLayer(poATCFreqLayer); 
     575    RegisterLayer(poStartupLocationLayer); 
     576    RegisterLayer(poAPTLightBeaconLayer); 
     577    RegisterLayer(poAPTWindsockLayer); 
     578    RegisterLayer(poTaxiwaySignLayer); 
     579    RegisterLayer(poVASI_PAPI_WIGWAG_Layer); 
    566580 
    567581    while((pszLine = CPLReadLine(fp)) != NULL) 
     
    594608        } 
    595609 
    596  
    597         if (nTokens < 2) 
    598         { 
    599             CPLDebug("XPlane", "Line %d : not enough columns : %d", 
    600                      nLineNumber, nTokens); 
    601             goto next_line; 
    602         } 
     610        ASSERT_MIN_COL(2); 
    603611 
    604612        nType = atoi(papszTokens[0]); 
     
    618626            bRunwayFound = FALSE; 
    619627 
    620             int nIDsToSum = nTokens - 5; 
    621  
    622             if (nTokens < 6) 
    623             { 
    624                 CPLDebug("XPlane", "Line %d : not enough columns : %d", 
    625                         nLineNumber, nTokens); 
    626                 goto next_line; 
    627             } 
     628            ASSERT_MIN_COL(6); 
    628629 
    629630            /* feet to meter */ 
    630631            dfElevation = READ_DOUBLE_WITH_BOUNDS_AND_CONVERSION(1, "elevation", FEET_TO_METER, -1000., 10000.); 
    631  
    632632            bControlTower = atoi(papszTokens[2]); 
    633  
    634633            // papszTokens[3] ignored 
    635  
    636634            osAptICAO = papszTokens[4]; 
    637  
    638             osAptName = papszTokens[5]; 
    639             int i; 
    640             for(i=1;i<nIDsToSum;i++) 
    641             { 
    642                 osAptName += " "; 
    643                 osAptName += papszTokens[5 + i]; 
    644             } 
     635            READ_STRING_UNTIL_END(osAptName, 5); 
    645636 
    646637            bAptHeaderFound = TRUE; 
     638        } 
     639        else if (nType == APT_RUNWAY_TAXIWAY_V_810) 
     640        { 
     641            /* 
     642            ASSERT_MIN_COL(15); 
     643 
     644            dfLat = READ_DOUBLE_WITH_BOUNDS(1, "latitude", -90., 90.); 
     645            dfLon = READ_DOUBLE_WITH_BOUNDS(2, "longitude", -180., 180.); 
     646            pszRwyNum = papszTokens[3]; 
     647            dfTrueHeading = READ_DOUBLE_WITH_BOUNDS(4, "true heading", 0., 360.); 
     648            dfLength = READ_DOUBLE(5, "length"); 
     649            dfLength *= FEET_TO_METER; 
     650            dfDisplacedThresholdLength1 = atoi(papszTokens[6]) * FEET_TO_METER; 
     651            if (strchr(papszTokens[6]) 
     652                dfDisplacedThresholdLength2 = atoi(strchr(papszTokens[6]) + 1) * FEET_TO_METER; 
     653            dfStopwayLength1 = atoi(papszTokens[7]) * FEET_TO_METER; 
     654            if (strchr(papszTokens[7]) 
     655                dfStopwayLength2 = atoi(strchr(papszTokens[7]) + 1) * FEET_TO_METER; 
     656            dfWidth = READ_DOUBLE(8, "width"); 
     657            dfWidth *= FEET_TO_METER; 
     658            if (strlen(papszTokens[9] == 6) 
     659            { 
     660                eVisualApproachLighting1 = papszTokens[9][0] - '0'; 
     661                // TODO 
     662            } 
     663            */ 
    647664        } 
    648665        else if (nType == APT_RUNWAY) 
     
    653670            int bHasCenterLineLights, bHasMIRL, bHasDistanceRemainingSigns; 
    654671            int nCurToken; 
    655  
    656             if (nTokens < 8 + 9 + 9) 
    657             { 
    658                 CPLDebug("XPlane", "Line %d : not enough columns : %d", 
    659                         nLineNumber, nTokens)
    660                 goto next_line; 
    661             } 
     672            int nRwy = 0; 
     673            double adfLat[2], adfLon[2]; 
     674            OGRFeature* apoRunwayThreshold[2]; 
     675            double dfLength; 
     676            CPLString aosRunwayId[2]
     677 
     678            ASSERT_MIN_COL(8 + 9 + 9); 
    662679 
    663680            dfWidth = READ_DOUBLE(1, "runway width"); 
    664  
    665681            eSurfaceCode = atoi(papszTokens[2]); 
    666  
    667682            eShoulderCode = atoi(papszTokens[3]); 
    668  
    669683            dfSmoothness = READ_DOUBLE_WITH_BOUNDS(4, "runway smoothness", 0., 1.); 
    670  
    671684            bHasCenterLineLights = atoi(papszTokens[5]); 
    672  
    673685            bHasMIRL = atoi(papszTokens[6]) == 2; 
    674  
    675686            bHasDistanceRemainingSigns = atoi(papszTokens[7]); 
    676687 
    677             nCurToken = 8; 
    678             while(nCurToken + 9 <= nTokens) 
    679             { 
    680                 CPLString osRunwayId; 
     688            for( nRwy=0, nCurToken = 8 ; nRwy<=1 ; nRwy++, nCurToken += 9 ) 
     689            { 
    681690                double dfLat, dfLon, dfDisplacedThresholdLength, dfStopwayLength; 
    682691                int eMarkings, eApproachLightingCode, eREIL; 
    683692                int bHasTouchdownLights; 
    684693 
    685                 osRunwayId = papszTokens[nCurToken + 0]; /* for example : 08, 24R, or xxx */ 
    686  
    687                 dfLat = READ_DOUBLE_WITH_BOUNDS(nCurToken + 1, "latitude", -90., 90.); 
    688  
    689                 dfLon  = READ_DOUBLE_WITH_BOUNDS(nCurToken + 2, "longitude", -180., 180.); 
     694                aosRunwayId[nRwy] = papszTokens[nCurToken + 0]; /* for example : 08, 24R, or xxx */ 
     695                adfLat[nRwy] = dfLat = READ_DOUBLE_WITH_BOUNDS(nCurToken + 1, "latitude", -90., 90.); 
     696                adfLon[nRwy] = dfLon = READ_DOUBLE_WITH_BOUNDS(nCurToken + 2, "longitude", -180., 180.); 
     697                dfDisplacedThresholdLength = READ_DOUBLE(nCurToken + 3, "displaced threshold length"); 
     698                dfStopwayLength = READ_DOUBLE(nCurToken + 4, "stopway/blastpad/over-run length"); 
     699                eMarkings = atoi(papszTokens[nCurToken + 5]); 
     700                eApproachLightingCode = atoi(papszTokens[nCurToken + 6]); 
     701                bHasTouchdownLights = atoi(papszTokens[nCurToken + 7]); 
     702                eREIL = atoi(papszTokens[nCurToken + 8]); 
    690703 
    691704                if (!bRunwayFound) 
     
    695708                } 
    696709 
    697                 dfDisplacedThresholdLength = READ_DOUBLE(nCurToken + 3, "displaced threshold length"); 
    698  
    699                 dfStopwayLength = READ_DOUBLE(nCurToken + 4, "stopway/blastpad/over-run length"); 
    700  
    701                 eMarkings = atoi(papszTokens[nCurToken + 5]); 
    702  
    703                 eApproachLightingCode = atoi(papszTokens[nCurToken + 6]); 
    704  
    705                 bHasTouchdownLights = atoi(papszTokens[nCurToken + 7]); 
    706  
    707                 eREIL = atoi(papszTokens[nCurToken + 8]); 
    708  
    709                 poRunwayLayer->AddFeature(osAptICAO, osRunwayId, 
    710                                           dfLat, dfLon, dfWidth, 
    711                                           RunwaySurfaceEnumeration.GetText(eSurfaceCode), 
    712                                           RunwayShoulderEnumeration.GetText(eShoulderCode), 
    713                                           dfSmoothness, bHasCenterLineLights, bHasMIRL, bHasDistanceRemainingSigns, 
    714                                           dfDisplacedThresholdLength, dfStopwayLength, 
    715                                           RunwayMarkingEnumeration.GetText(eMarkings), 
    716                                           RunwayApproachLightingEnumeration.GetText(eApproachLightingCode), 
    717                                           bHasTouchdownLights, 
    718                                           RunwayREILEnumeration.GetText(eREIL)); 
    719  
     710                apoRunwayThreshold[nRwy] = 
     711                    poRunwayThresholdLayer->AddFeature   
     712                       (osAptICAO, aosRunwayId[nRwy], 
     713                        dfLat, dfLon, dfWidth, 
     714                        RunwaySurfaceEnumeration.GetText(eSurfaceCode), 
     715                        RunwayShoulderEnumeration.GetText(eShoulderCode), 
     716                        dfSmoothness, bHasCenterLineLights, bHasMIRL, bHasDistanceRemainingSigns, 
     717                        dfDisplacedThresholdLength, dfStopwayLength, 
     718                        RunwayMarkingEnumeration.GetText(eMarkings), 
     719                        RunwayApproachLightingEnumeration.GetText(eApproachLightingCode), 
     720                        bHasTouchdownLights, 
     721                        RunwayREILEnumeration.GetText(eREIL)); 
    720722                bRunwayFound = TRUE; 
    721  
    722                 nCurToken += 9; 
    723             } 
     723            } 
     724 
     725            dfLength = OGRXPlane_Distance(adfLat[0], adfLon[0], adfLat[1], adfLon[1]); 
     726            poRunwayThresholdLayer->SetRunwayLengthAndHeading(apoRunwayThreshold[0], dfLength, 
     727                                        OGRXPlane_Track(adfLat[0], adfLon[0], adfLat[1], adfLon[1])); 
     728            poRunwayThresholdLayer->SetRunwayLengthAndHeading(apoRunwayThreshold[1], dfLength, 
     729                                        OGRXPlane_Track(adfLat[1], adfLon[1], adfLat[0], adfLon[0])); 
     730 
     731            poRunwayLayer->AddFeature(osAptICAO, aosRunwayId[0], aosRunwayId[1], 
     732                                      adfLat[0], adfLon[0], adfLat[1], adfLon[1], 
     733                                      dfWidth, 
     734                                      RunwaySurfaceEnumeration.GetText(eSurfaceCode), 
     735                                      RunwayShoulderEnumeration.GetText(eShoulderCode), 
     736                                      dfSmoothness, bHasCenterLineLights, bHasMIRL, bHasDistanceRemainingSigns); 
     737        } 
     738        else if (nType == APT_WATER_RUNWAY) 
     739        { 
     740            double adfLat[2], adfLon[2]; 
     741            OGRFeature* apoWaterRunwayThreshold[2]; 
     742            double dfWidth, dfLength; 
     743            int bBuoys; 
     744            CPLString aosRunwayId[2]; 
     745            int i; 
     746 
     747            ASSERT_MIN_COL(9); 
     748 
     749            dfWidth = READ_DOUBLE(1, "runway width"); 
     750            bBuoys = atoi(papszTokens[2]); 
     751 
     752            for(i=0;i<2;i++) 
     753            { 
     754                aosRunwayId[i] = papszTokens[3 + 3*i]; 
     755                adfLat[i] = READ_DOUBLE_WITH_BOUNDS(4 + 3*i, "latitude", -90., 90.); 
     756                adfLon[i] = READ_DOUBLE_WITH_BOUNDS(5 + 3*i, "longitude", -180., 180.); 
     757 
     758                apoWaterRunwayThreshold[i] = 
     759                    poWaterRunwayThresholdLayer->AddFeature   
     760                        (osAptICAO, aosRunwayId[i], adfLat[i], adfLon[i], dfWidth, bBuoys); 
     761 
     762            } 
     763 
     764            dfLength = OGRXPlane_Distance(adfLat[0], adfLon[0], adfLat[1], adfLon[1]); 
     765 
     766 
     767            poWaterRunwayThresholdLayer->SetRunwayLengthAndHeading(apoWaterRunwayThreshold[0], dfLength, 
     768                                        OGRXPlane_Track(adfLat[0], adfLon[0], adfLat[1], adfLon[1])); 
     769            poWaterRunwayThresholdLayer->SetRunwayLengthAndHeading(apoWaterRunwayThreshold[1], dfLength, 
     770                                        OGRXPlane_Track(adfLat[1], adfLon[1], adfLat[0], adfLon[0])); 
     771 
     772            poWaterRunwayLayer->AddFeature(osAptICAO, aosRunwayId[0], aosRunwayId[1], 
     773                                      adfLat[0], adfLon[0], adfLat[1], adfLon[1], 
     774                                      dfWidth, bBuoys); 
     775        } 
     776        else if (nType == APT_HELIPAD) 
     777        { 
     778            double dfLat, dfLon, dfTrueHeading, dfLength, dfWidth, dfSmoothness; 
     779            int eSurfaceCode, eMarkings, eShoulderCode; 
     780            int bEdgeLighting; 
     781            const char* pszHelipadName; 
     782 
     783            ASSERT_MIN_COL(12); 
     784 
     785            pszHelipadName = papszTokens[1]; 
     786            dfLat = READ_DOUBLE_WITH_BOUNDS(2, "latitude", -90., 90.); 
     787            dfLon = READ_DOUBLE_WITH_BOUNDS(3, "longitude", -180., 180.); 
     788            dfTrueHeading = READ_DOUBLE_WITH_BOUNDS(4, "true headi